Merge inbound to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Fri, 27 Apr 2018 00:39:26 +0300
changeset 415855 63a0e2f626febb98d87d2543955ab99a653654ff
parent 415773 975e9b7613aaeea40c9d4cdf6ada1c6fa07e6d84 (current diff)
parent 415854 1472f261db239683061a82d3ceeeb14c31bbc158 (diff)
child 415883 f551d1f94952bd23073a75244fba738e6e3080c9
child 415975 f679e7f1a758cd0f36adb333ebe0e5dc25f07b78
push id33910
push usershindli@mozilla.com
push dateThu, 26 Apr 2018 21:39:52 +0000
treeherdermozilla-central@63a0e2f626fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
63a0e2f626fe / 61.0a1 / 20180426220144 / files
nightly linux64
63a0e2f626fe / 61.0a1 / 20180426220144 / files
nightly mac
63a0e2f626fe / 61.0a1 / 20180426220144 / files
nightly win32
63a0e2f626fe / 61.0a1 / 20180426220144 / files
nightly win64
63a0e2f626fe / 61.0a1 / 20180426220144 / 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
testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
testing/mozbase/mozdevice/mozdevice/devicemanager.py
testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
testing/mozbase/mozdevice/mozdevice/dmcli.py
testing/mozbase/mozdevice/mozdevice/droid.py
testing/web-platform/meta/2dcontext/drawing-paths-to-the-canvas/canvas_focus_drawCustomFocusRing_001.html.ini
testing/web-platform/tests/2dcontext/drawing-paths-to-the-canvas/canvas_focus_drawCustomFocusRing_001.html
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -756,17 +756,19 @@ Accessible::TakeFocus()
         widget->SetCurrentItem(this);
       }
     }
   }
 
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     AutoHandlingUserInputStatePusher inputStatePusher(true, nullptr, focusContent->OwnerDoc());
-    nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
+    // XXXbz: Can we actually have a non-element content here?
+    RefPtr<Element> element =
+      focusContent->IsElement() ? focusContent->AsElement() : nullptr;
     fm->SetFocus(element, 0);
   }
 }
 
 void
 Accessible::XULElmName(DocAccessible* aDocument,
                        nsIContent* aElm, nsString& aName)
 {
@@ -1751,19 +1753,20 @@ Accessible::RelationByType(RelationType 
           if (form) {
             nsCOMPtr<nsIContent> formContent =
               do_QueryInterface(form->GetDefaultSubmitElement());
             return Relation(mDoc, formContent);
           }
         }
       } else {
         // In XUL, use first <button default="true" .../> in the document
-        dom::XULDocument* xulDoc = mContent->OwnerDoc()->AsXULDocument();
+        nsIDocument* doc = mContent->OwnerDoc();
         nsCOMPtr<nsIDOMXULButtonElement> buttonEl;
-        if (xulDoc) {
+        if (doc->IsXULDocument()) {
+          dom::XULDocument* xulDoc = doc->AsXULDocument();
           nsCOMPtr<nsINodeList> possibleDefaultButtons =
             xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
                                            NS_LITERAL_STRING("true"));
           if (possibleDefaultButtons) {
             uint32_t length = possibleDefaultButtons->Length();
             // Check for button in list of default="true" elements
             for (uint32_t count = 0; count < length && !buttonEl; count ++) {
               buttonEl = do_QueryInterface(possibleDefaultButtons->Item(count));
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -320,17 +320,17 @@ DocAccessible::FocusedChild()
   return FocusMgr()->FocusedAccessible();
 }
 
 void
 DocAccessible::TakeFocus()
 {
   // Focus the document.
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
-  nsCOMPtr<nsIDOMElement> newFocus;
+  RefPtr<dom::Element> newFocus;
   AutoHandlingUserInputStatePusher inputStatePusher(true, nullptr, mDocumentNode);
   fm->MoveFocus(mDocumentNode->GetWindow(), nullptr,
                 nsFocusManager::MOVEFOCUS_ROOT, 0, getter_AddRefs(newFocus));
 }
 
 // HyperTextAccessible method
 already_AddRefed<TextEditor>
 DocAccessible::GetEditor() const
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1367,17 +1367,17 @@ HyperTextAccessible::SetSelectionRange(i
     return NS_OK;
 
   nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager();
   if (DOMFocusManager) {
     NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE);
     nsIDocument* docNode = mDoc->DocumentNode();
     NS_ENSURE_TRUE(docNode, NS_ERROR_FAILURE);
     nsCOMPtr<nsPIDOMWindowOuter> window = docNode->GetWindow();
-    nsCOMPtr<nsIDOMElement> result;
+    RefPtr<dom::Element> result;
     DOMFocusManager->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
                                nsIFocusManager::FLAG_BYMOVEFOCUS, getter_AddRefs(result));
   }
 
   return NS_OK;
 }
 
 int32_t
--- a/devtools/client/inspector/flexbox/components/FlexboxItem.js
+++ b/devtools/client/inspector/flexbox/components/FlexboxItem.js
@@ -48,17 +48,17 @@ class FlexboxItem extends PureComponent 
       onToggleFlexboxHighlighter,
     } = this.props;
 
     onToggleFlexboxHighlighter(flexbox.nodeFront);
   }
 
   onFlexboxInspectIconClick(nodeFront) {
     const { setSelectedNode } = this.props;
-    setSelectedNode(nodeFront, { reason: "layout-panel" }).catch(e => console.error(e));
+    setSelectedNode(nodeFront, { reason: "layout-panel" });
     nodeFront.scrollIntoView().catch(e => console.error(e));
   }
 
   render() {
     const {
       flexbox,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
--- a/devtools/client/inspector/grids/components/GridItem.js
+++ b/devtools/client/inspector/grids/components/GridItem.js
@@ -80,17 +80,17 @@ class GridItem extends PureComponent {
       onToggleGridHighlighter,
     } = this.props;
 
     onToggleGridHighlighter(grid.nodeFront);
   }
 
   onGridInspectIconClick(nodeFront) {
     let { setSelectedNode } = this.props;
-    setSelectedNode(nodeFront, { reason: "layout-panel" }).catch(e => console.error(e));
+    setSelectedNode(nodeFront, { reason: "layout-panel" });
     nodeFront.scrollIntoView().catch(e => console.error(e));
   }
 
   render() {
     let {
       grid,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
--- a/devtools/shared/css/generated/mach_commands.py
+++ b/devtools/shared/css/generated/mach_commands.py
@@ -56,17 +56,17 @@ class MachCommands(MachCommandBase):
         with open(dataPath, "r") as f:
             data = eval(f.read())
 
         # Map this list
         # (name, prop, id, flags, pref, proptype) => (name, pref)
         preferences = [
             (name, pref)
             for name, prop, id, flags, pref, proptype in data
-            if 'CSS_PROPERTY_INTERNAL' not in flags and pref]
+            if 'CSSPropFlags::Internal' not in flags and pref]
 
         return preferences
 
     def get_properties_db_from_xpcshell(self):
         """Generate the static css properties db for devtools from an xpcshell script."""
         build = MozbuildObject.from_environment()
 
         # Get the paths
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -604,17 +604,17 @@ EffectCompositor::GetOverriddenPropertie
   }
 
   AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
   {
     nsCSSPropertyIDSet propertiesToTrackAsSet;
     for (KeyframeEffectReadOnly* effect : aEffectSet) {
       for (const AnimationProperty& property : effect->Properties()) {
         if (nsCSSProps::PropHasFlags(property.mProperty,
-                                     CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
+                                     CSSPropFlags::CanAnimateOnCompositor) &&
             !propertiesToTrackAsSet.HasProperty(property.mProperty)) {
           propertiesToTrackAsSet.AddProperty(property.mProperty);
           propertiesToTrack.AppendElement(property.mProperty);
         }
       }
       // Skip iterating over the rest of the effects if we've already
       // found all the compositor-animatable properties.
       if (propertiesToTrack.Length() == LayerAnimationInfo::kRecords) {
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -494,17 +494,17 @@ KeyframeEffectReadOnly::IsRunningOnCompo
   return false;
 }
 
 void
 KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSPropertyID aProperty,
                                                  bool aIsRunning)
 {
   MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
-                                      CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
+                                      CSSPropFlags::CanAnimateOnCompositor),
              "Property being animated on compositor is a recognized "
              "compositor-animatable property");
   for (AnimationProperty& property : mProperties) {
     if (property.mProperty == aProperty) {
       property.mIsRunningOnCompositor = aIsRunning;
       // We currently only set a performance warning message when animations
       // cannot be run on the compositor, so if this animation is running
       // on the compositor we don't need a message.
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMMozPromiseRequestHolder.h
@@ -0,0 +1,125 @@
+/* -*- 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_DOMMozPromiseRequestHolder_h
+#define mozilla_dom_DOMMozPromiseRequestHolder_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/MozPromise.h"
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * This is a helper class that can be used when MozPromises are
+ * being consumed by binding layer code.  It effectively creates
+ * a MozPromiseRequestHolder that auto-disconnects when the binding's
+ * global is disconnected.
+ *
+ * It can be used like this:
+ *
+ *    RefPtr<Promise>
+ *    SomeAsyncAPI(Args& aArgs, ErrorResult& aRv)
+ *    {
+ *      nsIGlobalObject* global = GetParentObject();
+ *      if (!global) {
+ *        aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ *        return nullptr;
+ *      }
+ *
+ *      RefPtr<Promise> outer = Promise::Create(global, aRv);
+ *      if (aRv.Failed()) {
+ *        return nullptr;
+ *      }
+ *
+ *      RefPtr<DOMMozPromiseRequestHolder> holder =
+ *        new DOMMozPromiseRequestHolder(global);
+ *
+ *      DoAsyncStuff()->Then(
+ *        global->EventTargetFor(TaskCategory::Other), __func__,
+ *        [holder, outer] (const Result& aResult) {
+ *          holder->Complete();
+ *          outer->MaybeResolve(aResult);
+ *        }, [holder, outer] (nsresult aRv) {
+ *          holder->Complete();
+ *          outer->MaybeReject(aRv);
+ *        })->Track(*holder);
+ *
+ *      return outer.forget();
+ *    }
+ *
+ * NOTE: Currently this helper class extends DETH.  This is only
+ *       so that it can bind to the global and receive the
+ *       DisconnectFromOwner() method call.  In this future the
+ *       binding code should be factored out so DETH is not
+ *       needed here.  See bug 1456893.
+ */
+template<typename PromiseType>
+class DOMMozPromiseRequestHolder final : public DOMEventTargetHelper
+{
+  MozPromiseRequestHolder<PromiseType> mHolder;
+
+  ~DOMMozPromiseRequestHolder() = default;
+
+  void
+  DisconnectFromOwner() override
+  {
+    mHolder.DisconnectIfExists();
+    DOMEventTargetHelper::DisconnectFromOwner();
+  }
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
+  {
+    // We are extending DETH to get notified when the global goes
+    // away, but this object should never actually be exposed to
+    // script.
+    MOZ_CRASH("illegal method");
+  }
+
+public:
+  explicit DOMMozPromiseRequestHolder(nsIGlobalObject* aGlobal)
+    : DOMEventTargetHelper(aGlobal)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(aGlobal);
+  }
+
+  operator MozPromiseRequestHolder<PromiseType>& ()
+  {
+    return mHolder;
+  }
+
+  operator const MozPromiseRequestHolder<PromiseType>& () const
+  {
+    return mHolder;
+  }
+
+  void
+  Complete()
+  {
+    mHolder.Complete();
+    DisconnectFromOwner();
+  }
+
+  void
+  DisconnectIfExists()
+  {
+    mHolder.DisconnectIfExists();
+  }
+
+  bool
+  Exists() const
+  {
+    return mHolder.Exists();
+  }
+
+  NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMMozPromiseRequestHolder, DOMEventTargetHelper)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DOMMozPromiseRequestHolder_h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -333,25 +333,24 @@ Element::TabIndex()
   }
 
   return TabIndexDefault();
 }
 
 void
 Element::Focus(mozilla::ErrorResult& aError)
 {
-  nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(this);
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   // Also other browsers seem to have the hack to not re-focus (and flush) when
   // the element is already focused.
-  if (fm && domElement) {
+  if (fm) {
     if (fm->CanSkipFocus(this)) {
       fm->NeedsFlushBeforeEventHandling(this);
     } else {
-      aError = fm->SetFocus(domElement, 0);
+      aError = fm->SetFocus(this, 0);
     }
   }
 }
 
 void
 Element::SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError)
 {
   nsAutoString value;
@@ -3301,19 +3300,19 @@ Element::PostHandleEventForLinks(EventCh
             WidgetMouseEvent::eLeftButton) {
         // don't make the link grab the focus if there is no link handler
         nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
         nsIDocument *document = GetComposedDoc();
         if (handler && document) {
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm) {
             aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
-            nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
-            fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
-                               nsIFocusManager::FLAG_NOSCROLL);
+            RefPtr<Element> kungFuDeathGrip(this);
+            fm->SetFocus(kungFuDeathGrip, nsIFocusManager::FLAG_BYMOUSE |
+                                          nsIFocusManager::FLAG_NOSCROLL);
           }
 
           EventStateManager::SetActiveManager(
             aVisitor.mPresContext->EventStateManager(), this);
 
           // OK, we're pretty sure we're going to load, so warm up a speculative
           // connection to be sure we have one ready when we open the channel.
           nsCOMPtr<nsISpeculativeConnect> sc =
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -69,24 +69,27 @@ namespace css {
   struct URLValue;
 } // namespace css
 namespace dom {
   struct AnimationFilter;
   struct ScrollIntoViewOptions;
   struct ScrollToOptions;
   class DOMIntersectionObserver;
   class DOMMatrixReadOnly;
+  class Element;
   class ElementOrCSSPseudoElement;
   class UnrestrictedDoubleOrKeyframeAnimationOptions;
   enum class CallerType : uint32_t;
   typedef nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
     IntersectionObserverList;
 } // namespace dom
 } // namespace mozilla
 
+// Declared here because of include hell.
+extern "C" bool Servo_Element_IsDisplayContents(const mozilla::dom::Element*);
 
 already_AddRefed<nsContentList>
 NS_GetContentList(nsINode* aRootNode,
                   int32_t  aMatchNameSpaceId,
                   const nsAString& aTagname);
 
 #define ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
 
@@ -1430,16 +1433,21 @@ public:
    * @param aType the kind of flush to do, typically FlushType::Frames or
    *              FlushType::Layout
    * @return the primary frame
    */
   nsIFrame* GetPrimaryFrame(FlushType aType);
   // Work around silly C++ name hiding stuff
   nsIFrame* GetPrimaryFrame() const { return nsIContent::GetPrimaryFrame(); }
 
+  bool IsDisplayContents() const
+  {
+    return HasServoData() && Servo_Element_IsDisplayContents(this);
+  }
+
   const nsAttrValue* GetParsedAttr(nsAtom* aAttr) const
   {
     return mAttrsAndChildren.GetAttr(aAttr);
   }
 
   const nsAttrValue* GetParsedAttr(nsAtom* aAttr, int32_t aNameSpaceID) const
   {
     return mAttrsAndChildren.GetAttr(aAttr, aNameSpaceID);
--- a/dom/base/ProcessGlobal.cpp
+++ b/dom/base/ProcessGlobal.cpp
@@ -8,16 +8,18 @@
 
 #include "nsContentCID.h"
 #include "mozilla/dom/MessageManagerBinding.h"
 #include "mozilla/dom/ResolveSystemBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+bool ProcessGlobal::sWasCreated = false;
+
 ProcessGlobal::ProcessGlobal(nsFrameMessageManager* aMessageManager)
  : MessageManagerGlobal(aMessageManager),
    mInitialized(false)
 {
   mozilla::HoldJSObjects(this);
 }
 
 ProcessGlobal::~ProcessGlobal()
@@ -58,17 +60,27 @@ ProcessGlobal::GetOwnPropertyNames(JSCon
 
 ProcessGlobal*
 ProcessGlobal::Get()
 {
   nsCOMPtr<nsIGlobalObject> service = do_GetService(NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID);
   if (!service) {
     return nullptr;
   }
-  return static_cast<ProcessGlobal*>(service.get());
+  ProcessGlobal* global = static_cast<ProcessGlobal*>(service.get());
+  if (global) {
+    sWasCreated = true;
+  }
+  return global;
+}
+
+bool
+ProcessGlobal::WasCreated()
+{
+  return sWasCreated;
 }
 
 void
 ProcessGlobal::MarkForCC()
 {
   MarkScopesForCC();
   MessageManagerGlobal::MarkForCC();
 }
--- a/dom/base/ProcessGlobal.h
+++ b/dom/base/ProcessGlobal.h
@@ -46,16 +46,17 @@ public:
                            bool aEnumerableOnly, ErrorResult& aRv);
 
   using ipc::MessageManagerCallback::GetProcessMessageManager;
   using MessageManagerGlobal::GetProcessMessageManager;
 
   bool Init();
 
   static ProcessGlobal* Get();
+  static bool WasCreated();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(ProcessGlobal, nsIMessageSender)
 
   void MarkForCC();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override
@@ -95,14 +96,16 @@ public:
 
   void SetInitialProcessData(JS::HandleValue aInitialData);
 
 protected:
   virtual ~ProcessGlobal();
 
 private:
   bool mInitialized;
+
+  static bool sWasCreated;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ProcessGlobal_h
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -3732,26 +3732,24 @@ Selection::NotifySelectionListeners()
                                              nsFocusManager::eOnlyCurrentWindow,
                                              getter_AddRefs(focusedWindow));
       nsCOMPtr<Element> focusedElement = do_QueryInterface(focusedContent);
       // When all selected ranges are in an editing host, it should take focus.
       // But otherwise, we shouldn't move focus since Chromium doesn't move
       // focus but only selection range is updated.
       if (newEditingHost && newEditingHost != focusedElement) {
         MOZ_ASSERT(!newEditingHost->IsInNativeAnonymousSubtree());
-        nsCOMPtr<nsIDOMElement> domElementToFocus =
-          do_QueryInterface(newEditingHost->AsDOMNode());
         // Note that don't steal focus from focused window if the window doesn't
         // have focus and if the window isn't focused window, shouldn't be
         // scrolled to the new focused element.
         uint32_t flags = nsIFocusManager::FLAG_NOSWITCHFRAME;
         if (focusedWindow != fm->GetFocusedWindow()) {
           flags |= nsIFocusManager::FLAG_NOSCROLL;
         }
-        fm->SetFocus(domElementToFocus, flags);
+        fm->SetFocus(newEditingHost, flags);
       }
     }
   }
 
   RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
   if (frameSelection->GetBatching()) {
     frameSelection->SetDirty();
     return NS_OK;
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -164,16 +164,17 @@ EXPORTS.mozilla.dom += [
     'DocumentFragment.h',
     'DocumentOrShadowRoot.h',
     'DocumentType.h',
     'DOMError.h',
     'DOMException.h',
     'DOMImplementation.h',
     'DOMIntersectionObserver.h',
     'DOMMatrix.h',
+    'DOMMozPromiseRequestHolder.h',
     'DOMParser.h',
     'DOMPoint.h',
     'DOMPrefs.h',
     'DOMPrefsInternal.h',
     'DOMQuad.h',
     'DOMRect.h',
     'DOMRequest.h',
     'DOMStringList.h',
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -464,17 +464,17 @@ mozilla::dom::TraceBlackJS(JSTracer* aTr
     }
   }
 #endif
 
   if (!nsCCUncollectableMarker::sGeneration) {
     return;
   }
 
-  if (nsFrameMessageManager::GetChildProcessManager()) {
+  if (ProcessGlobal::WasCreated() && nsFrameMessageManager::GetChildProcessManager()) {
     ProcessGlobal* pg = ProcessGlobal::Get();
     if (pg) {
       mozilla::TraceScriptHolder(ToSupports(pg), aTrc);
     }
   }
 
   // Mark globals of active windows black.
   nsGlobalWindowOuter::OuterWindowByIdTable* windowsById =
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -230,22 +230,22 @@ nsContentSink::Init(nsIDocument* aDoc,
     FavorPerformanceHint(!mDynamicLowerValue, 0);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentSink::StyleSheetLoaded(StyleSheet* aSheet,
-                                bool aWasAlternate,
+                                bool aWasDeferred,
                                 nsresult aStatus)
 {
-  NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
-  if (!aWasAlternate) {
-    NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
+  MOZ_ASSERT(!mRunsToCompletion, "How come a fragment parser observed sheets?");
+  if (!aWasDeferred) {
+    MOZ_ASSERT(mPendingSheetCount > 0, "How'd that happen?");
     --mPendingSheetCount;
 
     if (mPendingSheetCount == 0 &&
         (mDeferredLayoutStart || mDeferredFlushTags)) {
       if (mDeferredFlushTags) {
         FlushTags();
       }
       if (mDeferredLayoutStart) {
@@ -785,25 +785,26 @@ nsContentSink::ProcessStyleLinkFromHeade
 
   mozilla::net::ReferrerPolicy referrerPolicy =
     mozilla::net::AttributeReferrerPolicyFromString(aReferrerPolicy);
   if (referrerPolicy == net::RP_Unset) {
     referrerPolicy = mDocument->GetReferrerPolicy();
   }
   // If this is a fragment parser, we don't want to observe.
   // We don't support CORS for processing instructions
-  bool isAlternate;
-  rv = mCSSLoader->LoadStyleLink(nullptr, url, nullptr, aTitle, aMedia, aAlternate,
-                                 CORS_NONE, referrerPolicy,
-                                 /* integrity = */ EmptyString(),
-                                 mRunsToCompletion ? nullptr : this,
-                                 &isAlternate);
-  NS_ENSURE_SUCCESS(rv, rv);
+  auto loadResultOrErr =
+    mCSSLoader->LoadStyleLink(nullptr, url, nullptr, aTitle, aMedia, aAlternate,
+                              CORS_NONE, referrerPolicy,
+                              /* integrity = */ EmptyString(),
+                              mRunsToCompletion ? nullptr : this);
+  if (loadResultOrErr.isErr()) {
+    return loadResultOrErr.unwrapErr();
+  }
 
-  if (!isAlternate && !mRunsToCompletion) {
+  if (loadResultOrErr.unwrap().ShouldBlock() && !mRunsToCompletion) {
     ++mPendingSheetCount;
     mScriptLoader->AddParserBlockingScriptExecutionBlocker();
   }
 
   return NS_OK;
 }
 
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10,16 +10,17 @@
 
 #include "AudioChannelService.h"
 #include "nsDocument.h"
 #include "nsIDocumentInlines.h"
 #include "mozilla/AnimationComparator.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/BinarySearch.h"
+#include "mozilla/CSSEnabledState.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/IntegerRange.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Likely.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/URLExtraData.h"
@@ -3519,21 +3520,20 @@ nsIDocument::GetActiveElement()
 {
   // Get the focused element.
   Element* focusedElement = GetRetargetedFocusedElement();
   if (focusedElement) {
     return focusedElement;
   }
 
   // No focused element anywhere in this document.  Try to get the BODY.
-  RefPtr<nsHTMLDocument> htmlDoc = AsHTMLDocument();
-  if (htmlDoc) {
+  if (IsHTMLOrXHTML()) {
     // Because of IE compatibility, return null when html document doesn't have
     // a body.
-    return htmlDoc->GetBody();
+    return AsHTMLDocument()->GetBody();
   }
 
   // If we couldn't get a BODY, return the root element.
   return GetDocumentElement();
 }
 
 Element*
 nsIDocument::GetCurrentScript()
@@ -5739,17 +5739,17 @@ GetPseudoElementType(const nsString& aSt
 {
   MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null");
   if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return CSSPseudoElementType::NotPseudo;
   }
   RefPtr<nsAtom> pseudo = NS_Atomize(Substring(aString, 1));
   return nsCSSPseudoElements::GetPseudoType(pseudo,
-      nsCSSProps::EnabledState::eInUASheets);
+      CSSEnabledState::eInUASheets);
 }
 
 already_AddRefed<Element>
 nsIDocument::CreateElement(const nsAString& aTagName,
                            const ElementCreationOptionsOrString& aOptions,
                            ErrorResult& rv)
 {
   rv = nsContentUtils::CheckQName(aTagName, false);
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -100,26 +100,35 @@ protected:
 
   bool IsVisibleNode(nsINode* aNode)
   {
     NS_PRECONDITION(aNode, "");
 
     if (mFlags & SkipInvisibleContent) {
       // Treat the visibility of the ShadowRoot as if it were
       // the host content.
-      nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-      if (ShadowRoot* shadowRoot = ShadowRoot::FromNodeOrNull(content)) {
-        content = shadowRoot->GetHost();
+      //
+      // FIXME(emilio): I suspect instead of this a bunch of the GetParent()
+      // calls here should be doing GetFlattenedTreeParent, then this condition
+      // should be unreachable...
+      if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(aNode)) {
+        aNode = shadowRoot->GetHost();
       }
 
-      if (content) {
-        nsIFrame* frame = content->GetPrimaryFrame();
+      if (aNode->IsContent()) {
+        nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
         if (!frame) {
+          if (aNode->IsElement() && aNode->AsElement()->IsDisplayContents()) {
+            return true;
+          }
           if (aNode->IsText()) {
             // We have already checked that our parent is visible.
+            //
+            // FIXME(emilio): Text not assigned to a <slot> in Shadow DOM should
+            // probably return false...
             return true;
           }
           if (aNode->IsHTMLElement(nsGkAtoms::rp)) {
             // Ruby parentheses are part of ruby structure, hence
             // shouldn't be stripped out even if it is not displayed.
             return true;
           }
           return false;
@@ -1243,21 +1252,24 @@ nsHTMLCopyEncoder::SetSelection(nsISelec
   // if selection is uninitialized return
   if (!rangeCount) {
     return NS_ERROR_FAILURE;
   }
 
   // we'll just use the common parent of the first range.  Implicit assumption
   // here that multi-range selections are table cell selections, in which case
   // the common parent is somewhere in the table and we don't really care where.
+  //
+  // FIXME(emilio, bug 1455894): This assumption is already wrong, and will
+  // probably be more wrong in a Shadow DOM world...
+  //
+  // We should be able to write this as "Find the common ancestor of the
+  // selection, then go through the flattened tree and serialize the selected
+  // nodes", effectively serializing the composed tree.
   RefPtr<nsRange> range = selection->GetRangeAt(0);
-  if (!range) {
-    // XXXbz can this happen given rangeCount > 0?
-    return NS_ERROR_NULL_POINTER;
-  }
   nsINode* commonParent = range->GetCommonAncestor();
 
   for (nsCOMPtr<nsIContent> selContent(do_QueryInterface(commonParent));
        selContent;
        selContent = selContent->GetParent())
   {
     // checking for selection inside a plaintext form widget
     if (selContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea))
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -297,26 +297,26 @@ nsFocusManager::IsFocused(nsIContent* aC
 static nsPIDOMWindowOuter*
 GetCurrentWindow(nsIContent* aContent)
 {
   nsIDocument* doc = aContent->GetComposedDoc();
   return doc ? doc->GetWindow() : nullptr;
 }
 
 // static
-nsIContent*
+Element*
 nsFocusManager::GetFocusedDescendant(nsPIDOMWindowOuter* aWindow,
                                      SearchRange aSearchRange,
                                      nsPIDOMWindowOuter** aFocusedWindow)
 {
   NS_ENSURE_TRUE(aWindow, nullptr);
 
   *aFocusedWindow = nullptr;
 
-  nsIContent* currentContent = nullptr;
+  Element* currentContent = nullptr;
   nsPIDOMWindowOuter* window = aWindow;
   for (;;) {
     *aFocusedWindow = window;
     currentContent = window->GetFocusedNode();
     if (!currentContent || aSearchRange == eOnlyCurrentWindow) {
       break;
     }
 
@@ -344,33 +344,33 @@ nsFocusManager::GetFocusedDescendant(nsP
   }
 
   NS_IF_ADDREF(*aFocusedWindow);
 
   return currentContent;
 }
 
 // static
-nsIContent*
+Element*
 nsFocusManager::GetRedirectedFocus(nsIContent* aContent)
 {
   // For input number, redirect focus to our anonymous text control.
   if (aContent->IsHTMLElement(nsGkAtoms::input)) {
     bool typeIsNumber =
       static_cast<dom::HTMLInputElement*>(aContent)->ControlType() ==
         NS_FORM_INPUT_NUMBER;
 
     if (typeIsNumber) {
       nsNumberControlFrame* numberControlFrame =
         do_QueryFrame(aContent->GetPrimaryFrame());
 
       if (numberControlFrame) {
         HTMLInputElement* textControl =
           numberControlFrame->GetAnonTextControl();
-        return static_cast<nsIContent*>(textControl);
+        return textControl;
       }
     }
   }
 
 #ifdef MOZ_XUL
   if (aContent->IsXULElement()) {
     nsCOMPtr<nsIDOMNode> inputField;
 
@@ -387,23 +387,23 @@ nsFocusManager::GetRedirectedFocus(nsICo
         nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc();
         if (!doc)
           return nullptr;
 
         nsINodeList* children = doc->BindingManager()->GetAnonymousNodesFor(aContent);
         if (children) {
           nsIContent* child = children->Item(0);
           if (child && child->IsXULElement(nsGkAtoms::slider))
-            return child;
+            return child->AsElement();
         }
       }
     }
 
     if (inputField) {
-      nsCOMPtr<nsIContent> retval = do_QueryInterface(inputField);
+      nsCOMPtr<Element> retval = do_QueryInterface(inputField);
       return retval;
     }
   }
 #endif
 
   return nullptr;
 }
 
@@ -508,46 +508,43 @@ nsFocusManager::GetLastFocusMethod(mozID
   *aLastFocusMethod = window ? window->GetFocusMethod() : 0;
 
   NS_ASSERTION((*aLastFocusMethod & FOCUSMETHOD_MASK) == *aLastFocusMethod,
                "invalid focus method");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFocusManager::SetFocus(nsIDOMElement* aElement, uint32_t aFlags)
+nsFocusManager::SetFocus(Element* aElement, uint32_t aFlags)
 {
   LOGFOCUS(("<<SetFocus begin>>"));
 
-  nsCOMPtr<nsIContent> newFocus = do_QueryInterface(aElement);
-  NS_ENSURE_ARG(newFocus);
-
-  SetFocusInner(newFocus, aFlags, true, true);
+  NS_ENSURE_ARG(aElement);
+
+  SetFocusInner(aElement, aFlags, true, true);
 
   LOGFOCUS(("<<SetFocus end>>"));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFocusManager::ElementIsFocusable(nsIDOMElement* aElement, uint32_t aFlags,
+nsFocusManager::ElementIsFocusable(Element* aElement, uint32_t aFlags,
                                    bool* aIsFocusable)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_INVALID_ARG);
 
-  nsCOMPtr<nsIContent> aContent = do_QueryInterface(aElement);
-
-  *aIsFocusable = CheckIfFocusable(aContent, aFlags) != nullptr;
+  *aIsFocusable = CheckIfFocusable(aElement, aFlags) != nullptr;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, nsIDOMElement* aStartElement,
-                          uint32_t aType, uint32_t aFlags, nsIDOMElement** aElement)
+nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, Element* aStartElement,
+                          uint32_t aType, uint32_t aFlags, Element** aElement)
 {
   *aElement = nullptr;
 
   LOGFOCUS(("<<MoveFocus begin Type: %d Flags: %x>>", aType, aFlags));
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug) && mFocusedWindow) {
     nsIDocument* doc = mFocusedWindow->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
@@ -563,47 +560,44 @@ nsFocusManager::MoveFocus(mozIDOMWindowP
   // the other focus methods is already set, or we're just moving to the root
   // or caret position.
   if (aType != MOVEFOCUS_ROOT && aType != MOVEFOCUS_CARET &&
       (aFlags & FOCUSMETHOD_MASK) == 0) {
     aFlags |= FLAG_BYMOVEFOCUS;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> window;
-  nsCOMPtr<nsIContent> startContent;
   if (aStartElement) {
-    startContent = do_QueryInterface(aStartElement);
-    NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG);
-
-    window = GetCurrentWindow(startContent);
+    window = GetCurrentWindow(aStartElement);
   } else {
     window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get();
   }
 
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
   bool noParentTraversal = aFlags & FLAG_NOPARENTFRAME;
   nsCOMPtr<nsIContent> newFocus;
-  nsresult rv = DetermineElementToMoveFocus(window, startContent, aType, noParentTraversal,
+  nsresult rv = DetermineElementToMoveFocus(window, aStartElement, aType, noParentTraversal,
                                             getter_AddRefs(newFocus));
   if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
     return NS_OK;
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOGCONTENTNAVIGATION("Element to be focused: %s", newFocus.get());
 
-  if (newFocus) {
+  if (newFocus && newFocus->IsElement()) {
     // for caret movement, pass false for the aFocusChanged argument,
     // otherwise the caret will end up moving to the focus position. This
     // would be a problem because the caret would move to the beginning of the
     // focused link making it impossible to navigate the caret over a link.
-    SetFocusInner(newFocus, aFlags, aType != MOVEFOCUS_CARET, true);
-    CallQueryInterface(newFocus, aElement);
+    SetFocusInner(newFocus->AsElement(), aFlags, aType != MOVEFOCUS_CARET,
+                  true);
+    *aElement = do_AddRef(newFocus->AsElement()).take();
   }
   else if (aType == MOVEFOCUS_ROOT || aType == MOVEFOCUS_CARET) {
     // no content was found, so clear the focus for these two types.
     ClearFocus(window);
   }
 
   LOGFOCUS(("<<MoveFocus end>>"));
 
@@ -761,17 +755,17 @@ nsFocusManager::WindowRaised(mozIDOMWind
   // Events for child process windows will be sent when ParentActivated
   // is called.
   if (XRE_IsParentProcess()) {
     ActivateOrDeactivate(window, true);
   }
 
   // retrieve the last focused element within the window that was raised
   nsCOMPtr<nsPIDOMWindowOuter> currentWindow;
-  nsCOMPtr<nsIContent> currentFocus =
+  RefPtr<Element> currentFocus =
     GetFocusedDescendant(window, eIncludeAllDescendants,
                          getter_AddRefs(currentWindow));
 
   NS_ASSERTION(currentWindow, "window raised with no window current");
   if (!currentWindow)
     return NS_OK;
 
   // If there is no nsIXULWindow, then this is an embedded or child process window.
@@ -935,17 +929,17 @@ nsFocusManager::WindowShown(mozIDOMWindo
     }
   }
 
   if (mFocusedWindow != window)
     return NS_OK;
 
   if (aNeedsFocus) {
     nsCOMPtr<nsPIDOMWindowOuter> currentWindow;
-    nsCOMPtr<nsIContent> currentFocus =
+    RefPtr<Element> currentFocus =
       GetFocusedDescendant(window, eIncludeAllDescendants,
                            getter_AddRefs(currentWindow));
     if (currentWindow)
       Focus(currentWindow, currentFocus, 0, true, false, false, true);
   }
   else {
     // Sometimes, an element in a window can be focused before the window is
     // visible, which would mean that the widget may not be properly focused.
@@ -1100,20 +1094,20 @@ nsFocusManager::FireDelayedEvents(nsIDoc
       }
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFocusManager::FocusPlugin(nsIContent* aContent)
+nsFocusManager::FocusPlugin(Element* aPlugin)
 {
-  NS_ENSURE_ARG(aContent);
-  SetFocusInner(aContent, 0, true, false);
+  NS_ENSURE_ARG(aPlugin);
+  SetFocusInner(aPlugin, 0, true, false);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFocusManager::ParentActivated(mozIDOMWindowProxy* aWindow, bool aActive)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
@@ -1224,21 +1218,21 @@ nsFocusManager::ActivateOrDeactivate(nsP
   }
 
   // Look for any remote child frames, iterate over them and send the activation notification.
   nsContentUtils::CallOnAllRemoteChildren(aWindow, ActivateOrDeactivateChild,
                                           (void *)aActive);
 }
 
 void
-nsFocusManager::SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
+nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags,
                               bool aFocusChanged, bool aAdjustWidget)
 {
   // if the element is not focusable, just return and leave the focus as is
-  nsCOMPtr<nsIContent> contentToFocus = CheckIfFocusable(aNewContent, aFlags);
+  RefPtr<Element> contentToFocus = CheckIfFocusable(aNewContent, aFlags);
   if (!contentToFocus)
     return;
 
   // check if the element to focus is a frame (iframe) containing a child
   // document. Frames are never directly focused; instead focusing a frame
   // means focus what is inside the frame. To do this, the descendant content
   // within the frame is retrieved and that will be focused instead.
   nsCOMPtr<nsPIDOMWindowOuter> newWindow;
@@ -1370,17 +1364,17 @@ nsFocusManager::SetFocusInner(nsIContent
 
   LOGCONTENT("Shift Focus: %s", contentToFocus.get());
   LOGFOCUS((" Flags: %x Current Window: %p New Window: %p Current Element: %p",
            aFlags, mFocusedWindow.get(), newWindow.get(), mFocusedContent.get()));
   LOGFOCUS((" In Active Window: %d In Focused Window: %d SendFocus: %d",
            isElementInActiveWindow, isElementInFocusedWindow, sendFocusEvent));
 
   if (sendFocusEvent) {
-    nsCOMPtr<nsIContent> oldFocusedContent = mFocusedContent;
+    RefPtr<Element> oldFocusedContent = mFocusedContent;
     // return if blurring fails or the focus changes during the blur
     if (mFocusedWindow) {
       // if the focus is being moved to another element in the same document,
       // or to a descendant, pass the existing window to Blur so that the
       // current node in the existing window is cleared. If moving to a
       // window elsewhere, we want to maintain the current node in the
       // window but still blur it.
       bool currentIsSameOrAncestor = IsSameOrAncestor(mFocusedWindow, newWindow);
@@ -1579,27 +1573,28 @@ nsFocusManager::IsNonFocusableRoot(nsICo
   // And in userfocusignored context nothing is focusable.
   nsIDocument* doc = aContent->GetComposedDoc();
   NS_ASSERTION(doc, "aContent must have current document");
   return aContent == doc->GetRootElement() &&
            (doc->HasFlag(NODE_IS_EDITABLE) || !aContent->IsEditable() ||
             nsContentUtils::IsUserFocusIgnored(aContent));
 }
 
-nsIContent*
-nsFocusManager::CheckIfFocusable(nsIContent* aContent, uint32_t aFlags)
+Element*
+nsFocusManager::CheckIfFocusable(Element* aContent, uint32_t aFlags)
 {
   if (!aContent)
     return nullptr;
 
   // this is a special case for some XUL elements or input number, where an
   // anonymous child is actually focusable and not the element itself.
-  nsCOMPtr<nsIContent> redirectedFocus = GetRedirectedFocus(aContent);
-  if (redirectedFocus)
+  RefPtr<Element> redirectedFocus = GetRedirectedFocus(aContent);
+  if (redirectedFocus) {
     return CheckIfFocusable(redirectedFocus, aFlags);
+  }
 
   nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc();
   // can't focus elements that are not in documents
   if (!doc) {
     LOGCONTENT("Cannot focus %s because content not in document", aContent)
     return nullptr;
   }
 
@@ -1609,18 +1604,19 @@ nsFocusManager::CheckIfFocusable(nsICont
   doc->FlushPendingNotifications(FlushType::EnsurePresShellInitAndFrames);
 
   nsIPresShell *shell = doc->GetShell();
   if (!shell)
     return nullptr;
 
   // the root content can always be focused,
   // except in userfocusignored context.
-  if (aContent == doc->GetRootElement())
+  if (aContent == doc->GetRootElement()) {
     return nsContentUtils::IsUserFocusIgnored(aContent) ? nullptr : aContent;
+  }
 
   // cannot focus content in print preview mode. Only the root can be focused.
   nsPresContext* presContext = shell->GetPresContext();
   if (presContext && presContext->Type() == nsPresContext::eContext_PrintPreview) {
     LOGCONTENT("Cannot focus %s while in print preview", aContent)
     return nullptr;
   }
 
@@ -1658,17 +1654,17 @@ nsFocusManager::Blur(nsPIDOMWindowOuter*
                      nsPIDOMWindowOuter* aAncestorWindowToFocus,
                      bool aIsLeavingDocument,
                      bool aAdjustWidgets,
                      nsIContent* aContentToFocus)
 {
   LOGFOCUS(("<<Blur begin>>"));
 
   // hold a reference to the focused content, which may be null
-  nsCOMPtr<nsIContent> content = mFocusedContent;
+  RefPtr<Element> content = mFocusedContent;
   if (content) {
     if (!content->IsInComposedDoc()) {
       mFocusedContent = nullptr;
       return true;
     }
     if (content == mFirstBlurEvent)
       return true;
   }
@@ -1833,17 +1829,17 @@ nsFocusManager::Blur(nsPIDOMWindowOuter*
   if (clearFirstBlurEvent)
     mFirstBlurEvent = nullptr;
 
   return result;
 }
 
 void
 nsFocusManager::Focus(nsPIDOMWindowOuter* aWindow,
-                      nsIContent* aContent,
+                      Element* aContent,
                       uint32_t aFlags,
                       bool aIsNewDocument,
                       bool aFocusChanged,
                       bool aWindowRaised,
                       bool aAdjustWidgets,
                       nsIContent* aContentLostFocus)
 {
   LOGFOCUS(("<<Focus begin>>"));
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -10,28 +10,30 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIFocusManager.h"
 #include "nsIObserver.h"
 #include "nsIWidget.h"
 #include "nsWeakReference.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/RefPtr.h"
 
 #define FOCUSMETHOD_MASK 0xF000
 #define FOCUSMETHODANDRING_MASK 0xF0F000
 
 #define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1"
 
 class nsIContent;
 class nsIDocShellTreeItem;
 class nsPIDOMWindowOuter;
 
 namespace mozilla {
 namespace dom {
+class Element;
 class TabParent;
 }
 }
 
 struct nsDelayedBlurOrFocusEvent;
 
 /**
  * The focus manager keeps track of where the focus is, that is, the node
@@ -57,20 +59,20 @@ public:
 
   /**
    * Retrieve the single focus manager.
    */
   static nsFocusManager* GetFocusManager() { return sInstance; }
 
   /**
    * A faster version of nsIFocusManager::GetFocusedElement, returning a
-   * raw nsIContent pointer (instead of having AddRef-ed nsIDOMElement
+   * raw Element pointer (instead of having AddRef-ed nsIDOMElement
    * pointer filled in to an out-parameter).
    */
-  nsIContent* GetFocusedContent() { return mFocusedContent; }
+  mozilla::dom::Element* GetFocusedContent() { return mFocusedContent; }
 
   /**
    * Returns true if aContent currently has focus.
    */
   bool IsFocused(nsIContent* aContent);
 
   /**
    * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
@@ -93,19 +95,19 @@ public:
   already_AddRefed<nsIDocument>
     SetMouseButtonHandlingDocument(nsIDocument* aDocument)
   {
     nsCOMPtr<nsIDocument> handlingDocument = mMouseButtonEventHandlingDocument;
     mMouseButtonEventHandlingDocument = aDocument;
     return handlingDocument.forget();
   }
 
-  void NeedsFlushBeforeEventHandling(nsIContent* aContent)
+  void NeedsFlushBeforeEventHandling(mozilla::dom::Element* aElement)
   {
-    if (mFocusedContent == aContent) {
+    if (mFocusedContent == aElement) {
       mEventHandlingNeedsFlush = true;
     }
   }
 
   bool CanSkipFocus(nsIContent* aContent);
 
   void FlushBeforeEventHandlingIfNeeded(nsIContent* aContent)
   {
@@ -137,31 +139,32 @@ public:
   {
     // Return focused content in aWindow.  So, aFocusedWindow is always aWindow.
     eOnlyCurrentWindow,
     // Return focused content in aWindow or one of all sub windows.
     eIncludeAllDescendants,
     // Return focused content in aWindow or one of visible sub windows.
     eIncludeVisibleDescendants,
   };
-  static nsIContent* GetFocusedDescendant(nsPIDOMWindowOuter* aWindow,
-                                          SearchRange aSearchRange,
-                                          nsPIDOMWindowOuter** aFocusedWindow);
+  static mozilla::dom::Element*
+  GetFocusedDescendant(nsPIDOMWindowOuter* aWindow,
+                       SearchRange aSearchRange,
+                       nsPIDOMWindowOuter** aFocusedWindow);
 
   /**
    * Returns the content node that focus will be redirected to if aContent was
    * focused. This is used for the special case of certain XUL elements such
    * as textboxes or input number which redirect focus to an anonymous child.
    *
    * aContent must be non-null.
    *
    * XXXndeakin this should be removed eventually but I want to do that as
    * followup work.
    */
-  static nsIContent* GetRedirectedFocus(nsIContent* aContent);
+  static mozilla::dom::Element* GetRedirectedFocus(nsIContent* aContent);
 
   /**
    * Returns an InputContextAction cause for aFlags.
    */
   static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
 
   static bool sMouseFocusesFormControl;
 
@@ -188,17 +191,17 @@ protected:
    * true, then the focus has actually shifted and the caret position will be
    * updated to the new focus, aNewContent will be scrolled into view (unless
    * a flag disables this) and the focus method for the window will be updated.
    * If aAdjustWidget is false, don't change the widget focus state.
    *
    * All actual focus changes must use this method to do so. (as opposed
    * to those that update the focus in an inactive window for instance).
    */
-  void SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
+  void SetFocusInner(mozilla::dom::Element* aNewContent, int32_t aFlags,
                      bool aFocusChanged, bool aAdjustWidget);
 
   /**
    * Returns true if aPossibleAncestor is the same as aWindow or an
    * ancestor of aWindow.
    */
   bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
                         nsPIDOMWindowOuter* aWindow);
@@ -239,17 +242,18 @@ protected:
    * methods.
    *
    * An element is focusable if it is in a document, the document isn't in
    * print preview mode and the element has an nsIFrame where the
    * CheckIfFocusable method returns true. For <area> elements, there is no
    * frame, so only the IsFocusable method on the content node must be
    * true.
    */
-  nsIContent* CheckIfFocusable(nsIContent* aContent, uint32_t aFlags);
+  mozilla::dom::Element* CheckIfFocusable(mozilla::dom::Element* aContent,
+                                          uint32_t aFlags);
 
   /**
    * Blurs the currently focused element. Returns false if another element was
    * focused as a result. This would mean that the caller should not proceed
    * with a pending call to Focus. Normally, true would be returned.
    *
    * The currently focused element within aWindowToClear will be cleared.
    * aWindowToClear may be null, which means that no window is cleared. This
@@ -297,17 +301,17 @@ protected:
    * raised.
    *
    * aWindowRaised should be true if the window is being raised. In this case,
    * command updaters will not be called.
    *
    * If aAdjustWidget is false, don't change the widget focus state.
    */
   void Focus(nsPIDOMWindowOuter* aWindow,
-             nsIContent* aContent,
+             mozilla::dom::Element* aContent,
              uint32_t aFlags,
              bool aIsNewDocument,
              bool aFocusChanged,
              bool aWindowRaised,
              bool aAdjustWidget,
              nsIContent* aContentLostFocus = nullptr);
 
   /**
@@ -636,17 +640,17 @@ private:
   // the child or top-level window that is currently focused. This window will
   // either be the same window as mActiveWindow or a descendant of it.
   // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
   nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow;
 
   // the currently focused content, which is always inside mFocusedWindow. This
   // is a cached copy of the mFocusedWindow's current content. This may be null
   // if no content is focused.
-  nsCOMPtr<nsIContent> mFocusedContent;
+  RefPtr<mozilla::dom::Element> mFocusedContent;
 
   // these fields store a content node temporarily while it is being focused
   // or blurred to ensure that a recursive call doesn't refire the same event.
   // They will always be cleared afterwards.
   nsCOMPtr<nsIContent> mFirstBlurEvent;
   nsCOMPtr<nsIContent> mFirstFocusEvent;
 
   // keep track of a window while it is being lowered
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -838,17 +838,18 @@ nsFrameLoader::Show(int32_t marginWidth,
 
   // Trigger editor re-initialization if midas is turned on in the
   // sub-document. This shouldn't be necessary, but given the way our
   // editor works, it is. See
   // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
   presShell = mDocShell->GetPresShell();
   if (presShell) {
     nsIDocument* doc = presShell->GetDocument();
-    nsHTMLDocument* htmlDoc = doc ? doc->AsHTMLDocument() : nullptr;
+    nsHTMLDocument* htmlDoc =
+      doc && doc->IsHTMLOrXHTML() ? doc->AsHTMLDocument() : nullptr;
 
     if (htmlDoc) {
       nsAutoString designMode;
       htmlDoc->GetDesignMode(designMode);
 
       if (designMode.EqualsLiteral("on")) {
         // Hold on to the editor object to let the document reattach to the
         // same editor object, instead of creating a new one.
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -236,17 +236,17 @@ nsSelectionCommandsBase::GetSelectionCon
 
 // Helpers for nsSelectMoveScrollCommand and nsPhysicalSelectMoveScrollCommand
 static void
 AdjustFocusAfterCaretMove(nsPIDOMWindowOuter* aWindow)
 {
   // adjust the focus to the new caret position
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
-    nsCOMPtr<nsIDOMElement> result;
+    RefPtr<dom::Element> result;
     fm->MoveFocus(aWindow, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
                   nsIFocusManager::FLAG_NOSCROLL, getter_AddRefs(result));
   }
 }
 
 static bool
 IsCaretOnInWindow(nsPIDOMWindowOuter* aWindow, nsISelectionController* aSelCont)
 {
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -4647,17 +4647,17 @@ static bool ShouldShowFocusRingIfFocused
   if (!aNode) {
     return true;
   }
   return !nsContentUtils::ContentIsLink(aNode) &&
     !aNode->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio);
 }
 
 void
-nsGlobalWindowInner::SetFocusedNode(nsIContent* aNode,
+nsGlobalWindowInner::SetFocusedNode(Element* aNode,
                                     uint32_t aFocusMethod,
                                     bool aNeedsFocus)
 {
   if (aNode && aNode->GetComposedDoc() != mDoc) {
     NS_WARNING("Trying to set focus to a node from a wrong document");
     return;
   }
 
@@ -5229,20 +5229,18 @@ nsGlobalWindowInner::FireOfflineStatusEv
   if (mWasOffline) {
     name.AssignLiteral("offline");
   } else {
     name.AssignLiteral("online");
   }
   // The event is fired at the body element, or if there is no body element,
   // at the document.
   nsCOMPtr<EventTarget> eventTarget = mDoc.get();
-  nsHTMLDocument* htmlDoc = mDoc->AsHTMLDocument();
-  if (htmlDoc) {
-    Element* body = htmlDoc->GetBody();
-    if (body) {
+  if (mDoc->IsHTMLOrXHTML()) {
+    if (Element* body = mDoc->GetBody()) {
       eventTarget = body;
     }
   } else {
     Element* documentElement = mDoc->GetDocumentElement();
     if (documentElement) {
       eventTarget = documentElement;
     }
   }
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -1192,17 +1192,17 @@ public:
 
   bool IsFrame();
 
   already_AddRefed<nsIWidget> GetMainWidget();
   nsIWidget* GetNearestWidget() const;
 
   bool IsInModalState();
 
-  virtual void SetFocusedNode(nsIContent* aNode,
+  virtual void SetFocusedNode(mozilla::dom::Element* aNode,
                               uint32_t aFocusMethod = 0,
                               bool aNeedsFocus = false) override;
 
   virtual uint32_t GetFocusMethod() override;
 
   virtual bool ShouldShowFocusRing() override;
 
   // Inner windows only.
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -4823,23 +4823,22 @@ nsGlobalWindowOuter::FocusOuter(ErrorRes
   nsCOMPtr<nsPIDOMWindowOuter> parent =
     parentDsti ? parentDsti->GetWindow() : nullptr;
   if (parent) {
     nsCOMPtr<nsIDocument> parentdoc = parent->GetDoc();
     if (!parentdoc) {
       return;
     }
 
-    nsIContent* frame = parentdoc->FindContentForSubDocument(mDoc);
-    nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
-    if (frameElement) {
+    RefPtr<Element> frame = parentdoc->FindContentForSubDocument(mDoc);
+    if (frame) {
       uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
       if (canFocus)
         flags |= nsIFocusManager::FLAG_RAISE;
-      aError = fm->SetFocus(frameElement, flags);
+      aError = fm->SetFocus(frame, flags);
     }
     return;
   }
 
   if (canFocus) {
     // if there is no parent, this must be a toplevel window, so raise the
     // window if canFocus is true. If this is a child process, the raise
     // window request will get forwarded to the parent by the puppet widget.
@@ -6294,24 +6293,26 @@ nsGlobalWindowOuter::UpdateCommands(cons
   }
 
   nsPIDOMWindowOuter *rootWindow = GetPrivateRoot();
   if (!rootWindow) {
     return;
   }
 
   nsIDocument* doc = rootWindow->GetExtantDoc();
-  XULDocument* xulDoc = doc ? doc->AsXULDocument() : nullptr;
   // See if we contain a XUL document.
+  if (!doc || !doc->IsXULDocument()) {
+    return;
+  }
   // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
   // XUL command dispatch if anAction is "selectionchange".
-  if (xulDoc && !anAction.EqualsLiteral("selectionchange")) {
+  if (!anAction.EqualsLiteral("selectionchange")) {
     // Retrieve the command dispatcher and call updateCommands on it.
     nsIDOMXULCommandDispatcher* xulCommandDispatcher =
-      xulDoc->GetCommandDispatcher();
+      doc->AsXULDocument()->GetCommandDispatcher();
     if (xulCommandDispatcher) {
       nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
                                                             anAction));
     }
   }
 }
 
 Selection*
@@ -6620,17 +6621,17 @@ nsGlobalWindowOuter::SetChromeEventHandl
     inner = static_cast<nsGlobalWindowInner*>(node);
     NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
                  "bad outer window pointer");
     inner->SetChromeEventHandlerInternal(aChromeEventHandler);
   }
 }
 
 void
-nsGlobalWindowOuter::SetFocusedNode(nsIContent* aNode,
+nsGlobalWindowOuter::SetFocusedNode(Element* aNode,
                                     uint32_t aFocusMethod,
                                     bool aNeedsFocus)
 {
   FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
 }
 
 uint32_t
 nsGlobalWindowOuter::GetFocusMethod()
@@ -6672,23 +6673,22 @@ nsGlobalWindowOuter::SetKeyboardIndicato
 
   nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),
                                                         aShowAccelerators,
                                                         aShowFocusRings);
 
   bool newShouldShowFocusRing = ShouldShowFocusRing();
   if (mInnerWindow && nsGlobalWindowInner::Cast(mInnerWindow)->mHasFocus &&
       mInnerWindow->mFocusedNode &&
-      oldShouldShowFocusRing != newShouldShowFocusRing &&
-      mInnerWindow->mFocusedNode->IsElement()) {
+      oldShouldShowFocusRing != newShouldShowFocusRing) {
     // Update focusedNode's state.
     if (newShouldShowFocusRing) {
-      mInnerWindow->mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
+      mInnerWindow->mFocusedNode->AddStates(NS_EVENT_STATE_FOCUSRING);
     } else {
-      mInnerWindow->mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
+      mInnerWindow->mFocusedNode->RemoveStates(NS_EVENT_STATE_FOCUSRING);
     }
   }
 }
 
 bool
 nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod)
 {
   FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
@@ -7253,21 +7253,22 @@ nsGlobalWindowOuter::RestoreWindowState(
   printf("restoring window state, state = %p\n", (void*)holder);
 #endif
 
   // And we're ready to go!
   nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
 
   // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
   // it easy to tell which link was last clicked when going back a page.
-  nsIContent* focusedNode = inner->GetFocusedNode();
+  Element* focusedNode = inner->GetFocusedNode();
   if (nsContentUtils::ContentIsLink(focusedNode)) {
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
-      nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
+      // XXXbz Do we need the stack strong ref here?
+      RefPtr<Element> focusedElement = focusedNode;
       fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
                                    nsIFocusManager::FLAG_SHOWRING);
     }
   }
 
   inner->Thaw();
 
   holder->DidRestoreWindow();
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -974,17 +974,17 @@ public:
   // Convenience functions for the many methods that need to scale
   // from device to CSS pixels or vice versa.  Note: if a presentation
   // context is not available, they will assume a 1:1 ratio.
   int32_t DevToCSSIntPixels(int32_t px);
   int32_t CSSToDevIntPixels(int32_t px);
   nsIntSize DevToCSSIntPixels(nsIntSize px);
   nsIntSize CSSToDevIntPixels(nsIntSize px);
 
-  virtual void SetFocusedNode(nsIContent* aNode,
+  virtual void SetFocusedNode(mozilla::dom::Element* aNode,
                               uint32_t aFocusMethod = 0,
                               bool aNeedsFocus = false) override;
 
   virtual uint32_t GetFocusMethod() override;
 
   virtual bool ShouldShowFocusRing() override;
 
   virtual void SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3342,19 +3342,33 @@ public:
   already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
 
   mozilla::dom::Promise* GetDocumentReadyForIdle(mozilla::ErrorResult& aRv);
 
   // ParentNode
   nsIHTMLCollection* Children();
   uint32_t ChildElementCount();
 
-  virtual nsHTMLDocument* AsHTMLDocument() { return nullptr; }
-  virtual mozilla::dom::SVGDocument* AsSVGDocument() { return nullptr; }
-  virtual mozilla::dom::XULDocument* AsXULDocument() { return nullptr; }
+  /**
+   * Asserts IsHTMLOrXHTML, and can't return null.
+   * Defined inline in nsHTMLDocument.h
+   */
+  inline nsHTMLDocument* AsHTMLDocument();
+
+  /**
+   * Asserts IsSVGDocument, and can't return null.
+   * Defined inline in SVGDocument.h
+   */
+  inline mozilla::dom::SVGDocument* AsSVGDocument();
+
+  /**
+   * Asserts IsXULDocument, and can't return null.
+   * Defined inline in XULDocument.h
+   */
+  inline mozilla::dom::XULDocument* AsXULDocument();
 
   /*
    * Given a node, get a weak reference to it and append that reference to
    * mBlockedTrackingNodes. Can be used later on to look up a node in it.
    * (e.g., by the UI)
    */
   void AddBlockedTrackingNode(nsINode *node)
   {
--- a/dom/base/nsIStyleSheetLinkingElement.h
+++ b/dom/base/nsIStyleSheetLinkingElement.h
@@ -4,26 +4,86 @@
  * 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 nsIStyleSheetLinkingElement_h__
 #define nsIStyleSheetLinkingElement_h__
 
 
 #include "nsISupports.h"
 #include "mozilla/StyleSheet.h"
+#include "mozilla/Result.h"
 
 class nsICSSLoaderObserver;
 class nsIURI;
 
 #define NS_ISTYLESHEETLINKINGELEMENT_IID          \
 { 0xa8b79f3b, 0x9d18, 0x4f9c, \
   { 0xb1, 0xaa, 0x8c, 0x9b, 0x1b, 0xaa, 0xac, 0xad } }
 
 class nsIStyleSheetLinkingElement : public nsISupports {
 public:
+  enum class ForceUpdate
+  {
+    Yes,
+    No,
+  };
+
+  enum class IsAlternate
+  {
+    Yes,
+    No,
+  };
+
+  enum class Completed
+  {
+    Yes,
+    No,
+  };
+
+  enum class MediaMatched
+  {
+    Yes,
+    No,
+  };
+
+  struct Update
+  {
+  private:
+    bool mWillNotify;
+    bool mIsAlternate;
+    bool mMediaMatched;
+
+  public:
+    Update()
+      : mWillNotify(false)
+      , mIsAlternate(false)
+      , mMediaMatched(false)
+    { }
+
+    Update(Completed aCompleted, IsAlternate aIsAlternate, MediaMatched aMediaMatched)
+      : mWillNotify(aCompleted == Completed::No)
+      , mIsAlternate(aIsAlternate == IsAlternate::Yes)
+      , mMediaMatched(aMediaMatched == MediaMatched::Yes)
+    { }
+
+    bool WillNotify() const
+    {
+      return mWillNotify;
+    }
+
+    bool ShouldBlock() const
+    {
+      if (!mWillNotify) {
+        return false;
+      }
+
+      return !mIsAlternate && mMediaMatched;
+    }
+  };
+
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISTYLESHEETLINKINGELEMENT_IID)
 
   /**
    * Used to make the association between a style sheet and
    * the element that linked it to the document.
    *
    * @param aStyleSheet the style sheet associated with this
    *                    element.
@@ -45,31 +105,22 @@ public:
    */
   virtual void InitStyleLinkElement(bool aDontLoadStyle) = 0;
 
   /**
    * Tells this element to update the stylesheet.
    *
    * @param aObserver    observer to notify once the stylesheet is loaded.
    *                     This will be passed to the CSSLoader
-   * @param [out] aWillNotify whether aObserver will be notified when the sheet
-   *                          loads.  If this is false, then either we didn't
-   *                          start the sheet load at all, the load failed, or
-   *                          this was an inline sheet that completely finished
-   *                          loading.  In the case when the load failed the
-   *                          failure code will be returned.
-   * @param [out] whether the sheet is an alternate sheet.  This value is only
-   *              meaningful if aWillNotify is true.
    * @param aForceUpdate whether we wand to force the update, flushing the
    *                     cached version if any.
    */
-  virtual nsresult UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                                    bool *aWillNotify,
-                                    bool *aIsAlternate,
-                                    bool aForceUpdate = false) = 0;
+  virtual mozilla::Result<Update, nsresult>
+    UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
+                     ForceUpdate = ForceUpdate::No) = 0;
 
   /**
    * Tells this element whether to update the stylesheet when the
    * element's properties change.
    *
    * @param aEnableUpdates update on changes or not.
    */
   virtual void SetEnableUpdates(bool aEnableUpdates) = 0;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -479,18 +479,18 @@ public:
   /*
    * Get and set the currently focused element within the document. If
    * aNeedsFocus is true, then set mNeedsFocus to true to indicate that a
    * document focus event is needed.
    *
    * DO NOT CALL EITHER OF THESE METHODS DIRECTLY. USE THE FOCUS MANAGER
    * INSTEAD.
    */
-  inline nsIContent* GetFocusedNode() const;
-  virtual void SetFocusedNode(nsIContent* aNode,
+  inline mozilla::dom::Element* GetFocusedNode() const;
+  virtual void SetFocusedNode(mozilla::dom::Element* aNode,
                               uint32_t aFocusMethod = 0,
                               bool aNeedsFocus = false) = 0;
 
   /**
    * Retrieves the method that was used to focus the current node.
    */
   virtual uint32_t GetFocusMethod() = 0;
 
@@ -654,18 +654,18 @@ protected:
   bool mMayHavePointerEnterLeaveEventListener;
 
   bool mAudioCaptured;
 
   // Our inner window's outer window.
   nsCOMPtr<nsPIDOMWindowOuter> mOuterWindow;
 
   // the element within the document that is currently focused when this
-  // window is active
-  nsCOMPtr<nsIContent> mFocusedNode;
+  // window is active.
+  RefPtr<mozilla::dom::Element> mFocusedNode;
 
   // The AudioContexts created for the current document, if any.
   nsTArray<mozilla::dom::AudioContext*> mAudioContexts; // Weak
 
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
 
   // A unique (as long as our 64-bit counter doesn't roll over) id for
   // this window.
@@ -968,18 +968,18 @@ public:
   /*
    * Get and set the currently focused element within the document. If
    * aNeedsFocus is true, then set mNeedsFocus to true to indicate that a
    * document focus event is needed.
    *
    * DO NOT CALL EITHER OF THESE METHODS DIRECTLY. USE THE FOCUS MANAGER
    * INSTEAD.
    */
-  inline nsIContent* GetFocusedNode() const;
-  virtual void SetFocusedNode(nsIContent* aNode,
+  inline mozilla::dom::Element* GetFocusedNode() const;
+  virtual void SetFocusedNode(mozilla::dom::Element* aNode,
                               uint32_t aFocusMethod = 0,
                               bool aNeedsFocus = false) = 0;
 
   /**
    * Retrieves the method that was used to focus the current node.
    */
   virtual uint32_t GetFocusMethod() = 0;
 
--- a/dom/base/nsPIDOMWindowInlines.h
+++ b/dom/base/nsPIDOMWindowInlines.h
@@ -84,19 +84,19 @@ nsPIDOMWindowOuter::GetDocShell() const
 }
 
 nsIDocShell*
 nsPIDOMWindowInner::GetDocShell() const
 {
   return mOuterWindow ? mOuterWindow->GetDocShell() : nullptr;
 }
 
-nsIContent*
+mozilla::dom::Element*
 nsPIDOMWindowOuter::GetFocusedNode() const
 {
   return mInnerWindow ? mInnerWindow->GetFocusedNode() : nullptr;
 }
 
-nsIContent*
+mozilla::dom::Element*
 nsPIDOMWindowInner::GetFocusedNode() const
 {
   return mFocusedNode;
 }
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -171,73 +171,65 @@ uint32_t nsStyleLinkElement::ParseLinkTy
   }
   if (inString) {
     nsContentUtils::ASCIIToLower(Substring(start, current), subString);
     linkMask |= ToLinkMask(subString);
   }
   return linkMask;
 }
 
-nsresult
+Result<nsStyleLinkElement::Update, nsresult>
 nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                                     bool* aWillNotify,
-                                     bool* aIsAlternate,
-                                     bool aForceReload)
+                                     ForceUpdate aForceUpdate)
 {
-  if (aForceReload) {
+  if (aForceUpdate == ForceUpdate::Yes) {
     // We remove this stylesheet from the cache to load a new version.
     nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
       thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
     if (doc && doc->CSSLoader()->GetEnabled() &&
         mStyleSheet && !mStyleSheet->IsInline()) {
       doc->CSSLoader()->ObsoleteSheet(mStyleSheet->GetOriginalURI());
     }
   }
-  return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aWillNotify,
-                            aIsAlternate, aForceReload);
+  return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aForceUpdate);
 }
 
-nsresult
-nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
-                                             ShadowRoot *aOldShadowRoot,
-                                             bool aForceUpdate)
+Result<nsStyleLinkElement::Update, nsresult>
+nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument* aOldDocument,
+                                             ShadowRoot* aOldShadowRoot,
+                                             ForceUpdate aForceUpdate)
 {
-  bool notify, alternate;
-  return DoUpdateStyleSheet(aOldDocument, aOldShadowRoot, nullptr, &notify,
-                            &alternate, aForceUpdate);
+  return DoUpdateStyleSheet(
+    aOldDocument, aOldShadowRoot, nullptr, aForceUpdate);
 }
 
-nsresult
+Result<nsStyleLinkElement::Update, nsresult>
 nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
                                        ShadowRoot* aOldShadowRoot,
                                        nsICSSLoaderObserver* aObserver,
-                                       bool* aWillNotify,
-                                       bool* aIsAlternate,
-                                       bool aForceUpdate)
+                                       ForceUpdate aForceUpdate)
 {
-  *aWillNotify = false;
-
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
   // All instances of nsStyleLinkElement should implement nsIContent.
   MOZ_ASSERT(thisContent);
 
   if (thisContent->IsInAnonymousSubtree() &&
       thisContent->IsAnonymousContentInSVGUseSubtree()) {
     // Stylesheets in <use>-cloned subtrees are disabled until we figure out
     // how they should behave.
-    return NS_OK;
+    return Update { };
   }
 
   // Check for a ShadowRoot because link elements are inert in a
   // ShadowRoot.
   ShadowRoot* containingShadow = thisContent->GetContainingShadow();
   if (thisContent->IsHTMLElement(nsGkAtoms::link) &&
       (aOldShadowRoot || containingShadow)) {
-    return NS_OK;
+    return Update { };
   }
 
   if (mStyleSheet && (aOldDocument || aOldShadowRoot)) {
     MOZ_ASSERT(!(aOldDocument && aOldShadowRoot),
                "ShadowRoot content is never in document, thus "
                "there should not be a old document and old "
                "ShadowRoot simultaneously.");
 
@@ -254,36 +246,35 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
     }
 
     nsStyleLinkElement::SetStyleSheet(nullptr);
   }
 
   // When static documents are created, stylesheets are cloned manually.
   if (mDontLoadStyle || !mUpdatesEnabled ||
       thisContent->OwnerDoc()->IsStaticDocument()) {
-    return NS_OK;
+    return Update { };
   }
 
   nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
     thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
   if (!doc || !doc->CSSLoader()->GetEnabled()) {
-    return NS_OK;
+    return Update { };
   }
 
   bool isInline;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline, getter_AddRefs(triggeringPrincipal));
 
-  if (!aForceUpdate && mStyleSheet && !isInline && uri) {
-    nsIURI* oldURI = mStyleSheet->GetSheetURI();
-    if (oldURI) {
+  if (aForceUpdate == ForceUpdate::No && mStyleSheet && !isInline && uri) {
+    if (nsIURI* oldURI = mStyleSheet->GetSheetURI()) {
       bool equal;
       nsresult rv = oldURI->Equals(uri, &equal);
       if (NS_SUCCEEDED(rv) && equal) {
-        return NS_OK; // We already loaded this stylesheet
+        return Update { };
       }
     }
   }
 
   if (mStyleSheet) {
     if (thisContent->IsInShadowTree()) {
       ShadowRoot* containingShadow = thisContent->GetContainingShadow();
       containingShadow->RemoveSheet(mStyleSheet);
@@ -292,90 +283,85 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
       doc->RemoveStyleSheet(mStyleSheet);
       doc->EndUpdate(UPDATE_STYLE);
     }
 
     nsStyleLinkElement::SetStyleSheet(nullptr);
   }
 
   if (!uri && !isInline) {
-    return NS_OK; // If href is empty and this is not inline style then just bail
+    // If href is empty and this is not inline style then just bail
+    return Update { };
   }
 
   nsAutoString title, type, media;
-  bool isAlternate;
-
-  GetStyleSheetInfo(title, type, media, &isAlternate);
-
+  bool hasAlternateRel;
+  GetStyleSheetInfo(title, type, media, &hasAlternateRel);
   if (!type.LowerCaseEqualsLiteral("text/css")) {
-    return NS_OK;
+    return Update { };
   }
 
-  bool doneLoading = false;
-  nsresult rv = NS_OK;
-
   // Load the link's referrerpolicy attribute. If the link does not provide a
   // referrerpolicy attribute, ignore this and use the document's referrer
   // policy
 
   net::ReferrerPolicy referrerPolicy = GetLinkReferrerPolicy();
   if (referrerPolicy == net::RP_Unset) {
     referrerPolicy = doc->GetReferrerPolicy();
   }
 
   if (isInline) {
     nsAutoString text;
     if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
-      return NS_ERROR_OUT_OF_MEMORY;
+      return Err(NS_ERROR_OUT_OF_MEMORY);
     }
 
+
     MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
                "<link> is not 'inline', and needs different CSP checks");
     MOZ_ASSERT(thisContent->IsElement());
+    nsresult rv = NS_OK;
     if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent->AsElement(),
                                            thisContent->NodePrincipal(),
                                            triggeringPrincipal,
                                            doc->GetDocumentURI(),
-                                           mLineNumber, text, &rv))
-      return rv;
-
-    // Parse the style sheet.
-    rv = doc->CSSLoader()->
-      LoadInlineStyle(thisContent, text, triggeringPrincipal, mLineNumber,
-                      title, media, referrerPolicy,
-                      aObserver, &doneLoading, &isAlternate);
-  } else {
-    nsAutoString integrity;
-    if (thisContent->IsElement()) {
-      thisContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
-                                        integrity);
-    }
-    if (!integrity.IsEmpty()) {
-      MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
-              ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
-               NS_ConvertUTF16toUTF8(integrity).get()));
+                                           mLineNumber, text, &rv)) {
+      if (NS_FAILED(rv)) {
+        return Err(rv);
+      }
+      return Update { };
     }
 
-    // XXXbz clone the URI here to work around content policies modifying URIs.
-    nsCOMPtr<nsIURI> clonedURI;
-    uri->Clone(getter_AddRefs(clonedURI));
-    NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
-    rv = doc->CSSLoader()->
-      LoadStyleLink(thisContent, clonedURI, triggeringPrincipal, title, media,
-                    isAlternate, GetCORSMode(), referrerPolicy, integrity,
-                    aObserver, &isAlternate);
-    if (NS_FAILED(rv)) {
-      // Don't propagate LoadStyleLink() errors further than this, since some
-      // consumers (e.g. nsXMLContentSink) will completely abort on innocuous
-      // things like a stylesheet load being blocked by the security system.
-      doneLoading = true;
-      isAlternate = false;
-      rv = NS_OK;
-    }
+    // Parse the style sheet.
+    return doc->CSSLoader()->
+      LoadInlineStyle(thisContent, text, triggeringPrincipal, mLineNumber,
+                      title, media, referrerPolicy,
+                      aObserver);
+  }
+  nsAutoString integrity;
+  if (thisContent->IsElement()) {
+    thisContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
+                                      integrity);
+  }
+  if (!integrity.IsEmpty()) {
+    MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
+            ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
+             NS_ConvertUTF16toUTF8(integrity).get()));
   }
-
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aWillNotify = !doneLoading;
-  *aIsAlternate = isAlternate;
-
-  return NS_OK;
+  auto resultOrError =
+    doc->CSSLoader()->LoadStyleLink(thisContent,
+                                    uri,
+                                    triggeringPrincipal,
+                                    title,
+                                    media,
+                                    hasAlternateRel,
+                                    GetCORSMode(),
+                                    referrerPolicy,
+                                    integrity,
+                                    aObserver);
+  if (resultOrError.isErr()) {
+    // Don't propagate LoadStyleLink() errors further than this, since some
+    // consumers (e.g. nsXMLContentSink) will completely abort on innocuous
+    // things like a stylesheet load being blocked by the security system.
+    return Update { };
+  }
+  return resultOrError;
 }
--- a/dom/base/nsStyleLinkElement.h
+++ b/dom/base/nsStyleLinkElement.h
@@ -11,16 +11,17 @@
  */
 
 #ifndef nsStyleLinkElement_h___
 #define nsStyleLinkElement_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/StyleSheetInlines.h"
+#include "mozilla/Unused.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "nsCOMPtr.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsTArray.h"
 
 class nsIDocument;
 class nsIURI;
 
@@ -40,26 +41,26 @@ public:
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override = 0;
 
   mozilla::StyleSheet* GetSheet() const { return mStyleSheet; }
 
   // nsIStyleSheetLinkingElement
   void SetStyleSheet(mozilla::StyleSheet* aStyleSheet) override;
   mozilla::StyleSheet* GetStyleSheet() override;
   void InitStyleLinkElement(bool aDontLoadStyle) override;
-  nsresult UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                            bool* aWillNotify,
-                            bool* aIsAlternate,
-                            bool aForceReload) override;
+
+  mozilla::Result<Update, nsresult>
+    UpdateStyleSheet(nsICSSLoaderObserver*, ForceUpdate) override;
+
   void SetEnableUpdates(bool aEnableUpdates) override;
   void GetCharset(nsAString& aCharset) override;
 
-  virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
-  virtual void SetLineNumber(uint32_t aLineNumber) override;
-  virtual uint32_t GetLineNumber() override;
+  void OverrideBaseURI(nsIURI* aNewBaseURI) override;
+  void SetLineNumber(uint32_t aLineNumber) override;
+  uint32_t GetLineNumber() override;
 
   enum RelValue {
     ePREFETCH =     0x00000001,
     eDNS_PREFETCH = 0x00000002,
     eSTYLESHEET =   0x00000004,
     eNEXT =         0x00000008,
     eALTERNATE =    0x00000010,
     ePRECONNECT =   0x00000020,
@@ -67,30 +68,35 @@ public:
     ePRELOAD =      0x00000080
   };
 
   // The return value is a bitwise or of 0 or more RelValues.
   static uint32_t ParseLinkTypes(const nsAString& aTypes);
 
   void UpdateStyleSheetInternal()
   {
-    UpdateStyleSheetInternal(nullptr, nullptr);
+    mozilla::Unused << UpdateStyleSheetInternal(nullptr, nullptr);
   }
 protected:
   /**
-   * @param aOldDocument should be non-null only if we're updating because we
-   *                     removed the node from the document.
+   * @param aOldDocument   should be non-null only if we're updating because we
+   *                       removed the node from the document.
+   * @param aOldShadowRoot should be non-null only if we're updating because we
+   *                       removed the node from a shadow tree.
    * @param aForceUpdate true will force the update even if the URI has not
    *                     changed.  This should be used in cases when something
    *                     about the content that affects the resulting sheet
    *                     changed but the URI may not have changed.
+   *
+   * TODO(emilio): Should probably pass a single DocumentOrShadowRoot.
    */
-  nsresult UpdateStyleSheetInternal(nsIDocument *aOldDocument,
-                                    mozilla::dom::ShadowRoot *aOldShadowRoot,
-                                    bool aForceUpdate = false);
+  mozilla::Result<Update, nsresult> UpdateStyleSheetInternal(
+      nsIDocument* aOldDocument,
+      mozilla::dom::ShadowRoot* aOldShadowRoot,
+      ForceUpdate = ForceUpdate::No);
 
   virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) = 0;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsAlternate) = 0;
 
   virtual mozilla::CORSMode GetCORSMode() const
@@ -116,22 +122,21 @@ private:
    *                     Passed as a parameter because on an update, the node
    *                     is removed from the tree before the sheet is removed
    *                     from the ShadowRoot.
    * @param aForceUpdate true will force the update even if the URI has not
    *                     changed.  This should be used in cases when something
    *                     about the content that affects the resulting sheet
    *                     changed but the URI may not have changed.
    */
-  nsresult DoUpdateStyleSheet(nsIDocument* aOldDocument,
-                              mozilla::dom::ShadowRoot* aOldShadowRoot,
-                              nsICSSLoaderObserver* aObserver,
-                              bool* aWillNotify,
-                              bool* aIsAlternate,
-                              bool aForceUpdate);
+  mozilla::Result<Update, nsresult>
+    DoUpdateStyleSheet(nsIDocument* aOldDocument,
+                       mozilla::dom::ShadowRoot* aOldShadowRoot,
+                       nsICSSLoaderObserver* aObserver,
+                       ForceUpdate);
 
   RefPtr<mozilla::StyleSheet> mStyleSheet;
 protected:
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mDontLoadStyle;
   bool mUpdatesEnabled;
   uint32_t mLineNumber;
 };
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -12,17 +12,17 @@ import argparse
 def generateLine(propName, extendedAttrs):
     return "  [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
                                                  propName)
 def generate(output, idlFilename, dataFile):
     with open(dataFile, "r") as f:
         propList = eval(f.read())
     props = ""
     for name, prop, id, flags, pref, proptype in propList:
-        if "CSS_PROPERTY_INTERNAL" in flags:
+        if "CSSPropFlags::Internal" in flags:
             continue
         # Unfortunately, even some of the getters here are fallible
         # (e.g. on nsComputedDOMStyle).
         extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
                          "SetterNeedsSubjectPrincipal=NonSystem"]
         if pref is not "":
             extendedAttrs.append('Pref="%s"' % pref)
 
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1078,45 +1078,45 @@ EventStateManager::LookForAccessKeyAndEx
 {
   int32_t count, start = -1;
   nsIContent* focusedContent = GetFocusedContent();
   if (focusedContent) {
     start = mAccessKeys.IndexOf(focusedContent);
     if (start == -1 && focusedContent->GetBindingParent())
       start = mAccessKeys.IndexOf(focusedContent->GetBindingParent());
   }
-  nsIContent *content;
+  RefPtr<Element> element;
   nsIFrame *frame;
   int32_t length = mAccessKeys.Count();
   for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
     uint32_t ch = aAccessCharCodes[i];
     nsAutoString accessKey;
     AppendUCS4ToUTF16(ch, accessKey);
     for (count = 1; count <= length; ++count) {
-      content = mAccessKeys[(start + count) % length];
-      frame = content->GetPrimaryFrame();
-      if (IsAccessKeyTarget(content, frame, accessKey)) {
+      // mAccessKeys always stores Element instances.
+      element = mAccessKeys[(start + count) % length]->AsElement();
+      frame = element->GetPrimaryFrame();
+      if (IsAccessKeyTarget(element, frame, accessKey)) {
         if (!aExecute) {
           return true;
         }
         bool shouldActivate = Prefs::KeyCausesActivation();
         while (shouldActivate && ++count <= length) {
           nsIContent *oc = mAccessKeys[(start + count) % length];
           nsIFrame *of = oc->GetPrimaryFrame();
           if (IsAccessKeyTarget(oc, of, accessKey))
             shouldActivate = false;
         }
 
         bool focusChanged = false;
         if (shouldActivate) {
-          focusChanged = content->PerformAccesskey(shouldActivate, aIsTrustedEvent);
+          focusChanged = element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
         } else {
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm) {
-            nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
             fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
             focusChanged = true;
           }
         }
 
         if (focusChanged && aIsTrustedEvent) {
           // If this is a child process, inform the parent that we want the focus, but
           // pass false since we don't want to change the window order.
@@ -3128,17 +3128,17 @@ EventStateManager::PostHandleKeyboardEve
           // Shift focus forward or back depending on shift key
           bool isDocMove =
             aKeyboardEvent->IsControl() || aKeyboardEvent->mKeyCode == NS_VK_F6;
           uint32_t dir = aKeyboardEvent->IsShift() ?
             (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC) :
                          static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD)) :
             (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARDDOC) :
                          static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD));
-          nsCOMPtr<nsIDOMElement> result;
+          RefPtr<Element> result;
           fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
                         nsIFocusManager::FLAG_BYKEY,
                         getter_AddRefs(result));
         }
       }
       return;
     case 0:
       // We handle keys with no specific keycode value below.
@@ -3303,16 +3303,18 @@ EventStateManager::PostHandleEvent(nsPre
           }
 
           int32_t tabIndexUnused;
           if (frame->IsFocusable(&tabIndexUnused, true)) {
             break;
           }
         }
 
+        MOZ_ASSERT_IF(newFocus, newFocus->IsElement());
+
         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
         if (fm) {
           // if something was found to focus, focus it. Otherwise, if the
           // element that was clicked doesn't have -moz-user-focus: ignore,
           // clear the existing focus. For -moz-user-focus: ignore, the focus
           // is just left as is.
           // Another effect of mouse clicking, handled in nsSelection, is that
           // it should update the caret position to where the mouse was
@@ -3324,18 +3326,17 @@ EventStateManager::PostHandleEvent(nsPre
             // doesn't unexpectedly scroll when clicking an element that is
             // only half visible
             uint32_t flags = nsIFocusManager::FLAG_BYMOUSE |
                              nsIFocusManager::FLAG_NOSCROLL;
             // If this was a touch-generated event, pass that information:
             if (mouseEvent->inputSource == MouseEventBinding::MOZ_SOURCE_TOUCH) {
               flags |= nsIFocusManager::FLAG_BYTOUCH;
             }
-            nsCOMPtr<nsIDOMElement> newFocusElement = do_QueryInterface(newFocus);
-            fm->SetFocus(newFocusElement, flags);
+            fm->SetFocus(newFocus->AsElement(), flags);
           }
           else if (!suppressBlur) {
             // clear the focus within the frame and then set it as the
             // focused frame
             EnsureDocument(mPresContext);
             if (mDocument) {
 #ifdef XP_MACOSX
               if (!activeContent || !activeContent->IsXULElement())
--- a/dom/html/HTMLHRElement.cpp
+++ b/dom/html/HTMLHRElement.cpp
@@ -2,16 +2,18 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLHRElement.h"
 #include "mozilla/dom/HTMLHRElementBinding.h"
 
+#include "nsCSSProps.h"
+
 NS_IMPL_NS_NEW_HTML_ELEMENT(HR)
 
 namespace mozilla {
 namespace dom {
 
 HTMLHRElement::HTMLHRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3205,17 +3205,17 @@ HTMLInputElement::Focus(ErrorResult& aEr
   // tab to the next one.
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
     for (nsIFrame* childFrame : frame->PrincipalChildList()) {
       // See if the child is a button control.
       nsCOMPtr<nsIFormControl> formCtrl =
         do_QueryInterface(childFrame->GetContent());
       if (formCtrl && formCtrl->ControlType() == NS_FORM_BUTTON_BUTTON) {
-        nsCOMPtr<nsIDOMElement> element = do_QueryInterface(formCtrl);
+        nsCOMPtr<Element> element = do_QueryInterface(formCtrl);
         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
         if (fm && element) {
           fm->SetFocus(element, 0);
         }
         break;
       }
     }
   }
--- a/dom/html/HTMLLabelElement.cpp
+++ b/dom/html/HTMLLabelElement.cpp
@@ -56,19 +56,20 @@ HTMLLabelElement::GetForm() const
 }
 
 void
 HTMLLabelElement::Focus(ErrorResult& aError)
 {
   // retarget the focus method at the for content
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
-    nsCOMPtr<nsIDOMElement> elem = do_QueryObject(GetLabeledElement());
-    if (elem)
+    RefPtr<Element> elem = GetLabeledElement();
+    if (elem) {
       fm->SetFocus(elem, 0);
+    }
   }
 }
 
 static bool
 InInteractiveHTMLContent(nsIContent* aContent, nsIContent* aStop)
 {
   nsIContent* content = aContent;
   while (content && content != aStop) {
@@ -151,22 +152,22 @@ HTMLLabelElement::PostHandleEvent(EventC
               // Also, within HTMLInputElement::PostHandleEvent, inputs will
               // be selected only when focused via a key or when the navigation
               // flag is used and we want to select the text on label clicks as
               // well.
               // If the label has been clicked by the user, we also want to
               // pass FLAG_BYMOUSE so that we get correct focus ring behavior,
               // but we don't want to pass FLAG_BYMOUSE if this click event was
               // caused by the user pressing an accesskey.
-              nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content);
               bool byMouse = (mouseEvent->inputSource != MouseEventBinding::MOZ_SOURCE_KEYBOARD);
               bool byTouch = (mouseEvent->inputSource == MouseEventBinding::MOZ_SOURCE_TOUCH);
-              fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS |
-                                 (byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) |
-                                 (byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0));
+              fm->SetFocus(content,
+                           nsIFocusManager::FLAG_BYMOVEFOCUS |
+                           (byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) |
+                           (byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0));
             }
           }
           // Dispatch a new click event to |content|
           //    (For compatibility with IE, we do only left click.  If
           //    we wanted to interpret the HTML spec very narrowly, we
           //    would do nothing.  If we wanted to do something
           //    sensible, we might send more events through like
           //    this.)  See bug 7554, bug 49897, and bug 96813.
--- a/dom/html/HTMLLegendElement.cpp
+++ b/dom/html/HTMLLegendElement.cpp
@@ -102,17 +102,17 @@ HTMLLegendElement::Focus(ErrorResult& aE
 
   // If the legend isn't focusable, focus whatever is focusable following
   // the legend instead, bug 81481.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm) {
     return;
   }
 
-  nsCOMPtr<nsIDOMElement> result;
+  RefPtr<Element> result;
   aError = fm->MoveFocus(nullptr, this, nsIFocusManager::MOVEFOCUS_FORWARD,
                          nsIFocusManager::FLAG_NOPARENTFRAME,
                          getter_AddRefs(result));
 }
 
 bool
 HTMLLegendElement::PerformAccesskey(bool aKeyCausesActivation,
                                     bool aIsTrustedEvent)
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -187,17 +187,17 @@ HTMLLinkElement::UnbindFromTree(bool aDe
   // Check for a ShadowRoot because link elements are inert in a
   // ShadowRoot.
   ShadowRoot* oldShadowRoot = GetBindingParent() ?
     GetBindingParent()->GetShadowRoot() : nullptr;
 
   CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 
-  UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
+  Unused << UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
 }
 
 bool
 HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
                                 nsAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 nsAttrValue& aResult)
@@ -323,32 +323,34 @@ HTMLLinkElement::AfterSetAttr(int32_t aN
       }
 
       if ((aName == nsGkAtoms::as || aName == nsGkAtoms::type ||
            aName == nsGkAtoms::crossorigin || aName == nsGkAtoms::media) &&
           IsInComposedDoc()) {
         UpdatePreload(aName, aValue, aOldValue);
       }
 
-      UpdateStyleSheetInternal(nullptr, nullptr,
-                               dropSheet ||
-                               (aName == nsGkAtoms::title ||
-                                aName == nsGkAtoms::media ||
-                                aName == nsGkAtoms::type));
+      const bool forceUpdate = dropSheet ||
+        aName == nsGkAtoms::title ||
+        aName == nsGkAtoms::media ||
+        aName == nsGkAtoms::type;
+
+      Unused << UpdateStyleSheetInternal(
+          nullptr, nullptr, forceUpdate ? ForceUpdate::Yes : ForceUpdate::No);
     }
   } else {
     // Since removing href or rel makes us no longer link to a
     // stylesheet, force updates for those too.
     if (aNameSpaceID == kNameSpaceID_None) {
       if (aName == nsGkAtoms::href ||
           aName == nsGkAtoms::rel ||
           aName == nsGkAtoms::title ||
           aName == nsGkAtoms::media ||
           aName == nsGkAtoms::type) {
-        UpdateStyleSheetInternal(nullptr, nullptr, true);
+        Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
       }
       if ((aName == nsGkAtoms::as || aName == nsGkAtoms::type ||
            aName == nsGkAtoms::crossorigin || aName == nsGkAtoms::media) &&
           IsInComposedDoc()) {
         UpdatePreload(aName, aValue, aOldValue);
       }
     }
   }
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -89,17 +89,17 @@ HTMLStyleElement::ContentRemoved(nsICont
   ContentChanged(aChild);
 }
 
 void
 HTMLStyleElement::ContentChanged(nsIContent* aContent)
 {
   mTriggeringPrincipal = nullptr;
   if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
-    UpdateStyleSheetInternal(nullptr, nullptr);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr);
   }
 }
 
 nsresult
 HTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                              nsIContent* aBindingParent,
                              bool aCompileEventHandlers)
 {
@@ -125,31 +125,31 @@ HTMLStyleElement::UnbindFromTree(bool aD
 
   if (oldShadow && GetContainingShadow()) {
     // The style is in a shadow tree and is still in the
     // shadow tree. Thus the sheets in the shadow DOM
     // do not need to be updated.
     return;
   }
 
-  UpdateStyleSheetInternal(oldDoc, oldShadow);
+  Unused << UpdateStyleSheetInternal(oldDoc, oldShadow);
 }
 
 nsresult
 HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                const nsAttrValue* aValue,
                                const nsAttrValue* aOldValue,
                                nsIPrincipal* aSubjectPrincipal,
                                bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::title ||
         aName == nsGkAtoms::media ||
         aName == nsGkAtoms::type) {
-      UpdateStyleSheetInternal(nullptr, nullptr, true);
+      Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
     }
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                             aOldValue, aSubjectPrincipal, aNotify);
 }
 
 void
@@ -186,17 +186,17 @@ HTMLStyleElement::SetTextContentInternal
   SetEnableUpdates(false);
 
   aError = nsContentUtils::SetNodeTextContent(this, aTextContent, true);
 
   SetEnableUpdates(true);
 
   mTriggeringPrincipal = aScriptedPrincipal;
 
-  UpdateStyleSheetInternal(nullptr, nullptr);
+  Unused << UpdateStyleSheetInternal(nullptr, nullptr);
 }
 
 already_AddRefed<nsIURI>
 HTMLStyleElement::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = true;
   *aTriggeringPrincipal = do_AddRef(mTriggeringPrincipal).take();
   return nullptr;
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -29,16 +29,17 @@ XPIDL_SOURCES += [
 ]
 
 XPIDL_MODULE = 'content_html'
 
 EXPORTS += [
     'nsGenericHTMLElement.h',
     'nsGenericHTMLFrameElement.h',
     'nsHTMLDNSPrefetch.h',
+    'nsHTMLDocument.h',
     'nsIConstraintValidation.h',
     'nsIForm.h',
     'nsIFormControl.h',
     'nsIFormProcessor.h',
     'nsIHTMLCollection.h',
     'nsIHTMLDocument.h',
     'nsIRadioGroupContainer.h',
     'nsIRadioVisitor.h',
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -10,17 +10,16 @@
 #include "nsDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsIHTMLCollection.h"
 #include "nsIScriptElement.h"
 #include "nsTArray.h"
 
 #include "PLDHashTable.h"
 #include "nsIHttpChannel.h"
-#include "nsHTMLStyleSheet.h"
 #include "nsThreadUtils.h"
 #include "nsICommandManager.h"
 #include "mozilla/dom/HTMLSharedElement.h"
 #include "mozilla/dom/BindingDeclarations.h"
 
 class nsIURI;
 class nsIDocShell;
 class nsICachingChannel;
@@ -220,18 +219,16 @@ public:
   void CaptureEvents();
   void ReleaseEvents();
   // We're picking up GetLocation from Document
   already_AddRefed<mozilla::dom::Location> GetLocation() const
   {
     return nsIDocument::GetLocation();
   }
 
-  virtual nsHTMLDocument* AsHTMLDocument() override { return this; }
-
   static bool MatchFormControls(Element* aElement, int32_t aNamespaceID,
                                 nsAtom* aAtom, void* aData);
 
   void GetFormsAndFormControls(nsContentList** aFormList,
                                nsContentList** aFormControlList);
 protected:
   ~nsHTMLDocument();
 
@@ -362,13 +359,20 @@ protected:
 
   /**
    * Temporary flag that is set in EndUpdate() to ignore
    * MaybeEditingStateChanged() script runners from a nested scope.
    */
   bool mPendingMaybeEditingStateChanged;
 };
 
+inline nsHTMLDocument*
+nsIDocument::AsHTMLDocument()
+{
+  MOZ_ASSERT(IsHTMLOrXHTML());
+  return static_cast<nsHTMLDocument*>(this);
+}
+
 #define NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(_class)                        \
     NS_DOCUMENT_INTERFACE_TABLE_BEGIN(_class)                                 \
     NS_INTERFACE_TABLE_ENTRY(_class, nsIHTMLDocument)
 
 #endif /* nsHTMLDocument_h___ */
--- a/dom/interfaces/base/nsIFocusManager.idl
+++ b/dom/interfaces/base/nsIFocusManager.idl
@@ -2,17 +2,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface mozIDOMWindowProxy;
 interface nsIDocument;
-interface nsIContent;
+
+webidl Element;
 
 [scriptable, uuid(86e1f1e1-365d-493b-b52a-a649f3f311dc)]
 /**
  * The focus manager deals with all focus related behaviour. Only one element
  * in the entire application may have the focus at a time; this element
  * receives any keyboard events. While there is only one application-wide
  * focused element, each nsIDOMWindow maintains a reference to the element
  * that would be focused if the window was active.
@@ -76,17 +77,17 @@ interface nsIFocusManager : nsISupports
    * element.
    */
   uint32_t getLastFocusMethod(in mozIDOMWindowProxy window);
 
   /**
    * Changes the focused element reference within the window containing
    * aElement to aElement.
    */
-  void setFocus(in nsIDOMElement aElement, in unsigned long aFlags);
+  void setFocus(in Element aElement, in unsigned long aFlags);
 
   /**
    * Move the focus to another element. If aStartElement is specified, then
    * movement is done relative to aStartElement. If aStartElement is null,
    * then movement is done relative to the currently focused element. If no
    * element is focused, focus the first focusable element within the
    * document (or the last focusable element if aType is MOVEFOCUS_END). This
    * method is equivalent to setting the focusedElement to the new element.
@@ -96,19 +97,19 @@ interface nsIFocusManager : nsISupports
    *
    * If no element is found, and aType is either MOVEFOCUS_ROOT or
    * MOVEFOCUS_CARET, then the focus is cleared. If aType is any other value,
    * the focus is not changed.
    *
    * Returns the element that was focused. The return value may be null if focus
    * was moved into a child process.
    */
-  nsIDOMElement moveFocus(in mozIDOMWindowProxy aWindow,
-                          in nsIDOMElement aStartElement,
-                          in unsigned long aType, in unsigned long aFlags);
+  Element moveFocus(in mozIDOMWindowProxy aWindow,
+                    in Element aStartElement,
+                    in unsigned long aType, in unsigned long aFlags);
 
   /**
    * Clears the focused element within aWindow. If the current focusedWindow
    * is a descendant of aWindow, sets the current focusedWindow to aWindow.
    *
    * @throws NS_ERROR_INVALID_ARG if aWindow is null
    */
   void clearFocus(in mozIDOMWindowProxy aWindow);
@@ -137,17 +138,17 @@ interface nsIFocusManager : nsISupports
   /**
    * Moves the selection caret within aWindow to the current focus.
    */
   void moveCaretToFocus(in mozIDOMWindowProxy aWindow);
 
   /***
    * Check if given element is focusable.
    */
-  boolean elementIsFocusable(in nsIDOMElement aElement, in unsigned long aFlags);
+  boolean elementIsFocusable(in Element aElement, in unsigned long aFlags);
 
   /*
    * Raise the window when switching focus
    */
   const unsigned long FLAG_RAISE = 1;
 
   /**
    * Do not scroll the element to focus into view
@@ -260,17 +261,17 @@ interface nsIFocusManager : nsISupports
    */
   [noscript] void fireDelayedEvents(in nsIDocument aDocument);
 
   /**
    * Indicate that a plugin wishes to take the focus. This is similar to a
    * normal focus except that the widget focus is not changed. Updating the
    * widget focus state is the responsibility of the caller.
    */
-  [noscript] void focusPlugin(in nsIContent aPlugin);
+  [noscript] void focusPlugin(in Element aPlugin);
 
   /**
    * Used in a child process to indicate that the parent window is now
    * active or deactive.
    */
   [noscript] void parentActivated(in mozIDOMWindowProxy aWindow,
                                   in bool active);
 };
--- a/dom/interfaces/xul/nsIDOMXULCommandDispatcher.idl
+++ b/dom/interfaces/xul/nsIDOMXULCommandDispatcher.idl
@@ -5,34 +5,35 @@
 
 #include "nsISupports.idl"
 
 interface nsIDOMElement;
 interface nsIController;
 interface nsIControllers;
 interface mozIDOMWindowProxy;
 
+webidl Element;
 
 [scriptable, uuid(a9fa9fd3-8d62-4f94-9ed8-3ea9c3cf0773)]
 interface nsIDOMXULCommandDispatcher : nsISupports
 {
-            attribute nsIDOMElement    focusedElement;
+            attribute Element focusedElement;
             attribute mozIDOMWindowProxy focusedWindow;
 
   void                      addCommandUpdater(in nsIDOMElement updater,
                                               in DOMString events,
                                               in DOMString targets);
   void                      removeCommandUpdater(in nsIDOMElement updater);
 
   void                      updateCommands(in DOMString eventName);
 
   nsIController             getControllerForCommand(in string command);
   nsIControllers            getControllers();
 
   void advanceFocus();
   void rewindFocus();
-  void advanceFocusIntoSubtree(in nsIDOMElement elt);
+  void advanceFocusIntoSubtree(in Element elt);
 
   // When locked, command updating is batched until unlocked. Always ensure that
   // lock and unlock is called in a pair.
   void lock();
   void unlock();
 };
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2679,17 +2679,17 @@ TabChild::RecvRenderLayers(const bool& a
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation)
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
-    nsCOMPtr<nsIDOMElement> result;
+    RefPtr<Element> result;
     nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
 
     // Move to the first or last document.
     uint32_t type = aForward ?
       (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC) :
                                 static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT)) :
       (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC) :
                                 static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST));
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -483,25 +483,24 @@ TabParent::ActorDestroy(ActorDestroyReas
   }
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvMoveFocus(const bool& aForward, const bool& aForDocumentNavigation)
 {
   nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   if (fm) {
-    nsCOMPtr<nsIDOMElement> dummy;
+    RefPtr<Element> dummy;
 
     uint32_t type = aForward ?
       (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARDDOC) :
                                 static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD)) :
       (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC) :
                                 static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD));
-    nsCOMPtr<nsIDOMElement> frame = do_QueryInterface(mFrameElement);
-    fm->MoveFocus(nullptr, frame, type, nsIFocusManager::FLAG_BYKEY,
+    fm->MoveFocus(nullptr, mFrameElement, type, nsIFocusManager::FLAG_BYKEY,
                   getter_AddRefs(dummy));
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvSizeShellTo(const uint32_t& aFlags, const int32_t& aWidth, const int32_t& aHeight,
                            const int32_t& aShellItemWidth, const int32_t& aShellItemHeight)
@@ -2024,18 +2023,18 @@ TabParent::RecvRequestFocus(const bool& 
   if (!content || !content->OwnerDoc()) {
     return IPC_OK();
   }
 
   uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
   if (aCanRaise)
     flags |= nsIFocusManager::FLAG_RAISE;
 
-  nsCOMPtr<nsIDOMElement> node = do_QueryInterface(mFrameElement);
-  fm->SetFocus(node, flags);
+  RefPtr<Element> element = mFrameElement;
+  fm->SetFocus(element, flags);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvEnableDisableCommands(const nsString& aAction,
                                      nsTArray<nsCString>&& aEnabledCommands,
                                      nsTArray<nsCString>&& aDisabledCommands)
 {
--- a/dom/media/mp4/MoofParser.cpp
+++ b/dom/media/mp4/MoofParser.cpp
@@ -925,17 +925,16 @@ Saiz::Saiz(Box& aBox, AtomType aDefaultT
 
 Result<Ok, nsresult>
 Saiz::Parse(Box& aBox)
 {
   BoxReader reader(aBox);
 
   uint32_t flags;
   MOZ_TRY_VAR(flags, reader->ReadU32());
-  uint8_t version = flags >> 24;
   if (flags & 1) {
     MOZ_TRY_VAR(mAuxInfoType, reader->ReadU32());
     MOZ_TRY_VAR(mAuxInfoTypeParameter, reader->ReadU32());
   }
   uint8_t defaultSampleInfoSize;
   MOZ_TRY_VAR(defaultSampleInfoSize, reader->ReadU8());
   uint32_t count;
   MOZ_TRY_VAR(count, reader->ReadU32());
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1476,17 +1476,17 @@ nsPluginInstanceOwner::ProcessMouseDown(
 
   // if the plugin is windowless, we need to set focus ourselves
   // otherwise, we might not get key events
   if (mPluginFrame && mPluginWindow &&
       mPluginWindow->type == NPWindowTypeDrawable) {
 
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
-      nsCOMPtr<nsIDOMElement> elem = do_QueryReferent(mContent);
+      nsCOMPtr<Element> elem = do_QueryReferent(mContent);
       fm->SetFocus(elem, 0);
     }
   }
 
   WidgetMouseEvent* mouseEvent =
     aMouseEvent->WidgetEventPtr()->AsMouseEvent();
   if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
     mLastMouseDownButtonType = mouseEvent->button;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 #include <stdint.h> // for intptr_t
 
 #include "mozilla/BasicEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/dom/Element.h"
 #include "PluginInstanceParent.h"
 #include "BrowserStreamParent.h"
 #include "PluginBackgroundDestroyer.h"
 #include "PluginModuleParent.h"
 #include "StreamNotifyParent.h"
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "gfxASurface.h"
@@ -2219,17 +2220,18 @@ PluginInstanceParent::AnswerPluginFocusC
 #if defined(OS_WIN)
     if (gotFocus) {
       nsPluginInstanceOwner* owner = GetOwner();
       if (owner) {
         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
         nsCOMPtr<nsIDOMElement> element;
         owner->GetDOMElement(getter_AddRefs(element));
         if (fm && element) {
-          fm->SetFocus(element, 0);
+          nsCOMPtr<dom::Element> domElement(do_QueryInterface(element));
+          fm->SetFocus(domElement, 0);
         }
       }
     }
     return IPC_OK();
 #else
     NS_NOTREACHED("PluginInstanceParent::AnswerPluginFocusChange not implemented!");
     return IPC_FAIL_NO_REASON(this);
 #endif
--- a/dom/svg/SVGDocument.h
+++ b/dom/svg/SVGDocument.h
@@ -8,16 +8,19 @@
 #define mozilla_dom_SVGDocument_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/XMLDocument.h"
 
 class nsSVGElement;
 
 namespace mozilla {
+
+class SVGContextPaint;
+
 namespace dom {
 
 class SVGForeignObjectElement;
 
 class SVGDocument final : public XMLDocument
 {
   friend class SVGForeignObjectElement; // To call EnsureNonSVGUserAgentStyleSheetsLoaded
 
@@ -31,22 +34,38 @@ public:
 
   virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
                                      bool aNotify) override;
   virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
                                             bool aNotify) override;
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override;
 
-  virtual SVGDocument* AsSVGDocument() override {
-    return this;
+  void SetCurrentContextPaint(const SVGContextPaint* aContextPaint)
+  {
+    mCurrentContextPaint = aContextPaint;
+  }
+
+  const SVGContextPaint* GetCurrentContextPaint() const
+  {
+    return mCurrentContextPaint;
   }
 
 private:
   void EnsureNonSVGUserAgentStyleSheetsLoaded();
 
   bool mHasLoadedNonSVGUserAgentStyleSheets;
+
+  // This is maintained by AutoSetRestoreSVGContextPaint.
+  const SVGContextPaint* mCurrentContextPaint = nullptr;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+inline mozilla::dom::SVGDocument*
+nsIDocument::AsSVGDocument()
+{
+  MOZ_ASSERT(IsSVGDocument());
+  return static_cast<mozilla::dom::SVGDocument*>(this);
+}
+
 #endif // mozilla_dom_SVGDocument_h
--- a/dom/svg/SVGStyleElement.cpp
+++ b/dom/svg/SVGStyleElement.cpp
@@ -81,31 +81,31 @@ SVGStyleElement::BindToTree(nsIDocument*
 }
 
 void
 SVGStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
   ShadowRoot* oldShadow = GetContainingShadow();
   SVGStyleElementBase::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheetInternal(oldDoc, oldShadow);
+  Unused << UpdateStyleSheetInternal(oldDoc, oldShadow);
 }
 
 nsresult
 SVGStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                               const nsAttrValue* aValue,
                               const nsAttrValue* aOldValue,
                               nsIPrincipal* aMaybeScriptedPrincipal,
                               bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::title ||
         aName == nsGkAtoms::media ||
         aName == nsGkAtoms::type) {
-      UpdateStyleSheetInternal(nullptr, nullptr, true);
+      Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
     }
   }
 
   return SVGStyleElementBase::AfterSetAttr(aNameSpaceID, aName, aValue,
                                            aOldValue, aMaybeScriptedPrincipal,
                                            aNotify);
 }
 
@@ -154,17 +154,17 @@ SVGStyleElement::ContentRemoved(nsIConte
 {
   ContentChanged(aChild);
 }
 
 void
 SVGStyleElement::ContentChanged(nsIContent* aContent)
 {
   if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
-    UpdateStyleSheetInternal(nullptr, nullptr);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr);
   }
 }
 
 //----------------------------------------------------------------------
 
 void
 SVGStyleElement::GetXmlspace(nsAString & aXmlspace)
 {
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -1,15 +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 "hasht.h"
+#include "nsHTMLDocument.h"
 #include "nsICryptoHash.h"
 #include "nsNetCID.h"
 #include "nsThreadUtils.h"
 #include "WebAuthnCoseIdentifiers.h"
 #include "mozilla/dom/AuthenticatorAttestationResponse.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PWebAuthnTransaction.h"
 #include "mozilla/dom/U2FUtil.h"
@@ -131,20 +132,16 @@ RelaxSameOrigin(nsPIDOMWindowInner* aPar
   if (NS_FAILED(uri->GetAsciiHost(originHost))) {
     return NS_ERROR_FAILURE;
   }
   nsCOMPtr<nsIDocument> document = aParent->GetDoc();
   if (!document || !document->IsHTMLDocument()) {
     return NS_ERROR_FAILURE;
   }
   nsHTMLDocument* html = document->AsHTMLDocument();
-  if (NS_WARN_IF(!html)) {
-    return NS_ERROR_FAILURE;
-  }
-
   if (!html->IsRegistrableDomainSuffixOfOrEqualTo(aInputRpId, originHost)) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   aRelaxedRpId.Assign(NS_ConvertUTF16toUTF8(aInputRpId));
   return NS_OK;
 }
 
--- a/dom/webauthn/WebAuthnManager.h
+++ b/dom/webauthn/WebAuthnManager.h
@@ -36,23 +36,16 @@
  * - On return of successful transaction information from parent process, turn
  *   information into DOM object format required by spec, and resolve promise
  *   (by running the Finish* functions of WebAuthnManager). On cancellation
  *   request from parent, reject promise with corresponding error code. Either
  *   outcome will also close the IPC channel.
  *
  */
 
-// Forward decl because of nsHTMLDocument.h's complex dependency on /layout/style
-class nsHTMLDocument {
-public:
-  bool IsRegistrableDomainSuffixOfOrEqualTo(const nsAString& aHostSuffixString,
-                                            const nsACString& aOrigHost);
-};
-
 namespace mozilla {
 namespace dom {
 
 class WebAuthnTransaction
 {
 public:
   WebAuthnTransaction(const RefPtr<Promise>& aPromise,
                       const nsTArray<uint8_t>& aRpIdHash,
--- a/dom/webauthn/WebAuthnUtil.cpp
+++ b/dom/webauthn/WebAuthnUtil.cpp
@@ -73,21 +73,18 @@ EvaluateAppID(nsPIDOMWindowInner* aParen
 
   // Run the HTML5 algorithm to relax the same-origin policy, copied from W3C
   // Web Authentication. See Bug 1244959 comment #8 for context on why we are
   // doing this instead of implementing the external-fetch FacetID logic.
   nsCOMPtr<nsIDocument> document = aParent->GetDoc();
   if (!document || !document->IsHTMLDocument()) {
     return false;
   }
+
   nsHTMLDocument* html = document->AsHTMLDocument();
-  if (NS_WARN_IF(!html)) {
-    return false;
-  }
-
   // Use the base domain as the facet for evaluation. This lets this algorithm
   // relax the whole eTLD+1.
   nsCOMPtr<nsIEffectiveTLDService> tldService =
     do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   if (!tldService) {
     return false;
   }
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3253,22 +3253,16 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
         // The state of the world may have changed, recheck it.
         normalRunnablesPending = NS_HasPendingEvents(mThread);
         // The debugger queue doesn't get cleared, so we can ignore that.
       }
 
       currentStatus = mStatus;
     }
 
-    if (currentStatus >= Terminating && previousStatus < Terminating) {
-      if (mScope) {
-        mScope->NoteTerminating();
-      }
-    }
-
     // if all holders are done then we can kill this thread.
     if (currentStatus != Running && !HasActiveHolders()) {
 
       // If we just changed status, we must schedule the current runnables.
       if (previousStatus != Running && currentStatus != Killing) {
         NotifyInternal(Killing);
 
 #ifdef DEBUG
@@ -4514,16 +4508,23 @@ WorkerPrivate::NotifyInternal(WorkerStat
   WorkerStatus previousStatus;
   {
     MutexAutoLock lock(mMutex);
 
     if (mStatus >= aStatus) {
       return true;
     }
 
+    if (aStatus >= Terminating) {
+      if (mScope) {
+        MutexAutoUnlock unlock(mMutex);
+        mScope->NoteTerminating();
+      }
+    }
+
     // Make sure the hybrid event target stops dispatching runnables
     // once we reaching the killing state.
     if (aStatus == Killing) {
       // To avoid deadlock we always acquire the event target mutex before the
       // worker private mutex.  (We do it in this order because this is what
       // workers best for event dispatching.)  To enforce that order here we
       // need to unlock the worker private mutex before we lock the event target
       // mutex in ForgetWorkerPrivate.
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -221,42 +221,41 @@ nsXBLBinding::BindAnonymousContent(nsICo
       child->UnbindFromTree();
       return;
     }
 
 #ifdef MOZ_XUL
     // To make XUL templates work (and other goodies that happen when
     // an element is added to a XUL document), we need to notify the
     // XUL document using its special API.
-    XULDocument* xuldoc = doc ? doc->AsXULDocument() : nullptr;
-    if (xuldoc) {
-      xuldoc->AddSubtreeToDocument(child);
+    if (doc && doc->IsXULDocument()) {
+      doc->AsXULDocument()->AddSubtreeToDocument(child);
     }
 #endif
   }
 }
 
 void
 nsXBLBinding::UnbindAnonymousContent(nsIDocument* aDocument,
                                      nsIContent* aAnonParent,
                                      bool aNullParent)
 {
   nsAutoScriptBlocker scriptBlocker;
   // Hold a strong ref while doing this, just in case.
   nsCOMPtr<nsIContent> anonParent = aAnonParent;
 #ifdef MOZ_XUL
-  XULDocument* xuldoc = aDocument ? aDocument->AsXULDocument() : nullptr;
+  const bool isXULDocument = aDocument && aDocument->IsXULDocument();
 #endif
   for (nsIContent* child = aAnonParent->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     child->UnbindFromTree(true, aNullParent);
 #ifdef MOZ_XUL
-    if (xuldoc) {
-      xuldoc->RemoveSubtreeFromDocument(child);
+    if (isXULDocument) {
+      aDocument->AsXULDocument()->RemoveSubtreeFromDocument(child);
     }
 #endif
   }
 }
 
 void
 nsXBLBinding::SetBoundElement(Element* aElement)
 {
--- a/dom/xbl/nsXBLResourceLoader.cpp
+++ b/dom/xbl/nsXBLResourceLoader.cpp
@@ -159,17 +159,17 @@ nsXBLResourceLoader::LoadResources(nsICo
   mResourceList = nullptr;
 
   return mPendingSheets == 0;
 }
 
 // nsICSSLoaderObserver
 NS_IMETHODIMP
 nsXBLResourceLoader::StyleSheetLoaded(StyleSheet* aSheet,
-                                      bool aWasAlternate,
+                                      bool aWasDeferred,
                                       nsresult aStatus)
 {
   if (!mResources) {
     // Our resources got destroyed -- just bail out
     return NS_OK;
   }
 
   mResources->AppendStyleSheet(aSheet);
--- a/dom/xml/XMLStylesheetProcessingInstruction.cpp
+++ b/dom/xml/XMLStylesheetProcessingInstruction.cpp
@@ -64,28 +64,28 @@ XMLStylesheetProcessingInstruction::Bind
 }
 
 void
 XMLStylesheetProcessingInstruction::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
 
   ProcessingInstruction::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheetInternal(oldDoc, nullptr);
+  Unused << UpdateStyleSheetInternal(oldDoc, nullptr);
 }
 
 // nsIDOMNode
 
 void
 XMLStylesheetProcessingInstruction::SetNodeValueInternal(const nsAString& aNodeValue,
                                                          ErrorResult& aError)
 {
   CharacterData::SetNodeValueInternal(aNodeValue, aError);
   if (!aError.Failed()) {
-    UpdateStyleSheetInternal(nullptr, nullptr, true);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
   }
 }
 
 // nsStyleLinkElement
 
 void
 XMLStylesheetProcessingInstruction::GetCharset(nsAString& aCharset)
 {
--- a/dom/xml/XMLStylesheetProcessingInstruction.h
+++ b/dom/xml/XMLStylesheetProcessingInstruction.h
@@ -3,16 +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/. */
 
 #ifndef mozilla_dom_XMLStylesheetProcessingInstruction_h
 #define mozilla_dom_XMLStylesheetProcessingInstruction_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/Unused.h"
 #include "mozilla/dom/ProcessingInstruction.h"
 #include "nsIURI.h"
 #include "nsStyleLinkElement.h"
 
 namespace mozilla {
 namespace dom {
 
 class XMLStylesheetProcessingInstruction final
@@ -63,17 +64,17 @@ public:
   void GetCharset(nsAString& aCharset) override;
 
   virtual void SetData(const nsAString& aData, mozilla::ErrorResult& rv) override
   {
     CharacterData::SetData(aData, rv);
     if (rv.Failed()) {
       return;
     }
-    UpdateStyleSheetInternal(nullptr, nullptr, true);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
   }
 
 protected:
   virtual ~XMLStylesheetProcessingInstruction();
 
   nsCOMPtr<nsIURI> mOverriddenBaseURI;
 
   already_AddRefed<nsIURI>
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -420,21 +420,21 @@ nsXMLContentSink::OnTransformDone(nsresu
 
   DropParserAndPerfHint();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXMLContentSink::StyleSheetLoaded(StyleSheet* aSheet,
-                                   bool aWasAlternate,
+                                   bool aWasDeferred,
                                    nsresult aStatus)
 {
   if (!mPrettyPrinting) {
-    return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
+    return nsContentSink::StyleSheetLoaded(aSheet, aWasDeferred, aStatus);
   }
 
   if (!mDocument->CSSLoader()->HasPendingLoads()) {
     mDocument->CSSLoader()->RemoveObserver(this);
     StartLayout(false);
     ScrollToRef();
   }
 
@@ -598,22 +598,21 @@ nsXMLContentSink::CloseElement(nsIConten
     rv = ProcessMETATag(aContent);
   }
   else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
     if (ssle) {
       ssle->SetEnableUpdates(true);
-      bool willNotify;
-      bool isAlternate;
-      rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
-                                  &willNotify,
-                                  &isAlternate);
-      if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
+      auto updateOrError =
+        ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
+      if (updateOrError.isErr()) {
+        rv = updateOrError.unwrapErr();
+      } else if (updateOrError.unwrap().ShouldBlock() && !mRunsToCompletion) {
         ++mPendingSheetCount;
         mScriptLoader->AddParserBlockingScriptExecutionBlocker();
       }
     }
   }
 
   return rv;
 }
@@ -1263,30 +1262,29 @@ nsXMLContentSink::HandleProcessingInstru
   nsresult rv = AddContentAsLeaf(node);
   NS_ENSURE_SUCCESS(rv, rv);
   DidAddContent();
 
   if (ssle) {
     // This is an xml-stylesheet processing instruction... but it might not be
     // a CSS one if the type is set to something else.
     ssle->SetEnableUpdates(true);
-    bool willNotify;
-    bool isAlternate;
-    rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
-                                &willNotify,
-                                &isAlternate);
-    NS_ENSURE_SUCCESS(rv, rv);
+    auto updateOrError =
+      ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
+    if (updateOrError.isErr()) {
+      return updateOrError.unwrapErr();
+    }
 
-    if (willNotify) {
+    auto update = updateOrError.unwrap();
+    if (update.WillNotify()) {
       // Successfully started a stylesheet load
-      if (!isAlternate && !mRunsToCompletion) {
+      if (update.ShouldBlock() && !mRunsToCompletion) {
         ++mPendingSheetCount;
         mScriptLoader->AddParserBlockingScriptExecutionBlocker();
       }
-
       return NS_OK;
     }
   }
 
   // Check whether this is a CSS stylesheet PI.  Make sure the type
   // handling here matches
   // XMLStylesheetProcessingInstruction::GetStyleSheetInfo.
   nsAutoString type;
--- a/dom/xslt/xslt/txMozillaXMLOutput.cpp
+++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp
@@ -317,21 +317,20 @@ txMozillaXMLOutput::endElement()
     }
 
     if (mCreatingNewDocument) {
         // Handle all sorts of stylesheets
         nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
             do_QueryInterface(mCurrentNode);
         if (ssle) {
             ssle->SetEnableUpdates(true);
-            bool willNotify;
-            bool isAlternate;
-            nsresult rv = ssle->UpdateStyleSheet(mNotifier, &willNotify,
-                                                 &isAlternate);
-            if (mNotifier && NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+            auto updateOrError = ssle->UpdateStyleSheet(mNotifier);
+            if (mNotifier &&
+                updateOrError.isOk() &&
+                updateOrError.unwrap().ShouldBlock()) {
                 mNotifier->AddPendingStylesheet();
             }
         }
     }
 
     // Add the element to the tree if it wasn't added before and take one step
     // up the tree
     uint32_t last = mCurrentNodeStack.Count() - 1;
@@ -395,20 +394,20 @@ txMozillaXMLOutput::processingInstructio
         }
     }
 
     rv = mCurrentNode->AppendChildTo(pi, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (ssle) {
         ssle->SetEnableUpdates(true);
-        bool willNotify;
-        bool isAlternate;
-        rv = ssle->UpdateStyleSheet(mNotifier, &willNotify, &isAlternate);
-        if (mNotifier && NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+        auto updateOrError = ssle->UpdateStyleSheet(mNotifier);
+        if (mNotifier &&
+            updateOrError.isOk() &&
+            updateOrError.unwrap().ShouldBlock()) {
             mNotifier->AddPendingStylesheet();
         }
     }
 
     return NS_OK;
 }
 
 nsresult
@@ -970,28 +969,28 @@ txTransformNotifier::ScriptEvaluated(nsr
         SignalTransformEnd();
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 txTransformNotifier::StyleSheetLoaded(StyleSheet* aSheet,
-                                      bool aWasAlternate,
+                                      bool aWasDeferred,
                                       nsresult aStatus)
 {
     if (mPendingStylesheetCount == 0) {
         // We weren't waiting on this stylesheet anyway.  This can happen if
         // SignalTransformEnd got called with an error aResult.  See
         // http://bugzilla.mozilla.org/show_bug.cgi?id=215465.
         return NS_OK;
     }
 
     // We're never waiting for alternate stylesheets
-    if (!aWasAlternate) {
+    if (!aWasDeferred) {
         --mPendingStylesheetCount;
         SignalTransformEnd();
     }
 
     return NS_OK;
 }
 
 void
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -2099,28 +2099,30 @@ XULDocument::InsertXMLStylesheetPI(const
                                       ? aBeforeThis->AsContent() : nullptr,
                                     false);
     if (NS_FAILED(rv)) return rv;
 
     ssle->SetEnableUpdates(true);
 
     // load the stylesheet if necessary, passing ourselves as
     // nsICSSObserver
-    bool willNotify;
-    bool isAlternate;
-    rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
-    if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
-        ++mPendingSheets;
+    auto result = ssle->UpdateStyleSheet(this);
+    if (result.isErr()) {
+        // Ignore errors from UpdateStyleSheet; we don't want failure to
+        // do that to break the XUL document load.  But do propagate out
+        // NS_ERROR_OUT_OF_MEMORY.
+        if (result.unwrapErr() == NS_ERROR_OUT_OF_MEMORY) {
+            return result.unwrapErr();
+        }
+        return NS_OK;
     }
 
-    // Ignore errors from UpdateStyleSheet; we don't want failure to
-    // do that to break the XUL document load.  But do propagate out
-    // NS_ERROR_OUT_OF_MEMORY.
-    if (rv == NS_ERROR_OUT_OF_MEMORY) {
-        return rv;
+    auto update = result.unwrap();
+    if (update.ShouldBlock()) {
+        ++mPendingSheets;
     }
 
     return NS_OK;
 }
 
 nsresult
 XULDocument::InsertXULOverlayPI(const nsXULPrototypePI* aProtoPI,
                                 nsINode* aParent,
@@ -2487,20 +2489,17 @@ XULDocument::ResumeWalk()
                             element->NodeInfo()->Equals(nsGkAtoms::style,
                                                         kNameSpaceID_SVG)) {
                             // XXX sucks that we have to do this -
                             // see bug 370111
                             nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
                                 do_QueryInterface(element);
                             NS_ASSERTION(ssle, "<html:style> doesn't implement "
                                                "nsIStyleSheetLinkingElement?");
-                            bool willNotify;
-                            bool isAlternate;
-                            ssle->UpdateStyleSheet(nullptr, &willNotify,
-                                                   &isAlternate);
+                            Unused << ssle->UpdateStyleSheet(nullptr);
                         }
                     }
                 }
                 // Now pop the context stack back up to the parent
                 // element and continue the prototype walk.
                 mContextStack.Pop();
                 continue;
             }
@@ -2875,24 +2874,23 @@ XULDocument::DoneWalking()
         }
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 XULDocument::StyleSheetLoaded(StyleSheet* aSheet,
-                              bool aWasAlternate,
+                              bool aWasDeferred,
                               nsresult aStatus)
 {
-    if (!aWasAlternate) {
+    if (!aWasDeferred) {
         // Don't care about when alternate sheets finish loading
-
-        NS_ASSERTION(mPendingSheets > 0,
-            "Unexpected StyleSheetLoaded notification");
+        MOZ_ASSERT(mPendingSheets > 0,
+                   "Unexpected StyleSheetLoaded notification");
 
         --mPendingSheets;
 
         if (!mStillWalking && mPendingSheets == 0) {
             return DoneWalking();
         }
     }
 
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -78,20 +78,16 @@ public:
                                        nsIStreamListener **aDocListener,
                                        bool aReset = true,
                                        nsIContentSink* aSink = nullptr) override;
 
     virtual void SetContentType(const nsAString& aContentType) override;
 
     virtual void EndLoad() override;
 
-    virtual XULDocument* AsXULDocument() override {
-        return this;
-    }
-
     // nsIMutationObserver interface
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
 
     /**
      * Notify the XUL document that a subtree has been added
@@ -717,9 +713,16 @@ protected:
 private:
     // helpers
 
 };
 
 } // namespace dom
 } // namespace mozilla
 
+inline mozilla::dom::XULDocument*
+nsIDocument::AsXULDocument()
+{
+  MOZ_ASSERT(IsXULDocument());
+  return static_cast<mozilla::dom::XULDocument*>(this);
+}
+
 #endif // mozilla_dom_XULDocument_h
--- a/dom/xul/nsXULCommandDispatcher.cpp
+++ b/dom/xul/nsXULCommandDispatcher.cpp
@@ -29,16 +29,17 @@
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsError.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
+using mozilla::dom::Element;
 
 static LazyLogModule gCommandLog("nsXULCommandDispatcher");
 
 ////////////////////////////////////////////////////////////////////////
 
 nsXULCommandDispatcher::nsXULCommandDispatcher(nsIDocument* aDocument)
     : mDocument(aDocument), mUpdaters(nullptr), mLocked(false)
 {
@@ -93,17 +94,17 @@ nsXULCommandDispatcher::GetWindowRoot()
     if (nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow()) {
       return window->GetTopWindowRoot();
     }
   }
 
   return nullptr;
 }
 
-nsIContent*
+Element*
 nsXULCommandDispatcher::GetRootFocusedContentAndWindow(nsPIDOMWindowOuter** aWindow)
 {
   *aWindow = nullptr;
 
   if (!mDocument) {
     return nullptr;
   }
 
@@ -115,37 +116,35 @@ nsXULCommandDispatcher::GetRootFocusedCo
                                aWindow);
     }
   }
 
   return nullptr;
 }
 
 NS_IMETHODIMP
-nsXULCommandDispatcher::GetFocusedElement(nsIDOMElement** aElement)
+nsXULCommandDispatcher::GetFocusedElement(Element** aElement)
 {
   *aElement = nullptr;
 
   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
-  nsIContent* focusedContent =
+  RefPtr<Element> focusedContent =
     GetRootFocusedContentAndWindow(getter_AddRefs(focusedWindow));
   if (focusedContent) {
-    CallQueryInterface(focusedContent, aElement);
-
     // Make sure the caller can access the focused element.
-    nsCOMPtr<nsINode> node = do_QueryInterface(*aElement);
-    if (!node || !nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()->Subsumes(node->NodePrincipal())) {
+    if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()->
+          Subsumes(focusedContent->NodePrincipal())) {
       // XXX This might want to return null, but we use that return value
       // to mean "there is no focused element," so to be clear, throw an
       // exception.
-      NS_RELEASE(*aElement);
       return NS_ERROR_DOM_SECURITY_ERR;
     }
   }
 
+  focusedContent.forget(aElement);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULCommandDispatcher::GetFocusedWindow(mozIDOMWindowProxy** aWindow)
 {
   *aWindow = nullptr;
 
@@ -163,23 +162,24 @@ nsXULCommandDispatcher::GetFocusedWindow
   if (doc && !nsContentUtils::CanCallerAccess(doc))
     return NS_ERROR_DOM_SECURITY_ERR;
 
   window.forget(aWindow);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXULCommandDispatcher::SetFocusedElement(nsIDOMElement* aElement)
+nsXULCommandDispatcher::SetFocusedElement(Element* aElement)
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_ERROR_FAILURE);
 
-  if (aElement)
+  if (aElement) {
     return fm->SetFocus(aElement, 0);
+  }
 
   // if aElement is null, clear the focus in the currently focused child window
   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
   GetRootFocusedContentAndWindow(getter_AddRefs(focusedWindow));
   return fm->ClearFocus(focusedWindow);
 }
 
 NS_IMETHODIMP
@@ -192,51 +192,51 @@ nsXULCommandDispatcher::SetFocusedWindow
 
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_ERROR_FAILURE);
 
   // get the containing frame for the window, and set it as focused. This will
   // end up focusing whatever is currently focused inside the frame. Since
   // setting the command dispatcher's focused window doesn't raise the window,
   // setting it to a top-level window doesn't need to do anything.
-  nsCOMPtr<nsIDOMElement> frameElement =
-    do_QueryInterface(window->GetFrameElementInternal());
-  if (frameElement)
+  RefPtr<Element> frameElement = window->GetFrameElementInternal();
+  if (frameElement) {
     return fm->SetFocus(frameElement, 0);
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULCommandDispatcher::AdvanceFocus()
 {
   return AdvanceFocusIntoSubtree(nullptr);
 }
 
 NS_IMETHODIMP
 nsXULCommandDispatcher::RewindFocus()
 {
   nsCOMPtr<nsPIDOMWindowOuter> win;
   GetRootFocusedContentAndWindow(getter_AddRefs(win));
 
-  nsCOMPtr<nsIDOMElement> result;
+  RefPtr<Element> result;
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm)
     return fm->MoveFocus(win, nullptr, nsIFocusManager::MOVEFOCUS_BACKWARD,
                          0, getter_AddRefs(result));
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXULCommandDispatcher::AdvanceFocusIntoSubtree(nsIDOMElement* aElt)
+nsXULCommandDispatcher::AdvanceFocusIntoSubtree(Element* aElt)
 {
   nsCOMPtr<nsPIDOMWindowOuter> win;
   GetRootFocusedContentAndWindow(getter_AddRefs(win));
 
-  nsCOMPtr<nsIDOMElement> result;
+  RefPtr<Element> result;
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm)
     return fm->MoveFocus(win, aElt, nsIFocusManager::MOVEFOCUS_FORWARD,
                          0, getter_AddRefs(result));
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -354,19 +354,18 @@ nsXULCommandDispatcher::UpdateCommands(c
     if (!mPendingUpdates.Contains(aEventName)) {
       mPendingUpdates.AppendElement(aEventName);
     }
 
     return NS_OK;
   }
 
   nsAutoString id;
-  nsCOMPtr<nsIDOMElement> domElement;
-  GetFocusedElement(getter_AddRefs(domElement));
-  nsCOMPtr<Element> element = do_QueryInterface(domElement);
+  RefPtr<Element> element;
+  GetFocusedElement(getter_AddRefs(element));
   if (element) {
     element->GetAttribute(NS_LITERAL_STRING("id"), id);
   }
 
   nsCOMArray<nsIContent> updaters;
 
   for (Updater* updater = mUpdaters; updater != nullptr; updater = updater->mNext) {
     // Skip any nodes that don't match our 'events' or 'targets'
--- a/dom/xul/nsXULCommandDispatcher.h
+++ b/dom/xul/nsXULCommandDispatcher.h
@@ -18,16 +18,22 @@
 #include "nsWeakReference.h"
 #include "nsIDOMNode.h"
 #include "nsString.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIDOMElement;
 class nsPIWindowRoot;
 
+namespace mozilla {
+namespace dom {
+class Element;
+} // namespace dom
+} // namespace mozilla
+
 class nsXULCommandDispatcher : public nsIDOMXULCommandDispatcher,
                                public nsSupportsWeakReference
 {
 public:
     explicit nsXULCommandDispatcher(nsIDocument* aDocument);
 
     // nsISupports
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -38,17 +44,18 @@ public:
     NS_DECL_NSIDOMXULCOMMANDDISPATCHER
 
     void Disconnect();
 protected:
     virtual ~nsXULCommandDispatcher();
 
     already_AddRefed<nsPIWindowRoot> GetWindowRoot();
 
-    nsIContent* GetRootFocusedContentAndWindow(nsPIDOMWindowOuter** aWindow);
+    mozilla::dom::Element*
+      GetRootFocusedContentAndWindow(nsPIDOMWindowOuter** aWindow);
 
     nsCOMPtr<nsIDocument> mDocument;
 
     class Updater {
     public:
       Updater(nsIDOMElement* aElement,
               const nsAString& aEvents,
               const nsAString& aTargets)
--- a/dom/xul/nsXULContentSink.cpp
+++ b/dom/xul/nsXULContentSink.cpp
@@ -668,18 +668,19 @@ XULContentSinkImpl::ReportError(const ch
   mTextLength = 0;
 
   // return leaving the document empty if we're asked to not add a <parsererror> root node
   nsCOMPtr<nsIDocument> idoc = do_QueryReferent(mDocument);
   if (idoc && idoc->SuppressParserErrorElement()) {
     return NS_OK;
   };
 
-  XULDocument* doc = idoc ? idoc->AsXULDocument() : nullptr;
-  if (doc && !doc->OnDocumentParserError()) {
+  if (idoc &&
+      idoc->IsXULDocument() &&
+      !idoc->AsXULDocument()->OnDocumentParserError()) {
     // The overlay was broken.  Don't add a messy element to the master doc.
     return NS_OK;
   }
 
   const char16_t* noAtts[] = { 0, 0 };
 
   NS_NAMED_LITERAL_STRING(errorNs,
                           "http://www.mozilla.org/newlayout/xml/parsererror.xml");
--- a/dom/xul/nsXULContentUtils.cpp
+++ b/dom/xul/nsXULContentUtils.cpp
@@ -116,21 +116,21 @@ nsXULContentUtils::SetCommandUpdater(nsI
         return NS_ERROR_NULL_POINTER;
 
     NS_PRECONDITION(aElement != nullptr, "null ptr");
     if (! aElement)
         return NS_ERROR_NULL_POINTER;
 
     nsresult rv;
 
-    XULDocument* xuldoc = aDocument->AsXULDocument();
-    NS_ASSERTION(xuldoc != nullptr, "not a xul document");
-    if (! xuldoc)
+    NS_ASSERTION(aDocument->IsXULDocument(), "not a xul document");
+    if (! aDocument->IsXULDocument())
         return NS_ERROR_UNEXPECTED;
 
+    XULDocument* xuldoc = aDocument->AsXULDocument();
     nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher =
         xuldoc->GetCommandDispatcher();
     NS_ASSERTION(dispatcher != nullptr, "no dispatcher");
     if (! dispatcher)
         return NS_ERROR_UNEXPECTED;
 
     nsAutoString events;
     aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events);
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -538,17 +538,17 @@ nsXULElement::IsFocusableInternal(int32_
 
   return shouldFocus;
 }
 
 bool
 nsXULElement::PerformAccesskey(bool aKeyCausesActivation,
                                bool aIsTrustedEvent)
 {
-    nsCOMPtr<nsIContent> content(this);
+    RefPtr<Element> content(this);
 
     if (IsXULElement(nsGkAtoms::label)) {
         nsAutoString control;
         GetAttr(kNameSpaceID_None, nsGkAtoms::control, control);
         if (control.IsEmpty()) {
             return false;
         }
 
@@ -572,31 +572,31 @@ nsXULElement::PerformAccesskey(bool aKey
 
     bool focused = false;
     nsXULElement* elm = FromNode(content);
     if (elm) {
         // Define behavior for each type of XUL element.
         if (!content->IsXULElement(nsGkAtoms::toolbarbutton)) {
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm) {
-            nsCOMPtr<nsIDOMElement> elementToFocus;
+            nsCOMPtr<Element> elementToFocus;
             // for radio buttons, focus the radiogroup instead
             if (content->IsXULElement(nsGkAtoms::radio)) {
               nsCOMPtr<nsIDOMXULSelectControlItemElement> controlItem(do_QueryInterface(content));
               if (controlItem) {
                 bool disabled;
                 controlItem->GetDisabled(&disabled);
                 if (!disabled) {
                   nsCOMPtr<nsIDOMXULSelectControlElement> selectControl;
                   controlItem->GetControl(getter_AddRefs(selectControl));
                   elementToFocus = do_QueryInterface(selectControl);
                 }
               }
             } else {
-              elementToFocus = do_QueryInterface(content);
+              elementToFocus = content;
             }
             if (elementToFocus) {
               fm->SetFocus(elementToFocus, nsIFocusManager::FLAG_BYKEY);
 
               // Return true if the element became focused.
               nsPIDOMWindowOuter* window = OwnerDoc()->GetWindow();
               focused = (window && window->GetFocusedNode());
             }
@@ -1113,26 +1113,24 @@ nsXULElement::AfterSetAttr(int32_t aName
                 } else if (aName == nsGkAtoms::drawintitlebar) {
                     SetDrawsInTitlebar(
                         aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
                 } else if (aName == nsGkAtoms::drawtitle) {
                     SetDrawsTitle(
                         aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
                 } else if (aName == nsGkAtoms::localedir) {
                     // if the localedir changed on the root element, reset the document direction
-                    XULDocument* xuldoc = document->AsXULDocument();
-                    if (xuldoc) {
-                        xuldoc->ResetDocumentDirection();
+                    if (document->IsXULDocument()) {
+                        document->AsXULDocument()->ResetDocumentDirection();
                     }
                 } else if (aName == nsGkAtoms::lwtheme ||
                          aName == nsGkAtoms::lwthemetextcolor) {
                     // if the lwtheme changed, make sure to reset the document lwtheme cache
-                    XULDocument* xuldoc = document->AsXULDocument();
-                    if (xuldoc) {
-                        xuldoc->ResetDocumentLWTheme();
+                    if (document->IsXULDocument()) {
+                        document->AsXULDocument()->ResetDocumentLWTheme();
                         UpdateBrightTitlebarForeground(document);
                     }
                 } else if (aName == nsGkAtoms::brighttitlebarforeground) {
                     UpdateBrightTitlebarForeground(document);
                 }
             }
 
             if (aName == nsGkAtoms::src && document) {
@@ -1146,26 +1144,24 @@ nsXULElement::AfterSetAttr(int32_t aName
                     ResetChromeMargins();
                 }
             }
 
             nsIDocument* doc = GetUncomposedDoc();
             if (doc && doc->GetRootElement() == this) {
                 if (aName == nsGkAtoms::localedir) {
                     // if the localedir changed on the root element, reset the document direction
-                    XULDocument* xuldoc = doc->AsXULDocument();
-                    if (xuldoc) {
-                        xuldoc->ResetDocumentDirection();
+                    if (doc->IsXULDocument()) {
+                        doc->AsXULDocument()->ResetDocumentDirection();
                     }
                 } else if ((aName == nsGkAtoms::lwtheme ||
                             aName == nsGkAtoms::lwthemetextcolor)) {
                     // if the lwtheme changed, make sure to restyle appropriately
-                    XULDocument* xuldoc = doc->AsXULDocument();
-                    if (xuldoc) {
-                        xuldoc->ResetDocumentLWTheme();
+                    if (doc->IsXULDocument()) {
+                        doc->AsXULDocument()->ResetDocumentLWTheme();
                         UpdateBrightTitlebarForeground(doc);
                     }
                 } else if (aName == nsGkAtoms::brighttitlebarforeground) {
                     UpdateBrightTitlebarForeground(doc);
                 } else if (aName == nsGkAtoms::drawintitlebar) {
                     SetDrawsInTitlebar(false);
                 } else if (aName == nsGkAtoms::drawtitle) {
                     SetDrawsTitle(false);
@@ -1229,23 +1225,23 @@ nsXULElement::ParseAttribute(int32_t aNa
     }
 
     return true;
 }
 
 void
 nsXULElement::RemoveBroadcaster(const nsAString & broadcasterId)
 {
-    XULDocument* xuldoc = OwnerDoc()->AsXULDocument();
-    if (xuldoc) {
-        Element* broadcaster = xuldoc->GetElementById(broadcasterId);
-        if (broadcaster) {
-            xuldoc->RemoveBroadcastListenerFor(*broadcaster, *this,
-                                               NS_LITERAL_STRING("*"));
-        }
+    nsIDocument* doc = OwnerDoc();
+    if (!doc->IsXULDocument()) {
+      return;
+    }
+    if (Element* broadcaster = doc->GetElementById(broadcasterId)) {
+        doc->AsXULDocument()->RemoveBroadcastListenerFor(
+           *broadcaster, *this, NS_LITERAL_STRING("*"));
     }
 }
 
 void
 nsXULElement::DestroyContent()
 {
     nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
     if (slots) {
--- a/dom/xul/nsXULPopupListener.cpp
+++ b/dom/xul/nsXULPopupListener.cpp
@@ -6,31 +6,31 @@
 /*
   This file provides the implementation for xul popup listener which
   tracks xul popups and context menus
  */
 
 #include "nsXULPopupListener.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
-#include "nsIDOMElement.h"
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
 #include "nsXULPopupManager.h"
 #include "nsIScriptContext.h"
 #include "nsIDocument.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/ReflowInput.h"
 #include "nsIObjectLoadingContent.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h" // for Event
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/FragmentOrElement.h"
 #include "mozilla/dom/MouseEvent.h"
 #include "mozilla/dom/MouseEventBinding.h"
 
 // for event firing in context menus
 #include "nsPresContext.h"
@@ -229,52 +229,47 @@ nsXULPopupListener::FireFocusOnTargetCon
   }
 
   nsIFrame* targetFrame = content->GetPrimaryFrame();
   if (!targetFrame) return NS_ERROR_FAILURE;
 
   const nsStyleUserInterface* ui = targetFrame->StyleUserInterface();
   bool suppressBlur = (ui->mUserFocus == StyleUserFocus::Ignore);
 
-  nsCOMPtr<nsIDOMElement> element;
-  nsCOMPtr<nsIContent> newFocus = content;
+  RefPtr<Element> newFocusElement;
 
   nsIFrame* currFrame = targetFrame;
   // Look for the nearest enclosing focusable frame.
   while (currFrame) {
     int32_t tabIndexUnused;
-    if (currFrame->IsFocusable(&tabIndexUnused, true)) {
-      newFocus = currFrame->GetContent();
-      nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
-      if (domElement) {
-        element = domElement;
-        break;
-      }
+    if (currFrame->IsFocusable(&tabIndexUnused, true) &&
+        currFrame->GetContent()->IsElement()) {
+      newFocusElement = currFrame->GetContent()->AsElement();
+      break;
     }
     currFrame = currFrame->GetParent();
   }
 
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
-    if (element) {
+    if (newFocusElement) {
       uint32_t focusFlags = nsIFocusManager::FLAG_BYMOUSE |
                             nsIFocusManager::FLAG_NOSCROLL;
       if (aIsTouch) {
         focusFlags |= nsIFocusManager::FLAG_BYTOUCH;
       }
-      fm->SetFocus(element, focusFlags);
+      fm->SetFocus(newFocusElement, focusFlags);
     } else if (!suppressBlur) {
       nsPIDOMWindowOuter *window = doc->GetWindow();
       fm->ClearFocus(window);
     }
   }
 
   EventStateManager* esm = context->EventStateManager();
-  nsCOMPtr<nsIContent> focusableContent = do_QueryInterface(element);
-  esm->SetContentState(focusableContent, NS_EVENT_STATE_ACTIVE);
+  esm->SetContentState(newFocusElement, NS_EVENT_STATE_ACTIVE);
 
   return NS_OK;
 }
 #endif
 
 // ClosePopup
 //
 // Do everything needed to shut down the popup.
--- a/editor/composer/nsEditingSession.cpp
+++ b/editor/composer/nsEditingSession.cpp
@@ -659,17 +659,18 @@ nsEditingSession::OnStateChange(nsIWebPr
         IsProgressForTargetDocument(aWebProgress);
 
       if (progressIsForTargetDocument) {
         nsCOMPtr<mozIDOMWindowProxy> window;
         aWebProgress->GetDOMWindow(getter_AddRefs(window));
 
         auto* piWindow = nsPIDOMWindowOuter::From(window);
         nsCOMPtr<nsIDocument> doc = piWindow->GetDoc();
-        nsHTMLDocument* htmlDoc = doc ? doc->AsHTMLDocument() : nullptr;
+        nsHTMLDocument* htmlDoc = doc && doc->IsHTMLOrXHTML()
+          ? doc->AsHTMLDocument() : nullptr;
         if (htmlDoc && htmlDoc->IsWriting()) {
           nsAutoString designMode;
           htmlDoc->GetDesignMode(designMode);
 
           if (designMode.EqualsLiteral("on")) {
             // This notification is for data coming in through
             // document.open/write/close(), ignore it.
 
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3435,17 +3435,17 @@ HTMLEditor::DebugUnitTests(int32_t* outN
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
 NS_IMETHODIMP
 HTMLEditor::StyleSheetLoaded(StyleSheet* aSheet,
-                             bool aWasAlternate,
+                             bool aWasDeferred,
                              nsresult aStatus)
 {
   AutoPlaceholderBatch batchIt(this);
 
   if (!mLastStyleSheetURL.IsEmpty()) {
     RemoveStyleSheetWithTransaction(mLastStyleSheetURL);
   }
 
@@ -5126,12 +5126,15 @@ HTMLEditor::GetEditorRoot()
 
 nsHTMLDocument*
 HTMLEditor::GetHTMLDocument() const
 {
   nsIDocument* doc = GetDocument();
   if (NS_WARN_IF(!doc)) {
     return nullptr;
   }
+  if (!doc->IsHTMLOrXHTML()) {
+    return nullptr;
+  }
   return doc->AsHTMLDocument();
 }
 
 } // namespace mozilla
--- a/editor/libeditor/tests/test_bug525389.html
+++ b/editor/libeditor/tests/test_bug525389.html
@@ -168,16 +168,22 @@ async function runTest() {
 //  verifyContent('<ol><li id="paste_here">X</li><li>Hello Kitty</li><span>Hello</span></ol>');
 
   await copyToClipBoard("<pre>Kitty</pre><span>Hello</span>", true);
   trans = getTransferableFromClipboard(true);
   pasteInto(trans, '<pre id="paste_here">Hello </pre>',"paste_here");
   verifyContent('<pre id="paste_here">Hello Kitty<span>Hello</span></pre>');
   is(pasteCount, 1, "paste event was not triggered");
 
+  await copyToClipBoard('1<span style="display: contents">2</span>3', true);
+  trans = getTransferableFromClipboard(true);
+  pasteInto(trans, '<div id="paste_here"></div>',"paste_here");
+  verifyContent('<div id="paste_here">1<span style="display: contents">2</span>3</div>');
+  is(pasteCount, 1, "paste event was not triggered");
+
   // test that we can preventDefault pastes
   pasteFunc = function (event) { event.preventDefault(); return false; };
   await copyToClipBoard("<pre>Kitty</pre><span>Hello</span>", true);
   trans = getTransferableFromClipboard(true);
   pasteInto(trans, '<pre id="paste_here">Hello </pre>',"paste_here");
   verifyContent('<pre id="paste_here">Hello </pre>');
   is(pasteCount, 0, "paste event was triggered");
 }
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -726,20 +726,20 @@ GetEventRegions(const ScrollNode& aLayer
 already_AddRefed<HitTestingTreeNode>
 APZCTreeManager::RecycleOrCreateNode(TreeBuildingState& aState,
                                      AsyncPanZoomController* aApzc,
                                      LayersId aLayersId)
 {
   // Find a node without an APZC and return it. Note that unless the layer tree
   // actually changes, this loop should generally do an early-return on the
   // first iteration, so it should be cheap in the common case.
-  for (size_t i = 0; i < aState.mNodesToDestroy.Length(); i++) {
+  for (int32_t i = aState.mNodesToDestroy.Length() - 1; i >= 0; i--) {
     RefPtr<HitTestingTreeNode> node = aState.mNodesToDestroy[i];
     if (!node->IsPrimaryHolder()) {
-      aState.mNodesToDestroy.RemoveElement(node);
+      aState.mNodesToDestroy.RemoveElementAt(i);
       node->RecycleWith(aApzc, aLayersId);
       return node.forget();
     }
   }
   RefPtr<HitTestingTreeNode> node = new HitTestingTreeNode(aApzc, false, aLayersId);
   return node.forget();
 }
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -613,16 +613,70 @@ FT2FontEntry::GetFontTable(uint32_t aTab
         }
     }
 
     // otherwise, use the default method (which in turn will call our
     // implementation of CopyFontTable)
     return gfxFontEntry::GetFontTable(aTableTag);
 }
 
+bool
+FT2FontEntry::HasVariations()
+{
+    if (mHasVariationsInitialized) {
+        return mHasVariations;
+    }
+    mHasVariationsInitialized = true;
+
+    AutoFTFace face(this);
+    if (face) {
+        mHasVariations =
+            FT_Face(face)->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS;
+    }
+
+    return mHasVariations;
+}
+
+void
+FT2FontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes)
+{
+    if (!HasVariations()) {
+        return;
+    }
+    AutoFTFace face(this);
+    if (!face) {
+        return;
+    }
+    FT_MM_Var* mmVar;
+    if (FT_Err_Ok != (FT_Get_MM_Var(face, &mmVar))) {
+        return;
+    }
+    gfxFT2Utils::GetVariationAxes(mmVar, aAxes);
+    FT_Done_MM_Var(FT_Face(face)->glyph->library, mmVar);
+}
+
+void
+FT2FontEntry::GetVariationInstances(
+    nsTArray<gfxFontVariationInstance>& aInstances)
+{
+    if (!HasVariations()) {
+        return;
+    }
+    AutoFTFace face(this);
+    if (!face) {
+        return;
+    }
+    FT_MM_Var* mmVar;
+    if (FT_Err_Ok != (FT_Get_MM_Var(face, &mmVar))) {
+        return;
+    }
+    gfxFT2Utils::GetVariationInstances(this, mmVar, aInstances);
+    FT_Done_MM_Var(FT_Face(face)->glyph->library, mmVar);
+}
+
 void
 FT2FontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                      FontListSizes* aSizes) const
 {
     gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontListSize +=
         mFilename.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
 }
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -82,32 +82,39 @@ public:
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
 
     virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override;
 
     virtual nsresult CopyFontTable(uint32_t aTableTag,
                                    nsTArray<uint8_t>& aBuffer) override;
 
+    bool HasVariations() override;
+    void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes) override;
+    void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) override;
+
     // Check for various kinds of brokenness, and set flags on the entry
     // accordingly so that we avoid using bad font tables
     void CheckForBrokenFont(gfxFontFamily *aFamily);
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const override;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const override;
 
     FT_Face mFTFace;
     cairo_font_face_t *mFontFace;
 
     nsCString mFilename;
     uint8_t   mFTFontIndex;
 
     mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontFreeType> mUnscaledFont;
+
+    bool mHasVariations = false;
+    bool mHasVariationsInitialized = false;
 };
 
 class FT2FontFamily : public gfxFontFamily
 {
 public:
     explicit FT2FontFamily(const nsAString& aName) :
         gfxFontFamily(aName) { }
 
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -6,16 +6,19 @@
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "mozilla/Likely.h"
 
 #ifdef HAVE_FONTCONFIG_FCFREETYPE_H
 #include <fontconfig/fcfreetype.h>
 #endif
 
+#include "ft2build.h"
+#include FT_MULTIPLE_MASTERS_H
+
 #include "prlink.h"
 
 uint32_t
 gfxFT2LockedFace::GetGlyph(uint32_t aCharCode)
 {
     if (MOZ_UNLIKELY(!mFace))
         return 0;
 
@@ -91,8 +94,67 @@ gfxFT2LockedFace::FindCharVariantFunctio
     }
 
     // Decrement the reference count incremented in
     // PR_FindFunctionSymbolAndLibrary.
     PR_UnloadLibrary(lib);
 
     return function;
 }
+
+/*static*/
+void
+gfxFT2Utils::GetVariationAxes(const FT_MM_Var* aMMVar,
+                              nsTArray<gfxFontVariationAxis>& aAxes)
+{
+    MOZ_ASSERT(aAxes.IsEmpty());
+    if (!aMMVar) {
+        return;
+    }
+    aAxes.SetCapacity(aMMVar->num_axis);
+    for (unsigned i = 0; i < aMMVar->num_axis; i++) {
+        const auto& a = aMMVar->axis[i];
+        gfxFontVariationAxis axis;
+        axis.mMinValue = a.minimum / 65536.0;
+        axis.mMaxValue = a.maximum / 65536.0;
+        axis.mDefaultValue = a.def / 65536.0;
+        axis.mTag = a.tag;
+        axis.mName.Assign(NS_ConvertUTF8toUTF16(a.name));
+        aAxes.AppendElement(axis);
+    }
+}
+
+/*static*/
+void
+gfxFT2Utils::GetVariationInstances(
+    gfxFontEntry* aFontEntry,
+    const FT_MM_Var* aMMVar,
+    nsTArray<gfxFontVariationInstance>& aInstances)
+{
+    MOZ_ASSERT(aInstances.IsEmpty());
+    if (!aMMVar) {
+        return;
+    }
+    hb_blob_t* nameTable =
+        aFontEntry->GetFontTable(TRUETYPE_TAG('n','a','m','e'));
+    if (!nameTable) {
+        return;
+    }
+    aInstances.SetCapacity(aMMVar->num_namedstyles);
+    for (unsigned i = 0; i < aMMVar->num_namedstyles; i++) {
+        const auto& ns = aMMVar->namedstyle[i];
+        gfxFontVariationInstance inst;
+        nsresult rv =
+            gfxFontUtils::ReadCanonicalName(nameTable, ns.strid, inst.mName);
+        if (NS_FAILED(rv)) {
+            continue;
+        }
+        inst.mValues.SetCapacity(aMMVar->num_axis);
+        for (unsigned j = 0; j < aMMVar->num_axis; j++) {
+            gfxFontVariationValue value;
+            value.mAxis = aMMVar->axis[j].tag;
+            value.mValue = ns.coords[j] / 65536.0;
+            inst.mValues.AppendElement(value);
+        }
+        aInstances.AppendElement(inst);
+    }
+    hb_blob_destroy(nameTable);
+}
--- a/gfx/thebes/gfxFT2Utils.h
+++ b/gfx/thebes/gfxFT2Utils.h
@@ -58,9 +58,27 @@ protected:
                                            FT_ULong charcode,
                                            FT_ULong variantSelector);
     CharVariantFunction FindCharVariantFunction();
 
     gfxFT2FontBase* MOZ_NON_OWNING_REF mGfxFont; // owned by caller
     FT_Face mFace;
 };
 
+
+// A couple of FreeType-based utilities shared by gfxFontconfigFontEntry
+// and FT2FontEntry.
+
+typedef struct FT_MM_Var_ FT_MM_Var;
+
+class gfxFT2Utils {
+public:
+    static void
+    GetVariationAxes(const FT_MM_Var* aMMVar,
+                     nsTArray<gfxFontVariationAxis>& aAxes);
+
+    static void
+    GetVariationInstances(gfxFontEntry* aFontEntry,
+                          const FT_MM_Var* aMMVar,
+                          nsTArray<gfxFontVariationInstance>& aInstances);
+};
+
 #endif /* GFX_FT2UTILS_H */
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1107,66 +1107,30 @@ gfxFontconfigFontEntry::GetMMVar()
         mMMVar = nullptr;
     }
     return mMMVar;
 }
 
 void
 gfxFontconfigFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes)
 {
-    MOZ_ASSERT(aAxes.IsEmpty());
-    FT_MM_Var* mmVar = GetMMVar();
-    if (!mmVar) {
+    if (!HasVariations()) {
         return;
     }
-    aAxes.SetCapacity(mmVar->num_axis);
-    for (unsigned i = 0; i < mmVar->num_axis; i++) {
-        const auto& a = mmVar->axis[i];
-        gfxFontVariationAxis axis;
-        axis.mMinValue = a.minimum / 65536.0;
-        axis.mMaxValue = a.maximum / 65536.0;
-        axis.mDefaultValue = a.def / 65536.0;
-        axis.mTag = a.tag;
-        axis.mName.Assign(NS_ConvertUTF8toUTF16(a.name));
-        aAxes.AppendElement(axis);
-    }
+    gfxFT2Utils::GetVariationAxes(GetMMVar(), aAxes);
 }
 
 void
 gfxFontconfigFontEntry::GetVariationInstances(
     nsTArray<gfxFontVariationInstance>& aInstances)
 {
-    MOZ_ASSERT(aInstances.IsEmpty());
-    FT_MM_Var* mmVar = GetMMVar();
-    if (!mmVar) {
-        return;
-    }
-    hb_blob_t* nameTable = GetFontTable(TRUETYPE_TAG('n','a','m','e'));
-    if (!nameTable) {
+    if (!HasVariations()) {
         return;
     }
-    aInstances.SetCapacity(mmVar->num_namedstyles);
-    for (unsigned i = 0; i < mmVar->num_namedstyles; i++) {
-        const auto& ns = mmVar->namedstyle[i];
-        gfxFontVariationInstance inst;
-        nsresult rv =
-            gfxFontUtils::ReadCanonicalName(nameTable, ns.strid, inst.mName);
-        if (NS_FAILED(rv)) {
-            continue;
-        }
-        inst.mValues.SetCapacity(mmVar->num_axis);
-        for (unsigned j = 0; j < mmVar->num_axis; j++) {
-            gfxFontVariationValue value;
-            value.mAxis = mmVar->axis[j].tag;
-            value.mValue = ns.coords[j] / 65536.0;
-            inst.mValues.AppendElement(value);
-        }
-        aInstances.AppendElement(inst);
-    }
-    hb_blob_destroy(nameTable);
+    gfxFT2Utils::GetVariationInstances(this, GetMMVar(), aInstances);
 }
 
 nsresult
 gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag,
                                       nsTArray<uint8_t>& aBuffer)
 {
     NS_ASSERTION(!mIsDataUserFont,
                  "data fonts should be reading tables directly from memory");
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -1077,37 +1077,54 @@ gfxFontEntry::GetVariationsForStyle(nsTA
                                     const gfxFontStyle& aStyle)
 {
     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
         return;
     }
 
     // Resolve high-level CSS properties from the requested style
     // (font-{style,weight,stretch}) to the appropriate variations.
-    float clampedWeight = Weight().Clamp(aStyle.weight).ToFloat();
+    // The value used is clamped to the range available in the font face,
+    // unless the face is a user font where no explicit descriptor was
+    // given, indicated by the corresponding 'auto' range-flag.
+    float weight = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoWeight))
+                   ? aStyle.weight.ToFloat()
+                   : Weight().Clamp(aStyle.weight).ToFloat();
     aResult.AppendElement(gfxFontVariation{HB_TAG('w','g','h','t'),
-                                           clampedWeight});
+                                           weight});
 
-    float clampedStretch = Stretch().Clamp(aStyle.stretch).Percentage();
+    float stretch = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoStretch))
+                    ? aStyle.stretch.Percentage()
+                    : Stretch().Clamp(aStyle.stretch).Percentage();
     aResult.AppendElement(gfxFontVariation{HB_TAG('w','d','t','h'),
-                                           clampedStretch});
+                                           stretch});
 
     if (SlantStyle().Min().IsOblique()) {
-        float clampedSlant =
-          aStyle.style.IsOblique()
-          ? SlantStyle().Clamp(aStyle.style).ObliqueAngle()
-          : aStyle.style.IsItalic()
-            ? SlantStyle().Clamp(FontSlantStyle::Oblique()).ObliqueAngle()
-            : SlantStyle().Clamp(FontSlantStyle::Oblique(0.0f)).ObliqueAngle();
+        // Figure out what slant angle we should try to match from the
+        // requested style.
+        float angle =
+            aStyle.style.IsNormal()
+                ? 0.0f
+                : aStyle.style.IsItalic()
+                    ? FontSlantStyle::Oblique().ObliqueAngle()
+                    : aStyle.style.ObliqueAngle();
+        // Clamp to the available range, unless the face is a user font
+        // with no explicit descriptor.
+        if (!(IsUserFont() && (mRangeFlags & RangeFlags::eAutoSlantStyle))) {
+            angle = SlantStyle().Clamp(
+                FontSlantStyle::Oblique(angle)).ObliqueAngle();
+        }
         aResult.AppendElement(gfxFontVariation{HB_TAG('s','l','n','t'),
-                                               clampedSlant});
+                                               angle});
     }
 
     // Although there is a registered tag 'ital', it is normally considered
-    // a binary toggle rather than a variable axis, 
+    // a binary toggle rather than a variable axis, so not set here.
+    // (For a non-standard font that implements 'ital' as an actual variation,
+    // authors can still use font-variation-settings to control it.)
 
     auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
         struct TagEquals {
             bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
                 return aIter.mTag == aTag;
             }
         };
         auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -360,28 +360,29 @@ public:
         uint32_t         rangeStart;
         uint32_t         rangeEnd;
         hb_tag_t         tags[3]; // one or two OpenType script tags to check,
                                   // plus a NULL terminator
     };
 
     bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags);
 
-    // For variation font support, which is not yet implemented on all
-    // platforms; default implementations assume it is not present.
-    virtual bool HasVariations()
-    {
-        return false;
-    }
-    virtual void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes)
-    {
-    }
-    virtual void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances)
-    {
-    }
+    /**
+     * Font-variation query methods.
+     *
+     * Font backends that don't support variations should provide empty
+     * implementations.
+     */
+    virtual bool HasVariations() = 0;
+
+    virtual void
+    GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes) = 0;
+
+    virtual void
+    GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) = 0;
 
     // Set up the entry's weight/stretch/style ranges according to axes found
     // by GetVariationAxes (for installed fonts; do NOT call this for user
     // fonts, where the ranges are provided by @font-face descriptors).
     void SetupVariationRanges();
 
     // Get variation axis settings that should be used to implement a particular
     // font style using this resource.
@@ -418,16 +419,30 @@ public:
     uint32_t         mUVSOffset = 0;
 
     uint32_t         mLanguageOverride = NO_FONT_LANGUAGE_OVERRIDE;
 
     WeightRange      mWeightRange = WeightRange(FontWeight(500));
     StretchRange     mStretchRange = StretchRange(FontStretch::Normal());
     SlantStyleRange  mStyleRange = SlantStyleRange(FontSlantStyle::Normal());
 
+    // For user fonts (only), we need to record whether or not weight/stretch/
+    // slant variations should be clamped to the range specified in the entry
+    // properties. When the @font-face rule omitted one or more of these
+    // descriptors, it is treated as the initial value for font-matching (and
+    // so that is what we record in the font entry), but when rendering the
+    // range is NOT clamped.
+    enum class RangeFlags : uint8_t {
+        eNoFlags        = 0,
+        eAutoWeight     = (1 << 0),
+        eAutoStretch    = (1 << 1),
+        eAutoSlantStyle = (1 << 2)
+    };
+    RangeFlags       mRangeFlags = RangeFlags::eNoFlags;
+
     bool             mFixedPitch  : 1;
     bool             mIsBadUnderlineFont : 1;
     bool             mIsUserFontContainer : 1; // userfont entry
     bool             mIsDataUserFont : 1;      // platform font entry (data)
     bool             mIsLocalUserFont : 1;     // platform font entry (local)
     bool             mStandardFace : 1;
     bool             mIgnoreGDEF  : 1;
     bool             mIgnoreGSUB  : 1;
@@ -622,16 +637,17 @@ private:
     };
 
     mozilla::UniquePtr<nsTHashtable<FontTableHashEntry> > mFontTableCache;
 
     gfxFontEntry(const gfxFontEntry&);
     gfxFontEntry& operator=(const gfxFontEntry&);
 };
 
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontEntry::RangeFlags)
 
 // used when iterating over all fonts looking for a match for a given character
 struct GlobalFontMatch {
     GlobalFontMatch(const uint32_t aCharacter,
                     const gfxFontStyle *aStyle) :
         mCh(aCharacter), mStyle(aStyle),
         mMatchRank(0.0f), mCount(0), mCmapsTested(0)
         {
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -158,16 +158,21 @@ public:
 
     virtual bool TestCharacterMap(uint32_t aCh);
 
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
     gfxFontEntry* Clone() const override;
 
+    // GDI backend doesn't support font variations:
+    bool HasVariations() override { return false; }
+    void GetVariationAxes(nsTArray<gfxFontVariationAxis>&) override {}
+    void GetVariationInstances(nsTArray<gfxFontVariationInstance>&) override {}
+
     // create a font entry for a font with a given name
     static GDIFontEntry* CreateFontEntry(const nsAString& aName,
                                          gfxWindowsFontType aFontType,
                                          SlantStyleRange aStyle,
                                          WeightRange aWeight,
                                          StretchRange aStretch,
                                          gfxUserFontData* aUserFontData);
 
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -18,16 +18,17 @@
 #include "nsNetUtil.h"
 #include "NullPrincipal.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "nsStreamUtils.h"
 #include "nsIPrincipal.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/SVGDocument.h"
 #include "mozilla/LoadInfo.h"
 #include "nsSVGUtils.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsContentUtils.h"
 #include "gfxFont.h"
 #include "nsSMILAnimationController.h"
 #include "gfxContext.h"
 #include "harfbuzz/hb.h"
@@ -210,20 +211,21 @@ gfxSVGGlyphsDocument::FindGlyphElements(
  * @return true iff rendering succeeded
  */
 void
 gfxSVGGlyphs::RenderGlyph(gfxContext *aContext, uint32_t aGlyphId,
                           SVGContextPaint* aContextPaint)
 {
     gfxContextAutoSaveRestore aContextRestorer(aContext);
 
-    Element *glyph = mGlyphIdMap.Get(aGlyphId);
+    Element* glyph = mGlyphIdMap.Get(aGlyphId);
     MOZ_ASSERT(glyph, "No glyph element. Should check with HasSVGGlyph() first!");
 
-    AutoSetRestoreSVGContextPaint autoSetRestore(aContextPaint, glyph->OwnerDoc());
+    AutoSetRestoreSVGContextPaint autoSetRestore(
+        *aContextPaint, *glyph->OwnerDoc()->AsSVGDocument());
 
     nsSVGUtils::PaintSVGGlyph(glyph, aContext);
 }
 
 bool
 gfxSVGGlyphs::GetGlyphExtents(uint32_t aGlyphId, const gfxMatrix& aSVGToAppSpace,
                               gfxRect *aResult)
 {
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -107,17 +107,18 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
              WeightRange aWeight,
              StretchRange aStretch,
              SlantStyleRange aStyle,
              const nsTArray<gfxFontFeature>& aFeatureSettings,
              const nsTArray<gfxFontVariation>& aVariationSettings,
              uint32_t aLanguageOverride,
              gfxCharacterMap* aUnicodeRanges,
-             uint8_t aFontDisplay)
+             uint8_t aFontDisplay,
+             RangeFlags aRangeFlags)
     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
       mUserFontLoadState(STATUS_NOT_LOADED),
       mFontDataLoadingState(NOT_LOADING),
       mUnsupportedFormat(false),
       mFontDisplay(aFontDisplay),
       mLoader(nullptr),
       mFontSet(aFontSet)
 {
@@ -126,16 +127,17 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
     mSrcIndex = 0;
     mWeightRange = aWeight;
     mStretchRange = aStretch;
     mStyleRange = aStyle;
     mFeatureSettings.AppendElements(aFeatureSettings);
     mVariationSettings.AppendElements(aVariationSettings);
     mLanguageOverride = aLanguageOverride;
     mCharacterMap = aUnicodeRanges;
+    mRangeFlags = aRangeFlags;
 }
 
 gfxUserFontEntry::~gfxUserFontEntry()
 {
     // Assert that we don't drop any gfxUserFontEntry objects during a Servo
     // traversal, since PostTraversalTask objects can hold raw pointers to
     // gfxUserFontEntry objects.
     MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
@@ -145,26 +147,28 @@ bool
 gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                           WeightRange aWeight,
                           StretchRange aStretch,
                           SlantStyleRange aStyle,
                           const nsTArray<gfxFontFeature>& aFeatureSettings,
                           const nsTArray<gfxFontVariation>& aVariationSettings,
                           uint32_t aLanguageOverride,
                           gfxCharacterMap* aUnicodeRanges,
-                          uint8_t aFontDisplay)
+                          uint8_t aFontDisplay,
+                          RangeFlags aRangeFlags)
 {
     return Weight() == aWeight &&
            Stretch() == aStretch &&
            SlantStyle() == aStyle &&
            mFeatureSettings == aFeatureSettings &&
            mVariationSettings == aVariationSettings &&
            mLanguageOverride == aLanguageOverride &&
            mSrcList == aFontFaceSrcList &&
            mFontDisplay == aFontDisplay &&
+           mRangeFlags == aRangeFlags &&
            ((!aUnicodeRanges && !mCharacterMap) ||
             (aUnicodeRanges && mCharacterMap && mCharacterMap->Equals(aUnicodeRanges)));
 }
 
 gfxFont*
 gfxUserFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold)
 {
     NS_NOTREACHED("should only be creating a gfxFont"
@@ -529,16 +533,17 @@ gfxUserFontEntry::DoLoadNextSrc(bool aFo
                      mFontSet, mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
                      NS_ConvertUTF16toUTF8(mFamilyName).get(),
                      uint32_t(mFontSet->mGeneration)));
                 fe->mFeatureSettings.AppendElements(mFeatureSettings);
                 fe->mVariationSettings.AppendElements(mVariationSettings);
                 fe->mLanguageOverride = mLanguageOverride;
                 fe->mFamilyName = mFamilyName;
+                fe->mRangeFlags = mRangeFlags;
                 // For src:local(), we don't care whether the request is from
                 // a private window as there's no issue of caching resources;
                 // local fonts are just available all the time.
                 StoreUserFontData(fe, false, nsString(), nullptr, 0,
                                   gfxUserFontData::kUnknownCompression);
                 mPlatformFontEntry = fe;
                 SetLoadState(STATUS_LOADED);
                 Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE,
@@ -799,16 +804,17 @@ gfxUserFontEntry::LoadPlatformFont(const
         }
 
         // copy OpenType feature/language settings from the userfont entry to the
         // newly-created font entry
         fe->mFeatureSettings.AppendElements(mFeatureSettings);
         fe->mVariationSettings.AppendElements(mVariationSettings);
         fe->mLanguageOverride = mLanguageOverride;
         fe->mFamilyName = mFamilyName;
+        fe->mRangeFlags = mRangeFlags;
         StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
                           &metadata, metaOrigLen, compression);
         if (LOG_ENABLED()) {
             LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) "
                  "(%p) gen: %8.8x compress: %d%%\n",
                  mFontSet, mSrcIndex,
                  mSrcList[mSrcIndex].mURI->GetSpecOrDefault().get(),
                  NS_ConvertUTF16toUTF8(mFamilyName).get(),
@@ -936,93 +942,77 @@ gfxUserFontSet::FindOrCreateUserFontEntr
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay)
+                               uint8_t aFontDisplay,
+                               RangeFlags aRangeFlags)
 {
     RefPtr<gfxUserFontEntry> entry;
 
     // If there's already a userfont entry in the family whose descriptors all match,
     // we can just move it to the end of the list instead of adding a new
     // face that will always "shadow" the old one.
     // Note that we can't do this for platform font entries, even if the
     // style descriptors match, as they might have had a different source list,
     // but we no longer have the old source list available to check.
     gfxUserFontFamily* family = LookupFamily(aFamilyName);
     if (family) {
         entry = FindExistingUserFontEntry(family, aFontFaceSrcList, aWeight,
                                           aStretch, aStyle,
                                           aFeatureSettings, aVariationSettings,
                                           aLanguageOverride,
-                                          aUnicodeRanges, aFontDisplay);
+                                          aUnicodeRanges, aFontDisplay,
+                                          aRangeFlags);
     }
 
     if (!entry) {
       entry = CreateUserFontEntry(aFontFaceSrcList, aWeight, aStretch,
                                   aStyle, aFeatureSettings, aVariationSettings,
                                   aLanguageOverride, aUnicodeRanges,
-                                  aFontDisplay);
+                                  aFontDisplay, aRangeFlags);
       entry->mFamilyName = aFamilyName;
     }
 
     return entry.forget();
 }
 
-already_AddRefed<gfxUserFontEntry>
-gfxUserFontSet::CreateUserFontEntry(
-                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
-                               const nsTArray<gfxFontFeature>& aFeatureSettings,
-                               const nsTArray<gfxFontVariation>& aVariationSettings,
-                               uint32_t aLanguageOverride,
-                               gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay)
-{
-
-    RefPtr<gfxUserFontEntry> userFontEntry =
-        new gfxUserFontEntry(this, aFontFaceSrcList, aWeight,
-                              aStretch, aStyle, aFeatureSettings, aVariationSettings,
-                              aLanguageOverride, aUnicodeRanges, aFontDisplay);
-    return userFontEntry.forget();
-}
-
 gfxUserFontEntry*
 gfxUserFontSet::FindExistingUserFontEntry(
                                gfxUserFontFamily* aFamily,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay)
+                               uint8_t aFontDisplay,
+                               RangeFlags aRangeFlags)
 {
     nsTArray<RefPtr<gfxFontEntry>>& fontList = aFamily->GetFontList();
 
     for (size_t i = 0, count = fontList.Length(); i < count; i++) {
         if (!fontList[i]->mIsUserFontContainer) {
             continue;
         }
 
         gfxUserFontEntry* existingUserFontEntry =
             static_cast<gfxUserFontEntry*>(fontList[i].get());
         if (!existingUserFontEntry->Matches(aFontFaceSrcList,
                                             aWeight, aStretch, aStyle,
                                             aFeatureSettings, aVariationSettings,
                                             aLanguageOverride,
-                                            aUnicodeRanges, aFontDisplay)) {
+                                            aUnicodeRanges, aFontDisplay,
+                                            aRangeFlags)) {
             continue;
         }
 
         return existingUserFontEntry;
     }
 
     return nullptr;
 }
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -186,16 +186,17 @@ class gfxUserFontSet {
 
 public:
     typedef mozilla::FontStretch FontStretch;
     typedef mozilla::StretchRange StretchRange;
     typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::SlantStyleRange SlantStyleRange;
     typedef mozilla::FontWeight FontWeight;
     typedef mozilla::WeightRange WeightRange;
+    typedef gfxFontEntry::RangeFlags RangeFlags;
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxUserFontSet)
 
     gfxUserFontSet();
 
     enum {
         // no flags ==> no hint set
         // unknown ==> unknown format hint set
@@ -238,31 +239,33 @@ public:
                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                               WeightRange aWeight,
                               StretchRange aStretch,
                               SlantStyleRange aStyle,
                               const nsTArray<gfxFontFeature>& aFeatureSettings,
                               const nsTArray<gfxFontVariation>& aVariationSettings,
                               uint32_t aLanguageOverride,
                               gfxCharacterMap* aUnicodeRanges,
-                              uint8_t aFontDisplay) = 0;
+                              uint8_t aFontDisplay,
+                              RangeFlags aRangeFlags) = 0;
 
     // creates a font face for the specified family, or returns an existing
     // matching entry on the family if there is one
     already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay);
+                               uint8_t aFontDisplay,
+                               RangeFlags aRangeFlags);
 
     // add in a font face for which we have the gfxUserFontEntry already
     void AddUserFontEntry(const nsAString& aFamilyName,
                           gfxUserFontEntry* aUserFontEntry);
 
     // Whether there is a face with this family name
     bool HasFamily(const nsAString& aFamilyName) const
     {
@@ -506,17 +509,18 @@ protected:
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    WeightRange aWeight,
                                    StretchRange aStretch,
                                    SlantStyleRange aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
-                                   uint8_t aFontDisplay);
+                                   uint8_t aFontDisplay,
+                                   RangeFlags aRangeFlags);
 
     // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
     // family if there is one
     gfxUserFontFamily* GetFamily(const nsAString& aFamilyName);
 
     // font families defined by @font-face rules
     nsRefPtrHashtable<nsStringHashKey, gfxUserFontFamily> mFontFamilies;
 
@@ -556,30 +560,32 @@ public:
                      const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                      WeightRange aWeight,
                      StretchRange aStretch,
                      SlantStyleRange aStyle,
                      const nsTArray<gfxFontFeature>& aFeatureSettings,
                      const nsTArray<gfxFontVariation>& aVariationSettings,
                      uint32_t aLanguageOverride,
                      gfxCharacterMap* aUnicodeRanges,
-                     uint8_t aFontDisplay);
+                     uint8_t aFontDisplay,
+                     RangeFlags aRangeFlags);
 
     virtual ~gfxUserFontEntry();
 
     // Return whether the entry matches the given list of attributes
     bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                  WeightRange aWeight,
                  StretchRange aStretch,
                  SlantStyleRange aStyle,
                  const nsTArray<gfxFontFeature>& aFeatureSettings,
                  const nsTArray<gfxFontVariation>& aVariationSettings,
                  uint32_t aLanguageOverride,
                  gfxCharacterMap* aUnicodeRanges,
-                 uint8_t aFontDisplay);
+                 uint8_t aFontDisplay,
+                 RangeFlags aRangeFlags);
 
     gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle,
                                 bool aNeedsBold) override;
 
     gfxFontEntry* GetPlatformFontEntry() const { return mPlatformFontEntry; }
 
     // is the font loading or loaded, or did it fail?
     UserFontLoadState LoadState() const { return mUserFontLoadState; }
@@ -628,16 +634,28 @@ public:
     gfxUserFontSet* GetUserFontSet() const { return mFontSet; }
 #endif
 
     const nsTArray<gfxFontFaceSrc>& SourceList() const
     {
       return mSrcList;
     }
 
+    // The variation-query APIs should not be called on placeholders.
+    bool HasVariations() override {
+      MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
+      return false;
+    }
+    void GetVariationAxes(nsTArray<gfxFontVariationAxis>&) override {
+      MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
+    }
+    void GetVariationInstances(nsTArray<gfxFontVariationInstance>&) override {
+      MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
+    }
+
 protected:
     const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
                                         uint32_t aLength,
                                         uint32_t& aSaneLength,
                                         gfxUserFontType aFontType);
 
     // attempt to load the next resource in the src list.
     void LoadNextSrc();
--- a/gfx/webrender_bindings/Moz2DImageRenderer.cpp
+++ b/gfx/webrender_bindings/Moz2DImageRenderer.cpp
@@ -84,33 +84,33 @@ static struct FontDeleteLog {
   }
 
   // Store namespace clears as font id 0, since this will never be allocated.
   void Add(WrIdNamespace aNamespace) {
     AddEntry(AsUint64(WrFontKey { aNamespace, 0 }));
   }
 
   void AddAll() {
-    AddEntry(0);
+    AddEntry(~0);
   }
 
   // Find a matching entry in the log, searching backwards starting at the newest
   // entry and finishing with the oldest entry. Returns a brief description of why
   // the font was deleted, if known.
   const char* Find(WrFontKey aKey) {
     uint64_t keyEntry = AsUint64(aKey);
     uint64_t namespaceEntry = AsUint64(WrFontKey { aKey.mNamespace, 0 });
     size_t offset = mNextEntry;
     do {
       offset = (offset + MAX_ENTRIES - 1) % MAX_ENTRIES;
       if (mEntries[offset] == keyEntry) {
         return "deleted font";
       } else if (mEntries[offset] == namespaceEntry) {
         return "cleared namespace";
-      } else if (!mEntries[offset]) {
+      } else if (mEntries[offset] == (uint64_t)~0) {
         return "cleared all";
       }
     } while (offset != mNextEntry);
     return "unknown font";
   }
 } sFontDeleteLog;
 
 void
--- a/image/SVGDocumentWrapper.cpp
+++ b/image/SVGDocumentWrapper.cpp
@@ -2,20 +2,20 @@
 /* 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 "SVGDocumentWrapper.h"
 
 #include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/SVGDocument.h"
 #include "nsICategoryManager.h"
 #include "nsIChannel.h"
 #include "nsIContentViewer.h"
-#include "nsIDocument.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIHttpChannel.h"
 #include "nsIObserverService.h"
 #include "nsIParser.h"
 #include "nsIPresShell.h"
 #include "nsIRequest.h"
 #include "nsIStreamListener.h"
 #include "nsIXMLContentSink.h"
@@ -413,29 +413,32 @@ SVGDocumentWrapper::UnregisterForXPCOMSh
   } else {
     mRegisteredForXPCOMShutdown = false;
   }
 }
 
 void
 SVGDocumentWrapper::FlushLayout()
 {
-  if (nsIDocument* doc = GetDocument()) {
+  if (SVGDocument* doc = GetDocument()) {
     doc->FlushPendingNotifications(FlushType::Layout);
   }
 }
 
-nsIDocument*
+SVGDocument*
 SVGDocumentWrapper::GetDocument()
 {
   if (!mViewer) {
     return nullptr;
   }
-
-  return mViewer->GetDocument(); // May be nullptr.
+  nsIDocument* doc = mViewer->GetDocument();
+  if (!doc) {
+    return nullptr;
+  }
+  return doc->AsSVGDocument();
 }
 
 SVGSVGElement*
 SVGDocumentWrapper::GetRootSVGElem()
 {
   if (!mViewer) {
     return nullptr; // Can happen during destruction
   }
--- a/image/SVGDocumentWrapper.h
+++ b/image/SVGDocumentWrapper.h
@@ -25,16 +25,17 @@ class nsIFrame;
 #define OBSERVER_SVC_CID "@mozilla.org/observer-service;1"
 
 // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
 #undef GetCurrentTime
 
 namespace mozilla {
 namespace dom {
 class SVGSVGElement;
+class SVGDocument;
 } // namespace dom
 
 namespace image {
 
 class SVGDocumentWrapper final : public nsIStreamListener,
                                  public nsIObserver,
                                  nsSupportsWeakReference
 {
@@ -49,17 +50,17 @@ public:
   enum Dimension {
     eWidth,
     eHeight
   };
 
   /**
    * Returns the wrapped document, or nullptr on failure. (No AddRef.)
    */
-  nsIDocument* GetDocument();
+  mozilla::dom::SVGDocument* GetDocument();
 
   /**
    * Returns the root <svg> element for the wrapped document, or nullptr on
    * failure.
    */
   mozilla::dom::SVGSVGElement* GetRootSVGElem();
 
   /**
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -10,16 +10,17 @@
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "imgFrame.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/SVGSVGElement.h"
+#include "mozilla/dom/SVGDocument.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Tuple.h"
 #include "nsIPresShell.h"
 #include "nsIStreamListener.h"
 #include "nsMimeTypes.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
@@ -122,17 +123,17 @@ protected:
 };
 
 NS_IMPL_ISUPPORTS(SVGRootRenderingObserver, nsIMutationObserver)
 
 class SVGParseCompleteListener final : public nsStubDocumentObserver {
 public:
   NS_DECL_ISUPPORTS
 
-  SVGParseCompleteListener(nsIDocument* aDocument,
+  SVGParseCompleteListener(SVGDocument* aDocument,
                            VectorImage* aImage)
     : mDocument(aDocument)
     , mImage(aImage)
   {
     MOZ_ASSERT(mDocument, "Need an SVG document");
     MOZ_ASSERT(mImage, "Need an image");
 
     mDocument->AddObserver(this);
@@ -166,17 +167,17 @@ public:
     MOZ_ASSERT(mDocument, "Duplicate call to Cancel");
     if (mDocument) {
       mDocument->RemoveObserver(this);
       mDocument = nullptr;
     }
   }
 
 private:
-  nsCOMPtr<nsIDocument> mDocument;
+  RefPtr<SVGDocument> mDocument;
   VectorImage* const mImage; // Raw pointer to owner.
 };
 
 NS_IMPL_ISUPPORTS(SVGParseCompleteListener, nsIDocumentObserver)
 
 class SVGLoadEventListener final : public nsIDOMEventListener {
 public:
   NS_DECL_ISUPPORTS
@@ -337,22 +338,25 @@ public:
     : mIsDrawing(aIsDrawing)
     // Apply any 'preserveAspectRatio' override (if specified) to the root
     // element:
     , mPAR(aParams.svgContext, aSVGDocumentWrapper->GetRootSVGElem())
     // Set the animation time:
     , mTime(aSVGDocumentWrapper->GetRootSVGElem(), aParams.animationTime)
   {
     MOZ_ASSERT(!aIsDrawing);
+    MOZ_ASSERT(aSVGDocumentWrapper->GetDocument());
+
     aIsDrawing = true;
 
     // Set context paint (if specified) on the document:
     if (aContextPaint) {
-      mContextPaint.emplace(aParams.svgContext->GetContextPaint(),
-                            aSVGDocumentWrapper->GetDocument());
+      MOZ_ASSERT(aParams.svgContext->GetContextPaint());
+      mContextPaint.emplace(*aParams.svgContext->GetContextPaint(),
+                            *aSVGDocumentWrapper->GetDocument());
     }
   }
 
 private:
   AutoRestore<bool> mIsDrawing;
   AutoPreserveAspectRatioOverride mPAR;
   AutoSVGTimeSetRestore mTime;
   Maybe<AutoSetRestoreSVGContextPaint> mContextPaint;
@@ -413,17 +417,17 @@ VectorImage::Init(const char* aMimeType,
 
 size_t
 VectorImage::SizeOfSourceWithComputedFallback(SizeOfState& aState) const
 {
   if (!mSVGDocumentWrapper) {
     return 0; // No document, so no memory used for the document.
   }
 
-  nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
+  SVGDocument* doc = mSVGDocumentWrapper->GetDocument();
   if (!doc) {
     return 0; // No document, so no memory used for the document.
   }
 
   nsWindowSizes windowSizes(aState);
   doc->DocAddSizeOfIncludingThis(windowSizes);
 
   if (windowSizes.getTotalSize() == 0) {
@@ -1368,17 +1372,17 @@ VectorImage::OnStartRequest(nsIRequest* 
   }
 
   // Create a listener to wait until the SVG document is fully loaded, which
   // will signal that this image is ready to render. Certain error conditions
   // will prevent us from ever getting this notification, so we also create a
   // listener that waits for parsing to complete and cancels the
   // SVGLoadEventListener if needed. The listeners are automatically attached
   // to the document by their constructors.
-  nsIDocument* document = mSVGDocumentWrapper->GetDocument();
+  SVGDocument* document = mSVGDocumentWrapper->GetDocument();
   mLoadEventListener = new SVGLoadEventListener(document, this);
   mParseCompleteListener = new SVGParseCompleteListener(document, this);
 
   return NS_OK;
 }
 
 //******************************************************************************
 NS_IMETHODIMP
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -703,37 +703,38 @@ function CreateArrayIterator(obj, kind) 
     UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
     return iterator;
 }
 
 // ES6, 22.1.5.2.1
 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next
 function ArrayIteratorNext() {
     // Step 1-3.
-    if (!IsObject(this) || !IsArrayIterator(this)) {
+    var obj;
+    if (!IsObject(this) || (obj = GuardToArrayIterator(this)) === null) {
         return callFunction(CallArrayIteratorMethodIfWrapped, this,
                             "ArrayIteratorNext");
     }
 
     // Step 4.
-    var a = UnsafeGetReservedSlot(this, ITERATOR_SLOT_TARGET);
+    var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET);
     var result = { value: undefined, done: false };
 
     // Step 5.
     if (a === null) {
       result.done = true;
       return result;
     }
 
     // Step 6.
     // The index might not be an integer, so we have to do a generic get here.
-    var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+    var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
 
     // Step 7.
-    var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+    var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
 
     // Step 8-9.
     var len;
     if (IsPossiblyWrappedTypedArray(a)) {
         len = PossiblyWrappedTypedArrayLength(a);
 
         // If the length is non-zero, the buffer can't be detached.
         if (len === 0) {
@@ -741,23 +742,23 @@ function ArrayIteratorNext() {
                 ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
         }
     } else {
         len = ToLength(a.length);
     }
 
     // Step 10.
     if (index >= len) {
-        UnsafeSetReservedSlot(this, ITERATOR_SLOT_TARGET, null);
+        UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null);
         result.done = true;
         return result;
     }
 
     // Step 11.
-    UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1);
+    UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1);
 
     // Step 16.
     if (itemKind === ITEM_KIND_VALUE) {
         result.value = a[index];
         return result;
     }
 
     // Step 13.
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -27,18 +27,18 @@ function MapConstructorInit(iterable) {
 
 // ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
 // 23.1.3.5 Map.prototype.forEach ( callbackfn [ , thisArg ] )
 function MapForEach(callbackfn, thisArg = undefined) {
     // Step 1.
     var M = this;
 
     // Steps 2-3.
-    if (!IsObject(M) || !IsMapObject(M))
-        return callFunction(CallMapMethodIfWrapped, M, callbackfn, thisArg, "MapForEach");
+    if (!IsObject(M) || (M = GuardToMapObject(M)) === null)
+        return callFunction(CallMapMethodIfWrapped, this, callbackfn, thisArg, "MapForEach");
 
     // Step 4.
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     // Steps 5-8.
     var entries = callFunction(std_Map_iterator, M);
 
@@ -70,18 +70,18 @@ function MapEntries() {
 
 var iteratorTemp = { mapIterationResultPair: null };
 
 function MapIteratorNext() {
     // Step 1.
     var O = this;
 
     // Steps 2-3.
-    if (!IsObject(O) || !IsMapIterator(O))
-        return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext");
+    if (!IsObject(O) || (O = GuardToMapIterator(O)) === null)
+        return callFunction(CallMapIteratorMethodIfWrapped, this, "MapIteratorNext");
 
     // Steps 4-5 (implemented in _GetNextMapEntryForIterator).
     // Steps 8-9 (omitted).
 
     var mapIterationResultPair = iteratorTemp.mapIterationResultPair;
     if (!mapIterationResultPair) {
         mapIterationResultPair = iteratorTemp.mapIterationResultPair =
             _CreateMapIterationResultPair();
@@ -90,17 +90,17 @@ function MapIteratorNext() {
     var retVal = {value: undefined, done: true};
 
     // Step 10.a, 11.
     var done = _GetNextMapEntryForIterator(O, mapIterationResultPair);
     if (!done) {
         // Steps 10.b-c (omitted).
 
         // Step 6.
-        var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+        var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
 
         var result;
         if (itemKind === ITEM_KIND_KEY) {
             // Step 10.d.i.
             result = mapIterationResultPair[0];
         } else if (itemKind === ITEM_KIND_VALUE) {
             // Step 10.d.ii.
             result = mapIterationResultPair[1];
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -807,17 +807,18 @@ ModuleObject::initialEnvironment() const
 {
     Value value = getReservedSlot(EnvironmentSlot);
     return value.toObject().as<ModuleEnvironmentObject>();
 }
 
 ModuleEnvironmentObject*
 ModuleObject::environment() const
 {
-    MOZ_ASSERT(!hadEvaluationError());
+    // Note that this it's valid to call this even if there was an error
+    // evaluating the module.
 
     // According to the spec the environment record is created during
     // instantiation, but we create it earlier than that.
     if (status() < MODULE_STATUS_INSTANTIATED)
         return nullptr;
 
     return &initialEnvironment();
 }
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -21,18 +21,18 @@ function SetConstructorInit(iterable) {
 
 // ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
 // 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] )
 function SetForEach(callbackfn, thisArg = undefined) {
     // Step 1.
     var S = this;
 
     // Steps 2-3.
-    if (!IsObject(S) || !IsSetObject(S))
-        return callFunction(CallSetMethodIfWrapped, S, callbackfn, thisArg, "SetForEach");
+    if (!IsObject(S) || (S = GuardToSetObject(S)) === null)
+        return callFunction(CallSetMethodIfWrapped, this, callbackfn, thisArg, "SetForEach");
 
     // Step 4.
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     // Steps 5-8.
     var values = callFunction(std_Set_iterator, S);
 
@@ -68,35 +68,35 @@ function SetSpecies() {
 
 var setIteratorTemp = { setIterationResult: null };
 
 function SetIteratorNext() {
     // Step 1.
     var O = this;
 
     // Steps 2-3.
-    if (!IsObject(O) || !IsSetIterator(O))
-        return callFunction(CallSetIteratorMethodIfWrapped, O, "SetIteratorNext");
+    if (!IsObject(O) || (O = GuardToSetIterator(O)) === null)
+        return callFunction(CallSetIteratorMethodIfWrapped, this, "SetIteratorNext");
 
     // Steps 4-5 (implemented in _GetNextSetEntryForIterator).
     // Steps 8-9 (omitted).
 
     var setIterationResult = setIteratorTemp.setIterationResult;
     if (!setIterationResult)
         setIterationResult = setIteratorTemp.setIterationResult = _CreateSetIterationResult();
 
     var retVal = {value: undefined, done: true};
 
     // Steps 10.a, 11.
     var done = _GetNextSetEntryForIterator(O, setIterationResult);
     if (!done) {
         // Steps 10.b-c (omitted).
 
         // Step 6.
-        var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+        var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
 
         var result;
         if (itemKind === ITEM_KIND_VALUE) {
             // Step 10.d.i.
             result = setIterationResult[0];
         } else {
             // Step 10.d.ii.
             assert(itemKind === ITEM_KIND_KEY_AND_VALUE, itemKind);
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -537,26 +537,27 @@ function String_iterator() {
     var S = ToString(this);
     var iterator = NewStringIterator();
     UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, S);
     UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
     return iterator;
 }
 
 function StringIteratorNext() {
-    if (!IsObject(this) || !IsStringIterator(this)) {
+    var obj;
+    if (!IsObject(this) || (obj = GuardToStringIterator(this)) === null) {
         return callFunction(CallStringIteratorMethodIfWrapped, this,
                             "StringIteratorNext");
     }
 
-    var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET);
+    var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET);
     // We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in
     // SelfHostring.cpp) so our current index can never be anything other than
     // an Int32Value.
-    var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+    var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
     var size = S.length;
     var result = { value: undefined, done: false };
 
     if (index >= size) {
         result.done = true;
         return result;
     }
 
@@ -565,17 +566,17 @@ function StringIteratorNext() {
     if (first >= 0xD800 && first <= 0xDBFF && index + 1 < size) {
         var second = callFunction(std_String_charCodeAt, S, index + 1);
         if (second >= 0xDC00 && second <= 0xDFFF) {
             first = (first - 0xD800) * 0x400 + (second - 0xDC00) + 0x10000;
             charCount = 2;
         }
     }
 
-    UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
+    UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
 
     // Communicate |first|'s possible range to the compiler.
     result.value = callFunction(std_String_fromCodePoint, null, first & 0x1fffff);
 
     return result;
 }
 
 var collatorCache = new Record();
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1,37 +1,37 @@
 /* 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/. */
 
 function ViewedArrayBufferIfReified(tarray) {
     assert(IsTypedArray(tarray), "non-typed array asked for its buffer");
 
     var buf = UnsafeGetReservedSlot(tarray, JS_TYPEDARRAYLAYOUT_BUFFER_SLOT);
-    assert(buf === null || (IsObject(buf) && (IsArrayBuffer(buf) || IsSharedArrayBuffer(buf))),
+    assert(buf === null || (IsObject(buf) && (GuardToArrayBuffer(buf) !== null || GuardToSharedArrayBuffer(buf) !== null)),
            "unexpected value in buffer slot");
     return buf;
 }
 
 function IsDetachedBuffer(buffer) {
     // A typed array with a null buffer has never had its buffer exposed to
     // become detached.
     if (buffer === null)
         return false;
 
-    assert(IsArrayBuffer(buffer) || IsSharedArrayBuffer(buffer),
+    assert(GuardToArrayBuffer(buffer) !== null || GuardToSharedArrayBuffer(buffer) !== null,
            "non-ArrayBuffer passed to IsDetachedBuffer");
 
     // Shared array buffers are not detachable.
     //
     // This check is more expensive than desirable, but IsDetachedBuffer is
     // only hot for non-shared memory in SetFromNonTypedArray, so there is an
     // optimization in place there to avoid incurring the cost here.  An
     // alternative is to give SharedArrayBuffer the same layout as ArrayBuffer.
-    if (IsSharedArrayBuffer(buffer))
+    if ((buffer = GuardToArrayBuffer(buffer)) === null)
         return false;
 
     var flags = UnsafeGetInt32FromReservedSlot(buffer, JS_ARRAYBUFFER_FLAGS_SLOT);
     return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
 }
 
 function TypedArrayLengthMethod() {
     return TypedArrayLength(this);
@@ -886,17 +886,18 @@ function SetFromNonTypedArray(target, ar
         ThrowRangeError(JSMSG_BAD_INDEX);
 
     // Step 22.
     var k = 0;
 
     // Optimization: if the buffer is shared then it is not detachable
     // and also not inline, so avoid checking overhead inside the loop in
     // that case.
-    var isShared = targetBuffer !== null && IsSharedArrayBuffer(targetBuffer);
+    var isShared = targetBuffer !== null
+                   && (targetBuffer = GuardToSharedArrayBuffer(targetBuffer)) !== null;
 
     // Steps 12-15, 21, 23-24.
     while (targetOffset < limitOffset) {
         // Steps 24a-c.
         var kNumber = ToNumber(src[k]);
 
         // Step 24d.  This explicit check will be unnecessary when we implement
         // throw-on-getting/setting-element-in-detached-buffer semantics.
@@ -1603,18 +1604,18 @@ function IterableToList(items, method) {
 
 // ES 2016 draft Mar 25, 2016 24.1.4.3.
 function ArrayBufferSlice(start, end) {
     // Step 1.
     var O = this;
 
     // Steps 2-3,
     // This function is not generic.
-    if (!IsObject(O) || !IsArrayBuffer(O)) {
-        return callFunction(CallArrayBufferMethodIfWrapped, O, start, end,
+    if (!IsObject(O) || (O = GuardToArrayBuffer(O)) === null) {
+        return callFunction(CallArrayBufferMethodIfWrapped, this, start, end,
                             "ArrayBufferSlice");
     }
 
     // Step 4.
     if (IsDetachedBuffer(O))
         ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
 
     // Step 5.
@@ -1640,47 +1641,49 @@ function ArrayBufferSlice(start, end) {
 
     // Step 11
     var ctor = SpeciesConstructor(O, GetBuiltinConstructor("ArrayBuffer"));
 
     // Step 12.
     var new_ = new ctor(newLen);
 
     var isWrapped = false;
-    if (IsArrayBuffer(new_)) {
+    var newBuffer;
+    if ((newBuffer = GuardToArrayBuffer(new_)) !== null) {
         // Step 14.
         if (IsDetachedBuffer(new_))
             ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
     } else {
+        newBuffer = new_;
         // Step 13.
-        if (!IsWrappedArrayBuffer(new_))
+        if (!IsWrappedArrayBuffer(newBuffer))
             ThrowTypeError(JSMSG_NON_ARRAY_BUFFER_RETURNED);
 
         isWrapped = true;
 
         // Step 14.
-        if (callFunction(CallArrayBufferMethodIfWrapped, new_, "IsDetachedBufferThis"))
+        if (callFunction(CallArrayBufferMethodIfWrapped, newBuffer, "IsDetachedBufferThis"))
             ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
     }
 
     // Step 15.
-    if (new_ === O)
+    if (newBuffer === O)
         ThrowTypeError(JSMSG_SAME_ARRAY_BUFFER_RETURNED);
 
     // Step 16.
-    var actualLen = PossiblyWrappedArrayBufferByteLength(new_);
+    var actualLen = PossiblyWrappedArrayBufferByteLength(newBuffer);
     if (actualLen < newLen)
         ThrowTypeError(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, newLen, actualLen);
 
     // Step 18.
     if (IsDetachedBuffer(O))
         ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
 
     // Steps 19-21.
-    ArrayBufferCopyData(new_, 0, O, first | 0, newLen | 0, isWrapped);
+    ArrayBufferCopyData(newBuffer, 0, O, first | 0, newLen | 0, isWrapped);
 
     // Step 22.
     return new_;
 }
 
 function IsDetachedBufferThis() {
   return IsDetachedBuffer(this);
 }
@@ -1702,18 +1705,18 @@ function SharedArrayBufferSpecies() {
 // Shared memory and atomics proposal 6.2.1.5.3 (30 Oct 2016)
 // http://tc39.github.io/ecmascript_sharedmem/shmem.html
 function SharedArrayBufferSlice(start, end) {
     // Step 1.
     var O = this;
 
     // Steps 2-4,
     // This function is not generic.
-    if (!IsObject(O) || !IsSharedArrayBuffer(O)) {
-        return callFunction(CallSharedArrayBufferMethodIfWrapped, O, start, end,
+    if (!IsObject(O) || (O = GuardToSharedArrayBuffer(O)) === null) {
+        return callFunction(CallSharedArrayBufferMethodIfWrapped, this, start, end,
                             "SharedArrayBufferSlice");
     }
 
     // Step 5.
     var len = SharedArrayBufferByteLength(O);
 
     // Step 6.
     var relativeStart = ToInteger(start);
@@ -1736,33 +1739,35 @@ function SharedArrayBufferSlice(start, e
     // Step 11
     var ctor = SpeciesConstructor(O, GetBuiltinConstructor("SharedArrayBuffer"));
 
     // Step 12.
     var new_ = new ctor(newLen);
 
     // Step 13.
     var isWrapped = false;
-    if (!IsSharedArrayBuffer(new_)) {
+    var newObj;
+    if ((newObj = GuardToSharedArrayBuffer(new_)) === null) {
         if (!IsWrappedSharedArrayBuffer(new_))
             ThrowTypeError(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED);
         isWrapped = true;
+        newObj = new_;
     }
 
     // Step 14.
-    if (new_ === O)
+    if (newObj === O)
         ThrowTypeError(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED);
 
     // Steb 14b.
-    if (SharedArrayBuffersMemorySame(new_, O))
+    if (SharedArrayBuffersMemorySame(newObj, O))
         ThrowTypeError(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED);
 
     // Step 15.
-    var actualLen = PossiblyWrappedSharedArrayBufferByteLength(new_);
+    var actualLen = PossiblyWrappedSharedArrayBufferByteLength(newObj);
     if (actualLen < newLen)
         ThrowTypeError(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, newLen, actualLen);
 
     // Steps 16-18.
-    SharedArrayBufferCopyData(new_, 0, O, first | 0, newLen | 0, isWrapped);
+    SharedArrayBufferCopyData(newObj, 0, O, first | 0, newLen | 0, isWrapped);
 
     // Step 19.
     return new_;
 }
--- a/js/src/builtin/intl/Collator.js
+++ b/js/src/builtin/intl/Collator.js
@@ -75,17 +75,17 @@ function resolveCollatorInternals(lazyCo
     return internalProps;
 }
 
 /**
  * Returns an object containing the Collator internal properties of |obj|.
  */
 function getCollatorInternals(obj) {
     assert(IsObject(obj), "getCollatorInternals called with non-object");
-    assert(IsCollator(obj), "getCollatorInternals called with non-Collator");
+    assert(GuardToCollator(obj) !== null, "getCollatorInternals called with non-Collator");
 
     var internals = getIntlObjectInternals(obj);
     assert(internals.type === "Collator", "bad type escaped getIntlObjectInternals");
 
     // If internal properties have already been computed, use them.
     var internalProps = maybeInternalProperties(internals);
     if (internalProps)
         return internalProps;
@@ -104,17 +104,17 @@ function getCollatorInternals(obj) {
  * all the work we can until the object is actually used as a Collator.  This
  * later work occurs in |resolveCollatorInternals|; steps not noted here occur
  * there.
  *
  * Spec: ECMAScript Internationalization API Specification, 10.1.1.
  */
 function InitializeCollator(collator, locales, options) {
     assert(IsObject(collator), "InitializeCollator called with non-object");
-    assert(IsCollator(collator), "InitializeCollator called with non-Collator");
+    assert(GuardToCollator(collator) != null, "InitializeCollator called with non-Collator");
 
     // Lazy Collator data has the following structure:
     //
     //   {
     //     requestedLocales: List of locales,
     //     usage: "sort" / "search",
     //     opt: // opt object computed in InitializeCollator
     //       {
@@ -324,17 +324,17 @@ function collatorSearchLocaleData() {
  * Spec: ECMAScript Internationalization API Specification, 10.3.3.1.
  */
 function collatorCompareToBind(x, y) {
     // Step 1.
     var collator = this;
 
     // Step 2.
     assert(IsObject(collator), "collatorCompareToBind called with non-object");
-    assert(IsCollator(collator), "collatorCompareToBind called with non-Collator");
+    assert(GuardToCollator(collator) !== null, "collatorCompareToBind called with non-Collator");
 
     // Steps 3-6
     var X = ToString(x);
     var Y = ToString(y);
 
     // Step 7.
     return intl_CompareStrings(collator, X, Y);
 }
@@ -348,17 +348,17 @@ function collatorCompareToBind(x, y) {
  *
  * Spec: ECMAScript Internationalization API Specification, 10.3.3.
  */
 function Intl_Collator_compare_get() {
     // Step 1.
     var collator = this;
 
     // Steps 2-3.
-    if (!IsObject(collator) || !IsCollator(collator))
+    if (!IsObject(collator) || (collator = GuardToCollator(collator)) === null)
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "Collator", "compare", "Collator");
 
     var internals = getCollatorInternals(collator);
 
     // Step 4.
     if (internals.boundCompare === undefined) {
         // Steps 4.a-b.
         var F = callFunction(FunctionBind, collatorCompareToBind, collator);
@@ -377,17 +377,17 @@ function Intl_Collator_compare_get() {
  *
  * Spec: ECMAScript Internationalization API Specification, 10.3.4.
  */
 function Intl_Collator_resolvedOptions() {
     // Step 1.
     var collator = this;
 
     // Steps 2-3.
-    if (!IsObject(collator) || !IsCollator(collator))
+    if (!IsObject(collator) || (collator = GuardToCollator(collator)) === null)
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "Collator", "resolvedOptions", "Collator");
 
     var internals = getCollatorInternals(collator);
 
     // Steps 4-5.
     var result = {
         locale: internals.locale,
         usage: internals.usage,
--- a/js/src/builtin/intl/CommonFunctions.js
+++ b/js/src/builtin/intl/CommonFunctions.js
@@ -1439,21 +1439,21 @@ function intlFallbackSymbol() {
     return fallbackSymbol;
 }
 
 /**
  * Initializes the INTL_INTERNALS_OBJECT_SLOT of the given object.
  */
 function initializeIntlObject(obj, type, lazyData) {
     assert(IsObject(obj), "Non-object passed to initializeIntlObject");
-    assert((type === "Collator" && IsCollator(obj)) ||
-           (type === "DateTimeFormat" && IsDateTimeFormat(obj)) ||
-           (type === "NumberFormat" && IsNumberFormat(obj)) ||
-           (type === "PluralRules" && IsPluralRules(obj)) ||
-           (type === "RelativeTimeFormat" && IsRelativeTimeFormat(obj)),
+    assert((type === "Collator" && GuardToCollator(obj) !== null) ||
+           (type === "DateTimeFormat" && GuardToDateTimeFormat(obj) !== null) ||
+           (type === "NumberFormat" && GuardToNumberFormat(obj) !== null) ||
+           (type === "PluralRules" && GuardToPluralRules(obj) !== null) ||
+           (type === "RelativeTimeFormat" && GuardToRelativeTimeFormat(obj) !== null),
            "type must match the object's class");
     assert(IsObject(lazyData), "non-object lazy data");
 
     // The meaning of an internals object for an object |obj| is as follows.
     //
     // The .type property indicates the type of Intl object that |obj| is:
     // "Collator", "DateTimeFormat", "NumberFormat", or "PluralRules" (likely
     // with more coming in future Intl specs).
@@ -1507,30 +1507,30 @@ function maybeInternalProperties(interna
  * properties!), with structure specified above.
  *
  * Spec: ECMAScript Internationalization API Specification, 10.3.
  * Spec: ECMAScript Internationalization API Specification, 11.3.
  * Spec: ECMAScript Internationalization API Specification, 12.3.
  */
 function getIntlObjectInternals(obj) {
     assert(IsObject(obj), "getIntlObjectInternals called with non-Object");
-    assert(IsCollator(obj) || IsDateTimeFormat(obj) ||
-           IsNumberFormat(obj) || IsPluralRules(obj) ||
-           IsRelativeTimeFormat(obj),
+    assert(GuardToCollator(obj) !== null || GuardToDateTimeFormat(obj) !== null ||
+           GuardToNumberFormat(obj) !== null || GuardToPluralRules(obj) !== null ||
+           GuardToRelativeTimeFormat(obj) !== null,
            "getIntlObjectInternals called with non-Intl object");
 
     var internals = UnsafeGetReservedSlot(obj, INTL_INTERNALS_OBJECT_SLOT);
 
     assert(IsObject(internals), "internals not an object");
     assert(hasOwn("type", internals), "missing type");
-    assert((internals.type === "Collator" && IsCollator(obj)) ||
-           (internals.type === "DateTimeFormat" && IsDateTimeFormat(obj)) ||
-           (internals.type === "NumberFormat" && IsNumberFormat(obj)) ||
-           (internals.type === "PluralRules" && IsPluralRules(obj)) ||
-           (internals.type === "RelativeTimeFormat" && IsRelativeTimeFormat(obj)),
+    assert((internals.type === "Collator" && GuardToCollator(obj) !== null) ||
+           (internals.type === "DateTimeFormat" && GuardToDateTimeFormat(obj) !== null) ||
+           (internals.type === "NumberFormat" && GuardToNumberFormat(obj) !== null) ||
+           (internals.type === "PluralRules" && GuardToPluralRules(obj) !== null) ||
+           (internals.type === "RelativeTimeFormat" && GuardToRelativeTimeFormat(obj) !== null),
            "type must match the object's class");
     assert(hasOwn("lazyData", internals), "missing lazyData");
     assert(hasOwn("internalProps", internals), "missing internalProps");
 
     return internals;
 }
 
 /**
--- a/js/src/builtin/intl/DateTimeFormat.js
+++ b/js/src/builtin/intl/DateTimeFormat.js
@@ -164,17 +164,17 @@ function replaceHourRepresentation(patte
     return resultPattern;
 }
 
 /**
  * Returns an object containing the DateTimeFormat internal properties of |obj|.
  */
 function getDateTimeFormatInternals(obj) {
     assert(IsObject(obj), "getDateTimeFormatInternals called with non-object");
-    assert(IsDateTimeFormat(obj), "getDateTimeFormatInternals called with non-DateTimeFormat");
+    assert(GuardToDateTimeFormat(obj) !== null, "getDateTimeFormatInternals called with non-DateTimeFormat");
 
     var internals = getIntlObjectInternals(obj);
     assert(internals.type === "DateTimeFormat", "bad type escaped getIntlObjectInternals");
 
     // If internal properties have already been computed, use them.
     var internalProps = maybeInternalProperties(internals);
     if (internalProps)
         return internalProps;
@@ -187,21 +187,21 @@ function getDateTimeFormatInternals(obj)
 
 /**
  * 12.1.10 UnwrapDateTimeFormat( dtf )
  */
 function UnwrapDateTimeFormat(dtf, methodName) {
     // Step 1 (not applicable in our implementation).
 
     // Step 2.
-    if (IsObject(dtf) && !IsDateTimeFormat(dtf) && dtf instanceof GetDateTimeFormatConstructor())
+    if (IsObject(dtf) && (GuardToDateTimeFormat(dtf)) === null && dtf instanceof GetDateTimeFormatConstructor())
         dtf = dtf[intlFallbackSymbol()];
 
     // Step 3.
-    if (!IsObject(dtf) || !IsDateTimeFormat(dtf)) {
+    if (!IsObject(dtf) || (dtf = GuardToDateTimeFormat(dtf)) === null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "DateTimeFormat", methodName,
                        "DateTimeFormat");
     }
 
     // Step 4.
     return dtf;
 }
 
@@ -297,17 +297,17 @@ function DefaultTimeZone() {
  * all the work we can until the object is actually used as a DateTimeFormat.
  * This later work occurs in |resolveDateTimeFormatInternals|; steps not noted
  * here occur there.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.1.1.
  */
 function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, mozExtensions) {
     assert(IsObject(dateTimeFormat), "InitializeDateTimeFormat called with non-Object");
-    assert(IsDateTimeFormat(dateTimeFormat),
+    assert(GuardToDateTimeFormat(dateTimeFormat) !== null,
            "InitializeDateTimeFormat called with non-DateTimeFormat");
 
     // Lazy DateTimeFormat data has the following structure:
     //
     //   {
     //     requestedLocales: List of locales,
     //
     //     localeOpt: // *first* opt computed in InitializeDateTimeFormat
@@ -780,17 +780,17 @@ function dateTimeFormatLocaleData() {
  * Spec: ECMAScript Internationalization API Specification, 12.1.5.
  */
 function dateTimeFormatFormatToBind(date) {
     // Step 1.
     var dtf = this;
 
     // Step 2.
     assert(IsObject(dtf), "dateTimeFormatFormatToBind called with non-Object");
-    assert(IsDateTimeFormat(dtf), "dateTimeFormatFormatToBind called with non-DateTimeFormat");
+    assert(GuardToDateTimeFormat(dtf) !== null, "dateTimeFormatFormatToBind called with non-DateTimeFormat");
 
     // Steps 3-4.
     var x = (date === undefined) ? std_Date_now() : ToNumber(date);
 
     // Step 5.
     return intl_FormatDateTime(dtf, x, /* formatToParts = */ false);
 }
 
@@ -826,17 +826,17 @@ function Intl_DateTimeFormat_format_get(
  *
  * Spec: ECMAScript Internationalization API Specification, 12.4.4.
  */
 function Intl_DateTimeFormat_formatToParts(date) {
     // Step 1.
     var dtf = this;
 
     // Steps 2-3.
-    if (!IsObject(dtf) || !IsDateTimeFormat(dtf)) {
+    if (!IsObject(dtf) || (dtf = GuardToDateTimeFormat(dtf)) == null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "DateTimeFormat", "formatToParts",
                        "DateTimeFormat");
     }
 
     // Ensure the DateTimeFormat internals are resolved.
     getDateTimeFormatInternals(dtf);
 
     // Steps 4-5.
--- a/js/src/builtin/intl/NumberFormat.js
+++ b/js/src/builtin/intl/NumberFormat.js
@@ -83,17 +83,17 @@ function resolveNumberFormatInternals(la
     return internalProps;
 }
 
 /**
  * Returns an object containing the NumberFormat internal properties of |obj|.
  */
 function getNumberFormatInternals(obj) {
     assert(IsObject(obj), "getNumberFormatInternals called with non-object");
-    assert(IsNumberFormat(obj), "getNumberFormatInternals called with non-NumberFormat");
+    assert(GuardToNumberFormat(obj) !== null, "getNumberFormatInternals called with non-NumberFormat");
 
     var internals = getIntlObjectInternals(obj);
     assert(internals.type === "NumberFormat", "bad type escaped getIntlObjectInternals");
 
     // If internal properties have already been computed, use them.
     var internalProps = maybeInternalProperties(internals);
     if (internalProps)
         return internalProps;
@@ -106,21 +106,21 @@ function getNumberFormatInternals(obj) {
 
 /**
  * 11.1.11 UnwrapNumberFormat( nf )
  */
 function UnwrapNumberFormat(nf, methodName) {
     // Step 1 (not applicable in our implementation).
 
     // Step 2.
-    if (IsObject(nf) && !IsNumberFormat(nf) && nf instanceof GetNumberFormatConstructor())
+    if (IsObject(nf) && (GuardToNumberFormat(nf)) === null && nf instanceof GetNumberFormatConstructor())
         nf = nf[intlFallbackSymbol()];
 
     // Step 3.
-    if (!IsObject(nf) || !IsNumberFormat(nf))
+    if (!IsObject(nf) || (nf = GuardToNumberFormat(nf)) === null)
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "NumberFormat", methodName, "NumberFormat");
 
     // Step 4.
     return nf;
 }
 
 /**
  * Applies digit options used for number formatting onto the intl object.
@@ -200,17 +200,17 @@ function IsWellFormedCurrencyCode(curren
  * all the work we can until the object is actually used as a NumberFormat.
  * This later work occurs in |resolveNumberFormatInternals|; steps not noted
  * here occur there.
  *
  * Spec: ECMAScript Internationalization API Specification, 11.1.2.
  */
 function InitializeNumberFormat(numberFormat, thisValue, locales, options) {
     assert(IsObject(numberFormat), "InitializeNumberFormat called with non-object");
-    assert(IsNumberFormat(numberFormat), "InitializeNumberFormat called with non-NumberFormat");
+    assert(GuardToNumberFormat(numberFormat) !== null, "InitializeNumberFormat called with non-NumberFormat");
 
     // Lazy NumberFormat data has the following structure:
     //
     //   {
     //     requestedLocales: List of locales,
     //     style: "decimal" / "percent" / "currency",
     //
     //     // fields present only if style === "currency":
@@ -400,17 +400,17 @@ function numberFormatLocaleData() {
  * Spec: ECMAScript Internationalization API Specification, 11.1.4.
  */
 function numberFormatFormatToBind(value) {
     // Step 1.
     var nf = this;
 
     // Step 2.
     assert(IsObject(nf), "InitializeNumberFormat called with non-object");
-    assert(IsNumberFormat(nf), "InitializeNumberFormat called with non-NumberFormat");
+    assert(GuardToNumberFormat(nf) !== null, "InitializeNumberFormat called with non-NumberFormat");
 
     // Steps 3-4.
     var x = ToNumber(value);
 
     // Step 5.
     return intl_FormatNumber(nf, x, /* formatToParts = */ false);
 }
 
@@ -444,17 +444,17 @@ function Intl_NumberFormat_format_get() 
 /**
  * 11.4.4 Intl.NumberFormat.prototype.formatToParts ( value )
  */
 function Intl_NumberFormat_formatToParts(value) {
     // Step 1.
     var nf = this;
 
     // Steps 2-3.
-    if (!IsObject(nf) || !IsNumberFormat(nf)) {
+    if (!IsObject(nf) || (nf = GuardToNumberFormat(nf)) === null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "NumberFormat", "formatToParts",
                        "NumberFormat");
     }
 
     // Ensure the NumberFormat internals are resolved.
     getNumberFormatInternals(nf);
 
     // Step 4.
--- a/js/src/builtin/intl/PluralRules.js
+++ b/js/src/builtin/intl/PluralRules.js
@@ -73,17 +73,17 @@ function resolvePluralRulesInternals(laz
     return internalProps;
 }
 
 /**
  * Returns an object containing the PluralRules internal properties of |obj|.
  */
 function getPluralRulesInternals(obj) {
     assert(IsObject(obj), "getPluralRulesInternals called with non-object");
-    assert(IsPluralRules(obj), "getPluralRulesInternals called with non-PluralRules");
+    assert(GuardToPluralRules(obj) !== null, "getPluralRulesInternals called with non-PluralRules");
 
     var internals = getIntlObjectInternals(obj);
     assert(internals.type === "PluralRules", "bad type escaped getIntlObjectInternals");
 
     var internalProps = maybeInternalProperties(internals);
     if (internalProps)
         return internalProps;
 
@@ -100,17 +100,17 @@ function getPluralRulesInternals(obj) {
  * all the work we can until the object is actually used as a PluralRules.
  * This later work occurs in |resolvePluralRulesInternals|; steps not noted
  * here occur there.
  *
  * Spec: ECMAScript 402 API, PluralRules, 13.1.1.
  */
 function InitializePluralRules(pluralRules, locales, options) {
     assert(IsObject(pluralRules), "InitializePluralRules called with non-object");
-    assert(IsPluralRules(pluralRules), "InitializePluralRules called with non-PluralRules");
+    assert(GuardToPluralRules(pluralRules) !== null, "InitializePluralRules called with non-PluralRules");
 
     // Lazy PluralRules data has the following structure:
     //
     //   {
     //     requestedLocales: List of locales,
     //     type: "cardinal" / "ordinal",
     //
     //     opt: // opt object computer in InitializePluralRules
@@ -191,17 +191,17 @@ function Intl_PluralRules_supportedLocal
  *
  * Spec: ECMAScript 402 API, PluralRules, 13.4.3.
  */
 function Intl_PluralRules_select(value) {
     // Step 1.
     let pluralRules = this;
 
     // Steps 2-3.
-    if (!IsObject(pluralRules) || !IsPluralRules(pluralRules))
+    if (!IsObject(pluralRules) || (pluralRules = GuardToPluralRules(pluralRules)) === null)
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "PluralRules", "select", "PluralRules");
 
     // Ensure the PluralRules internals are resolved.
     getPluralRulesInternals(pluralRules);
 
     // Step 4.
     let n = ToNumber(value);
 
@@ -214,17 +214,17 @@ function Intl_PluralRules_select(value) 
  *
  * Spec: ECMAScript 402 API, PluralRules, 13.4.4.
  */
 function Intl_PluralRules_resolvedOptions() {
     // Step 1.
     var pluralRules = this;
 
     // Steps 2-3.
-    if (!IsObject(pluralRules) || !IsPluralRules(pluralRules)) {
+    if (!IsObject(pluralRules) || (pluralRules = GuardToPluralRules(pluralRules)) === null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "PluralRules", "resolvedOptions",
                        "PluralRules");
     }
 
     var internals = getPluralRulesInternals(pluralRules);
 
     var internalsPluralCategories = internals.pluralCategories;
     if (internalsPluralCategories === null) {
--- a/js/src/builtin/intl/RelativeTimeFormat.js
+++ b/js/src/builtin/intl/RelativeTimeFormat.js
@@ -58,17 +58,17 @@ function resolveRelativeTimeFormatIntern
 }
 
 /**
  * Returns an object containing the RelativeTimeFormat internal properties of |obj|,
  * or throws a TypeError if |obj| isn't RelativeTimeFormat-initialized.
  */
 function getRelativeTimeFormatInternals(obj, methodName) {
     assert(IsObject(obj), "getRelativeTimeFormatInternals called with non-object");
-    assert(IsRelativeTimeFormat(obj), "getRelativeTimeFormatInternals called with non-RelativeTimeFormat");
+    assert(GuardToRelativeTimeFormat(obj) !== null, "getRelativeTimeFormatInternals called with non-RelativeTimeFormat");
 
     var internals = getIntlObjectInternals(obj);
     assert(internals.type === "RelativeTimeFormat", "bad type escaped getIntlObjectInternals");
 
     var internalProps = maybeInternalProperties(internals);
     if (internalProps)
         return internalProps;
 
@@ -86,17 +86,17 @@ function getRelativeTimeFormatInternals(
  * This later work occurs in |resolveRelativeTimeFormatInternals|; steps not noted
  * here occur there.
  *
  * Spec: ECMAScript 402 API, RelativeTimeFormat, 1.1.1.
  */
 function InitializeRelativeTimeFormat(relativeTimeFormat, locales, options) {
     assert(IsObject(relativeTimeFormat),
            "InitializeRelativeimeFormat called with non-object");
-    assert(IsRelativeTimeFormat(relativeTimeFormat),
+    assert(GuardToRelativeTimeFormat(relativeTimeFormat) !== null,
            "InitializeRelativeTimeFormat called with non-RelativeTimeFormat");
 
     // Lazy RelativeTimeFormat data has the following structure:
     //
     //   {
     //     requestedLocales: List of locales,
     //     style: "long" / "short" / "narrow",
     //     numeric: "always" / "auto",
@@ -169,17 +169,17 @@ function Intl_RelativeTimeFormat_support
  *
  * Spec: ECMAScript 402 API, RelativeTImeFormat, 1.4.3.
  */
 function Intl_RelativeTimeFormat_format(value, unit) {
     // Step 1.
     let relativeTimeFormat = this;
 
     // Step 2.
-    if (!IsObject(relativeTimeFormat) || !IsRelativeTimeFormat(relativeTimeFormat))
+    if (!IsObject(relativeTimeFormat) || (relativeTimeFormat = GuardToRelativeTimeFormat(relativeTimeFormat)) === null)
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "RelativeTimeFormat", "format", "RelativeTimeFormat");
 
     // Ensure the RelativeTimeFormat internals are resolved.
     var internals = getRelativeTimeFormatInternals(relativeTimeFormat);
 
     // Step 3.
     let t = ToNumber(value);
 
@@ -205,23 +205,24 @@ function Intl_RelativeTimeFormat_format(
 }
 
 /**
  * Returns the resolved options for a PluralRules object.
  *
  * Spec: ECMAScript 402 API, RelativeTimeFormat, 1.4.4.
  */
 function Intl_RelativeTimeFormat_resolvedOptions() {
+    var relativeTimeFormat;
     // Check "this RelativeTimeFormat object" per introduction of section 1.4.
-    if (!IsObject(this) || !IsRelativeTimeFormat(this)) {
+    if (!IsObject(this) || (relativeTimeFormat = GuardToRelativeTimeFormat(this)) === null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "RelativeTimeFormat", "resolvedOptions",
                        "RelativeTimeFormat");
     }
 
-    var internals = getRelativeTimeFormatInternals(this, "resolvedOptions");
+    var internals = getRelativeTimeFormatInternals(relativeTimeFormat, "resolvedOptions");
 
     var result = {
         locale: internals.locale,
         style: internals.style,
         numeric: internals.numeric,
     };
 
     return result;
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -1456,29 +1456,25 @@ GCSchedulingTunables::setParameter(JSGCP
       case JSGC_DYNAMIC_MARK_SLICE:
         dynamicMarkSliceEnabled_ = value != 0;
         break;
       case JSGC_ALLOCATION_THRESHOLD:
         gcZoneAllocThresholdBase_ = value * 1024 * 1024;
         break;
       case JSGC_ALLOCATION_THRESHOLD_FACTOR: {
         double newFactor = value / 100.0;
-        if (newFactor < MinAllocationThresholdFactor || newFactor > 1.0) {
-            fprintf(stderr, "alloc factor %f %f\n", newFactor, MinAllocationThresholdFactor);
+        if (newFactor < MinAllocationThresholdFactor || newFactor > 1.0)
             return false;
-        }
         allocThresholdFactor_ = newFactor;
         break;
       }
       case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT: {
         double newFactor = value / 100.0;
-        if (newFactor < MinAllocationThresholdFactor || newFactor > 1.0) {
-            fprintf(stderr, "alloc factor %f %f\n", newFactor, MinAllocationThresholdFactor);
+        if (newFactor < MinAllocationThresholdFactor || newFactor > 1.0)
             return false;
-        }
         allocThresholdFactorAvoidInterrupt_ = newFactor;
         break;
       }
       case JSGC_MIN_EMPTY_CHUNK_COUNT:
         setMinEmptyChunkCount(value);
         break;
       case JSGC_MAX_EMPTY_CHUNK_COUNT:
         setMaxEmptyChunkCount(value);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1443555.js
@@ -0,0 +1,36 @@
+// |jit-test| error: TypeError
+
+"use strict";
+
+setJitCompilerOption("baseline.warmup.trigger", 0);
+
+let moduleRepo = {};
+setModuleResolveHook(function(module, specifier) {
+    if (specifier in moduleRepo)
+        return moduleRepo[specifier];
+    throw "Module '" + specifier + "' not found";
+});
+
+let mainSrc = `
+import A from "A";
+
+const a = A;
+
+function requestAnimationFrame(f) { Promise.resolve().then(f); };
+
+requestAnimationFrame(loopy);
+a = 2;
+function loopy() {
+    A;
+}
+`;
+
+let ASrc = `
+export default 1;
+`;
+
+moduleRepo['A'] = parseModule(ASrc);
+
+let m = parseModule(mainSrc);
+m.declarationInstantiation()
+m.evaluation();
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -12581,16 +12581,43 @@ CodeGenerator::visitHasClass(LHasClass* 
 {
     Register lhs = ToRegister(ins->lhs());
     Register output = ToRegister(ins->output());
 
     masm.loadObjClassUnsafe(lhs, output);
     masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
 }
 
+void
+CodeGenerator::visitGuardToClass(LGuardToClass* ins)
+{
+    Register lhs = ToRegister(ins->lhs());
+    Register output = ToRegister(ins->output());
+    Register temp = ToRegister(ins->temp());
+
+    Label notEqual;
+
+    masm.branchTestObjClass(Assembler::NotEqual, lhs, ins->mir()->getClass(), temp,
+                            output, &notEqual);
+    masm.mov(lhs, output);
+
+    if (ins->mir()->type() == MIRType::Object) {
+        // Can't return null-return here, so bail
+        bailoutFrom(&notEqual, ins->snapshot());
+    } else {
+        Label done;
+        masm.jump(&done);
+
+        masm.bind(&notEqual);
+        masm.mov(ImmPtr(0), output);
+
+        masm.bind(&done);
+    }
+}
+
 typedef JSString* (*ObjectClassToStringFn)(JSContext*, HandleObject);
 static const VMFunction ObjectClassToStringInfo =
     FunctionInfo<ObjectClassToStringFn>(js::ObjectClassToString, "ObjectClassToString");
 
 void
 CodeGenerator::visitObjectClassToString(LObjectClassToString* lir)
 {
     pushArg(ToRegister(lir->object()));
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -24,21 +24,21 @@
     _(AtomicsSub)                   \
     _(AtomicsAnd)                   \
     _(AtomicsOr)                    \
     _(AtomicsXor)                   \
     _(AtomicsIsLockFree)            \
                                     \
     _(Boolean)                      \
                                     \
-    _(IntlIsCollator)               \
-    _(IntlIsDateTimeFormat)         \
-    _(IntlIsNumberFormat)           \
-    _(IntlIsPluralRules)            \
-    _(IntlIsRelativeTimeFormat)     \
+    _(IntlGuardToCollator)          \
+    _(IntlGuardToDateTimeFormat)    \
+    _(IntlGuardToNumberFormat)      \
+    _(IntlGuardToPluralRules)       \
+    _(IntlGuardToRelativeTimeFormat) \
                                     \
     _(MathAbs)                      \
     _(MathFloor)                    \
     _(MathCeil)                     \
     _(MathRound)                    \
     _(MathClz32)                    \
     _(MathSqrt)                     \
     _(MathATan2)                    \
@@ -127,35 +127,35 @@
     _(IntrinsicToInteger)           \
     _(IntrinsicToString)            \
     _(IntrinsicIsConstructing)      \
     _(IntrinsicSubstringKernel)     \
     _(IntrinsicObjectHasPrototype)  \
     _(IntrinsicFinishBoundFunctionInit) \
     _(IntrinsicIsPackedArray)       \
                                     \
-    _(IntrinsicIsArrayIterator)     \
-    _(IntrinsicIsMapIterator)       \
-    _(IntrinsicIsSetIterator)       \
-    _(IntrinsicIsStringIterator)    \
+    _(IntrinsicGuardToArrayIterator) \
+    _(IntrinsicGuardToMapIterator)  \
+    _(IntrinsicGuardToSetIterator)  \
+    _(IntrinsicGuardToStringIterator) \
                                     \
-    _(IntrinsicIsMapObject)         \
+    _(IntrinsicGuardToMapObject)    \
     _(IntrinsicGetNextMapEntryForIterator) \
                                     \
-    _(IntrinsicIsSetObject)         \
+    _(IntrinsicGuardToSetObject)    \
     _(IntrinsicGetNextSetEntryForIterator) \
                                     \
     _(IntrinsicNewArrayIterator)    \
     _(IntrinsicNewStringIterator)   \
                                     \
-    _(IntrinsicIsArrayBuffer)       \
+    _(IntrinsicGuardToArrayBuffer)  \
     _(IntrinsicArrayBufferByteLength) \
     _(IntrinsicPossiblyWrappedArrayBufferByteLength) \
                                     \
-    _(IntrinsicIsSharedArrayBuffer) \
+    _(IntrinsicGuardToSharedArrayBuffer) \
                                     \
     _(TypedArrayConstructor)        \
     _(IntrinsicIsTypedArray)        \
     _(IntrinsicIsPossiblyWrappedTypedArray) \
     _(IntrinsicTypedArrayLength)    \
     _(IntrinsicPossiblyWrappedTypedArrayLength)    \
     _(IntrinsicSetDisjointTypedElements) \
                                     \
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -780,16 +780,17 @@ class IonBuilder
     InliningResult inlineIsWrappedArrayConstructor(CallInfo& callInfo);
     InliningResult inlineToInteger(CallInfo& callInfo);
     InliningResult inlineToString(CallInfo& callInfo);
     InliningResult inlineDump(CallInfo& callInfo);
     InliningResult inlineHasClass(CallInfo& callInfo, const Class* clasp,
                                   const Class* clasp2 = nullptr,
                                   const Class* clasp3 = nullptr,
                                   const Class* clasp4 = nullptr);
+    InliningResult inlineGuardToClass(CallInfo& callInfo, const Class* clasp);
     InliningResult inlineIsConstructing(CallInfo& callInfo);
     InliningResult inlineSubstringKernel(CallInfo& callInfo);
     InliningResult inlineObjectHasPrototype(CallInfo& callInfo);
     InliningResult inlineFinishBoundFunctionInit(CallInfo& callInfo);
     InliningResult inlineIsPackedArray(CallInfo& callInfo);
 
     // Testing functions.
     InliningResult inlineBailout(CallInfo& callInfo);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4507,16 +4507,26 @@ void
 LIRGenerator::visitHasClass(MHasClass* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::Boolean);
     define(new(alloc()) LHasClass(useRegister(ins->object())), ins);
 }
 
 void
+LIRGenerator::visitGuardToClass(MGuardToClass* ins)
+{
+    MOZ_ASSERT(ins->object()->type() == MIRType::Object);
+    MOZ_ASSERT(ins->type() == MIRType::ObjectOrNull|| ins->type() == MIRType::Object);
+    LGuardToClass* lir = new(alloc()) LGuardToClass(useRegister(ins->object()), temp());
+    assignSnapshot(lir, Bailout_TypeBarrierO);
+    define(lir, ins);
+}
+
+void
 LIRGenerator::visitObjectClassToString(MObjectClassToString* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::String);
     auto lir = new(alloc()) LObjectClassToString(useRegisterAtStart(ins->object()));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -114,26 +114,26 @@ IonBuilder::inlineNativeCall(CallInfo& c
       case InlinableNative::AtomicsIsLockFree:
         return inlineAtomicsIsLockFree(callInfo);
 
       // Boolean natives.
       case InlinableNative::Boolean:
         return inlineBoolean(callInfo);
 
       // Intl natives.
-      case InlinableNative::IntlIsCollator:
-        return inlineHasClass(callInfo, &CollatorObject::class_);
-      case InlinableNative::IntlIsDateTimeFormat:
-        return inlineHasClass(callInfo, &DateTimeFormatObject::class_);
-      case InlinableNative::IntlIsNumberFormat:
-        return inlineHasClass(callInfo, &NumberFormatObject::class_);
-      case InlinableNative::IntlIsPluralRules:
-        return inlineHasClass(callInfo, &PluralRulesObject::class_);
-      case InlinableNative::IntlIsRelativeTimeFormat:
-        return inlineHasClass(callInfo, &RelativeTimeFormatObject::class_);
+      case InlinableNative::IntlGuardToCollator:
+        return inlineGuardToClass(callInfo, &CollatorObject::class_);
+      case InlinableNative::IntlGuardToDateTimeFormat:
+        return inlineGuardToClass(callInfo, &DateTimeFormatObject::class_);
+      case InlinableNative::IntlGuardToNumberFormat:
+        return inlineGuardToClass(callInfo, &NumberFormatObject::class_);
+      case InlinableNative::IntlGuardToPluralRules:
+        return inlineGuardToClass(callInfo, &PluralRulesObject::class_);
+      case InlinableNative::IntlGuardToRelativeTimeFormat:
+        return inlineGuardToClass(callInfo, &RelativeTimeFormatObject::class_);
 
       // Math natives.
       case InlinableNative::MathAbs:
         return inlineMathAbs(callInfo);
       case InlinableNative::MathFloor:
         return inlineMathFloor(callInfo);
       case InlinableNative::MathCeil:
         return inlineMathCeil(callInfo);
@@ -314,54 +314,54 @@ IonBuilder::inlineNativeCall(CallInfo& c
       case InlinableNative::IntrinsicToInteger:
         return inlineToInteger(callInfo);
       case InlinableNative::IntrinsicToString:
         return inlineToString(callInfo);
       case InlinableNative::IntrinsicIsConstructing:
         return inlineIsConstructing(callInfo);
       case InlinableNative::IntrinsicSubstringKernel:
         return inlineSubstringKernel(callInfo);
-      case InlinableNative::IntrinsicIsArrayIterator:
-        return inlineHasClass(callInfo, &ArrayIteratorObject::class_);
-      case InlinableNative::IntrinsicIsMapIterator:
-        return inlineHasClass(callInfo, &MapIteratorObject::class_);
-      case InlinableNative::IntrinsicIsSetIterator:
-        return inlineHasClass(callInfo, &SetIteratorObject::class_);
-      case InlinableNative::IntrinsicIsStringIterator:
-        return inlineHasClass(callInfo, &StringIteratorObject::class_);
+      case InlinableNative::IntrinsicGuardToArrayIterator:
+        return inlineGuardToClass(callInfo, &ArrayIteratorObject::class_);
+      case InlinableNative::IntrinsicGuardToMapIterator:
+        return inlineGuardToClass(callInfo, &MapIteratorObject::class_);
+      case InlinableNative::IntrinsicGuardToSetIterator:
+        return inlineGuardToClass(callInfo, &SetIteratorObject::class_);
+      case InlinableNative::IntrinsicGuardToStringIterator:
+        return inlineGuardToClass(callInfo, &StringIteratorObject::class_);
       case InlinableNative::IntrinsicObjectHasPrototype:
         return inlineObjectHasPrototype(callInfo);
       case InlinableNative::IntrinsicFinishBoundFunctionInit:
         return inlineFinishBoundFunctionInit(callInfo);
       case InlinableNative::IntrinsicIsPackedArray:
         return inlineIsPackedArray(callInfo);
 
       // Map intrinsics.
-      case InlinableNative::IntrinsicIsMapObject:
-        return inlineHasClass(callInfo, &MapObject::class_);
+      case InlinableNative::IntrinsicGuardToMapObject:
+        return inlineGuardToClass(callInfo, &MapObject::class_);
       case InlinableNative::IntrinsicGetNextMapEntryForIterator:
         return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map);
 
       // Set intrinsics.
-      case InlinableNative::IntrinsicIsSetObject:
-        return inlineHasClass(callInfo, &SetObject::class_);
+      case InlinableNative::IntrinsicGuardToSetObject:
+        return inlineGuardToClass(callInfo, &SetObject::class_);
       case InlinableNative::IntrinsicGetNextSetEntryForIterator:
         return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set);
 
       // ArrayBuffer intrinsics.
-      case InlinableNative::IntrinsicIsArrayBuffer:
-        return inlineHasClass(callInfo, &ArrayBufferObject::class_);
+      case InlinableNative::IntrinsicGuardToArrayBuffer:
+        return inlineGuardToClass(callInfo, &ArrayBufferObject::class_);
       case InlinableNative::IntrinsicArrayBufferByteLength:
         return inlineArrayBufferByteLength(callInfo);
       case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
         return inlinePossiblyWrappedArrayBufferByteLength(callInfo);
 
       // SharedArrayBuffer intrinsics.
-      case InlinableNative::IntrinsicIsSharedArrayBuffer:
-        return inlineHasClass(callInfo, &SharedArrayBufferObject::class_);
+      case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
+        return inlineGuardToClass(callInfo, &SharedArrayBufferObject::class_);
 
       // TypedArray intrinsics.
       case InlinableNative::TypedArrayConstructor:
         return inlineTypedArray(callInfo, target->native());
       case InlinableNative::IntrinsicIsTypedArray:
         return inlineIsTypedArray(callInfo);
       case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
         return inlineIsPossiblyWrappedTypedArray(callInfo);
@@ -2559,16 +2559,47 @@ IonBuilder::inlineHasClass(CallInfo& cal
         }
     }
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningResult
+IonBuilder::inlineGuardToClass(CallInfo& callInfo, const Class* clasp)
+{
+    MOZ_ASSERT(!callInfo.constructing());
+    MOZ_ASSERT(callInfo.argc() == 1);
+
+    if (callInfo.getArg(0)->type() != MIRType::Object)
+        return InliningStatus_NotInlined;
+
+    if (getInlineReturnType() != MIRType::ObjectOrNull &&
+        getInlineReturnType() != MIRType::Object)
+    {
+        return InliningStatus_NotInlined;
+    }
+    
+    TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
+    const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr;
+
+    if (knownClass && knownClass == clasp) {
+        current->push(callInfo.getArg(0));
+    } else {
+        MGuardToClass* guardToClass = MGuardToClass::New(alloc(), callInfo.getArg(0),
+                                                         clasp, getInlineReturnType());
+        current->add(guardToClass);
+        current->push(guardToClass);
+    }
+
+    callInfo.setImplicitlyUsedUnchecked();
+    return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningResult
 IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode)
 {
     MOZ_ASSERT(!callInfo.constructing());
     MOZ_ASSERT(callInfo.argc() == 2);
 
     MDefinition* iterArg = callInfo.getArg(0);
     MDefinition* resultArg = callInfo.getArg(1);
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -13656,16 +13656,58 @@ class MHasClass
         if (!ins->isHasClass())
             return false;
         if (getClass() != ins->toHasClass()->getClass())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 };
 
+class MGuardToClass
+    : public MUnaryInstruction,
+      public SingleObjectPolicy::Data
+{
+    const Class* class_;
+
+    MGuardToClass(MDefinition* object, const Class* clasp, MIRType resultType)
+      : MUnaryInstruction(classOpcode, object)
+      , class_(clasp)
+    {
+        MOZ_ASSERT(object->type() == MIRType::Object ||
+                   (object->type() == MIRType::Value && object->mightBeType(MIRType::Object)));
+        MOZ_ASSERT(resultType == MIRType::Object || resultType == MIRType::ObjectOrNull);
+        setResultType(resultType);
+        setMovable();
+        if (resultType == MIRType::Object) {
+            // We will bail out if the class type is incorrect,
+            // so we need to ensure we don't eliminate this instruction
+            setGuard();
+        }
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardToClass)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    const Class* getClass() const {
+        return class_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isGuardToClass())
+            return false;
+        if (getClass() != ins->toGuardToClass()->getClass())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+};
+
 // Note: we might call a proxy trap, so this instruction is effectful.
 class MIsArray
   : public MUnaryInstruction,
     public BoxExceptPolicy<0, MIRType::Object>::Data
 {
     explicit MIsArray(MDefinition* value)
       : MUnaryInstruction(classOpcode, value)
     {
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -9055,16 +9055,40 @@ class LHasClass : public LInstructionHel
     const LAllocation* lhs() {
         return getOperand(0);
     }
     MHasClass* mir() const {
         return mir_->toHasClass();
     }
 };
 
+class LGuardToClass : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(GuardToClass);
+    explicit LGuardToClass(const LAllocation& lhs, const LDefinition& temp)
+      : LInstructionHelper(classOpcode)
+    {
+        setOperand(0, lhs);
+        setTemp(0, temp);
+    }
+
+    const LAllocation* lhs() {
+        return getOperand(0);
+    }
+
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
+
+    MGuardToClass* mir() const {
+        return mir_->toGuardToClass();
+    }
+};
+
 class LObjectClassToString : public LCallInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(ObjectClassToString);
 
     explicit LObjectClassToString(const LAllocation& lhs)
       : LCallInstructionHelper(classOpcode)
     {
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -1193,153 +1193,158 @@ void
 js::UnwindIteratorForUncatchableException(JSObject* obj)
 {
     if (obj->is<PropertyIteratorObject>()) {
         NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
         ni->unlink();
     }
 }
 
+static bool
+SuppressDeletedProperty(JSContext* cx, NativeIterator* ni, HandleObject obj,
+                        Handle<JSFlatString*> str)
+{
+    if (ni->obj != obj)
+        return true;
+
+    // Optimization for the following common case:
+    //
+    //    for (var p in o) {
+    //        delete o[p];
+    //    }
+    //
+    // Note that usually both strings will be atoms so we only check for pointer
+    // equality here.
+    if (ni->props_cursor > ni->begin() && ni->props_cursor[-1] == str)
+        return true;
+
+    while (true) {
+        bool restart = false;
+
+        // Check whether id is still to come.
+        GCPtrFlatString* const props_cursor = ni->props_cursor;
+        GCPtrFlatString* const props_end = ni->end();
+        for (GCPtrFlatString* idp = props_cursor; idp < props_end; ++idp) {
+            // Common case: both strings are atoms.
+            if ((*idp)->isAtom() && str->isAtom()) {
+                if (*idp != str)
+                    continue;
+            } else {
+                if (!EqualStrings(*idp, str))
+                    continue;
+            }
+
+            // Check whether another property along the prototype chain became
+            // visible as a result of this deletion.
+            RootedObject proto(cx);
+            if (!GetPrototype(cx, obj, &proto))
+                return false;
+            if (proto) {
+                RootedId id(cx);
+                RootedValue idv(cx, StringValue(*idp));
+                if (!ValueToId<CanGC>(cx, idv, &id))
+                    return false;
+
+                Rooted<PropertyDescriptor> desc(cx);
+                if (!GetPropertyDescriptor(cx, proto, id, &desc))
+                    return false;
+
+                if (desc.object() && desc.enumerable())
+                    continue;
+            }
+
+            // If GetPropertyDescriptor above removed a property from ni, start
+            // over.
+            if (props_end != ni->props_end || props_cursor != ni->props_cursor) {
+                restart = true;
+                break;
+            }
+
+            // No property along the prototype chain stepped in to take the
+            // property's place, so go ahead and delete id from the list.
+            // If it is the next property to be enumerated, just skip it.
+            if (idp == props_cursor) {
+                ni->incCursor();
+            } else {
+                for (GCPtrFlatString* p = idp; p + 1 != props_end; p++)
+                    *p = *(p + 1);
+                ni->props_end = ni->end() - 1;
+
+                // This invokes the pre barrier on this element, since
+                // it's no longer going to be marked, and ensures that
+                // any existing remembered set entry will be dropped.
+                *ni->props_end = nullptr;
+            }
+
+            // Don't reuse modified native iterators.
+            ni->flags |= JSITER_UNREUSABLE;
+            return true;
+        }
+
+        if (!restart)
+            return true;
+    }
+}
+
 /*
  * Suppress enumeration of deleted properties. This function must be called
  * when a property is deleted and there might be active enumerators.
  *
  * We maintain a list of active non-escaping for-in enumerators. To suppress
  * a property, we check whether each active enumerator contains the (obj, id)
  * pair and has not yet enumerated |id|. If so, and |id| is the next property,
  * we simply advance the cursor. Otherwise, we delete |id| from the list.
  *
  * We do not suppress enumeration of a property deleted along an object's
  * prototype chain. Only direct deletions on the object are handled.
- *
- * This function can suppress multiple properties at once. The |predicate|
- * argument is an object which can be called on an id and returns true or
- * false. It also must have a method |matchesAtMostOne| which allows us to
- * stop searching after the first deletion if true.
  */
-template<typename StringPredicate>
 static bool
-SuppressDeletedPropertyHelper(JSContext* cx, HandleObject obj, StringPredicate predicate)
+SuppressDeletedPropertyHelper(JSContext* cx, HandleObject obj, Handle<JSFlatString*> str)
 {
     NativeIterator* enumeratorList = cx->compartment()->enumerators;
     NativeIterator* ni = enumeratorList->next();
 
     while (ni != enumeratorList) {
-      again:
-        if (ni->obj == obj && ni->props_cursor < ni->props_end) {
-            /* Check whether id is still to come. */
-            GCPtrFlatString* props_cursor = ni->current();
-            GCPtrFlatString* props_end = ni->end();
-            for (GCPtrFlatString* idp = props_cursor; idp < props_end; ++idp) {
-                if (predicate(*idp)) {
-                    /*
-                     * Check whether another property along the prototype chain
-                     * became visible as a result of this deletion.
-                     */
-                    RootedObject proto(cx);
-                    if (!GetPrototype(cx, obj, &proto))
-                        return false;
-                    if (proto) {
-                        RootedId id(cx);
-                        RootedValue idv(cx, StringValue(*idp));
-                        if (!ValueToId<CanGC>(cx, idv, &id))
-                            return false;
-
-                        Rooted<PropertyDescriptor> desc(cx);
-                        if (!GetPropertyDescriptor(cx, proto, id, &desc))
-                            return false;
-
-                        if (desc.object()) {
-                            if (desc.enumerable())
-                                continue;
-                        }
-                    }
-
-                    /*
-                     * If GetPropertyDescriptorById above removed a property from
-                     * ni, start over.
-                     */
-                    if (props_end != ni->props_end || props_cursor != ni->props_cursor)
-                        goto again;
-
-                    /*
-                     * No property along the prototype chain stepped in to take the
-                     * property's place, so go ahead and delete id from the list.
-                     * If it is the next property to be enumerated, just skip it.
-                     */
-                    if (idp == props_cursor) {
-                        ni->incCursor();
-                    } else {
-                        for (GCPtrFlatString* p = idp; p + 1 != props_end; p++)
-                            *p = *(p + 1);
-                        ni->props_end = ni->end() - 1;
-
-                        /*
-                         * This invokes the pre barrier on this element, since
-                         * it's no longer going to be marked, and ensures that
-                         * any existing remembered set entry will be dropped.
-                         */
-                        *ni->props_end = nullptr;
-                    }
-
-                    /* Don't reuse modified native iterators. */
-                    ni->flags |= JSITER_UNREUSABLE;
-
-                    if (predicate.matchesAtMostOne())
-                        break;
-                }
-            }
-        }
+        if (!SuppressDeletedProperty(cx, ni, obj, str))
+            return false;
         ni = ni->next();
     }
+
     return true;
 }
 
-namespace {
-
-class SingleStringPredicate {
-    Handle<JSFlatString*> str;
-public:
-    explicit SingleStringPredicate(Handle<JSFlatString*> str) : str(str) {}
-
-    bool operator()(JSFlatString* str) { return EqualStrings(str, this->str); }
-    bool matchesAtMostOne() { return true; }
-};
-
-} /* anonymous namespace */
-
 bool
 js::SuppressDeletedProperty(JSContext* cx, HandleObject obj, jsid id)
 {
     if (MOZ_LIKELY(!cx->compartment()->objectMaybeInIteration(obj)))
         return true;
 
     if (JSID_IS_SYMBOL(id))
         return true;
 
     Rooted<JSFlatString*> str(cx, IdToString(cx, id));
     if (!str)
         return false;
-    return SuppressDeletedPropertyHelper(cx, obj, SingleStringPredicate(str));
+    return SuppressDeletedPropertyHelper(cx, obj, str);
 }
 
 bool
 js::SuppressDeletedElement(JSContext* cx, HandleObject obj, uint32_t index)
 {
     if (MOZ_LIKELY(!cx->compartment()->objectMaybeInIteration(obj)))
         return true;
 
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
 
     Rooted<JSFlatString*> str(cx, IdToString(cx, id));
     if (!str)
         return false;
-    return SuppressDeletedPropertyHelper(cx, obj, SingleStringPredicate(str));
+    return SuppressDeletedPropertyHelper(cx, obj, str);
 }
 
 bool
 js::IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval)
 {
     // Fast path for native iterators.
     if (MOZ_LIKELY(iterobj->is<PropertyIteratorObject>())) {
         NativeIterator* ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -202,16 +202,32 @@ intrinsic_IsInstanceOfBuiltin(JSContext*
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
 
     args.rval().setBoolean(args[0].toObject().is<T>());
     return true;
 }
 
+template<typename T>
+static bool
+intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isObject());
+
+    if (args[0].toObject().is<T>()) {
+        args.rval().setObject(args[0].toObject());
+        return true;
+    }
+    args.rval().setNull();
+    return true;
+}
+
 /**
  * Self-hosting intrinsic returning the original constructor for a builtin
  * the name of which is the first and only argument.
  *
  * The return value is guaranteed to be the original constructor even if
  * content code changed the named binding on the global object.
  *
  * This intrinsic shouldn't be called directly. Instead, the
@@ -2353,28 +2369,28 @@ static const JSFunctionSpec intrinsic_fu
     JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator,     0,0,
                     IntrinsicNewArrayIterator),
 
     JS_FN("CallArrayIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>,      2,0),
 
     JS_FN("_SetCanonicalName",       intrinsic_SetCanonicalName,        2,0),
 
-    JS_INLINABLE_FN("IsArrayIterator",
-                    intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
-                    IntrinsicIsArrayIterator),
-    JS_INLINABLE_FN("IsMapIterator",
-                    intrinsic_IsInstanceOfBuiltin<MapIteratorObject>,   1,0,
-                    IntrinsicIsMapIterator),
-    JS_INLINABLE_FN("IsSetIterator",
-                    intrinsic_IsInstanceOfBuiltin<SetIteratorObject>,   1,0,
-                    IntrinsicIsSetIterator),
-    JS_INLINABLE_FN("IsStringIterator",
-                    intrinsic_IsInstanceOfBuiltin<StringIteratorObject>, 1,0,
-                    IntrinsicIsStringIterator),
+    JS_INLINABLE_FN("GuardToArrayIterator",
+                    intrinsic_GuardToBuiltin<ArrayIteratorObject>, 1,0,
+                    IntrinsicGuardToArrayIterator),
+    JS_INLINABLE_FN("GuardToMapIterator",
+                    intrinsic_GuardToBuiltin<MapIteratorObject>,   1,0,
+                    IntrinsicGuardToMapIterator),
+    JS_INLINABLE_FN("GuardToSetIterator",
+                    intrinsic_GuardToBuiltin<SetIteratorObject>,   1,0,
+                    IntrinsicGuardToSetIterator),
+    JS_INLINABLE_FN("GuardToStringIterator",
+                    intrinsic_GuardToBuiltin<StringIteratorObject>, 1,0,
+                    IntrinsicGuardToStringIterator),
 
     JS_FN("_CreateMapIterationResultPair", intrinsic_CreateMapIterationResultPair, 0, 0),
     JS_INLINABLE_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 2,0,
                     IntrinsicGetNextMapEntryForIterator),
     JS_FN("CallMapIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>,        2,0),
 
     JS_FN("_CreateSetIterationResult", intrinsic_CreateSetIterationResult, 0, 0),
@@ -2392,22 +2408,22 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("IsGeneratorObject",
           intrinsic_IsInstanceOfBuiltin<GeneratorObject>,               1,0),
     JS_FN("GeneratorObjectIsClosed", intrinsic_GeneratorObjectIsClosed, 1,0),
     JS_FN("IsSuspendedGenerator",    intrinsic_IsSuspendedGenerator,    1,0),
 
     JS_FN("GeneratorIsRunning",      intrinsic_GeneratorIsRunning,      1,0),
     JS_FN("GeneratorSetClosed",      intrinsic_GeneratorSetClosed,      1,0),
 
-    JS_INLINABLE_FN("IsArrayBuffer",
-          intrinsic_IsInstanceOfBuiltin<ArrayBufferObject>,             1,0,
-          IntrinsicIsArrayBuffer),
-    JS_INLINABLE_FN("IsSharedArrayBuffer",
-          intrinsic_IsInstanceOfBuiltin<SharedArrayBufferObject>,       1,0,
-          IntrinsicIsSharedArrayBuffer),
+    JS_INLINABLE_FN("GuardToArrayBuffer",
+          intrinsic_GuardToBuiltin<ArrayBufferObject>,             1,0,
+          IntrinsicGuardToArrayBuffer),
+    JS_INLINABLE_FN("GuardToSharedArrayBuffer",
+          intrinsic_GuardToBuiltin<SharedArrayBufferObject>,       1,0,
+          IntrinsicGuardToSharedArrayBuffer),
     JS_FN("IsWrappedArrayBuffer",
           intrinsic_IsWrappedArrayBuffer<ArrayBufferObject>,            1,0),
     JS_FN("IsWrappedSharedArrayBuffer",
           intrinsic_IsWrappedArrayBuffer<SharedArrayBufferObject>,      1,0),
 
     JS_INLINABLE_FN("ArrayBufferByteLength",
                     intrinsic_ArrayBufferByteLength<ArrayBufferObject>, 1,0,
                     IntrinsicArrayBufferByteLength),
@@ -2462,22 +2478,22 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("CallSharedArrayBufferMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<SharedArrayBufferObject>>, 2, 0),
     JS_FN("CallTypedArrayMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0),
 
     JS_FN("CallGeneratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<GeneratorObject>>, 2, 0),
 
-    JS_INLINABLE_FN("IsMapObject", intrinsic_IsInstanceOfBuiltin<MapObject>, 1, 0,
-                    IntrinsicIsMapObject),
+    JS_INLINABLE_FN("GuardToMapObject", intrinsic_GuardToBuiltin<MapObject>, 1, 0,
+                    IntrinsicGuardToMapObject),
     JS_FN("CallMapMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<MapObject>>, 2, 0),
 
-    JS_INLINABLE_FN("IsSetObject", intrinsic_IsInstanceOfBuiltin<SetObject>, 1, 0,
-                    IntrinsicIsSetObject),
+    JS_INLINABLE_FN("GuardToSetObject", intrinsic_GuardToBuiltin<SetObject>, 1, 0,
+                    IntrinsicGuardToSetObject),
     JS_FN("CallSetMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0),
 
     // See builtin/TypedObject.h for descriptors of the typedobj functions.
     JS_FN("NewOpaqueTypedObject",           js::NewOpaqueTypedObject, 1, 0),
     JS_FN("NewDerivedTypedObject",          js::NewDerivedTypedObject, 3, 0),
     JS_FN("TypedObjectBuffer",              TypedObject::GetBuffer, 1, 0),
     JS_FN("TypedObjectByteOffset",          TypedObject::GetByteOffset, 1, 0),
     JS_FN("AttachTypedObject",              js::AttachTypedObject, 3, 0),
@@ -2542,31 +2558,31 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
     JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 1, 0),
     JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
     JS_FN("intl_RelativeTimeFormat_availableLocales", intl_RelativeTimeFormat_availableLocales, 0,0),
     JS_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 4,0),
     JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2,0),
     JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2,0),
 
-    JS_INLINABLE_FN("IsCollator",
-                    intrinsic_IsInstanceOfBuiltin<CollatorObject>, 1,0,
-                    IntlIsCollator),
-    JS_INLINABLE_FN("IsDateTimeFormat",
-                    intrinsic_IsInstanceOfBuiltin<DateTimeFormatObject>, 1,0,
-                    IntlIsDateTimeFormat),
-    JS_INLINABLE_FN("IsNumberFormat",
-                    intrinsic_IsInstanceOfBuiltin<NumberFormatObject>, 1,0,
-                    IntlIsNumberFormat),
-    JS_INLINABLE_FN("IsPluralRules",
-                    intrinsic_IsInstanceOfBuiltin<PluralRulesObject>, 1,0,
-                    IntlIsPluralRules),
-    JS_INLINABLE_FN("IsRelativeTimeFormat",
-                    intrinsic_IsInstanceOfBuiltin<RelativeTimeFormatObject>, 1,0,
-                    IntlIsRelativeTimeFormat),
+    JS_INLINABLE_FN("GuardToCollator",
+                    intrinsic_GuardToBuiltin<CollatorObject>, 1,0,
+                    IntlGuardToCollator),
+    JS_INLINABLE_FN("GuardToDateTimeFormat",
+                    intrinsic_GuardToBuiltin<DateTimeFormatObject>, 1,0,
+                    IntlGuardToDateTimeFormat),
+    JS_INLINABLE_FN("GuardToNumberFormat",
+                    intrinsic_GuardToBuiltin<NumberFormatObject>, 1,0,
+                    IntlGuardToNumberFormat),
+    JS_INLINABLE_FN("GuardToPluralRules",
+                    intrinsic_GuardToBuiltin<PluralRulesObject>, 1,0,
+                    IntlGuardToPluralRules),
+    JS_INLINABLE_FN("GuardToRelativeTimeFormat",
+                    intrinsic_GuardToBuiltin<RelativeTimeFormatObject>, 1,0,
+                    IntlGuardToRelativeTimeFormat),
     JS_FN("GetDateTimeFormatConstructor",
           intrinsic_GetBuiltinIntlConstructor<GlobalObject::getOrCreateDateTimeFormatConstructor>,
           0,0),
     JS_FN("GetNumberFormatConstructor",
           intrinsic_GetBuiltinIntlConstructor<GlobalObject::getOrCreateNumberFormatConstructor>,
           0,0),
 
     JS_FN("GetOwnPropertyDescriptorToArray", GetOwnPropertyDescriptorToArray, 2,0),
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -856,17 +856,18 @@ void
 AccessibleCaretManager::ChangeFocusToOrClearOldFocus(nsIFrame* aFrame) const
 {
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   MOZ_ASSERT(fm);
 
   if (aFrame) {
     nsIContent* focusableContent = aFrame->GetContent();
     MOZ_ASSERT(focusableContent, "Focusable frame must have content!");
-    nsCOMPtr<nsIDOMElement> focusableElement = do_QueryInterface(focusableContent);
+    RefPtr<Element> focusableElement =
+      focusableContent->IsElement() ? focusableContent->AsElement() : nullptr;
     fm->SetFocus(focusableElement, nsIFocusManager::FLAG_BYMOUSE);
   } else {
     nsPIDOMWindowOuter* win = mPresShell->GetDocument()->GetWindow();
     if (win) {
       fm->ClearFocus(win);
       fm->SetFocusedWindow(win);
     }
   }
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -443,17 +443,17 @@ IsInlineFrame(const nsIFrame* aFrame)
 }
 
 /**
  * True for display: contents elements.
  */
 static inline bool
 IsDisplayContents(const Element* aElement)
 {
-  return aElement->HasServoData() && Servo_Element_IsDisplayContents(aElement);
+  return aElement->IsDisplayContents();
 }
 
 static inline bool
 IsDisplayContents(const nsIContent* aContent)
 {
   return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
 }
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1457,23 +1457,21 @@ GetPropagatedScrollbarStylesForViewport(
     return docElement;
   }
 
   // Don't look in the BODY for non-HTML documents or HTML documents
   // with non-HTML roots.
   // XXX this should be earlier; we shouldn't even look at the document root
   // for non-HTML documents. Fix this once we support explicit CSS styling
   // of the viewport
-  // XXX what about XHTML?
-  nsHTMLDocument* htmlDoc = document->AsHTMLDocument();
-  if (!htmlDoc || !docElement->IsHTMLElement()) {
+  if (!document->IsHTMLOrXHTML() || !docElement->IsHTMLElement()) {
     return nullptr;
   }
 
-  Element* bodyElement = htmlDoc->GetBodyElement();
+  Element* bodyElement = document->AsHTMLDocument()->GetBodyElement();
   if (!bodyElement) {
     // No body, nothing to do here.
     return nullptr;
   }
 
   MOZ_ASSERT(bodyElement->IsHTMLElement(nsGkAtoms::body),
              "GetBodyElement returned something bogus");
 
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -17,29 +17,29 @@
 #include "mozilla/Vector.h"
 #include "mozilla/WeakPtr.h"
 #include "nsTObserverArray.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsTObserverArray.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
-#include "mozilla/AnimationEventDispatcher.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/layers/TransactionIdAllocator.h"
 
 class nsPresContext;
 class nsIPresShell;
 class nsIDocument;
 class imgIRequest;
 class nsINode;
 class nsIRunnable;
 
 namespace mozilla {
+class AnimationEventDispatcher;
 class RefreshDriverTimer;
 class Runnable;
 
 namespace layout {
 class VsyncChild;
 } // namespace layout
 
 namespace dom {
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -1586,18 +1586,17 @@ nsFrameSelection::RepaintSelection(Selec
   }
 #endif
   return mDomSelections[index]->Repaint(mShell->GetPresContext());
 }
 
 static bool
 IsDisplayContents(const nsIContent* aContent)
 {
-  return aContent->IsElement() && aContent->AsElement()->HasServoData() &&
-    Servo_Element_IsDisplayContents(aContent->AsElement());
+  return aContent->IsElement() && aContent->AsElement()->IsDisplayContents();
 }
 
 nsIFrame*
 nsFrameSelection::GetFrameForNodeOffset(nsIContent*        aNode,
                                         int32_t            aOffset,
                                         CaretAssociateHint aHint,
                                         int32_t*           aReturnOffset) const
 {
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -1589,25 +1589,26 @@ nsPluginFrame::HandleEvent(nsPresContext
 
   if (!mInstanceOwner)
     return NS_ERROR_NULL_POINTER;
 
   mInstanceOwner->ConsiderNewEventloopNestingLevel();
 
   if (anEvent->mMessage == ePluginActivate) {
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-    nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(GetContent());
-    if (fm && elem)
+    if (fm) {
+      RefPtr<Element> elem = GetContent()->AsElement();
       return fm->SetFocus(elem, 0);
+    }
   }
   else if (anEvent->mMessage == ePluginFocus) {
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
-      nsCOMPtr<nsIContent> content = GetContent();
-      return fm->FocusPlugin(content);
+      RefPtr<Element> elem = GetContent()->AsElement();
+      return fm->FocusPlugin(elem);
     }
   }
 
   if (mInstanceOwner->SendNativeEvents() &&
       anEvent->IsNativeEventDelivererForPlugin()) {
     *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
     // Due to plugin code reentering Gecko, this frame may be dead at this
     // point.
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -376,18 +376,18 @@ InspectorUtils::GetCSSPropertyNames(Glob
     if (nsCSSProps::IsEnabled(cssProp, enabledState)) {
       nsDependentCString name(kCSSRawProperties[prop]);
       aResult.AppendElement(NS_ConvertASCIItoUTF16(name));
     }
   };
 
   uint32_t prop = 0;
   for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
-    if (nsCSSProps::PropertyParseType(nsCSSPropertyID(prop)) !=
-        CSS_PROPERTY_PARSE_INACCESSIBLE) {
+    if (!nsCSSProps::PropHasFlags(nsCSSPropertyID(prop),
+                                  CSSPropFlags::Inaccessible)) {
       appendProperty(prop);
     }
   }
 
   if (aOptions.mIncludeShorthands) {
     for ( ; prop < eCSSProperty_COUNT; ++prop) {
       appendProperty(prop);
     }
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -8,16 +8,17 @@
 
 #include "BasicLayers.h"
 #include "gfxPrefs.h"
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/EventForwards.h"  // for Modifiers
 #include "mozilla/ViewportFrame.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/LayerTransactionParent.h"
 #include "nsContentUtils.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
 #include "nsIObserver.h"
@@ -309,21 +310,17 @@ RenderFrameParent::GetTextureFactoryIden
 
 void
 RenderFrameParent::TakeFocusForClickFromTap()
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm) {
     return;
   }
-  nsCOMPtr<nsIContent> owner = mFrameLoader->GetOwnerContent();
-  if (!owner) {
-    return;
-  }
-  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(owner);
+  RefPtr<Element> element = mFrameLoader->GetOwnerContent();
   if (!element) {
     return;
   }
   fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
                         nsIFocusManager::FLAG_BYTOUCH |
                         nsIFocusManager::FLAG_NOSCROLL);
 }
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -676,17 +676,17 @@ AddAnimationsForProperty(nsIFrame* aFram
     data = TransformData(origin, offsetToTransformOrigin,
                          bounds, devPixelsToAppUnits,
                          scaleX, scaleY, hasPerspectiveParent);
   } else if (aProperty == eCSSProperty_opacity) {
     data = null_t();
   }
 
   MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
-                                      CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
+                                      CSSPropFlags::CanAnimateOnCompositor),
              "inconsistent property flags");
 
   // Add from first to last (since last overrides)
   for (size_t animIdx = 0; animIdx < compositorAnimations.Length(); animIdx++) {
     dom::Animation* anim = compositorAnimations[animIdx];
     if (!anim->IsRelevant()) {
       continue;
     }
@@ -809,17 +809,17 @@ GenerateAndPushTextMask(nsIFrame* aFrame
 /* static */ void
 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
                                                          nsDisplayListBuilder* aBuilder,
                                                          nsDisplayItem* aItem,
                                                          nsIFrame* aFrame,
                                                          nsCSSPropertyID aProperty)
 {
   MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
-                                      CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
+                                      CSSPropFlags::CanAnimateOnCompositor),
              "inconsistent property flags");
 
   // This function can be called in two ways:  from
   // nsDisplay*::BuildLayer while constructing a layer (with all
   // pointers non-null), or from RestyleManager's handling of
   // UpdateOpacityLayer/UpdateTransformLayer hints.
   MOZ_ASSERT(!aBuilder == !aItem,
              "should only be called in two configurations, with both "
--- a/layout/printing/nsPrintPreviewListener.cpp
+++ b/layout/printing/nsPrintPreviewListener.cpp
@@ -177,21 +177,19 @@ nsPrintPreviewListener::HandleEvent(Even
           nsIDocument* parentDoc = doc->GetParentDocument();
           NS_ASSERTION(parentDoc, "no parent document");
 
           nsCOMPtr<nsPIDOMWindowOuter> win = parentDoc->GetWindow();
 
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm && win) {
             dom::Element* fromElement = parentDoc->FindContentForSubDocument(doc);
-            nsCOMPtr<nsIDOMElement> from = do_QueryInterface(fromElement);
-
             bool forward = (action == eEventAction_Tab);
-            nsCOMPtr<nsIDOMElement> result;
-            fm->MoveFocus(win, from,
+            RefPtr<dom::Element> result;
+            fm->MoveFocus(win, fromElement,
                           forward ? nsIFocusManager::MOVEFOCUS_FORWARD :
                                     nsIFocusManager::MOVEFOCUS_BACKWARD,
                           nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
           }
         }
       }
       MOZ_FALLTHROUGH;
       case eEventAction_Suppress:
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -3,17 +3,17 @@ skip-if(!asyncPan) == bg-fixed-cover-1.h
 skip-if(!asyncPan) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
 skip-if(!asyncPan) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
 skip-if(!asyncPan) == bg-fixed-child.html bg-fixed-child-ref.html
 skip-if(!asyncPan) == bg-fixed-child-clip-1.html bg-fixed-child-clip-ref.html
 skip-if(!asyncPan) == bg-fixed-child-clip-2.html bg-fixed-child-clip-ref.html
 fuzzy(1,246) fuzzy-if(skiaContent,2,170) fuzzy-if(browserIsRemote&&d2d,59,187) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html
 skip-if(!asyncPan) == bg-fixed-in-opacity.html bg-fixed-in-opacity-ref.html
 # Passing the test below without WebRender would require implementing CSS filters in the Gecko compositor.
-fails-if(!webrender) skip-if(!asyncPan) fuzzy-if(webrender&&gtkWidget,0-1,0-59) fuzzy-if(webrender&&winWidget,0-1,0-8) == bg-fixed-in-css-filter.html bg-fixed-in-css-filter-ref.html # bug 1454794 for webrender fuzziness
+fails-if(!webrender) skip-if(!asyncPan) fuzzy-if(webrender&&gtkWidget,0-1,0-87) fuzzy-if(webrender&&winWidget,0-1,0-8) == bg-fixed-in-css-filter.html bg-fixed-in-css-filter-ref.html # bug 1454794 for webrender fuzziness
 skip-if(!asyncPan) == bg-fixed-child-no-culling-1.html bg-fixed-child-no-culling-1-ref.html
 skip-if(!asyncPan) == bg-fixed-child-no-culling-2.html bg-fixed-child-no-culling-2-ref.html
 skip-if(!asyncPan) == bg-fixed-child-no-culling-3.html bg-fixed-child-no-culling-3-ref.html
 fuzzy-if(Android,2,4000) fuzzy-if(browserIsRemote&&cocoaWidget,2,179524) fuzzy-if(browserIsRemote&&winWidget,1,74590) fuzzy-if(gtkWidget&&layersGPUAccelerated,1,3528) skip-if(!asyncPan) == bg-fixed-transformed-image.html bg-fixed-transformed-image-ref.html
 skip-if(!asyncPan) == element-1.html element-1-ref.html
 pref(layers.force-active,true) skip-if(!asyncPan) == iframe-1.html iframe-1-ref.html
 skip-if(!asyncPan) == nested-1.html nested-1-ref.html
 skip-if(!asyncPan) == nested-2.html nested-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/style/CSSPropFlags.h
@@ -0,0 +1,58 @@
+/* -*- 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_CSSPropFlags_h
+#define mozilla_CSSPropFlags_h
+
+#include "mozilla/TypedEnumBits.h"
+
+namespace mozilla {
+
+enum class CSSPropFlags : uint8_t
+{
+  // This property is not parsed. It is only there for internal use like
+  // attribute mapping.
+  Inaccessible = 1 << 0,
+
+  // This property's getComputedStyle implementation requires layout to
+  // be flushed.
+  GetCSNeedsLayoutFlush = 1 << 1,
+
+  // The following two flags along with the pref defines where the this
+  // property can be used:
+  // * If none of the two flags is presented, the pref completely controls
+  //   the availability of this property. And in that case, if it has no
+  //   pref, this property is usable everywhere.
+  // * If any of the flags is set, this property is always enabled in the
+  //   specific contexts regardless of the value of the pref. If there is
+  //   no pref for this property at all in this case, it is an internal-
+  //   only property, which cannot be used anywhere else, and should be
+  //   wrapped in "#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL".
+  // Note that, these flags have no effect on the use of aliases of this
+  // property.
+  // Furthermore, for the purposes of animation (including triggering
+  // transitions) these flags are ignored. That is, if the property is disabled
+  // by a pref, we will *not* run animations or transitions on it even in
+  // UA sheets or chrome.
+  EnabledInUASheets = 1 << 2,
+  EnabledInChrome = 1 << 3,
+  EnabledInUASheetsAndChrome = EnabledInUASheets | EnabledInChrome,
+  EnabledMask = EnabledInUASheetsAndChrome,
+
+  // This property can be animated on the compositor.
+  CanAnimateOnCompositor = 1 << 4,
+
+  // This property is an internal property that is not represented in
+  // the DOM. Properties with this flag are defined in an #ifndef
+  // CSS_PROP_LIST_EXCLUDE_INTERNAL section.
+  Internal = 1 << 5,
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CSSPropFlags)
+
+} // namespace mozilla
+
+#endif // mozilla_CSSPropFlags_h
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -50,21 +50,23 @@ public:
           const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
           WeightRange aWeight,
           StretchRange aStretch,
           SlantStyleRange aStyle,
           const nsTArray<gfxFontFeature>& aFeatureSettings,
           const nsTArray<gfxFontVariation>& aVariationSettings,
           uint32_t aLanguageOverride,
           gfxCharacterMap* aUnicodeRanges,
-          uint8_t aFontDisplay)
+          uint8_t aFontDisplay,
+          RangeFlags aRangeFlags)
       : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
                          aStyle, aFeatureSettings, aVariationSettings,
                          aLanguageOverride,
-                         aUnicodeRanges, aFontDisplay) {}
+                         aUnicodeRanges, aFontDisplay,
+                         aRangeFlags) {}
 
     virtual void SetLoadState(UserFontLoadState aLoadState) override;
     virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) override;
     const AutoTArray<FontFace*,1>& GetFontFaces() { return mFontFaces; }
 
   protected:
     // The FontFace objects that use this user font entry.  We need to store
     // an array of these, not just a single pointer, since the user font
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -991,18 +991,23 @@ GetWeightForDescriptor(const nsCSSValue&
       return FontWeight::Normal();
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown font-weight descriptor value");
       return FontWeight::Normal();
   }
 }
 
 static WeightRange
-GetWeightRangeForDescriptor(const nsCSSValue& aVal)
+GetWeightRangeForDescriptor(const nsCSSValue& aVal,
+                            gfxFontEntry::RangeFlags& aRangeFlags)
 {
+  if (aVal.GetUnit() == eCSSUnit_Null) {
+    aRangeFlags |= gfxFontEntry::RangeFlags::eAutoWeight;
+    return WeightRange(FontWeight::Normal());
+  }
   if (aVal.GetUnit() == eCSSUnit_Pair) {
     return WeightRange(GetWeightForDescriptor(aVal.GetPairValue().mXValue),
                        GetWeightForDescriptor(aVal.GetPairValue().mYValue));
   }
   return WeightRange(GetWeightForDescriptor(aVal));
 }
 
 static FontSlantStyle
@@ -1019,18 +1024,23 @@ GetStyleForDescriptor(const nsCSSValue& 
       return aVal.GetFontSlantStyle();
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown font-style descriptor value");
       return FontSlantStyle::Normal();
   }
 }
 
 static SlantStyleRange
-GetStyleRangeForDescriptor(const nsCSSValue& aVal)
+GetStyleRangeForDescriptor(const nsCSSValue& aVal,
+                           gfxFontEntry::RangeFlags& aRangeFlags)
 {
+  if (aVal.GetUnit() == eCSSUnit_Null) {
+    aRangeFlags |= gfxFontEntry::RangeFlags::eAutoSlantStyle;
+    return SlantStyleRange(FontSlantStyle::Normal());
+  }
   if (aVal.GetUnit() == eCSSUnit_Pair) {
     return SlantStyleRange(GetStyleForDescriptor(aVal.GetPairValue().mXValue),
                            GetStyleForDescriptor(aVal.GetPairValue().mYValue));
   }
   return SlantStyleRange(GetStyleForDescriptor(aVal));
 }
 
 static FontStretch
@@ -1043,18 +1053,23 @@ GetStretchForDescriptor(const nsCSSValue
       return aVal.GetFontStretch();
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown font-style descriptor value");
       return FontStretch::Normal();
   }
 }
 
 static StretchRange
-GetStretchRangeForDescriptor(const nsCSSValue& aVal)
+GetStretchRangeForDescriptor(const nsCSSValue& aVal,
+                             gfxFontEntry::RangeFlags& aRangeFlags)
 {
+  if (aVal.GetUnit() == eCSSUnit_Null) {
+    aRangeFlags |= gfxFontEntry::RangeFlags::eAutoStretch;
+    return StretchRange(FontStretch::Normal());
+  }
   if (aVal.GetUnit() == eCSSUnit_Pair) {
     return StretchRange(GetStretchForDescriptor(aVal.GetPairValue().mXValue),
                        GetStretchForDescriptor(aVal.GetPairValue().mYValue));
   }
   return StretchRange(GetStretchForDescriptor(aVal));
 }
 
 /* static */ already_AddRefed<gfxUserFontEntry>
@@ -1065,27 +1080,29 @@ FontFaceSet::FindOrCreateUserFontEntryFr
   FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
 
   nsCSSValue val;
   nsCSSUnit unit;
 
   uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
   uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
 
+  gfxFontEntry::RangeFlags rangeFlags = gfxFontEntry::RangeFlags::eNoFlags;
+
   // set up weight
   aFontFace->GetDesc(eCSSFontDesc_Weight, val);
-  WeightRange weight = GetWeightRangeForDescriptor(val);
+  WeightRange weight = GetWeightRangeForDescriptor(val, rangeFlags);
 
   // set up stretch
   aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
-  StretchRange stretch = GetStretchRangeForDescriptor(val);
+  StretchRange stretch = GetStretchRangeForDescriptor(val, rangeFlags);
 
   // set up font style
   aFontFace->GetDesc(eCSSFontDesc_Style, val);
-  SlantStyleRange italicStyle = GetStyleRangeForDescriptor(val);
+  SlantStyleRange italicStyle = GetStyleRangeForDescriptor(val, rangeFlags);
 
   // set up font display
   aFontFace->GetDesc(eCSSFontDesc_Display, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Enumerated) {
     fontDisplay = val.GetIntValue();
   } else {
     NS_ASSERTION(unit == eCSSUnit_Null,
@@ -1257,17 +1274,19 @@ FontFaceSet::FindOrCreateUserFontEntryFr
   }
 
   RefPtr<gfxUserFontEntry> entry =
     set->mUserFontSet->FindOrCreateUserFontEntry(aFamilyName, srcArray, weight,
                                                  stretch, italicStyle,
                                                  featureSettings,
                                                  variationSettings,
                                                  languageOverride,
-                                                 unicodeRanges, fontDisplay);
+                                                 unicodeRanges, fontDisplay,
+                                                 rangeFlags);
+
   return entry.forget();
 }
 
 RawServoFontFaceRule*
 FontFaceSet::FindRuleForEntry(gfxFontEntry* aFontEntry)
 {
   NS_ASSERTION(!aFontEntry->mIsUserFontContainer, "only platform font entries");
   for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
@@ -1844,17 +1863,17 @@ FontFaceSet::PrefEnabled()
   }
   return enabled;
 }
 
 // nsICSSLoaderObserver
 
 NS_IMETHODIMP
 FontFaceSet::StyleSheetLoaded(StyleSheet* aSheet,
-                              bool aWasAlternate,
+                              bool aWasDeferred,
                               nsresult aStatus)
 {
   CheckLoadingFinished();
   return NS_OK;
 }
 
 void
 FontFaceSet::FlushUserFontSet()
@@ -1992,20 +2011,21 @@ FontFaceSet::UserFontSet::CreateUserFont
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay)
+                               uint8_t aFontDisplay,
+                               RangeFlags aRangeFlags)
 {
   RefPtr<gfxUserFontEntry> entry =
     new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle,
                         aFeatureSettings, aVariationSettings,
                         aLanguageOverride, aUnicodeRanges,
-                        aFontDisplay);
+                        aFontDisplay, aRangeFlags);
   return entry.forget();
 }
 
 #undef LOG_ENABLED
 #undef LOG
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -100,17 +100,18 @@ public:
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    WeightRange aWeight,
                                    StretchRange aStretch,
                                    SlantStyleRange aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
-                                   uint8_t aFontDisplay) override;
+                                   uint8_t aFontDisplay,
+                                   RangeFlags aRangeFlags) override;
 
   private:
     RefPtr<FontFaceSet> mFontFaceSet;
   };
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
   NS_DECL_NSIDOMEVENTLISTENER
--- a/layout/style/GenerateCSSPropsGenerated.py
+++ b/layout/style/GenerateCSSPropsGenerated.py
@@ -23,17 +23,17 @@ def get_properties(dataFile):
 
     properties = sorted(properties, cmp=property_compare)
 
     for i, p in enumerate(properties):
         p["index"] = i
 
     # Record each property's IDL name.
     for p in properties:
-        if "CSS_PROPERTY_INTERNAL" in p["flags"]:
+        if "CSSPropFlags::Internal" in p["flags"]:
             p["idlname"] = None
         else:
             idl_name = p["prop"]
             if not idl_name.startswith("Moz"):
                 idl_name = idl_name[0].lower() + idl_name[1:]
             p["idlname"] = idl_name
 
     return properties
--- a/layout/style/GenerateServoCSSPropList.py
+++ b/layout/style/GenerateServoCSSPropList.py
@@ -64,29 +64,29 @@ def generate_header(output, data):
 """)
 
     MACRO_NAMES = {
         "longhand": "CSS_PROP_LONGHAND",
         "shorthand": "CSS_PROP_SHORTHAND",
         "alias": "CSS_PROP_ALIAS",
     }
     for name, method, id, flags, pref, proptype in data:
-        is_internal = "CSS_PROPERTY_INTERNAL" in flags
+        is_internal = "CSSPropFlags::Internal" in flags
         pref = '"' + pref + '"'
         if proptype == "alias":
             params = [name, id[0], id[1], method, pref]
         else:
             if method == "CssFloat":
                 method = "CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float)"
             elif method.startswith("Moz"):
                 method = "CSS_PROP_DOMPROP_PREFIXED({})".format(method[3:])
             if flags:
                 flags = " | ".join(flags)
             else:
-                flags = "0"
+                flags = "CSSPropFlags(0)"
             params = [name, id, method, flags, pref]
 
         if is_internal:
             output.write("#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL\n")
         output.write("{}({})\n".format(MACRO_NAMES[proptype], ", ".join(params)))
         if is_internal:
             output.write("#endif\n")
 
--- a/layout/style/GenericSpecifiedValues.h
+++ b/layout/style/GenericSpecifiedValues.h
@@ -10,17 +10,17 @@
  * code generic over style backends.
  */
 
 #ifndef mozilla_GenericSpecifiedValues_h
 #define mozilla_GenericSpecifiedValues_h
 
 #include "mozilla/ServoUtils.h"
 #include "mozilla/FontPropertyTypes.h"
-#include "nsCSSProps.h"
+#include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 #include "nsColor.h"
 
 class nsAttrValue;
 
 namespace mozilla {
 
 class ServoSpecifiedValues;
--- a/layout/style/LayerAnimationInfo.cpp
+++ b/layout/style/LayerAnimationInfo.cpp
@@ -19,36 +19,36 @@ namespace mozilla {
       nsChangeHint_UpdateOpacityLayer } };
 
 #ifdef DEBUG
 /* static */ void
 LayerAnimationInfo::Initialize()
 {
   for (const Record& record : sRecords) {
     MOZ_ASSERT(nsCSSProps::PropHasFlags(record.mProperty,
-                                        CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
+                                        CSSPropFlags::CanAnimateOnCompositor),
                "CSS property with entry in LayerAnimation::sRecords does not "
-               "have the CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR flag");
+               "have the CSSPropFlags::CanAnimateOnCompositor flag");
   }
 
   // Check that every property with the flag for animating on the
   // compositor has an entry in LayerAnimationInfo::sRecords.
   for (nsCSSPropertyID prop = nsCSSPropertyID(0);
        prop < eCSSProperty_COUNT;
        prop = nsCSSPropertyID(prop + 1)) {
     if (nsCSSProps::PropHasFlags(prop,
-                                 CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
+                                 CSSPropFlags::CanAnimateOnCompositor)) {
       bool found = false;
       for (const Record& record : sRecords) {
         if (record.mProperty == prop) {
           found = true;
           break;
         }
       }
       MOZ_ASSERT(found,
-                 "CSS property with the CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR "
+                 "CSS property with the CSSPropFlags::CanAnimateOnCompositor "
                  "flag does not have an entry in LayerAnimationInfo::sRecords");
     }
   }
 }
 #endif
 
 } // namespace mozilla
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -140,16 +140,17 @@ NS_IMPL_ISUPPORTS(SheetLoadData, nsIRunn
                   nsIThreadObserver)
 
 SheetLoadData::SheetLoadData(Loader* aLoader,
                              const nsAString& aTitle,
                              nsIURI* aURI,
                              StyleSheet* aSheet,
                              nsIStyleSheetLinkingElement* aOwningElement,
                              bool aIsAlternate,
+                             bool aMediaMatches,
                              nsICSSLoaderObserver* aObserver,
                              nsIPrincipal* aLoaderPrincipal,
                              nsINode* aRequestingNode)
   : mLoader(aLoader)
   , mTitle(aTitle)
   , mEncoding(nullptr)
   , mURI(aURI)
   , mLineNumber(1)
@@ -158,16 +159,17 @@ SheetLoadData::SheetLoadData(Loader* aLo
   , mPendingChildren(0)
   , mSyncLoad(false)
   , mIsNonDocumentSheet(false)
   , mIsLoading(false)
   , mIsBeingParsed(false)
   , mIsCancelled(false)
   , mMustNotify(false)
   , mWasAlternate(aIsAlternate)
+  , mMediaMatched(aMediaMatches)
   , mUseSystemPrincipal(false)
   , mSheetAlreadyComplete(false)
   , mIsCrossOriginNoCORS(false)
   , mBlockResourceTiming(false)
   , mLoadFailed(false)
   , mOwningElement(aOwningElement)
   , mObserver(aObserver)
   , mLoaderPrincipal(aLoaderPrincipal)
@@ -194,16 +196,17 @@ SheetLoadData::SheetLoadData(Loader* aLo
   , mPendingChildren(0)
   , mSyncLoad(false)
   , mIsNonDocumentSheet(false)
   , mIsLoading(false)
   , mIsBeingParsed(false)
   , mIsCancelled(false)
   , mMustNotify(false)
   , mWasAlternate(false)
+  , mMediaMatched(true)
   , mUseSystemPrincipal(false)
   , mSheetAlreadyComplete(false)
   , mIsCrossOriginNoCORS(false)
   , mBlockResourceTiming(false)
   , mLoadFailed(false)
   , mOwningElement(nullptr)
   , mObserver(aObserver)
   , mLoaderPrincipal(aLoaderPrincipal)
@@ -240,16 +243,17 @@ SheetLoadData::SheetLoadData(Loader* aLo
   , mPendingChildren(0)
   , mSyncLoad(aSyncLoad)
   , mIsNonDocumentSheet(true)
   , mIsLoading(false)
   , mIsBeingParsed(false)
   , mIsCancelled(false)
   , mMustNotify(false)
   , mWasAlternate(false)
+  , mMediaMatched(true)
   , mUseSystemPrincipal(aUseSystemPrincipal)
   , mSheetAlreadyComplete(false)
   , mIsCrossOriginNoCORS(false)
   , mBlockResourceTiming(false)
   , mLoadFailed(false)
   , mOwningElement(nullptr)
   , mObserver(aObserver)
   , mLoaderPrincipal(aLoaderPrincipal)
@@ -412,17 +416,17 @@ Loader::~Loader()
 void
 Loader::DropDocumentReference(void)
 {
   mDocument = nullptr;
   // Flush out pending datas just so we don't leak by accident.  These
   // loads should short-circuit through the mDocument check in
   // LoadSheet and just end up in SheetComplete immediately
   if (mSheets) {
-    StartAlternateLoads();
+    StartDeferredLoads();
   }
 }
 
 nsresult
 Loader::SetPreferredSheet(const nsAString& aTitle)
 {
 #ifdef DEBUG
   if (mDocument) {
@@ -442,17 +446,18 @@ Loader::SetPreferredSheet(const nsAStrin
   if (mSheets) {
     LoadDataArray arr(mSheets->mPendingDatas.Count());
     for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
       SheetLoadData* data = iter.Data();
       MOZ_ASSERT(data, "Must have a data");
 
       // Note that we don't want to affect what the selected style set is, so
       // use true for aHasAlternateRel.
-      if (!data->mLoader->IsAlternate(data->mTitle, true)) {
+      auto isAlternate = data->mLoader->IsAlternateSheet(data->mTitle, true);
+      if (isAlternate == IsAlternate::No) {
         arr.AppendElement(data);
         iter.Remove();
       }
     }
 
     mDatasToNotifyOn += arr.Length();
     for (uint32_t i = 0; i < arr.Length(); ++i) {
       --mDatasToNotifyOn;
@@ -827,37 +832,44 @@ SheetLoadData::VerifySheetReadyToParse(n
   }
 
   // Enough to set the URIs on mSheet, since any sibling datas we have share
   // the same mInner as mSheet and will thus get the same URI.
   mSheet->SetURIs(channelURI, originalURI, channelURI);
   return NS_OK_PARSE_SHEET;
 }
 
-bool
-Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel)
+Loader::IsAlternate
+Loader::IsAlternateSheet(const nsAString& aTitle, bool aHasAlternateRel)
 {
   // A sheet is alternate if it has a nonempty title that doesn't match the
   // currently selected style set.  But if there _is_ no currently selected
   // style set, the sheet wasn't marked as an alternate explicitly, and aTitle
   // is nonempty, we should select the style set corresponding to aTitle, since
   // that's a preferred sheet.
+  //
+  // FIXME(emilio): This should return false for Shadow DOM regardless of the
+  // document.
   if (aTitle.IsEmpty()) {
-    return false;
+    return IsAlternate::No;
   }
 
   if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) {
     // There's no preferred set yet, and we now have a sheet with a title.
     // Make that be the preferred set.
     mDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, aTitle);
-    // We're definitely not an alternate
-    return false;
+    // We're definitely not an alternate.
+    return IsAlternate::No;
   }
 
-  return !aTitle.Equals(mPreferredSheet);
+  if (aTitle.Equals(mPreferredSheet)) {
+    return IsAlternate::No;
+  }
+
+  return IsAlternate::Yes;
 }
 
 nsresult
 Loader::ObsoleteSheet(nsIURI* aURI)
 {
   if (!mSheets) {
     return NS_OK;
   }
@@ -928,32 +940,32 @@ Loader::CreateSheet(nsIURI* aURI,
                     css::SheetParsingMode aParsingMode,
                     CORSMode aCORSMode,
                     ReferrerPolicy aReferrerPolicy,
                     const nsAString& aIntegrity,
                     bool aSyncLoad,
                     bool aHasAlternateRel,
                     const nsAString& aTitle,
                     StyleSheetState& aSheetState,
-                    bool *aIsAlternate,
+                    IsAlternate* aIsAlternate,
                     RefPtr<StyleSheet>* aSheet)
 {
   LOG(("css::Loader::CreateSheet"));
   NS_PRECONDITION(aSheet, "Null out param!");
 
   if (!mSheets) {
     mSheets = new Sheets();
   }
 
   *aSheet = nullptr;
   aSheetState = eSheetStateUnknown;
 
   // Check the alternate state before doing anything else, because it
   // can mess with our hashtables.
-  *aIsAlternate = IsAlternate(aTitle, aHasAlternateRel);
+  *aIsAlternate = IsAlternateSheet(aTitle, aHasAlternateRel);
 
   if (aURI) {
     aSheetState = eSheetComplete;
     RefPtr<StyleSheet> sheet;
 
     // First, the XUL cache
 #ifdef MOZ_XUL
     if (IsChromeURI(aURI)) {
@@ -1104,42 +1116,63 @@ Loader::CreateSheet(nsIURI* aURI,
 
   NS_ASSERTION(*aSheet, "We should have a sheet by now!");
   NS_ASSERTION(aSheetState != eSheetStateUnknown, "Have to set a state!");
   LOG(("  State: %s", gStateStrings[aSheetState]));
 
   return NS_OK;
 }
 
+static Loader::MediaMatched
+MediaListMatches(const MediaList* aMediaList, const nsIDocument* aDocument)
+{
+  if (!aMediaList || !aDocument) {
+    return Loader::MediaMatched::Yes;
+  }
+
+  nsPresContext* pc = aDocument->GetPresContext();
+  if (!pc) {
+    // Conservatively assume a match.
+    return Loader::MediaMatched::Yes;
+  }
+
+  if (aMediaList->Matches(pc)) {
+    return Loader::MediaMatched::Yes;
+  }
+
+  return Loader::MediaMatched::No;
+}
+
 /**
  * PrepareSheet() handles setting the media and title on the sheet, as
  * well as setting the enabled state based on the title and whether
  * the sheet had "alternate" in its rel.
  */
-void
+Loader::MediaMatched
 Loader::PrepareSheet(StyleSheet* aSheet,
                      const nsAString& aTitle,
                      const nsAString& aMediaString,
                      MediaList* aMediaList,
-                     bool aIsAlternate)
+                     IsAlternate aIsAlternate)
 {
   NS_PRECONDITION(aSheet, "Must have a sheet!");
 
   RefPtr<MediaList> mediaList(aMediaList);
 
   if (!aMediaString.IsEmpty()) {
     NS_ASSERTION(!aMediaList,
                  "must not provide both aMediaString and aMediaList");
     mediaList = MediaList::Create(aMediaString);
   }
 
   aSheet->SetMedia(mediaList);
 
   aSheet->SetTitle(aTitle);
-  aSheet->SetEnabled(!aIsAlternate);
+  aSheet->SetEnabled(aIsAlternate == IsAlternate::No);
+  return MediaListMatches(mediaList, mDocument);
 }
 
 /**
  * InsertSheetInDoc handles ordering of sheets in the document.  Here
  * we have two types of sheets -- those with linking elements and
  * those without.  The latter are loaded by Link: headers.
  * The following constraints are observed:
  * 1) Any sheet with a linking element comes after all sheets without
@@ -1392,17 +1425,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
 
   if (existingData) {
     LOG(("  Glomming on to existing load"));
     SheetLoadData* data = existingData;
     while (data->mNext) {
       data = data->mNext;
     }
     data->mNext = aLoadData; // transfer ownership
-    if (aSheetState == eSheetPending && !aLoadData->mWasAlternate) {
+    if (aSheetState == eSheetPending && !aLoadData->ShouldDefer()) {
       // Kick the load off; someone cares about it right away
 
 #ifdef DEBUG
       SheetLoadData* removedData;
       NS_ASSERTION(mSheets->mPendingDatas.Get(&key, &removedData) &&
                    removedData == existingData,
                    "Bad pending table.");
 #endif
@@ -1487,17 +1520,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
 #ifdef DEBUG
     mSyncCallback = false;
 #endif
     LOG_ERROR(("  Failed to create channel"));
     SheetComplete(aLoadData, rv);
     return rv;
   }
 
-  if (!aLoadData->mWasAlternate) {
+  if (!aLoadData->ShouldDefer()) {
     nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
     if (cos) {
       cos->AddClassFlags(nsIClassOfService::Leader);
     }
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
@@ -1704,33 +1737,33 @@ Loader::SheetComplete(SheetLoadData* aLo
   for (uint32_t i = 0; i < count; ++i) {
     --mDatasToNotifyOn;
 
     SheetLoadData* data = datasToNotify[i];
     NS_ASSERTION(data && data->mMustNotify, "How did this data get here?");
     if (data->mObserver) {
       LOG(("  Notifying observer %p for data %p.  wasAlternate: %d",
            data->mObserver.get(), data, data->mWasAlternate));
-      data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
+      data->mObserver->StyleSheetLoaded(data->mSheet, data->ShouldDefer(),
                                         aStatus);
     }
 
     nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> >::ForwardIterator iter(mObservers);
     nsCOMPtr<nsICSSLoaderObserver> obs;
     while (iter.HasMore()) {
       obs = iter.GetNext();
       LOG(("  Notifying global observer %p for data %p.  wasAlternate: %d",
            obs.get(), data, data->mWasAlternate));
       obs->StyleSheetLoaded(data->mSheet, data->mWasAlternate, aStatus);
     }
   }
 
   if (mSheets->mLoadingDatas.Count() == 0 && mSheets->mPendingDatas.Count() > 0) {
-    LOG(("  No more loading sheets; starting alternates"));
-    StartAlternateLoads();
+    LOG(("  No more loading sheets; starting deferred loads"));
+    StartDeferredLoads();
   }
 }
 
 void
 Loader::DoSheetComplete(SheetLoadData* aLoadData, LoadDataArray& aDatasToNotify)
 {
   LOG(("css::Loader::DoSheetComplete"));
   NS_PRECONDITION(aLoadData, "Must have a load data!");
@@ -1858,130 +1891,141 @@ Loader::MarkLoadTreeFailed(SheetLoadData
     if (aLoadData->mParentData) {
       MarkLoadTreeFailed(aLoadData->mParentData);
     }
 
     aLoadData = aLoadData->mNext;
   } while (aLoadData);
 }
 
-nsresult
+Result<Loader::LoadSheetResult, nsresult>
 Loader::LoadInlineStyle(nsIContent* aElement,
                         const nsAString& aBuffer,
                         nsIPrincipal* aTriggeringPrincipal,
                         uint32_t aLineNumber,
                         const nsAString& aTitle,
                         const nsAString& aMedia,
                         ReferrerPolicy aReferrerPolicy,
-                        nsICSSLoaderObserver* aObserver,
-                        bool* aCompleted,
-                        bool* aIsAlternate)
+                        nsICSSLoaderObserver* aObserver)
 {
   LOG(("css::Loader::LoadInlineStyle"));
 
-  *aCompleted = true;
-
   if (!mEnabled) {
     LOG_WARN(("  Not enabled"));
-    return NS_ERROR_NOT_AVAILABLE;
+    return Err(NS_ERROR_NOT_AVAILABLE);
   }
 
-  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
+  if (!mDocument) {
+    return Err(NS_ERROR_NOT_INITIALIZED);
+  }
 
   nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
   NS_ASSERTION(owningElement, "Element is not a style linking element!");
 
   // Since we're not planning to load a URI, no need to hand a principal to the
   // load data or to CreateSheet().  Also, OK to use CORS_NONE for the CORS
   // mode.
 
   StyleSheetState state;
   RefPtr<StyleSheet> sheet;
+  IsAlternate isAlternate;
   nsresult rv = CreateSheet(nullptr, aElement, nullptr, eAuthorSheetFeatures,
                             CORS_NONE, aReferrerPolicy,
                             EmptyString(), // no inline integrity checks
-                            false, false, aTitle, state, aIsAlternate,
+                            false, false, aTitle, state, &isAlternate,
                             &sheet);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return Err(rv);
+  }
   NS_ASSERTION(state == eSheetNeedsParser,
                "Inline sheets should not be cached");
 
-  LOG(("  Sheet is alternate: %d", *aIsAlternate));
+  LOG(("  Sheet is alternate: %d", static_cast<int>(isAlternate)));
 
-  PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate);
+  auto matched = PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
 
   if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
     ShadowRoot* containingShadow = aElement->GetContainingShadow();
     MOZ_ASSERT(containingShadow);
     containingShadow->InsertSheet(sheet, aElement);
   } else {
     rv = InsertSheetInDoc(sheet, aElement, mDocument);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      return Err(rv);
+    }
   }
 
   nsIPrincipal* principal = aElement->NodePrincipal();
   if (aTriggeringPrincipal) {
     // The triggering principal may be an expanded principal, which is safe to
     // use for URL security checks, but not as the loader principal for a
     // stylesheet. So treat this as principal inheritance, and downgrade if
     // necessary.
     principal = BasePrincipal::Cast(aTriggeringPrincipal)->PrincipalToInherit();
   }
 
   SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
-                                          owningElement, *aIsAlternate,
+                                          owningElement,
+                                          isAlternate == IsAlternate::Yes,
+                                          matched == MediaMatched::Yes,
                                           aObserver, nullptr,
                                           static_cast<nsINode*>(aElement));
 
   // We never actually load this, so just set its principal directly
   sheet->SetPrincipal(principal);
 
   NS_ADDREF(data);
   data->mLineNumber = aLineNumber;
+  bool completed = true;
   // Parse completion releases the load data.
   //
   // Note that we need to parse synchronously, since the web expects that the
   // effects of inline stylesheets are visible immediately (aside from @imports).
   rv = ParseSheet(aBuffer, EmptyCString(),
-                  data, /* aAllowAsync = */ false, *aCompleted);
-  NS_ENSURE_SUCCESS(rv, rv);
+                  data,
+                  /* aAllowAsync = */ false,
+                  completed);
+  if (NS_FAILED(rv)) {
+    return Err(rv);
+  }
 
-  // If aCompleted is true, |data| may well be deleted by now.
-  if (!*aCompleted) {
+  // If completed is true, |data| may well be deleted by now.
+  if (!completed) {
     data->mMustNotify = true;
   }
-  return rv;
+  return LoadSheetResult { completed ? Completed::Yes : Completed::No, isAlternate, matched };
 }
 
-nsresult
+Result<Loader::LoadSheetResult, nsresult>
 Loader::LoadStyleLink(nsIContent* aElement,
                       nsIURI* aURL,
                       nsIPrincipal* aTriggeringPrincipal,
                       const nsAString& aTitle,
                       const nsAString& aMedia,
                       bool aHasAlternateRel,
                       CORSMode aCORSMode,
                       ReferrerPolicy aReferrerPolicy,
                       const nsAString& aIntegrity,
-                      nsICSSLoaderObserver* aObserver,
-                      bool* aIsAlternate)
+                      nsICSSLoaderObserver* aObserver)
 {
   NS_PRECONDITION(aURL, "Must have URL to load");
   LOG(("css::Loader::LoadStyleLink"));
   LOG_URI("  Link uri: '%s'", aURL);
   LOG(("  Link title: '%s'", NS_ConvertUTF16toUTF8(aTitle).get()));
   LOG(("  Link media: '%s'", NS_ConvertUTF16toUTF8(aMedia).get()));
   LOG(("  Link alternate rel: %d", aHasAlternateRel));
 
   if (!mEnabled) {
     LOG_WARN(("  Not enabled"));
-    return NS_ERROR_NOT_AVAILABLE;
+    return Err(NS_ERROR_NOT_AVAILABLE);
   }
 
-  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
+  if (!mDocument) {
+    return Err(NS_ERROR_NOT_INITIALIZED);
+  }
 
   nsIPrincipal* loadingPrincipal = aElement ? aElement->NodePrincipal()
                                             : mDocument->NodePrincipal();
 
   nsIPrincipal* principal = aTriggeringPrincipal ? aTriggeringPrincipal
                                                  : loadingPrincipal;
 
   nsISupports* context = aElement;
@@ -1999,74 +2043,98 @@ Loader::LoadStyleLink(nsIContent* aEleme
     if (aElement && !mDocument->IsLoadedAsData()) {
       // Fire an async error event on it.
       RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
         new LoadBlockingAsyncEventDispatcher(aElement,
                                              NS_LITERAL_STRING("error"),
                                              false, false);
       loadBlockingAsyncDispatcher->PostDOMEvent();
     }
-    return rv;
+    return Err(rv);
   }
 
   StyleSheetState state;
   RefPtr<StyleSheet> sheet;
+  IsAlternate isAlternate;
   rv = CreateSheet(aURL, aElement, principal, eAuthorSheetFeatures,
                    aCORSMode, aReferrerPolicy, aIntegrity, false,
-                   aHasAlternateRel, aTitle, state, aIsAlternate,
+                   aHasAlternateRel, aTitle, state, &isAlternate,
                    &sheet);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return Err(rv);
+  }
+
+  LOG(("  Sheet is alternate: %d", static_cast<int>(isAlternate)));
 
-  LOG(("  Sheet is alternate: %d", *aIsAlternate));
+  auto matched = PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
 
-  PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate);
-
+  // FIXME(emilio, bug 1410578): Shadow DOM should be handled here too.
   rv = InsertSheetInDoc(sheet, aElement, mDocument);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return Err(rv);
+  }
 
   nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
 
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete: 0x%p", sheet.get()));
     if (aObserver || !mObservers.IsEmpty() || owningElement) {
-      rv = PostLoadEvent(aURL, sheet, aObserver, *aIsAlternate,
+      rv = PostLoadEvent(aURL,
+                         sheet,
+                         aObserver,
+                         isAlternate,
+                         matched,
                          owningElement);
-      return rv;
+      if (NS_FAILED(rv)) {
+        return Err(rv);
+      }
     }
 
-    return NS_OK;
+    // The load hasn't been completed yet, will be done in PostLoadEvent.
+    return LoadSheetResult { Completed::No, isAlternate, matched };
   }
 
   // Now we need to actually load it
   nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
   SheetLoadData* data = new SheetLoadData(this, aTitle, aURL, sheet,
-                                          owningElement, *aIsAlternate,
+                                          owningElement,
+                                          isAlternate == IsAlternate::Yes,
+                                          matched == MediaMatched::Yes,
                                           aObserver, principal, requestingNode);
   NS_ADDREF(data);
 
-  // If we have to parse and it's an alternate non-inline, defer it
-  if (aURL && state == eSheetNeedsParser && mSheets->mLoadingDatas.Count() != 0 &&
-      *aIsAlternate) {
-    LOG(("  Deferring alternate sheet load"));
+  auto result = LoadSheetResult { Completed::No, isAlternate, matched };
+
+  MOZ_ASSERT(result.ShouldBlock() == !data->ShouldDefer(),
+             "These should better match!");
+
+  // If we have to parse and it's a non-blocking non-inline sheet, defer it.
+  if (aURL &&
+      state == eSheetNeedsParser &&
+      mSheets->mLoadingDatas.Count() != 0 &&
+      !result.ShouldBlock()) {
+    LOG(("  Deferring sheet load"));
     URIPrincipalReferrerPolicyAndCORSModeHashKey key(data->mURI,
                                                      data->mLoaderPrincipal,
                                                      data->mSheet->GetCORSMode(),
                                                      data->mSheet->GetReferrerPolicy());
     mSheets->mPendingDatas.Put(&key, data);
 
     data->mMustNotify = true;
-    return NS_OK;
+    return result;
   }
 
   // Load completion will free the data
   rv = LoadSheet(data, state, false);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return Err(rv);
+  }
 
   data->mMustNotify = true;
-  return rv;
+  return result;
 }
 
 static bool
 HaveAncestorDataWithURI(SheetLoadData *aData, nsIURI *aURI)
 {
   if (!aData->mURI) {
     // Inline style; this won't have any ancestors
     MOZ_ASSERT(!aData->mParentData,
@@ -2166,17 +2234,17 @@ Loader::LoadChildSheet(StyleSheet* aPare
 
   // Now that we know it's safe to load this (passes security check and not a
   // loop) do so.
   RefPtr<StyleSheet> sheet;
   StyleSheetState state;
   if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, sheet)) {
     state = eSheetComplete;
   } else {
-    bool isAlternate;
+    IsAlternate isAlternate;
     const nsAString& empty = EmptyString();
     // For now, use CORS_NONE for child sheets
     rv = CreateSheet(aURL, nullptr, principal,
                      aParentSheet->ParsingMode(),
                      CORS_NONE, aParentSheet->GetReferrerPolicy(),
                      EmptyString(), // integrity is only checked on main sheet
                      aParentData ? aParentData->mSyncLoad : false,
                      false, empty, state, &isAlternate, &sheet);
@@ -2323,32 +2391,37 @@ Loader::InternalLoadNonDocumentSheet(nsI
   nsCOMPtr<nsIPrincipal> loadingPrincipal = (aOriginPrincipal && mDocument
                                              ? mDocument->NodePrincipal()
                                              : nullptr);
   nsresult rv = CheckContentPolicy(loadingPrincipal, aOriginPrincipal,
                                    aURL, mDocument, aIsPreload);
   NS_ENSURE_SUCCESS(rv, rv);
 
   StyleSheetState state;
-  bool isAlternate;
   RefPtr<StyleSheet> sheet;
   bool syncLoad = (aObserver == nullptr);
   const nsAString& empty = EmptyString();
+  IsAlternate isAlternate;
 
   rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aParsingMode,
                    aCORSMode, aReferrerPolicy, aIntegrity, syncLoad,
                    false, empty, state, &isAlternate, &sheet);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrepareSheet(sheet, empty, empty, nullptr, isAlternate);
 
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete"));
     if (aObserver || !mObservers.IsEmpty()) {
-      rv = PostLoadEvent(aURL, sheet, aObserver, false, nullptr);
+      rv = PostLoadEvent(aURL,
+                         sheet,
+                         aObserver,
+                         IsAlternate::No,
+                         MediaMatched::Yes,
+                         nullptr);
     }
     if (aSheet) {
       sheet.swap(*aSheet);
     }
     return rv;
   }
 
   SheetLoadData* data = new SheetLoadData(this,
@@ -2374,30 +2447,32 @@ Loader::InternalLoadNonDocumentSheet(nsI
 
   return rv;
 }
 
 nsresult
 Loader::PostLoadEvent(nsIURI* aURI,
                       StyleSheet* aSheet,
                       nsICSSLoaderObserver* aObserver,
-                      bool aWasAlternate,
+                      IsAlternate aWasAlternate,
+                      MediaMatched aMediaMatched,
                       nsIStyleSheetLinkingElement* aElement)
 {
   LOG(("css::Loader::PostLoadEvent"));
   NS_PRECONDITION(aSheet, "Must have sheet");
   NS_PRECONDITION(aObserver || !mObservers.IsEmpty() || aElement,
                   "Must have observer or element");
 
   RefPtr<SheetLoadData> evt =
     new SheetLoadData(this, EmptyString(), // title doesn't matter here
                       aURI,
                       aSheet,
                       aElement,
-                      aWasAlternate,
+                      aWasAlternate == IsAlternate::Yes,
+                      aMediaMatched == MediaMatched::Yes,
                       aObserver,
                       nullptr,
                       mDocument);
 
   if (!mPostedEvents.AppendElement(evt)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
@@ -2537,17 +2612,17 @@ Loader::AddObserver(nsICSSLoaderObserver
 
 void
 Loader::RemoveObserver(nsICSSLoaderObserver* aObserver)
 {
   mObservers.RemoveElement(aObserver);
 }
 
 void
-Loader::StartAlternateLoads()
+Loader::StartDeferredLoads()
 {
   NS_PRECONDITION(mSheets, "Don't call me!");
   LoadDataArray arr(mSheets->mPendingDatas.Count());
   for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
     arr.AppendElement(iter.Data());
     iter.Remove();
   }
 
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -14,29 +14,29 @@
 #include "nsCompatibility.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsRefPtrHashtable.h"
 #include "nsStringFwd.h"
 #include "nsTArray.h"
 #include "nsTObserverArray.h"
 #include "nsURIHashKey.h"
+#include "nsIStyleSheetLinkingElement.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsICSSLoaderObserver;
 class nsIConsoleReportCollector;
 class nsIContent;
 class nsIDocument;
-class nsIStyleSheetLinkingElement;
 
 namespace mozilla {
 namespace dom {
 class DocGroup;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
@@ -186,16 +186,21 @@ enum StyleSheetState {
   eSheetLoading,
   eSheetComplete
 };
 
 class Loader final {
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
 public:
+  typedef nsIStyleSheetLinkingElement::IsAlternate IsAlternate;
+  typedef nsIStyleSheetLinkingElement::MediaMatched MediaMatched;
+  typedef nsIStyleSheetLinkingElement::Completed Completed;
+  typedef nsIStyleSheetLinkingElement::Update LoadSheetResult;
+
   Loader();
   // aDocGroup is used for dispatching SheetLoadData in PostLoadEvent(). It
   // can be null if you want to use this constructor, and there's no
   // document when the Loader is constructed.
   explicit Loader(mozilla::dom::DocGroup*);
   explicit Loader(nsIDocument*);
 
  private:
@@ -212,83 +217,77 @@ public:
   { mCompatMode = aCompatMode; }
   nsCompatibility GetCompatibilityMode() { return mCompatMode; }
   nsresult SetPreferredSheet(const nsAString& aTitle);
 
   // XXXbz sort out what the deal is with events!  When should they fire?
 
   /**
    * Load an inline style sheet.  If a successful result is returned and
-   * *aCompleted is false, then aObserver is guaranteed to be notified
+   * result.WillNotify() is true, then aObserver is guaranteed to be notified
    * asynchronously once the sheet is marked complete.  If an error is
-   * returned, or if *aCompleted is true, aObserver will not be notified.  In
-   * addition to parsing the sheet, this method will insert it into the
-   * stylesheet list of this CSSLoader's document.
+   * returned, or if result.WillNotify() is false, aObserver will not be
+   * notified.  In addition to parsing the sheet, this method will insert it
+   * into the stylesheet list of this CSSLoader's document.
    *
    * @param aElement the element linking to the stylesheet.  This must not be
    *                 null and must implement nsIStyleSheetLinkingElement.
    * @param aBuffer the stylesheet data
    * @param aTriggeringPrincipal The principal of the scripted caller that
    *                             initiated the load, if available. Otherwise
    *                             null.
    * @param aLineNumber the line number at which the stylesheet data started.
    * @param aTitle the title of the sheet.
    * @param aMedia the media string for the sheet.
    * @param aReferrerPolicy the referrer policy for loading the sheet.
    * @param aObserver the observer to notify when the load completes.
    *        May be null.
-   * @param [out] aCompleted whether parsing of the sheet completed.
-   * @param [out] aIsAlternate whether the stylesheet ended up being an
-   *        alternate sheet.
    */
-  nsresult LoadInlineStyle(nsIContent* aElement,
-                           const nsAString& aBuffer,
-                           nsIPrincipal* aTriggeringPrincipal,
-                           uint32_t aLineNumber,
-                           const nsAString& aTitle,
-                           const nsAString& aMedia,
-                           ReferrerPolicy aReferrerPolicy,
-                           nsICSSLoaderObserver* aObserver,
-                           bool* aCompleted,
-                           bool* aIsAlternate);
+  Result<LoadSheetResult, nsresult>
+    LoadInlineStyle(nsIContent* aElement,
+                    const nsAString& aBuffer,
+                    nsIPrincipal* aTriggeringPrincipal,
+                    uint32_t aLineNumber,
+                    const nsAString& aTitle,
+                    const nsAString& aMedia,
+                    ReferrerPolicy aReferrerPolicy,
+                    nsICSSLoaderObserver* aObserver);
 
   /**
    * Load a linked (document) stylesheet.  If a successful result is returned,
    * aObserver is guaranteed to be notified asynchronously once the sheet is
-   * loaded and marked complete.  If an error is returned, aObserver will not
-   * be notified.  In addition to loading the sheet, this method will insert it
-   * into the stylesheet list of this CSSLoader's document.
+   * loaded and marked complete, i.e., result.WillNotify() will always return
+   * true.  If an error is returned, aObserver will not be notified.  In
+   * addition to loading the sheet, this method will insert it into the
+   * stylesheet list of this CSSLoader's document.
    *
    * @param aElement the element linking to the the stylesheet.  May be null.
    * @param aURL the URL of the sheet.
    * @param aTriggeringPrincipal the triggering principal for the load. May be
    *        null, in which case the NodePrincipal() of the element (or
    *        document if aElement is null) should be used.
    * @param aTitle the title of the sheet.
    * @param aMedia the media string for the sheet.
    * @param aHasAlternateRel whether the rel for this link included
    *        "alternate".
    * @param aCORSMode the CORS mode for this load.
    * @param aObserver the observer to notify when the load completes.
    *                  May be null.
-   * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
-   *        an alternate sheet.  Note that this need not match
-   *        aHasAlternateRel.
    */
-  nsresult LoadStyleLink(nsIContent* aElement,
-                         nsIURI* aURL,
-                         nsIPrincipal* aTriggeringPrincipal,
-                         const nsAString& aTitle,
-                         const nsAString& aMedia,
-                         bool aHasAlternateRel,
-                         CORSMode aCORSMode,
-                         ReferrerPolicy aReferrerPolicy,
-                         const nsAString& aIntegrity,
-                         nsICSSLoaderObserver* aObserver,
-                         bool* aIsAlternate);
+  Result<LoadSheetResult, nsresult>
+    LoadStyleLink(nsIContent* aElement,
+                  nsIURI* aURL,
+                  nsIPrincipal* aTriggeringPrincipal,
+                  const nsAString& aTitle,
+                  const nsAString& aMedia,
+                  bool aHasAlternateRel,
+                  CORSMode aCORSMode,
+                  ReferrerPolicy aReferrerPolicy,
+                  const nsAString& aIntegrity,
+                  nsICSSLoaderObserver* aObserver);
 
   /**
    * Load a child (@import-ed) style sheet.  In addition to loading the sheet,
    * this method will insert it into the child sheet list of aParentSheet.  If
    * there is no sheet currently being parsed and the child sheet is not
    * complete when this method returns, then when the child sheet becomes
    * complete aParentSheet will be QIed to nsICSSLoaderObserver and
    * asynchronously notified, just like for LoadStyleLink.  Note that if the
@@ -457,19 +456,19 @@ public:
   /**
    * Remove an observer added via AddObserver.
    */
   void RemoveObserver(nsICSSLoaderObserver* aObserver);
 
   // These interfaces are public only for the benefit of static functions
   // within nsCSSLoader.cpp.
 
-  // IsAlternate can change our currently selected style set if none
-  // is selected and aHasAlternateRel is false.
-  bool IsAlternate(const nsAString& aTitle, bool aHasAlternateRel);
+  // IsAlternateSheet can change our currently selected style set if none is
+  // selected and aHasAlternateRel is false.
+  IsAlternate IsAlternateSheet(const nsAString& aTitle, bool aHasAlternateRel);
 
   typedef nsTArray<RefPtr<SheetLoadData> > LoadDataArray;
 
   // Measure our size.
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   // Marks all the sheets at the given URI obsolete, and removes them from the
   // cache.
@@ -503,28 +502,28 @@ private:
                        css::SheetParsingMode aParsingMode,
                        CORSMode aCORSMode,
                        ReferrerPolicy aReferrerPolicy,
                        const nsAString& aIntegrity,
                        bool aSyncLoad,
                        bool aHasAlternateRel,
                        const nsAString& aTitle,
                        StyleSheetState& aSheetState,
-                       bool *aIsAlternate,
+                       IsAlternate* aIsAlternate,
                        RefPtr<StyleSheet>* aSheet);
 
   // Pass in either a media string or the MediaList from the CSSParser.  Don't
   // pass both.
   //
   // This method will set the sheet's enabled state based on aIsAlternate
-  void PrepareSheet(StyleSheet* aSheet,
-                    const nsAString& aTitle,
-                    const nsAString& aMediaString,
-                    dom::MediaList* aMediaList,
-                    bool aIsAlternate);
+  MediaMatched PrepareSheet(StyleSheet* aSheet,
+                            const nsAString& aTitle,
+                            const nsAString& aMediaString,
+                            dom::MediaList* aMediaList,
+                            IsAlternate);
 
   nsresult InsertSheetInDoc(StyleSheet* aSheet,
                             nsIContent* aLinkingContent,
                             nsIDocument* aDocument);
 
   nsresult InsertChildSheet(StyleSheet* aSheet,
                             StyleSheet* aParentSheet);
 
@@ -546,21 +545,22 @@ private:
   // canceled at some point (in which case it will be sent with
   // NS_BINDING_ABORTED).  aWasAlternate indicates the state when the load was
   // initiated, not the state at some later time.  aURI should be the URI the
   // sheet was loaded from (may be null for inline sheets).  aElement is the
   // owning element for this sheet.
   nsresult PostLoadEvent(nsIURI* aURI,
                          StyleSheet* aSheet,
                          nsICSSLoaderObserver* aObserver,
-                         bool aWasAlternate,
+                         IsAlternate aWasAlternate,
+                         MediaMatched aMediaMatched,
                          nsIStyleSheetLinkingElement* aElement);
 
   // Start the loads of all the sheets in mPendingDatas
-  void StartAlternateLoads();
+  void StartDeferredLoads();
 
   // Handle an event posted by PostLoadEvent
   void HandleLoadEvent(SheetLoadData* aEvent);
 
   // Note: LoadSheet is responsible for releasing aLoadData and setting the
   // sheet to complete on failure.
   nsresult LoadSheet(SheetLoadData* aLoadData,
                      StyleSheetState aSheetState,
--- a/layout/style/PreloadedStyleSheet.cpp
+++ b/layout/style/PreloadedStyleSheet.cpp
@@ -88,17 +88,17 @@ PreloadedStyleSheet::Preload()
   return GetSheet(&sheet);
 }
 
 NS_IMPL_ISUPPORTS(PreloadedStyleSheet::StylesheetPreloadObserver,
                   nsICSSLoaderObserver)
 
 NS_IMETHODIMP
 PreloadedStyleSheet::StylesheetPreloadObserver::StyleSheetLoaded(
-  StyleSheet* aSheet, bool aWasAlternate, nsresult aStatus)
+  StyleSheet* aSheet, bool aWasDeferred, nsresult aStatus)
 {
   MOZ_DIAGNOSTIC_ASSERT(!mPreloadedSheet->mLoaded);
   mPreloadedSheet->mLoaded = true;
 
   if (NS_FAILED(aStatus)) {
     mPromise->MaybeReject(aStatus);
   } else {
     mPromise->MaybeResolve(mPreloadedSheet);
--- a/layout/style/ServoCSSPropList.mako.py
+++ b/layout/style/ServoCSSPropList.mako.py
@@ -25,28 +25,28 @@ def is_internal(prop):
         "-moz-window-transform",
         "-moz-window-transform-origin",
     ]
     return prop.name in OTHER_INTERNALS
 
 def flags(prop):
     result = []
     if prop.explicitly_enabled_in_chrome():
-        result.append("CSS_PROPERTY_ENABLED_IN_UA_SHEETS_AND_CHROME")
+        result.append("EnabledInUASheetsAndChrome")
     elif prop.explicitly_enabled_in_ua_sheets():
-        result.append("CSS_PROPERTY_ENABLED_IN_UA_SHEETS")
+        result.append("EnabledInUASheets")
     if is_internal(prop):
-        result.append("CSS_PROPERTY_INTERNAL")
+        result.append("Internal")
     if prop.enabled_in == "":
-        result.append("CSS_PROPERTY_PARSE_INACCESSIBLE")
+        result.append("Inaccessible")
     if "GETCS_NEEDS_LAYOUT_FLUSH" in prop.flags:
-        result.append("CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH")
+        result.append("GetCSNeedsLayoutFlush")
     if "CAN_ANIMATE_ON_COMPOSITOR" in prop.flags:
-        result.append("CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR")
-    return ", ".join('"{}"'.format(flag) for flag in result)
+        result.append("CanAnimateOnCompositor")
+    return ", ".join('"CSSPropFlags::{}"'.format(flag) for flag in result)
 
 def pref(prop):
     if prop.gecko_pref:
         return '"' + prop.gecko_pref + '"'
     return '""'
 %>
 
 [
--- a/layout/style/SheetLoadData.h
+++ b/layout/style/SheetLoadData.h
@@ -45,16 +45,17 @@ protected:
 public:
   // Data for loading a sheet linked from a document
   SheetLoadData(Loader* aLoader,
                 const nsAString& aTitle,
                 nsIURI* aURI,
                 StyleSheet* aSheet,
                 nsIStyleSheetLinkingElement* aOwningElement,
                 bool aIsAlternate,
+                bool aMediaMatches,
                 nsICSSLoaderObserver* aObserver,
                 nsIPrincipal* aLoaderPrincipal,
                 nsINode* aRequestingNode);
 
   // Data for loading a sheet linked from an @import rule
   SheetLoadData(Loader* aLoader,
                 nsIURI* aURI,
                 StyleSheet* aSheet,
@@ -152,16 +153,20 @@ public:
   // are fired for any SheetLoadData that has a non-null
   // mOwningElement.
   bool mMustNotify : 1;
 
   // mWasAlternate is true if the sheet was an alternate when the load data was
   // created.
   bool mWasAlternate : 1;
 
+  // mMediaMatched is true if the sheet matched its medialist when the load data
+  // was created.
+  bool mMediaMatched : 1;
+
   // mUseSystemPrincipal is true if the system principal should be used for
   // this sheet, no matter what the channel principal is.  Only true for sync
   // loads.
   bool mUseSystemPrincipal : 1;
 
   // If true, this SheetLoadData is being used as a way to handle
   // async observer notification for an already-complete sheet.
   bool mSheetAlreadyComplete : 1;
@@ -194,16 +199,21 @@ public:
 
   // The node that identifies who started loading us.
   nsCOMPtr<nsINode> mRequestingNode;
 
   // The encoding to use for preloading Must be empty if mOwningElement
   // is non-null.
   const Encoding* mPreloadEncoding;
 
+  bool ShouldDefer() const
+  {
+    return mWasAlternate || !mMediaMatched;
+  }
+
 private:
   void FireLoadEvent(nsIThreadInternal* aThread);
 };
 
 typedef nsMainThreadPtrHolder<SheetLoadData> SheetLoadDataHolder;
 
 } // namespace css
 } // namespace mozilla
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -12,17 +12,17 @@
 #include "mozilla/gfx/MatrixFwd.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/UniquePtr.h"
 #include "nsStringFwd.h"
 #include "nsStringBuffer.h"
 #include "nsCoord.h"
 #include "nsColor.h"
-#include "nsCSSProps.h"
+#include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 #include "nsStyleCoord.h"
 #include "nsStyleTransformMatrix.h"
 
 class nsIFrame;
 class gfx3DMatrix;
 
 namespace mozilla {
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -64,16 +64,17 @@ EXPORTS += [
 EXPORTS.mozilla += [
     '!ServoCSSPropList.h',
     'AnimationCollection.h',
     'BindingStyleRule.h',
     'CachedInheritingStyles.h',
     'ComputedStyle.h',
     'ComputedStyleInlines.h',
     'CSSEnabledState.h',
+    'CSSPropFlags.h',
     'DeclarationBlock.h',
     'DeclarationBlockInlines.h',
     'DocumentStyleRootIterator.h',
     'GenericSpecifiedValues.h',
     'GenericSpecifiedValuesInlines.h',
     'LayerAnimationInfo.h',
     'MediaFeatureChange.h',
     'PostTraversalTask.h',
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -35,54 +35,52 @@
   InterCaps and all hyphens ('-') must be removed.  Callers using this
   parameter must also define the CSS_PROP_PUBLIC_OR_PRIVATE(publicname_,
   privatename_) macro to yield either publicname_ or privatename_.
   The names differ in that publicname_ has Moz prefixes where they are
   used, and also in CssFloat vs. Float.  The caller's choice depends on
   whether the use is for internal use such as eCSSProperty_* or
   nsRuleData::ValueFor* or external use such as exposing DOM properties.
 
-  -. 'flags', a bitfield containing CSS_PROPERTY_* flags.
-
   -. 'pref' is the name of a pref that controls whether the property
   is enabled.  The property is enabled if 'pref' is an empty string,
   or if the boolean property whose name is 'pref' is set to true.
 
   -. 'parsevariant', to be passed to ParseVariant in the parser.
 
   -. 'kwtable', which is either nullptr or the name of the appropriate
   keyword table member of class nsCSSProps, for use in
   nsCSSProps::LookupPropertyValue.
 
   -. 'animtype_' gives the animation type (see nsStyleAnimType) of this
   property.
 
-  CSS_PROP_SHORTHAND only takes 1-5.
+  CSS_PROP_SHORTHAND only takes 1-4.
 
  ******/
 
 
 /*************************************************************************/
 
 
 // All includers must explicitly define CSS_PROP_SHORTHAND if they
 // want it.
 #ifndef CSS_PROP_SHORTHAND
-#define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) /* nothing */
+#define CSS_PROP_SHORTHAND(name_, id_, method_, pref_) /* nothing */
 #define DEFINED_CSS_PROP_SHORTHAND
 #endif
 
 #define CSS_PROP_DOMPROP_PREFIXED(name_) \
   CSS_PROP_PUBLIC_OR_PRIVATE(Moz ## name_, name_)
 
 // Callers may define CSS_PROP_LIST_EXCLUDE_INTERNAL if they want to
 // exclude internal properties that are not represented in the DOM (only
 // the DOM style code defines this).  All properties defined in an
 // #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL section must have the
-// CSS_PROPERTY_INTERNAL flag set.
+// CSSPropFlags::Internal flag set.
 
 // Callers may also define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 // to exclude properties that are not considered to be components of the 'all'
 // shorthand property.  Currently this excludes 'direction' and 'unicode-bidi',
 // as required by the CSS Cascading and Inheritance specification, and any
 // internal properties that cannot be changed by using CSS syntax.  For example,
 // the internal '-moz-system-font' property is not excluded, as it is set by the
 // 'font' shorthand, while '-x-lang' is excluded as there is no way to set this
@@ -90,25 +88,25 @@
 
 // A caller who wants all the properties can define the |CSS_PROP|
 // macro.
 #ifdef CSS_PROP
 
 #define USED_CSS_PROP
 // We still need this extra level so that CSS_PROP_DOMPROP_PREFIXED has
 // a chance to be expanded.
-#define CSS_PROP_(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_)
+#define CSS_PROP_(name_, id_, method_, pref_, parsevariant_, kwtable_) CSS_PROP(name_, id_, method_, pref_, parsevariant_, kwtable_)
 
 #else /* !defined(CSS_PROP) */
 
 // An includer who does not define CSS_PROP can define any or all of the
 // per-struct macros that are equivalent to it, and the rest will be
 // ignored.
 
-#define CSS_PROP_(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_) /* nothing */
+#define CSS_PROP_(name_, id_, method_, pref_, parsevariant_, kwtable_) /* nothing */
 
 #endif /* !defined(CSS_PROP) */
 
 /*************************************************************************/
 
 // For notes XXX bug 3935 below, the names being parsed do not correspond
 // to the constants used internally.  It would be nice to bring the
 // constants into line sometime.
@@ -139,2990 +137,2600 @@
 
 // Please keep these sorted by property name, ignoring any "-moz-",
 // "-webkit-" or "-x-" prefix.
 
 CSS_PROP_(
     align-content,
     align_content,
     AlignContent,
-    0,
     "",
     VARIANT_HK,
     kAutoCompletionAlignJustifyContent)
 CSS_PROP_(
     align-items,
     align_items,
     AlignItems,
-    0,
     "",
     VARIANT_HK,
     kAutoCompletionAlignItems)
 CSS_PROP_(
     align-self,
     align_self,
     AlignSelf,
-    0,
     "",
     VARIANT_HK,
     kAutoCompletionAlignJustifySelf)
 CSS_PROP_SHORTHAND(
     all,
     all,
     All,
-    0,
     "layout.css.all-shorthand.enabled")
 CSS_PROP_SHORTHAND(
     animation,
     animation,
     Animation,
-    0,
     "")
 CSS_PROP_(
     animation-delay,
     animation_delay,
     AnimationDelay,
-    0,
     "",
     VARIANT_TIME, // used by list parsing
     nullptr)
 CSS_PROP_(
     animation-direction,
     animation_direction,
     AnimationDirection,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kAnimationDirectionKTable)
 CSS_PROP_(
     animation-duration,
     animation_duration,
     AnimationDuration,
-    0,
     "",
     VARIANT_TIME | VARIANT_NONNEGATIVE_DIMENSION, // used by list parsing
     nullptr)
 CSS_PROP_(
     animation-fill-mode,
     animation_fill_mode,
     AnimationFillMode,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kAnimationFillModeKTable)
 CSS_PROP_(
     animation-iteration-count,
     animation_iteration_count,
     AnimationIterationCount,
-    0,
     "",
     VARIANT_KEYWORD | VARIANT_NUMBER, // used by list parsing
     kAnimationIterationCountKTable)
 CSS_PROP_(
     animation-name,
     animation_name,
     AnimationName,
-    0,
     "",
     // FIXME: The spec should say something about 'inherit' and 'initial'
     // not being allowed.
     VARIANT_NONE | VARIANT_IDENTIFIER_NO_INHERIT | VARIANT_STRING, // used by list parsing
     nullptr)
 CSS_PROP_(
     animation-play-state,
     animation_play_state,
     AnimationPlayState,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kAnimationPlayStateKTable)
 CSS_PROP_(
     animation-timing-function,
     animation_timing_function,
     AnimationTimingFunction,
-    0,
     "",
     VARIANT_KEYWORD | VARIANT_TIMING_FUNCTION, // used by list parsing
     kTransitionTimingFunctionKTable)
 CSS_PROP_(
     -moz-appearance,
     _moz_appearance,
     CSS_PROP_DOMPROP_PREFIXED(Appearance),
-    0,
     "",
     VARIANT_HK,
     kAppearanceKTable)
 CSS_PROP_(
     backface-visibility,
     backface_visibility,
     BackfaceVisibility,
-    0,
     "",
     VARIANT_HK,
     kBackfaceVisibilityKTable)
 CSS_PROP_SHORTHAND(
     background,
     background,
     Background,
-    0,
     "")
 CSS_PROP_(
     background-attachment,
     background_attachment,
     BackgroundAttachment,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kImageLayerAttachmentKTable)
 CSS_PROP_(
     background-blend-mode,
     background_blend_mode,
     BackgroundBlendMode,
-    0,
     "layout.css.background-blend-mode.enabled",
     VARIANT_KEYWORD, // used by list parsing
     kBlendModeKTable)
 CSS_PROP_(
     background-clip,
     background_clip,
     BackgroundClip,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kBackgroundClipKTable)
 CSS_PROP_(
     background-color,
     background_color,
     BackgroundColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     background-image,
     background_image,
     BackgroundImage,
-    0,
     "",
     VARIANT_IMAGE, // used by list parsing
     nullptr)
 CSS_PROP_(
     background-origin,
     background_origin,
     BackgroundOrigin,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kBackgroundOriginKTable)
 CSS_PROP_SHORTHAND(
     background-position,
     background_position,
     BackgroundPosition,
-    0,
     "")
 CSS_PROP_(
     background-position-x,
     background_position_x,
     BackgroundPositionX,
-    0,
     "",
     0,
     kImageLayerPositionKTable)
 CSS_PROP_(
     background-position-y,
     background_position_y,
     BackgroundPositionY,
-    0,
     "",
     0,
     kImageLayerPositionKTable)
 CSS_PROP_(
     background-repeat,
     background_repeat,
     BackgroundRepeat,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kImageLayerRepeatKTable)
 CSS_PROP_(
     background-size,
     background_size,
     BackgroundSize,
-    0,
     "",
     0,
     kImageLayerSizeKTable)
 CSS_PROP_(
     -moz-binding,
     _moz_binding,
     CSS_PROP_DOMPROP_PREFIXED(Binding),
-    0,
     "",
     VARIANT_HUO,
     nullptr) // XXX bug 3935
 CSS_PROP_(
     block-size,
     block_size,
     BlockSize,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_SHORTHAND(
     border,
     border,
     Border,
-    0,
     "")
 CSS_PROP_SHORTHAND(
     border-block-end,
     border_block_end,
     BorderBlockEnd,
-    0,
     "")
 CSS_PROP_(
     border-block-end-color,
     border_block_end_color,
     BorderBlockEndColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-block-end-style,
     border_block_end_style,
     BorderBlockEndStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     border-block-end-width,
     border_block_end_width,
     BorderBlockEndWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_SHORTHAND(
     border-block-start,
     border_block_start,
     BorderBlockStart,
-    0,
     "")
 CSS_PROP_(
     border-block-start-color,
     border_block_start_color,
     BorderBlockStartColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-block-start-style,
     border_block_start_style,
     BorderBlockStartStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     border-block-start-width,
     border_block_start_width,
     BorderBlockStartWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_SHORTHAND(
     border-bottom,
     border_bottom,
     BorderBottom,
-    0,
     "")
 CSS_PROP_(
     border-bottom-color,
     border_bottom_color,
     BorderBottomColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-bottom-left-radius,
     border_bottom_left_radius,
     BorderBottomLeftRadius,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     border-bottom-right-radius,
     border_bottom_right_radius,
     BorderBottomRightRadius,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     border-bottom-style,
     border_bottom_style,
     BorderBottomStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)  // on/off will need reflow
 CSS_PROP_(
     border-bottom-width,
     border_bottom_width,
     BorderBottomWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_(
     border-collapse,
     border_collapse,
     BorderCollapse,
-    0,
     "",
     VARIANT_HK,
     kBorderCollapseKTable)
 CSS_PROP_SHORTHAND(
     border-color,
     border_color,
     BorderColor,
-    0,
     "")
 CSS_PROP_SHORTHAND(
     border-image,
     border_image,
     BorderImage,
-    0,
     "")
 CSS_PROP_(
     border-image-outset,
     border_image_outset,
     BorderImageOutset,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     border-image-repeat,
     border_image_repeat,
     BorderImageRepeat,
-    0,
     "",
     0,
     kBorderImageRepeatKTable)
 CSS_PROP_(
     border-image-slice,
     border_image_slice,
     BorderImageSlice,
-    0,
     "",
     0,
     kBorderImageSliceKTable)
 CSS_PROP_(
     border-image-source,
     border_image_source,
     BorderImageSource,
-    0,
     "",
     VARIANT_IMAGE | VARIANT_INHERIT,
     nullptr)
 CSS_PROP_(
     border-image-width,
     border_image_width,
     BorderImageWidth,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_SHORTHAND(
     border-inline-end,
     border_inline_end,
     BorderInlineEnd,
-    0,
     "")
 CSS_PROP_(
     border-inline-end-color,
     border_inline_end_color,
     BorderInlineEndColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-inline-end-style,
     border_inline_end_style,
     BorderInlineEndStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     border-inline-end-width,
     border_inline_end_width,
     BorderInlineEndWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_SHORTHAND(
     border-inline-start,
     border_inline_start,
     BorderInlineStart,
-    0,
     "")
 CSS_PROP_(
     border-inline-start-color,
     border_inline_start_color,
     BorderInlineStartColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-inline-start-style,
     border_inline_start_style,
     BorderInlineStartStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     border-inline-start-width,
     border_inline_start_width,
     BorderInlineStartWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_SHORTHAND(
     border-left,
     border_left,
     BorderLeft,
-    0,
     "")
 CSS_PROP_(
     border-left-color,
     border_left_color,
     BorderLeftColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-left-style,
     border_left_style,
     BorderLeftStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     border-left-width,
     border_left_width,
     BorderLeftWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_SHORTHAND(
     border-radius,
     border_radius,
     BorderRadius,
-    0,
     "")
 CSS_PROP_SHORTHAND(
     border-right,
     border_right,
     BorderRight,
-    0,
     "")
 CSS_PROP_(
     border-right-color,
     border_right_color,
     BorderRightColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-right-style,
     border_right_style,
     BorderRightStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     border-right-width,
     border_right_width,
     BorderRightWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_(
     border-spacing,
     border_spacing,
     BorderSpacing,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_SHORTHAND(
     border-style,
     border_style,
     BorderStyle,
-    0,
     "")  // on/off will need reflow
 CSS_PROP_SHORTHAND(
     border-top,
     border_top,
     BorderTop,
-    0,
     "")
 CSS_PROP_(
     border-top-color,
     border_top_color,
     BorderTopColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     border-top-left-radius,
     border_top_left_radius,
     BorderTopLeftRadius,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     border-top-right-radius,
     border_top_right_radius,
     BorderTopRightRadius,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     border-top-style,
     border_top_style,
     BorderTopStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)  // on/off will need reflow
 CSS_PROP_(
     border-top-width,
     border_top_width,
     BorderTopWidth,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_SHORTHAND(
     border-width,
     border_width,
     BorderWidth,
-    0,
     "")
 CSS_PROP_(
     bottom,
     bottom,
     Bottom,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     -moz-box-align,
     _moz_box_align,
     CSS_PROP_DOMPROP_PREFIXED(BoxAlign),
-    0,
     "",
     VARIANT_HK,
     kBoxAlignKTable) // XXX bug 3935
 CSS_PROP_(
     box-decoration-break,
     box_decoration_break,
     BoxDecorationBreak,
-    0,
     "layout.css.box-decoration-break.enabled",
     VARIANT_HK,
     kBoxDecorationBreakKTable)
 CSS_PROP_(
     -moz-box-direction,
     _moz_box_direction,
     CSS_PROP_DOMPROP_PREFIXED(BoxDirection),
-    0,
     "",
     VARIANT_HK,
     kBoxDirectionKTable) // XXX bug 3935
 CSS_PROP_(
     -moz-box-flex,
     _moz_box_flex,
     CSS_PROP_DOMPROP_PREFIXED(BoxFlex),
-    0,
     "",
     VARIANT_HN,
     nullptr) // XXX bug 3935
 CSS_PROP_(
     -moz-box-ordinal-group,
     _moz_box_ordinal_group,
     CSS_PROP_DOMPROP_PREFIXED(BoxOrdinalGroup),
-    0,
     "",
     VARIANT_HI,
     nullptr)
 CSS_PROP_(
     -moz-box-orient,
     _moz_box_orient,
     CSS_PROP_DOMPROP_PREFIXED(BoxOrient),
-    0,
     "",
     VARIANT_HK,
     kBoxOrientKTable) // XXX bug 3935
 CSS_PROP_(
     -moz-box-pack,
     _moz_box_pack,
     CSS_PROP_DOMPROP_PREFIXED(BoxPack),
-    0,
     "",
     VARIANT_HK,
     kBoxPackKTable) // XXX bug 3935
 CSS_PROP_(
     box-shadow,
     box_shadow,
     BoxShadow,
-    0,
         // NOTE: some components must be nonnegative
     "",
     VARIANT_COLOR | VARIANT_LENGTH | VARIANT_CALC | VARIANT_INHERIT | VARIANT_NONE,
     kBoxShadowTypeKTable)
 CSS_PROP_(
     box-sizing,
     box_sizing,
     BoxSizing,
-    0,
     "",
     VARIANT_HK,
     kBoxSizingKTable)
 CSS_PROP_(
     caption-side,
     caption_side,
     CaptionSide,
-    0,
     "",
     VARIANT_HK,
     kCaptionSideKTable)
 CSS_PROP_(
     caret-color,
     caret_color,
     CaretColor,
-    0,
     "",
     VARIANT_AUTO | VARIANT_HC,
     nullptr)
 CSS_PROP_(
     clear,
     clear,
     Clear,
-    0,
     "",
     VARIANT_HK,
     kClearKTable)
 CSS_PROP_(
     clip,
     clip,
     Clip,
-    0,
     "",
     VARIANT_AH,
     nullptr)
 CSS_PROP_(
     clip-path,
     clip_path,
     ClipPath,
-    0,
     "",
     VARIANT_HUO,
     nullptr)
 CSS_PROP_(
     clip-rule,
     clip_rule,
     ClipRule,
-    0,
     "",
     VARIANT_HK,
     kFillRuleKTable)
 CSS_PROP_(
     color,
     color,
     Color,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     color-adjust,
     color_adjust,
     ColorAdjust,
-    0,
     "layout.css.color-adjust.enabled",
     VARIANT_HK,
     kColorAdjustKTable)
 CSS_PROP_(
     color-interpolation,
     color_interpolation,
     ColorInterpolation,
-    0,
     "",
     VARIANT_HK,
     kColorInterpolationKTable)
 CSS_PROP_(
     color-interpolation-filters,
     color_interpolation_filters,
     ColorInterpolationFilters,
-    0,
     "",
     VARIANT_HK,
     kColorInterpolationKTable)
 CSS_PROP_(
     column-count,
     column_count,
     ColumnCount,
-    0,
     "",
     VARIANT_AHI,
     nullptr)
 CSS_PROP_(
     column-fill,
     column_fill,
     ColumnFill,
-    0,
     "",
     VARIANT_HK,
     kColumnFillKTable)
 CSS_PROP_(
     column-gap,
     column_gap,
     ColumnGap,
-    0,
     "",
     VARIANT_HLP | VARIANT_NORMAL | VARIANT_CALC,
     nullptr)
 CSS_PROP_SHORTHAND(
     column-rule,
     column_rule,
     ColumnRule,
-    0,
     "")
 CSS_PROP_(
     column-rule-color,
     column_rule_color,
     ColumnRuleColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     column-rule-style,
     column_rule_style,
     ColumnRuleStyle,
-    0,
     "",
     VARIANT_HK,
     kBorderStyleKTable)
 CSS_PROP_(
     column-rule-width,
     column_rule_width,
     ColumnRuleWidth,
-    0,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable)
 CSS_PROP_(
     column-span,
     column_span,
     ColumnSpan,
-    0,
     "layout.css.column-span.enabled",
     VARIANT_HK,
     kColumnSpanKTable)
 CSS_PROP_(
     column-width,
     column_width,
     ColumnWidth,
-    0,
     "",
     VARIANT_AHL | VARIANT_CALC,
     nullptr)
 CSS_PROP_SHORTHAND(
     columns,
     columns,
     Columns,
-    0,
     "")
 CSS_PROP_(
     contain,
     contain,
     Contain,
-    0,
     "layout.css.contain.enabled",
     // Does not affect parsing, but is needed for tab completion in devtools:
     VARIANT_HK | VARIANT_NONE,
     kContainKTable)
 CSS_PROP_(
     content,
     content,
     Content,
-    0,
     "",
     VARIANT_HMK | VARIANT_NONE | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR,
     kContentKTable)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     // Only intended to be used internally by Mozilla, so prefixed.
     -moz-context-properties,
     _moz_context_properties,
     CSS_PROP_DOMPROP_PREFIXED(ContextProperties),
-    CSS_PROPERTY_INTERNAL,
     "",
     0,
     nullptr)
 CSS_PROP_(
     -moz-control-character-visibility,
     _moz_control_character_visibility,
     CSS_PROP_DOMPROP_PREFIXED(ControlCharacterVisibility),
-    CSS_PROPERTY_INTERNAL,
     "",
     VARIANT_HK,
     kControlCharacterVisibilityKTable)
 #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     counter-increment,
     counter_increment,
     CounterIncrement,
-    0,
     "",
     VARIANT_INHERIT | VARIANT_NONE,
     nullptr) // XXX bug 137285
 CSS_PROP_(
     counter-reset,
     counter_reset,
     CounterReset,
-    0,
     "",
     VARIANT_INHERIT | VARIANT_NONE,
     nullptr) // XXX bug 137285
 CSS_PROP_(
     cursor,
     cursor,
     Cursor,
-    0,
     "",
     0,
     kCursorKTable)
 #ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 CSS_PROP_(
     direction,
     direction,
     Direction,
-    0,
     "",
     VARIANT_HK,
     kDirectionKTable)
 #endif // !defined(CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND)
 CSS_PROP_(
     display,
     display,
     Display,
-    0,
     "",
     VARIANT_HK,
     kDisplayKTable)
 CSS_PROP_(
     dominant-baseline,
     dominant_baseline,
     DominantBaseline,
-    0,
     "",
     VARIANT_HK,
     kDominantBaselineKTable)
 CSS_PROP_(
     empty-cells,
     empty_cells,
     EmptyCells,
-    0,
     "",
     VARIANT_HK,
     kEmptyCellsKTable)
 CSS_PROP_(
     fill,
     fill,
     Fill,
-    0,
     "",
     0,
     kContextPatternKTable)
 CSS_PROP_(
     fill-opacity,
     fill_opacity,
     FillOpacity,
-    0,
     "",
     VARIANT_HN | VARIANT_KEYWORD,
     kContextOpacityKTable)
 CSS_PROP_(
     fill-rule,
     fill_rule,
     FillRule,
-    0,
     "",
     VARIANT_HK,
     kFillRuleKTable)
 CSS_PROP_(
     filter,
     filter,
     Filter,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_SHORTHAND(
     flex,
     flex,
     Flex,
-    0,
     "")
 CSS_PROP_(
     flex-basis,
     flex_basis,
     FlexBasis,
-    0,
     "",
     // NOTE: The parsing implementation for the 'flex' shorthand property has
     // its own code to parse each subproperty. It does not depend on the
     // longhand parsing defined here.
     VARIANT_AHKLP | VARIANT_CALC,
     kFlexBasisKTable)
 CSS_PROP_(
     flex-direction,
     flex_direction,
     FlexDirection,
-    0,
     "",
     VARIANT_HK,
     kFlexDirectionKTable)
 CSS_PROP_SHORTHAND(
     flex-flow,
     flex_flow,
     FlexFlow,
-    0,
     "")
 CSS_PROP_(
     flex-grow,
     flex_grow,
     FlexGrow,
-    0,
     "",
     // NOTE: The parsing implementation for the 'flex' shorthand property has
     // its own code to parse each subproperty. It does not depend on the
     // longhand parsing defined here.
     VARIANT_HN,
     nullptr)
 CSS_PROP_(
     flex-shrink,
     flex_shrink,
     FlexShrink,
-    0,
     "",
     // NOTE: The parsing implementation for the 'flex' shorthand property has
     // its own code to parse each subproperty. It does not depend on the
     // longhand parsing defined here.
     VARIANT_HN,
     nullptr)
 CSS_PROP_(
     flex-wrap,
     flex_wrap,
     FlexWrap,
-    0,
     "",
     VARIANT_HK,
     kFlexWrapKTable)
 CSS_PROP_(
     float,
     float,
     CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float),
-    0,
     "",
     VARIANT_HK,
     kFloatKTable)
 CSS_PROP_(
     -moz-float-edge,
     _moz_float_edge,
     CSS_PROP_DOMPROP_PREFIXED(FloatEdge),
-    0,
     "",
     VARIANT_HK,
     kFloatEdgeKTable) // XXX bug 3935
 CSS_PROP_(
     flood-color,
     flood_color,
     FloodColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     flood-opacity,
     flood_opacity,
     FloodOpacity,
-    0,
     "",
     VARIANT_HN,
     nullptr)
 CSS_PROP_SHORTHAND(
     font,
     font,
     Font,
-    0,
     "")
 CSS_PROP_(
     font-family,
     font_family,
     FontFamily,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     font-feature-settings,
     font_feature_settings,
     FontFeatureSettings,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     font-kerning,
     font_kerning,
     FontKerning,
-    0,
     "",
     VARIANT_HK,
     kFontKerningKTable)
 CSS_PROP_(
     font-language-override,
     font_language_override,
     FontLanguageOverride,
-    0,
     "",
     VARIANT_NORMAL | VARIANT_INHERIT | VARIANT_STRING,
     nullptr)
 CSS_PROP_(
     font-optical-sizing,
     font_optical_sizing,
     FontOpticalSizing,
-    0,
     "layout.css.font-variations.enabled",
     VARIANT_HK,
     kFontOpticalSizingKTable)
 CSS_PROP_(
     font-size,
     font_size,
     FontSize,
-    0,
     "",
     VARIANT_HKLP | VARIANT_SYSFONT | VARIANT_CALC,
     kFontSizeKTable)
 CSS_PROP_(
     font-size-adjust,
     font_size_adjust,
     FontSizeAdjust,
-    0,
     "",
     VARIANT_HON | VARIANT_SYSFONT,
     nullptr)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     -moz-font-smoothing-background-color,
     _moz_font_smoothing_background_color,
     CSS_PROP_DOMPROP_PREFIXED(FontSmoothingBackgroundColor),
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_ENABLED_IN_UA_SHEETS_AND_CHROME,
     "",
     VARIANT_HC,
     nullptr)
 #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     font-stretch,
     font_stretch,
     FontStretch,
-    0,
     "",
     VARIANT_HK | VARIANT_SYSFONT | VARIANT_PERCENT,
     kFontStretchKTable)
 CSS_PROP_(
     font-style,
     font_style,
     FontStyle,
-    0,
     "",
     VARIANT_HK | VARIANT_SYSFONT,
     kFontStyleKTable)
 CSS_PROP_(
     font-synthesis,
     font_synthesis,
     FontSynthesis,
-    0,
     "",
     0,
     kFontSynthesisKTable)
 CSS_PROP_SHORTHAND(
     font-variant,
     font_variant,
     FontVariant,
-    0,
     "")
 CSS_PROP_(
     font-variant-alternates,
     font_variant_alternates,
     FontVariantAlternates,
-    0,
     "",
     0,
     kFontVariantAlternatesKTable)
 CSS_PROP_(
     font-variant-caps,
     font_variant_caps,
     FontVariantCaps,
-    0,
     "",
     VARIANT_HMK,
     kFontVariantCapsKTable)
 CSS_PROP_(
     font-variant-east-asian,
     font_variant_east_asian,
     FontVariantEastAsian,
-    0,
     "",
     0,
     kFontVariantEastAsianKTable)
 CSS_PROP_(
     font-variant-ligatures,
     font_variant_ligatures,
     FontVariantLigatures,
-    0,
     "",
     0,
     kFontVariantLigaturesKTable)
 CSS_PROP_(
     font-variant-numeric,
     font_variant_numeric,
     FontVariantNumeric,
-    0,
     "",
     0,
     kFontVariantNumericKTable)
 CSS_PROP_(
     font-variant-position,
     font_variant_position,
     FontVariantPosition,
-    0,
     "",
     VARIANT_HMK,
     kFontVariantPositionKTable)
 CSS_PROP_(
     font-variation-settings,
     font_variation_settings,
     FontVariationSettings,
-    0,
     "layout.css.font-variations.enabled",
     0,
     nullptr)
 CSS_PROP_(
     font-weight,
     font_weight,
     FontWeight,
-    0,
         // NOTE: This property has range restrictions on interpolation!
     "",
     0,
     kFontWeightKTable)
 CSS_PROP_(
     -moz-force-broken-image-icon,
     _moz_force_broken_image_icon,
     CSS_PROP_DOMPROP_PREFIXED(ForceBrokenImageIcon),
-    0,
     "",
     VARIANT_HI,
     nullptr) // bug 58646
 CSS_PROP_SHORTHAND(
     gap,
     gap,
     Gap,
-    0,
     "")
 CSS_PROP_SHORTHAND(
     grid,
     grid,
     Grid,
-    0,
     "")
 CSS_PROP_SHORTHAND(
     grid-area,
     grid_area,
     GridArea,
-    0,
     "")
 CSS_PROP_(
     grid-auto-columns,
     grid_auto_columns,
     GridAutoColumns,
-    0,
     "",
     0,
     kGridTrackBreadthKTable)
 CSS_PROP_(
     grid-auto-flow,
     grid_auto_flow,
     GridAutoFlow,
-    0,
     "",
     0,
     kGridAutoFlowKTable)
 CSS_PROP_(
     grid-auto-rows,
     grid_auto_rows,
     GridAutoRows,
-    0,
     "",
     0,
     kGridTrackBreadthKTable)
 CSS_PROP_SHORTHAND(
     grid-column,
     grid_column,
     GridColumn,
-    0,
     "")
 CSS_PROP_(
     grid-column-end,
     grid_column_end,
     GridColumnEnd,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     grid-column-start,
     grid_column_start,
     GridColumnStart,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_SHORTHAND(
     grid-row,
     grid_row,
     GridRow,
-    0,
     "")
 CSS_PROP_(
     grid-row-end,
     grid_row_end,
     GridRowEnd,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     grid-row-start,
     grid_row_start,
     GridRowStart,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_SHORTHAND(
     grid-template,
     grid_template,
     GridTemplate,
-    0,
     "")
 CSS_PROP_(
     grid-template-areas,
     grid_template_areas,
     GridTemplateAreas,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     grid-template-columns,
     grid_template_columns,
     GridTemplateColumns,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     0,
     kGridTrackBreadthKTable)
 CSS_PROP_(
     grid-template-rows,
     grid_template_rows,
     GridTemplateRows,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     0,
     kGridTrackBreadthKTable)
 CSS_PROP_(
     height,
     height,
     Height,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     hyphens,
     hyphens,
     Hyphens,
-    0,
     "",
     VARIANT_HK,
     kHyphensKTable)
 CSS_PROP_(
     image-orientation,
     image_orientation,
     ImageOrientation,
-    0,
     "layout.css.image-orientation.enabled",
     0,
     kImageOrientationKTable)
 CSS_PROP_(
     -moz-image-region,
     _moz_image_region,
     CSS_PROP_DOMPROP_PREFIXED(ImageRegion),
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_(
     image-rendering,
     image_rendering,
     ImageRendering,
-    0,
     "",
     VARIANT_HK,
     kImageRenderingKTable)
 CSS_PROP_(
     ime-mode,
     ime_mode,
     ImeMode,
-    0,
     "",
     VARIANT_HK,
     kIMEModeKTable)
 CSS_PROP_(
     initial-letter,
     initial_letter,
     InitialLetter,
-    0,
     "layout.css.initial-letter.enabled",
     0,
     nullptr)
 CSS_PROP_(
     inline-size,
     inline_size,
     InlineSize,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     isolation,
     isolation,
     Isolation,
-    0,
     "layout.css.isolation.enabled",
     VARIANT_HK,
     kIsolationKTable)
 CSS_PROP_(
     justify-content,
     justify_content,
     JustifyContent,
-    0,
     "",
     VARIANT_HK,
     kAutoCompletionAlignJustifyContent)
 CSS_PROP_(
     justify-items,
     justify_items,
     JustifyItems,
-    0,
     "",
     VARIANT_HK,
     // for auto-completion we use same values as justify-self:
     kAutoCompletionAlignJustifySelf)
 CSS_PROP_(
     justify-self,
     justify_self,
     JustifySelf,
-    0,
     "",
     VARIANT_HK,
     kAutoCompletionAlignJustifySelf)
 #ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     -x-lang,
     _x_lang,
     Lang,
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     0,
     nullptr)
 #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 #endif // CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 CSS_PROP_(
     left,
     left,
     Left,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     letter-spacing,
     letter_spacing,
     LetterSpacing,
-    0,
     "",
     VARIANT_HL | VARIANT_NORMAL | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     lighting-color,
     lighting_color,
     LightingColor,
-    0,
     "",
     VARIANT_HC,
     nullptr)
 CSS_PROP_(
     line-height,
     line_height,
     LineHeight,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLPN | VARIANT_KEYWORD | VARIANT_NORMAL | VARIANT_SYSFONT | VARIANT_CALC,
     kLineHeightKTable)
 CSS_PROP_SHORTHAND(
     list-style,
     list_style,
     ListStyle,
-    0,
     "")
 CSS_PROP_(
     list-style-image,
     list_style_image,
     ListStyleImage,
-    0,
     "",
     VARIANT_HUO,
     nullptr)
 CSS_PROP_(
     list-style-position,
     list_style_position,
     ListStylePosition,
-    0,
     "",
     VARIANT_HK,
     kListStylePositionKTable)
 CSS_PROP_(
     list-style-type,
     list_style_type,
     ListStyleType,
-    0,
     "",
     0,
     nullptr)
 CSS_PROP_SHORTHAND(
     margin,
     margin,
     Margin,
-    0,
     "")
 CSS_PROP_(
     margin-block-end,
     margin_block_end,
     MarginBlockEnd,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-block-start,
     margin_block_start,
     MarginBlockStart,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-bottom,
     margin_bottom,
     MarginBottom,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-inline-end,
     margin_inline_end,
     MarginInlineEnd,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-inline-start,
     margin_inline_start,
     MarginInlineStart,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-left,
     margin_left,
     MarginLeft,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-right,
     margin_right,
     MarginRight,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     margin-top,
     margin_top,
     MarginTop,
-    CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 CSS_PROP_SHORTHAND(
     marker,
     marker,
     Marker,
-    0,
     "")
 CSS_PROP_(
     marker-end,
     marker_end,
     MarkerEnd,
-    0,
     "",
     VARIANT_HUO,
     nullptr)
 CSS_PROP_(
     marker-mid,
     marker_mid,
     MarkerMid,
-    0,
     "",
     VARIANT_HUO,
     nullptr)
 CSS_PROP_(
     marker-start,
     marker_start,
     MarkerStart,
-    0,
     "",
     VARIANT_HUO,
     nullptr)
 CSS_PROP_SHORTHAND(
     mask,
     mask,
     Mask,
-    0,
     "")
 CSS_PROP_(
     mask-clip,
     mask_clip,
     MaskClip,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kMaskClipKTable)
 CSS_PROP_(
     mask-composite,
     mask_composite,
     MaskComposite,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kImageLayerCompositeKTable)
 CSS_PROP_(
     mask-image,
     mask_image,
     MaskImage,
-    0,
     "",
     VARIANT_IMAGE, // used by list parsing
     nullptr)
 CSS_PROP_(
     mask-mode,
     mask_mode,
     MaskMode,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kImageLayerModeKTable)
 CSS_PROP_(
     mask-origin,
     mask_origin,
     MaskOrigin,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kMaskOriginKTable)
 CSS_PROP_SHORTHAND(
     mask-position,
     mask_position,
     MaskPosition,
-    0,
     "")
 CSS_PROP_(
     mask-position-x,
     mask_position_x,
     MaskPositionX,
-    0,
     "",
     0,
     kImageLayerPositionKTable)
 CSS_PROP_(
     mask-position-y,
     mask_position_y,
     MaskPositionY,
-    0,
     "",
     0,
     kImageLayerPositionKTable)
 CSS_PROP_(
     mask-repeat,
     mask_repeat,
     MaskRepeat,
-    0,
     "",
     VARIANT_KEYWORD, // used by list parsing
     kImageLayerRepeatKTable)
 CSS_PROP_(
     mask-size,
     mask_size,
     MaskSize,
-    0,
     "",
     0,
     kImageLayerSizeKTable)
 CSS_PROP_(
     mask-type,
     mask_type,
     MaskType,
-    0,
     "",
     VARIANT_HK,
     kMaskTypeKTable)
 #ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     -moz-math-display,
     _moz_math_display,
     MathDisplay,
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "",
     VARIANT_HK,
     kMathDisplayKTable)
 CSS_PROP_(
     -moz-math-variant,
     _moz_math_variant,
     MathVariant,
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     VARIANT_HK,
     kMathVariantKTable)
 #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 #endif // CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 CSS_PROP_(
     max-block-size,
     max_block_size,
     MaxBlockSize,
-    0,
     "",
     VARIANT_HLPO | VARIANT_CALC,
     nullptr)
 CSS_PROP_(
     max-height,
     max_height,
     MaxHeight,
-    0,
     "",
     VARIANT_HKLPO | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     max-inline-size,
     max_inline_size,
     MaxInlineSize,
-    0,
     "",
     VARIANT_HKLPO | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     max-width,
     max_width,
     MaxWidth,
-    0,
     "",
     VARIANT_HKLPO | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     min-block-size,
     min_block_size,
     MinBlockSize,
-    0,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     -moz-min-font-size-ratio,
     _moz_min_font_size_ratio,
     CSS_PROP_DOMPROP_PREFIXED(MinFontSizeRatio),
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "",
     VARIANT_INHERIT | VARIANT_PERCENT,
     nullptr)
 #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     min-height,
     min_height,
     MinHeight,
-    0,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     min-inline-size,
     min_inline_size,
     MinInlineSize,
-    0,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     min-width,
     min_width,
     MinWidth,
-    0,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable)
 CSS_PROP_(
     mix-blend-mode,
     mix_blend_mode,
     MixBlendMode,
-    0,
     "layout.css.mix-blend-mode.enabled",