Bug 1423167: Move most attribute-related methods from nsIContent to Element. r?bz draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 05 Dec 2017 18:05:51 +0100
changeset 708163 848a04166ba3fae8ac5c135dc40b312a012a7a35
parent 708151 c0cb4801c3771403e592454d983ab3a39ca98e45
child 743106 3a0f3761792bf4a712b3852cc1daaa6607a2619c
push id92295
push userbmo:emilio@crisal.io
push dateWed, 06 Dec 2017 08:36:08 +0000
reviewersbz
bugs1423167
milestone59.0a1
Bug 1423167: Move most attribute-related methods from nsIContent to Element. r?bz MozReview-Commit-ID: 6WXqNiODttD
accessible/base/ARIAMap.cpp
accessible/base/ARIAMap.h
accessible/base/nsAccessibilityService.cpp
accessible/generic/ARIAGridAccessible.cpp
accessible/generic/Accessible.cpp
accessible/html/HTMLSelectAccessible.cpp
accessible/xul/XULSliderAccessible.cpp
accessible/xul/XULSliderAccessible.h
dom/base/DocumentFragment.h
dom/base/Element.h
dom/base/FragmentOrElement.cpp
dom/base/FragmentOrElement.h
dom/base/nsContentCreatorFunctions.h
dom/base/nsContentUtils.cpp
dom/base/nsDocument.cpp
dom/base/nsGenericDOMDataNode.cpp
dom/base/nsGenericDOMDataNode.h
dom/base/nsHTMLContentSerializer.cpp
dom/base/nsHTMLContentSerializer.h
dom/base/nsIContent.h
dom/base/nsINode.cpp
dom/base/nsIdentifierMapEntry.h
dom/base/nsMappedAttributeElement.h
dom/base/nsObjectLoadingContent.cpp
dom/base/nsTreeSanitizer.cpp
dom/base/nsTreeSanitizer.h
dom/base/nsXHTMLContentSerializer.cpp
dom/base/nsXHTMLContentSerializer.h
dom/base/nsXMLContentSerializer.cpp
dom/base/nsXMLContentSerializer.h
dom/svg/SVGAElement.h
dom/svg/SVGStyleElement.h
dom/xbl/nsXBLBinding.cpp
dom/xbl/nsXBLBinding.h
dom/xbl/nsXBLContentSink.cpp
dom/xbl/nsXBLContentSink.h
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xbl/nsXBLPrototypeBinding.h
dom/xbl/nsXBLService.cpp
dom/xbl/nsXBLService.h
dom/xml/nsXMLContentSink.cpp
dom/xml/nsXMLContentSink.h
dom/xml/nsXMLPrettyPrinter.cpp
dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
dom/xslt/xslt/txMozillaTextOutput.cpp
dom/xslt/xslt/txMozillaTextOutput.h
dom/xslt/xslt/txMozillaXMLOutput.cpp
dom/xslt/xslt/txMozillaXMLOutput.h
dom/xul/XULDocument.cpp
dom/xul/XULDocument.h
dom/xul/nsIXULDocument.h
dom/xul/nsXULElement.cpp
dom/xul/nsXULElement.h
dom/xul/templates/nsIXULTemplateBuilder.idl
dom/xul/templates/nsXULContentBuilder.cpp
dom/xul/templates/nsXULContentUtils.cpp
dom/xul/templates/nsXULContentUtils.h
dom/xul/templates/nsXULSortService.cpp
dom/xul/templates/nsXULSortService.h
dom/xul/templates/nsXULTemplateBuilder.cpp
dom/xul/templates/nsXULTemplateBuilder.h
dom/xul/templates/nsXULTemplateQueryProcessorRDF.cpp
dom/xul/templates/nsXULTemplateQueryProcessorRDF.h
dom/xul/templates/nsXULTreeBuilder.cpp
dom/xul/templates/nsXULTreeBuilder.h
editor/libeditor/EditorBase.cpp
editor/libeditor/HTMLEditor.h
editor/libeditor/HTMLStyleEditor.cpp
editor/libeditor/TextEditRules.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/forms/nsButtonFrameRenderer.cpp
layout/forms/nsComboboxControlFrame.h
layout/forms/nsDateTimeControlFrame.h
layout/forms/nsFileControlFrame.h
layout/forms/nsHTMLButtonControlFrame.cpp
layout/generic/ScrollbarActivity.cpp
layout/generic/ScrollbarActivity.h
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsVideoFrame.cpp
layout/generic/nsVideoFrame.h
layout/mathml/nsMathMLmactionFrame.cpp
layout/xul/PopupBoxObject.cpp
layout/xul/nsDeckFrame.cpp
layout/xul/nsIRootBox.h
layout/xul/nsMenuFrame.cpp
layout/xul/nsMenuPopupFrame.cpp
layout/xul/nsProgressMeterFrame.cpp
layout/xul/nsResizerFrame.cpp
layout/xul/nsRootBoxFrame.cpp
layout/xul/nsScrollbarButtonFrame.cpp
layout/xul/nsScrollbarFrame.cpp
layout/xul/nsSliderFrame.cpp
layout/xul/nsSplitterFrame.cpp
layout/xul/nsXULPopupManager.cpp
layout/xul/nsXULPopupManager.h
layout/xul/nsXULTooltipListener.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
layout/xul/tree/nsTreeBodyFrame.h
layout/xul/tree/nsTreeColumns.cpp
layout/xul/tree/nsTreeContentView.cpp
layout/xul/tree/nsTreeContentView.h
layout/xul/tree/nsTreeUtils.cpp
layout/xul/tree/nsTreeUtils.h
parser/html/nsHtml5TreeOperation.cpp
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -1381,40 +1381,40 @@ aria::HasDefinedARIAHidden(nsIContent* a
 
 ////////////////////////////////////////////////////////////////////////////////
 // AttrIterator class
 
 bool
 AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
 {
   while (mAttrIdx < mAttrCount) {
-    const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx);
+    const nsAttrName* attr = mElement->GetAttrNameAt(mAttrIdx);
     mAttrIdx++;
     if (attr->NamespaceEquals(kNameSpaceID_None)) {
       nsAtom* attrAtom = attr->Atom();
       nsDependentAtomString attrStr(attrAtom);
       if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
         continue; // Not ARIA
 
       uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
       if (attrFlags & ATTR_BYPASSOBJ)
         continue; // No need to handle exposing as obj attribute here
 
       if ((attrFlags & ATTR_VALTOKEN) &&
-           !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
+           !nsAccUtils::HasDefinedARIAToken(mElement, attrAtom))
         continue; // only expose token based attributes if they are defined
 
       if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) &&
-          mContent->AttrValueIs(kNameSpaceID_None, attrAtom,
+          mElement->AttrValueIs(kNameSpaceID_None, attrAtom,
                                 nsGkAtoms::_false, eCaseMatters)) {
         continue; // only expose token based attribute if value is not 'false'.
       }
 
       nsAutoString value;
-      if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
+      if (mElement->GetAttr(kNameSpaceID_None, attrAtom, value)) {
         aAttrName.Assign(Substring(attrStr, 5));
         aAttrValue.Assign(value);
         return true;
       }
     }
   }
 
   return false;
--- a/accessible/base/ARIAMap.h
+++ b/accessible/base/ARIAMap.h
@@ -9,16 +9,17 @@
 #define mozilla_a11y_aria_ARIAMap_h_
 
 #include "ARIAStateMap.h"
 #include "mozilla/a11y/AccTypes.h"
 #include "mozilla/a11y/Role.h"
 
 #include "nsAtom.h"
 #include "nsIContent.h"
+#include "mozilla/dom/Element.h"
 
 class nsINode;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Value constants
 
 /**
  * Used to define if role requires to expose Value interface.
@@ -283,30 +284,31 @@ bool HasDefinedARIAHidden(nsIContent* aC
 
  /**
   * Represents a simple enumerator for iterating through ARIA attributes
   * exposed as object attributes on a given accessible.
   */
 class AttrIterator
 {
 public:
-  explicit AttrIterator(nsIContent* aContent) :
-    mContent(aContent), mAttrIdx(0)
+  explicit AttrIterator(nsIContent* aContent)
+    : mElement(aContent->IsElement() ? aContent->AsElement() : nullptr)
+    , mAttrIdx(0)
   {
-    mAttrCount = mContent->GetAttrCount();
+    mAttrCount = mElement ? mElement->GetAttrCount() : 0;
   }
 
   bool Next(nsAString& aAttrName, nsAString& aAttrValue);
 
 private:
   AttrIterator() = delete;
   AttrIterator(const AttrIterator&) = delete;
   AttrIterator& operator= (const AttrIterator&) = delete;
 
-  nsIContent* mContent;
+  dom::Element* mElement;
   uint32_t mAttrIdx;
   uint32_t mAttrCount;
 };
 
 } // namespace aria
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -109,30 +109,32 @@ using namespace mozilla::dom;
  * Return true if the element must be accessible.
  */
 static bool
 MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
 {
   if (aContent->GetPrimaryFrame()->IsFocusable())
     return true;
 
-  uint32_t attrCount = aContent->GetAttrCount();
-  for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) {
-    const nsAttrName* attr = aContent->GetAttrNameAt(attrIdx);
-    if (attr->NamespaceEquals(kNameSpaceID_None)) {
-      nsAtom* attrAtom = attr->Atom();
-      nsDependentAtomString attrStr(attrAtom);
-      if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
-        continue; // not ARIA
+  if (aContent->IsElement()) {
+    uint32_t attrCount = aContent->AsElement()->GetAttrCount();
+    for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) {
+      const nsAttrName* attr = aContent->AsElement()->GetAttrNameAt(attrIdx);
+      if (attr->NamespaceEquals(kNameSpaceID_None)) {
+        nsAtom* attrAtom = attr->Atom();
+        nsDependentAtomString attrStr(attrAtom);
+        if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
+          continue; // not ARIA
 
-      // A global state or a property and in case of token defined.
-      uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
-      if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) ||
-           nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) {
-        return true;
+        // A global state or a property and in case of token defined.
+        uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
+        if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) ||
+             nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) {
+          return true;
+        }
       }
     }
   }
 
   // If the given ID is referred by relation attribute then create an accessible
   // for it.
   nsAutoString id;
   if (nsCoreUtils::GetID(aContent, id) && !id.IsEmpty())
--- a/accessible/generic/ARIAGridAccessible.cpp
+++ b/accessible/generic/ARIAGridAccessible.cpp
@@ -460,26 +460,28 @@ ARIAGridAccessible::GetCellInRowAt(Acces
 
 nsresult
 ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
                                     bool aIsSelected, bool aNotify)
 {
   if (IsARIARole(nsGkAtoms::table))
     return NS_OK;
 
-  nsIContent *content = aAccessible->GetContent();
+  nsIContent* content = aAccessible->GetContent();
   NS_ENSURE_STATE(content);
 
   nsresult rv = NS_OK;
-  if (aIsSelected)
-    rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
-                          NS_LITERAL_STRING("true"), aNotify);
-  else
-    rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
-                          NS_LITERAL_STRING("false"), aNotify);
+  if (content->IsElement()) {
+    if (aIsSelected)
+      rv = content->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
+                                         NS_LITERAL_STRING("true"), aNotify);
+    else
+      rv = content->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
+                                         NS_LITERAL_STRING("false"), aNotify);
+  }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // No "smart" select/unselect for internal call.
   if (!aNotify)
     return NS_OK;
 
   // If row or cell accessible was selected then we're able to not bother about
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -699,22 +699,24 @@ void
 Accessible::SetSelected(bool aSelect)
 {
   if (!HasOwnContent())
     return;
 
   Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
   if (select) {
     if (select->State() & states::MULTISELECTABLE) {
-      if (ARIARoleMap()) {
+      if (mContent->IsElement() && ARIARoleMap()) {
         if (aSelect) {
-          mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
-                            NS_LITERAL_STRING("true"), true);
+          mContent->AsElement()->SetAttr(kNameSpaceID_None,
+                                         nsGkAtoms::aria_selected,
+                                         NS_LITERAL_STRING("true"), true);
         } else {
-          mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, true);
+          mContent->AsElement()->UnsetAttr(kNameSpaceID_None,
+                                           nsGkAtoms::aria_selected, true);
         }
       }
       return;
     }
 
     if (aSelect)
       TakeFocus();
   }
@@ -1411,18 +1413,22 @@ Accessible::SetCurValue(double aValue)
 
   checkValue = MaxValue();
   if (!IsNaN(checkValue) && aValue > checkValue)
     return false;
 
   nsAutoString strValue;
   strValue.AppendFloat(aValue);
 
+  if (!mContent->IsElement())
+    return true;
+
   return NS_SUCCEEDED(
-    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true));
+    mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
+                                   strValue, true));
 }
 
 role
 Accessible::ARIATransformRole(role aRole)
 {
   // Beginning with ARIA 1.1, user agents are expected to use the native host
   // language role of the element when the region role is used without a name.
   // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-region
@@ -2565,18 +2571,20 @@ Accessible::CurrentItem()
 
 void
 Accessible::SetCurrentItem(Accessible* aItem)
 {
   nsAtom* id = aItem->GetContent()->GetID();
   if (id) {
     nsAutoString idStr;
     id->ToString(idStr);
-    mContent->SetAttr(kNameSpaceID_None,
-                      nsGkAtoms::aria_activedescendant, idStr, true);
+    mContent->AsElement()->SetAttr(kNameSpaceID_None,
+                                   nsGkAtoms::aria_activedescendant,
+                                   idStr,
+                                   true);
   }
 }
 
 Accessible*
 Accessible::ContainerWidget() const
 {
   if (HasARIARole() && mContent->HasID()) {
     for (Accessible* parent = Parent(); parent; parent = parent->Parent()) {
--- a/accessible/html/HTMLSelectAccessible.cpp
+++ b/accessible/html/HTMLSelectAccessible.cpp
@@ -105,19 +105,23 @@ HTMLSelectListAccessible::CurrentItem()
     }
   }
   return nullptr;
 }
 
 void
 HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem)
 {
-  aItem->GetContent()->SetAttr(kNameSpaceID_None,
-                               nsGkAtoms::selected, NS_LITERAL_STRING("true"),
-                               true);
+  if (!aItem->GetContent()->IsElement())
+    return;
+
+  aItem->GetContent()->AsElement()->SetAttr(kNameSpaceID_None,
+                                            nsGkAtoms::selected,
+                                            NS_LITERAL_STRING("true"),
+                                            true);
 }
 
 bool
 HTMLSelectListAccessible::IsAcceptableChild(nsIContent* aEl) const
 {
   return aEl->IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::optgroup);
 }
 
--- a/accessible/xul/XULSliderAccessible.cpp
+++ b/accessible/xul/XULSliderAccessible.cpp
@@ -8,17 +8,18 @@
 #include "nsAccessibilityService.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsIFrame.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/FloatingPoint.h"
 
-using namespace mozilla::a11y;
+namespace mozilla {
+namespace a11y {
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULSliderAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULSliderAccessible::
   XULSliderAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
@@ -35,17 +36,17 @@ XULSliderAccessible::NativeRole()
 }
 
 uint64_t
 XULSliderAccessible::NativeInteractiveState() const
  {
   if (NativelyUnavailable())
     return states::UNAVAILABLE;
 
-  nsIContent* sliderElm = GetSliderElement();
+  dom::Element* sliderElm = GetSliderElement();
   if (sliderElm) {
     nsIFrame* frame = sliderElm->GetPrimaryFrame();
     if (frame && frame->IsFocusable())
       return states::FOCUSABLE;
   }
 
   return 0;
 }
@@ -78,17 +79,17 @@ XULSliderAccessible::ActionNameAt(uint8_
 }
 
 bool
 XULSliderAccessible::DoAction(uint8_t aIndex)
 {
   if (aIndex != 0)
     return false;
 
-  nsIContent* sliderElm = GetSliderElement();
+  dom::Element* sliderElm = GetSliderElement();
   if (sliderElm)
     DoCommand(sliderElm);
 
   return true;
 }
 
 double
 XULSliderAccessible::MaxValue() const
@@ -124,27 +125,27 @@ XULSliderAccessible::SetCurValue(double 
   if (AccessibleWrap::SetCurValue(aValue))
     return true;
 
   return SetSliderAttr(nsGkAtoms::curpos, aValue);
 }
 
 // Utils
 
-nsIContent*
+dom::Element*
 XULSliderAccessible::GetSliderElement() const
 {
-  if (!mSliderNode) {
+  if (!mSliderElement) {
     // XXX: we depend on anonymous content.
-    mSliderNode = mContent->OwnerDoc()->
+    mSliderElement = mContent->OwnerDoc()->
       GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid,
                                      NS_LITERAL_STRING("slider"));
   }
 
-  return mSliderNode;
+  return mSliderElement;
 }
 
 nsresult
 XULSliderAccessible::GetSliderAttr(nsAtom* aName, nsAString& aValue) const
 {
   aValue.Truncate();
 
   if (IsDefunct())
@@ -158,18 +159,17 @@ XULSliderAccessible::GetSliderAttr(nsAto
 }
 
 nsresult
 XULSliderAccessible::SetSliderAttr(nsAtom* aName, const nsAString& aValue)
 {
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  nsIContent* sliderElm = GetSliderElement();
-  if (sliderElm)
+  if (dom::Element* sliderElm = GetSliderElement())
     sliderElm->SetAttr(kNameSpaceID_None, aName, aValue, true);
 
   return NS_OK;
 }
 
 double
 XULSliderAccessible::GetSliderAttr(nsAtom* aName) const
 {
@@ -207,8 +207,10 @@ XULThumbAccessible::
 // XULThumbAccessible: Accessible
 
 role
 XULThumbAccessible::NativeRole()
 {
   return roles::INDICATOR;
 }
 
+}
+}
--- a/accessible/xul/XULSliderAccessible.h
+++ b/accessible/xul/XULSliderAccessible.h
@@ -38,26 +38,26 @@ public:
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t aIndex) override;
 
 protected:
   /**
    * Return anonymous slider element.
    */
-  nsIContent* GetSliderElement() const;
+  dom::Element* GetSliderElement() const;
 
   nsresult GetSliderAttr(nsAtom *aName, nsAString& aValue) const;
   nsresult SetSliderAttr(nsAtom *aName, const nsAString& aValue);
 
   double GetSliderAttr(nsAtom *aName) const;
   bool SetSliderAttr(nsAtom *aName, double aValue);
 
 private:
-  mutable nsCOMPtr<nsIContent> mSliderNode;
+  mutable RefPtr<dom::Element> mSliderElement;
 };
 
 
 /**
  * Used for slider's thumb element.
  */
 class XULThumbAccessible : public AccessibleWrap
 {
--- a/dom/base/DocumentFragment.h
+++ b/dom/base/DocumentFragment.h
@@ -64,43 +64,16 @@ public:
                                             nsIDOMNode::DOCUMENT_FRAGMENT_NODE)),
       mHost(nullptr)
   {
     Init();
   }
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  // nsIContent
-  using nsIContent::SetAttr;
-  virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
-                           nsAtom* aPrefix, const nsAString& aValue,
-                           nsIPrincipal* aSubjectPrincipal,
-                           bool aNotify) override
-  {
-    return NS_OK;
-  }
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
-                             bool aNotify) override
-  {
-    return NS_OK;
-  }
-  virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override
-  {
-    return nullptr;
-  }
-  virtual BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override
-  {
-    return BorrowedAttrInfo(nullptr, nullptr);
-  }
-  virtual uint32_t GetAttrCount() const override
-  {
-    return 0;
-  }
-
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override
   {
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -425,16 +425,21 @@ public:
    * Get a hint that tells the style system what to do when
    * an attribute on this node changes, if something needs to happen
    * in response to the change *other* than the result of what is
    * mapped into style data via any type of style rule.
    */
   virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
                                               int32_t aModType) const;
 
+  virtual nsresult WalkContentStyleRules(nsRuleWalker* aRuleWalker)
+  {
+    return NS_OK;
+  }
+
   inline Directionality GetDirectionality() const {
     if (HasFlag(NODE_HAS_DIRECTION_RTL)) {
       return eDir_RTL;
     }
 
     if (HasFlag(NODE_HAS_DIRECTION_LTR)) {
       return eDir_LTR;
     }
@@ -692,18 +697,16 @@ public:
    * null otherwise.
    *
    * @param aStr the unparsed attribute string
    * @return the node info. May be nullptr.
    */
   already_AddRefed<mozilla::dom::NodeInfo>
   GetExistingAttrNameFromQName(const nsAString& aStr) const;
 
-  using nsIContent::SetAttr;
-
   /**
    * Helper for SetAttr/SetParsedAttr. This method will return true if aNotify
    * is true or there are mutation listeners that must be triggered, the
    * attribute is currently set, and the new value that is about to be set is
    * different to the current value. As a perf optimization the new and old
    * values will not actually be compared if we aren't notifying and we don't
    * have mutation listeners (in which case it's cheap to just return false
    * and let the caller go ahead and set the value).
@@ -753,57 +756,137 @@ public:
 
   /**
    * Sets the class attribute to a value that contains no whitespace.
    * Assumes that we are not notifying and that the attribute hasn't been
    * set previously.
    */
   nsresult SetSingleClassFromParser(nsAtom* aSingleClassName);
 
-  virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
-                           const nsAString& aValue, nsIPrincipal* aSubjectPrincipal,
-                           bool aNotify) override;
   // aParsedValue receives the old value of the attribute. That's useful if
   // either the input or output value of aParsedValue is StoresOwnData.
   nsresult SetParsedAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
                          nsAttrValue& aParsedValue, bool aNotify);
   // GetAttr is not inlined on purpose, to keep down codesize from all
   // the inlined nsAttrValue bits for C++ callers.
   bool GetAttr(int32_t aNameSpaceID, nsAtom* aName,
                nsAString& aResult) const;
   inline bool HasAttr(int32_t aNameSpaceID, nsAtom* aName) const;
   // aCaseSensitive == eIgnoreCaase means ASCII case-insensitive matching.
   inline bool AttrValueIs(int32_t aNameSpaceID, nsAtom* aName,
                           const nsAString& aValue,
                           nsCaseTreatment aCaseSensitive) const;
   inline bool AttrValueIs(int32_t aNameSpaceID, nsAtom* aName,
                           nsAtom* aValue,
                           nsCaseTreatment aCaseSensitive) const;
-  virtual int32_t FindAttrValueIn(int32_t aNameSpaceID,
-                                  nsAtom* aName,
-                                  AttrValuesArray* aValues,
-                                  nsCaseTreatment aCaseSensitive) const override;
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
-                             bool aNotify) override;
+  int32_t FindAttrValueIn(int32_t aNameSpaceID,
+                          nsAtom* aName,
+                          AttrValuesArray* aValues,
+                          nsCaseTreatment aCaseSensitive) const override;
+
+  /**
+   * Set attribute values. All attribute values are assumed to have a
+   * canonical string representation that can be used for these
+   * methods. The SetAttr method is assumed to perform a translation
+   * of the canonical form into the underlying content specific
+   * form.
+   *
+   * @param aNameSpaceID the namespace of the attribute
+   * @param aName the name of the attribute
+   * @param aValue the value to set
+   * @param aNotify specifies how whether or not the document should be
+   *        notified of the attribute change.
+   */
+  nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
+                   const nsAString& aValue, bool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
+  }
+  nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
+                   const nsAString& aValue, bool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, aPrefix, aValue, nullptr, aNotify);
+  }
+  nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue,
+                   nsIPrincipal* aTriggeringPrincipal, bool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nullptr, aValue, aTriggeringPrincipal, aNotify);
+  }
 
-  virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const final override
+  /**
+   * Set attribute values. All attribute values are assumed to have a
+   * canonical String representation that can be used for these
+   * methods. The SetAttr method is assumed to perform a translation
+   * of the canonical form into the underlying content specific
+   * form.
+   *
+   * @param aNameSpaceID the namespace of the attribute
+   * @param aName the name of the attribute
+   * @param aPrefix the prefix of the attribute
+   * @param aValue the value to set
+   * @param aMaybeScriptedPrincipal the principal of the scripted caller responsible
+   *        for setting the attribute, or null if no scripted caller can be
+   *        determined. A null value here does not guarantee that there is no
+   *        scripted caller, but a non-null value does guarantee that a scripted
+   *        caller with the given principal is directly responsible for the
+   *        attribute change.
+   * @param aNotify specifies how whether or not the document should be
+   *        notified of the attribute change.
+   */
+  virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
+                           nsAtom* aPrefix, const nsAString& aValue,
+                           nsIPrincipal* aMaybeScriptedPrincipal,
+                           bool aNotify);
+
+  /**
+   * Remove an attribute so that it is no longer explicitly specified.
+   *
+   * @param aNameSpaceID the namespace id of the attribute
+   * @param aAttr the name of the attribute to unset
+   * @param aNotify specifies whether or not the document should be
+   * notified of the attribute change
+   */
+  virtual nsresult UnsetAttr(int32_t aNameSpaceID,
+                             nsAtom* aAttribute,
+                             bool aNotify);
+
+  /**
+   * Get the namespace / name / prefix of a given attribute.
+   *
+   * @param   aIndex the index of the attribute name
+   * @returns The name at the given index, or null if the index is
+   *          out-of-bounds.
+   * @note    The document returned by NodeInfo()->GetDocument() (if one is
+   *          present) is *not* necessarily the owner document of the element.
+   * @note    The pointer returned by this function is only valid until the
+   *          next call of either GetAttrNameAt or SetAttr on the element.
+   */
+  const nsAttrName* GetAttrNameAt(uint32_t aIndex) const
   {
     return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
   }
 
-  virtual BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const final override
+  /**
+   * Gets the attribute info (name and value) for this element at a given index.
+   */
+  BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const
   {
     if (aIndex >= mAttrsAndChildren.AttrCount()) {
       return BorrowedAttrInfo(nullptr, nullptr);
     }
 
     return mAttrsAndChildren.AttrInfoAt(aIndex);
   }
 
-  virtual uint32_t GetAttrCount() const final override
+  /**
+   * Get the number of all specified attributes.
+   *
+   * @return the number of attributes
+   */
+  uint32_t GetAttrCount() const
   {
     return mAttrsAndChildren.AttrCount();
   }
 
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
   /**
    * Get the class list of this element (this corresponds to the value of the
@@ -1484,17 +1567,17 @@ public:
    */
   void SetAttr(nsAtom* aAttr, const nsAString& aValue, ErrorResult& aError)
   {
     aError = SetAttr(kNameSpaceID_None, aAttr, aValue, true);
   }
 
   void SetAttr(nsAtom* aAttr, const nsAString& aValue, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
   {
-    aError = nsIContent::SetAttr(kNameSpaceID_None, aAttr, aValue, &aTriggeringPrincipal, true);
+    aError = SetAttr(kNameSpaceID_None, aAttr, aValue, &aTriggeringPrincipal, true);
   }
 
   /**
    * Set a content attribute via a reflecting nullable string IDL
    * attribute (e.g. a CORS attribute).  If DOMStringIsNull(aValue),
    * this will actually remove the content attribute.
    */
   void SetOrRemoveNullableStringAttr(nsAtom* aName, const nsAString& aValue,
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -386,31 +386,35 @@ nsIContent::LookupNamespaceURIInternal(c
   }
   else {
     name = nsGkAtoms::xmlns;
   }
   // Trace up the content parent chain looking for the namespace
   // declaration that declares aNamespacePrefix.
   const nsIContent* content = this;
   do {
-    if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
+    if (content->IsElement() &&
+        content->AsElement()->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
       return NS_OK;
   } while ((content = content->GetParent()));
   return NS_ERROR_FAILURE;
 }
 
 nsAtom*
 nsIContent::GetLang() const
 {
   for (const auto* content = this; content; content = content->GetParent()) {
-    if (!content->GetAttrCount() || !content->IsElement()) {
+    if (!content->IsElement()) {
       continue;
     }
 
     auto* element = content->AsElement();
+    if (!element->GetAttrCount()) {
+      continue;
+    }
 
     // xml:lang has precedence over lang on HTML elements (see
     // XHTML1 section C.7).
     const nsAttrValue* attr =
       element->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
     if (!attr && element->SupportsLangAttr()) {
       attr = element->GetParsedAttr(nsGkAtoms::lang);
     }
@@ -1174,22 +1178,16 @@ bool
 nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse)
 {
   if (aTabIndex) {
     *aTabIndex = -1; // Default, not tabbable
   }
   return false;
 }
 
-NS_IMETHODIMP
-FragmentOrElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
-{
-  return NS_OK;
-}
-
 bool
 FragmentOrElement::IsLink(nsIURI** aURI) const
 {
   *aURI = nullptr;
   return false;
 }
 
 nsIContent*
@@ -2236,18 +2234,18 @@ FragmentOrElement::CopyInnerTo(FragmentO
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t i, count = mAttrsAndChildren.AttrCount();
   for (i = 0; i < count; ++i) {
     const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
     const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
     nsAutoString valStr;
     value->ToString(valStr);
-    rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
-                                name->GetPrefix(), valStr, false);
+    rv = aDst->AsElement()->SetAttr(name->NamespaceID(), name->LocalName(),
+                                    name->GetPrefix(), valStr, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 const nsTextFragment*
 FragmentOrElement::GetText()
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -160,18 +160,16 @@ public:
   virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
   virtual nsIContent *GetXBLInsertionPoint() const override;
   virtual void SetXBLInsertionPoint(nsIContent* aContent) override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
   virtual void DestroyContent() override;
   virtual void SaveSubtreeState() override;
 
-  NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
-
   nsIHTMLCollection* Children();
   uint32_t ChildElementCount()
   {
     return Children()->Length();
   }
 
   /**
    * Sets the IsElementInStyleScope flag on each element in the subtree rooted
--- a/dom/base/nsContentCreatorFunctions.h
+++ b/dom/base/nsContentCreatorFunctions.h
@@ -58,17 +58,17 @@ NS_NewMathMLElement(mozilla::dom::Elemen
 
 #ifdef MOZ_XUL
 nsresult
 NS_NewXULElement(mozilla::dom::Element** aResult,
                  already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                  mozilla::dom::FromParser aFromParser);
 
 void
-NS_TrustedNewXULElement(nsIContent** aResult,
+NS_TrustedNewXULElement(mozilla::dom::Element** aResult,
                         already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 #endif
 
 nsresult
 NS_NewSVGElement(mozilla::dom::Element** aResult,
                  already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                  mozilla::dom::FromParser aFromParser);
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5053,23 +5053,23 @@ nsContentUtils::CreateContextualFragment
   if (content && !content->IsElement())
     content = content->GetParent();
 
   while (content && content->IsElement()) {
     nsString& tagName = *tagStack.AppendElement();
     tagName = content->NodeInfo()->QualifiedName();
 
     // see if we need to add xmlns declarations
-    uint32_t count = content->GetAttrCount();
+    uint32_t count = content->AsElement()->GetAttrCount();
     bool setDefaultNamespace = false;
     if (count > 0) {
       uint32_t index;
 
       for (index = 0; index < count; index++) {
-        const BorrowedAttrInfo info = content->GetAttrInfoAt(index);
+        const BorrowedAttrInfo info = content->AsElement()->GetAttrInfoAt(index);
         const nsAttrName* name = info.mName;
         if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
           info.mValue->ToString(uriStr);
 
           // really want something like nsXMLContentSerializer::SerializeAttr
           tagName.AppendLiteral(" xmlns"); // space important
           if (name->GetPrefix()) {
             tagName.Append(char16_t(':'));
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -416,20 +416,20 @@ nsIdentifierMapEntry::GetIdElement()
 
 Element*
 nsIdentifierMapEntry::GetImageIdElement()
 {
   return mImageElement ? mImageElement.get() : GetIdElement();
 }
 
 void
-nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements)
-{
-  for (size_t i = 0; i < mIdContentList.Length(); ++i) {
-    aElements->AppendObject(mIdContentList[i]);
+nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<Element>* aElements)
+{
+  for (Element* element : mIdContentList) {
+    aElements->AppendObject(element);
   }
 }
 
 void
 nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
                                                void* aData, bool aForImage)
 {
   if (!mChangeCallbacks) {
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -632,62 +632,29 @@ nsGenericDOMDataNode::UnbindFromTree(boo
 }
 
 already_AddRefed<nsINodeList>
 nsGenericDOMDataNode::GetChildren(uint32_t aFilter)
 {
   return nullptr;
 }
 
-nsresult
-nsGenericDOMDataNode::SetAttr(int32_t aNameSpaceID, nsAtom* aAttr,
-                              nsAtom* aPrefix, const nsAString& aValue,
-                              nsIPrincipal* aContentPrincipal,
-                              bool aNotify)
-{
-  return NS_OK;
-}
-
-nsresult
-nsGenericDOMDataNode::UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttr,
-                                bool aNotify)
-{
-  return NS_OK;
-}
-
-const nsAttrName*
-nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const
-{
-  return nullptr;
-}
-
-BorrowedAttrInfo
-nsGenericDOMDataNode::GetAttrInfoAt(uint32_t aIndex) const
-{
-  return BorrowedAttrInfo(nullptr, nullptr);
-}
-
-uint32_t
-nsGenericDOMDataNode::GetAttrCount() const
-{
-  return 0;
-}
-
 uint32_t
 nsGenericDOMDataNode::GetChildCount() const
 {
   return 0;
 }
 
 nsIContent *
 nsGenericDOMDataNode::GetChildAt(uint32_t aIndex) const
 {
   return nullptr;
 }
 
+
 int32_t
 nsGenericDOMDataNode::IndexOf(const nsINode* aPossibleChild) const
 {
   return -1;
 }
 
 nsresult
 nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
@@ -1118,36 +1085,16 @@ nsGenericDOMDataNode::AppendTextTo(nsASt
 already_AddRefed<nsAtom>
 nsGenericDOMDataNode::GetCurrentValueAtom()
 {
   nsAutoString val;
   GetData(val);
   return NS_Atomize(val);
 }
 
-NS_IMETHODIMP
-nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP_(bool)
-nsGenericDOMDataNode::IsAttributeMapped(const nsAtom* aAttribute) const
-{
-  return false;
-}
-
-nsChangeHint
-nsGenericDOMDataNode::GetAttributeChangeHint(const nsAtom* aAttribute,
-                                             int32_t aModType) const
-{
-  NS_NOTREACHED("Shouldn't be calling this!");
-  return nsChangeHint(0);
-}
-
 void
 nsGenericDOMDataNode::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
                                              size_t* aNodeSize) const
 {
   nsIContent::AddSizeOfExcludingThis(aSizes, aNodeSize);
   *aNodeSize += mText.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
 }
 
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -128,27 +128,16 @@ public:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) override;
 
-
-  using nsIContent::SetAttr;
-  virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
-                           nsAtom* aPrefix, const nsAString& aValue,
-                           nsIPrincipal* aSubjectPrincipal,
-                           bool aNotify) override;
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
-                             bool aNotify) override;
-  virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override;
-  virtual mozilla::dom::BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override;
-  virtual uint32_t GetAttrCount() const override;
   virtual const nsTextFragment *GetText() override;
   virtual uint32_t TextLength() const override;
   virtual nsresult SetText(const char16_t* aBuffer, uint32_t aLength,
                            bool aNotify) override;
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
@@ -179,21 +168,16 @@ public:
   virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) override;
   virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
   virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
   virtual nsIContent *GetXBLInsertionPoint() const override;
   virtual void SetXBLInsertionPoint(nsIContent* aContent) override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
-  NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
-  NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const;
-  virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
-                                              int32_t aModType) const;
-
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override
   {
     nsCOMPtr<nsINode> result = CloneDataNode(aNodeInfo, true);
     result.forget(aResult);
 
     if (!*aResult) {
       return NS_ERROR_OUT_OF_MEMORY;
--- a/dom/base/nsHTMLContentSerializer.cpp
+++ b/dom/base/nsHTMLContentSerializer.cpp
@@ -59,44 +59,44 @@ nsHTMLContentSerializer::~nsHTMLContentS
 NS_IMETHODIMP
 nsHTMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
                                              nsAString& aStr)
 {
   return NS_OK;
 }
 
 bool
-nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
-                                                 nsIContent *aOriginalElement,
+nsHTMLContentSerializer::SerializeHTMLAttributes(Element* aElement,
+                                                 Element* aOriginalElement,
                                                  nsAString& aTagPrefix,
                                                  const nsAString& aTagNamespaceURI,
                                                  nsAtom* aTagName,
                                                  int32_t aNamespace,
                                                  nsAString& aStr)
 {
-  int32_t count = aContent->GetAttrCount();
+  int32_t count = aElement->GetAttrCount();
   if (!count)
     return true;
 
   nsresult rv;
   nsAutoString valueStr;
   NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
 
   for (int32_t index = 0; index < count; index++) {
-    const nsAttrName* name = aContent->GetAttrNameAt(index);
+    const nsAttrName* name = aElement->GetAttrNameAt(index);
     int32_t namespaceID = name->NamespaceID();
     nsAtom* attrName = name->LocalName();
 
     // Filter out any attribute starting with [-|_]moz
     nsDependentAtomString attrNameStr(attrName);
     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
       continue;
     }
-    aContent->GetAttr(namespaceID, attrName, valueStr);
+    aElement->GetAttr(namespaceID, attrName, valueStr);
 
     //
     // Filter out special case of <br type="_moz"> or <br _moz*>,
     // used by the editor.  Bug 16988.  Yuck.
     //
     if (aTagName == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML &&
         attrName == nsGkAtoms::type && namespaceID == kNameSpaceID_None &&
         StringBeginsWith(valueStr, _mozStr)) {
@@ -104,45 +104,45 @@ nsHTMLContentSerializer::SerializeHTMLAt
     }
 
     if (mIsCopying && mIsFirstChildOfOL &&
         aTagName == nsGkAtoms::li && aNamespace == kNameSpaceID_XHTML &&
         attrName == nsGkAtoms::value && namespaceID == kNameSpaceID_None){
       // This is handled separately in SerializeLIValueAttribute()
       continue;
     }
-    bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
+    bool isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
 
     if (((attrName == nsGkAtoms::href &&
           (namespaceID == kNameSpaceID_None ||
            namespaceID == kNameSpaceID_XLink)) ||
          (attrName == nsGkAtoms::src && namespaceID == kNameSpaceID_None))) {
       // Make all links absolute when converting only the selection:
       if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) {
         // Would be nice to handle OBJECT tags, but that gets more complicated
         // since we have to search the tag list for CODEBASE as well. For now,
         // just leave them relative.
-        nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
+        nsCOMPtr<nsIURI> uri = aElement->GetBaseURI();
         if (uri) {
           nsAutoString absURI;
           rv = NS_MakeAbsoluteURI(absURI, valueStr, uri);
           if (NS_SUCCEEDED(rv)) {
             valueStr = absURI;
           }
         }
       }
     }
 
     if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&
         aNamespace == kNameSpaceID_XHTML && attrName == nsGkAtoms::content
         && namespaceID == kNameSpaceID_None) {
       // If we're serializing a <meta http-equiv="content-type">,
       // use the proper value, rather than what's in the document.
       nsAutoString header;
-      aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
+      aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
       if (header.LowerCaseEqualsLiteral("content-type")) {
         valueStr = NS_LITERAL_STRING("text/html; charset=") +
           NS_ConvertASCIItoUTF16(mCharset);
       }
     }
 
     nsDependentAtomString nameStr(attrName);
     nsAutoString prefix;
@@ -168,32 +168,30 @@ nsHTMLContentSerializer::SerializeHTMLAt
 
 NS_IMETHODIMP
 nsHTMLContentSerializer::AppendElementStart(Element* aElement,
                                             Element* aOriginalElement,
                                             nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
-  nsIContent* content = aElement;
-
   bool forceFormat = false;
   nsresult rv = NS_OK;
-  if (!CheckElementStart(content, forceFormat, aStr, rv)) {
+  if (!CheckElementStart(aElement, forceFormat, aStr, rv)) {
     // When we go to AppendElementEnd for this element, we're going to
     // MaybeLeaveFromPreContent().  So make sure to MaybeEnterInPreContent()
     // now, so our PreLevel() doesn't get confused.
-    MaybeEnterInPreContent(content);
+    MaybeEnterInPreContent(aElement);
     return rv;
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAtom *name = content->NodeInfo()->NameAtom();
-  int32_t ns = content->GetNameSpaceID();
+  nsAtom *name = aElement->NodeInfo()->NameAtom();
+  int32_t ns = aElement->GetNameSpaceID();
 
   bool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     if (mColPos && lineBreakBeforeOpen) {
       NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
     }
     else {
@@ -219,17 +217,17 @@ nsHTMLContentSerializer::AppendElementSt
   // Always reset to avoid false newlines in case MaybeAddNewlineForRootNode wasn't
   // called
   mAddNewlineForRootNode = false;
 
   NS_ENSURE_TRUE(AppendToString(kLessThan, aStr), NS_ERROR_OUT_OF_MEMORY);
 
   NS_ENSURE_TRUE(AppendToString(nsDependentAtomString(name), aStr), NS_ERROR_OUT_OF_MEMORY);
 
-  MaybeEnterInPreContent(content);
+  MaybeEnterInPreContent(aElement);
 
   // for block elements, we increase the indentation
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel())
     NS_ENSURE_TRUE(IncrIndentation(name), NS_ERROR_OUT_OF_MEMORY);
 
   // Need to keep track of OL and LI elements in order to get ordinal number
   // for the LI.
   if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML){
@@ -259,17 +257,17 @@ nsHTMLContentSerializer::AppendElementSt
       // If OL is parent of this LI, serialize attributes in different manner.
       NS_ENSURE_TRUE(SerializeLIValueAttribute(aElement, aStr), NS_ERROR_OUT_OF_MEMORY);
     }
   }
 
   // Even LI passed above have to go through this
   // for serializing attributes other than "value".
   nsAutoString dummyPrefix;
-  NS_ENSURE_TRUE(SerializeHTMLAttributes(content,
+  NS_ENSURE_TRUE(SerializeHTMLAttributes(aElement,
                                          aOriginalElement,
                                          dummyPrefix,
                                          EmptyString(),
                                          name,
                                          ns,
                                          aStr), NS_ERROR_OUT_OF_MEMORY);
 
   NS_ENSURE_TRUE(AppendToString(kGreaterThan, aStr), NS_ERROR_OUT_OF_MEMORY);
@@ -282,42 +280,39 @@ nsHTMLContentSerializer::AppendElementSt
     ++mDisableEntityEncoding;
   }
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel() &&
     LineBreakAfterOpen(ns, name)) {
     NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
   }
 
-  NS_ENSURE_TRUE(AfterElementStart(content, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
+  NS_ENSURE_TRUE(AfterElementStart(aElement, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
-                                          nsAString& aStr)
+nsHTMLContentSerializer::AppendElementEnd(Element* aElement, nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
-  nsIContent* content = aElement;
-
-  nsAtom *name = content->NodeInfo()->NameAtom();
-  int32_t ns = content->GetNameSpaceID();
+  nsAtom *name = aElement->NodeInfo()->NameAtom();
+  int32_t ns = aElement->GetNameSpaceID();
 
   if (ns == kNameSpaceID_XHTML &&
       (name == nsGkAtoms::script ||
        name == nsGkAtoms::style ||
        name == nsGkAtoms::noscript ||
        name == nsGkAtoms::noframes)) {
     --mDisableEntityEncoding;
   }
 
   bool forceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
-                     content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
+                     aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     DecrIndentation(name);
   }
 
   if (name == nsGkAtoms::script) {
     nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aElement);
 
@@ -339,17 +334,17 @@ nsHTMLContentSerializer::AppendElementEn
   }
 
   if (ns == kNameSpaceID_XHTML) {
     bool isContainer =
       nsHTMLElement::IsContainer(nsHTMLTags::CaseSensitiveAtomTagToId(name));
     if (!isContainer) {
       // Keep this in sync with the cleanup at the end of this method.
       MOZ_ASSERT(name != nsGkAtoms::body);
-      MaybeLeaveFromPreContent(content);
+      MaybeLeaveFromPreContent(aElement);
       return NS_OK;
     }
   }
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
 
     bool lineBreakBeforeClose = LineBreakBeforeClose(ns, name);
 
@@ -371,17 +366,17 @@ nsHTMLContentSerializer::AppendElementEn
     NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
   }
 
   NS_ENSURE_TRUE(AppendToString(kEndTag, aStr), NS_ERROR_OUT_OF_MEMORY);
   NS_ENSURE_TRUE(AppendToString(nsDependentAtomString(name), aStr), NS_ERROR_OUT_OF_MEMORY);
   NS_ENSURE_TRUE(AppendToString(kGreaterThan, aStr), NS_ERROR_OUT_OF_MEMORY);
 
   // Keep this cleanup in sync with the IsContainer() early return above.
-  MaybeLeaveFromPreContent(content);
+  MaybeLeaveFromPreContent(aElement);
 
   if ((mDoFormat || forceFormat)&& !mDoRaw  && !PreLevel()
       && LineBreakAfterClose(ns, name)) {
     NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
   }
   else {
     MaybeFlagNewlineForRootNode(aElement);
   }
--- a/dom/base/nsHTMLContentSerializer.h
+++ b/dom/base/nsHTMLContentSerializer.h
@@ -12,17 +12,16 @@
 
 #ifndef nsHTMLContentSerializer_h__
 #define nsHTMLContentSerializer_h__
 
 #include "mozilla/Attributes.h"
 #include "nsXHTMLContentSerializer.h"
 #include "nsString.h"
 
-class nsIContent;
 class nsAtom;
 
 class nsHTMLContentSerializer final : public nsXHTMLContentSerializer {
  public:
   nsHTMLContentSerializer();
   virtual ~nsHTMLContentSerializer();
 
   NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
@@ -32,18 +31,18 @@ class nsHTMLContentSerializer final : pu
   NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
                               nsAString& aStr) override;
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr) override;
  protected:
 
   MOZ_MUST_USE
-  virtual bool SerializeHTMLAttributes(nsIContent* aContent,
-                                       nsIContent *aOriginalElement,
+  virtual bool SerializeHTMLAttributes(mozilla::dom::Element* aContent,
+                                       mozilla::dom::Element* aOriginalElement,
                                        nsAString& aTagPrefix,
                                        const nsAString& aTagNamespaceURI,
                                        nsAtom* aTagName,
                                        int32_t aNamespace,
                                        nsAString& aStr);
 
   MOZ_MUST_USE
   virtual bool AppendAndTranslateEntities(const nsAString& aStr,
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -10,17 +10,16 @@
 #include "mozilla/dom/BorrowedAttrInfo.h"
 #include "nsCaseTreatment.h" // for enum, cannot be forward-declared
 #include "nsINode.h"
 #include "nsStringFwd.h"
 
 // Forward declarations
 class nsAtom;
 class nsIURI;
-class nsRuleWalker;
 class nsAttrValue;
 class nsAttrName;
 class nsTextFragment;
 class nsIFrame;
 class nsXBLBinding;
 class nsITextControlElement;
 
 namespace mozilla {
@@ -352,78 +351,26 @@ public:
 
   bool IsGeneratedContentContainerForAfter() const
   {
     return IsRootOfNativeAnonymousSubtree() &&
            mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter;
   }
 
   /**
-   * Set attribute values. All attribute values are assumed to have a
-   * canonical string representation that can be used for these
-   * methods. The SetAttr method is assumed to perform a translation
-   * of the canonical form into the underlying content specific
-   * form.
-   *
-   * @param aNameSpaceID the namespace of the attribute
-   * @param aName the name of the attribute
-   * @param aValue the value to set
-   * @param aNotify specifies how whether or not the document should be
-   *        notified of the attribute change.
-   */
-  nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
-                   const nsAString& aValue, bool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
-  }
-  nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
-                   const nsAString& aValue, bool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, aPrefix, aValue, nullptr, aNotify);
-  }
-  nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue,
-                   nsIPrincipal* aTriggeringPrincipal, bool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nullptr, aValue, aTriggeringPrincipal, aNotify);
-  }
-
-  /**
-   * Set attribute values. All attribute values are assumed to have a
-   * canonical String representation that can be used for these
-   * methods. The SetAttr method is assumed to perform a translation
-   * of the canonical form into the underlying content specific
-   * form.
-   *
-   * @param aNameSpaceID the namespace of the attribute
-   * @param aName the name of the attribute
-   * @param aPrefix the prefix of the attribute
-   * @param aValue the value to set
-   * @param aMaybeScriptedPrincipal the principal of the scripted caller responsible
-   *        for setting the attribute, or null if no scripted caller can be
-   *        determined. A null value here does not guarantee that there is no
-   *        scripted caller, but a non-null value does guarantee that a scripted
-   *        caller with the given principal is directly responsible for the
-   *        attribute change.
-   * @param aNotify specifies how whether or not the document should be
-   *        notified of the attribute change.
-   */
-  virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
-                           nsAtom* aPrefix, const nsAString& aValue,
-                           nsIPrincipal* aMaybeScriptedPrincipal,
-                           bool aNotify) = 0;
-
-  /**
    * Get the current value of the attribute. This returns a form that is
    * suitable for passing back into SetAttr.
    *
    * @param aNameSpaceID the namespace of the attr
    * @param aName the name of the attr
    * @param aResult the value (may legitimately be the empty string) [OUT]
    * @returns true if the attribute was set (even when set to empty string)
    *          false when not set.
+   *
+   * FIXME(emilio): Move to Element.
    */
   bool GetAttr(int32_t aNameSpaceID, nsAtom* aName,
                nsAString& aResult) const;
 
   /**
    * Determine if an attribute has been set (empty string or otherwise).
    *
    * @param aNameSpaceId the namespace id of the attribute
@@ -488,53 +435,16 @@ public:
                                   nsAtom* aName,
                                   AttrValuesArray* aValues,
                                   nsCaseTreatment aCaseSensitive) const
   {
     return ATTR_MISSING;
   }
 
   /**
-   * Remove an attribute so that it is no longer explicitly specified.
-   *
-   * @param aNameSpaceID the namespace id of the attribute
-   * @param aAttr the name of the attribute to unset
-   * @param aNotify specifies whether or not the document should be
-   * notified of the attribute change
-   */
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttr,
-                             bool aNotify) = 0;
-
-
-  /**
-   * Get the namespace / name / prefix of a given attribute.
-   *
-   * @param   aIndex the index of the attribute name
-   * @returns The name at the given index, or null if the index is
-   *          out-of-bounds.
-   * @note    The document returned by NodeInfo()->GetDocument() (if one is
-   *          present) is *not* necessarily the owner document of the element.
-   * @note    The pointer returned by this function is only valid until the
-   *          next call of either GetAttrNameAt or SetAttr on the element.
-   */
-  virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const = 0;
-
-  /**
-   * Gets the attribute info (name and value) for this content at a given index.
-   */
-  virtual mozilla::dom::BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const = 0;
-
-  /**
-   * Get the number of all specified attributes.
-   *
-   * @return the number of attributes
-   */
-  virtual uint32_t GetAttrCount() const = 0;
-
-  /**
    * Get direct access (but read only) to the text in the text content.
    * NOTE: For elements this is *not* the concatenation of all text children,
    * it is simply null;
    */
   virtual const nsTextFragment *GetText() = 0;
 
   /**
    * Get the length of the text content.
@@ -921,22 +831,16 @@ public:
   nsAtom* GetID() const {
     if (HasID()) {
       return DoGetID();
     }
     return nullptr;
   }
 
   /**
-   * Walk aRuleWalker over the content style rules (presentational
-   * hint rules) for this content node.
-   */
-  NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) = 0;
-
-  /**
    * Should be called when the node can become editable or when it can stop
    * being editable (for example when its contentEditable attribute changes,
    * when it is moved into an editable parent, ...).  If aNotify is true and
    * the node is an element, this will notify the state change.
    */
   virtual void UpdateEditableState(bool aNotify);
 
   /**
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -773,27 +773,32 @@ nsINode::LookupPrefix(const nsAString& a
   if (element) {
     // XXX Waiting for DOM spec to list error codes.
 
     // Trace up the content parent chain looking for the namespace
     // declaration that defines the aNamespaceURI namespace. Once found,
     // return the prefix (i.e. the attribute localName).
     for (nsIContent* content = element; content;
          content = content->GetParent()) {
-      uint32_t attrCount = content->GetAttrCount();
+      if (!content->IsElement()) {
+        continue;
+      }
+
+      Element* element = content->AsElement();
+      uint32_t attrCount = element->GetAttrCount();
 
       for (uint32_t i = 0; i < attrCount; ++i) {
-        const nsAttrName* name = content->GetAttrNameAt(i);
+        const nsAttrName* name = element->GetAttrNameAt(i);
 
         if (name->NamespaceEquals(kNameSpaceID_XMLNS) &&
-            content->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
+            element->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
                                  aNamespaceURI, eCaseMatters)) {
           // If the localName is "xmlns", the prefix we output should be
           // null.
-          nsAtom *localName = name->LocalName();
+          nsAtom* localName = name->LocalName();
 
           if (localName != nsGkAtoms::xmlns) {
             localName->ToString(aPrefix);
           }
           else {
             SetDOMStringToNull(aPrefix);
           }
           return;
--- a/dom/base/nsIdentifierMapEntry.h
+++ b/dom/base/nsIdentifierMapEntry.h
@@ -147,17 +147,17 @@ public:
   /**
    * If this entry has a non-null image element set (using SetImageElement),
    * the image element will be returned, otherwise the same as GetIdElement().
    */
   Element* GetImageIdElement();
   /**
    * Append all the elements with this id to aElements
    */
-  void AppendAllIdContent(nsCOMArray<nsIContent>* aElements);
+  void AppendAllIdContent(nsCOMArray<Element>* aElements);
   /**
    * This can fire ID change callbacks.
    * @return true if the content could be added, false if we failed due
    * to OOM.
    */
   bool AddIdElement(Element* aElement);
   /**
    * This can fire ID change callbacks.
--- a/dom/base/nsMappedAttributeElement.h
+++ b/dom/base/nsMappedAttributeElement.h
@@ -34,17 +34,17 @@ protected:
   {}
 
 public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
 
   static void MapNoAttributesInto(const nsMappedAttributes* aAttributes,
                                   mozilla::GenericSpecifiedValues* aGenericData);
 
-  NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
+  virtual nsresult WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
   virtual bool SetAndSwapMappedAttribute(nsAtom* aName,
                                          nsAttrValue& aValue,
                                          bool* aValueWasSet,
                                          nsresult* aRetval) override;
 
   virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 };
 
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -919,24 +919,24 @@ nsObjectLoadingContent::GetNestedParams(
 nsresult
 nsObjectLoadingContent::BuildParametersArray()
 {
   if (mCachedAttributes.Length() || mCachedParameters.Length()) {
     MOZ_ASSERT(false, "Parameters array should be empty.");
     return NS_OK;
   }
 
-  nsCOMPtr<nsIContent> content =
+  nsCOMPtr<Element> element =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
-  for (uint32_t i = 0; i != content->GetAttrCount(); i += 1) {
+  for (uint32_t i = 0; i != element->GetAttrCount(); i += 1) {
     MozPluginParameter param;
-    const nsAttrName* attrName = content->GetAttrNameAt(i);
+    const nsAttrName* attrName = element->GetAttrNameAt(i);
     nsAtom* atom = attrName->LocalName();
-    content->GetAttr(attrName->NamespaceID(), atom, param.mValue);
+    element->GetAttr(attrName->NamespaceID(), atom, param.mValue);
     atom->ToString(param.mName);
     mCachedAttributes.AppendElement(param);
   }
 
   nsAutoCString wmodeOverride;
   Preferences::GetCString("plugins.force.wmode", wmodeOverride);
 
   for (uint32_t i = 0; i < mCachedAttributes.Length(); i++) {
@@ -953,20 +953,20 @@ nsObjectLoadingContent::BuildParametersA
     mCachedAttributes.AppendElement(param);
   }
 
   // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
   // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
   // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
   // look for "data", lets instead copy the "data" attribute and add another entry
   // to the bottom of the array if there isn't already a "src" specified.
-  if (content->IsHTMLElement(nsGkAtoms::object) &&
-      !content->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
+  if (element->IsHTMLElement(nsGkAtoms::object) &&
+      !element->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
     MozPluginParameter param;
-    content->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
+    element->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
     if (!param.mValue.IsEmpty()) {
       param.mName = NS_LITERAL_STRING("SRC");
       mCachedAttributes.AppendElement(param);
     }
   }
 
   GetNestedParams(mCachedParameters);
 
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -1396,20 +1396,22 @@ nsTreeSanitizer::SanitizeChildren(nsINod
   while (node) {
     if (node->IsElement()) {
       mozilla::dom::Element* elt = node->AsElement();
       mozilla::dom::NodeInfo* nodeInfo = node->NodeInfo();
       nsAtom* localName = nodeInfo->NameAtom();
       int32_t ns = nodeInfo->NamespaceID();
 
       if (MustPrune(ns, localName, elt)) {
-        RemoveAllAttributes(node);
+        RemoveAllAttributes(elt);
         nsIContent* descendant = node;
         while ((descendant = descendant->GetNextNode(node))) {
-          RemoveAllAttributes(descendant);
+          if (descendant->IsElement()) {
+            RemoveAllAttributes(descendant->AsElement());
+          }
         }
         nsIContent* next = node->GetNextNonChildNode(aRoot);
         node->RemoveFromParent();
         node = next;
         continue;
       }
       if (nsGkAtoms::style == localName) {
         // If styles aren't allowed, style elements got pruned above. Even
@@ -1445,17 +1447,17 @@ nsTreeSanitizer::SanitizeChildren(nsINod
                              true,
                              mAllowStyles,
                              false);
         }
         node = node->GetNextNonChildNode(aRoot);
         continue;
       }
       if (MustFlatten(ns, localName)) {
-        RemoveAllAttributes(node);
+        RemoveAllAttributes(elt);
         nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot);
         nsCOMPtr<nsIContent> parent = node->GetParent();
         nsCOMPtr<nsIContent> child; // Must keep the child alive during move
         ErrorResult rv;
         while ((child = node->GetFirstChild())) {
           nsCOMPtr<nsINode> refNode = node;
           parent->InsertBefore(*child, refNode, rv);
           if (rv.Failed()) {
@@ -1500,17 +1502,17 @@ nsTreeSanitizer::SanitizeChildren(nsINod
     if (!mAllowComments && node->IsNodeOfType(nsINode::eCOMMENT)) {
       node->RemoveFromParent();
     }
     node = next;
   }
 }
 
 void
-nsTreeSanitizer::RemoveAllAttributes(nsIContent* aElement)
+nsTreeSanitizer::RemoveAllAttributes(Element* aElement)
 {
   const nsAttrName* attrName;
   while ((attrName = aElement->GetAttrNameAt(0))) {
     int32_t attrNs = attrName->NamespaceID();
     RefPtr<nsAtom> attrLocal = attrName->LocalName();
     aElement->UnsetAttr(attrNs, attrLocal, false);
   }
 }
--- a/dom/base/nsTreeSanitizer.h
+++ b/dom/base/nsTreeSanitizer.h
@@ -141,18 +141,18 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
      * security check.
      *
      * @param aElement the element whose attribute to possibly modify
      * @param aNamespace the namespace of the URL attribute
      * @param aLocalName the local name of the URL attribute
      * @return true if the attribute was removed and false otherwise
      */
     bool SanitizeURL(mozilla::dom::Element* aElement,
-                       int32_t aNamespace,
-                       nsAtom* aLocalName);
+                     int32_t aNamespace,
+                     nsAtom* aLocalName);
 
     /**
      * Checks a style rule for the presence of the 'binding' CSS property and
      * removes that property from the rule.
      *
      * @param aDeclaration The style declaration to check
      * @return true if the rule was modified and false otherwise
      */
@@ -173,17 +173,17 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
     bool SanitizeStyleSheet(const nsAString& aOriginal,
                               nsAString& aSanitized,
                               nsIDocument* aDocument,
                               nsIURI* aBaseURI);
 
     /**
      * Removes all attributes from an element node.
      */
-    void RemoveAllAttributes(nsIContent* aElement);
+    void RemoveAllAttributes(mozilla::dom::Element* aElement);
 
     /**
      * The whitelist of HTML elements.
      */
     static nsTHashtable<nsRefPtrHashKey<nsAtom>>* sElementsHTML;
 
     /**
      * The whitelist of non-presentational HTML attributes.
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -151,46 +151,46 @@ nsXHTMLContentSerializer::AppendText(nsI
       NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
     }
   }
 
   return NS_OK;
 }
 
 bool
-nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
-                                              nsIContent *aOriginalElement,
+nsXHTMLContentSerializer::SerializeAttributes(Element* aElement,
+                                              Element* aOriginalElement,
                                               nsAString& aTagPrefix,
                                               const nsAString& aTagNamespaceURI,
                                               nsAtom* aTagName,
                                               nsAString& aStr,
                                               uint32_t aSkipAttr,
                                               bool aAddNSAttr)
 {
   nsresult rv;
   uint32_t index, count;
   nsAutoString prefixStr, uriStr, valueStr;
   nsAutoString xmlnsStr;
   xmlnsStr.AssignLiteral(kXMLNS);
 
-  int32_t contentNamespaceID = aContent->GetNameSpaceID();
+  int32_t contentNamespaceID = aElement->GetNameSpaceID();
 
   // this method is not called by nsHTMLContentSerializer
   // so we don't have to check HTML element, just XHTML
 
   if (mIsCopying && kNameSpaceID_XHTML == contentNamespaceID) {
 
     // Need to keep track of OL and LI elements in order to get ordinal number
     // for the LI.
     if (aTagName == nsGkAtoms::ol) {
       // We are copying and current node is an OL;
       // Store its start attribute value in olState->startVal.
       nsAutoString start;
       int32_t startAttrVal = 0;
-      aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
+      aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
       if (!start.IsEmpty()) {
         nsresult rv = NS_OK;
         startAttrVal = start.ToInteger(&rv);
         //If OL has "start" attribute, first LI element has to start with that value
         //Therefore subtracting 1 as all the LI elements are incrementing it before using it;
         //In failure of ToInteger(), default StartAttrValue to 0.
         if (NS_SUCCEEDED(rv))
           --startAttrVal;
@@ -199,17 +199,17 @@ nsXHTMLContentSerializer::SerializeAttri
       }
       olState state (startAttrVal, true);
       mOLStateStack.AppendElement(state);
     }
     else if (aTagName == nsGkAtoms::li) {
       mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
       if (mIsFirstChildOfOL) {
         // If OL is parent of this LI, serialize attributes in different manner.
-        NS_ENSURE_TRUE(SerializeLIValueAttribute(aContent, aStr), false);
+        NS_ENSURE_TRUE(SerializeLIValueAttribute(aElement, aStr), false);
       }
     }
   }
 
   // If we had to add a new namespace declaration, serialize
   // and push it on the namespace stack
   if (aAddNSAttr) {
     if (aTagPrefix.IsEmpty()) {
@@ -223,28 +223,28 @@ nsXHTMLContentSerializer::SerializeAttri
                                    aTagNamespaceURI,
                                    aStr, true), false);
     }
     PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement);
   }
 
   NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
 
-  count = aContent->GetAttrCount();
+  count = aElement->GetAttrCount();
 
   // Now serialize each of the attributes
   // XXX Unfortunately we need a namespace manager to get
   // attribute URIs.
   for (index = 0; index < count; index++) {
 
     if (aSkipAttr == index) {
         continue;
     }
 
-    mozilla::dom::BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
+    mozilla::dom::BorrowedAttrInfo info = aElement->GetAttrInfoAt(index);
     const nsAttrName* name = info.mName;
 
     int32_t namespaceID = name->NamespaceID();
     nsAtom* attrName = name->LocalName();
     nsAtom* attrPrefix = name->GetPrefix();
 
     // Filter out any attribute starting with [-|_]moz
     nsDependentAtomString attrNameStr(attrName);
@@ -282,57 +282,57 @@ nsXHTMLContentSerializer::SerializeAttri
       }
 
       if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li)
           && (attrName == nsGkAtoms::value)) {
         // This is handled separately in SerializeLIValueAttribute()
         continue;
       }
 
-      isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
+      isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
 
       if (namespaceID == kNameSpaceID_None &&
           ((attrName == nsGkAtoms::href) ||
           (attrName == nsGkAtoms::src))) {
         // Make all links absolute when converting only the selection:
         if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) {
           // Would be nice to handle OBJECT tags,
           // but that gets more complicated since we have to
           // search the tag list for CODEBASE as well.
           // For now, just leave them relative.
-          nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
+          nsCOMPtr<nsIURI> uri = aElement->GetBaseURI();
           if (uri) {
             nsAutoString absURI;
             rv = NS_MakeAbsoluteURI(absURI, valueStr, uri);
             if (NS_SUCCEEDED(rv)) {
               valueStr = absURI;
             }
           }
         }
       }
 
       if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&
           attrName == nsGkAtoms::content) {
         // If we're serializing a <meta http-equiv="content-type">,
         // use the proper value, rather than what's in the document.
         nsAutoString header;
-        aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
+        aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
         if (header.LowerCaseEqualsLiteral("content-type")) {
           valueStr = NS_LITERAL_STRING("text/html; charset=") +
             NS_ConvertASCIItoUTF16(mCharset);
         }
       }
 
       // Expand shorthand attribute.
       if (namespaceID == kNameSpaceID_None && IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) {
         valueStr = nameStr;
       }
     }
     else {
-      isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
+      isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
     }
 
     NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
 
     if (addNSAttr) {
       NS_ASSERTION(!prefixStr.IsEmpty(),
                    "Namespaced attributes must have a prefix");
       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, true), false);
@@ -409,37 +409,37 @@ nsXHTMLContentSerializer::AppendDocument
 {
   if (!mBodyOnly)
     return nsXMLContentSerializer::AppendDocumentStart(aDocument, aStr);
 
   return NS_OK;
 }
 
 bool
-nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent,
-                                            bool & aForceFormat,
+nsXHTMLContentSerializer::CheckElementStart(Element* aElement,
+                                            bool& aForceFormat,
                                             nsAString& aStr,
                                             nsresult& aResult)
 {
   aResult = NS_OK;
 
   // The _moz_dirty attribute is emitted by the editor to
   // indicate that this element should be pretty printed
   // even if we're not in pretty printing mode
   aForceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
-                 aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
+                 aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
 
-  if (aContent->IsHTMLElement(nsGkAtoms::br) &&
+  if (aElement->IsHTMLElement(nsGkAtoms::br) &&
       (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre) &&
       PreLevel() > 0) {
     aResult = AppendNewLineToString(aStr) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     return false;
   }
 
-  if (aContent->IsHTMLElement(nsGkAtoms::body)) {
+  if (aElement->IsHTMLElement(nsGkAtoms::body)) {
     ++mInBody;
   }
 
   return true;
 }
 
 bool
 nsXHTMLContentSerializer::CheckElementEnd(mozilla::dom::Element* aElement,
@@ -829,17 +829,17 @@ nsXHTMLContentSerializer::IsFirstChildOf
 
     return false;
   }
   else
     return false;
 }
 
 bool
-nsXHTMLContentSerializer::HasNoChildren(nsIContent * aContent) {
+nsXHTMLContentSerializer::HasNoChildren(nsIContent* aContent) {
 
   for (nsIContent* child = aContent->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
 
     if (!child->IsNodeOfType(nsINode::eTEXT))
       return false;
 
--- a/dom/base/nsXHTMLContentSerializer.h
+++ b/dom/base/nsXHTMLContentSerializer.h
@@ -43,20 +43,20 @@ class nsXHTMLContentSerializer : public 
                         nsAString& aStr) override;
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr) override;
 
  protected:
 
 
-  virtual bool CheckElementStart(nsIContent * aContent,
-                          bool & aForceFormat,
-                          nsAString& aStr,
-                          nsresult& aResult) override;
+  virtual bool CheckElementStart(mozilla::dom::Element* aElement,
+                                 bool& aForceFormat,
+                                 nsAString& aStr,
+                                 nsresult& aResult) override;
 
   MOZ_MUST_USE
   virtual bool AfterElementStart(nsIContent* aContent,
                                  nsIContent* aOriginalElement,
                                  nsAString& aStr) override;
 
   virtual bool CheckElementEnd(mozilla::dom::Element* aContent,
                                bool& aForceFormat,
@@ -72,24 +72,24 @@ class nsXHTMLContentSerializer : public 
 
   bool HasLongLines(const nsString& text, int32_t& aLastNewlineOffset);
 
   // functions to check if we enter in or leave from a preformated content
   virtual void MaybeEnterInPreContent(nsIContent* aNode) override;
   virtual void MaybeLeaveFromPreContent(nsIContent* aNode) override;
 
   MOZ_MUST_USE
-  virtual bool SerializeAttributes(nsIContent* aContent,
-                           nsIContent *aOriginalElement,
-                           nsAString& aTagPrefix,
-                           const nsAString& aTagNamespaceURI,
-                           nsAtom* aTagName,
-                           nsAString& aStr,
-                           uint32_t aSkipAttr,
-                           bool aAddNSAttr) override;
+  virtual bool SerializeAttributes(mozilla::dom::Element* aContent,
+                                   mozilla::dom::Element* aOriginalElement,
+                                   nsAString& aTagPrefix,
+                                   const nsAString& aTagNamespaceURI,
+                                   nsAtom* aTagName,
+                                   nsAString& aStr,
+                                   uint32_t aSkipAttr,
+                                   bool aAddNSAttr) override;
 
   bool IsFirstChildOfOL(nsIContent* aElement);
 
   MOZ_MUST_USE
   bool SerializeLIValueAttribute(nsIContent* aElement,
                                  nsAString& aStr);
   bool IsShorthandAttr(const nsAtom* aAttrName,
                          const nsAtom* aElementName);
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -707,30 +707,30 @@ nsXMLContentSerializer::SerializeAttr(co
   else {
     NS_ENSURE_TRUE(AppendToStringConvertLF(attrString, aStr), false);
   }
 
   return true;
 }
 
 uint32_t
-nsXMLContentSerializer::ScanNamespaceDeclarations(nsIContent* aContent,
-                                                  nsIContent *aOriginalElement,
+nsXMLContentSerializer::ScanNamespaceDeclarations(Element* aElement,
+                                                  Element* aOriginalElement,
                                                   const nsAString& aTagNamespaceURI)
 {
   uint32_t index, count;
   nsAutoString uriStr, valueStr;
 
-  count = aContent->GetAttrCount();
+  count = aElement->GetAttrCount();
 
   // First scan for namespace declarations, pushing each on the stack
   uint32_t skipAttr = count;
   for (index = 0; index < count; index++) {
 
-    const BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
+    const BorrowedAttrInfo info = aElement->GetAttrInfoAt(index);
     const nsAttrName* name = info.mName;
 
     int32_t namespaceID = name->NamespaceID();
     nsAtom *attrName = name->LocalName();
 
     if (namespaceID == kNameSpaceID_XMLNS ||
         // Also push on the stack attrs named "xmlns" in the null
         // namespace... because once we serialize those out they'll look like
@@ -794,18 +794,18 @@ nsXMLContentSerializer::IsJavaScript(nsI
       return false;
   }
 
   return aContent->IsEventAttributeName(aAttrNameAtom);
 }
 
 
 bool
-nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
-                                            nsIContent *aOriginalElement,
+nsXMLContentSerializer::SerializeAttributes(Element* aElement,
+                                            Element* aOriginalElement,
                                             nsAString& aTagPrefix,
                                             const nsAString& aTagNamespaceURI,
                                             nsAtom* aTagName,
                                             nsAString& aStr,
                                             uint32_t aSkipAttr,
                                             bool aAddNSAttr)
 {
 
@@ -823,27 +823,27 @@ nsXMLContentSerializer::SerializeAttribu
     }
     else {
       // Serialize namespace decl
       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, aTagPrefix, aTagNamespaceURI, aStr, true), false);
     }
     PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement);
   }
 
-  count = aContent->GetAttrCount();
+  count = aElement->GetAttrCount();
 
   // Now serialize each of the attributes
   // XXX Unfortunately we need a namespace manager to get
   // attribute URIs.
   for (index = 0; index < count; index++) {
     if (aSkipAttr == index) {
         continue;
     }
 
-    const nsAttrName* name = aContent->GetAttrNameAt(index);
+    const nsAttrName* name = aElement->GetAttrNameAt(index);
     int32_t namespaceID = name->NamespaceID();
     nsAtom* attrName = name->LocalName();
     nsAtom* attrPrefix = name->GetPrefix();
 
     // Filter out any attribute starting with [-|_]moz
     nsDependentAtomString attrNameStr(attrName);
     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
@@ -858,20 +858,20 @@ nsXMLContentSerializer::SerializeAttribu
     }
 
     bool addNSAttr = false;
     if (kNameSpaceID_XMLNS != namespaceID) {
       nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     }
 
-    aContent->GetAttr(namespaceID, attrName, valueStr);
+    aElement->GetAttr(namespaceID, attrName, valueStr);
 
     nsDependentAtomString nameStr(attrName);
-    bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
+    bool isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
 
     NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
 
     if (addNSAttr) {
       NS_ASSERTION(!prefixStr.IsEmpty(),
                    "Namespaced attributes must have a prefix");
       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, true), false);
       PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement);
@@ -883,40 +883,39 @@ nsXMLContentSerializer::SerializeAttribu
 
 NS_IMETHODIMP
 nsXMLContentSerializer::AppendElementStart(Element* aElement,
                                            Element* aOriginalElement,
                                            nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
-  nsIContent* content = aElement;
-
   bool forceFormat = false;
   nsresult rv = NS_OK;
-  if (!CheckElementStart(content, forceFormat, aStr, rv)) {
+  if (!CheckElementStart(aElement, forceFormat, aStr, rv)) {
     // When we go to AppendElementEnd for this element, we're going to
     // MaybeLeaveFromPreContent().  So make sure to MaybeEnterInPreContent()
     // now, so our PreLevel() doesn't get confused.
-    MaybeEnterInPreContent(content);
+    MaybeEnterInPreContent(aElement);
     return rv;
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString tagPrefix, tagLocalName, tagNamespaceURI;
   aElement->NodeInfo()->GetPrefix(tagPrefix);
   aElement->NodeInfo()->GetName(tagLocalName);
   aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
 
-  uint32_t skipAttr = ScanNamespaceDeclarations(content,
-                          aOriginalElement, tagNamespaceURI);
+  uint32_t skipAttr =
+    ScanNamespaceDeclarations(aElement, aOriginalElement, tagNamespaceURI);
 
-  nsAtom *name = content->NodeInfo()->NameAtom();
-  bool lineBreakBeforeOpen = LineBreakBeforeOpen(content->GetNameSpaceID(), name);
+  nsAtom *name = aElement->NodeInfo()->NameAtom();
+  bool lineBreakBeforeOpen =
+    LineBreakBeforeOpen(aElement->GetNameSpaceID(), name);
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     if (mColPos && lineBreakBeforeOpen) {
       NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
     }
     else {
       NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
     }
@@ -947,35 +946,36 @@ nsXMLContentSerializer::AppendElementSta
   // Serialize the qualified name of the element
   NS_ENSURE_TRUE(AppendToString(kLessThan, aStr), NS_ERROR_OUT_OF_MEMORY);
   if (!tagPrefix.IsEmpty()) {
     NS_ENSURE_TRUE(AppendToString(tagPrefix, aStr), NS_ERROR_OUT_OF_MEMORY);
     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(":"), aStr), NS_ERROR_OUT_OF_MEMORY);
   }
   NS_ENSURE_TRUE(AppendToString(tagLocalName, aStr), NS_ERROR_OUT_OF_MEMORY);
 
-  MaybeEnterInPreContent(content);
+  MaybeEnterInPreContent(aElement);
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     NS_ENSURE_TRUE(IncrIndentation(name), NS_ERROR_OUT_OF_MEMORY);
   }
 
-  NS_ENSURE_TRUE(SerializeAttributes(content, aOriginalElement, tagPrefix, tagNamespaceURI,
-                                     name, aStr, skipAttr, addNSAttr),
+  NS_ENSURE_TRUE(SerializeAttributes(aElement, aOriginalElement, tagPrefix,
+                                     tagNamespaceURI, name, aStr, skipAttr,
+                                     addNSAttr),
                  NS_ERROR_OUT_OF_MEMORY);
 
   NS_ENSURE_TRUE(AppendEndOfElementStart(aElement, aOriginalElement, aStr),
                  NS_ERROR_OUT_OF_MEMORY);
 
   if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
-    && LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
+    && LineBreakAfterOpen(aElement->GetNameSpaceID(), name)) {
     NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
   }
 
-  NS_ENSURE_TRUE(AfterElementStart(content, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
+  NS_ENSURE_TRUE(AfterElementStart(aElement, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
 
 // aElement is the actual element we're outputting.  aOriginalElement is the one
 // in the original DOM, which is the one we have to test for kids.
 static bool
 ElementNeedsSeparateEndTag(Element* aElement, Element* aOriginalElement)
@@ -1140,18 +1140,18 @@ nsXMLContentSerializer::AppendDocumentSt
 
   NS_ENSURE_TRUE(aStr.AppendLiteral("?>", mozilla::fallible), NS_ERROR_OUT_OF_MEMORY);
   mAddNewlineForRootNode = true;
 
   return NS_OK;
 }
 
 bool
-nsXMLContentSerializer::CheckElementStart(nsIContent * aContent,
-                                          bool & aForceFormat,
+nsXMLContentSerializer::CheckElementStart(Element*,
+                                          bool& aForceFormat,
                                           nsAString& aStr,
                                           nsresult& aResult)
 {
   aResult = NS_OK;
   aForceFormat = false;
   return true;
 }
 
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -204,23 +204,23 @@ class nsXMLContentSerializer : public ns
                        const nsAString& aURI,
                        nsIContent* aElement,
                        bool aIsAttribute);
   /**
    * GenerateNewPrefix generates a new prefix and writes it to aPrefix
    */
   void GenerateNewPrefix(nsAString& aPrefix);
 
-  uint32_t ScanNamespaceDeclarations(nsIContent* aContent,
-                                     nsIContent *aOriginalElement,
+  uint32_t ScanNamespaceDeclarations(mozilla::dom::Element* aContent,
+                                     mozilla::dom::Element* aOriginalElement,
                                      const nsAString& aTagNamespaceURI);
 
   MOZ_MUST_USE
-  virtual bool SerializeAttributes(nsIContent* aContent,
-                                   nsIContent *aOriginalElement,
+  virtual bool SerializeAttributes(mozilla::dom::Element* aContent,
+                                   mozilla::dom::Element* aOriginalElement,
                                    nsAString& aTagPrefix,
                                    const nsAString& aTagNamespaceURI,
                                    nsAtom* aTagName,
                                    nsAString& aStr,
                                    uint32_t aSkipAttr,
                                    bool aAddNSAttr);
 
   MOZ_MUST_USE
@@ -238,20 +238,20 @@ class nsXMLContentSerializer : public ns
   /**
    * This method can be redefined to check if the element can be serialized.
    * It is called when the serialization of the start tag is asked
    * (AppendElementStart)
    * In this method you can also force the formating
    * by setting aForceFormat to true.
    * @return boolean  true if the element can be output
    */
-  virtual bool CheckElementStart(nsIContent * aContent,
-                                   bool & aForceFormat,
-                                   nsAString& aStr,
-                                   nsresult& aResult);
+  virtual bool CheckElementStart(Element* aElement,
+                                 bool & aForceFormat,
+                                 nsAString& aStr,
+                                 nsresult& aResult);
 
   /**
    * This method is responsible for appending the '>' at the end of the start
    * tag, possibly preceded by '/' and maybe a ' ' before that too.
    *
    * aElement and aOriginalElement are the same as the corresponding arguments
    * to AppendElementStart.
    */
--- a/dom/svg/SVGAElement.h
+++ b/dom/svg/SVGAElement.h
@@ -51,17 +51,17 @@ public:
                               bool aNullParent = true) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
   virtual int32_t TabIndexDefault() override;
   virtual bool IsSVGFocusable(bool* aIsFocusable, int32_t* aTabIndex) override;
   virtual bool IsLink(nsIURI** aURI) const override;
   virtual void GetLinkTarget(nsAString& aTarget) override;
   virtual already_AddRefed<nsIURI> GetHrefURI() const override;
   virtual EventStates IntrinsicState() const override;
-  using nsIContent::SetAttr;
+  using Element::SetAttr;
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
                            nsAtom* aPrefix, const nsAString& aValue,
                            nsIPrincipal* aSubjectPrincipal,
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
                              bool aNotify) override;
 
   // Link
--- a/dom/svg/SVGStyleElement.h
+++ b/dom/svg/SVGStyleElement.h
@@ -39,17 +39,17 @@ public:
                                            SVGStyleElementBase)
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
-  using nsIContent::SetAttr;
+  using Element::SetAttr;
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
                            nsAtom* aPrefix, const nsAString& aValue,
                            nsIPrincipal* aSubjectPrincipal,
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
                              bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsAtom* aAttribute,
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -257,17 +257,17 @@ nsXBLBinding::UnbindAnonymousContent(nsI
     if (xuldoc) {
       xuldoc->RemoveSubtreeFromDocument(child);
     }
 #endif
   }
 }
 
 void
-nsXBLBinding::SetBoundElement(nsIContent* aElement)
+nsXBLBinding::SetBoundElement(Element* aElement)
 {
   mBoundElement = aElement;
   if (mNextBinding)
     mNextBinding->SetBoundElement(aElement);
 
   if (!mBoundElement) {
     return;
   }
@@ -296,17 +296,17 @@ nsXBLBinding::HasStyleSheets() const
 
 void
 nsXBLBinding::GenerateAnonymousContent()
 {
   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                "Someone forgot a script blocker");
 
   // Fetch the content element for this binding.
-  nsIContent* content =
+  Element* content =
     mPrototypeBinding->GetImmediateChild(nsGkAtoms::content);
 
   if (!content) {
     // We have no anonymous content.
     if (mNextBinding)
       mNextBinding->GenerateAnonymousContent();
 
     return;
@@ -412,18 +412,22 @@ nsXBLBinding::GenerateAnonymousContent()
         nsAutoString value2;
         attrInfo.mValue->ToString(value2);
         mBoundElement->SetAttr(namespaceID, name, attrInfo.mName->GetPrefix(),
                                value2, false);
       }
     }
 
     // Conserve space by wiping the attributes off the clone.
+    //
+    // FIXME(emilio): It'd be nice to make `mContent` a `RefPtr<Element>`, but
+    // as of right now it can also be a ShadowRoot (we don't enter in this
+    // codepath though). Move Shadow DOM outside XBL and then fix that.
     if (mContent)
-      mContent->UnsetAttr(namespaceID, name, false);
+      mContent->AsElement()->UnsetAttr(namespaceID, name, false);
   }
 }
 
 nsIURI*
 nsXBLBinding::GetSourceDocURI()
 {
   nsIContent* targetContent =
     mPrototypeBinding->GetImmediateChild(nsGkAtoms::content);
--- a/dom/xbl/nsXBLBinding.h
+++ b/dom/xbl/nsXBLBinding.h
@@ -59,18 +59,18 @@ public:
 
   nsXBLPrototypeBinding* PrototypeBinding() const { return mPrototypeBinding; }
   nsIContent* GetAnonymousContent() { return mContent.get(); }
   nsXBLBinding* GetBindingWithContent();
 
   nsXBLBinding* GetBaseBinding() const { return mNextBinding; }
   void SetBaseBinding(nsXBLBinding *aBinding);
 
-  nsIContent* GetBoundElement() { return mBoundElement; }
-  void SetBoundElement(nsIContent *aElement);
+  mozilla::dom::Element* GetBoundElement() { return mBoundElement; }
+  void SetBoundElement(mozilla::dom::Element* aElement);
 
   /*
    * Does a lookup for a method or attribute provided by one of the bindings'
    * prototype implementation. If found, |desc| will be set up appropriately,
    * and wrapped into cx->compartment.
    *
    * May only be called when XBL code is being run in a separate scope, because
    * otherwise we don't have untainted data with which to do a proper lookup.
@@ -168,17 +168,17 @@ protected:
   bool mMarkedForDeath;
   bool mUsingContentXBLScope;
   bool mIsShadowRootBinding;
 
   nsXBLPrototypeBinding* mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
   nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
   RefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
 
-  nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
+  mozilla::dom::Element* mBoundElement; // [WEAK] We have a reference, but we don't own it.
 
   // The <xbl:children> elements that we found in our <xbl:content> when we
   // processed this binding. The default insertion point has no includes
   // attribute and all other insertion points must have at least one includes
   // attribute. These points must be up-to-date with respect to their parent's
   // children, even if their parent has another binding attached to it,
   // preventing us from rendering their contents directly.
   RefPtr<mozilla::dom::XBLChildrenElement> mDefaultInsertionPoint;
--- a/dom/xbl/nsXBLContentSink.cpp
+++ b/dom/xbl/nsXBLContentSink.cpp
@@ -530,17 +530,18 @@ nsXBLContentSink::OnOpenContainer(const 
   return ret && mState != eXBL_InResources && mState != eXBL_InImplementation;
 }
 
 #undef ENSURE_XBL_STATE
 
 nsresult
 nsXBLContentSink::ConstructBinding(uint32_t aLineNumber)
 {
-  nsCOMPtr<nsIContent> binding = GetCurrentContent();
+  // This is only called from HandleStartElement, so it'd better be an element.
+  RefPtr<Element> binding = GetCurrentContent()->AsElement();
   binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID);
   NS_ConvertUTF16toUTF8 cid(mCurrentBindingID);
 
   nsresult rv = NS_OK;
 
   // Don't create a binding with no id. nsXBLPrototypeBinding::Read also
   // performs this check.
   if (!cid.IsEmpty()) {
@@ -875,23 +876,22 @@ nsXBLContentSink::CreateElement(const ch
   Element* result;
   nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result);
   *aResult = result;
   return rv;
 #endif
 }
 
 nsresult
-nsXBLContentSink::AddAttributes(const char16_t** aAtts,
-                                nsIContent* aContent)
+nsXBLContentSink::AddAttributes(const char16_t** aAtts, Element* aElement)
 {
-  if (aContent->IsXULElement())
+  if (aElement->IsXULElement())
     return NS_OK; // Nothing to do, since the proto already has the attrs.
 
-  return nsXMLContentSink::AddAttributes(aAtts, aContent);
+  return nsXMLContentSink::AddAttributes(aAtts, aElement);
 }
 
 #ifdef MOZ_XUL
 nsresult
 nsXBLContentSink::AddAttributesToXULPrototype(const char16_t **aAtts,
                                               uint32_t aAttsCount,
                                               nsXULPrototypeElement* aElement)
 {
--- a/dom/xbl/nsXBLContentSink.h
+++ b/dom/xbl/nsXBLContentSink.h
@@ -87,18 +87,17 @@ protected:
 
     bool NotifyForDocElement() override { return false; }
 
     nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
                            mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
                            nsIContent** aResult, bool* aAppendContent,
                            mozilla::dom::FromParser aFromParser) override;
 
-    nsresult AddAttributes(const char16_t** aAtts,
-                           nsIContent* aContent) override;
+    nsresult AddAttributes(const char16_t** aAtts, Element* aElement) override;
 
 #ifdef MOZ_XUL
     nsresult AddAttributesToXULPrototype(const char16_t **aAtts,
                                          uint32_t aAttsCount,
                                          nsXULPrototypeElement* aElement);
 #endif
 
     // Our own helpers for constructing XBL prototype objects.
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -57,38 +57,38 @@ using namespace mozilla::dom;
 // Helper Classes =====================================================================
 
 // nsXBLAttributeEntry and helpers.  This class is used to efficiently handle
 // attribute changes in anonymous content.
 
 class nsXBLAttributeEntry {
 public:
   nsXBLAttributeEntry(nsAtom* aSrcAtom, nsAtom* aDstAtom,
-                      int32_t aDstNameSpace, nsIContent* aContent)
-    : mElement(aContent),
+                      int32_t aDstNameSpace, Element* aElement)
+    : mElement(aElement),
       mSrcAttribute(aSrcAtom),
       mDstAttribute(aDstAtom),
       mDstNameSpace(aDstNameSpace),
       mNext(nullptr) { }
 
   ~nsXBLAttributeEntry() {
     NS_CONTENT_DELETE_LIST_MEMBER(nsXBLAttributeEntry, this, mNext);
   }
 
   nsAtom* GetSrcAttribute() { return mSrcAttribute; }
   nsAtom* GetDstAttribute() { return mDstAttribute; }
   int32_t GetDstNameSpace() { return mDstNameSpace; }
 
-  nsIContent* GetElement() { return mElement; }
+  Element* GetElement() { return mElement; }
 
   nsXBLAttributeEntry* GetNext() { return mNext; }
   void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; }
 
 protected:
-  nsIContent* mElement;
+  Element* mElement;
 
   RefPtr<nsAtom> mSrcAttribute;
   RefPtr<nsAtom> mDstAttribute;
   int32_t mDstNameSpace;
   nsXBLAttributeEntry* mNext;
 };
 
 // =============================================================================
@@ -108,17 +108,17 @@ nsXBLPrototypeBinding::nsXBLPrototypeBin
   mBaseNameSpaceID(kNameSpaceID_None)
 {
   MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
 }
 
 nsresult
 nsXBLPrototypeBinding::Init(const nsACString& aID,
                             nsXBLDocumentInfo* aInfo,
-                            nsIContent* aElement,
+                            Element* aElement,
                             bool aFirstBinding)
 {
   nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The binding URI might be an immutable URI (e.g. for about: URIs). In that case,
   // we'll fail in SetRef below, but that doesn't matter much for now.
   if (aFirstBinding) {
@@ -175,18 +175,17 @@ nsXBLPrototypeBinding::Trace(const Trace
 {
   if (mImplementation)
     mImplementation->Trace(aCallbacks, aClosure);
 }
 
 void
 nsXBLPrototypeBinding::Initialize()
 {
-  nsIContent* content = GetImmediateChild(nsGkAtoms::content);
-  if (content) {
+  if (Element* content = GetImmediateChild(nsGkAtoms::content)) {
     ConstructAttributeTable(content);
   }
 }
 
 nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
 {
   delete mImplementation;
   MOZ_COUNT_DTOR(nsXBLPrototypeBinding);
@@ -202,17 +201,17 @@ nsXBLPrototypeBinding::SetBasePrototype(
     NS_ERROR("Base XBL prototype binding is already defined!");
     return;
   }
 
   mBaseBinding = aBinding;
 }
 
 void
-nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
+nsXBLPrototypeBinding::SetBindingElement(Element* aElement)
 {
   mBinding = aElement;
   if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle,
                             nsGkAtoms::_false, eCaseMatters))
     mInheritStyle = false;
 
   mChromeOnlyContent = mBinding->AttrValueIs(kNameSpaceID_None,
                                              nsGkAtoms::chromeOnlyContent,
@@ -318,39 +317,38 @@ nsXBLPrototypeBinding::InstallImplementa
   return NS_OK;
 }
 
 // XXXbz this duplicates lots of SetAttrs
 void
 nsXBLPrototypeBinding::AttributeChanged(nsAtom* aAttribute,
                                         int32_t aNameSpaceID,
                                         bool aRemoveFlag,
-                                        nsIContent* aChangedElement,
+                                        Element* aChangedElement,
                                         nsIContent* aAnonymousContent,
                                         bool aNotify)
 {
   if (!mAttributeTable)
     return;
 
   InnerAttributeTable *attributesNS = mAttributeTable->Get(aNameSpaceID);
   if (!attributesNS)
     return;
 
   nsXBLAttributeEntry* xblAttr = attributesNS->Get(aAttribute);
   if (!xblAttr)
     return;
 
   // Iterate over the elements in the array.
-  nsCOMPtr<nsIContent> content = GetImmediateChild(nsGkAtoms::content);
+  RefPtr<Element> content = GetImmediateChild(nsGkAtoms::content);
   while (xblAttr) {
-    nsIContent* element = xblAttr->GetElement();
+    Element* element = xblAttr->GetElement();
 
-    nsCOMPtr<nsIContent> realElement = LocateInstance(aChangedElement, content,
-                                                      aAnonymousContent,
-                                                      element);
+    RefPtr<Element> realElement =
+      LocateInstance(aChangedElement, content, aAnonymousContent, element);
 
     if (realElement) {
       // Hold a strong reference here so that the atom doesn't go away during
       // UnsetAttr.
       RefPtr<nsAtom> dstAttr = xblAttr->GetDstAttribute();
       int32_t dstNs = xblAttr->GetDstNameSpace();
 
       if (aRemoveFlag)
@@ -431,24 +429,24 @@ bool
 nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const
 {
   // Check our IID table.
   return !!mInterfaceTable.GetWeak(aIID);
 }
 
 // Internal helpers ///////////////////////////////////////////////////////////////////////
 
-nsIContent*
+Element*
 nsXBLPrototypeBinding::GetImmediateChild(nsAtom* aTag)
 {
   for (nsIContent* child = mBinding->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     if (child->NodeInfo()->Equals(aTag, kNameSpaceID_XBL)) {
-      return child;
+      return child->AsElement();
     }
   }
 
   return nullptr;
 }
 
 nsresult
 nsXBLPrototypeBinding::InitClass(const nsString& aClassName,
@@ -456,45 +454,51 @@ nsXBLPrototypeBinding::InitClass(const n
                                  JS::Handle<JSObject*> aScriptObject,
                                  JS::MutableHandle<JSObject*> aClassObject,
                                  bool* aNew)
 {
   return nsXBLBinding::DoInitJSClass(aContext, aScriptObject,
                                      aClassName, this, aClassObject, aNew);
 }
 
-nsIContent*
-nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
+Element*
+nsXBLPrototypeBinding::LocateInstance(Element* aBoundElement,
                                       nsIContent* aTemplRoot,
                                       nsIContent* aCopyRoot,
-                                      nsIContent* aTemplChild)
+                                      Element* aTemplChild)
 {
   // XXX We will get in trouble if the binding instantiation deviates from the template
   // in the prototype.
   if (aTemplChild == aTemplRoot || !aTemplChild)
     return nullptr;
 
-  nsIContent* templParent = aTemplChild->GetParent();
+  Element* templParent = aTemplChild->GetParentElement();
 
   // We may be disconnected from our parent during cycle collection.
   if (!templParent)
     return nullptr;
 
   nsIContent *copyParent =
     templParent == aTemplRoot ? aCopyRoot :
                    LocateInstance(aBoundElement, aTemplRoot, aCopyRoot, templParent);
 
   if (!copyParent)
     return nullptr;
 
-  return copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
+  nsIContent* child = copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
+  if (child && child->IsElement()) {
+    return child->AsElement();
+  }
+  return nullptr;
 }
 
 void
-nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
+nsXBLPrototypeBinding::SetInitialAttributes(
+    Element* aBoundElement,
+    nsIContent* aAnonymousContent)
 {
   if (!mAttributeTable) {
     return;
   }
 
   for (auto iter1 = mAttributeTable->Iter(); !iter1.Done(); iter1.Next()) {
     InnerAttributeTable* xblAttributes = iter1.UserData();
     if (xblAttributes) {
@@ -523,19 +527,19 @@ nsXBLPrototypeBinding::SetInitialAttribu
 
         if (attrPresent) {
           nsIContent* content = GetImmediateChild(nsGkAtoms::content);
 
           nsXBLAttributeEntry* curr = entry;
           while (curr) {
             nsAtom* dst = curr->GetDstAttribute();
             int32_t dstNs = curr->GetDstNameSpace();
-            nsIContent* element = curr->GetElement();
+            Element* element = curr->GetElement();
 
-            nsIContent* realElement =
+            Element* realElement =
               LocateInstance(aBoundElement, content,
                              aAnonymousContent, element);
 
             if (realElement) {
               realElement->SetAttr(dstNs, dst, value, false);
 
               // XXXndeakin shouldn't this be done in lieu of SetAttr?
               if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
@@ -590,39 +594,39 @@ nsXBLPrototypeBinding::EnsureAttributeTa
     mAttributeTable =
         new nsClassHashtable<nsUint32HashKey, InnerAttributeTable>(2);
   }
 }
 
 void
 nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* aSourceTag,
                                            int32_t aDestNamespaceID, nsAtom* aDestTag,
-                                           nsIContent* aContent)
+                                           Element* aElement)
 {
     InnerAttributeTable* attributesNS = mAttributeTable->Get(aSourceNamespaceID);
     if (!attributesNS) {
       attributesNS = new InnerAttributeTable(2);
       mAttributeTable->Put(aSourceNamespaceID, attributesNS);
     }
 
     nsXBLAttributeEntry* xblAttr =
-      new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aContent);
+      new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aElement);
 
     nsXBLAttributeEntry* entry = attributesNS->Get(aSourceTag);
     if (!entry) {
       attributesNS->Put(aSourceTag, xblAttr);
     } else {
       while (entry->GetNext())
         entry = entry->GetNext();
       entry->SetNext(xblAttr);
     }
 }
 
 void
-nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
+nsXBLPrototypeBinding::ConstructAttributeTable(Element* aElement)
 {
   // Don't add entries for <children> elements, since those will get
   // removed from the DOM when we construct the insertion point table.
   if (!aElement->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
     nsAutoString inherits;
     aElement->GetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, inherits);
 
     if (!inherits.IsEmpty()) {
@@ -687,17 +691,19 @@ nsXBLPrototypeBinding::ConstructAttribut
       free(str);
     }
   }
 
   // Recur into our children.
   for (nsIContent* child = aElement->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
-    ConstructAttributeTable(child);
+    if (child->IsElement()) {
+      ConstructAttributeTable(child->AsElement());
+    }
   }
 }
 
 nsresult
 nsXBLPrototypeBinding::ConstructInterfaceTable(const nsAString& aImpls)
 {
   if (!aImpls.IsEmpty()) {
     // Obtain the interface info manager that can tell us the IID
@@ -1190,22 +1196,21 @@ nsXBLPrototypeBinding::ReadContentNode(n
   int32_t namespaceID;
   nsresult rv = ReadNamespace(aStream, namespaceID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // There is no content to read so just return.
   if (namespaceID == XBLBinding_Serialize_NoContent)
     return NS_OK;
 
-  nsCOMPtr<nsIContent> content;
-
   // If this is a text type, just read the string and return.
   if (namespaceID == XBLBinding_Serialize_TextNode ||
       namespaceID == XBLBinding_Serialize_CDATANode ||
       namespaceID == XBLBinding_Serialize_CommentNode) {
+    nsCOMPtr<nsIContent> content;
     switch (namespaceID) {
       case XBLBinding_Serialize_TextNode:
         content = new nsTextNode(aNim);
         break;
       case XBLBinding_Serialize_CDATANode:
         content = new CDATASection(aNim);
         break;
       case XBLBinding_Serialize_CommentNode:
@@ -1239,16 +1244,17 @@ nsXBLPrototypeBinding::ReadContentNode(n
   RefPtr<nsAtom> tagAtom = NS_Atomize(tag);
   RefPtr<NodeInfo> nodeInfo =
     aNim->GetNodeInfo(tagAtom, prefixAtom, namespaceID, nsIDOMNode::ELEMENT_NODE);
 
   uint32_t attrCount;
   rv = aStream->Read32(&attrCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  RefPtr<Element> element;
   // Create XUL prototype elements, or regular elements for other namespaces.
   // This needs to match the code in nsXBLContentSink::CreateElement.
 #ifdef MOZ_XUL
   if (namespaceID == kNameSpaceID_XUL) {
     nsIURI* documentURI = aDocument->GetDocumentURI();
 
     RefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
 
@@ -1288,27 +1294,22 @@ nsXBLPrototypeBinding::ReadContentNode(n
                             namespaceID, nsIDOMNode::ATTRIBUTE_NODE);
         attrs[i].mName.SetTo(ni);
       }
 
       rv = prototype->SetAttrAt(i, val, documentURI);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    nsCOMPtr<Element> result;
     nsresult rv =
-      nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(result));
+      nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(element));
     NS_ENSURE_SUCCESS(rv, rv);
-    content = result;
-  }
-  else {
+  } else {
 #endif
-    nsCOMPtr<Element> element;
     NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), NOT_FROM_PARSER);
-    content = element;
 
     for (uint32_t i = 0; i < attrCount; i++) {
       rv = ReadNamespace(aStream, namespaceID);
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsAutoString prefix, name, val;
       rv = aStream->ReadString(prefix);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -1317,17 +1318,17 @@ nsXBLPrototypeBinding::ReadContentNode(n
       rv = aStream->ReadString(val);
       NS_ENSURE_SUCCESS(rv, rv);
 
       RefPtr<nsAtom> prefixAtom;
       if (!prefix.IsEmpty())
         prefixAtom = NS_Atomize(prefix);
 
       RefPtr<nsAtom> nameAtom = NS_Atomize(name);
-      content->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
+      element->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
     }
 
 #ifdef MOZ_XUL
   }
 #endif
 
   // Now read the attribute forwarding entries (xbl:inherits)
 
@@ -1343,38 +1344,38 @@ nsXBLPrototypeBinding::ReadContentNode(n
     NS_ENSURE_SUCCESS(rv, rv);
     rv = aStream->ReadString(destAttribute);
     NS_ENSURE_SUCCESS(rv, rv);
 
     RefPtr<nsAtom> srcAtom = NS_Atomize(srcAttribute);
     RefPtr<nsAtom> destAtom = NS_Atomize(destAttribute);
 
     EnsureAttributeTable();
-    AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, content);
+    AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, element);
 
     rv = ReadNamespace(aStream, srcNamespaceID);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Finally, read in the child nodes.
   uint32_t childCount;
   rv = aStream->Read32(&childCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (uint32_t i = 0; i < childCount; i++) {
     nsCOMPtr<nsIContent> child;
     ReadContentNode(aStream, aDocument, aNim, getter_AddRefs(child));
 
     // Child may be null if this was a comment for example and can just be ignored.
     if (child) {
-      content->AppendChildTo(child, false);
+      element->AppendChildTo(child, false);
     }
   }
 
-  content.swap(*aContent);
+  element.forget(aContent);
   return NS_OK;
 }
 
 nsresult
 nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
                                         nsIContent* aNode)
 {
   nsresult rv;
@@ -1400,40 +1401,41 @@ nsXBLPrototypeBinding::WriteContentNode(
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoString content;
     aNode->GetText()->AppendTo(content);
     return aStream->WriteWStringZ(content.get());
   }
 
   // Otherwise, this is an element.
+  Element* element = aNode->AsElement();
 
   // Write the namespace id followed by the tag name
-  rv = WriteNamespace(aStream, aNode->GetNameSpaceID());
+  rv = WriteNamespace(aStream, element->GetNameSpaceID());
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString prefixStr;
-  aNode->NodeInfo()->GetPrefix(prefixStr);
+  element->NodeInfo()->GetPrefix(prefixStr);
   rv = aStream->WriteWStringZ(prefixStr.get());
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aStream->WriteWStringZ(nsDependentAtomString(aNode->NodeInfo()->NameAtom()).get());
+  rv = aStream->WriteWStringZ(nsDependentAtomString(element->NodeInfo()->NameAtom()).get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Write attributes
-  uint32_t count = aNode->GetAttrCount();
+  uint32_t count = element->GetAttrCount();
   rv = aStream->Write32(count);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t i;
   for (i = 0; i < count; i++) {
     // Write out the namespace id, the namespace prefix, the local tag name,
     // and the value, in that order.
 
-    const BorrowedAttrInfo attrInfo = aNode->GetAttrInfoAt(i);
+    const BorrowedAttrInfo attrInfo = element->GetAttrInfoAt(i);
     const nsAttrName* name = attrInfo.mName;
 
     // XXXndeakin don't write out xbl:inherits?
     int32_t namespaceID = name->NamespaceID();
     rv = WriteNamespace(aStream, namespaceID);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoString prefixStr;
@@ -1457,17 +1459,17 @@ nsXBLPrototypeBinding::WriteContentNode(
     for (auto iter1 = mAttributeTable->Iter(); !iter1.Done(); iter1.Next()) {
       int32_t srcNamespace = iter1.Key();
       InnerAttributeTable* xblAttributes = iter1.UserData();
 
       for (auto iter2 = xblAttributes->Iter(); !iter2.Done(); iter2.Next()) {
         nsXBLAttributeEntry* entry = iter2.UserData();
 
         do {
-          if (entry->GetElement() == aNode) {
+          if (entry->GetElement() == element) {
             WriteNamespace(aStream, srcNamespace);
             aStream->WriteWStringZ(
               nsDependentAtomString(entry->GetSrcAttribute()).get());
             WriteNamespace(aStream, entry->GetDstNameSpace());
             aStream->WriteWStringZ(
               nsDependentAtomString(entry->GetDstAttribute()).get());
           }
 
@@ -1475,22 +1477,22 @@ nsXBLPrototypeBinding::WriteContentNode(
         } while (entry);
       }
     }
   }
   rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Finally, write out the child nodes.
-  count = aNode->GetChildCount();
+  count = element->GetChildCount();
   rv = aStream->Write32(count);
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (i = 0; i < count; i++) {
-    rv = WriteContentNode(aStream, aNode->GetChildAt(i));
+    rv = WriteContentNode(aStream, element->GetChildAt(i));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLPrototypeBinding::ReadNamespace(nsIObjectInputStream* aStream,
--- a/dom/xbl/nsXBLPrototypeBinding.h
+++ b/dom/xbl/nsXBLPrototypeBinding.h
@@ -36,18 +36,18 @@ class nsXBLProtoImplField;
 // by XBLDocumentInfo().  Consumers who want to refcount things should refcount
 // that.
 class nsXBLPrototypeBinding final :
   public mozilla::SupportsWeakPtr<nsXBLPrototypeBinding>
 {
 public:
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsXBLPrototypeBinding)
 
-  nsIContent* GetBindingElement() const { return mBinding; }
-  void SetBindingElement(nsIContent* aElement);
+  mozilla::dom::Element* GetBindingElement() const { return mBinding; }
+  void SetBindingElement(mozilla::dom::Element* aElement);
 
   nsIURI* BindingURI() const { return mBindingURI; }
   nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; }
   nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); }
   nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; }
 
   // Checks if aURI refers to this binding by comparing to both possible
   // binding URIs.
@@ -106,26 +106,28 @@ public:
   nsresult ConstructInterfaceTable(const nsAString& aImpls);
 
   void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
   nsXBLProtoImpl* GetImplementation() { return mImplementation; }
   nsresult InstallImplementation(nsXBLBinding* aBinding);
   bool HasImplementation() const { return mImplementation != nullptr; }
 
   void AttributeChanged(nsAtom* aAttribute, int32_t aNameSpaceID,
-                        bool aRemoveFlag, nsIContent* aChangedElement,
+                        bool aRemoveFlag,
+                        mozilla::dom::Element* aChangedElement,
                         nsIContent* aAnonymousContent, bool aNotify);
 
   void SetBasePrototype(nsXBLPrototypeBinding* aBinding);
   nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; }
 
   nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; }
   bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); }
 
-  void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
+  void SetInitialAttributes(mozilla::dom::Element* aBoundElement,
+                            nsIContent* aAnonymousContent);
 
   void AppendStyleSheet(mozilla::StyleSheet* aSheet);
   void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
   void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
   mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
   size_t SheetCount() const;
   bool HasStyleSheets() const;
   void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
@@ -241,58 +243,58 @@ public:
   ~nsXBLPrototypeBinding();
 
   // Init must be called after construction to initialize the prototype
   // binding.  It may well throw errors (eg on out-of-memory).  Do not confuse
   // this with the Initialize() method, which must be called after the
   // binding's handlers, properties, etc are all set.
   nsresult Init(const nsACString& aRef,
                 nsXBLDocumentInfo* aInfo,
-                nsIContent* aElement,
+                mozilla::dom::Element* aElement,
                 bool aFirstBinding = false);
 
   void Traverse(nsCycleCollectionTraversalCallback &cb) const;
   void Unlink();
   void Trace(const TraceCallbacks& aCallbacks, void *aClosure) const;
 
 // Internal member functions.
 public:
   /**
    * GetImmediateChild locates the immediate child of our binding element which
    * has the localname given by aTag and is in the XBL namespace.
    */
-  nsIContent* GetImmediateChild(nsAtom* aTag);
-  nsIContent* LocateInstance(nsIContent* aBoundElt,
-                             nsIContent* aTemplRoot,
-                             nsIContent* aCopyRoot,
-                             nsIContent* aTemplChild);
+  mozilla::dom::Element* GetImmediateChild(nsAtom* aTag);
+  mozilla::dom::Element* LocateInstance(mozilla::dom::Element* aBoundElt,
+                                        nsIContent* aTemplRoot,
+                                        nsIContent* aCopyRoot,
+                                        mozilla::dom::Element* aTemplChild);
 
   bool ChromeOnlyContent() { return mChromeOnlyContent; }
   bool BindToUntrustedContent() { return mBindToUntrustedContent; }
 
   typedef nsClassHashtable<nsRefPtrHashKey<nsAtom>, nsXBLAttributeEntry> InnerAttributeTable;
 
 protected:
   // Ensure that mAttributeTable has been created.
   void EnsureAttributeTable();
   // Ad an entry to the attribute table
   void AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* aSourceTag,
                            int32_t aDestNamespaceID, nsAtom* aDestTag,
-                           nsIContent* aContent);
-  void ConstructAttributeTable(nsIContent* aElement);
+                           mozilla::dom::Element* aContent);
+  void ConstructAttributeTable(mozilla::dom::Element* aElement);
   void CreateKeyHandlers();
 
 private:
   void EnsureResources();
 
 // MEMBER VARIABLES
 protected:
   nsCOMPtr<nsIURI> mBindingURI;
   nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only non-null on the first binding.
-  nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
+  RefPtr<mozilla::dom::Element> mBinding; // Strong. We own a ref to our content element in the binding doc.
   nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
 
   // the url of the base binding
   nsCOMPtr<nsIURI> mBaseBindingURI;
 
   nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields,
                                    // the constructor, and the destructor).
 
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -474,89 +474,89 @@ private:
   Element* mElement;
   bool mHadData;
   bool* mResolveStyle;
 };
 
 // This function loads a particular XBL file and installs all of the bindings
 // onto the element.
 nsresult
-nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
+nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
                            nsIPrincipal* aOriginPrincipal,
                            nsXBLBinding** aBinding, bool* aResolveStyle)
 {
   NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
 
   *aBinding = nullptr;
   *aResolveStyle = false;
 
-  AutoEnsureSubtreeStyled subtreeStyled(aContent->AsElement());
+  AutoEnsureSubtreeStyled subtreeStyled(aElement);
 
   if (MOZ_UNLIKELY(!aURL)) {
     return NS_OK;
   }
 
   // Easy case: The binding was already loaded.
-  nsXBLBinding* binding = aContent->GetXBLBinding();
+  nsXBLBinding* binding = aElement->GetXBLBinding();
   if (binding && !binding->MarkedForDeath() &&
       binding->PrototypeBinding()->CompareBindingURI(aURL)) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
+  nsCOMPtr<nsIDocument> document = aElement->OwnerDoc();
 
   nsAutoCString urlspec;
   nsresult rv;
   bool ok = nsContentUtils::GetWrapperSafeScriptFilename(document, aURL,
                                                          urlspec, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (ok) {
     // Block an attempt to load a binding that has special wrapper
     // automation needs.
     return NS_OK;
   }
 
   if (binding) {
-    FlushStyleBindings(aContent);
+    FlushStyleBindings(aElement);
     binding = nullptr;
   }
 
   bool ready;
   RefPtr<nsXBLBinding> newBinding;
-  if (NS_FAILED(rv = GetBinding(aContent, aURL, false, aOriginPrincipal,
+  if (NS_FAILED(rv = GetBinding(aElement, aURL, false, aOriginPrincipal,
                                 &ready, getter_AddRefs(newBinding)))) {
     return rv;
   }
 
   if (!newBinding) {
 #ifdef DEBUG
     nsAutoCString str(NS_LITERAL_CSTRING("Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over.  The invalid binding name is: ") + aURL->GetSpecOrDefault());
     NS_ERROR(str.get());
 #endif
     return NS_OK;
   }
 
-  if (::IsAncestorBinding(document, aURL, aContent)) {
+  if (::IsAncestorBinding(document, aURL, aElement)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
-  AutoStyleElement styleElement(aContent->AsElement(), aResolveStyle);
+  AutoStyleElement styleElement(aElement, aResolveStyle);
 
   // We loaded a style binding.  It goes on the end.
   // Install the binding on the content node.
-  aContent->SetXBLBinding(newBinding);
+  aElement->SetXBLBinding(newBinding);
 
   {
     nsAutoScriptBlocker scriptBlocker;
 
     // Set the binding's bound element.
-    newBinding->SetBoundElement(aContent);
+    newBinding->SetBoundElement(aElement);
 
     // Tell the binding to build the anonymous content.
     newBinding->GenerateAnonymousContent();
 
     // Tell the binding to install event handlers
     newBinding->InstallEventHandlers();
 
     // Set up our properties
@@ -567,30 +567,28 @@ nsXBLService::LoadBindings(nsIContent* a
     *aResolveStyle = newBinding->HasStyleSheets();
 
     newBinding.forget(aBinding);
   }
 
   return NS_OK;
 }
 
-nsresult
-nsXBLService::FlushStyleBindings(nsIContent* aContent)
+void
+nsXBLService::FlushStyleBindings(Element* aElement)
 {
-  nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
+  nsCOMPtr<nsIDocument> document = aElement->OwnerDoc();
 
-  nsXBLBinding *binding = aContent->GetXBLBinding();
+  nsXBLBinding* binding = aElement->GetXBLBinding();
   if (binding) {
     // Clear out the script references.
     binding->ChangeDocument(document, nullptr);
 
-    aContent->SetXBLBinding(nullptr); // Flush old style bindings
+    aElement->SetXBLBinding(nullptr); // Flush old style bindings
   }
-
-  return NS_OK;
 }
 
 //
 // AttachGlobalKeyHandler
 //
 // Creates a new key handler and prepares to listen to key events on the given
 // event receiver (either a document or an content node). If the receiver is content,
 // then extra work needs to be done to hook it up to the document (XXX WHY??)
--- a/dom/xbl/nsXBLService.h
+++ b/dom/xbl/nsXBLService.h
@@ -41,17 +41,17 @@ class nsXBLService final : public nsSupp
   }
 
   static nsXBLService* GetInstance() { return gInstance; }
 
   static bool IsChromeOrResourceURI(nsIURI* aURI);
 
   // This function loads a particular XBL file and installs all of the bindings
   // onto the element.  aOriginPrincipal must not be null here.
-  nsresult LoadBindings(nsIContent* aContent, nsIURI* aURL,
+  nsresult LoadBindings(mozilla::dom::Element* aElement, nsIURI* aURL,
                         nsIPrincipal* aOriginPrincipal,
                         nsXBLBinding** aBinding, bool* aResolveStyle);
 
   // Indicates whether or not a binding is fully loaded.
   nsresult BindingReady(nsIContent* aBoundElement, nsIURI* aURI, bool* aIsReady);
 
   // This method checks the hashtable and then calls FetchBindingDocument on a
   // miss.  aOriginPrincipal or aBoundDocument may be null to bypass security
@@ -67,18 +67,18 @@ class nsXBLService final : public nsSupp
   static nsresult AttachGlobalKeyHandler(mozilla::dom::EventTarget* aTarget);
   static nsresult DetachGlobalKeyHandler(mozilla::dom::EventTarget* aTarget);
 
 private:
   nsXBLService();
   virtual ~nsXBLService();
 
 protected:
-  // This function clears out the bindings on a given content node.
-  nsresult FlushStyleBindings(nsIContent* aContent);
+  // This function clears out the bindings on a given element.
+  void FlushStyleBindings(mozilla::dom::Element*);
 
   // This method synchronously loads and parses an XBL file.
   nsresult FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
                                 nsIURI* aDocumentURI, nsIURI* aBindingURI,
                                 nsIPrincipal* aOriginPrincipal, bool aForceSyncLoad,
                                 nsIDocument** aResult);
 
   /**
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -975,17 +975,17 @@ nsXMLContentSink::HandleStartElement(con
   // on the stack inside CreateElement (which is effectively what the HTML sink
   // does), but that's hard with all the subclass overrides going on.
   nsCOMPtr<nsIContent> parent = GetCurrentContent();
 
   result = PushContent(content);
   NS_ENSURE_SUCCESS(result, result);
 
   // Set the attributes on the new content element
-  result = AddAttributes(aAtts, content);
+  result = AddAttributes(aAtts, content->AsElement());
 
   if (NS_OK == result) {
     // Store the element
     if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
       NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
 
       parent->AppendChildTo(content, false);
     }
@@ -1408,17 +1408,17 @@ nsXMLContentSink::ReportError(const char
 
   FlushTags();
 
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSink::AddAttributes(const char16_t** aAtts,
-                                nsIContent* aContent)
+                                Element* aContent)
 {
   // Add tag attributes to the content attributes
   RefPtr<nsAtom> prefix, localName;
   while (*aAtts) {
     int32_t nameSpaceID;
     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
                                    getter_AddRefs(localName), &nameSpaceID);
 
--- a/dom/xml/nsXMLContentSink.h
+++ b/dom/xml/nsXMLContentSink.h
@@ -94,17 +94,17 @@ protected:
 
   void ContinueInterruptedParsingIfEnabled();
 
   // Start layout.  If aIgnorePendingSheets is true, this will happen even if
   // we still have stylesheet loads pending.  Otherwise, we'll wait until the
   // stylesheets are all done loading.
   virtual void MaybeStartLayout(bool aIgnorePendingSheets);
 
-  virtual nsresult AddAttributes(const char16_t** aNode, nsIContent* aContent);
+  virtual nsresult AddAttributes(const char16_t** aNode, Element* aElement);
   nsresult AddText(const char16_t* aString, int32_t aLength);
 
   virtual bool OnOpenContainer(const char16_t **aAtts,
                                  uint32_t aAttsCount,
                                  int32_t aNameSpaceID,
                                  nsAtom* aTagName,
                                  uint32_t aLineNumber) { return true; }
   // Set the given content as the root element for the created document
--- a/dom/xml/nsXMLPrettyPrinter.cpp
+++ b/dom/xml/nsXMLPrettyPrinter.cpp
@@ -139,51 +139,51 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocum
 
     // Compute the binding URI.
     nsCOMPtr<nsIURI> bindingUri;
     rv = NS_NewURI(getter_AddRefs(bindingUri),
         NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Compute the bound element.
-    nsCOMPtr<nsIContent> rootCont = aDocument->GetRootElement();
-    NS_ENSURE_TRUE(rootCont, NS_ERROR_UNEXPECTED);
+    RefPtr<Element> rootElement = aDocument->GetRootElement();
+    NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED);
 
     // Grab the system principal.
     nsCOMPtr<nsIPrincipal> sysPrincipal;
     nsContentUtils::GetSecurityManager()->
         GetSystemPrincipal(getter_AddRefs(sysPrincipal));
 
     // Destroy any existing frames before we unbind anonymous content.
     // Note that the shell might be Destroy'ed by now (see bug 1415541).
-    if (!shell->IsDestroying() && rootCont->IsElement()) {
-        shell->DestroyFramesForAndRestyle(rootCont->AsElement());
+    if (!shell->IsDestroying()) {
+        shell->DestroyFramesForAndRestyle(rootElement);
     }
 
     // Load the bindings.
     RefPtr<nsXBLBinding> unused;
     bool ignored;
-    rv = xblService->LoadBindings(rootCont, bindingUri, sysPrincipal,
+    rv = xblService->LoadBindings(rootElement, bindingUri, sysPrincipal,
                                   getter_AddRefs(unused), &ignored);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Fire an event at the bound element to pass it |resultFragment|.
     RefPtr<CustomEvent> event =
-      NS_NewDOMCustomEvent(rootCont, nullptr, nullptr);
+      NS_NewDOMCustomEvent(rootElement, nullptr, nullptr);
     MOZ_ASSERT(event);
     nsCOMPtr<nsIWritableVariant> resultFragmentVariant = new nsVariant();
     rv = resultFragmentVariant->SetAsISupports(resultFragment);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     rv = event->InitCustomEvent(NS_LITERAL_STRING("prettyprint-dom-created"),
                                 /* bubbles = */ false, /* cancelable = */ false,
                                 /* detail = */ resultFragmentVariant);
     NS_ENSURE_SUCCESS(rv, rv);
     event->SetTrusted(true);
     bool dummy;
-    rv = rootCont->DispatchEvent(event, &dummy);
+    rv = rootElement->DispatchEvent(event, &dummy);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Observe the document so we know when to switch to "normal" view
     aDocument->AddObserver(this);
     mDocument = aDocument;
 
     NS_ADDREF_THIS();
 
--- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
+++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
@@ -115,45 +115,52 @@ txXPathTreeWalker::moveToNextAttribute()
     return moveToValidAttribute(mPosition.mIndex + 1);
 }
 
 bool
 txXPathTreeWalker::moveToValidAttribute(uint32_t aStartIndex)
 {
     NS_ASSERTION(!mPosition.isDocument(), "documents doesn't have attrs");
 
-    uint32_t total = mPosition.Content()->GetAttrCount();
+    if (!mPosition.Content()->IsElement()) {
+      return false;
+    }
+
+    Element* element = mPosition.Content()->AsElement();
+    uint32_t total = element->GetAttrCount();
     if (aStartIndex >= total) {
         return false;
     }
 
     uint32_t index;
     for (index = aStartIndex; index < total; ++index) {
-        const nsAttrName* name = mPosition.Content()->GetAttrNameAt(index);
+        const nsAttrName* name = element->GetAttrNameAt(index);
 
         // We need to ignore XMLNS attributes.
         if (name->NamespaceID() != kNameSpaceID_XMLNS) {
             mPosition.mIndex = index;
 
             return true;
         }
     }
     return false;
 }
 
 bool
 txXPathTreeWalker::moveToNamedAttribute(nsAtom* aLocalName, int32_t aNSID)
 {
-    if (!mPosition.isContent()) {
+    if (!mPosition.isContent() || !mPosition.Content()->IsElement()) {
         return false;
     }
 
+    Element* element = mPosition.Content()->AsElement();
+
     const nsAttrName* name;
     uint32_t i;
-    for (i = 0; (name = mPosition.Content()->GetAttrNameAt(i)); ++i) {
+    for (i = 0; (name = element->GetAttrNameAt(i)); ++i) {
         if (name->Equals(aLocalName, aNSID)) {
             mPosition.mIndex = i;
 
             return true;
         }
     }
     return false;
 }
@@ -305,18 +312,19 @@ txXPathNodeUtils::getLocalName(const txX
             node->GetNodeName(target);
 
             return NS_Atomize(target);
         }
 
         return nullptr;
     }
 
-    RefPtr<nsAtom> localName = aNode.Content()->
-        GetAttrNameAt(aNode.mIndex)->LocalName();
+    // This is an attribute node, so we necessarily come from an element.
+    RefPtr<nsAtom> localName =
+      aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->LocalName();
 
     return localName.forget();
 }
 
 nsAtom*
 txXPathNodeUtils::getPrefix(const txXPathNode& aNode)
 {
     if (aNode.isDocument()) {
@@ -324,17 +332,17 @@ txXPathNodeUtils::getPrefix(const txXPat
     }
 
     if (aNode.isContent()) {
         // All other nsIContent node types but elements have a null prefix
         // which is what we want here.
         return aNode.Content()->NodeInfo()->GetPrefixAtom();
     }
 
-    return aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetPrefix();
+    return aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->GetPrefix();
 }
 
 /* static */
 void
 txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName)
 {
     if (aNode.isDocument()) {
         aLocalName.Truncate();
@@ -357,17 +365,17 @@ txXPathNodeUtils::getLocalName(const txX
             return;
         }
 
         aLocalName.Truncate();
 
         return;
     }
 
-    aNode.Content()->GetAttrNameAt(aNode.mIndex)->LocalName()->
+    aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->LocalName()->
       ToString(aLocalName);
 
     // Check for html
     if (aNode.Content()->NodeInfo()->NamespaceEquals(kNameSpaceID_None) &&
         aNode.Content()->IsHTMLElement()) {
         nsContentUtils::ASCIIToUpper(aLocalName);
     }
 }
@@ -391,32 +399,32 @@ txXPathNodeUtils::getNodeName(const txXP
             return;
         }
 
         aName.Truncate();
 
         return;
     }
 
-    aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetQualifiedName(aName);
+    aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->GetQualifiedName(aName);
 }
 
 /* static */
 int32_t
 txXPathNodeUtils::getNamespaceID(const txXPathNode& aNode)
 {
     if (aNode.isDocument()) {
         return kNameSpaceID_None;
     }
 
     if (aNode.isContent()) {
         return aNode.Content()->GetNameSpaceID();
     }
 
-    return aNode.Content()->GetAttrNameAt(aNode.mIndex)->NamespaceID();
+    return aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->NamespaceID();
 }
 
 /* static */
 void
 txXPathNodeUtils::getNamespaceURI(const txXPathNode& aNode, nsAString& aURI)
 {
     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(getNamespaceID(aNode), aURI);
 }
@@ -436,17 +444,17 @@ txXPathNodeUtils::getNodeType(const txXP
     return txXPathNodeType::ATTRIBUTE_NODE;
 }
 
 /* static */
 void
 txXPathNodeUtils::appendNodeValue(const txXPathNode& aNode, nsAString& aResult)
 {
     if (aNode.isAttribute()) {
-        const nsAttrName* name = aNode.Content()->GetAttrNameAt(aNode.mIndex);
+        const nsAttrName* name = aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex);
 
         if (aResult.IsEmpty()) {
             aNode.Content()->GetAttr(name->NamespaceID(), name->LocalName(),
                                      aResult);
         }
         else {
             nsAutoString result;
             aNode.Content()->GetAttr(name->NamespaceID(), name->LocalName(),
@@ -687,17 +695,18 @@ txXPathNativeNode::createXPathNode(nsIDO
 /* static */
 nsINode*
 txXPathNativeNode::getNode(const txXPathNode& aNode)
 {
     if (!aNode.isAttribute()) {
         return aNode.mNode;
     }
 
-    const nsAttrName* name = aNode.Content()->GetAttrNameAt(aNode.mIndex);
+    const nsAttrName* name =
+      aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex);
 
     nsAutoString namespaceURI;
     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(name->NamespaceID(), namespaceURI);
 
     nsCOMPtr<Element> element = do_QueryInterface(aNode.mNode);
     nsDOMAttributeMap* map = element->Attributes();
     return map->GetNamedItemNS(namespaceURI,
                                nsDependentAtomString(name->LocalName()));
--- a/dom/xslt/xslt/txMozillaTextOutput.cpp
+++ b/dom/xslt/xslt/txMozillaTextOutput.cpp
@@ -15,16 +15,17 @@
 #include "txURIUtils.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
 #include "mozilla/Encoding.h"
 #include "nsTextNode.h"
 #include "nsNameSpaceManager.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 txMozillaTextOutput::txMozillaTextOutput(nsITransformObserver* aObserver)
 {
     MOZ_COUNT_CTOR(txMozillaTextOutput);
     mObserver = do_GetWeakReference(aObserver);
 }
 
@@ -191,38 +192,43 @@ txMozillaTextOutput::createResultDocumen
           mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
                                 nsGkAtoms::transformiix, namespaceID);
 
 
         rv = mDocument->AppendChildTo(mTextParent, true);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
-        nsCOMPtr<nsIContent> html, head, body;
+        RefPtr<Element> html, head, body;
         rv = createXHTMLElement(nsGkAtoms::html, getter_AddRefs(html));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = createXHTMLElement(nsGkAtoms::head, getter_AddRefs(head));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = html->AppendChildTo(head, false);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = createXHTMLElement(nsGkAtoms::body, getter_AddRefs(body));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = html->AppendChildTo(body, false);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        rv = createXHTMLElement(nsGkAtoms::pre, getter_AddRefs(mTextParent));
-        NS_ENSURE_SUCCESS(rv, rv);
+        {
+          RefPtr<Element> textParent;
+          rv = createXHTMLElement(nsGkAtoms::pre, getter_AddRefs(textParent));
+          NS_ENSURE_SUCCESS(rv, rv);
+          mTextParent = textParent.forget();
+        }
 
-        rv = mTextParent->SetAttr(kNameSpaceID_None, nsGkAtoms::id,
-                                  NS_LITERAL_STRING("transformiixResult"),
-                                  false);
+        rv = mTextParent->AsElement()->SetAttr(kNameSpaceID_None,
+                                               nsGkAtoms::id,
+                                               NS_LITERAL_STRING("transformiixResult"),
+                                               false);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = body->AppendChildTo(mTextParent, false);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = mDocument->AppendChildTo(html, true);
         NS_ENSURE_SUCCESS(rv, rv);
     }
@@ -245,15 +251,14 @@ txMozillaTextOutput::startElement(nsAtom
 }
 
 void txMozillaTextOutput::getOutputDocument(nsIDOMDocument** aDocument)
 {
     CallQueryInterface(mDocument, aDocument);
 }
 
 nsresult
-txMozillaTextOutput::createXHTMLElement(nsAtom* aName,
-                                        nsIContent** aResult)
+txMozillaTextOutput::createXHTMLElement(nsAtom* aName, Element** aResult)
 {
     nsCOMPtr<Element> element = mDocument->CreateHTMLElement(aName);
     element.forget(aResult);
     return NS_OK;
 }
--- a/dom/xslt/xslt/txMozillaTextOutput.h
+++ b/dom/xslt/xslt/txMozillaTextOutput.h
@@ -11,31 +11,37 @@
 #include "nsWeakPtr.h"
 #include "txOutputFormat.h"
 
 class nsIDOMDocumentFragment;
 class nsITransformObserver;
 class nsIDocument;
 class nsIContent;
 
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
+
 class txMozillaTextOutput : public txAOutputXMLEventHandler
 {
 public:
     explicit txMozillaTextOutput(nsITransformObserver* aObserver);
     explicit txMozillaTextOutput(nsIDOMDocumentFragment* aDest);
     virtual ~txMozillaTextOutput();
 
     TX_DECL_TXAXMLEVENTHANDLER
     TX_DECL_TXAOUTPUTXMLEVENTHANDLER
 
     nsresult createResultDocument(nsIDocument* aSourceDocument,
                                   bool aLoadedAsData);
 
 private:
-    nsresult createXHTMLElement(nsAtom* aName, nsIContent** aResult);
+    nsresult createXHTMLElement(nsAtom* aName, mozilla::dom::Element** aResult);
 
     nsCOMPtr<nsIContent> mTextParent;
     nsWeakPtr mObserver;
     nsCOMPtr<nsIDocument> mDocument;
     txOutputFormat mOutputFormat;
     nsString mText;
 };
 
--- a/dom/xslt/xslt/txMozillaXMLOutput.cpp
+++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp
@@ -683,17 +683,17 @@ txMozillaXMLOutput::startHTMLElement(nsI
         mTableStateStack.pop();
     }
 
     if (aElement->IsHTMLElement(nsGkAtoms::table) && aIsHTML) {
         mTableState = TABLE;
     }
     else if (aElement->IsHTMLElement(nsGkAtoms::tr) && aIsHTML &&
              NS_PTR_TO_INT32(mTableStateStack.peek()) == TABLE) {
-        nsCOMPtr<nsIContent> tbody;
+        RefPtr<Element> tbody;
         rv = createHTMLElement(nsGkAtoms::tbody, getter_AddRefs(tbody));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = mCurrentNode->AppendChildTo(tbody, true);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY));
         NS_ENSURE_SUCCESS(rv, rv);
@@ -703,17 +703,17 @@ txMozillaXMLOutput::startHTMLElement(nsI
         }
 
         mCurrentNode = tbody;
     }
     else if (aElement->IsHTMLElement(nsGkAtoms::head) &&
              mOutputFormat.mMethod == eHTMLOutput) {
         // Insert META tag, according to spec, 16.2, like
         // <META http-equiv="Content-Type" content="text/html; charset=EUC-JP">
-        nsCOMPtr<nsIContent> meta;
+        RefPtr<Element> meta;
         rv = createHTMLElement(nsGkAtoms::meta, getter_AddRefs(meta));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = meta->SetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv,
                            NS_LITERAL_STRING("Content-Type"), false);
         NS_ENSURE_SUCCESS(rv, rv);
 
         nsAutoString metacontent;
@@ -910,18 +910,17 @@ txMozillaXMLOutput::createResultDocument
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
 
     return NS_OK;
 }
 
 nsresult
-txMozillaXMLOutput::createHTMLElement(nsAtom* aName,
-                                      nsIContent** aResult)
+txMozillaXMLOutput::createHTMLElement(nsAtom* aName, Element** aResult)
 {
     NS_ASSERTION(mOutputFormat.mMethod == eHTMLOutput,
                  "need to adjust createHTMLElement");
 
     *aResult = nullptr;
 
     RefPtr<NodeInfo> ni;
     ni = mNodeInfoManager->GetNodeInfo(aName, nullptr,
--- a/dom/xslt/xslt/txMozillaXMLOutput.h
+++ b/dom/xslt/xslt/txMozillaXMLOutput.h
@@ -77,17 +77,17 @@ public:
                                   bool aLoadedAsData);
 
 private:
     nsresult createTxWrapper();
     nsresult startHTMLElement(nsIContent* aElement, bool aXHTML);
     nsresult endHTMLElement(nsIContent* aElement);
     void processHTTPEquiv(nsAtom* aHeader, const nsString& aValue);
     nsresult createHTMLElement(nsAtom* aName,
-                               nsIContent** aResult);
+                               mozilla::dom::Element** aResult);
 
     nsresult attributeInternal(nsAtom* aPrefix, nsAtom* aLocalName,
                                int32_t aNsID, const nsString& aValue);
     nsresult startElementInternal(nsAtom* aPrefix, nsAtom* aLocalName,
                                   int32_t aNsID);
 
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsINode> mCurrentNode;     // This is updated once an element is
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -153,17 +153,17 @@ struct BroadcasterMapEntry : public PLDH
 
 Element*
 nsRefMapEntry::GetFirstElement()
 {
     return mRefContentList.SafeElementAt(0);
 }
 
 void
-nsRefMapEntry::AppendAll(nsCOMArray<nsIContent>* aElements)
+nsRefMapEntry::AppendAll(nsCOMArray<Element>* aElements)
 {
     for (size_t i = 0; i < mRefContentList.Length(); ++i) {
         aElements->AppendObject(mRefContentList[i]);
     }
 }
 
 bool
 nsRefMapEntry::AddElement(Element* aElement)
@@ -1093,17 +1093,17 @@ XULDocument::ContentRemoved(nsIDocument*
 
 //----------------------------------------------------------------------
 //
 // nsIXULDocument interface
 //
 
 void
 XULDocument::GetElementsForID(const nsAString& aID,
-                              nsCOMArray<nsIContent>& aElements)
+                              nsCOMArray<Element>& aElements)
 {
     aElements.Clear();
 
     nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aID);
     if (entry) {
         entry->AppendAllIdContent(&aElements);
     }
     nsRefMapEntry *refEntry = mRefMap.GetEntry(aID);
@@ -2054,17 +2054,17 @@ XULDocument::ApplyPersistentAttributes()
 
     return NS_OK;
 }
 
 
 nsresult
 XULDocument::ApplyPersistentAttributesInternal()
 {
-    nsCOMArray<nsIContent> elements;
+    nsCOMArray<Element> elements;
 
     nsAutoCString utf8uri;
     nsresult rv = mDocumentURI->GetSpec(utf8uri);
     if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
     }
     NS_ConvertUTF8toUTF16 uri(utf8uri);
 
@@ -2102,17 +2102,17 @@ XULDocument::ApplyPersistentAttributesIn
     }
 
     return NS_OK;
 }
 
 
 nsresult
 XULDocument::ApplyPersistentAttributesToElements(const nsAString &aID,
-                                                 nsCOMArray<nsIContent>& aElements)
+                                                 nsCOMArray<Element>& aElements)
 {
     nsAutoCString utf8uri;
     nsresult rv = mDocumentURI->GetSpec(utf8uri);
     if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
     }
     NS_ConvertUTF8toUTF16 uri(utf8uri);
 
@@ -2142,22 +2142,22 @@ XULDocument::ApplyPersistentAttributesTo
         RefPtr<nsAtom> attr = NS_Atomize(attrstr);
         if (NS_WARN_IF(!attr)) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
         uint32_t cnt = aElements.Count();
 
         for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
-            nsCOMPtr<nsIContent> element = aElements.SafeObjectAt(i);
+            RefPtr<Element> element = aElements.SafeObjectAt(i);
             if (!element) {
                  continue;
             }
 
-            rv = element->SetAttr(kNameSpaceID_None, attr, value, PR_TRUE);
+            Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
         }
     }
 
     return NS_OK;
 }
 
 void
 XULDocument::TraceProtos(JSTracer* aTrc)
@@ -3148,17 +3148,17 @@ XULDocument::MaybeBroadcast()
             }
             return;
         }
         if (!mHandlingDelayedAttrChange) {
             mHandlingDelayedAttrChange = true;
             for (uint32_t i = 0; i < mDelayedAttrChangeBroadcasts.Length(); ++i) {
                 nsAtom* attrName = mDelayedAttrChangeBroadcasts[i].mAttrName;
                 if (mDelayedAttrChangeBroadcasts[i].mNeedsAttrChange) {
-                    nsCOMPtr<nsIContent> listener =
+                    nsCOMPtr<Element> listener =
                         do_QueryInterface(mDelayedAttrChangeBroadcasts[i].mListener);
                     const nsString& value = mDelayedAttrChangeBroadcasts[i].mAttr;
                     if (mDelayedAttrChangeBroadcasts[i].mSetAttr) {
                         listener->SetAttr(kNameSpaceID_None, attrName, value,
                                           true);
                     } else {
                         listener->UnsetAttr(kNameSpaceID_None, attrName,
                                             true);
@@ -3605,17 +3605,17 @@ XULDocument::CreateOverlayElement(nsXULP
     if (NS_FAILED(rv)) return rv;
 
     element.forget(aResult);
     return NS_OK;
 }
 
 nsresult
 XULDocument::AddAttributes(nsXULPrototypeElement* aPrototype,
-                           nsIContent* aElement)
+                           Element* aElement)
 {
     nsresult rv;
 
     for (uint32_t i = 0; i < aPrototype->mNumAttributes; ++i) {
         nsXULPrototypeAttribute* protoattr = &(aPrototype->mAttributes[i]);
         nsAutoString  valueStr;
         protoattr->mValue.ToString(valueStr);
 
@@ -3689,22 +3689,22 @@ XULDocument::CreateTemplateBuilder(Eleme
     if (isTreeBuilder) {
         // Create and initialize a tree builder.
         RefPtr<nsXULTreeBuilder> builder = new nsXULTreeBuilder(aElement);
         nsresult rv = builder->Init();
         NS_ENSURE_SUCCESS(rv, rv);
 
         // Create a <treechildren> if one isn't there already.
         // XXXvarga what about attributes?
-        nsCOMPtr<nsIContent> bodyContent;
+        RefPtr<Element> bodyContent;
         nsXULContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL,
                                           nsGkAtoms::treechildren,
                                           getter_AddRefs(bodyContent));
 
-        if (! bodyContent) {
+        if (!bodyContent) {
             bodyContent =
                 document->CreateElem(nsDependentAtomString(nsGkAtoms::treechildren),
                                      nullptr, kNameSpaceID_XUL);
 
             aElement->AppendChildTo(bodyContent, false);
         }
     }
     else {
@@ -3755,17 +3755,17 @@ XULDocument::AddPrototypeSheets()
 //
 
 nsForwardReference::Result
 XULDocument::OverlayForwardReference::Resolve()
 {
     // Resolve a forward reference from an overlay element; attempt to
     // hook it up into the main document.
     nsresult rv;
-    nsCOMPtr<nsIContent> target;
+    RefPtr<Element> target;
 
     nsIPresShell *shell = mDocument->GetShell();
     bool notify = shell && shell->DidInitialize();
 
     nsAutoString id;
     mOverlay->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
     if (id.IsEmpty()) {
         // mOverlay is a direct child of <overlay> and has no id.
@@ -3813,160 +3813,157 @@ XULDocument::OverlayForwardReference::Re
 
     mResolved = true;
     return eResolve_Succeeded;
 }
 
 
 
 nsresult
-XULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
-                                            nsIContent* aOverlayNode,
+XULDocument::OverlayForwardReference::Merge(Element* aTargetElement,
+                                            Element* aOverlayElement,
                                             bool aNotify)
 {
     // This function is given:
-    // aTargetNode:  the node in the document whose 'id' attribute
-    //               matches a toplevel node in our overlay.
-    // aOverlayNode: the node in the overlay document that matches
-    //               a node in the actual document.
-    // aNotify:      whether or not content manipulation methods should
-    //               use the aNotify parameter. After the initial
-    //               reflow (i.e. in the dynamic overlay merge case),
-    //               we want all the content manipulation methods we
-    //               call to notify so that frames are constructed
-    //               etc. Otherwise do not, since that's during initial
-    //               document construction before StartLayout has been
-    //               called which will do everything for us.
+    // aTargetElement:  the element in the document whose 'id' attribute
+    //                  matches a toplevel node in our overlay.
+    // aOverlayElement: the element in the overlay document that matches
+    //                  an element in the actual document.
+    // aNotify:         whether or not content manipulation methods should
+    //                  use the aNotify parameter. After the initial
+    //                  reflow (i.e. in the dynamic overlay merge case),
+    //                  we want all the content manipulation methods we
+    //                  call to notify so that frames are constructed
+    //                  etc. Otherwise do not, since that's during initial
+    //                  document construction before StartLayout has been
+    //                  called which will do everything for us.
     //
     // This function merges the tree from the overlay into the tree in
     // the document, overwriting attributes and appending child content
     // nodes appropriately. (See XUL overlay reference for details)
 
     nsresult rv;
 
     // Merge attributes from the overlay content node to that of the
     // actual document.
     uint32_t i;
     const nsAttrName* name;
-    for (i = 0; (name = aOverlayNode->GetAttrNameAt(i)); ++i) {
+    for (i = 0; (name = aOverlayElement->GetAttrNameAt(i)); ++i) {
         // We don't want to swap IDs, they should be the same.
         if (name->Equals(nsGkAtoms::id))
             continue;
 
         // In certain cases merging command or observes is unsafe, so don't.
         if (!aNotify) {
-            if (aTargetNode->NodeInfo()->Equals(nsGkAtoms::observes,
-                                                kNameSpaceID_XUL))
+            if (aTargetElement->NodeInfo()->Equals(nsGkAtoms::observes,
+                                                   kNameSpaceID_XUL))
                 continue;
 
             if (name->Equals(nsGkAtoms::observes) &&
-                aTargetNode->HasAttr(kNameSpaceID_None, nsGkAtoms::observes))
+                aTargetElement->HasAttr(kNameSpaceID_None, nsGkAtoms::observes))
                 continue;
 
             if (name->Equals(nsGkAtoms::command) &&
-                aTargetNode->HasAttr(kNameSpaceID_None, nsGkAtoms::command) &&
-                !aTargetNode->NodeInfo()->Equals(nsGkAtoms::key,
-                                                 kNameSpaceID_XUL) &&
-                !aTargetNode->NodeInfo()->Equals(nsGkAtoms::menuitem,
-                                                 kNameSpaceID_XUL))
+                aTargetElement->HasAttr(kNameSpaceID_None, nsGkAtoms::command) &&
+                !aTargetElement->NodeInfo()->Equals(nsGkAtoms::key,
+                                                    kNameSpaceID_XUL) &&
+                !aTargetElement->NodeInfo()->Equals(nsGkAtoms::menuitem,
+                                                   kNameSpaceID_XUL))
                 continue;
         }
 
         int32_t nameSpaceID = name->NamespaceID();
         nsAtom* attr = name->LocalName();
         nsAtom* prefix = name->GetPrefix();
 
         nsAutoString value;
-        aOverlayNode->GetAttr(nameSpaceID, attr, value);
+        aOverlayElement->GetAttr(nameSpaceID, attr, value);
 
         // Element in the overlay has the 'removeelement' attribute set
         // so remove it from the actual document.
-        if (attr == nsGkAtoms::removeelement &&
-            value.EqualsLiteral("true")) {
-
-            nsCOMPtr<nsINode> parent = aTargetNode->GetParentNode();
+        if (attr == nsGkAtoms::removeelement && value.EqualsLiteral("true")) {
+            nsCOMPtr<nsINode> parent = aTargetElement->GetParentNode();
             if (!parent) return NS_ERROR_FAILURE;
-            rv = RemoveElement(parent, aTargetNode);
+            rv = RemoveElement(parent, aTargetElement);
             if (NS_FAILED(rv)) return rv;
-
             return NS_OK;
         }
 
-        rv = aTargetNode->SetAttr(nameSpaceID, attr, prefix, value, aNotify);
-        if (!NS_FAILED(rv) && !aNotify)
-            rv = mDocument->BroadcastAttributeChangeFromOverlay(aTargetNode,
-                                                                nameSpaceID,
-                                                                attr, prefix,
-                                                                value);
+        rv = aTargetElement->SetAttr(nameSpaceID, attr, prefix, value, aNotify);
+        if (!NS_FAILED(rv) && !aNotify) {
+            rv = mDocument->BroadcastAttributeChangeFromOverlay(
+                    aTargetElement, nameSpaceID, attr, prefix, value);
+        }
         if (NS_FAILED(rv)) return rv;
     }
 
 
     // Walk our child nodes, looking for elements that have the 'id'
     // attribute set. If we find any, we must do a parent check in the
     // actual document to ensure that the structure matches that of
     // the actual document. If it does, we can call ourselves and attempt
     // to merge inside that subtree. If not, we just append the tree to
     // the parent like any other.
 
-    uint32_t childCount = aOverlayNode->GetChildCount();
+    uint32_t childCount = aOverlayElement->GetChildCount();
 
     // This must be a strong reference since it will be the only
     // reference to a content object during part of this loop.
     nsCOMPtr<nsIContent> currContent;
 
     for (i = 0; i < childCount; ++i) {
-        currContent = aOverlayNode->GetFirstChild();
+        currContent = aOverlayElement->GetFirstChild();
 
         nsAtom *idAtom = currContent->GetID();
 
-        nsIContent *elementInDocument = nullptr;
+        Element* elementInDocument = nullptr;
         if (idAtom) {
             nsDependentAtomString id(idAtom);
 
             if (!id.IsEmpty()) {
-                nsIDocument *doc = aTargetNode->GetUncomposedDoc();
+                nsIDocument *doc = aTargetElement->GetUncomposedDoc();
                 //XXXsmaug should we use ShadowRoot::GetElementById()
                 //         if doc is null?
                 if (!doc) return NS_ERROR_FAILURE;
 
                 elementInDocument = doc->GetElementById(id);
             }
         }
 
         // The item has an 'id' attribute set, and we need to check with
         // the actual document to see if an item with this id exists at
         // this locale. If so, we want to merge the subtree under that
         // node. Otherwise, we just do an append as if the element had
         // no id attribute.
         if (elementInDocument) {
-            // Given two parents, aTargetNode and aOverlayNode, we want
+            // Given two parents, aTargetElement and aOverlayElement, we want
             // to call merge on currContent if we find an associated
             // node in the document with the same id as currContent that
             // also has aTargetNode as its parent.
 
-            nsIContent *elementParent = elementInDocument->GetParent();
+            nsIContent* elementParent = elementInDocument->GetParent();
 
             nsAtom *parentID = elementParent->GetID();
-            if (parentID &&
-                aTargetNode->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
-                                         nsDependentAtomString(parentID),
-                                         eCaseMatters)) {
+            if (parentID && aTargetElement->GetID() == parentID) {
                 // The element matches. "Go Deep!"
-                rv = Merge(elementInDocument, currContent, aNotify);
+                //
+                // Note that currContent is necessarily an element, because
+                // elementInDocument can only be non-null when currContent has a
+                // non-null ID.
+                rv = Merge(elementInDocument, currContent->AsElement(), aNotify);
                 if (NS_FAILED(rv)) return rv;
-                aOverlayNode->RemoveChildAt(0, false);
+                aOverlayElement->RemoveChildAt(0, false);
 
                 continue;
             }
         }
 
-        aOverlayNode->RemoveChildAt(0, false);
-
-        rv = InsertElement(aTargetNode, currContent, aNotify);
+        aOverlayElement->RemoveChildAt(0, false);
+
+        rv = InsertElement(aTargetElement, currContent, aNotify);
         if (NS_FAILED(rv)) return rv;
     }
 
     return NS_OK;
 }
 
 
 
@@ -4087,17 +4084,17 @@ XULDocument::BroadcastAttributeChangeFro
     // We've got listeners: push the value.
     for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
         BroadcastListener* bl = entry->mListeners[i];
 
         if ((bl->mAttribute != aAttribute) &&
             (bl->mAttribute != nsGkAtoms::_asterisk))
             continue;
 
-        nsCOMPtr<nsIContent> l = do_QueryReferent(bl->mListener);
+        nsCOMPtr<Element> l = do_QueryReferent(bl->mListener);
         if (l) {
             rv = l->SetAttr(aNameSpaceID, aAttribute,
                             aPrefix, aValue, false);
             if (NS_FAILED(rv)) return rv;
         }
     }
     return rv;
 }
@@ -4250,18 +4247,17 @@ XULDocument::CheckBroadcasterHookup(Elem
     }
 
     *aNeedsHookup = false;
     *aDidResolve = true;
     return NS_OK;
 }
 
 nsresult
-XULDocument::InsertElement(nsINode* aParent, nsIContent* aChild,
-                           bool aNotify)
+XULDocument::InsertElement(nsINode* aParent, nsIContent* aChild, bool aNotify)
 {
     // Insert aChild appropriately into aParent, accounting for a
     // 'pos' attribute set on aChild.
 
     nsAutoString posStr;
     bool wasInserted = false;
 
     // insert after an element of a given id
@@ -4301,17 +4297,16 @@ XULDocument::InsertElement(nsINode* aPar
                     return rv;
 
                 wasInserted = true;
             }
         }
     }
 
     if (!wasInserted) {
-
         aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::position, posStr);
         if (!posStr.IsEmpty()) {
             nsresult rv;
             // Positions are one-indexed.
             int32_t pos = posStr.ToInteger(&rv);
             // Note: if the insertion index (which is |pos - 1|) would be less
             // than 0 or greater than the number of children aParent has, then
             // don't insert, since the position is bogus.  Just skip on to
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -59,17 +59,17 @@ public:
   }
   nsRefMapEntry(const nsRefMapEntry& aOther) :
     nsStringHashKey(&aOther.GetKey())
   {
     NS_ERROR("Should never be called");
   }
 
   mozilla::dom::Element* GetFirstElement();
-  void AppendAll(nsCOMArray<nsIContent>* aElements);
+  void AppendAll(nsCOMArray<mozilla::dom::Element>* aElements);
   /**
    * @return true if aElement was added, false if we failed due to OOM
    */
   bool AddElement(mozilla::dom::Element* aElement);
   /**
    * @return true if aElement was removed and it was the last content for
    * this ref, so this entry should be removed from the map
    */
@@ -121,17 +121,17 @@ public:
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
     NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
 
     // nsIXULDocument interface
     virtual void GetElementsForID(const nsAString& aID,
-                                  nsCOMArray<nsIContent>& aElements) override;
+                                  nsCOMArray<mozilla::dom::Element>& aElements) override;
 
     NS_IMETHOD AddSubtreeToDocument(nsIContent* aContent) override;
     NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aContent) override;
     NS_IMETHOD SetTemplateBuilderFor(nsIContent* aContent,
                                      nsIXULTemplateBuilder* aBuilder) override;
     NS_IMETHOD GetTemplateBuilderFor(nsIContent* aContent,
                                      nsIXULTemplateBuilder** aResult) override;
     NS_IMETHOD OnPrototypeLoadDone(bool aResumeWalk) override;
@@ -257,17 +257,17 @@ protected:
 
     nsresult
     LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic, bool* aShouldReturn,
                         bool* aFailureFromContent);
 
     nsresult ApplyPersistentAttributes();
     nsresult ApplyPersistentAttributesInternal();
     nsresult ApplyPersistentAttributesToElements(const nsAString &aID,
-                                                 nsCOMArray<nsIContent>& aElements);
+                                                 nsCOMArray<Element>& aElements);
 
     nsresult
     AddElementToDocumentPre(Element* aElement);
 
     nsresult
     AddElementToDocumentPost(Element* aElement);
 
     nsresult
@@ -435,17 +435,17 @@ protected:
      * later resolution.
      */
     nsresult CreateOverlayElement(nsXULPrototypeElement* aPrototype,
                                   Element** aResult);
 
     /**
      * Add attributes from the prototype to the element.
      */
-    nsresult AddAttributes(nsXULPrototypeElement* aPrototype, nsIContent* aElement);
+    nsresult AddAttributes(nsXULPrototypeElement* aPrototype, Element* aElement);
 
     /**
      * The prototype-script of the current transcluded script that is being
      * loaded.  For document.write('<script src="nestedwrite.js"><\/script>')
      * to work, these need to be in a stack element type, and we need to hold
      * the top of stack here.
      */
     nsXULPrototypeScript* mCurrentScriptProto;
@@ -540,23 +540,23 @@ protected:
 
     /**
      * Used to hook up overlays
      */
     class OverlayForwardReference : public nsForwardReference
     {
     protected:
         XULDocument* mDocument;      // [WEAK]
-        nsCOMPtr<nsIContent> mOverlay; // [OWNER]
+        nsCOMPtr<Element> mOverlay; // [OWNER]
         bool mResolved;
 
-        nsresult Merge(nsIContent* aTargetNode, nsIContent* aOverlayNode, bool aNotify);
+        nsresult Merge(Element* aTargetNode, Element* aOverlayNode, bool aNotify);
 
     public:
-        OverlayForwardReference(XULDocument* aDocument, nsIContent* aOverlay)
+        OverlayForwardReference(XULDocument* aDocument, Element* aOverlay)
             : mDocument(aDocument), mOverlay(aOverlay), mResolved(false) {}
 
         virtual ~OverlayForwardReference();
 
         virtual Phase GetPhase() override { return eConstruction; }
         virtual Result Resolve() override;
     };
 
@@ -593,16 +593,18 @@ protected:
                            bool* aNeedsHookup,
                            bool* aDidResolve);
 
     void
     SynchronizeBroadcastListener(Element *aBroadcaster,
                                  Element *aListener,
                                  const nsAString &aAttr);
 
+    // FIXME: This should probably be renamed, there's nothing guaranteeing that
+    // aChild is an Element as far as I can tell!
     static
     nsresult
     InsertElement(nsINode* aParent, nsIContent* aChild, bool aNotify);
 
     static
     nsresult
     RemoveElement(nsINode* aParent, nsINode* aChild);
 
--- a/dom/xul/nsIXULDocument.h
+++ b/dom/xul/nsIXULDocument.h
@@ -8,16 +8,22 @@
 
 #include "nsISupports.h"
 #include "nsString.h"
 #include "nsCOMArray.h"
 
 class nsIXULTemplateBuilder;
 class nsIContent;
 
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
+
 
 // 81ba4be5-6cc5-478a-9b08-b3e7ed524455
 #define NS_IXULDOCUMENT_IID \
   {0x81ba4be5, 0x6cc5, 0x478a, {0x9b, 0x08, 0xb3, 0xe7, 0xed, 0x52, 0x44, 0x55}}
 
 
 /*
  * An XUL-specific extension to nsIDocument. Includes methods for
@@ -29,17 +35,18 @@ class nsIXULDocument : public nsISupport
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXULDOCUMENT_IID)
 
   /**
    * Get the elements for a particular resource --- all elements whose 'id'
    * or 'ref' is aID. The nsCOMArray will be truncated and filled in with
    * nsIContent pointers.
    */
-  virtual void GetElementsForID(const nsAString& aID, nsCOMArray<nsIContent>& aElements) = 0;
+  virtual void GetElementsForID(const nsAString& aID,
+                                nsCOMArray<mozilla::dom::Element>& aElements) = 0;
 
   /**
    * Notify the XUL document that a subtree has been added
    */
   NS_IMETHOD AddSubtreeToDocument(nsIContent* aElement) = 0;
 
   /**
    * Notify the XUL document that a subtree has been removed
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -275,17 +275,17 @@ NS_NewXULElement(Element** aResult, alre
     if (doc && !doc->AllowXULXBL()) {
         return NS_ERROR_NOT_AVAILABLE;
     }
 
     return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, nullptr, nullptr);
 }
 
 void
-NS_TrustedNewXULElement(nsIContent** aResult,
+NS_TrustedNewXULElement(Element** aResult,
                         already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
 {
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
     NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
 
     // Create an nsXULElement with the specified namespace and tag.
     NS_ADDREF(*aResult = new nsXULElement(ni.forget()));
 }
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -798,17 +798,17 @@ protected:
 
     void UnregisterAccessKey(const nsAString& aOldValue);
     bool BoolAttrIsTrue(nsAtom* aName) const;
 
     friend nsresult
     NS_NewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo,
                      mozilla::dom::FromParser aFromParser, const nsAString* aIs);
     friend void
-    NS_TrustedNewXULElement(nsIContent** aResult, mozilla::dom::NodeInfo *aNodeInfo);
+    NS_TrustedNewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo);
 
     static already_AddRefed<nsXULElement>
     Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *aNodeInfo,
            bool aIsScriptable, bool aIsRoot);
 
     bool IsReadWriteTextElement() const
     {
         return IsAnyOfXULElements(nsGkAtoms::textbox, nsGkAtoms::textarea) &&
--- a/dom/xul/templates/nsIXULTemplateBuilder.idl
+++ b/dom/xul/templates/nsIXULTemplateBuilder.idl
@@ -13,16 +13,17 @@ interface nsIXULTemplateQueryProcessor;
 interface nsIRDFResource;
 interface nsIRDFCompositeDataSource;
 interface nsIDOMDataTransfer;
 
 %{C++
 class nsAtom;
 %}
 [ptr] native nsAtomPtr(nsAtom);
+[ptr] native Element (mozilla::dom::Element);
 
 /**
  * A template builder, given an input source of data, a template, and a
  * reference point, generates a list of results from the input, and copies
  * part of the template for each result. Templates may generate content
  * recursively, using the same template, but with the previous iteration's
  * results as the reference point. As an example, for an XML datasource the
  * initial reference point would be a specific node in the DOM tree and a
@@ -288,17 +289,17 @@ interface nsIXULTemplateBuilder : nsISup
     void addRuleFilter(in nsIDOMNode aRule, in nsIXULTemplateRuleFilter aFilter);
 
     /**
      * Invoked lazily by a XUL element that needs its child content built.
      * If aForceCreation is true, then the contents of an element will be
      * generated even if it is closed. If false, the element will only
      * generate its contents if it is open. This behaviour is used with menus.
      */
-    [noscript] void createContents(in nsIContent aElement,
+    [noscript] void createContents(in Element aElement,
                                    in boolean aForceCreation);
 
     /**
      * Add a listener to this template builder. The template builder
      * holds a strong reference to the listener.
      */
     void addListener(in nsIXULBuilderListener aListener);
 
--- a/dom/xul/templates/nsXULContentBuilder.cpp
+++ b/dom/xul/templates/nsXULContentBuilder.cpp
@@ -67,17 +67,17 @@ using namespace mozilla::dom;
  *
  * If recursion is allowed, generation continues, where the generation node
  * becomes the container to insert into.
  */
 class nsXULContentBuilder : public nsXULTemplateBuilder
 {
 public:
     // nsIXULTemplateBuilder interface
-    NS_IMETHOD CreateContents(nsIContent* aElement, bool aForceCreation) override;
+    NS_IMETHOD CreateContents(Element* aElement, bool aForceCreation) override;
 
     using nsIXULTemplateBuilder::HasGeneratedContent;
     bool HasGeneratedContent(nsIRDFResource* aResource,
                              const nsAString& aTag,
                              ErrorResult& aError) override;
 
     using nsIXULTemplateBuilder::GetResultForContent;
     nsIXULTemplateResult* GetResultForContent(Element& aElement) override;
@@ -96,65 +96,65 @@ protected:
     {
         mSortState.Traverse(aCb);
     }
 
     virtual void Uninit(bool aIsFinal) override;
 
     // Implementation methods
     nsresult
-    OpenContainer(nsIContent* aElement);
+    OpenContainer(Element* aElement);
 
     nsresult
-    CloseContainer(nsIContent* aElement);
+    CloseContainer(Element* aElement);
 
     /**
      * Build content from a template for a given result. This will be called
      * recursively or on demand and will be called for every node in the
      * generated content tree.
      */
     nsresult
     BuildContentFromTemplate(nsIContent *aTemplateNode,
                              nsIContent *aResourceNode,
-                             nsIContent *aRealNode,
+                             Element* aRealElement,
                              bool aIsUnique,
                              bool aIsSelfReference,
                              nsIXULTemplateResult* aChild,
                              bool aNotify,
                              nsTemplateMatch* aMatch,
-                             nsIContent** aContainer,
+                             Element** aContainer,
                              int32_t* aNewIndexInContainer);
 
     /**
      * Copy the attributes from the template node to the node generated
      * from it, performing any substitutions.
      *
-     * @param aTemplateNode node within template
-     * @param aRealNode generated node to set attibutes upon
+     * @param aTemplateElement element within template
+     * @param aRealElement generated element to set attibutes upon
      * @param aResult result to look up variable->value bindings in
      * @param aNotify true to notify of DOM changes
      */
     nsresult
-    CopyAttributesToElement(nsIContent* aTemplateNode,
-                            nsIContent* aRealNode,
+    CopyAttributesToElement(Element* aTemplateElement,
+                            Element* aRealElement,
                             nsIXULTemplateResult* aResult,
                             bool aNotify);
 
     /**
      * Add any necessary persistent attributes (persist="...") from the
      * local store to a generated node.
      *
      * @param aTemplateNode node within template
      * @param aRealNode generated node to set persisted attibutes upon
      * @param aResult result to look up variable->value bindings in
      */
     nsresult
-    AddPersistentAttributes(Element* aTemplateNode,
+    AddPersistentAttributes(Element* aTemplateElement,
                             nsIXULTemplateResult* aResult,
-                            nsIContent* aRealNode);
+                            Element* aRealElement);
 
     /**
      * Recalculate any attributes that have variable references. This will
      * be called when a binding has been changed to update the attributes.
      * The attributes are copied from the node aTemplateNode in the template
      * to the generated node aRealNode, using the values from the result
      * aResult. This method will operate recursively.
      *
@@ -177,80 +177,80 @@ protected:
     /**
      * Create the appropriate generated content for aElement, by calling
      * CreateContainerContents.
      *
      * @param aElement element to generate content inside
      * @param aForceCreation true to force creation for closed items such as menus
      */
     nsresult
-    CreateTemplateAndContainerContents(nsIContent* aElement,
+    CreateTemplateAndContainerContents(Element* aElement,
                                        bool aForceCreation);
 
     /**
      * Generate the results for a template, by calling
      * CreateContainerContentsForQuerySet for each queryset.
      *
      * @param aElement element to generate content inside
      * @param aResult reference point for query
      * @param aForceCreation true to force creation for closed items such as menus
      * @param aNotify true to notify of DOM changes as each element is inserted
      * @param aNotifyAtEnd notify at the end of all DOM changes
      */
     nsresult
-    CreateContainerContents(nsIContent* aElement,
+    CreateContainerContents(Element* aElement,
                             nsIXULTemplateResult* aResult,
                             bool aForceCreation,
                             bool aNotify,
                             bool aNotifyAtEnd);
 
     /**
      * Generate the results for a query.
      *
      * @param aElement element to generate content inside
      * @param aResult reference point for query
      * @param aNotify true to notify of DOM changes
      * @param aContainer container content was added inside
      * @param aNewIndexInContainer index with container in which content was added
      */
     nsresult
-    CreateContainerContentsForQuerySet(nsIContent* aElement,
+    CreateContainerContentsForQuerySet(Element* aElement,
                                        nsIXULTemplateResult* aResult,
                                        bool aNotify,
                                        nsTemplateQuerySet* aQuerySet,
-                                       nsIContent** aContainer,
+                                       Element** aContainer,
                                        int32_t* aNewIndexInContainer);
 
     /**
      * Check if an element with a particular tag exists with a container.
      * If it is not present, append a new element with that tag into the
      * container.
      *
      * @param aParent parent container
      * @param aNameSpaceID namespace of tag to locate or create
      * @param aTag tag to locate or create
      * @param aNotify true to notify of DOM changes
      * @param aResult set to the found or created node.
      */
     nsresult
-    EnsureElementHasGenericChild(nsIContent* aParent,
+    EnsureElementHasGenericChild(Element* aParent,
                                  int32_t aNameSpaceID,
                                  nsAtom* aTag,
                                  bool aNotify,
-                                 nsIContent** aResult);
+                                 Element** aResult);
 
     bool
     IsOpen(nsIContent* aElement);
 
     nsresult
     RemoveGeneratedContent(nsIContent* aElement);
 
     nsresult
     GetElementsForResult(nsIXULTemplateResult* aResult,
-                         nsCOMArray<nsIContent>& aElements);
+                         nsCOMArray<Element>& aElements);
 
     nsresult
     CreateElement(int32_t aNameSpaceID,
                   nsAtom* aTag,
                   Element** aResult);
 
     /**
      * Set the container and empty attributes on a node. If
@@ -259,17 +259,17 @@ protected:
      * false.
      *
      * @param aElement element to set attributes on
      * @param aResult result to use to determine state of attributes
      * @param aIgnoreNonContainers true to not change for non-containers
      * @param aNotify true to notify of DOM changes
      */
     nsresult
-    SetContainerAttrs(nsIContent *aElement,
+    SetContainerAttrs(Element* aElement,
                       nsIXULTemplateResult* aResult,
                       bool aIgnoreNonContainers,
                       bool aNotify);
 
     virtual nsresult
     RebuildAll() override;
 
     // GetInsertionLocations, ReplaceMatch and SynchronizeResult are inherited
@@ -277,27 +277,27 @@ protected:
 
     /**
      * Return true if the result can be inserted into the template as
      * generated content. For the content builder, aLocations will be set
      * to the list of containers where the content should be inserted.
      */
     virtual bool
     GetInsertionLocations(nsIXULTemplateResult* aOldResult,
-                          nsCOMArray<nsIContent>** aLocations) override;
+                          nsCOMArray<Element>** aLocations) override;
 
     /**
      * Remove the content associated with aOldResult which no longer matches,
      * and/or generate content for a new match.
      */
     virtual nsresult
     ReplaceMatch(nsIXULTemplateResult* aOldResult,
                  nsTemplateMatch* aNewMatch,
                  nsTemplateRule* aNewMatchRule,
-                 void *aContext) override;
+                 Element* aContext) override;
 
     /**
      * Synchronize a result bindings with the generated content for that
      * result. This will be called as a result of the template builder's
      * ResultBindingChanged method.
      */
     virtual nsresult
     SynchronizeResult(nsIXULTemplateResult* aResult) override;
@@ -312,17 +312,17 @@ protected:
                         int32_t* aSortOrder);
 
     /**
      * Insert a generated node into the container where it should go according
      * to the current sort. aNode is the generated content node and aResult is
      * the result for the generated node.
      */
     nsresult
-    InsertSortedNode(nsIContent* aContainer,
+    InsertSortedNode(Element* aContainer,
                      nsIContent* aNode,
                      nsIXULTemplateResult* aResult,
                      bool aNotify);
 
     /**
      * Maintains a mapping between elements in the DOM and the matches
      * that they support.
      */
@@ -373,40 +373,40 @@ nsXULContentBuilder::Uninit(bool aIsFina
     mSortState.initialized = false;
 
     nsXULTemplateBuilder::Uninit(aIsFinal);
 }
 
 nsresult
 nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
                                               nsIContent *aResourceNode,
-                                              nsIContent *aRealNode,
+                                              Element* aRealElement,
                                               bool aIsUnique,
                                               bool aIsSelfReference,
                                               nsIXULTemplateResult* aChild,
                                               bool aNotify,
                                               nsTemplateMatch* aMatch,
-                                              nsIContent** aContainer,
+                                              Element** aContainer,
                                               int32_t* aNewIndexInContainer)
 {
     // This is the mother lode. Here is where we grovel through an
     // element in the template, copying children from the template
     // into the "real" content tree, performing substitution as we go
     // by looking stuff up using the results.
     //
     //   |aTemplateNode| is the element in the "template tree", whose
     //   children we will duplicate and move into the "real" content
     //   tree.
     //
     //   |aResourceNode| is the element in the "real" content tree that
     //   has the "id" attribute set to an result's id. This is
     //   not directly used here, but rather passed down to the XUL
     //   sort service to perform container-level sort.
     //
-    //   |aRealNode| is the element in the "real" content tree to which
+    //   |aRealElement| is the element in the "real" content tree to which
     //   the new elements will be copied.
     //
     //   |aIsUnique| is set to "true" so long as content has been
     //   "unique" (or "above" the resource element) so far in the
     //   template.
     //
     //   |aIsSelfReference| should be set to "true" for cases where
     //   the reference and member variables are the same, indicating
@@ -443,25 +443,24 @@ nsXULContentBuilder::BuildContentFromTem
 
         nsAutoString id;
         aChild->GetId(id);
 
         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
                ("Tags: [Template: %s  Resource: %s  Real: %s] for id %s",
                 nsAtomCString(aTemplateNode->NodeInfo()->NameAtom()).get(),
                 nsAtomCString(aResourceNode->NodeInfo()->NameAtom()).get(),
-                nsAtomCString(aRealNode->NodeInfo()->NameAtom()).get(), NS_ConvertUTF16toUTF8(id).get()));
+                nsAtomCString(aRealElement->NodeInfo()->NameAtom()).get(), NS_ConvertUTF16toUTF8(id).get()));
     }
 
     // Iterate through all of the template children, constructing
     // "real" content model nodes for each "template" child.
     for (nsIContent* tmplKid = aTemplateNode->GetFirstChild();
          tmplKid;
          tmplKid = tmplKid->GetNextSibling()) {
-
         int32_t nameSpaceID = tmplKid->GetNameSpaceID();
 
         // Check whether this element is the generation element. The generation
         // element is the element that is cookie-cutter copied once for each
         // different result specified by |aChild|.
         //
         // Nodes that appear -above- the generation element
         // (that is, are ancestors of the generation element in the
@@ -506,53 +505,65 @@ nsXULContentBuilder::BuildContentFromTem
         // "uri='...'" syntax.)
         if (tmplKid->HasAttr(kNameSpaceID_None, nsGkAtoms::uri) && aMatch->IsActive()) {
             isGenerationElement = true;
             isUnique = false;
         }
 
         MOZ_ASSERT_IF(isGenerationElement, tmplKid->IsElement());
 
-        nsAtom *tag = tmplKid->NodeInfo()->NameAtom();
+        nsAtom* tag = tmplKid->NodeInfo()->NameAtom();
 
         if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
             MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
                    ("xultemplate[%p]     building %s %s %s",
                     this, nsAtomCString(tag).get(),
                     (isGenerationElement ? "[resource]" : ""),
                     (isUnique ? "[unique]" : "")));
         }
 
         // Set to true if the child we're trying to create now
         // already existed in the content model.
         bool realKidAlreadyExisted = false;
 
-        nsCOMPtr<nsIContent> realKid;
+        RefPtr<Element> realKid;
         if (isUnique) {
             // The content is "unique"; that is, we haven't descended
             // far enough into the template to hit the generation
             // element yet. |EnsureElementHasGenericChild()| will
             // conditionally create the element iff it isn't there
             // already.
-            rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
-            if (NS_FAILED(rv))
-                return rv;
+            //
+            // FIXME(emilio): The code below doesn't really make much sense if
+            // tmplKid is not an element. If it ever wasn't, we'd either find a
+            // child by tag, which doesn't really make sense, and event worse...
+            // If we didn't find it, we'd create an actual element with a text
+            // node tag for it.
+            //
+            // Both are completely bogus in tons of ways, so just avoid calling
+            // into EnsureElementHasGenericChild for non-elements, assuming the
+            // node is already there.
+            rv = NS_ELEMENT_WAS_THERE;
+            if (!tmplKid->IsElement()) {
+              rv = EnsureElementHasGenericChild(aRealElement, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
+              if (NS_FAILED(rv))
+                  return rv;
+            }
 
             if (rv == NS_ELEMENT_WAS_THERE) {
                 realKidAlreadyExisted = true;
-            }
-            else {
+            } else {
                 // Potentially remember the index of this element as the first
                 // element that we've generated. Note that we remember
                 // this -before- we recurse!
                 if (aContainer && !*aContainer) {
-                    *aContainer = aRealNode;
+                    *aContainer = aRealElement;
                     NS_ADDREF(*aContainer);
 
-                    uint32_t indx = aRealNode->GetChildCount();
+                    uint32_t indx = aRealElement->GetChildCount();
 
                     // Since EnsureElementHasGenericChild() added us, make
                     // sure to subtract one for our real index.
                     *aNewIndexInContainer = indx - 1;
                 }
             }
 
             // Recurse until we get to the resource element. Since
@@ -561,18 +572,17 @@ nsXULContentBuilder::BuildContentFromTem
             // of the function will trip this to |false| as soon as we
             // encounter it.
             rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, true,
                                           aIsSelfReference, aChild, aNotify, aMatch,
                                           aContainer, aNewIndexInContainer);
 
             if (NS_FAILED(rv))
                 return rv;
-        }
-        else if (isGenerationElement) {
+        } else if (isGenerationElement) {
             // It's the "resource" element. Create a new element using
             // the namespace ID and tag from the template element.
             nsCOMPtr<Element> element;
             rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element));
             if (NS_FAILED(rv))
                 return rv;
             realKid = element.forget();
 
@@ -587,19 +597,18 @@ nsXULContentBuilder::BuildContentFromTem
                 return rv;
 
             rv = realKid->SetAttr(kNameSpaceID_None, nsGkAtoms::id, id, false);
             if (NS_FAILED(rv))
                 return rv;
 
             // Set up the element's 'container' and 'empty' attributes.
             SetContainerAttrs(realKid, aChild, true, false);
-        }
-        else if (tag == nsGkAtoms::textnode &&
-                 nameSpaceID == kNameSpaceID_XUL) {
+        } else if (tag == nsGkAtoms::textnode &&
+                   nameSpaceID == kNameSpaceID_XUL) {
             // <xul:text value="..."> is replaced by text of the
             // actual value of the 'rdf:resource' attribute for the
             // given node.
             // SynchronizeUsingTemplate contains code used to update textnodes,
             // so make sure to modify both when changing this
             nsAutoString attrValue;
             tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
             if (!attrValue.IsEmpty()) {
@@ -607,69 +616,71 @@ nsXULContentBuilder::BuildContentFromTem
                 rv = SubstituteText(aChild, attrValue, value);
                 if (NS_FAILED(rv)) return rv;
 
                 RefPtr<nsTextNode> content =
                   new nsTextNode(mRoot->NodeInfo()->NodeInfoManager());
 
                 content->SetText(value, false);
 
-                rv = aRealNode->AppendChildTo(content, aNotify);
+                rv = aRealElement->AppendChildTo(content, aNotify);
                 if (NS_FAILED(rv)) return rv;
 
                 // XXX Don't bother remembering text nodes as the
                 // first element we've generated?
             }
-        }
-        else if (tmplKid->IsNodeOfType(nsINode::eTEXT)) {
+        } else if (tmplKid->IsNodeOfType(nsINode::eTEXT)) {
             nsCOMPtr<nsIDOMNode> tmplTextNode = do_QueryInterface(tmplKid);
             if (!tmplTextNode) {
                 NS_ERROR("textnode not implementing nsIDOMNode??");
                 return NS_ERROR_FAILURE;
             }
             nsCOMPtr<nsIDOMNode> clonedNode;
             tmplTextNode->CloneNode(false, 1, getter_AddRefs(clonedNode));
             nsCOMPtr<nsIContent> clonedContent = do_QueryInterface(clonedNode);
             if (!clonedContent) {
                 NS_ERROR("failed to clone textnode");
                 return NS_ERROR_FAILURE;
             }
-            rv = aRealNode->AppendChildTo(clonedContent, aNotify);
+            rv = aRealElement->AppendChildTo(clonedContent, aNotify);
             if (NS_FAILED(rv)) return rv;
-        }
-        else {
+        } else {
             // It's just a generic element. Create it!
             nsCOMPtr<Element> element;
             rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element));
             if (NS_FAILED(rv)) return rv;
             realKid = element.forget();
         }
 
         if (realKid && !realKidAlreadyExisted) {
             // Potentially remember the index of this element as the
             // first element that we've generated.
             if (aContainer && !*aContainer) {
-                *aContainer = aRealNode;
+                *aContainer = aRealElement;
                 NS_ADDREF(*aContainer);
 
-                uint32_t indx = aRealNode->GetChildCount();
+                uint32_t indx = aRealElement->GetChildCount();
 
                 // Since we haven't inserted any content yet, our new
                 // index in the container will be the current count of
                 // elements in the container.
                 *aNewIndexInContainer = indx;
             }
 
             // Remember the template kid from which we created the
             // real kid. This allows us to sync back up with the
             // template to incrementally build content.
             mTemplateMap.Put(realKid, tmplKid);
 
-            rv = CopyAttributesToElement(tmplKid, realKid, aChild, false);
-            if (NS_FAILED(rv)) return rv;
+            if (tmplKid->IsElement()) {
+                rv = CopyAttributesToElement(tmplKid->AsElement(),
+                                             realKid, aChild,
+                                             false);
+                if (NS_FAILED(rv)) return rv;
+            }
 
             // Add any persistent attributes
             if (isGenerationElement) {
                 rv = AddPersistentAttributes(tmplKid->AsElement(), aChild,
                                              realKid);
                 if (NS_FAILED(rv)) return rv;
             }
 
@@ -698,85 +709,85 @@ nsXULContentBuilder::BuildContentFromTem
 
             // We'll _already_ have added the unique elements; but if
             // it's -not- unique, then use the XUL sort service now to
             // append the element to the content model.
             if (! isUnique) {
                 rv = NS_ERROR_UNEXPECTED;
 
                 if (isGenerationElement)
-                    rv = InsertSortedNode(aRealNode, realKid, aChild, aNotify);
+                    rv = InsertSortedNode(aRealElement, realKid, aChild, aNotify);
 
                 if (NS_FAILED(rv)) {
-                    rv = aRealNode->AppendChildTo(realKid, aNotify);
+                    rv = aRealElement->AppendChildTo(realKid, aNotify);
                     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element");
                 }
             }
         }
     }
 
     return NS_OK;
 }
 
 nsresult
-nsXULContentBuilder::CopyAttributesToElement(nsIContent* aTemplateNode,
-                                             nsIContent* aRealNode,
+nsXULContentBuilder::CopyAttributesToElement(Element* aTemplateElement,
+                                             Element* aRealElement,
                                              nsIXULTemplateResult* aResult,
                                              bool aNotify)
 {
     nsresult rv;
 
     // Copy all attributes from the template to the new element
-    uint32_t numAttribs = aTemplateNode->GetAttrCount();
+    uint32_t numAttribs = aTemplateElement->GetAttrCount();
 
     for (uint32_t attr = 0; attr < numAttribs; attr++) {
-        const nsAttrName* name = aTemplateNode->GetAttrNameAt(attr);
+        const nsAttrName* name = aTemplateElement->GetAttrNameAt(attr);
         int32_t attribNameSpaceID = name->NamespaceID();
         // Hold a strong reference here so that the atom doesn't go away
         // during UnsetAttr.
         RefPtr<nsAtom> attribName = name->LocalName();
 
         // XXXndeakin ignore namespaces until bug 321182 is fixed
         if (attribName != nsGkAtoms::id && attribName != nsGkAtoms::uri) {
             nsAutoString attribValue;
-            aTemplateNode->GetAttr(attribNameSpaceID, attribName, attribValue);
+            aTemplateElement->GetAttr(attribNameSpaceID, attribName, attribValue);
             if (!attribValue.IsEmpty()) {
                 nsAutoString value;
                 rv = SubstituteText(aResult, attribValue, value);
                 if (NS_FAILED(rv))
                     return rv;
 
                 // if the string is empty after substitutions, remove the
                 // attribute
                 if (!value.IsEmpty()) {
-                    rv = aRealNode->SetAttr(attribNameSpaceID,
+                    rv = aRealElement->SetAttr(attribNameSpaceID,
                                             attribName,
                                             name->GetPrefix(),
                                             value,
                                             aNotify);
                 }
                 else {
-                    rv = aRealNode->UnsetAttr(attribNameSpaceID,
+                    rv = aRealElement->UnsetAttr(attribNameSpaceID,
                                               attribName,
                                               aNotify);
                 }
 
                 if (NS_FAILED(rv))
                     return rv;
             }
         }
     }
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::AddPersistentAttributes(Element* aTemplateNode,
                                              nsIXULTemplateResult* aResult,
-                                             nsIContent* aRealNode)
+                                             Element* aRealElement)
 {
     if (!mRoot)
         return NS_OK;
 
     nsCOMPtr<nsIRDFResource> resource;
     nsresult rv = GetResultResource(aResult, getter_AddRefs(resource));
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -832,45 +843,47 @@ nsXULContentBuilder::AddPersistentAttrib
         NS_ASSERTION(value != nullptr, "unable to stomach that sort of node");
         if (! value)
             continue;
 
         const char16_t* valueStr;
         rv = value->GetValueConst(&valueStr);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        rv = aRealNode->SetAttr(nameSpaceID, tag, nsDependentString(valueStr),
-                                false);
+        rv = aRealElement->SetAttr(nameSpaceID, tag, nsDependentString(valueStr),
+                                   false);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::SynchronizeUsingTemplate(nsIContent* aTemplateNode,
-                                              nsIContent* aRealElement,
+                                              nsIContent* aRealNode,
                                               nsIXULTemplateResult* aResult)
 {
     // check all attributes on the template node; if they reference a resource,
     // update the equivalent attribute on the content node
     nsresult rv;
-    rv = CopyAttributesToElement(aTemplateNode, aRealElement, aResult, true);
-    if (NS_FAILED(rv))
-        return rv;
+    if (aTemplateNode->IsElement() && aRealNode->IsElement()) {
+        rv = CopyAttributesToElement(aTemplateNode->AsElement(), aRealNode->AsElement(), aResult, true);
+        if (NS_FAILED(rv))
+            return rv;
+    }
 
     uint32_t count = aTemplateNode->GetChildCount();
 
     for (uint32_t loop = 0; loop < count; ++loop) {
         nsIContent *tmplKid = aTemplateNode->GetChildAt(loop);
 
         if (! tmplKid)
             break;
 
-        nsIContent *realKid = aRealElement->GetChildAt(loop);
+        nsIContent *realKid = aRealNode->GetChildAt(loop);
         if (! realKid)
             break;
 
         // check for text nodes and update them accordingly.
         // This code is similar to that in BuildContentFromTemplate
         if (tmplKid->NodeInfo()->Equals(nsGkAtoms::textnode,
                                         kNameSpaceID_XUL)) {
             nsAutoString attrValue;
@@ -911,17 +924,17 @@ nsXULContentBuilder::RemoveMember(nsICon
 
     // Remove from the template map
     mTemplateMap.Remove(aContent);
 
     return NS_OK;
 }
 
 nsresult
-nsXULContentBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
+nsXULContentBuilder::CreateTemplateAndContainerContents(Element* aElement,
                                                         bool aForceCreation)
 {
     // Generate both 1) the template content for the current element,
     // and 2) recursive subcontent (if the current element refers to a
     // container result).
 
     MOZ_LOG(gXULTemplateLog, LogLevel::Info,
            ("nsXULContentBuilder::CreateTemplateAndContainerContents start - flags: %d",
@@ -961,17 +974,17 @@ nsXULContentBuilder::CreateTemplateAndCo
 
     MOZ_LOG(gXULTemplateLog, LogLevel::Info,
            ("nsXULContentBuilder::CreateTemplateAndContainerContents end"));
 
     return NS_OK;
 }
 
 nsresult
-nsXULContentBuilder::CreateContainerContents(nsIContent* aElement,
+nsXULContentBuilder::CreateContainerContents(Element* aElement,
                                              nsIXULTemplateResult* aResult,
                                              bool aForceCreation,
                                              bool aNotify,
                                              bool aNotifyAtEnd)
 {
     if (!aForceCreation && !IsOpen(aElement))
         return NS_OK;
 
@@ -1016,17 +1029,17 @@ nsXULContentBuilder::CreateContainerCont
             return NS_OK;
 
         // Now mark the element's contents as being generated so that
         // any re-entrant calls don't trigger an infinite recursion.
         xulcontent->SetTemplateGenerated();
     }
 
     int32_t newIndexInContainer = -1;
-    nsIContent* container = nullptr;
+    Element* container = nullptr;
 
     int32_t querySetCount = mQuerySets.Length();
 
     for (int32_t r = 0; r < querySetCount; r++) {
         nsTemplateQuerySet* queryset = mQuerySets[r];
 
         nsAtom* tag = queryset->GetTag();
         if (tag && tag != aElement->NodeInfo()->NameAtom())
@@ -1044,21 +1057,21 @@ nsXULContentBuilder::CreateContainerCont
     }
 
     NS_IF_RELEASE(container);
 
     return NS_OK;
 }
 
 nsresult
-nsXULContentBuilder::CreateContainerContentsForQuerySet(nsIContent* aElement,
+nsXULContentBuilder::CreateContainerContentsForQuerySet(Element* aElement,
                                                         nsIXULTemplateResult* aResult,
                                                         bool aNotify,
                                                         nsTemplateQuerySet* aQuerySet,
-                                                        nsIContent** aContainer,
+                                                        Element** aContainer,
                                                         int32_t* aNewIndexInContainer)
 {
     if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
         nsAutoString id;
         aResult->GetId(id);
         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
                ("nsXULContentBuilder::CreateContainerContentsForQuerySet start for ref %s\n",
                NS_ConvertUTF16toUTF8(id).get()));
@@ -1197,21 +1210,21 @@ nsXULContentBuilder::CreateContainerCont
             newmatch->mNext = existingmatch;
         }
     }
 
     return rv;
 }
 
 nsresult
-nsXULContentBuilder::EnsureElementHasGenericChild(nsIContent* parent,
+nsXULContentBuilder::EnsureElementHasGenericChild(Element* parent,
                                                   int32_t nameSpaceID,
                                                   nsAtom* tag,
                                                   bool aNotify,
-                                                  nsIContent** result)
+                                                  Element** result)
 {
     nsresult rv;
 
     rv = nsXULContentUtils::FindChildByTag(parent, nameSpaceID, tag, result);
     if (NS_FAILED(rv))
         return rv;
 
     if (rv == NS_RDF_NO_VALUE) {
@@ -1306,17 +1319,17 @@ nsXULContentBuilder::RemoveGeneratedCont
         }
     }
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::GetElementsForResult(nsIXULTemplateResult* aResult,
-                                          nsCOMArray<nsIContent>& aElements)
+                                          nsCOMArray<Element>& aElements)
 {
     // if the root has been removed from the document, just return
     // since there won't be any generated content any more
     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc());
     if (! xuldoc)
         return NS_OK;
 
     nsAutoString id;
@@ -1340,17 +1353,17 @@ nsXULContentBuilder::CreateElement(int32
     RefPtr<mozilla::dom::NodeInfo> nodeInfo =
         doc->NodeInfoManager()->GetNodeInfo(aTag, nullptr, aNameSpaceID,
                                             nsIDOMNode::ELEMENT_NODE);
 
     return NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER);
 }
 
 nsresult
-nsXULContentBuilder::SetContainerAttrs(nsIContent *aElement,
+nsXULContentBuilder::SetContainerAttrs(Element* aElement,
                                        nsIXULTemplateResult* aResult,
                                        bool aIgnoreNonContainers,
                                        bool aNotify)
 {
     NS_PRECONDITION(aResult != nullptr, "null ptr");
     if (! aResult)
         return NS_ERROR_NULL_POINTER;
 
@@ -1385,17 +1398,17 @@ nsXULContentBuilder::SetContainerAttrs(n
 
 
 //----------------------------------------------------------------------
 //
 // nsIXULTemplateBuilder methods
 //
 
 NS_IMETHODIMP
-nsXULContentBuilder::CreateContents(nsIContent* aElement, bool aForceCreation)
+nsXULContentBuilder::CreateContents(Element* aElement, bool aForceCreation)
 {
     NS_PRECONDITION(aElement != nullptr, "null ptr");
     if (! aElement)
         return NS_ERROR_NULL_POINTER;
 
     // don't build contents for closed elements. aForceCreation will be true
     // when a menu is about to be opened, so the content should be built anyway.
     if (!aForceCreation && !IsOpen(aElement))
@@ -1431,17 +1444,17 @@ nsXULContentBuilder::HasGeneratedContent
     NS_ConvertUTF8toUTF16 refID(uri);
 
     // just return if the node is no longer in a document
     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc());
     if (!xuldoc) {
         return false;
     }
 
-    nsCOMArray<nsIContent> elements;
+    nsCOMArray<Element> elements;
     xuldoc->GetElementsForID(refID, elements);
 
     uint32_t cnt = elements.Count();
 
     for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
         nsCOMPtr<nsIContent> content = elements.SafeObjectAt(i);
 
         do {
@@ -1524,30 +1537,30 @@ nsXULContentBuilder::NodeWillBeDestroyed
 
 //----------------------------------------------------------------------
 //
 // nsXULTemplateBuilder methods
 //
 
 bool
 nsXULContentBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
-                                           nsCOMArray<nsIContent>** aLocations)
+                                           nsCOMArray<Element>** aLocations)
 {
     *aLocations = nullptr;
 
     nsAutoString ref;
     nsresult rv = aResult->GetBindingFor(mRefVariable, ref);
     if (NS_FAILED(rv))
         return false;
 
     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc());
     if (! xuldoc)
         return false;
 
-    *aLocations = new nsCOMArray<nsIContent>;
+    *aLocations = new nsCOMArray<Element>;
     NS_ENSURE_TRUE(*aLocations, false);
 
     xuldoc->GetElementsForID(ref, **aLocations);
     uint32_t count = (*aLocations)->Count();
 
     bool found = false;
 
     for (uint32_t t = 0; t < count; t++) {
@@ -1573,84 +1586,83 @@ nsXULContentBuilder::GetInsertionLocatio
 
     return found;
 }
 
 nsresult
 nsXULContentBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult,
                                   nsTemplateMatch* aNewMatch,
                                   nsTemplateRule* aNewMatchRule,
-                                  void *aContext)
+                                  Element* aContext)
 
 {
     nsresult rv;
-    nsIContent* content = static_cast<nsIContent*>(aContext);
 
     // update the container attributes for the match
-    if (content) {
+    if (aContext) {
         nsAutoString ref;
         if (aNewMatch)
             rv = aNewMatch->mResult->GetBindingFor(mRefVariable, ref);
         else
             rv = aOldResult->GetBindingFor(mRefVariable, ref);
         if (NS_FAILED(rv))
             return rv;
 
         if (!ref.IsEmpty()) {
             nsCOMPtr<nsIXULTemplateResult> refResult;
             rv = GetResultForId(ref, getter_AddRefs(refResult));
             if (NS_FAILED(rv))
                 return rv;
 
             if (refResult)
-                SetContainerAttrs(content, refResult, false, true);
+                SetContainerAttrs(aContext, refResult, false, true);
         }
     }
 
     if (aOldResult) {
-        nsCOMArray<nsIContent> elements;
+        nsCOMArray<Element> elements;
         rv = GetElementsForResult(aOldResult, elements);
         if (NS_FAILED(rv))
             return rv;
 
         uint32_t count = elements.Count();
 
         for (int32_t e = int32_t(count) - 1; e >= 0; --e) {
             nsCOMPtr<nsIContent> child = elements.SafeObjectAt(e);
 
             nsTemplateMatch* match;
             if (mContentSupportMap.Get(child, &match)) {
-                if (content == match->GetContainer())
+                if (aContext == match->GetContainer())
                     RemoveMember(child);
             }
         }
     }
 
     if (aNewMatch) {
         nsCOMPtr<nsIContent> action = aNewMatchRule->GetAction();
-        return BuildContentFromTemplate(action, content, content, true,
+        return BuildContentFromTemplate(action, aContext, aContext, true,
                                         mRefVariable == aNewMatchRule->GetMemberVariable(),
                                         aNewMatch->mResult, true, aNewMatch,
                                         nullptr, nullptr);
     }
 
     return NS_OK;
 }
 
 
 nsresult
 nsXULContentBuilder::SynchronizeResult(nsIXULTemplateResult* aResult)
 {
-    nsCOMArray<nsIContent> elements;
+    nsCOMArray<Element> elements;
     GetElementsForResult(aResult, elements);
 
     uint32_t cnt = elements.Count();
 
     for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
-        nsCOMPtr<nsIContent> element = elements.SafeObjectAt(i);
+        nsCOMPtr<Element> element = elements.SafeObjectAt(i);
 
         nsTemplateMatch* match;
         if (! mContentSupportMap.Get(element, &match))
             continue;
 
         nsCOMPtr<nsIContent> templateNode;
         mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode));
 
@@ -1666,17 +1678,17 @@ nsXULContentBuilder::SynchronizeResult(n
 }
 
 //----------------------------------------------------------------------
 //
 // Implementation methods
 //
 
 nsresult
-nsXULContentBuilder::OpenContainer(nsIContent* aElement)
+nsXULContentBuilder::OpenContainer(Element* aElement)
 {
     if (aElement != mRoot) {
         if (mFlags & eDontRecurse)
             return NS_OK;
 
         bool rightBuilder = false;
 
         nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aElement->GetComposedDoc());
@@ -1702,17 +1714,17 @@ nsXULContentBuilder::OpenContainer(nsICo
     }
 
     CreateTemplateAndContainerContents(aElement, false);
 
     return NS_OK;
 }
 
 nsresult
-nsXULContentBuilder::CloseContainer(nsIContent* aElement)
+nsXULContentBuilder::CloseContainer(Element* aElement)
 {
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::RebuildAll()
 {
     NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
@@ -1788,17 +1800,17 @@ nsXULContentBuilder::CompareResultToNode
     // flip the sort order if performing a descending sorting
     if (mSortState.direction == nsSortState_descending)
         *aSortOrder = -*aSortOrder;
 
     return NS_OK;
 }
 
 nsresult
-nsXULContentBuilder::InsertSortedNode(nsIContent* aContainer,
+nsXULContentBuilder::InsertSortedNode(Element* aContainer,
                                       nsIContent* aNode,
                                       nsIXULTemplateResult* aResult,
                                       bool aNotify)
 {
     nsresult rv;
 
     if (!mSortState.initialized) {
         nsAutoString sort, sortDirection, sortHints;
--- a/dom/xul/templates/nsXULContentUtils.cpp
+++ b/dom/xul/templates/nsXULContentUtils.cpp
@@ -121,25 +121,25 @@ nsXULContentUtils::GetCollation()
 }
 
 //------------------------------------------------------------------------
 
 nsresult
 nsXULContentUtils::FindChildByTag(nsIContent* aElement,
                                   int32_t aNameSpaceID,
                                   nsAtom* aTag,
-                                  nsIContent** aResult)
+                                  Element** aResult)
 {
     for (nsIContent* child = aElement->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
 
-        if (child->NodeInfo()->Equals(aTag, aNameSpaceID)) {
-            NS_ADDREF(*aResult = child);
-
+        if (child->IsElement() &&
+            child->NodeInfo()->Equals(aTag, aNameSpaceID)) {
+            NS_ADDREF(*aResult = child->AsElement());
             return NS_OK;
         }
     }
 
     *aResult = nullptr;
     return NS_RDF_NO_VALUE; // not found
 }
 
--- a/dom/xul/templates/nsXULContentUtils.h
+++ b/dom/xul/templates/nsXULContentUtils.h
@@ -18,16 +18,22 @@ class nsAtom;
 class nsIContent;
 class nsIDocument;
 class nsIRDFNode;
 class nsIRDFResource;
 class nsIRDFLiteral;
 class nsIRDFService;
 class nsICollation;
 
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
+
 // errors to pass to LogTemplateError
 #define ERROR_TEMPLATE_INVALID_QUERYPROCESSOR                           \
         "querytype attribute doesn't specify a valid query processor"
 #define ERROR_TEMPLATE_INVALID_QUERYSET                                 \
         "unexpected <queryset> element"
 #define ERROR_TEMPLATE_NO_MEMBERVAR                                     \
         "no member variable found. Action body should have an element with uri attribute"
 #define ERROR_TEMPLATE_WHERE_NO_SUBJECT                                 \
@@ -98,17 +104,17 @@ public:
 
     static nsresult
     Finish();
 
     static nsresult
     FindChildByTag(nsIContent *aElement,
                    int32_t aNameSpaceID,
                    nsAtom* aTag,
-                   nsIContent **aResult);
+                   mozilla::dom::Element** aResult);
 
     static nsresult
     FindChildByResource(nsIContent* aElement,
                         nsIRDFResource* aResource,
                         nsIContent** aResult);
 
     static nsresult
     GetTextForNode(nsIRDFNode* aNode, nsAString& aResult);
--- a/dom/xul/templates/nsXULSortService.cpp
+++ b/dom/xul/templates/nsXULSortService.cpp
@@ -23,36 +23,36 @@
 #include "nsIXULTemplateBuilder.h"
 #include "nsTemplateMatch.h"
 #include "nsICollation.h"
 #include "nsUnicharUtils.h"
 
 NS_IMPL_ISUPPORTS(XULSortServiceImpl, nsIXULSortService)
 
 void
-XULSortServiceImpl::SetSortHints(nsIContent *aNode, nsSortState* aSortState)
+XULSortServiceImpl::SetSortHints(Element* aElement, nsSortState* aSortState)
 {
   // set sort and sortDirection attributes when is sort is done
-  aNode->SetAttr(kNameSpaceID_None, nsGkAtoms::sort,
-                 aSortState->sort, true);
+  aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sort,
+                    aSortState->sort, true);
 
   nsAutoString direction;
   if (aSortState->direction == nsSortState_descending)
     direction.AssignLiteral("descending");
   else if (aSortState->direction == nsSortState_ascending)
     direction.AssignLiteral("ascending");
-  aNode->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
-                 direction, true);
+  aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
+                    direction, true);
 
   // for trees, also set the sort info on the currently sorted column
-  if (aNode->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
+  if (aElement->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
     if (aSortState->sortKeys.Length() >= 1) {
       nsAutoString sortkey;
       aSortState->sortKeys[0]->ToString(sortkey);
-      SetSortColumnHints(aNode, sortkey, direction);
+      SetSortColumnHints(aElement, sortkey, direction);
     }
   }
 }
 
 void
 XULSortServiceImpl::SetSortColumnHints(nsIContent *content,
                                        const nsAString &sortResource,
                                        const nsAString &sortDirection)
@@ -66,27 +66,28 @@ XULSortServiceImpl::SetSortColumnHints(n
       SetSortColumnHints(child, sortResource, sortDirection);
     } else if (child->IsXULElement(nsGkAtoms::treecol)) {
       nsAutoString value;
       child->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, value);
       // also check the resource attribute for older code
       if (value.IsEmpty())
         child->GetAttr(kNameSpaceID_None, nsGkAtoms::resource, value);
       if (value == sortResource) {
-        child->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
-                       NS_LITERAL_STRING("true"), true);
-        child->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
-                       sortDirection, true);
+        child->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
+                                    NS_LITERAL_STRING("true"), true);
+
+        child->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
+                                    sortDirection, true);
         // Note: don't break out of loop; want to set/unset
         // attribs on ALL sort columns
       } else if (!value.IsEmpty()) {
-        child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
-                         true);
-        child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
-                         true);
+        child->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
+                                      true);
+        child->AsElement()->UnsetAttr(kNameSpaceID_None,
+                                      nsGkAtoms::sortDirection, true);
       }
     }
   }
 }
 
 nsresult
 XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
                                    nsSortState* aSortState,
@@ -104,17 +105,17 @@ XULSortServiceImpl::GetItemsToSort(nsICo
         return rv;
 
       return GetTemplateItemsToSort(aContainer, builder, aSortState, aSortItems);
     }
   }
 
   // if there is no template builder, just get the children. For trees,
   // get the treechildren element as use that as the parent
-  nsCOMPtr<nsIContent> treechildren;
+  RefPtr<Element> treechildren;
   if (aContainer->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
     nsXULContentUtils::FindChildByTag(aContainer,
                                       kNameSpaceID_XUL,
                                       nsGkAtoms::treechildren,
                                       getter_AddRefs(treechildren));
     if (!treechildren)
       return NS_OK;
 
@@ -318,18 +319,18 @@ XULSortServiceImpl::InvertSortInfo(nsTAr
     while (half-- > 0) {
       aData[downPoint--].swap(aData[upPoint++]);
     }
   }
   return NS_OK;
 }
 
 nsresult
-XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement,
-                                        nsIContent* aContainer,
+XULSortServiceImpl::InitializeSortState(Element* aRootElement,
+                                        Element* aContainer,
                                         const nsAString& aSortKey,
                                         const nsAString& aSortHints,
                                         nsSortState* aSortState)
 {
   // used as an optimization for the content builder
   if (aContainer != aSortState->lastContainer.get()) {
     aSortState->lastContainer = aContainer;
     aSortState->lastWasFirst = false;
@@ -462,17 +463,17 @@ XULSortServiceImpl::CompareValues(const 
 }
 
 NS_IMETHODIMP
 XULSortServiceImpl::Sort(nsIDOMNode* aNode,
                          const nsAString& aSortKey,
                          const nsAString& aSortHints)
 {
   // get root content node
-  nsCOMPtr<nsIContent> sortNode = do_QueryInterface(aNode);
+  nsCOMPtr<Element> sortNode = do_QueryInterface(aNode);
   if (!sortNode)
     return NS_ERROR_FAILURE;
 
   nsSortState sortState;
   nsresult rv = InitializeSortState(sortNode, sortNode,
                                     aSortKey, aSortHints, &sortState);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/xul/templates/nsXULSortService.h
+++ b/dom/xul/templates/nsXULSortService.h
@@ -91,17 +91,17 @@ public:
 
   // nsISortService
   NS_DECL_NSIXULSORTSERVICE
 
   /**
    * Set sort and sortDirection attributes when a sort is done.
    */
   void
-  SetSortHints(nsIContent *aNode, nsSortState* aSortState);
+  SetSortHints(mozilla::dom::Element* aElement, nsSortState* aSortState);
 
   /**
    * Set sortActive and sortDirection attributes on a tree column when a sort
    * is done. The column to change is the one with a sort attribute that
    * matches the sort key. The sort attributes are removed from the other
    * columns.
    */
   void
@@ -151,18 +151,18 @@ public:
    *
    * @param aRootElement the element that contains sort attributes
    * @param aContainer the container to sort, usually equal to aRootElement
    * @param aSortKey space separated list of sort keys
    * @param aSortDirection direction to sort in
    * @param aSortState structure filled in with sort data
    */
   static nsresult
-  InitializeSortState(nsIContent* aRootElement,
-                      nsIContent* aContainer,
+  InitializeSortState(mozilla::dom::Element* aRootElement,
+                      mozilla::dom::Element* aContainer,
                       const nsAString& aSortKey,
                       const nsAString& aSortDirection,
                       nsSortState* aSortState);
 
   /**
    * Compares aLeft and aRight and returns < 0, 0, or > 0. The sort
    * hints are checked for case matching and integer sorting.
    */
--- a/dom/xul/templates/nsXULTemplateBuilder.cpp
+++ b/dom/xul/templates/nsXULTemplateBuilder.cpp
@@ -471,17 +471,17 @@ nsXULTemplateBuilder::Init()
     if (NS_SUCCEEDED(rv)) {
         StartObserving(doc);
     }
 
     return rv;
 }
 
 NS_IMETHODIMP
-nsXULTemplateBuilder::CreateContents(nsIContent* aElement, bool aForceCreation)
+nsXULTemplateBuilder::CreateContents(Element* aElement, bool aForceCreation)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTemplateBuilder::HasGeneratedContent(nsIRDFResource* aResource,
                                           nsAtom* aTag,
                                           bool* aGenerated)
@@ -570,17 +570,17 @@ nsXULTemplateBuilder::UpdateResult(nsIXU
       return NS_OK;
 
     // get the containers where content may be inserted. If
     // GetInsertionLocations returns false, no container has generated
     // any content yet so new content should not be generated either. This
     // will be false if the result applies to content that is in a closed menu
     // or treeitem for example.
 
-    nsAutoPtr<nsCOMArray<nsIContent> > insertionPoints;
+    nsAutoPtr<nsCOMArray<Element> > insertionPoints;
     bool mayReplace = GetInsertionLocations(aOldResult ? aOldResult : aNewResult,
                                               getter_Transfers(insertionPoints));
     if (! mayReplace)
         return NS_OK;
 
     nsresult rv = NS_OK;
 
     nsCOMPtr<nsIRDFResource> oldId, newId;
@@ -627,17 +627,17 @@ nsXULTemplateBuilder::UpdateResult(nsIXU
             return NS_OK;
     }
 
     if (insertionPoints) {
         // iterate over each insertion point and add or remove the result from
         // that container
         uint32_t count = insertionPoints->Count();
         for (uint32_t t = 0; t < count; t++) {
-            nsCOMPtr<nsIContent> insertionPoint = insertionPoints->SafeObjectAt(t);
+            nsCOMPtr<Element> insertionPoint = insertionPoints->SafeObjectAt(t);
             if (insertionPoint) {
                 rv = UpdateResultInContainer(aOldResult, aNewResult, queryset,
                                              oldId, newId, insertionPoint);
                 if (NS_FAILED(rv))
                     return rv;
             }
         }
     }
@@ -652,17 +652,17 @@ nsXULTemplateBuilder::UpdateResult(nsIXU
 }
 
 nsresult
 nsXULTemplateBuilder::UpdateResultInContainer(nsIXULTemplateResult* aOldResult,
                                               nsIXULTemplateResult* aNewResult,
                                               nsTemplateQuerySet* aQuerySet,
                                               nsIRDFResource* aOldId,
                                               nsIRDFResource* aNewId,
-                                              nsIContent* aInsertionPoint)
+                                              Element* aInsertionPoint)
 {
     // This method takes a result that no longer applies (aOldResult) and
     // replaces it with a new result (aNewResult). Either may be null
     // indicating to just remove a result or add a new one without replacing.
     //
     // Matches are stored in the hashtable mMatchMap, keyed by result id. If
     // there is more than one query, or the same id is found in different
     // containers, the values in the hashtable will be a linked list of all
@@ -1699,22 +1699,21 @@ nsXULTemplateBuilder::SubstituteTextRepl
     }
 
     c->str += replacementText;
 }
 
 bool
 nsXULTemplateBuilder::IsTemplateElement(nsIContent* aContent)
 {
-    return aContent->NodeInfo()->Equals(nsGkAtoms::_template,
-                                        kNameSpaceID_XUL);
+    return aContent->NodeInfo()->Equals(nsGkAtoms::_template, kNameSpaceID_XUL);
 }
 
 nsresult
-nsXULTemplateBuilder::GetTemplateRoot(nsIContent** aResult)
+nsXULTemplateBuilder::GetTemplateRoot(Element** aResult)
 {
     NS_PRECONDITION(mRoot != nullptr, "not initialized");
     if (! mRoot)
         return NS_ERROR_NOT_INITIALIZED;
 
     // First, check and see if the root has a template attribute. This
     // allows a template to be specified "out of line"; e.g.,
     //
@@ -1730,58 +1729,58 @@ nsXULTemplateBuilder::GetTemplateRoot(ns
         nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mRoot->GetComposedDoc());
         if (! domDoc)
             return NS_OK;
 
         nsCOMPtr<nsIDOMElement> domElement;
         domDoc->GetElementById(templateID, getter_AddRefs(domElement));
 
         if (domElement) {
-            nsCOMPtr<nsIContent> content = do_QueryInterface(domElement);
+            nsCOMPtr<Element> content = do_QueryInterface(domElement);
             NS_ENSURE_STATE(content &&
                             !nsContentUtils::ContentIsDescendantOf(mRoot,
                                                                    content));
             content.forget(aResult);
             return NS_OK;
         }
     }
 
     // If root node has no template attribute, then look for a child
     // node which is a template tag.
     for (nsIContent* child = mRoot->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
 
         if (IsTemplateElement(child)) {
-            NS_ADDREF(*aResult = child);
+            NS_ADDREF(*aResult = child->AsElement());
             return NS_OK;
         }
     }
 
     // Look through the anonymous children as well. Although FlattenedChildIterator
     // will find a template element that has been placed in an insertion point, many
     // bindings do not have a specific insertion point for the template element, which
     // would cause it to not be part of the flattened content tree. The check above to
     // check the explicit children as well handles this case.
     FlattenedChildIterator iter(mRoot);
     for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
         if (IsTemplateElement(child)) {
-            NS_ADDREF(*aResult = child);
+            NS_ADDREF(*aResult = child->AsElement());
             return NS_OK;
         }
     }
 
     *aResult = nullptr;
     return NS_OK;
 }
 
 nsresult
 nsXULTemplateBuilder::CompileQueries()
 {
-    nsCOMPtr<nsIContent> tmpl;
+    nsCOMPtr<Element> tmpl;
     GetTemplateRoot(getter_AddRefs(tmpl));
     if (! tmpl)
         return NS_OK;
 
     if (! mRoot)
         return NS_ERROR_NOT_INITIALIZED;
 
     // Determine if there are any special settings we need to observe
@@ -1862,17 +1861,17 @@ nsXULTemplateBuilder::CompileQueries()
     }
 
     mQueriesCompiled = true;
 
     return NS_OK;
 }
 
 nsresult
-nsXULTemplateBuilder::CompileTemplate(nsIContent* aTemplate,
+nsXULTemplateBuilder::CompileTemplate(Element* aTemplate,
                                       nsTemplateQuerySet* aQuerySet,
                                       bool aIsQuerySet,
                                       int32_t* aPriority,
                                       bool* aCanUseTemplate)
 {
     NS_ASSERTION(aQuerySet, "No queryset supplied");
 
     nsresult rv = NS_OK;
@@ -1910,27 +1909,29 @@ nsXULTemplateBuilder::CompileTemplate(ns
                 if (!mQuerySets.AppendElement(aQuerySet)) {
                     delete aQuerySet;
                     return NS_ERROR_OUT_OF_MEMORY;
                 }
             }
 
             hasQuerySet = true;
 
-            rv = CompileTemplate(rulenode, aQuerySet, true, aPriority, aCanUseTemplate);
+            // Known to be a <xul:queryset>.
+            rv = CompileTemplate(rulenode->AsElement(), aQuerySet, true,
+                                 aPriority, aCanUseTemplate);
             if (NS_FAILED(rv))
                 return rv;
         }
 
         // once a queryset is used, everything must be a queryset
         if (isQuerySetMode)
             continue;
 
         if (ni->Equals(nsGkAtoms::rule, kNameSpaceID_XUL)) {
-            nsCOMPtr<nsIContent> action;
+            RefPtr<Element> action;
             nsXULContentUtils::FindChildByTag(rulenode,
                                               kNameSpaceID_XUL,
                                               nsGkAtoms::action,
                                               getter_AddRefs(action));
 
             if (action){
                 RefPtr<nsAtom> memberVariable = mMemberVariable;
                 if (!memberVariable) {
@@ -1954,30 +1955,32 @@ nsXULTemplateBuilder::CompileTemplate(ns
                         rv = mQueryProcessor->CompileQuery(this, query,
                                                            mRefVariable, memberVariable,
                                                            getter_AddRefs(aQuerySet->mCompiledQuery));
                         if (NS_FAILED(rv))
                             return rv;
                     }
 
                     if (aQuerySet->mCompiledQuery) {
-                        rv = CompileExtendedQuery(rulenode, action, memberVariable,
+                        // It's an element (we test it for <xul:rule>, plus it
+                        // has `action` as a kid).
+                        rv = CompileExtendedQuery(rulenode->AsElement(),
+                                                  action, memberVariable,
                                                   aQuerySet);
                         if (NS_FAILED(rv))
                             return rv;
 
                         *aCanUseTemplate = true;
                     }
-                }
-                else {
+                } else {
                     // backwards-compatible RDF template syntax where there is
                     // an <action> node but no <query> node. In this case,
                     // use the conditions as if it was the query.
 
-                    nsCOMPtr<nsIContent> conditions;
+                    RefPtr<Element> conditions;
                     nsXULContentUtils::FindChildByTag(rulenode,
                                                       kNameSpaceID_XUL,
                                                       nsGkAtoms::conditions,
                                                       getter_AddRefs(conditions));
 
                     if (conditions) {
                         // create a new queryset if one hasn't been created already
                         if (hasQuerySet) {
@@ -2001,56 +2004,58 @@ nsXULTemplateBuilder::CompileTemplate(ns
                         rv = mQueryProcessor->CompileQuery(this, conditionsnode,
                                                            mRefVariable,
                                                            memberVariable,
                                                            getter_AddRefs(aQuerySet->mCompiledQuery));
                         if (NS_FAILED(rv))
                             return rv;
 
                         if (aQuerySet->mCompiledQuery) {
-                            rv = CompileExtendedQuery(rulenode, action, memberVariable,
+                            // Known to be a <xul:rule>, plus known to have
+                            // kids.
+                            rv = CompileExtendedQuery(rulenode->AsElement(),
+                                                      action, memberVariable,
                                                       aQuerySet);
                             if (NS_FAILED(rv))
                                 return rv;
 
                             *aCanUseTemplate = true;
                         }
                     }
                 }
-            }
-            else {
+            } else {
                 if (hasQuery)
                     continue;
 
                 // a new queryset must always be created in this case
                 if (hasQuerySet) {
                     aQuerySet = new nsTemplateQuerySet(++*aPriority);
                     if (!mQuerySets.AppendElement(aQuerySet)) {
                         delete aQuerySet;
                         return NS_ERROR_OUT_OF_MEMORY;
                     }
                 }
 
                 hasQuerySet = true;
 
-                rv = CompileSimpleQuery(rulenode, aQuerySet, aCanUseTemplate);
+                // Known to be a <xul:rule>.
+                rv = CompileSimpleQuery(rulenode->AsElement(), aQuerySet,
+                                        aCanUseTemplate);
                 if (NS_FAILED(rv))
                     return rv;
             }
 
             hasRule = true;
-        }
-        else if (ni->Equals(nsGkAtoms::query, kNameSpaceID_XUL)) {
+        } else if (ni->Equals(nsGkAtoms::query, kNameSpaceID_XUL)) {
             if (hasQuery)
               continue;
 
             aQuerySet->mQueryNode = rulenode;
             hasQuery = true;
-        }
-        else if (ni->Equals(nsGkAtoms::action, kNameSpaceID_XUL)) {
+        } else if (ni->Equals(nsGkAtoms::action, kNameSpaceID_XUL)) {
             // the query must appear before the action
             if (! hasQuery)
                 continue;
 
             RefPtr<nsAtom> tag;
             DetermineRDFQueryRef(aQuerySet->mQueryNode, getter_AddRefs(tag));
             if (tag)
                 aQuerySet->SetTag(tag);
@@ -2089,30 +2094,30 @@ nsXULTemplateBuilder::CompileTemplate(ns
         // <template> tag are the one-and-only template.
         rv = CompileSimpleQuery(aTemplate, aQuerySet, aCanUseTemplate);
      }
 
     return rv;
 }
 
 nsresult
-nsXULTemplateBuilder::CompileExtendedQuery(nsIContent* aRuleElement,
+nsXULTemplateBuilder::CompileExtendedQuery(Element* aRuleElement,
                                            nsIContent* aActionElement,
                                            nsAtom* aMemberVariable,
                                            nsTemplateQuerySet* aQuerySet)
 {
     // Compile an "extended" <template> rule. An extended rule may have
     // a <conditions> child, an <action> child, and a <bindings> child.
     nsresult rv;
 
     nsTemplateRule* rule = aQuerySet->NewRule(aRuleElement, aActionElement, aQuerySet);
     if (! rule)
          return NS_ERROR_OUT_OF_MEMORY;
 
-    nsCOMPtr<nsIContent> conditions;
+    RefPtr<Element> conditions;
     nsXULContentUtils::FindChildByTag(aRuleElement,
                                       kNameSpaceID_XUL,
                                       nsGkAtoms::conditions,
                                       getter_AddRefs(conditions));
 
     // allow the conditions to be placed directly inside the rule
     if (!conditions)
         conditions = aRuleElement;
@@ -2122,17 +2127,17 @@ nsXULTemplateBuilder::CompileExtendedQue
     if (NS_FAILED(rv)) {
         aQuerySet->RemoveRule(rule);
         return rv;
     }
 
     rule->SetVars(mRefVariable, aMemberVariable);
 
     // If we've got bindings, add 'em.
-    nsCOMPtr<nsIContent> bindings;
+    RefPtr<Element> bindings;
     nsXULContentUtils::FindChildByTag(aRuleElement,
                                       kNameSpaceID_XUL,
                                       nsGkAtoms::bindings,
                                       getter_AddRefs(bindings));
 
     // allow bindings to be placed directly inside rule
     if (!bindings)
         bindings = aRuleElement;
@@ -2165,17 +2170,17 @@ nsXULTemplateBuilder::DetermineMemberVar
 
     return nullptr;
 }
 
 void
 nsXULTemplateBuilder::DetermineRDFQueryRef(nsIContent* aQueryElement, nsAtom** aTag)
 {
     // check for a tag
-    nsCOMPtr<nsIContent> content;
+    RefPtr<Element> content;
     nsXULContentUtils::FindChildByTag(aQueryElement,
                                       kNameSpaceID_XUL,
                                       nsGkAtoms::content,
                                       getter_AddRefs(content));
 
     if (! content) {
         // look for older treeitem syntax as well
         nsXULContentUtils::FindChildByTag(aQueryElement,
@@ -2195,17 +2200,17 @@ nsXULTemplateBuilder::DetermineRDFQueryR
         content->GetAttr(kNameSpaceID_None, nsGkAtoms::tag, tag);
 
         if (!tag.IsEmpty())
             *aTag = NS_Atomize(tag).take();
     }
 }
 
 nsresult
-nsXULTemplateBuilder::CompileSimpleQuery(nsIContent* aRuleElement,
+nsXULTemplateBuilder::CompileSimpleQuery(Element* aRuleElement,
                                          nsTemplateQuerySet* aQuerySet,
                                          bool* aCanUseTemplate)
 {
     // compile a simple query, which is a query with no <query> or
     // <conditions>. This means that a default query is used.
     nsCOMPtr<nsIDOMNode> query(do_QueryInterface(aRuleElement));
 
     RefPtr<nsAtom> memberVariable;
@@ -2452,30 +2457,30 @@ nsXULTemplateBuilder::CompileBinding(nsT
         return NS_OK;
     }
 
     return aRule->AddBinding(svar, predicate, ovar);
 }
 
 nsresult
 nsXULTemplateBuilder::AddSimpleRuleBindings(nsTemplateRule* aRule,
-                                            nsIContent* aElement)
+                                            Element* aElement)
 {
     // Crawl the content tree of a "simple" rule, adding a variable
     // assignment for any attribute whose value is "rdf:".
 
-    AutoTArray<nsIContent*, 8> elements;
+    AutoTArray<Element*, 8> elements;
 
     if (elements.AppendElement(aElement) == nullptr)
         return NS_ERROR_OUT_OF_MEMORY;
 
     while (elements.Length()) {
         // Pop the next element off the stack
         uint32_t i = elements.Length() - 1;
-        nsIContent* element = elements[i];
+        Element* element = elements[i];
         elements.RemoveElementAt(i);
 
         // Iterate through its attributes, looking for substitutions
         // that we need to add as bindings.
         uint32_t count = element->GetAttrCount();
 
         for (i = 0; i < count; ++i) {
             const nsAttrName* name = element->GetAttrNameAt(i);
@@ -2490,18 +2495,20 @@ nsXULTemplateBuilder::AddSimpleRuleBindi
                 ParseAttribute(value, AddBindingsFor, nullptr, aRule);
             }
         }
 
         // Push kids onto the stack, and search them next.
         for (nsIContent* child = element->GetLastChild();
              child;
              child = child->GetPreviousSibling()) {
-
-            if (!elements.AppendElement(child))
+            if (!child->IsElement())
+                continue;
+
+            if (!elements.AppendElement(child->AsElement()))
                 return NS_ERROR_OUT_OF_MEMORY;
         }
     }
 
     aRule->AddBindingsToQueryProcessor(mQueryProcessor);
 
     return NS_OK;
 }
--- a/dom/xul/templates/nsXULTemplateBuilder.h
+++ b/dom/xul/templates/nsXULTemplateBuilder.h
@@ -154,17 +154,17 @@ public:
      * @param aInsertionPoint container to remove or add result inside
      */
     nsresult
     UpdateResultInContainer(nsIXULTemplateResult* aOldResult,
                             nsIXULTemplateResult* aNewResult,
                             nsTemplateQuerySet* aQuerySet,
                             nsIRDFResource* aOldId,
                             nsIRDFResource* aNewId,
-                            nsIContent* aInsertionPoint);
+                            Element* aInsertionPoint);
 
     nsresult
     ComputeContainmentProperties();
 
     static bool
     IsTemplateElement(nsIContent* aContent);
 
     virtual nsresult
@@ -188,17 +188,17 @@ public:
     // generated content can be removed during uninitialization.
     void UninitFalse() { Uninit(false); mRoot = nullptr; }
     void UninitTrue() { Uninit(true); mRoot = nullptr; }
 
     /**
      * Find the <template> tag that applies for this builder
      */
     nsresult
-    GetTemplateRoot(nsIContent** aResult);
+    GetTemplateRoot(Element** aResult);
 
     /**
      * Compile the template's queries
      */
     nsresult
     CompileQueries();
 
     /**
@@ -213,33 +213,33 @@ public:
      *
      * @param aTemplate <template> to compile
      * @param aQuerySet first queryset
      * @param aIsQuerySet true if
      * @param aPriority the queryset index, incremented when a new one is added
      * @param aCanUseTemplate true if template is valid
      */
     nsresult
-    CompileTemplate(nsIContent* aTemplate,
+    CompileTemplate(Element* aTemplate,
                     nsTemplateQuerySet* aQuerySet,
                     bool aIsQuerySet,
                     int32_t* aPriority,
                     bool* aCanUseTemplate);
 
     /**
      * Compile a query using the extended syntax. For backwards compatible RDF
      * syntax where there is no <query>, the <conditions> becomes the query.
      *
      * @param aRuleElement <rule> element
      * @param aActionElement <action> element
      * @param aMemberVariable member variable for the query
      * @param aQuerySet the queryset
      */
     nsresult
-    CompileExtendedQuery(nsIContent* aRuleElement,
+    CompileExtendedQuery(Element* aRuleElement,
                          nsIContent* aActionElement,
                          nsAtom* aMemberVariable,
                          nsTemplateQuerySet* aQuerySet);
 
     /**
      * Determine the ref variable and tag from inside a RDF query.
      */
     void DetermineRDFQueryRef(nsIContent* aQueryElement, nsAtom** tag);
@@ -255,17 +255,17 @@ public:
      * <query> and should use a default query which would normally just return
      * a list of children of the reference point.
      *
      * @param aRuleElement the <rule>
      * @param aQuerySet the query set
      * @param aCanUseTemplate true if the query is valid
      */
     nsresult
-    CompileSimpleQuery(nsIContent* aRuleElement,
+    CompileSimpleQuery(Element* aRuleElement,
                        nsTemplateQuerySet* aQuerySet,
                        bool* aCanUseTemplate);
 
     /**
      * Compile the <conditions> tag in a rule
      *
      * @param aRule template rule
      * @param aConditions <conditions> element
@@ -299,17 +299,17 @@ public:
      */
     nsresult
     CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding);
 
     /**
      * Add automatic bindings for simple rules
      */
     nsresult
-    AddSimpleRuleBindings(nsTemplateRule* aRule, nsIContent* aElement);
+    AddSimpleRuleBindings(nsTemplateRule* aRule, Element* aElement);
 
     static void
     AddBindingsFor(nsXULTemplateBuilder* aSelf,
                    const nsAString& aVariable,
                    void* aClosure);
 
     /**
      * Load the datasources for the template. shouldDelayBuilding is an out
@@ -489,29 +489,29 @@ protected:
      * Those results will be generated when the container is opened.
      * If false is returned, no content should be generated. Possible
      * insertion locations may optionally be set for new content, depending on
      * the builder being used. Note that *aLocations or some items within
      * aLocations may be null.
      */
     virtual bool
     GetInsertionLocations(nsIXULTemplateResult* aResult,
-                          nsCOMArray<nsIContent>** aLocations) = 0;
+                          nsCOMArray<Element>** aLocations) = 0;
 
     /**
      * Must be implemented by subclasses. Handle removing the generated
      * output for aOldMatch and adding new output for aNewMatch. Either
      * aOldMatch or aNewMatch may be null. aContext is the location returned
      * from the call to MayGenerateResult.
      */
     virtual nsresult
     ReplaceMatch(nsIXULTemplateResult* aOldResult,
                  nsTemplateMatch* aNewMatch,
                  nsTemplateRule* aNewMatchRule,
-                 void *aContext) = 0;
+                 Element* aContext) = 0;
 
     /**
      * Must be implemented by subclasses. Handle change in bound
      * variable values for aResult. aModifiedVars contains the set
      * of variables that have changed.
      * @param aResult the ersult for which variable bindings has changed.
      * @param aModifiedVars the set of variables for which the bindings
      * have changed.
--- a/dom/xul/templates/nsXULTemplateQueryProcessorRDF.cpp
+++ b/dom/xul/templates/nsXULTemplateQueryProcessorRDF.cpp
@@ -359,24 +359,24 @@ nsXULTemplateQueryProcessorRDF::CompileQ
 
     if (content->NodeInfo()->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
         // simplified syntax with no rules
 
         query->SetSimple();
         NS_ASSERTION(!mSimpleRuleMemberTest,
                      "CompileQuery called twice with the same template");
         if (!mSimpleRuleMemberTest)
-            rv = CompileSimpleQuery(query, content, &lastnode);
+            rv = CompileSimpleQuery(query, content->AsElement(), &lastnode);
         else
             rv = NS_ERROR_FAILURE;
     }
     else if (content->NodeInfo()->Equals(nsGkAtoms::rule, kNameSpaceID_XUL)) {
         // simplified syntax with at least one rule
         query->SetSimple();
-        rv = CompileSimpleQuery(query, content, &lastnode);
+        rv = CompileSimpleQuery(query, content->AsElement(), &lastnode);
     }
     else {
         rv = CompileExtendedQuery(query, content, &lastnode);
     }
 
     if (NS_FAILED(rv))
         return rv;
 
@@ -1476,17 +1476,17 @@ nsXULTemplateQueryProcessorRDF::AddDefau
     mSimpleRuleMemberTest = membernode;
     *aChildNode = membernode;
 
     return NS_OK;
 }
 
 nsresult
 nsXULTemplateQueryProcessorRDF::CompileSimpleQuery(nsRDFQuery* aQuery,
-                                                   nsIContent* aQueryElement,
+                                                   Element* aQueryElement,
                                                    TestNode** aLastNode)
 {
     // Compile a "simple" (or old-school style) <template> query.
     nsresult rv;
 
     TestNode* parentNode;
 
     if (! mSimpleRuleMemberTest) {
--- a/dom/xul/templates/nsXULTemplateQueryProcessorRDF.h
+++ b/dom/xul/templates/nsXULTemplateQueryProcessorRDF.h
@@ -29,16 +29,22 @@
 #include "mozilla/Attributes.h"
 
 #include "mozilla/Logging.h"
 extern mozilla::LazyLogModule gXULTemplateLog;
 
 class nsIContent;
 class nsXULTemplateResultRDF;
 
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
+
 /**
  * An object that generates results from a query on an RDF graph
  */
 class nsXULTemplateQueryProcessorRDF final : public nsIXULTemplateQueryProcessor,
                                              public nsIRDFObserver
 {
 public:
     typedef nsTArray<RefPtr<nsXULTemplateResultRDF> > ResultArray;
@@ -178,18 +184,18 @@ public:
     /**
      * Compile a query that's specified using the simple template
      * syntax. Each  TestNode is created in a chain, the last compiled node
      * is returned as aLastNode. All nodes will have been added to mAllTests
      * which owns the nodes.
      */
     nsresult
     CompileSimpleQuery(nsRDFQuery* aQuery,
-                      nsIContent* aQueryElement,
-                      TestNode** aLastNode);
+                       mozilla::dom::Element* aQueryElement,
+                       TestNode** aLastNode);
 
     RDFBindingSet*
     GetBindingsForRule(nsIDOMNode* aRule);
 
     /*
      * Indicate that a result is dependant on a particular resource. When an
      * assertion is added to or removed from the graph involving that
      * resource, that result must be recalculated.
--- a/dom/xul/templates/nsXULTreeBuilder.cpp
+++ b/dom/xul/templates/nsXULTreeBuilder.cpp
@@ -275,17 +275,17 @@ void
 nsXULTreeBuilder::GetRowProperties(int32_t aRow, nsAString& aProperties,
                                    ErrorResult& aError)
 {
     if (!IsValidRowIndex(aRow)) {
         aError.Throw(NS_ERROR_INVALID_ARG);
         return;
     }
 
-    nsCOMPtr<nsIContent> row;
+    nsCOMPtr<Element> row;
     GetTemplateActionRowFor(aRow, getter_AddRefs(row));
     if (row) {
         nsAutoString raw;
         row->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw);
 
         if (!raw.IsEmpty()) {
             SubstituteText(mRows[aRow]->mMatch->mResult, raw, aProperties);
         }
@@ -1041,17 +1041,17 @@ nsXULTreeBuilder::HasGeneratedContent(ns
     }
 
     return aResource == rootresource ||
            mRows.FindByResource(aResource) != mRows.Last();
 }
 
 bool
 nsXULTreeBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
-                                        nsCOMArray<nsIContent>** aLocations)
+                                        nsCOMArray<Element>** aLocations)
 {
     *aLocations = nullptr;
 
     // Get the reference point and check if it is an open container. Rows
     // should not be generated otherwise.
 
     nsAutoString ref;
     nsresult rv = aResult->GetBindingFor(mRefVariable, ref);
@@ -1084,17 +1084,17 @@ struct ResultComparator
         return mTreebuilder->CompareResults(mResult, aSubtree.mMatch->mResult);
     }
 };
 
 nsresult
 nsXULTreeBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult,
                                nsTemplateMatch* aNewMatch,
                                nsTemplateRule* aNewMatchRule,
-                               void *aLocation)
+                               Element*)
 {
     if (! mBoxObject)
         return NS_OK;
 
     if (aOldResult) {
         // Grovel through the rows looking for oldresult.
         nsTreeRows::iterator iter = mRows.Find(aOldResult);
 
@@ -1245,17 +1245,17 @@ nsXULTreeBuilder::SynchronizeResult(nsIX
 
 //----------------------------------------------------------------------
 
 nsresult
 nsXULTreeBuilder::EnsureSortVariables()
 {
     // Grovel through <treecols> kids to find the <treecol>
     // with the sort attributes.
-    nsCOMPtr<nsIContent> treecols;
+    nsCOMPtr<Element> treecols;
 
     nsXULContentUtils::FindChildByTag(mRoot, kNameSpaceID_XUL,
                                       nsGkAtoms::treecols,
                                       getter_AddRefs(treecols));
 
     if (!treecols)
         return NS_OK;
 
@@ -1339,36 +1339,36 @@ nsXULTreeBuilder::RebuildAll()
     if (mBoxObject) {
         mBoxObject->EndUpdateBatch();
     }
 
     return rv;
 }
 
 nsresult
-nsXULTreeBuilder::GetTemplateActionRowFor(int32_t aRow, nsIContent** aResult)
+nsXULTreeBuilder::GetTemplateActionRowFor(int32_t aRow, Element** aResult)
 {
     // Get the template in the DOM from which we're supposed to
     // generate text
     nsTreeRows::Row& row = *(mRows[aRow]);
 
     // The match stores the indices of the rule and query to use. Use these
     // to look up the right nsTemplateRule and use that rule's action to get
     // the treerow in the template.
     int16_t ruleindex = row.mMatch->RuleIndex();
     if (ruleindex >= 0) {
         nsTemplateQuerySet* qs = mQuerySets[row.mMatch->QuerySetPriority()];
         nsTemplateRule* rule = qs->GetRuleAt(ruleindex);
         if (rule) {
-            nsCOMPtr<nsIContent> children;
+            nsCOMPtr<Element> children;
             nsXULContentUtils::FindChildByTag(rule->GetAction(), kNameSpaceID_XUL,
                                               nsGkAtoms::treechildren,
                                               getter_AddRefs(children));
             if (children) {
-                nsCOMPtr<nsIContent> item;
+                nsCOMPtr<Element> item;
                 nsXULContentUtils::FindChildByTag(children, kNameSpaceID_XUL,
                                                   nsGkAtoms::treeitem,
                                                   getter_AddRefs(item));
                 if (item)
                     return nsXULContentUtils::FindChildByTag(item,
                                                              kNameSpaceID_XUL,
                                                              nsGkAtoms::treerow,
                                                              aResult);
@@ -1378,17 +1378,17 @@ nsXULTreeBuilder::GetTemplateActionRowFo
 
     *aResult = nullptr;
     return NS_OK;
 }
 
 nsIContent*
 nsXULTreeBuilder::GetTemplateActionCellFor(int32_t aRow, nsTreeColumn& aCol)
 {
-    nsCOMPtr<nsIContent> row;
+    RefPtr<Element> row;
     GetTemplateActionRowFor(aRow, getter_AddRefs(row));
     if (!row) {
         return nullptr;
     }
 
     RefPtr<nsAtom> colAtom(aCol.GetAtom());
     int32_t colIndex(aCol.GetIndex());
 
--- a/dom/xul/templates/nsXULTreeBuilder.h
+++ b/dom/xul/templates/nsXULTreeBuilder.h
@@ -156,17 +156,17 @@ protected:
     virtual nsresult
     RebuildAll() override;
 
     /**
      * Given a row, use the row's match to figure out the appropriate
      * <treerow> in the rule's <action>.
      */
     nsresult
-    GetTemplateActionRowFor(int32_t aRow, nsIContent** aResult);
+    GetTemplateActionRowFor(int32_t aRow, mozilla::dom::Element** aResult);
 
     /**
      * Given a row and a column ID, use the row's match to figure out
      * the appropriate <treecell> in the rule's <action>.
      */
     nsIContent*
     GetTemplateActionCellFor(int32_t aRow, nsTreeColumn& aCol);
 
@@ -243,26 +243,26 @@ protected:
     // from nsXULTemplateBuilder
 
     /**
      * Return true if the result can be inserted into the template as a new
      * row.
      */
     bool
     GetInsertionLocations(nsIXULTemplateResult* aResult,
-                          nsCOMArray<nsIContent>** aLocations) override;
+                          nsCOMArray<Element>** aLocations) override;
 
     /**
      * Implement result replacement
      */
     virtual nsresult
     ReplaceMatch(nsIXULTemplateResult* aOldResult,
                  nsTemplateMatch* aNewMatch,
                  nsTemplateRule* aNewMatchRule,
-                 void* aContext) override;
+                 Element* aContext) override;
 
     /**
      * Implement match synchronization
      */
     virtual nsresult
     SynchronizeResult(nsIXULTemplateResult* aResult) override;
 
     bool IsValidRowIndex(int32_t aRowIndex);
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -5343,17 +5343,17 @@ EditorBase::DetermineCurrentDirection()
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorBase::SwitchTextDirection()
 {
   // Get the current root direction from its frame
-  nsIContent* rootElement = GetExposedRoot();
+  Element* rootElement = GetExposedRoot();
 
   nsresult rv = DetermineCurrentDirection();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Apply the opposite direction
   if (IsRightToLeft()) {
     NS_ASSERTION(!IsLeftToRight(),
                  "Unexpected mutually exclusive flag");
@@ -5374,17 +5374,17 @@ EditorBase::SwitchTextDirection()
 
   return rv;
 }
 
 void
 EditorBase::SwitchTextDirectionTo(uint32_t aDirection)
 {
   // Get the current root direction from its frame
-  nsIContent* rootElement = GetExposedRoot();
+  Element* rootElement = GetExposedRoot();
 
   nsresult rv = DetermineCurrentDirection();
   NS_ENSURE_SUCCESS_VOID(rv);
 
   // Apply the requested direction
   if (aDirection == nsIPlaintextEditor::eEditorLeftToRight &&
       IsRightToLeft()) {
     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -750,17 +750,17 @@ protected:
                              const nsAString* aAttribute,
                              const bool aChildrenOnly = false);
   nsresult RemoveInlinePropertyImpl(nsAtom* aProperty,
                                     const nsAString* aAttribute);
 
   bool NodeIsProperty(nsINode& aNode);
   bool IsAtFrontOfNode(nsINode& aNode, int32_t aOffset);
   bool IsAtEndOfNode(nsINode& aNode, int32_t aOffset);
-  bool IsOnlyAttribute(const nsIContent* aElement, const nsAString& aAttribute);
+  bool IsOnlyAttribute(const Element* aElement, const nsAString& aAttribute);
 
   nsresult RemoveBlockContainer(nsIContent& aNode);
 
   nsIContent* GetPriorHTMLSibling(nsINode* aNode);
 
   nsIContent* GetNextHTMLSibling(nsINode* aNode);
 
   /**
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -726,31 +726,29 @@ HTMLEditor::RemoveStyleInside(nsIContent
           CloneAttribute(nsGkAtoms::style, spanNode, aNode.AsElement());
         NS_ENSURE_SUCCESS(rv, rv);
         rv =
           CloneAttribute(nsGkAtoms::_class, spanNode, aNode.AsElement());
         NS_ENSURE_SUCCESS(rv, rv);
       }
       nsresult rv = RemoveContainer(&aNode);
       NS_ENSURE_SUCCESS(rv, rv);
-    } else {
+    } else if (aNode.IsElement()) {
       // otherwise we just want to eliminate the attribute
       RefPtr<nsAtom> attribute = NS_Atomize(*aAttribute);
-      if (aNode.HasAttr(kNameSpaceID_None, attribute)) {
+      if (aNode.AsElement()->HasAttr(kNameSpaceID_None, attribute)) {
         // if this matching attribute is the ONLY one on the node,
         // then remove the whole node.  Otherwise just nix the attribute.
-        if (IsOnlyAttribute(&aNode, *aAttribute)) {
+        if (IsOnlyAttribute(aNode.AsElement(), *aAttribute)) {
           nsresult rv = RemoveContainer(&aNode);
           if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
           }
         } else {
-          nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(&aNode);
-          NS_ENSURE_TRUE(elem, NS_ERROR_NULL_POINTER);
-          nsresult rv = RemoveAttribute(elem, *aAttribute);
+          nsresult rv = RemoveAttribute(aNode.AsElement(), attribute);
           if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
           }
         }
       }
     }
   }
 
@@ -791,24 +789,24 @@ HTMLEditor::RemoveStyleInside(nsIContent
       aAttribute && aAttribute->LowerCaseEqualsLiteral("size")) {
     // if we are setting font size, remove any nested bigs and smalls
     return RemoveContainer(&aNode);
   }
   return NS_OK;
 }
 
 bool
-HTMLEditor::IsOnlyAttribute(const nsIContent* aContent,
+HTMLEditor::IsOnlyAttribute(const Element* aElement,
                             const nsAString& aAttribute)
 {
-  MOZ_ASSERT(aContent);
+  MOZ_ASSERT(aElement);
 
-  uint32_t attrCount = aContent->GetAttrCount();
+  uint32_t attrCount = aElement->GetAttrCount();
   for (uint32_t i = 0; i < attrCount; ++i) {
-    const nsAttrName* name = aContent->GetAttrNameAt(i);
+    const nsAttrName* name = aElement->GetAttrNameAt(i);
     if (!name->NamespaceEquals(kNameSpaceID_None)) {
       return false;
     }
 
     nsAutoString attrString;
     name->LocalName()->ToString(attrString);
     // if it's the attribute we know about, or a special _moz attribute,
     // keep looking
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -1380,19 +1380,22 @@ TextEditRules::CreateTrailingBRIfNeeded(
 
   // Check to see if the trailing BR is a former bogus node - this will have
   // stuck around if we previously morphed a trailing node into a bogus node.
   if (!mTextEditor->IsMozEditorBogusNode(lastChild)) {
     return NS_OK;
   }
 
   // Morph it back to a mozBR
-  lastChild->UnsetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom, false);
-  lastChild->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
-                     NS_LITERAL_STRING("_moz"), true);
+  lastChild->AsElement()->UnsetAttr(kNameSpaceID_None,
+                                    kMOZEditorBogusNodeAttrAtom,
+                                    false);
+  lastChild->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
+                                  NS_LITERAL_STRING("_moz"),
+                                  true);
   return NS_OK;
 }
 
 nsresult
 TextEditRules::CreateBogusNodeIfNeeded(Selection* aSelection)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(mTextEditor, NS_ERROR_NULL_POINTER);
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -5882,17 +5882,17 @@ nsCSSFrameConstructor::AddFrameConstruct
       if (!xblService)
         return;
 
       bool resolveStyle;
 
       nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
 
       nsresult rv = xblService->LoadBindings(
-        aContent, display->mBinding->GetURI(),
+        aContent->AsElement(), display->mBinding->GetURI(),
         display->mBinding->mExtraData->GetPrincipal(),
         getter_AddRefs(newPendingBinding->mBinding), &resolveStyle);
       if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
         return;
 
       if (newPendingBinding->mBinding) {
         pendingBinding = newPendingBinding;
         // aState takes over owning newPendingBinding
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -8489,57 +8489,57 @@ nsLayoutUtils::PostRestyleEvent(Element*
     nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
     if (presShell) {
       presShell->GetPresContext()->RestyleManager()->PostRestyleEvent(
         aElement, aRestyleHint, aMinChangeHint);
     }
   }
 }
 
-nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent,
+nsSetAttrRunnable::nsSetAttrRunnable(Element* aElement,
                                      nsAtom* aAttrName,
                                      const nsAString& aValue)
   : mozilla::Runnable("nsSetAttrRunnable")
-  , mContent(aContent)
+  , mElement(aElement)
   , mAttrName(aAttrName)
   , mValue(aValue)
 {
-  NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
-}
-
-nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent,
+  NS_ASSERTION(aElement && aAttrName, "Missing stuff, prepare to crash");
+}
+
+nsSetAttrRunnable::nsSetAttrRunnable(Element* aElement,
                                      nsAtom* aAttrName,
                                      int32_t aValue)
   : mozilla::Runnable("nsSetAttrRunnable")
-  , mContent(aContent)
+  , mElement(aElement)
   , mAttrName(aAttrName)
 {
-  NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
+  NS_ASSERTION(aElement && aAttrName, "Missing stuff, prepare to crash");
   mValue.AppendInt(aValue);
 }
 
 NS_IMETHODIMP
 nsSetAttrRunnable::Run()
 {
-  return mContent->SetAttr(kNameSpaceID_None, mAttrName, mValue, true);
-}
-
-nsUnsetAttrRunnable::nsUnsetAttrRunnable(nsIContent* aContent,
+  return mElement->SetAttr(kNameSpaceID_None, mAttrName, mValue, true);
+}
+
+nsUnsetAttrRunnable::nsUnsetAttrRunnable(Element* aElement,
                                          nsAtom* aAttrName)
   : mozilla::Runnable("nsUnsetAttrRunnable")
-  , mContent(aContent)
+  , mElement(aElement)
   , mAttrName(aAttrName)
 {
-  NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
+  NS_ASSERTION(aElement && aAttrName, "Missing stuff, prepare to crash");
 }
 
 NS_IMETHODIMP
 nsUnsetAttrRunnable::Run()
 {
-  return mContent->UnsetAttr(kNameSpaceID_None, mAttrName, true);
+  return mElement->UnsetAttr(kNameSpaceID_None, mAttrName, true);
 }
 
 /**
  * Compute the minimum font size inside of a container with the given
  * width, such that **when the user zooms the container to fill the full
  * width of the device**, the fonts satisfy our minima.
  */
 static nscoord
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -3255,36 +3255,36 @@ void StrokeLineWithSnapping(const nsPoin
                                           nsPresContext* aPresContext);
 
   } // namespace layout
 } // namespace mozilla
 
 class nsSetAttrRunnable : public mozilla::Runnable
 {
 public:
-  nsSetAttrRunnable(nsIContent* aContent, nsAtom* aAttrName,
+  nsSetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName,
                     const nsAString& aValue);
-  nsSetAttrRunnable(nsIContent* aContent, nsAtom* aAttrName,
+  nsSetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName,
                     int32_t aValue);
 
   NS_DECL_NSIRUNNABLE
 
-  nsCOMPtr<nsIContent> mContent;
+  RefPtr<Element> mElement;
   RefPtr<nsAtom> mAttrName;
   nsAutoString mValue;
 };
 
 class nsUnsetAttrRunnable : public mozilla::Runnable
 {
 public:
-  nsUnsetAttrRunnable(nsIContent* aContent, nsAtom* aAttrName);
+  nsUnsetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName);
 
   NS_DECL_NSIRUNNABLE
 
-  nsCOMPtr<nsIContent> mContent;
+  RefPtr<Element> mElement;
   RefPtr<nsAtom> mAttrName;
 };
 
 // This class allows you to easily set any pointer variable and ensure it's
 // set to nullptr when leaving its scope.
 template<typename T>
 class MOZ_RAII SetAndNullOnExit
 {
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -55,23 +55,24 @@ nsButtonFrameRenderer::SetFrame(nsFrame*
 
 nsIFrame*
 nsButtonFrameRenderer::GetFrame()
 {
   return mFrame;
 }
 
 void
-nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool notify)
+nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool aNotify)
 {
+  Element* element = mFrame->GetContent()->AsElement();
   if (aDisabled)
-    mFrame->GetContent()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
-                                  notify);
+    element->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
+                     aNotify);
   else
-    mFrame->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, notify);
+    element->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, aNotify);
 }
 
 bool
 nsButtonFrameRenderer::isDisabled()
 {
   return mFrame->GetContent()->AsElement()->
     State().HasState(NS_EVENT_STATE_DISABLED);
 }
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -279,17 +279,17 @@ protected:
 private:
   // If our total transform to the root frame of the root document is only a 2d
   // translation then return that translation, otherwise returns (0,0).
   nsPoint GetCSSTransformTranslation();
 
 protected:
   nsFrameList              mPopupFrames;             // additional named child list
   nsCOMPtr<nsIContent>     mDisplayContent;          // Anonymous content used to display the current selection
-  nsCOMPtr<nsIContent>     mButtonContent;           // Anonymous content for the button
+  RefPtr<Element>     mButtonContent;                // Anonymous content for the button
   nsContainerFrame*        mDisplayFrame;            // frame to display selection
   nsIFrame*                mButtonFrame;             // button frame
   nsIFrame*                mDropdownFrame;           // dropdown list frame
   nsIListControlFrame *    mListControlFrame;        // ListControl Interface for the dropdown frame
 
   // The inline size of our display area.  Used by that frame's reflow
   // to size to the full inline size except the drop-marker.
   nscoord mDisplayISize;
--- a/layout/forms/nsDateTimeControlFrame.h
+++ b/layout/forms/nsDateTimeControlFrame.h
@@ -109,12 +109,12 @@ private:
 
   /**
    * Sync the disabled state of the anonymous children up with our content's.
    */
   void SyncDisabledState();
 
   // Anonymous child which is bound via XBL to an element that wraps the input
   // area and reset button.
-  nsCOMPtr<nsIContent> mInputAreaContent;
+  RefPtr<mozilla::dom::Element> mInputAreaContent;
 };
 
 #endif // nsDateTimeControlFrame_h__
--- a/layout/forms/nsFileControlFrame.h
+++ b/layout/forms/nsFileControlFrame.h
@@ -131,22 +131,22 @@ protected:
     return nsBlockFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
    * The text box input.
    * @see nsFileControlFrame::CreateAnonymousContent
    */
-  nsCOMPtr<nsIContent> mTextContent;
+  RefPtr<Element> mTextContent;
   /**
    * The button to open a file or directory picker.
    * @see nsFileControlFrame::CreateAnonymousContent
    */
-  nsCOMPtr<nsIContent> mBrowseFilesOrDirs;
+  RefPtr<Element> mBrowseFilesOrDirs;
 
   /**
    * Drag and drop mouse listener.
    * This makes sure we don't get used after destruction.
    */
   RefPtr<DnDListener> mMouseListener;
 
 protected:
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -371,18 +371,18 @@ nsHTMLButtonControlFrame::GetNaturalBase
     *aBaseline += BSize(aWM) - (innerBStart + inner->BSize(aWM));
   }
   return true;
 }
 
 nsresult nsHTMLButtonControlFrame::SetFormProperty(nsAtom* aName, const nsAString& aValue)
 {
   if (nsGkAtoms::value == aName) {
-    return mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::value,
-                             aValue, true);
+    return mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::value,
+                                          aValue, true);
   }
   return NS_OK;
 }
 
 nsStyleContext*
 nsHTMLButtonControlFrame::GetAdditionalStyleContext(int32_t aIndex) const
 {
   return mRenderer.GetStyleContext(aIndex);
--- a/layout/generic/ScrollbarActivity.cpp
+++ b/layout/generic/ScrollbarActivity.cpp
@@ -11,16 +11,17 @@
 #include "nsIDOMEvent.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIFrame.h"
 #include "nsContentUtils.h"
 #include "nsAString.h"
 #include "nsQueryFrame.h"
 #include "nsComponentManagerUtils.h"
 #include "nsStyledElement.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace layout {
 
 NS_IMPL_ISUPPORTS(ScrollbarActivity, nsIDOMEventListener)
 
@@ -154,17 +155,17 @@ bool
 ScrollbarActivity::IsStillFading(TimeStamp aTime)
 {
   return !mFadeBeginTime.IsNull() && (aTime - mFadeBeginTime < FadeDuration());
 }
 
 void
 ScrollbarActivity::HandleEventForScrollbar(const nsAString& aType,
                                            nsIContent* aTarget,
-                                           nsIContent* aScrollbar,
+                                           Element* aScrollbar,
                                            bool* aStoredHoverState)
 {
   if (!aTarget || !aScrollbar ||
       !nsContentUtils::ContentIsDescendantOf(aTarget, aScrollbar))
     return;
 
   if (aType.EqualsLiteral("mousedown")) {
     ActivityStarted();
@@ -318,24 +319,24 @@ ScrollbarActivity::UnregisterFromRefresh
 {
   nsRefreshDriver* refreshDriver = GetRefreshDriver();
   if (refreshDriver) {
     refreshDriver->RemoveRefreshObserver(this, FlushType::Style);
   }
 }
 
 static void
-SetBooleanAttribute(nsIContent* aContent, nsAtom* aAttribute, bool aValue)
+SetBooleanAttribute(Element* aElement, nsAtom* aAttribute, bool aValue)
 {
-  if (aContent) {
+  if (aElement) {
     if (aValue) {
-      aContent->SetAttr(kNameSpaceID_None, aAttribute,
+      aElement->SetAttr(kNameSpaceID_None, aAttribute,
                         NS_LITERAL_STRING("true"), true);
     } else {
-      aContent->UnsetAttr(kNameSpaceID_None, aAttribute, true);
+      aElement->UnsetAttr(kNameSpaceID_None, aAttribute, true);
     }
   }
 }
 
 void
 ScrollbarActivity::SetIsActive(bool aNewActive)
 {
   if (mIsActive == aNewActive)
@@ -440,31 +441,31 @@ void
 ScrollbarActivity::CancelFadeBeginTimer()
 {
   if (mFadeBeginTimer) {
     mFadeBeginTimer->Cancel();
   }
 }
 
 void
-ScrollbarActivity::HoveredScrollbar(nsIContent* aScrollbar)
+ScrollbarActivity::HoveredScrollbar(Element* aScrollbar)
 {
   SetBooleanAttribute(GetHorizontalScrollbar(), nsGkAtoms::hover, false);
   SetBooleanAttribute(GetVerticalScrollbar(), nsGkAtoms::hover, false);
   SetBooleanAttribute(aScrollbar, nsGkAtoms::hover, true);
 }
 
 nsRefreshDriver*
 ScrollbarActivity::GetRefreshDriver()
 {
   nsIFrame* scrollableFrame = do_QueryFrame(mScrollableFrame);
   return scrollableFrame->PresContext()->RefreshDriver();
 }
 
-nsIContent*
+Element*
 ScrollbarActivity::GetScrollbarContent(bool aVertical)
 {
   nsIFrame* box = mScrollableFrame->GetScrollbarBox(aVertical);
-  return box ? box->GetContent() : nullptr;
+  return box ? box->GetContent()->AsElement() : nullptr;
 }
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/generic/ScrollbarActivity.h
+++ b/layout/generic/ScrollbarActivity.h
@@ -97,17 +97,17 @@ protected:
 
   bool IsActivityOngoing()
   { return mNestedActivityCounter > 0; }
   bool IsStillFading(TimeStamp aTime);
   void QueryLookAndFeelVals();
 
   void HandleEventForScrollbar(const nsAString& aType,
                                nsIContent* aTarget,
-                               nsIContent* aScrollbar,
+                               dom::Element* aScrollbar,
                                bool* aStoredHoverState);
 
   void SetIsActive(bool aNewActive);
   bool SetIsFading(bool aNewFading); // returns false if 'this' was destroyed
 
   void BeginFade();
   void EndFade();
 
@@ -120,22 +120,22 @@ protected:
   void StopListeningForScrollAreaEvents();
   void AddScrollbarEventListeners(nsIDOMEventTarget* aScrollbar);
   void RemoveScrollbarEventListeners(nsIDOMEventTarget* aScrollbar);
 
   void RegisterWithRefreshDriver();
   void UnregisterFromRefreshDriver();
 
   bool UpdateOpacity(TimeStamp aTime); // returns false if 'this' was destroyed
-  void HoveredScrollbar(nsIContent* aScrollbar);
+  void HoveredScrollbar(dom::Element* aScrollbar);
 
   nsRefreshDriver* GetRefreshDriver();
-  nsIContent* GetScrollbarContent(bool aVertical);
-  nsIContent* GetHorizontalScrollbar() { return GetScrollbarContent(false); }
-  nsIContent* GetVerticalScrollbar() { return GetScrollbarContent(true); }
+  dom::Element* GetScrollbarContent(bool aVertical);
+  dom::Element* GetHorizontalScrollbar() { return GetScrollbarContent(false); }
+  dom::Element* GetVerticalScrollbar() { return GetScrollbarContent(true); }
 
   const TimeDuration FadeDuration() {
     return TimeDuration::FromMilliseconds(mScrollbarFadeDuration);
   }
 
   nsIScrollbarMediator* mScrollableFrame;
   TimeStamp mFadeBeginTime;
   nsCOMPtr<nsITimer> mFadeBeginTimer;
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -1258,17 +1258,18 @@ nsHTMLFramesetFrame::MouseDrag(nsPresCon
       HTMLFrameSetElement* ourContent = HTMLFrameSetElement::FromContent(mContent);
       NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
       const nsFramesetSpec* colSpecs = nullptr;
       ourContent->GetColSpec(&mNumCols, &colSpecs);
       nsAutoString newColAttr;
       GenerateRowCol(aPresContext, width, mNumCols, colSpecs, mColSizes.get(),
                      newColAttr);
       // Setting the attr will trigger a reflow
-      mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::cols, newColAttr, true);
+      mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::cols,
+                                     newColAttr, true);
     }
   } else {
     change = aPresContext->DevPixelsToAppUnits(
                              aEvent->mRefPoint.y - mFirstDragPoint.y);
     if (change > mNextNeighborOrigSize - mMinDrag) {
       change = mNextNeighborOrigSize - mMinDrag;
     } else if (change <= mMinDrag - mPrevNeighborOrigSize) {
       change = mMinDrag - mPrevNeighborOrigSize;
@@ -1282,17 +1283,18 @@ nsHTMLFramesetFrame::MouseDrag(nsPresCon
       HTMLFrameSetElement* ourContent = HTMLFrameSetElement::FromContent(mContent);
       NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
       const nsFramesetSpec* rowSpecs = nullptr;
       ourContent->GetRowSpec(&mNumRows, &rowSpecs);
       nsAutoString newRowAttr;
       GenerateRowCol(aPresContext, height, mNumRows, rowSpecs, mRowSizes.get(),
                      newRowAttr);
       // Setting the attr will trigger a reflow
-      mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::rows, newRowAttr, true);
+      mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::rows,
+                                     newRowAttr, true);
     }
   }
 
   ENSURE_TRUE(weakFrame.IsAlive());
   if (change != 0) {
     mDrag.Reset(mDragger->mVertical, mDragger->mPrevNeighbor, change, this);
   }
 }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -4743,24 +4743,24 @@ ScrollFrameHelper::Destroy(PostDestroyDa
 void
 ScrollFrameHelper::UpdateScrollbarPosition()
 {
   AutoWeakFrame weakFrame(mOuter);
   mFrameIsUpdatingScrollbar = true;
 
   nsPoint pt = GetScrollPosition();
   if (mVScrollbarBox) {
-    SetCoordAttribute(mVScrollbarBox->GetContent(), nsGkAtoms::curpos,
-                      pt.y - GetScrolledRect().y);
+    SetCoordAttribute(mVScrollbarBox->GetContent()->AsElement(),
+                      nsGkAtoms::curpos, pt.y - GetScrolledRect().y);
     if (!weakFrame.IsAlive()) {
       return;
     }
   }
   if (mHScrollbarBox) {
-    SetCoordAttribute(mHScrollbarBox->GetContent(), nsGkAtoms::curpos,
+    SetCoordAttribute(mHScrollbarBox->GetContent()->AsElement(), nsGkAtoms::curpos,
                       pt.x - GetScrolledRect().x);
     if (!weakFrame.IsAlive()) {
       return;
     }
   }
 
   mFrameIsUpdatingScrollbar = false;
 }
@@ -5419,28 +5419,28 @@ nsXULScrollFrame::XULLayout(nsBoxLayoutS
 
   mHelper.UpdatePrevScrolledRect();
 
   mHelper.PostOverflowEvent();
   return NS_OK;
 }
 
 void
-ScrollFrameHelper::FinishReflowForScrollbar(nsIContent* aContent,
-                                                nscoord aMinXY, nscoord aMaxXY,
-                                                nscoord aCurPosXY,
-                                                nscoord aPageIncrement,
-                                                nscoord aIncrement)
+ScrollFrameHelper::FinishReflowForScrollbar(Element* aElement,
+                                            nscoord aMinXY, nscoord aMaxXY,
+                                            nscoord aCurPosXY,
+                                            nscoord aPageIncrement,
+                                            nscoord aIncrement)
 {
   // Scrollbars assume zero is the minimum position, so translate for them.
-  SetCoordAttribute(aContent, nsGkAtoms::curpos, aCurPosXY - aMinXY);
-  SetScrollbarEnabled(aContent, aMaxXY - aMinXY);
-  SetCoordAttribute(aContent, nsGkAtoms::maxpos, aMaxXY - aMinXY);
-  SetCoordAttribute(aContent, nsGkAtoms::pageincrement, aPageIncrement);
-  SetCoordAttribute(aContent, nsGkAtoms::increment, aIncrement);
+  SetCoordAttribute(aElement, nsGkAtoms::curpos, aCurPosXY - aMinXY);
+  SetScrollbarEnabled(aElement, aMaxXY - aMinXY);
+  SetCoordAttribute(aElement, nsGkAtoms::maxpos, aMaxXY - aMinXY);
+  SetCoordAttribute(aElement, nsGkAtoms::pageincrement, aPageIncrement);
+  SetCoordAttribute(aElement, nsGkAtoms::increment, aIncrement);
 }
 
 bool
 ScrollFrameHelper::ReflowFinished()
 {
   mPostedReflowCallback = false;
 
   bool doScroll = true;
@@ -5494,20 +5494,21 @@ ScrollFrameHelper::ReflowFinished()
   nscoord maxX = scrolledContentRect.XMost() - scrollClampingScrollPort.width;
   nscoord minY = scrolledContentRect.y;
   nscoord maxY = scrolledContentRect.YMost() - scrollClampingScrollPort.height;
 
   // Suppress handling of the curpos attribute changes we make here.
   NS_ASSERTION(!mFrameIsUpdatingScrollbar, "We shouldn't be reentering here");
   mFrameIsUpdatingScrollbar = true;
 
-  nsCOMPtr<nsIContent> vScroll =
-    mVScrollbarBox ? mVScrollbarBox->GetContent() : nullptr;
-  nsCOMPtr<nsIContent> hScroll =
-    mHScrollbarBox ? mHScrollbarBox->GetContent() : nullptr;
+  // FIXME(emilio): Why this instead of mHScrollbarContent / mVScrollbarContent?
+  RefPtr<Element> vScroll =
+    mVScrollbarBox ? mVScrollbarBox->GetContent()->AsElement() : nullptr;
+  RefPtr<Element> hScroll =
+    mHScrollbarBox ? mHScrollbarBox->GetContent()->AsElement() : nullptr;
 
   // Note, in some cases mOuter may get deleted while finishing reflow
   // for scrollbars. XXXmats is this still true now that we have a script
   // blocker in this scope? (if not, remove the weak frame checks below).
   if (vScroll || hScroll) {
     AutoWeakFrame weakFrame(mOuter);
     nsPoint scrollPos = GetScrollPosition();
     nsSize lineScrollAmount = GetLineScrollAmount();
@@ -5839,50 +5840,50 @@ ScrollFrameHelper::LayoutScrollbars(nsBo
 static bool ShellIsAlive(nsWeakPtr& aWeakPtr)
 {
   nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aWeakPtr));
   return !!shell;
 }
 #endif
 
 void
-ScrollFrameHelper::SetScrollbarEnabled(nsIContent* aContent, nscoord aMaxPos)
+ScrollFrameHelper::SetScrollbarEnabled(Element* aElement, nscoord aMaxPos)
 {
   DebugOnly<nsWeakPtr> weakShell(
     do_GetWeakReference(mOuter->PresShell()));
   if (aMaxPos) {
-    aContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
+    aElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
   } else {
-    aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
+    aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
                       NS_LITERAL_STRING("true"), true);
   }
   MOZ_ASSERT(ShellIsAlive(weakShell), "pres shell was destroyed by scrolling");
 }
 
 void
-ScrollFrameHelper::SetCoordAttribute(nsIContent* aContent, nsAtom* aAtom,
-                                         nscoord aSize)
+ScrollFrameHelper::SetCoordAttribute(Element* aElement, nsAtom* aAtom,
+                                     nscoord aSize)
 {
   DebugOnly<nsWeakPtr> weakShell(
     do_GetWeakReference(mOuter->PresShell()));
   // convert to pixels
   int32_t pixelSize = nsPresContext::AppUnitsToIntCSSPixels(aSize);
 
   // only set the attribute if it changed.
 
   nsAutoString newValue;
   newValue.AppendInt(pixelSize);
 
-  if (aContent->AttrValueIs(kNameSpaceID_None, aAtom, newValue, eCaseMatters)) {
+  if (aElement->AttrValueIs(kNameSpaceID_None, aAtom, newValue, eCaseMatters)) {
     return;
   }
 
   AutoWeakFrame weakFrame(mOuter);
-  nsCOMPtr<nsIContent> kungFuDeathGrip = aContent;
-  aContent->SetAttr(kNameSpaceID_None, aAtom, newValue, true);
+  RefPtr<Element> kungFuDeathGrip = aElement;
+  aElement->SetAttr(kNameSpaceID_None, aAtom, newValue, true);
   MOZ_ASSERT(ShellIsAlive(weakShell), "pres shell was destroyed by scrolling");
   if (!weakFrame.IsAlive()) {
     return;
   }
 
   if (mScrollbarActivity) {
     RefPtr<ScrollbarActivity> scrollbarActivity(mScrollbarActivity);
     scrollbarActivity->ActivityOccurred();
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -165,28 +165,30 @@ public:
     void Revoke() { mHelper = nullptr; }
   private:
     ScrollFrameHelper *mHelper;
   };
 
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
-  void FinishReflowForScrollbar(nsIContent* aContent, nscoord aMinXY,
-                                nscoord aMaxXY, nscoord aCurPosXY,
-                                nscoord aPageIncrement,
+  void FinishReflowForScrollbar(mozilla::dom::Element* aElement,
+                                nscoord aMinXY, nscoord aMaxXY,
+                                nscoord aCurPosXY, nscoord aPageIncrement,
                                 nscoord aIncrement);
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
-  void SetScrollbarEnabled(nsIContent* aContent, nscoord aMaxPos);
+  void SetScrollbarEnabled(mozilla::dom::Element* aElement, nscoord aMaxPos);
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
-  void SetCoordAttribute(nsIContent* aContent, nsAtom* aAtom, nscoord aSize);
+  void SetCoordAttribute(mozilla::dom::Element* aElement,
+                         nsAtom* aAtom,
+                         nscoord aSize);
 
   nscoord GetCoordAttribute(nsIFrame* aFrame, nsAtom* aAtom, nscoord aDefaultValue,
                             nscoord* aRangeStart, nscoord* aRangeLength);
 
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    * Update scrollbar curpos attributes to reflect current scroll position
    */
@@ -495,20 +497,20 @@ public:
 
   bool DragScroll(WidgetEvent* aEvent);
 
   void AsyncScrollbarDragRejected();
 
   bool IsRootScrollFrameOfDocument() const { return mIsRoot; }
 
   // owning references to the nsIAnonymousContentCreator-built content
-  nsCOMPtr<nsIContent> mHScrollbarContent;
-  nsCOMPtr<nsIContent> mVScrollbarContent;
-  nsCOMPtr<nsIContent> mScrollCornerContent;
-  nsCOMPtr<nsIContent> mResizerContent;
+  nsCOMPtr<mozilla::dom::Element> mHScrollbarContent;
+  nsCOMPtr<mozilla::dom::Element> mVScrollbarContent;
+  nsCOMPtr<mozilla::dom::Element> mScrollCornerContent;
+  nsCOMPtr<mozilla::dom::Element> mResizerContent;
 
   RefPtr<ScrollEvent> mScrollEvent;
   RefPtr<ScrollEndEvent> mScrollEndEvent;
   nsRevocableEventPtr<AsyncScrollPortEvent> mAsyncScrollPortEvent;
   nsRevocableEventPtr<ScrolledAreaEvent> mScrolledAreaEvent;
   nsIFrame* mHScrollbarBox;
   nsIFrame* mVScrollbarBox;
   nsIFrame* mScrolledFrame;
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -88,41 +88,39 @@ NS_QUERYFRAME_HEAD(nsVideoFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 nsresult
 nsVideoFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   nsNodeInfoManager *nodeInfoManager = GetContent()->GetComposedDoc()->NodeInfoManager();
   RefPtr<NodeInfo> nodeInfo;
-  Element *element;
 
   if (HasVideoElement()) {
     // Create an anonymous image element as a child to hold the poster
     // image. We may not have a poster image now, but one could be added
     // before we load, or on a subsequent load.
     nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::img,
                                             nullptr,
                                             kNameSpaceID_XHTML,
                                             nsIDOMNode::ELEMENT_NODE);
     NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
-    element = NS_NewHTMLImageElement(nodeInfo.forget());
-    mPosterImage = element;
+    mPosterImage = NS_NewHTMLImageElement(nodeInfo.forget());
     NS_ENSURE_TRUE(mPosterImage, NS_ERROR_OUT_OF_MEMORY);
 
     // Set the nsImageLoadingContent::ImageState() to 0. This means that the
     // image will always report its state as 0, so it will never be reframed
     // to show frames for loading or the broken image icon. This is important,
     // as the image is native anonymous, and so can't be reframed (currently).
     nsCOMPtr<nsIImageLoadingContent> imgContent = do_QueryInterface(mPosterImage);
     NS_ENSURE_TRUE(imgContent, NS_ERROR_FAILURE);
 
     imgContent->ForceImageState(true, 0);
     // And now have it update its internal state
-    element->UpdateState(false);
+    mPosterImage->UpdateState(false);
 
     UpdatePosterSource(false);
 
     if (!aElements.AppendElement(mPosterImage))
       return NS_ERROR_OUT_OF_MEMORY;
 
     // Set up the caption overlay div for showing any TextTrack data
     nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::div,
--- a/layout/generic/nsVideoFrame.h
+++ b/layout/generic/nsVideoFrame.h
@@ -83,17 +83,17 @@ public:
     return nsSplittableFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
   }
 
   nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                 uint32_t aFilters) override;
 
-  nsIContent* GetPosterImage() { return mPosterImage; }
+  mozilla::dom::Element* GetPosterImage() { return mPosterImage; }
 
   // Returns true if we should display the poster. Note that once we show
   // a video frame, the poster will never be displayed again.
   bool ShouldDisplayPoster();
 
   nsIContent *GetCaptionOverlay() { return mCaptionDiv; }
 
   nsIContent *GetVideoControls() { return mVideoControls; }
@@ -124,19 +124,19 @@ protected:
   void UpdatePosterSource(bool aNotify);
 
   // Notify the mediaElement that the mCaptionDiv was created.
   void UpdateTextTrack();
 
   virtual ~nsVideoFrame();
 
   // Anonymous child which is bound via XBL to the video controls.
-  nsCOMPtr<nsIContent> mVideoControls;
+  RefPtr<mozilla::dom::Element> mVideoControls;
 
   // Anonymous child which is the image element of the poster frame.
-  nsCOMPtr<nsIContent> mPosterImage;
+  RefPtr<mozilla::dom::Element> mPosterImage;
 
   // Anonymous child which is the text track caption display div.
   nsCOMPtr<nsIContent> mCaptionDiv;
 
 };
 
 #endif /* nsVideoFrame_h___ */
--- a/layout/mathml/nsMathMLmactionFrame.cpp
+++ b/layout/mathml/nsMathMLmactionFrame.cpp
@@ -325,17 +325,18 @@ void
 nsMathMLmactionFrame::MouseClick()
 {
   if (NS_MATHML_ACTION_TYPE_TOGGLE == mActionType) {
     if (mChildCount > 1) {
       int32_t selection = (mSelection == mChildCount)? 1 : mSelection + 1;
       nsAutoString value;
       value.AppendInt(selection);
       bool notify = false; // don't yet notify the document
-      mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::selection_, value, notify);
+      mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::selection_,
+                                     value, notify);
 
       // Now trigger a content-changed reflow...
       PresShell()->
         FrameNeedsReflow(mSelectedFrame, nsIPresShell::eTreeChange,
                          NS_FRAME_IS_DIRTY);
     }
   }
 }
--- a/layout/xul/PopupBoxObject.cpp
+++ b/layout/xul/PopupBoxObject.cpp
@@ -156,25 +156,25 @@ PopupBoxObject::SizeTo(int32_t aWidth, i
 {
   if (!mContent)
     return;
 
   nsAutoString width, height;
   width.AppendInt(aWidth);
   height.AppendInt(aHeight);
 
-  nsCOMPtr<nsIContent> content = mContent;
+  RefPtr<Element> element = mContent->AsElement();
 
   // We only want to pass aNotify=true to SetAttr once, but must make sure
   // we pass it when a value is being changed.  Thus, we check if the height
   // is the same and if so, pass true when setting the width.
-  bool heightSame = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
+  bool heightSame = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
 
-  content->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
-  content->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
+  element->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
+  element->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
 }
 
 bool
 PopupBoxObject::AutoPosition()
 {
   nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   if (menuPopupFrame) {
     return menuPopupFrame->GetAutoPosition();
@@ -209,20 +209,21 @@ PopupBoxObject::SetConsumeRollupEvent(ui
 void
 PopupBoxObject::EnableKeyboardNavigator(bool aEnableKeyboardNavigator)
 {
   if (!mContent)
     return;
 
   // Use ignorekeys="true" on the popup instead of using this function.
   if (aEnableKeyboardNavigator)
-    mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys, true);
+    mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys,
+                                     true);
   else
-    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys,
-                      NS_LITERAL_STRING("true"), true);
+    mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys,
+                                   NS_LITERAL_STRING("true"), true);
 }
 
 void
 PopupBoxObject::GetPopupState(nsString& aState)
 {
   // set this here in case there's no frame for the popup
   aState.AssignLiteral("closed");
 
--- a/layout/xul/nsDeckFrame.cpp
+++ b/layout/xul/nsDeckFrame.cpp
@@ -173,17 +173,17 @@ nsDeckFrame::RemoveFrame(ChildListID aLi
     int32_t removedIndex = mFrames.IndexOf(aOldFrame);
     MOZ_ASSERT(removedIndex >= 0,
                "A deck child was removed that was not in mFrames.");
     if (removedIndex < mIndex) {
       mIndex--;
       // This is going to cause us to handle the index change in IndexedChanged,
       // but since the new index will match mIndex, it's essentially a noop.
       nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
-        mContent, nsGkAtoms::selectedIndex, mIndex));
+        mContent->AsElement(), nsGkAtoms::selectedIndex, mIndex));
     }
   }
   nsBoxFrame::RemoveFrame(aListID, aOldFrame);
 }
 
 void
 nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                          const nsDisplayListSet& aLists)
--- a/layout/xul/nsIRootBox.h
+++ b/layout/xul/nsIRootBox.h
@@ -5,29 +5,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef nsIRootBox_h___
 #define nsIRootBox_h___
 
 #include "nsQueryFrame.h"
 class nsPopupSetFrame;
+class nsIPresShell;
 class nsIContent;
-class nsIPresShell;
+
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
 
 class nsIRootBox
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsIRootBox)
 
   virtual nsPopupSetFrame* GetPopupSetFrame() = 0;
   virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) = 0;
 
-  virtual nsIContent* GetDefaultTooltip() = 0;
-  virtual void SetDefaultTooltip(nsIContent* aTooltip) = 0;
+  virtual mozilla::dom::Element* GetDefaultTooltip() = 0;
+  virtual void SetDefaultTooltip(mozilla::dom::Element* aTooltip) = 0;
 
   virtual nsresult AddTooltipSupport(nsIContent* aNode) = 0;
   virtual nsresult RemoveTooltipSupport(nsIContent* aNode) = 0;
 
   static nsIRootBox* GetRootBox(nsIPresShell* aShell);
 };
 
 #endif
--- a/layout/xul/nsMenuFrame.cpp
+++ b/layout/xul/nsMenuFrame.cpp
@@ -64,17 +64,17 @@ NS_DECLARE_FRAME_PROPERTY_FRAMELIST(Popu
 static int32_t gMenuJustOpenedOrClosed = false;
 
 const int32_t kBlinkDelay = 67; // milliseconds
 
 // this class is used for dispatching menu activation events asynchronously.
 class nsMenuActivateEvent : public Runnable
 {
 public:
-  nsMenuActivateEvent(nsIContent* aMenu,
+  nsMenuActivateEvent(Element* aMenu,
                       nsPresContext* aPresContext,
                       bool aIsActivate)
     : mozilla::Runnable("nsMenuActivateEvent")
     , mMenu(aMenu)
     , mPresContext(aPresContext)
     , mIsActivate(aIsActivate)
   {
   }
@@ -104,17 +104,17 @@ public:
 
     EventDispatcher::DispatchDOMEvent(mMenu, nullptr, event,
         mPresContext, nullptr);
 
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIContent> mMenu;
+  RefPtr<Element> mMenu;
   RefPtr<nsPresContext> mPresContext;
   bool mIsActivate;
 };
 
 class nsMenuAttributeChangedEvent : public Runnable
 {
 public:
   nsMenuAttributeChangedEvent(nsIFrame* aFrame, nsAtom* aAttr)
@@ -332,17 +332,18 @@ nsMenuFrame::DestroyFrom(nsIFrame* aDest
   StopBlinking();
 
   // Null out the pointer to this frame in the mediator wrapper so that it
   // doesn't try to interact with a deallocated frame.
   mTimerMediator->ClearFrame();
 
   // if the menu content is just being hidden, it may be made visible again
   // later, so make sure to clear the highlighting.
-  mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, false);
+  mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
+                                   false);
 
   // are we our menu parent's current menu item?
   nsMenuParent* menuParent = GetMenuParent();
   if (menuParent && menuParent->GetCurrentMenuItem() == this) {
     // yes; tell it that we're going away
     menuParent->CurrentMenuIsBeingDestroyed();
   }
 
@@ -548,18 +549,18 @@ nsMenuFrame::ToggleMenuState()
 }
 
 void
 nsMenuFrame::PopupOpened()
 {
   gMenuJustOpenedOrClosed = true;
 
   AutoWeakFrame weakFrame(this);
-  mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
-                    NS_LITERAL_STRING("true"), true);
+  mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
+                                 NS_LITERAL_STRING("true"), true);
   if (!weakFrame.IsAlive())
     return;
 
   nsMenuParent* menuParent = GetMenuParent();
   if (menuParent) {
     menuParent->SetActive(true);
     // Make sure the current menu which is being toggled on
     // the menubar is highlighted
@@ -567,17 +568,17 @@ nsMenuFrame::PopupOpened()
   }
 }
 
 void
 nsMenuFrame::PopupClosed(bool aDeselectMenu)
 {
   AutoWeakFrame weakFrame(this);
   nsContentUtils::AddScriptRunner(
-    new nsUnsetAttrRunnable(mContent, nsGkAtoms::open));
+    new nsUnsetAttrRunnable(mContent->AsElement(), nsGkAtoms::open));
   if (!weakFrame.IsAlive())
     return;
 
   // if the popup is for a menu on a menubar, inform menubar to deactivate
   nsMenuParent* menuParent = GetMenuParent();
   if (menuParent && menuParent->MenuClosed()) {
     if (aDeselectMenu) {
       SelectMenu(false);
@@ -599,17 +600,17 @@ nsMenuFrame::PopupClosed(bool aDeselectM
           nsMenuBarFrame* menubar = do_QueryFrame(parent);
           if (menubar && menubar->GetStayActive())
             return;
 
           parent = parent->GetParent();
         }
 
         nsCOMPtr<nsIRunnable> event =
-          new nsMenuActivateEvent(current->GetContent(),
+          new nsMenuActivateEvent(current->GetContent()->AsElement(),
                                   PresContext(), true);
         mContent->OwnerDoc()->Dispatch(TaskCategory::Other,
                                        event.forget());
       }
     }
   }
 }
 
@@ -650,17 +651,17 @@ nsMenuFrame::SelectMenu(bool aActivateFl
     // cancel the close timer if selecting a menu within the popup to be closed
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm) {
       nsMenuParent* menuParent = GetMenuParent();
       pm->CancelMenuTimer(menuParent);
     }
 
     nsCOMPtr<nsIRunnable> event =
-      new nsMenuActivateEvent(mContent, PresContext(), aActivateFlag);
+      new nsMenuActivateEvent(mContent->AsElement(), PresContext(), aActivateFlag);
     mContent->OwnerDoc()->Dispatch(TaskCategory::Other,
                                    event.forget());
   }
 
   return NS_OK;
 }
 
 nsresult
@@ -901,18 +902,19 @@ nsMenuFrame::Notify(nsITimer* aTimer)
       case 0:
         NS_ASSERTION(false, "Blink timer fired while not blinking");
         StopBlinking();
         break;
       case 1:
         {
           // Turn the highlight back on and wait for a while before closing the menu.
           AutoWeakFrame weakFrame(this);
-          mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
-                            NS_LITERAL_STRING("true"), true);
+          mContent->AsElement()->SetAttr(kNameSpaceID_None,
+                                         nsGkAtoms::menuactive,
+                                         NS_LITERAL_STRING("true"), true);
           if (weakFrame.IsAlive()) {
             aTimer->InitWithCallback(mTimerMediator, kBlinkDelay, nsITimer::TYPE_ONE_SHOT);
           }
         }
         break;
       default: {
         nsMenuParent* menuParent = GetMenuParent();
         if (menuParent) {
@@ -946,18 +948,18 @@ nsMenuFrame::UpdateMenuType()
     case 1:
       mType = eMenuType_Radio;
       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, mGroupName);
       break;
 
     default:
       if (mType != eMenuType_Normal) {
         AutoWeakFrame weakFrame(this);
-        mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
-                            true);
+        mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
+                                         true);
         ENSURE_TRUE(weakFrame.IsAlive());
       }
       mType = eMenuType_Normal;
       break;
   }
   UpdateMenuSpecialState();
 }
 
@@ -1010,18 +1012,18 @@ nsMenuFrame::UpdateMenuSpecialState()
   nsIFrame* firstMenuItem = nsXULPopupManager::GetNextMenuItem(GetParent(), nullptr, true, false);
   nsIFrame* sib = firstMenuItem;
   while (sib) {
     nsMenuFrame* menu = do_QueryFrame(sib);
     if (sib != this) {
       if (menu && menu->GetMenuType() == eMenuType_Radio &&
           menu->IsChecked() && menu->GetRadioGroupName() == mGroupName) {
         /* uncheck the old item */
-        sib->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
-                                     true);
+        sib->GetContent()->AsElement()->UnsetAttr(
+            kNameSpaceID_None, nsGkAtoms::checked, true);
         /* XXX in DEBUG, check to make sure that there aren't two checked items */
         return;
       }
     }
     sib = nsXULPopupManager::GetNextMenuItem(GetParent(), menu, true, true);
     if (sib == firstMenuItem) {
       break;
     }
@@ -1040,17 +1042,17 @@ nsMenuFrame::BuildAcceleratorText(bool a
   }
   // accelText is definitely empty here.
 
   // Now we're going to compute the accelerator text, so remember that we did.
   AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
 
   // If anything below fails, just leave the accelerator text blank.
   AutoWeakFrame weakFrame(this);
-  mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, aNotify);
+  mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, aNotify);
   ENSURE_TRUE(weakFrame.IsAlive());
 
   // See if we have a key node and use that instead.
   nsAutoString keyValue;
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyValue);
   if (keyValue.IsEmpty())
     return;
 
@@ -1175,17 +1177,18 @@ nsMenuFrame::BuildAcceleratorText(bool a
     token = nsCRT::strtok(newStr, ", \t", &newStr);
   }
 
   free(str);
 
   accelText += accelString;
 
   mIgnoreAccelTextChange = true;
-  mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText, aNotify);
+  mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::acceltext,
+                                 accelText, aNotify);
   ENSURE_TRUE(weakFrame.IsAlive());
 
   mIgnoreAccelTextChange = false;
 }
 
 void
 nsMenuFrame::Execute(WidgetGUIEvent* aEvent)
 {
@@ -1226,17 +1229,17 @@ nsMenuFrame::StartBlinking(WidgetGUIEven
 
   if (!ShouldBlink()) {
     PassMenuCommandEventToPopupManager();
     return;
   }
 
   // Blink off.
   AutoWeakFrame weakFrame(this);
-  mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, true);
+  mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, true);
   if (!weakFrame.IsAlive())
     return;
 
   nsMenuParent* menuParent = GetMenuParent();
   if (menuParent) {
     // Make this menu ignore events from now on.
     menuParent->LockMenuUntilClosed(true);
   }
@@ -1278,18 +1281,18 @@ nsMenuFrame::CreateMenuCommandEvent(Widg
   }
 
   // Because the command event is firing asynchronously, a flag is needed to
   // indicate whether user input is being handled. This ensures that a popup
   // window won't get blocked.
   bool userinput = EventStateManager::IsHandlingUserInput();
 
   mDelayedMenuCommandEvent =
-    new nsXULMenuCommandEvent(mContent, isTrusted, shift, control, alt, meta,
-                              userinput, aFlipChecked);
+    new nsXULMenuCommandEvent(mContent->AsElement(), isTrusted, shift, control,
+                              alt, meta, userinput, aFlipChecked);
 }
 
 void
 nsMenuFrame::PassMenuCommandEventToPopupManager()
 {
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   nsMenuParent* menuParent = GetMenuParent();
   if (pm && menuParent && mDelayedMenuCommandEvent) {
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -179,17 +179,17 @@ nsMenuPopupFrame::Init(nsIContent*      
   }
 
   if (aContent->NodeInfo()->Equals(nsGkAtoms::tooltip, kNameSpaceID_XUL) &&
       aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::_default,
                             nsGkAtoms::_true, eIgnoreCase)) {
     nsIRootBox* rootBox =
       nsIRootBox::GetRootBox(PresContext()->GetPresShell());
     if (rootBox) {
-      rootBox->SetDefaultTooltip(aContent);
+      rootBox->SetDefaultTooltip(aContent->AsElement());
     }
   }
 
   AddStateBits(NS_FRAME_IN_POPUP);
 }
 
 bool
 nsMenuPopupFrame::HasRemoteContent() const
@@ -2342,17 +2342,17 @@ nsMenuPopupFrame::DestroyFrom(nsIFrame* 
     PresShell()->CancelReflowCallback(this);
     mReflowCallbackData.Clear();
   }
 
   nsMenuFrame* menu = do_QueryFrame(GetParent());
   if (menu) {
     // clear the open attribute on the parent menu
     nsContentUtils::AddScriptRunner(
-      new nsUnsetAttrRunnable(menu->GetContent(), nsGkAtoms::open));
+      new nsUnsetAttrRunnable(menu->GetContent()->AsElement(), nsGkAtoms::open));
   }
 
   ClearPopupShownDispatcher();
 
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   if (pm)
     pm->PopupDestroyed(this);
 
@@ -2392,17 +2392,17 @@ nsMenuPopupFrame::MoveTo(const CSSIntPoi
 
   nsPresContext* presContext = PresContext();
   mAnchorType = MenuPopupAnchorType_Point;
   mScreenRect.x = aPos.x - presContext->AppUnitsToIntCSSPixels(margin.left);
   mScreenRect.y = aPos.y - presContext->AppUnitsToIntCSSPixels(margin.top);
 
   SetPopupPosition(nullptr, true, false, true);
 
-  nsCOMPtr<nsIContent> popup = mContent;
+  RefPtr<Element> popup = mContent->AsElement();
   if (aUpdateAttrs && (popup->HasAttr(kNameSpaceID_None, nsGkAtoms::left) ||
                        popup->HasAttr(kNameSpaceID_None, nsGkAtoms::top)))
   {
     nsAutoString left, top;
     left.AppendInt(aPos.x);
     top.AppendInt(aPos.y);
     popup->SetAttr(kNameSpaceID_None, nsGkAtoms::left, left, false);
     popup->SetAttr(kNameSpaceID_None, nsGkAtoms::top, top, false);
--- a/layout/xul/nsProgressMeterFrame.cpp
+++ b/layout/xul/nsProgressMeterFrame.cpp
@@ -134,21 +134,21 @@ nsProgressMeterFrame::AttributeChanged(i
 
   // did the progress change?
   bool undetermined = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mode,
                                             nsGkAtoms::undetermined, eCaseMatters);
   if (nsGkAtoms::mode == aAttribute ||
       (!undetermined &&
        (nsGkAtoms::value == aAttribute || nsGkAtoms::max == aAttribute))) {
     nsIFrame* barChild = PrincipalChildList().FirstChild();
-    if (!barChild) return NS_OK;
+    if (!barChild || !barChild->GetContent()->IsElement()) return NS_OK;
     nsIFrame* remainderChild = barChild->GetNextSibling();
     if (!remainderChild) return NS_OK;
     nsCOMPtr<nsIContent> remainderContent = remainderChild->GetContent();
-    if (!remainderContent) return NS_OK;
+    if (!remainderContent->IsElement()) return NS_OK;
 
     int32_t flex = 1, maxFlex = 1;
     if (!undetermined) {
       nsAutoString value, maxValue;
       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxValue);
 
       nsresult error;
@@ -164,19 +164,19 @@ nsProgressMeterFrame::AttributeChanged(i
         flex = 0;
       }
       if (flex > maxFlex) {
         flex = maxFlex;
       }
     }
 
     nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
-      barChild->GetContent(), nsGkAtoms::flex, flex));
+      barChild->GetContent()->AsElement(), nsGkAtoms::flex, flex));
     nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
-      remainderContent, nsGkAtoms::flex, maxFlex - flex));
+      remainderContent->AsElement(), nsGkAtoms::flex, maxFlex - flex));
     nsContentUtils::AddScriptRunner(new nsReflowFrameRunnable(
       this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY));
   }
   return NS_OK;
 }
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -411,23 +411,24 @@ nsResizerFrame::ResizeContent(nsIContent
     if (aOriginalSizeInfo) {
       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::width,
                         aOriginalSizeInfo->width);
       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::height,
                         aOriginalSizeInfo->height);
     }
     // only set the property if the element could have changed in that direction
     if (aDirection.mHorizontal) {
-      aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, aSizeInfo.width, true);
+      aContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::width,
+                                     aSizeInfo.width, true);
     }
     if (aDirection.mVertical) {
-      aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, aSizeInfo.height, true);
+      aContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::height,
+                                     aSizeInfo.height, true);
     }
-  }
-  else {
+  } else {
     nsCOMPtr<nsStyledElement> inlineStyleContent =
       do_QueryInterface(aContent);
     if (inlineStyleContent) {
       nsICSSDeclaration* decl = inlineStyleContent->Style();
 
       if (aOriginalSizeInfo) {
         decl->GetPropertyValue(NS_LITERAL_STRING("width"),
                                aOriginalSizeInfo->width);
--- a/layout/xul/nsRootBoxFrame.cpp
+++ b/layout/xul/nsRootBoxFrame.cpp
@@ -50,18 +50,18 @@ public:
 
   explicit nsRootBoxFrame(nsStyleContext* aContext);
 
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS(nsRootBoxFrame)
 
   virtual nsPopupSetFrame* GetPopupSetFrame() override;
   virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) override;
-  virtual nsIContent* GetDefaultTooltip() override;
-  virtual void SetDefaultTooltip(nsIContent* aTooltip) override;
+  virtual Element* GetDefaultTooltip() override;
+  virtual void SetDefaultTooltip(Element* aTooltip) override;
   virtual nsresult AddTooltipSupport(nsIContent* aNode) override;
   virtual nsresult RemoveTooltipSupport(nsIContent* aNode) override;
 
   virtual void AppendFrames(ChildListID     aListID,
                             nsFrameList&    aFrameList) override;
   virtual void InsertFrames(ChildListID     aListID,
                             nsIFrame*       aPrevFrame,
                             nsFrameList&    aFrameList) override;
@@ -89,17 +89,17 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   nsPopupSetFrame* mPopupSetFrame;
 
 protected:
-  nsIContent* mDefaultTooltip;
+  Element* mDefaultTooltip;
 };
 
 //----------------------------------------------------------------------
 
 nsContainerFrame*
 NS_NewRootBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsRootBoxFrame(aContext);
@@ -226,24 +226,24 @@ nsRootBoxFrame::SetPopupSetFrame(nsPopup
   // element box frame is created.
   if (!mPopupSetFrame || !aPopupSet) {
     mPopupSetFrame = aPopupSet;
   } else {
     NS_NOTREACHED("Popup set is already defined! Only 1 allowed.");
   }
 }
 
-nsIContent*
+Element*
 nsRootBoxFrame::GetDefaultTooltip()
 {
   return mDefaultTooltip;
 }
 
 void
-nsRootBoxFrame::SetDefaultTooltip(nsIContent* aTooltip)
+nsRootBoxFrame::SetDefaultTooltip(Element* aTooltip)
 {
   mDefaultTooltip = aTooltip;
 }
 
 nsresult
 nsRootBoxFrame::AddTooltipSupport(nsIContent* aNode)
 {
   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
--- a/layout/xul/nsScrollbarButtonFrame.cpp
+++ b/layout/xul/nsScrollbarButtonFrame.cpp
@@ -113,31 +113,32 @@ nsScrollbarButtonFrame::HandleButtonPres
   GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
 
   if (scrollbar == nullptr)
     return false;
 
   static nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::increment,
                                                    &nsGkAtoms::decrement,
                                                    nullptr };
-  int32_t index = mContent->FindAttrValueIn(kNameSpaceID_None,
-                                            nsGkAtoms::type,
-                                            strings, eCaseMatters);
+  int32_t index = mContent->AsElement()->FindAttrValueIn(kNameSpaceID_None,
+                                                         nsGkAtoms::type,
+                                                         strings, eCaseMatters);
   int32_t direction;
   if (index == 0)
     direction = 1;
   else if (index == 1)
     direction = -1;
   else
     return false;
 
   bool repeat = pressedButtonAction != 2;
   // set this attribute so we can style it later
   AutoWeakFrame weakFrame(this);
-  mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
+  mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::active,
+                                 NS_LITERAL_STRING("true"), true);
 
   nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED);
 
   if (!weakFrame.IsAlive()) {
     return false;
   }
 
   nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
@@ -190,17 +191,17 @@ nsScrollbarButtonFrame::HandleButtonPres
 
 NS_IMETHODIMP
 nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext,
                                       WidgetGUIEvent* aEvent,
                                       nsEventStatus* aEventStatus)
 {
   nsIPresShell::SetCapturingContent(nullptr, 0);
   // we're not active anymore
-  mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
+  mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
   StopRepeat();
   nsIFrame* scrollbar;
   GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
   nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
   if (sb) {
     nsIScrollbarMediator* m = sb->GetScrollbarMediator();
     if (m) {
       m->ScrollbarReleased(sb);
--- a/layout/xul/nsScrollbarFrame.cpp
+++ b/layout/xul/nsScrollbarFrame.cpp
@@ -232,17 +232,17 @@ nsScrollbarFrame::SetIncrementToWhole(in
   // of a page.
   mSmoothScroll = false;
 }
 
 int32_t
 nsScrollbarFrame::MoveToNewPosition()
 {
   // get the scrollbar's content node
-  nsCOMPtr<nsIContent> content = GetContent();
+  RefPtr<Element> content = GetContent()->AsElement();
 
   // get the current pos
   int32_t curpos = nsSliderFrame::GetCurrentPosition(content);
 
   // get the max pos
   int32_t maxpos = nsSliderFrame::GetMaxPosition(content);
 
   // increment the given amount
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -258,18 +258,17 @@ nsSliderFrame::AttributeChanged(int32_t 
   // if the current position changes
   if (aAttribute == nsGkAtoms::curpos) {
      CurrentPositionChanged();
   } else if (aAttribute == nsGkAtoms::minpos ||
              aAttribute == nsGkAtoms::maxpos) {
       // bounds check it.
 
       nsIFrame* scrollbarBox = GetScrollbar();
-      nsCOMPtr<nsIContent> scrollbar;
-      scrollbar = GetContentOfBox(scrollbarBox);
+      nsCOMPtr<nsIContent> scrollbar = GetContentOfBox(scrollbarBox);
       int32_t current = GetCurrentPosition(scrollbar);
       int32_t min = GetMinPosition(scrollbar);
       int32_t max = GetMaxPosition(scrollbar);
 
       // inform the parent <scale> that the minimum or maximum changed
       nsIFrame* parent = GetParent();
       if (parent) {
         nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
@@ -299,17 +298,17 @@ nsSliderFrame::AttributeChanged(int32_t 
           if (mediator) {
             mediator->ScrollByWhole(scrollbarFrame, direction,
                                     nsIScrollbarMediator::ENABLE_SNAP);
           }
         }
         // 'this' might be destroyed here
 
         nsContentUtils::AddScriptRunner(
-          new nsSetAttrRunnable(scrollbar, nsGkAtoms::curpos, current));
+          new nsSetAttrRunnable(scrollbar->AsElement(), nsGkAtoms::curpos, current));
       }
   }
 
   if (aAttribute == nsGkAtoms::minpos ||
       aAttribute == nsGkAtoms::maxpos ||
       aAttribute == nsGkAtoms::pageincrement ||
       aAttribute == nsGkAtoms::increment) {
 
@@ -500,18 +499,17 @@ nsSliderFrame::DoXULLayout(nsBoxLayoutSt
 #endif
 
   // get the content area inside our borders
   nsRect clientRect;
   GetXULClientRect(clientRect);
 
   // get the scrollbar
   nsIFrame* scrollbarBox = GetScrollbar();
-  nsCOMPtr<nsIContent> scrollbar;
-  scrollbar = GetContentOfBox(scrollbarBox);
+  nsCOMPtr<nsIContent> scrollbar = GetContentOfBox(scrollbarBox);
 
   // get the thumb's pref size
   nsSize thumbSize = thumbBox->GetXULPrefSize(aState);
 
   if (IsXULHorizontal())
     thumbSize.height = clientRect.height;
   else
     thumbSize.width = clientRect.width;
@@ -697,17 +695,17 @@ nsSliderFrame::HandleEvent(nsPresContext
     AutoWeakFrame weakFrame(this);
     // should aMaySnap be true here?
     SetCurrentThumbPosition(scrollbar, pos - thumbLength/2, false, false);
     NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
 
     DragThumb(true);
 
 #ifdef MOZ_WIDGET_GTK
-    nsCOMPtr<nsIContent> thumb = thumbFrame->GetContent();
+    RefPtr<Element> thumb = thumbFrame->GetContent()->AsElement();
     thumb->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
 #endif
 
     if (aEvent->mClass == eTouchEventClass) {
       *aEventStatus = nsEventStatus_eConsumeNoDefault;
     }
 
     if (isHorizontal)
@@ -811,18 +809,17 @@ nsSliderFrame::PageUpDown(nscoord change
   SetCurrentPositionInternal(scrollbar, newpos, true);
 }
 
 // called when the current position changed and we need to update the thumb's location
 void
 nsSliderFrame::CurrentPositionChanged()
 {
   nsIFrame* scrollbarBox = GetScrollbar();
-  nsCOMPtr<nsIContent> scrollbar;
-  scrollbar = GetContentOfBox(scrollbarBox);
+  nsCOMPtr<nsIContent> scrollbar = GetContentOfBox(scrollbarBox);
 
   // get the current position
   int32_t curPos = GetCurrentPosition(scrollbar);
 
   // do nothing if the position did not change
   if (mCurPos == curPos)
     return;
 
@@ -885,17 +882,17 @@ nsSliderFrame::CurrentPositionChanged()
     nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
     if (sliderListener) {
       nsContentUtils::AddScriptRunner(
         new nsValueChangedRunnable(sliderListener, nsGkAtoms::curpos, mCurPos, mUserChanged));
     }
   }
 }
 
-static void UpdateAttribute(nsIContent* aScrollbar, nscoord aNewPos, bool aNotify, bool aIsSmooth) {
+static void UpdateAttribute(Element* aScrollbar, nscoord aNewPos, bool aNotify, bool aIsSmooth) {
   nsAutoString str;
   str.AppendInt(aNewPos);
 
   if (aIsSmooth) {
     aScrollbar->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false);
   }
   aScrollbar->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, str, aNotify);
   if (aIsSmooth) {
@@ -971,24 +968,24 @@ nsSliderFrame::SetCurrentPositionInterna
     nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator();
     if (mediator) {
       nscoord oldPos = nsPresContext::CSSPixelsToAppUnits(GetCurrentPosition(scrollbar));
       nscoord newPos = nsPresContext::CSSPixelsToAppUnits(aNewPos);
       mediator->ThumbMoved(scrollbarFrame, oldPos, newPos);
       if (!weakFrame.IsAlive()) {
         return;
       }
-      UpdateAttribute(scrollbar, aNewPos, /* aNotify */false, aIsSmooth);
+      UpdateAttribute(scrollbar->AsElement(), aNewPos, /* aNotify */false, aIsSmooth);
       CurrentPositionChanged();
       mUserChanged = false;
       return;
     }
   }
 
-  UpdateAttribute(scrollbar, aNewPos, true, aIsSmooth);
+  UpdateAttribute(scrollbar->AsElement(), aNewPos, true, aIsSmooth);
   if (!weakFrame.IsAlive()) {
     return;
   }
   mUserChanged = false;
 
 #ifdef DEBUG_SLIDER
   printf("Current Pos=%d\n",aNewPos);
 #endif
@@ -1216,17 +1213,17 @@ nsSliderFrame::StartDrag(nsIDOMEvent* aE
   }
 
   nsIFrame* thumbFrame = mFrames.FirstChild();
   if (!thumbFrame) {
     return NS_OK;
   }
 
 #ifdef MOZ_WIDGET_GTK
-  nsCOMPtr<nsIContent> thumb = thumbFrame->GetContent();
+  RefPtr<Element> thumb = thumbFrame->GetContent()->AsElement();
   thumb->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
 #endif
 
   if (isHorizontal)
     mThumbStart = thumbFrame->GetPosition().x;
   else
     mThumbStart = thumbFrame->GetPosition().y;
 
@@ -1254,17 +1251,17 @@ nsSliderFrame::StopDrag()
 
   mScrollingWithAPZ = false;
 
   UnsuppressDisplayport();
 
 #ifdef MOZ_WIDGET_GTK
   nsIFrame* thumbFrame = mFrames.FirstChild();
   if (thumbFrame) {
-    nsCOMPtr<nsIContent> thumb = thumbFrame->GetContent();
+    RefPtr<Element> thumb = thumbFrame->GetContent()->AsElement();
     thumb->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
   }
 #endif
 
   if (mChange) {
     StopRepeat();
     mChange = 0;
   }
--- a/layout/xul/nsSplitterFrame.cpp
+++ b/layout/xul/nsSplitterFrame.cpp
@@ -279,18 +279,18 @@ nsSplitterFrame::Init(nsIContent*       
   // determine orientation of parent, and if vertical, set orient to vertical
   // on splitter content, then re-resolve style
   // XXXbz this is pretty messed up, since this can change whether we should
   // have a frame at all.  This really needs a better solution.
   if (aParent && aParent->IsXULBoxFrame()) {
     if (!aParent->IsXULHorizontal()) {
       if (!nsContentUtils::HasNonEmptyAttr(aContent, kNameSpaceID_None,
                                            nsGkAtoms::orient)) {
-        aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::orient,
-                          NS_LITERAL_STRING("vertical"), false);
+        aContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::orient,
+                                       NS_LITERAL_STRING("vertical"), false);
         if (StyleContext()->IsGecko()) {
           // FIXME(emilio): Even if we did this in Servo, this just won't
           // work, and we'd need a specific "really re-resolve the style" API...
           GeckoStyleContext* parentStyleContext =
             StyleContext()->AsGecko()->GetParent();
           RefPtr<nsStyleContext> newContext = PresContext()->StyleSet()->
             ResolveStyleFor(aContent->AsElement(), parentStyleContext,
                             LazyComputeBehavior::Allow);
@@ -417,18 +417,21 @@ nsSplitterFrameInner::MouseUp(nsPresCont
 {
   if (mDragging && mOuter) {
     AdjustChildren(aPresContext);
     AddListener();
     nsIPresShell::SetCapturingContent(nullptr, 0); // XXXndeakin is this needed?
     mDragging = false;
     State newState = GetState();
     // if the state is dragging then make it Open.
-    if (newState == Dragging)
-      mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, EmptyString(), true);
+    if (newState == Dragging) {
+      mOuter->mContent->AsElement()->SetAttr(kNameSpaceID_None,
+                                             nsGkAtoms::state, EmptyString(),
+                                             true);
+    }
 
     mPressed = false;
 
     // if we dragged then fire a command event.
     if (mDidDrag) {
       RefPtr<nsXULElement> element =
         nsXULElement::FromContent(mOuter->GetContent());
       element->DoCommand();
@@ -508,45 +511,49 @@ nsSplitterFrameInner::MouseDrag(nsPresCo
     {
       // and we are not collapsed then collapse
       if (currentState == Dragging) {
         if (pastEnd)
         {
           //printf("Collapse right\n");
           if (supportsAfter)
           {
-            nsCOMPtr<nsIContent> outer = mOuter->mContent;
+            RefPtr<Element> outer = mOuter->mContent->AsElement();
             outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate,
                            NS_LITERAL_STRING("after"),
                            true);
             outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
                            NS_LITERAL_STRING("collapsed"),
                            true);
           }
 
         } else if (pastBegin)
         {
           //printf("Collapse left\n");
           if (supportsBefore)
           {
-            nsCOMPtr<nsIContent> outer = mOuter->mContent;
+            RefPtr<Element> outer = mOuter->mContent->AsElement();
             outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate,
                            NS_LITERAL_STRING("before"),
                            true);
             outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
                            NS_LITERAL_STRING("collapsed"),
                            true);
           }
         }
       }
     } else {
       // if we are not in a collapsed position and we are not dragging make sure
       // we are dragging.
-      if (currentState != Dragging)
-        mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("dragging"), true);
+      if (currentState != Dragging) {
+        mOuter->mContent->AsElement()->SetAttr(kNameSpaceID_None,
+                                               nsGkAtoms::state,
+                                               NS_LITERAL_STRING("dragging"),
+                                               true);
+      }
       AdjustChildren(aPresContext);
     }
 
     mDidDrag = true;
   }
 }
 
 void
@@ -688,20 +695,21 @@ nsSplitterFrameInner::MouseDown(nsIDOMEv
 
         nsMargin margin(0,0,0,0);
         childBox->GetXULMargin(margin);
         nsRect r(childBox->GetRect());
         r.Inflate(margin);
 
         // We need to check for hidden attribute too, since treecols with
         // the hidden="true" attribute are not really hidden, just collapsed
-        if (!content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::fixed,
-                                  nsGkAtoms::_true, eCaseMatters) &&
-            !content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
-                                  nsGkAtoms::_true, eCaseMatters)) {
+        if (!content->IsElement() ||
+            (!content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::fixed,
+                                   nsGkAtoms::_true, eCaseMatters) &&
+             !content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
+                                   nsGkAtoms::_true, eCaseMatters))) {
             if (count < childIndex && (resizeBefore != Flex || flex > 0)) {
                 mChildInfosBefore[mChildInfosBeforeCount].childElem = content;
                 mChildInfosBefore[mChildInfosBeforeCount].min     = isHorizontal ? minSize.width : minSize.height;
                 mChildInfosBefore[mChildInfosBeforeCount].max     = isHorizontal ? maxSize.width : maxSize.height;
                 mChildInfosBefore[mChildInfosBeforeCount].current = isHorizontal ? r.width : r.height;
                 mChildInfosBefore[mChildInfosBeforeCount].flex    = flex;
                 mChildInfosBefore[mChildInfosBeforeCount].index   = count;
                 mChildInfosBefore[mChildInfosBeforeCount].changed = mChildInfosBefore[mChildInfosBeforeCount].current;
@@ -775,18 +783,18 @@ nsSplitterFrameInner::MouseMove(nsIDOMEv
   NS_ENSURE_TRUE(mOuter, NS_OK);
   if (!mPressed)
     return NS_OK;
 
   if (mDragging)
     return NS_OK;
 
   nsCOMPtr<nsIDOMEventListener> kungfuDeathGrip(this);
-  mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
-                            NS_LITERAL_STRING("dragging"), true);
+  mOuter->mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
+                                         NS_LITERAL_STRING("dragging"), true);
 
   RemoveListener();
   mDragging = true;
 
   return NS_OK;
 }
 
 void
@@ -852,31 +860,31 @@ nsSplitterFrameInner::UpdateState()
     if (newState == CollapsedBefore || mState == CollapsedBefore) {
       splitterSibling = mOuter->GetPrevSibling();
     } else {
       splitterSibling = mOuter->GetNextSibling();
     }
 
     if (splitterSibling) {
       nsCOMPtr<nsIContent> sibling = splitterSibling->GetContent();
-      if (sibling) {
+      if (sibling && sibling->IsElement()) {
         if (mState == CollapsedBefore || mState == CollapsedAfter) {
           // CollapsedBefore -> Open
           // CollapsedBefore -> Dragging
           // CollapsedAfter -> Open
           // CollapsedAfter -> Dragging
           nsContentUtils::AddScriptRunner(
-            new nsUnsetAttrRunnable(sibling, nsGkAtoms::collapsed));
+            new nsUnsetAttrRunnable(sibling->AsElement(), nsGkAtoms::collapsed));
         } else if ((mState == Open || mState == Dragging)
                    && (newState == CollapsedBefore ||
                        newState == CollapsedAfter)) {
           // Open -> CollapsedBefore / CollapsedAfter
           // Dragging -> CollapsedBefore / CollapsedAfter
           nsContentUtils::AddScriptRunner(
-            new nsSetAttrRunnable(sibling, nsGkAtoms::collapsed,
+            new nsSetAttrRunnable(sibling->AsElement(), nsGkAtoms::collapsed,
                                   NS_LITERAL_STRING("true")));
         }
       }
     }
   }
   mState = newState;
 }
 
@@ -969,26 +977,30 @@ nsSplitterFrameInner::SetPreferredSize(n
     pref -= (margin.left + margin.right);
     attribute = nsGkAtoms::width;
   } else {
     pref -= (margin.top + margin.bottom);
     attribute = nsGkAtoms::height;
   }
 
   nsIContent* content = aChildBox->GetContent();
+  if (!content->IsElement()) {
+    return;
+  }
 
   // set its preferred size.
   nsAutoString prefValue;
   prefValue.AppendInt(pref/aOnePixel);
   if (content->AttrValueIs(kNameSpaceID_None, attribute,
-                           prefValue, eCaseMatters))
+                           prefValue, eCaseMatters)) {
      return;
+  }
 
   AutoWeakFrame weakBox(aChildBox);
-  content->SetAttr(kNameSpaceID_None, attribute, prefValue, true);
+  content->AsElement()->SetAttr(kNameSpaceID_None, attribute, prefValue, true);
   ENSURE_TRUE(weakBox.IsAlive());
   aState.PresShell()->FrameNeedsReflow(aChildBox, nsIPresShell::eStyleChange,
                                        NS_FRAME_IS_DIRTY);
 }
 
 
 void
 nsSplitterFrameInner::AddRemoveSpace(nscoord aDiff,
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -543,17 +543,17 @@ nsXULPopupManager::PopupResized(nsIFrame
   if (!view)
     return;
 
   LayoutDeviceIntRect curDevSize = view->CalcWidgetBounds(eWindowType_popup);
   // If the size is what we think it is, we have nothing to do.
   if (curDevSize.width == aSize.width && curDevSize.height == aSize.height)
     return;
 
-  nsIContent* popup = menuPopupFrame->GetContent();
+  Element* popup = menuPopupFrame->GetContent()->AsElement();
 
   // Only set the width and height if the popup already has these attributes.
   if (!popup->HasAttr(kNameSpaceID_None, nsGkAtoms::width) ||
       !popup->HasAttr(kNameSpaceID_None, nsGkAtoms::height)) {
     return;
   }
 
   // The size is different. Convert the actual size to css pixels and store it
@@ -705,17 +705,17 @@ nsXULPopupManager::ShowMenu(nsIContent *
   // have been created yet.
   if (aMenu) {
     nsIContent* element = aMenu;
     do {
       RefPtr<nsXULElement> xulelem = nsXULElement::FromContent(element);
       if (xulelem) {
         nsCOMPtr<nsIXULTemplateBuilder> builder = xulelem->GetBuilder();
         if (builder) {
-          builder->CreateContents(aMenu, true);
+          builder->CreateContents(aMenu->AsElement(), true);
           break;
         }
       }
       element = element->GetParent();
     } while (element);
   }
 
   nsMenuFrame* menuFrame = do_QueryFrame(aMenu->GetPrimaryFrame());
@@ -1994,44 +1994,45 @@ nsXULPopupManager::UpdateMenuItems(nsICo
     if (grandChild->IsXULElement(nsGkAtoms::menugroup)) {
       if (grandChild->GetChildCount() == 0) {
         continue;
       }
       grandChild = grandChild->GetFirstChild();
     }
     if (grandChild->IsXULElement(nsGkAtoms::menuitem)) {
       // See if we have a command attribute.
+      Element* grandChildElement = grandChild->AsElement();
       nsAutoString command;
-      grandChild->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
+      grandChildElement->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
       if (!command.IsEmpty()) {
         // We do! Look it up in our document
         RefPtr<dom::Element> commandElement =
           document->GetElementById(command);
         if (commandElement) {
           nsAutoString commandValue;
           // The menu's disabled state needs to be updated to match the command.
           if (commandElement->GetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandValue))
-            grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandValue, true);
+            grandChildElement->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandValue, true);
           else
-            grandChild->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
+            grandChildElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
 
           // The menu's label, accesskey checked and hidden states need to be updated
           // to match the command. Note that unlike the disabled state if the
           // command has *no* value, we assume the menu is supplying its own.
           if (commandElement->GetAttr(kNameSpaceID_None, nsGkAtoms::label, commandValue))
-            grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::label, commandValue, true);
+            grandChildElement->SetAttr(kNameSpaceID_None, nsGkAtoms::label, commandValue, true);
 
           if (commandElement->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandValue))
-            grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandValue, true);
+            grandChildElement->SetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandValue, true);
 
           if (commandElement->GetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandValue))
-            grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandValue, true);
+            grandChildElement->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandValue, true);
 
           if (commandElement->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, commandValue))
-            grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, commandValue, true);
+            grandChildElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, commandValue, true);
         }
       }
     }
     if (!grandChild->GetNextSibling() &&
         grandChild->GetParent()->IsXULElement(nsGkAtoms::menugroup)) {
       grandChild = grandChild->GetParent();
     }
   }
--- a/layout/xul/nsXULPopupManager.h
+++ b/layout/xul/nsXULPopupManager.h
@@ -284,17 +284,17 @@ private:
   bool mIsContextMenu;
   bool mSelectFirstItem;
 };
 
 // this class is used for dispatching menu command events asynchronously.
 class nsXULMenuCommandEvent : public mozilla::Runnable
 {
 public:
-  nsXULMenuCommandEvent(nsIContent* aMenu,
+  nsXULMenuCommandEvent(mozilla::dom::Element* aMenu,
                         bool aIsTrusted,
                         bool aShift,
                         bool aControl,
                         bool aAlt,
                         bool aMeta,
                         bool aUserInput,
                         bool aFlipChecked)
     : mozilla::Runnable("nsXULMenuCommandEvent")
@@ -311,17 +311,17 @@ public:
     NS_ASSERTION(aMenu, "null menu supplied to nsXULMenuCommandEvent constructor");
   }
 
   NS_IMETHOD Run() override;
 
   void SetCloseMenuMode(CloseMenuMode aCloseMenuMode) { mCloseMenuMode = aCloseMenuMode; }
 
 private:
-  nsCOMPtr<nsIContent> mMenu;
+  RefPtr<mozilla::dom::Element> mMenu;
   bool mIsTrusted;
   bool mShift;
   bool mControl;
   bool mAlt;
   bool mMeta;
   bool mUserInput;
   bool mFlipChecked;
   CloseMenuMode mCloseMenuMode;
--- a/layout/xul/nsXULTooltipListener.cpp
+++ b/layout/xul/nsXULTooltipListener.cpp
@@ -472,17 +472,17 @@ GetTreeCellCoords(nsITreeBoxObject* aTre
   bx->GetX(&myX);
   bx->GetY(&myY);
   *aX += myX;
   *aY += myY;
 }
 #endif
 
 static void
-SetTitletipLabel(nsITreeBoxObject* aTreeBox, nsIContent* aTooltip,
+SetTitletipLabel(nsITreeBoxObject* aTreeBox, Element* aTooltip,
                  int32_t aRow, nsITreeColumn* aCol)
 {
   nsCOMPtr<nsITreeView> view;
   aTreeBox->GetView(getter_AddRefs(view));
   if (view) {
     nsAutoString label;
 #ifdef DEBUG
     nsresult rv =
@@ -492,17 +492,17 @@ SetTitletipLabel(nsITreeBoxObject* aTree
     aTooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, true);
   }
 }
 #endif
 
 void
 nsXULTooltipListener::LaunchTooltip()
 {
-  nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
+  nsCOMPtr<Element> currentTooltip = do_QueryReferent(mCurrentTooltip);
   if (!currentTooltip)
     return;
 
 #ifdef MOZ_XUL
   if (mIsSourceTree && mNeedTitletip) {
     nsCOMPtr<nsITreeBoxObject> obx;
     GetSourceTreeBoxObject(getter_AddRefs(obx));
 
@@ -587,20 +587,19 @@ nsXULTooltipListener::FindTooltip(nsICon
   }
 
   nsAutoString tooltipText;
   aTarget->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, tooltipText);
   if (!tooltipText.IsEmpty()) {
     // specifying tooltiptext means we will always use the default tooltip
     nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetShell());
     NS_ENSURE_STATE(rootBox);
-    *aTooltip = rootBox->GetDefaultTooltip();
-    if (*aTooltip) {
-      NS_ADDREF(*aTooltip);
-      (*aTooltip)->SetAttr(kNameSpaceID_None, nsGkAtoms::label, tooltipText, true);
+    if (RefPtr<Element> tooltip = rootBox->GetDefaultTooltip()) {
+      tooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::label, tooltipText, true);
+      tooltip.forget(aTooltip);
     }
     return NS_OK;
   }
 
   nsAutoString tooltipId;
   aTarget->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltip, tooltipId);
 
   // if tooltip == _child, look for first <tooltip> child
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -831,22 +831,22 @@ nsTreeBodyFrame::ScrollParts nsTreeBodyF
     baseElement ? baseElement->GetPrimaryFrame() : nullptr;
   if (treeFrame) {
     // The way we do this, searching through the entire frame subtree, is pretty
     // dumb! We should know where these frames are.
     FindScrollParts(treeFrame, &result);
     if (result.mHScrollbar) {
       result.mHScrollbar->SetScrollbarMediatorContent(GetContent());
       nsIFrame* f = do_QueryFrame(result.mHScrollbar);
-      result.mHScrollbarContent = f->GetContent();
+      result.mHScrollbarContent = f->GetContent()->AsElement();
     }
     if (result.mVScrollbar) {
       result.mVScrollbar->SetScrollbarMediatorContent(GetContent());
       nsIFrame* f = do_QueryFrame(result.mVScrollbar);
-      result.mVScrollbarContent = f->GetContent();
+      result.mVScrollbarContent = f->GetContent()->AsElement();
     }
   }
   return result;
 }
 
 void
 nsTreeBodyFrame::UpdateScrollbars(const ScrollParts& aParts)
 {
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -178,19 +178,19 @@ public:
 
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
 
   friend nsIFrame* NS_NewTreeBodyFrame(nsIPresShell* aPresShell);
   friend class nsTreeColumn;
 
   struct ScrollParts {
     nsScrollbarFrame*    mVScrollbar;
-    nsCOMPtr<nsIContent> mVScrollbarContent;
+    RefPtr<Element>      mVScrollbarContent;
     nsScrollbarFrame*    mHScrollbar;
-    nsCOMPtr<nsIContent> mHScrollbarContent;
+    RefPtr<Element>      mHScrollbarContent;
     nsIFrame*            mColumnsFrame;
     nsIScrollableFrame*  mColumnsScrollFrame;
   };
 
   DrawResult PaintTreeBody(gfxContext& aRenderingContext,
                            const nsRect& aDirtyRect, nsPoint aPt,
                            nsDisplayListBuilder* aBuilder);
 
--- a/layout/xul/tree/nsTreeColumns.cpp
+++ b/layout/xul/tree/nsTreeColumns.cpp
@@ -268,17 +268,17 @@ nsTreeColumn::Invalidate()
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
 
   // If we have an Id, cache the Id as an atom.
   if (!mId.IsEmpty()) {
     mAtom = NS_Atomize(mId);
   }
 
   // Cache our index.
-  nsTreeUtils::GetColumnIndex(mContent, &mIndex);
+  nsTreeUtils::GetColumnIndex(mContent->AsElement(), &mIndex);
 
   const nsStyleVisibility* vis = frame->StyleVisibility();
 
   // Cache our text alignment policy.
   const nsStyleText* textStyle = frame->StyleText();
 
   mTextAlignment = textStyle->mTextAlign;
   // START or END alignment sometimes means RIGHT
@@ -674,17 +674,20 @@ nsTreeColumns::RestoreNaturalOrder()
     nsTreeUtils::GetImmediateChild(content, nsGkAtoms::treecols);
   if (!colsContent)
     return NS_OK;
 
   for (uint32_t i = 0; i < colsContent->GetChildCount(); ++i) {
     nsCOMPtr<nsIContent> child = colsContent->GetChildAt(i);
     nsAutoString ordinal;
     ordinal.AppendInt(i);
-    child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, true);
+    if (child->IsElement()) {
+      child->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal,
+                                  true);
+    }
   }
 
   nsTreeColumns::InvalidateColumns();
 
   if (mTree) {
     mTree->Invalidate();
   }
   return NS_OK;
--- a/layout/xul/tree/nsTreeContentView.cpp
+++ b/layout/xul/tree/nsTreeContentView.cpp
@@ -822,17 +822,17 @@ nsTreeContentView::SetCellValue(int32_t 
     return;
   }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aColumn);
+    Element* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, true);
   }
 }
 
 NS_IMETHODIMP
 nsTreeContentView::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
 {
@@ -853,17 +853,17 @@ nsTreeContentView::SetCellText(int32_t a
     return;
   }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aColumn);
+    Element* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aValue, true);
   }
 }
 
 NS_IMETHODIMP
 nsTreeContentView::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
 {
@@ -1560,36 +1560,36 @@ nsTreeContentView::UpdateParentIndexes(i
   for (int32_t i = aIndex + aSkip; i < count; i++) {
     Row* row = mRows[i].get();
     if (row->mParentIndex > aIndex) {
       row->mParentIndex += aCount;
     }
   }
 }
 
-nsIContent*
+Element*
 nsTreeContentView::GetCell(nsIContent* aContainer, nsTreeColumn& aCol)
 {
   RefPtr<nsAtom> colAtom(aCol.GetAtom());
   int32_t colIndex(aCol.GetIndex());
 
   // Traverse through cells, try to find the cell by "ref" attribute or by cell
   // index in a row. "ref" attribute has higher priority.
-  nsIContent* result = nullptr;
+  Element* result = nullptr;
   int32_t j = 0;
   dom::FlattenedChildIterator iter(aContainer);
   for (nsIContent* cell = iter.GetNextChild(); cell; cell = iter.GetNextChild()) {
     if (cell->IsXULElement(nsGkAtoms::treecell)) {
       if (colAtom && cell->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ref,
                                        colAtom, eCaseMatters)) {
-        result = cell;
+        result = cell->AsElement();
         break;
       }
       else if (j == colIndex) {
-        result = cell;
+        result = cell->AsElement();
       }
       j++;
     }
   }
 
   return result;
 }
 
--- a/layout/xul/tree/nsTreeContentView.h
+++ b/layout/xul/tree/nsTreeContentView.h
@@ -167,17 +167,17 @@ class nsTreeContentView final : public n
 
     int32_t FindContent(nsIContent* aContent);
 
     void UpdateSubtreeSizes(int32_t aIndex, int32_t aCount);
 
     void UpdateParentIndexes(int32_t aIndex, int32_t aSkip, int32_t aCount);
 
     // Content helpers.
-    nsIContent* GetCell(nsIContent* aContainer, nsTreeColumn& aCol);
+    mozilla::dom::Element* GetCell(nsIContent* aContainer, nsTreeColumn& aCol);
 
   private:
     bool IsValidRowIndex(int32_t aRowIndex);
 
     nsCOMPtr<nsITreeBoxObject>          mBoxObject;
     nsCOMPtr<nsITreeSelection>          mSelection;
     nsCOMPtr<nsIContent>                mRoot;
     nsCOMPtr<nsIContent>                mBody;
--- a/layout/xul/tree/nsTreeUtils.cpp
+++ b/layout/xul/tree/nsTreeUtils.cpp
@@ -79,17 +79,17 @@ nsTreeUtils::GetDescendantChild(nsIConte
       return child;
     }
   }
 
   return nullptr;
 }
 
 nsresult
-nsTreeUtils::UpdateSortIndicators(nsIContent* aColumn, const nsAString& aDirection)
+nsTreeUtils::UpdateSortIndicators(Element* aColumn, const nsAString& aDirection)
 {
   aColumn->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, aDirection, true);
   aColumn->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive, NS_LITERAL_STRING("true"), true);
 
   // Unset sort attribute(s) on the other columns
   nsCOMPtr<nsIContent> parentContent = aColumn->GetParent();
   if (parentContent &&
       parentContent->NodeInfo()->Equals(nsGkAtoms::treecols,
@@ -97,38 +97,38 @@ nsTreeUtils::UpdateSortIndicators(nsICon
     uint32_t i, numChildren = parentContent->GetChildCount();
     for (i = 0; i < numChildren; ++i) {
       nsCOMPtr<nsIContent> childContent = parentContent->GetChildAt(i);
 
       if (childContent &&
           childContent != aColumn &&
           childContent->NodeInfo()->Equals(nsGkAtoms::treecol,
                                            kNameSpaceID_XUL)) {
-        childContent->UnsetAttr(kNameSpaceID_None,
-                                nsGkAtoms::sortDirection, true);
-        childContent->UnsetAttr(kNameSpaceID_None,
-                                nsGkAtoms::sortActive, true);
+        childContent->AsElement()->UnsetAttr(kNameSpaceID_None,
+                                             nsGkAtoms::sortDirection, true);
+        childContent->AsElement()->UnsetAttr(kNameSpaceID_None,
+                                             nsGkAtoms::sortActive, true);
       }
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-nsTreeUtils::GetColumnIndex(nsIContent* aColumn, int32_t* aResult)
+nsTreeUtils::GetColumnIndex(Element* aColumn, int32_t* aResult)
 {
   nsIContent* parentContent = aColumn->GetParent();
   if (parentContent &&
       parentContent->NodeInfo()->Equals(nsGkAtoms::treecols,
                                         kNameSpaceID_XUL)) {
     uint32_t i, numChildren = parentContent->GetChildCount();
     int32_t colIndex = 0;
     for (i = 0; i < numChildren; ++i) {
-      nsIContent *childContent = parentContent->GetChildAt(i);
+      nsIContent* childContent = parentContent->GetChildAt(i);
       if (childContent &&
           childContent->NodeInfo()->Equals(nsGkAtoms::treecol,
                                            kNameSpaceID_XUL)) {
         if (childContent == aColumn) {
           *aResult = colIndex;
           return NS_OK;
         }
         ++colIndex;
--- a/layout/xul/tree/nsTreeUtils.h
+++ b/layout/xul/tree/nsTreeUtils.h
@@ -9,16 +9,21 @@
 
 #include "mozilla/AtomArray.h"
 #include "nsError.h"
 #include "nsString.h"
 #include "nsTreeStyleCache.h"
 
 class nsAtom;
 class nsIContent;
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
 
 class nsTreeUtils
 {
   public:
     /**
      * Parse a whitespace separated list of properties into an array
      * of atoms.
      */
@@ -28,15 +33,15 @@ class nsTreeUtils
 
     static nsIContent*
     GetImmediateChild(nsIContent* aContainer, nsAtom* aTag);
 
     static nsIContent*
     GetDescendantChild(nsIContent* aContainer, nsAtom* aTag);
 
     static nsresult
-    UpdateSortIndicators(nsIContent* aColumn, const nsAString& aDirection);
+    UpdateSortIndicators(mozilla::dom::Element* aColumn, const nsAString& aDirection);
 
     static nsresult
-    GetColumnIndex(nsIContent* aColumn, int32_t* aResult);
+    GetColumnIndex(mozilla::dom::Element* aColumn, int32_t* aResult);
 };
 
 #endif // nsTreeUtils_h__
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -1076,33 +1076,33 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
       return NS_OK;
     }
     case eTreeOpDisableEncodingMenu: {
       nsIDocument* doc = aBuilder->GetDocument();
       doc->DisableEncodingMenu();
       return NS_OK;
     }
     case eTreeOpAddClass: {
-      nsIContent* node = *(mOne.node);
+      Element* element = (*(mOne.node))->AsElement();
       char16_t* str = mTwo.unicharPtr;
       nsDependentString depStr(str);
       // See viewsource.css for the possible classes
       nsAutoString klass;
-      node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
+      element->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
       if (!klass.IsEmpty()) {
         klass.Append(' ');
         klass.Append(depStr);
-        node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
+        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
       } else {
-        node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
+        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
       }
       return NS_OK;
     }
     case eTreeOpAddViewSourceHref: {
-      nsIContent* node = *mOne.node;
+      Element* element = (*mOne.node)->AsElement();
       char16_t* buffer = mTwo.unicharPtr;
       int32_t length = mFour.integer;
 
       nsDependentString relative(buffer, length);
 
       nsIDocument* doc = aBuilder->GetDocument();
 
       auto encoding = doc->GetDocumentCharacterSet();
@@ -1144,42 +1144,42 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
       rv = uri->GetSpec(spec);
       NS_ENSURE_SUCCESS(rv, rv);
 
       viewSourceUrl.Append(spec);
 
       nsAutoString utf16;
       CopyUTF8toUTF16(viewSourceUrl, utf16);
 
-      node->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
+      element->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
       return NS_OK;
     }
     case eTreeOpAddViewSourceBase: {
       char16_t* buffer = mTwo.unicharPtr;
       int32_t length = mFour.integer;
       nsDependentString baseUrl(buffer, length);
       aBuilder->AddBase(baseUrl);
       return NS_OK;
     }
     case eTreeOpAddError: {
-      nsIContent* node = *(mOne.node);
+      Element* element = (*(mOne.node))->AsElement();
       char* msgId = mTwo.charPtr;
       RefPtr<nsAtom> atom = Reget(mThree.atom);
       RefPtr<nsAtom> otherAtom = Reget(mFour.atom);
       // See viewsource.css for the possible classes in addition to "error".
       nsAutoString klass;
-      node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
+      element->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
       if (!klass.IsEmpty()) {
         klass.AppendLiteral(" error");
-        node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
+        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
       } else {
-        node->SetAttr(kNameSpaceID_None,
-                      nsGkAtoms::_class,
-                      NS_LITERAL_STRING("error"),
-                      true);
+        element->SetAttr(kNameSpaceID_None,
+                         nsGkAtoms::_class,
+                         NS_LITERAL_STRING("error"),
+                         true);
       }
 
       nsresult rv;
       nsAutoString message;
       if (otherAtom) {
         const char16_t* params[] = { atom->GetUTF16String(),
                                       otherAtom->GetUTF16String() };
         rv = nsContentUtils::FormatLocalizedString(
@@ -1192,32 +1192,32 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
         NS_ENSURE_SUCCESS(rv, NS_OK);
       } else {
         rv = nsContentUtils::GetLocalizedString(
           nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message);
         NS_ENSURE_SUCCESS(rv, NS_OK);
       }
 
       nsAutoString title;
-      node->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
+      element->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
       if (!title.IsEmpty()) {
         title.Append('\n');
         title.Append(message);
-        node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
+        element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
       } else {
-        node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
+        element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
       }
       return rv;
     }
     case eTreeOpAddLineNumberId: {
-      nsIContent* node = *(mOne.node);
+      Element* element = (*(mOne.node))->AsElement();
       int32_t lineNumber = mFour.integer;
       nsAutoString val(NS_LITERAL_STRING("line"));
       val.AppendInt(lineNumber);
-      node->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
+      element->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
       return NS_OK;
     }
     case eTreeOpStartLayout: {
       aBuilder->StartLayout(aInterrupted); // this causes a notification flush anyway
       return NS_OK;
     }
     default: {
       MOZ_CRASH("Bogus tree op");