Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 24 Apr 2015 15:42:31 -0400
changeset 241015 f214df6ac75f0202e40733be62c5b169d7a40b7f
parent 241014 753c674f7c1fa8e5714d8441a85c6d369d04d1ce (current diff)
parent 240950 c09eaddb6740b411e91da6615044376e4106f898 (diff)
child 241016 d8db346eeac3e943175dee82e25438149d31def0
child 241102 013f80fd50f1b99d3cc3a6ae3494e49e74fbdc78
child 241108 f21141c84ed0c292f3a15ce233b814c9aefbd760
child 241167 e311030ff4913385b662c13101eaa676fd0dd7b2
push id58988
push userryanvm@gmail.com
push dateFri, 24 Apr 2015 19:58:56 +0000
treeherdermozilla-inbound@d8db346eeac3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone40.0a1
first release with
nightly linux32
f214df6ac75f / 40.0a1 / 20150425030208 / files
nightly linux64
f214df6ac75f / 40.0a1 / 20150425030208 / files
nightly mac
f214df6ac75f / 40.0a1 / 20150425030208 / files
nightly win32
f214df6ac75f / 40.0a1 / 20150425030208 / files
nightly win64
f214df6ac75f / 40.0a1 / 20150425030208 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
dom/ipc/tests/test_NewUnmonitoredThread.html
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1084,16 +1084,26 @@ window.addEventListener('ContentStart', 
   let stats = volumeService.createOrGetVolumeByPath(path).getStats();
 
   // We must set the size in KB, and keep a bit of free space.
   let size = Math.floor(stats.totalBytes / 1024) - 1024;
   Services.prefs.setIntPref("browser.cache.disk.capacity", size);
 })();
 #endif
 
+#ifdef MOZ_WIDGET_GONK
+try {
+  let gmpService = Cc["@mozilla.org/gecko-media-plugin-service;1"]
+                     .getService(Ci.mozIGeckoMediaPluginChromeService);
+  gmpService.addPluginDirectory("/system/b2g/gmp-clearkey/0.1");
+} catch(e) {
+  dump("Failed to add clearkey path! " + e + "\n");
+}
+#endif
+
 // Calling this observer will cause a shutdown an a profile reset.
 // Use eg. : Services.obs.notifyObservers(null, 'b2g-reset-profile', null);
 Services.obs.addObserver(function resetProfile(subject, topic, data) {
   Services.obs.removeObserver(resetProfile, topic);
 
   // Listening for 'profile-before-change2' which is late in the shutdown
   // sequence, but still has xpcom access.
   Services.obs.addObserver(function clearProfile(subject, topic, data) {
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -154,16 +154,17 @@
 @BINPATH@/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chardet.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_events.xpt
+@BINPATH@/components/content_geckomediaplugins.xpt
 @BINPATH@/components/content_html.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/devtools_security.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/diskspacewatcher.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
--- a/build/unix/mozconfig.linux
+++ b/build/unix/mozconfig.linux
@@ -36,8 +36,10 @@ if [ -d "$topsrcdir/gtk3" ]; then
   export PKG_CONFIG_SYSROOT_DIR="$topsrcdir/gtk3"
   export PKG_CONFIG_PATH="$topsrcdir/gtk3/usr/local/lib/pkgconfig"
   export PATH="$topsrcdir/gtk3/usr/local/bin:${PATH}"
   # Ensure cairo, gdk-pixbuf, etc. are not taken from the system installed packages.
   LDFLAGS="-L$topsrcdir/gtk3/usr/local/lib"
   mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib"
   ac_add_options --enable-default-toolkit=cairo-gtk3
 fi
+
+export SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE=/builds/crash-stats-api.token
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2602,11 +2602,10 @@ nsMessageManagerSH<Super>::Enumerate(nsI
 {
   JS::Rooted<JSObject*> obj(cx, obj_);
 
   *_retval = SystemGlobalEnumerate(cx, obj);
   NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
 
   // Don't call up to our superclass, since neither nsDOMGenericSH nor
   // nsEventTargetSH have WANT_ENUMERATE.
-  MOZ_ASSERT(!(this->GetScriptableFlags() & nsIXPCScriptable::WANT_ENUMERATE));
   return NS_OK;
 }
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -4075,23 +4075,22 @@ ArrayBufferBuilder::mapToFileInPackage(c
   }
 
   // If file was added to the package as stored(uncompressed), map to the
   // offset of file in zip package.
   if (!zipItem->Compression()) {
     uint32_t offset = zip->GetDataOffset(zipItem);
     uint32_t size = zipItem->RealSize();
     mozilla::AutoFDClose pr_fd;
-    mozilla::ScopedClose fd;
     rv = aJarFile->OpenNSPRFileDesc(PR_RDONLY, 0, &pr_fd.rwget());
     if (NS_FAILED(rv)) {
       return rv;
     }
-    fd.rwget() = PR_FileDesc2NativeHandle(pr_fd);
-    mMapPtr = JS_CreateMappedArrayBufferContents(fd, offset, size);
+    mMapPtr = JS_CreateMappedArrayBufferContents(PR_FileDesc2NativeHandle(pr_fd),
+                                                 offset, size);
     if (mMapPtr) {
       mLength = size;
       return NS_OK;
     }
   }
   return NS_ERROR_FAILURE;
 #endif
 }
--- a/dom/bindings/OwningNonNull.h
+++ b/dom/bindings/OwningNonNull.h
@@ -24,17 +24,17 @@ public:
   MOZ_IMPLICIT OwningNonNull(T& aValue)
   {
     init(&aValue);
   }
 
   template<class U>
   MOZ_IMPLICIT OwningNonNull(already_AddRefed<U>&& aValue)
   {
-    init(aValue.take());
+    init(aValue);
   }
 
   // This is no worse than get() in terms of const handling.
   operator T&() const
   {
     MOZ_ASSERT(mInited);
     MOZ_ASSERT(mPtr, "OwningNonNull<T> was set to null");
     return *mPtr;
@@ -101,17 +101,17 @@ public:
   template<typename U>
   void swap(U& aOther)
   {
     mPtr.swap(aOther);
   }
 
 protected:
   template<typename U>
-  void init(U aValue)
+  void init(U&& aValue)
   {
     mPtr = aValue;
     MOZ_ASSERT(mPtr);
 #ifdef DEBUG
     mInited = true;
 #endif
   }
 
--- a/dom/ipc/PreallocatedProcessManager.cpp
+++ b/dom/ipc/PreallocatedProcessManager.cpp
@@ -87,57 +87,16 @@ private:
   void Enable();
   void Disable();
 
   void ObserveProcessShutdown(nsISupports* aSubject);
 
   bool mEnabled;
   bool mShutdown;
   nsRefPtr<ContentParent> mPreallocatedAppProcess;
-
-#if defined(MOZ_NUWA_PROCESS) && defined(ENABLE_TESTS)
-  // For testing NS_NewUnmonitoredThread().
-
-  void CreateUnmonitoredThread();
-  void DestroyUnmonitoredThread();
-
-  class UnmonitoredThreadRunnable : public nsRunnable
-  {
-  public:
-    UnmonitoredThreadRunnable()
-      : mMonitor("UnmonitoredThreadRunnable")
-      , mEnabled(true)
-    { }
-
-    NS_IMETHODIMP Run() override
-    {
-      MonitorAutoLock mon(mMonitor);
-      while (mEnabled) {
-        mMonitor.Wait();
-      }
-      return NS_OK;
-    }
-
-    void Disable()
-    {
-      MonitorAutoLock mon(mMonitor);
-      mEnabled = false;
-      mMonitor.NotifyAll();
-    }
-
-  private:
-    ~UnmonitoredThreadRunnable() { }
-
-    Monitor mMonitor;
-    bool mEnabled;
-  };
-
-  nsCOMPtr<nsIThread> mUnmonitoredThread;
-  nsRefPtr<UnmonitoredThreadRunnable> mUnmonitoredThreadRunnable;
-#endif
 };
 
 /* static */ StaticRefPtr<PreallocatedProcessManagerImpl>
 PreallocatedProcessManagerImpl::sSingleton;
 
 /* static */ PreallocatedProcessManagerImpl*
 PreallocatedProcessManagerImpl::Singleton()
 {
@@ -191,50 +150,16 @@ PreallocatedProcessManagerImpl::Observe(
     mShutdown = true;
   } else {
     MOZ_ASSERT(false);
   }
 
   return NS_OK;
 }
 
-#if defined(MOZ_NUWA_PROCESS) && defined(ENABLE_TESTS)
-void
-PreallocatedProcessManagerImpl::CreateUnmonitoredThread()
-{
-  if (Preferences::GetBool("dom.ipc.newUnmonitoredThread.testMode")) {
-    // Create an unmonitored thread and dispatch a blocking runnable in test
-    // case startup.
-    nsresult rv = NS_NewUnmonitoredThread(getter_AddRefs(mUnmonitoredThread),
-                                          nullptr);
-    NS_ENSURE_SUCCESS_VOID(rv);
-
-    mUnmonitoredThreadRunnable = new UnmonitoredThreadRunnable();
-    mUnmonitoredThread->Dispatch(mUnmonitoredThreadRunnable,
-                                 NS_DISPATCH_NORMAL);
-  }
-}
-
-void
-PreallocatedProcessManagerImpl::DestroyUnmonitoredThread()
-{
-  // Cleanup after the test case finishes.
-  if (mUnmonitoredThreadRunnable) {
-    mUnmonitoredThreadRunnable->Disable();
-  }
-
-  if (mUnmonitoredThread) {
-    mUnmonitoredThread->Shutdown();
-  }
-
-  mUnmonitoredThreadRunnable = nullptr;
-  mUnmonitoredThread = nullptr;
-}
-#endif
-
 void
 PreallocatedProcessManagerImpl::RereadPrefs()
 {
   if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled")) {
     Enable();
   } else {
     Disable();
   }
@@ -250,21 +175,16 @@ void
 PreallocatedProcessManagerImpl::Enable()
 {
   if (mEnabled) {
     return;
   }
 
   mEnabled = true;
 #ifdef MOZ_NUWA_PROCESS
-#ifdef ENABLE_TESTS
-  // For testing New_UnmonitoredThread().
-  CreateUnmonitoredThread();
-#endif
-
   ScheduleDelayedNuwaFork();
 #else
   AllocateAfterDelay();
 #endif
 }
 
 void
 PreallocatedProcessManagerImpl::AllocateAfterDelay()
@@ -447,21 +367,16 @@ PreallocatedProcessManagerImpl::Disable(
 {
   if (!mEnabled) {
     return;
   }
 
   mEnabled = false;
 
 #ifdef MOZ_NUWA_PROCESS
-#ifdef ENABLE_TESTS
-  // Shut down the test-only unmonitored thread.
-  DestroyUnmonitoredThread();
-#endif
-
   // Cancel pending fork.
   if (mPreallocateAppProcessTask) {
     mPreallocateAppProcessTask->Cancel();
     mPreallocateAppProcessTask = nullptr;
   }
 #endif
 
   if (mPreallocatedAppProcess) {
--- a/dom/ipc/tests/mochitest.ini
+++ b/dom/ipc/tests/mochitest.ini
@@ -12,14 +12,12 @@ skip-if = buildapp == 'b2g' || buildapp 
 # This test is only supposed to run in the main process
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android'
 [test_cpow_cookies.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 [test_NuwaProcessCreation.html]
 skip-if = toolkit != 'gonk'
 [test_NuwaProcessDeadlock.html]
 skip-if = toolkit != 'gonk'
-[test_NewUnmonitoredThread.html]
-skip-if = toolkit != 'gonk'
 [test_child_docshell.html]
 skip-if = toolkit == 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
 [test_CrashService_crash.html]
 skip-if = !(crashreporter && !e10s && (toolkit == 'gtk2' || toolkit == 'gtk3' || toolkit == 'cocoa' || toolkit == 'windows') && (buildapp != 'b2g' || toolkit == 'gonk') && (buildapp != 'mulet')) # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
deleted file mode 100644
--- a/dom/ipc/tests/test_NewUnmonitoredThread.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-Test if Nuwa process created successfully.
--->
-<head>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body onload="setup()">
-
-<script type="application/javascript;version=1.7">
-"use strict";
-
-function runTest()
-{
-  info("Launch the Nuwa process");
-  let cpmm = SpecialPowers.Cc["@mozilla.org/childprocessmessagemanager;1"]
-                          .getService(SpecialPowers.Ci.nsISyncMessageSender);
-  let seenNuwaReady = false;
-  let msgHandler = {
-    receiveMessage: function receiveMessage(msg) {
-      msg = SpecialPowers.wrap(msg);
-      if (msg.name == 'TEST-ONLY:nuwa-ready') {
-        ok(true, "Got nuwa-ready");
-        is(seenNuwaReady, false, "Already received nuwa ready");
-        seenNuwaReady = true;
-      } else if (msg.name == 'TEST-ONLY:nuwa-add-new-process') {
-        ok(true, "Got nuwa-add-new-process");
-        is(seenNuwaReady, true, "Receive nuwa-add-new-process before nuwa-ready");
-        shutdown();
-      }
-    }
-  };
-
-  function shutdown() {
-    info("Shut down the test case");
-    cpmm.removeMessageListener("TEST-ONLY:nuwa-ready", msgHandler);
-    cpmm.removeMessageListener("TEST-ONLY:nuwa-add-new-process", msgHandler);
-
-    SimpleTest.finish();
-  }
-
-  cpmm.addMessageListener("TEST-ONLY:nuwa-ready", msgHandler);
-  cpmm.addMessageListener("TEST-ONLY:nuwa-add-new-process", msgHandler);
-
-
-  // Setting this pref to true should cause us to prelaunch a process.
-  SpecialPowers.setBoolPref('dom.ipc.processPrelaunch.enabled', true);
-}
-
-function setup2()
-{
-  info("Enable the Nuwa process to test the unmonitored thread");
-
-  SpecialPowers.pushPrefEnv({
-    'set': [
-      ['dom.ipc.processPrelaunch.enabled', false],
-      ['dom.ipc.preallocatedProcessManager.testMode', true]
-    ]
-  }, runTest);
-}
-
-function setup()
-{
-  info("Create an unmonitored thread.");
-
-  SimpleTest.waitForExplicitFinish();
-
-  SpecialPowers.pushPrefEnv({
-    'set': [
-      // For testing NS_NewUnmonitoredThread()
-      ['dom.ipc.newUnmonitoredThread.testMode', true],
-    ]
-  }, setup2);
-}
-
-</script>
-</body>
-</html>
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -1348,38 +1348,36 @@ already_AddRefed<Element>
 nsEditor::CreateNode(nsIAtom* aTag,
                      nsINode* aParent,
                      int32_t aPosition)
 {
   MOZ_ASSERT(aTag && aParent);
 
   nsAutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillCreateNode(nsDependentAtomString(aTag),
-                                        GetAsDOMNode(aParent), aPosition);
+  for (auto& listener : mActionListeners) {
+    listener->WillCreateNode(nsDependentAtomString(aTag),
+                             GetAsDOMNode(aParent), aPosition);
   }
 
   nsCOMPtr<Element> ret;
 
   nsRefPtr<CreateElementTxn> txn =
     CreateTxnForCreateElement(*aTag, *aParent, aPosition);
   nsresult res = DoTransaction(txn);
   if (NS_SUCCEEDED(res)) {
     ret = txn->GetNewNode();
     MOZ_ASSERT(ret);
   }
 
   mRangeUpdater.SelAdjCreateNode(aParent, aPosition);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidCreateNode(nsDependentAtomString(aTag),
-                                       GetAsDOMNode(ret),
-                                       GetAsDOMNode(aParent), aPosition,
-                                       res);
+  for (auto& listener : mActionListeners) {
+    listener->DidCreateNode(nsDependentAtomString(aTag), GetAsDOMNode(ret),
+                            GetAsDOMNode(aParent), aPosition, res);
   }
 
   return ret.forget();
 }
 
 
 NS_IMETHODIMP
 nsEditor::InsertNode(nsIDOMNode* aNode, nsIDOMNode* aParent, int32_t aPosition)
@@ -1391,30 +1389,30 @@ nsEditor::InsertNode(nsIDOMNode* aNode, 
   return InsertNode(*node, *parent, aPosition);
 }
 
 nsresult
 nsEditor::InsertNode(nsIContent& aNode, nsINode& aParent, int32_t aPosition)
 {
   nsAutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(),
-                                        aPosition);
+  for (auto& listener : mActionListeners) {
+    listener->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(),
+                             aPosition);
   }
 
   nsRefPtr<InsertNodeTxn> txn = CreateTxnForInsertNode(aNode, aParent,
                                                        aPosition);
   nsresult res = DoTransaction(txn);
 
   mRangeUpdater.SelAdjInsertNode(aParent.AsDOMNode(), aPosition);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(),
-                                       aPosition, res);
+  for (auto& listener : mActionListeners) {
+    listener->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), aPosition,
+                            res);
   }
 
   return res;
 }
 
 
 NS_IMETHODIMP
 nsEditor::SplitNode(nsIDOMNode* aNode,
@@ -1430,32 +1428,31 @@ nsEditor::SplitNode(nsIDOMNode* aNode,
 }
 
 nsIContent*
 nsEditor::SplitNode(nsIContent& aNode, int32_t aOffset, ErrorResult& aResult)
 {
   nsAutoRules beginRulesSniffing(this, EditAction::splitNode,
                                  nsIEditor::eNext);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillSplitNode(aNode.AsDOMNode(), aOffset);
+  for (auto& listener : mActionListeners) {
+    listener->WillSplitNode(aNode.AsDOMNode(), aOffset);
   }
 
   nsRefPtr<SplitNodeTxn> txn = CreateTxnForSplitNode(aNode, aOffset);
   aResult = DoTransaction(txn);
 
   nsCOMPtr<nsIContent> newNode = aResult.Failed() ? nullptr
                                                   : txn->GetNewNode();
 
   mRangeUpdater.SelAdjSplitNode(aNode, aOffset, newNode);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidSplitNode(aNode.AsDOMNode(), aOffset,
-                                      GetAsDOMNode(newNode),
-                                      aResult.ErrorCode());
+  for (auto& listener : mActionListeners) {
+    listener->DidSplitNode(aNode.AsDOMNode(), aOffset, GetAsDOMNode(newNode),
+                           aResult.ErrorCode());
   }
 
   return newNode;
 }
 
 
 NS_IMETHODIMP
 nsEditor::JoinNodes(nsIDOMNode* aLeftNode,
@@ -1478,35 +1475,33 @@ nsEditor::JoinNodes(nsINode& aLeftNode, 
                                  nsIEditor::ePrevious);
 
   // Remember some values; later used for saved selection updating.
   // Find the offset between the nodes to be joined.
   int32_t offset = parent->IndexOf(&aRightNode);
   // Find the number of children of the lefthand node
   uint32_t oldLeftNodeLen = aLeftNode.Length();
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillJoinNodes(aLeftNode.AsDOMNode(),
-                                       aRightNode.AsDOMNode(),
-                                       parent->AsDOMNode());
+  for (auto& listener : mActionListeners) {
+    listener->WillJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
+                            parent->AsDOMNode());
   }
 
   nsresult result;
   nsRefPtr<JoinNodeTxn> txn = CreateTxnForJoinNode(aLeftNode, aRightNode);
   if (txn)  {
     result = DoTransaction(txn);
   }
 
   mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
                                 (int32_t)oldLeftNodeLen);
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidJoinNodes(aLeftNode.AsDOMNode(),
-                                      aRightNode.AsDOMNode(),
-                                      parent->AsDOMNode(), result);
+  for (auto& listener : mActionListeners) {
+    listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
+                           parent->AsDOMNode(), result);
   }
 
   return result;
 }
 
 
 NS_IMETHODIMP
 nsEditor::DeleteNode(nsIDOMNode* aNode)
@@ -1517,28 +1512,28 @@ nsEditor::DeleteNode(nsIDOMNode* aNode)
 }
 
 nsresult
 nsEditor::DeleteNode(nsINode* aNode)
 {
   nsAutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::ePrevious);
 
   // save node location for selection updating code.
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillDeleteNode(aNode->AsDOMNode());
+  for (auto& listener : mActionListeners) {
+    listener->WillDeleteNode(aNode->AsDOMNode());
   }
 
   nsRefPtr<DeleteNodeTxn> txn;
   nsresult res = CreateTxnForDeleteNode(aNode, getter_AddRefs(txn));
   if (NS_SUCCEEDED(res))  {
     res = DoTransaction(txn);
   }
 
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidDeleteNode(aNode->AsDOMNode(), res);
+  for (auto& listener : mActionListeners) {
+    listener->DidDeleteNode(aNode->AsDOMNode(), res);
   }
 
   NS_ENSURE_SUCCESS(res, res);
   return NS_OK;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // ReplaceContainer: replace inNode with a new node (outNode) which is contructed 
@@ -1733,33 +1728,30 @@ NS_IMETHODIMP
 nsEditor::AddEditorObserver(nsIEditorObserver *aObserver)
 {
   // we don't keep ownership of the observers.  They must
   // remove themselves as observers before they are destroyed.
   
   NS_ENSURE_TRUE(aObserver, NS_ERROR_NULL_POINTER);
 
   // Make sure the listener isn't already on the list
-  if (mEditorObservers.IndexOf(aObserver) == -1) 
-  {
-    if (!mEditorObservers.AppendObject(aObserver))
-      return NS_ERROR_FAILURE;
+  if (!mEditorObservers.Contains(aObserver)) {
+    mEditorObservers.AppendElement(*aObserver);
   }
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsEditor::RemoveEditorObserver(nsIEditorObserver *aObserver)
 {
   NS_ENSURE_TRUE(aObserver, NS_ERROR_FAILURE);
 
-  if (!mEditorObservers.RemoveObject(aObserver))
-    return NS_ERROR_FAILURE;
+  mEditorObservers.RemoveElement(aObserver);
 
   return NS_OK;
 }
 
 class EditorInputEventDispatcher : public nsRunnable
 {
 public:
   EditorInputEventDispatcher(nsEditor* aEditor,
@@ -1809,36 +1801,36 @@ private:
 };
 
 void
 nsEditor::NotifyEditorObservers(NotificationForEditorObservers aNotification)
 {
   switch (aNotification) {
     case eNotifyEditorObserversOfEnd:
       mIsInEditAction = false;
-      for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
-        mEditorObservers[i]->EditAction();
+      for (auto& observer : mEditorObservers) {
+        observer->EditAction();
       }
 
       if (!mDispatchInputEvent) {
         return;
       }
 
       FireInputEvent();
       break;
     case eNotifyEditorObserversOfBefore:
       mIsInEditAction = true;
-      for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
-        mEditorObservers[i]->BeforeEditAction();
+      for (auto& observer : mEditorObservers) {
+        observer->BeforeEditAction();
       }
       break;
     case eNotifyEditorObserversOfCancel:
       mIsInEditAction = false;
-      for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
-        mEditorObservers[i]->CancelEditAction();
+      for (auto& observer : mEditorObservers) {
+        observer->CancelEditAction();
       }
       break;
     default:
       MOZ_CRASH("Handle all notifications here");
       break;
   }
 }
 
@@ -1861,60 +1853,54 @@ nsEditor::FireInputEvent()
 }
 
 NS_IMETHODIMP
 nsEditor::AddEditActionListener(nsIEditActionListener *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
 
   // Make sure the listener isn't already on the list
-  if (mActionListeners.IndexOf(aListener) == -1) 
-  {
-    if (!mActionListeners.AppendObject(aListener))
-      return NS_ERROR_FAILURE;
+  if (!mActionListeners.Contains(aListener)) {
+    mActionListeners.AppendElement(*aListener);
   }
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsEditor::RemoveEditActionListener(nsIEditActionListener *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
 
-  if (!mActionListeners.RemoveObject(aListener))
-    return NS_ERROR_FAILURE;
+  mActionListeners.RemoveElement(aListener);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsEditor::AddDocumentStateListener(nsIDocumentStateListener *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
 
-  if (mDocStateListeners.IndexOf(aListener) == -1)
-  {
-    if (!mDocStateListeners.AppendObject(aListener))
-      return NS_ERROR_FAILURE;
+  if (!mDocStateListeners.Contains(aListener)) {
+    mDocStateListeners.AppendElement(*aListener);
   }
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsEditor::RemoveDocumentStateListener(nsIDocumentStateListener *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
 
-  if (!mDocStateListeners.RemoveObject(aListener))
-    return NS_ERROR_FAILURE;
+  mDocStateListeners.RemoveElement(aListener);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP nsEditor::OutputToString(const nsAString& aFormatType,
                                        uint32_t aFlags,
                                        nsAString& aOutputString)
@@ -2387,33 +2373,33 @@ nsEditor::InsertTextIntoTextNodeImpl(con
 
     txn = CreateTxnForIMEText(aStringToInsert);
     isIMETransaction = true;
   } else {
     txn = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset);
   }
 
   // Let listeners know what's up
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillInsertText(
+  for (auto& listener : mActionListeners) {
+    listener->WillInsertText(
       static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()), aOffset,
       aStringToInsert);
   }
 
   // XXX We may not need these view batches anymore.  This is handled at a
   // higher level now I believe.
   BeginUpdateViewBatch();
   nsresult res = DoTransaction(txn);
   EndUpdateViewBatch();
 
   mRangeUpdater.SelAdjInsertText(aTextNode, aOffset, aStringToInsert);
 
   // let listeners know what happened
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidInsertText(
+  for (auto& listener : mActionListeners) {
+    listener->DidInsertText(
       static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()),
       aOffset, aStringToInsert, res);
   }
 
   // Added some cruft here for bug 43366.  Layout was crashing because we left
   // an empty text node lying around in the document.  So I delete empty text
   // nodes caused by IME.  I have to mark the IME transaction as "fixed", which
   // means that furure IME txns won't merge with it.  This is because we don't
@@ -2460,58 +2446,56 @@ nsEditor::GetFirstEditableNode(nsINode* 
 
   return (node != aRoot) ? node : nullptr;
 }
 
 
 NS_IMETHODIMP
 nsEditor::NotifyDocumentListeners(TDocumentListenerNotification aNotificationType)
 {
-  int32_t numListeners = mDocStateListeners.Count();
-  if (!numListeners)    // maybe there just aren't any.
+  if (!mDocStateListeners.Length()) {
+    // Maybe there just aren't any.
     return NS_OK;
+  }
  
-  nsCOMArray<nsIDocumentStateListener> listeners(mDocStateListeners);
+  nsTArray<OwningNonNull<nsIDocumentStateListener>>
+    listeners(mDocStateListeners);
   nsresult rv = NS_OK;
-  int32_t i;
 
   switch (aNotificationType)
   {
     case eDocumentCreated:
-      for (i = 0; i < numListeners;i++)
-      {
-        rv = listeners[i]->NotifyDocumentCreated();
+      for (auto& listener : listeners) {
+        rv = listener->NotifyDocumentCreated();
         if (NS_FAILED(rv))
           break;
       }
       break;
       
     case eDocumentToBeDestroyed:
-      for (i = 0; i < numListeners;i++)
-      {
-        rv = listeners[i]->NotifyDocumentWillBeDestroyed();
+      for (auto& listener : listeners) {
+        rv = listener->NotifyDocumentWillBeDestroyed();
         if (NS_FAILED(rv))
           break;
       }
       break;
 
     case eDocumentStateChanged:
       {
         bool docIsDirty;
         rv = GetDocumentModified(&docIsDirty);
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (static_cast<int8_t>(docIsDirty) == mDocDirtyState)
           return NS_OK;
 
         mDocDirtyState = docIsDirty;
 
-        for (i = 0; i < numListeners;i++)
-        {
-          rv = listeners[i]->NotifyDocumentStateChanged(mDocDirtyState);
+        for (auto& listener : listeners) {
+          rv = listener->NotifyDocumentStateChanged(mDocDirtyState);
           if (NS_FAILED(rv))
             break;
         }
       }
       break;
     
     default:
       NS_NOTREACHED("Unknown notification");
@@ -2537,27 +2521,27 @@ nsEditor::DeleteText(nsGenericDOMDataNod
 {
   nsRefPtr<DeleteTextTxn> txn =
     CreateTxnForDeleteText(aCharData, aOffset, aLength);
   NS_ENSURE_STATE(txn);
 
   nsAutoRules beginRulesSniffing(this, EditAction::deleteText, nsIEditor::ePrevious);
 
   // Let listeners know what's up
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->WillDeleteText(
+  for (auto& listener : mActionListeners) {
+    listener->WillDeleteText(
         static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
         aLength);
   }
 
   nsresult res = DoTransaction(txn);
 
   // Let listeners know what happened
-  for (int32_t i = 0; i < mActionListeners.Count(); i++) {
-    mActionListeners[i]->DidDeleteText(
+  for (auto& listener : mActionListeners) {
+    listener->DidDeleteText(
         static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
         aLength, res);
   }
 
   return res;
 }
 
 
@@ -3955,41 +3939,48 @@ nsEditor::DeleteSelectionImpl(EDirection
                                              getter_AddRefs(deleteNode),
                                              &deleteCharOffset,
                                              &deleteCharLength);
   nsCOMPtr<nsIDOMCharacterData> deleteCharData(do_QueryInterface(deleteNode));
 
   if (NS_SUCCEEDED(res))  
   {
     nsAutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction);
-    int32_t i;
     // Notify nsIEditActionListener::WillDelete[Selection|Text|Node]
-    if (!deleteNode)
-      for (i = 0; i < mActionListeners.Count(); i++)
-        mActionListeners[i]->WillDeleteSelection(selection);
-    else if (deleteCharData)
-      for (i = 0; i < mActionListeners.Count(); i++)
-        mActionListeners[i]->WillDeleteText(deleteCharData, deleteCharOffset, 1);
-    else
-      for (i = 0; i < mActionListeners.Count(); i++)
-        mActionListeners[i]->WillDeleteNode(deleteNode->AsDOMNode());
+    if (!deleteNode) {
+      for (auto& listener : mActionListeners) {
+        listener->WillDeleteSelection(selection);
+      }
+    } else if (deleteCharData) {
+      for (auto& listener : mActionListeners) {
+        listener->WillDeleteText(deleteCharData, deleteCharOffset, 1);
+      }
+    } else {
+      for (auto& listener : mActionListeners) {
+        listener->WillDeleteNode(deleteNode->AsDOMNode());
+      }
+    }
 
     // Delete the specified amount
     res = DoTransaction(txn);  
 
     // Notify nsIEditActionListener::DidDelete[Selection|Text|Node]
-    if (!deleteNode)
-      for (i = 0; i < mActionListeners.Count(); i++)
-        mActionListeners[i]->DidDeleteSelection(selection);
-    else if (deleteCharData)
-      for (i = 0; i < mActionListeners.Count(); i++)
-        mActionListeners[i]->DidDeleteText(deleteCharData, deleteCharOffset, 1, res);
-    else
-      for (i = 0; i < mActionListeners.Count(); i++)
-        mActionListeners[i]->DidDeleteNode(deleteNode->AsDOMNode(), res);
+    if (!deleteNode) {
+      for (auto& listener : mActionListeners) {
+        listener->DidDeleteSelection(selection);
+      }
+    } else if (deleteCharData) {
+      for (auto& listener : mActionListeners) {
+        listener->DidDeleteText(deleteCharData, deleteCharOffset, 1, res);
+      }
+    } else {
+      for (auto& listener : mActionListeners) {
+        listener->DidDeleteNode(deleteNode->AsDOMNode(), res);
+      }
+    }
   }
 
   return res;
 }
 
 already_AddRefed<Element>
 nsEditor::DeleteSelectionAndCreateElement(nsIAtom& aTag)
 {
--- a/editor/libeditor/nsEditor.h
+++ b/editor/libeditor/nsEditor.h
@@ -2,19 +2,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __editor_h__
 #define __editor_h__
 
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc.
+#include "mozilla/dom/OwningNonNull.h"  // for OwningNonNull
 #include "mozilla/dom/Text.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
-#include "nsCOMArray.h"                 // for nsCOMArray
 #include "nsCOMPtr.h"                   // for already_AddRefed, nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
 #include "nsGkAtoms.h"
 #include "nsIEditor.h"                  // for nsIEditor::EDirection, etc
 #include "nsIEditorIMESupport.h"        // for NS_DECL_NSIEDITORIMESUPPORT, etc
 #include "nsIObserver.h"                // for NS_DECL_NSIOBSERVER, etc
 #include "nsIPhonetic.h"                // for NS_DECL_NSIPHONETIC, etc
 #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor, etc
@@ -825,19 +825,22 @@ protected:
   nsIAtom          *mPlaceHolderName;    // name of placeholder transaction
   nsSelectionState *mSelState;           // saved selection state for placeholder txn batching
   nsString         *mPhonetic;
   // IME composition this is not null between compositionstart and
   // compositionend.
   nsRefPtr<mozilla::TextComposition> mComposition;
 
   // various listeners
-  nsCOMArray<nsIEditActionListener> mActionListeners;  // listens to all low level actions on the doc
-  nsCOMArray<nsIEditorObserver> mEditorObservers;  // just notify once per high level change
-  nsCOMArray<nsIDocumentStateListener> mDocStateListeners;// listen to overall doc state (dirty or not, just created, etc)
+  // Listens to all low level actions on the doc
+  nsTArray<mozilla::dom::OwningNonNull<nsIEditActionListener>> mActionListeners;
+  // Just notify once per high level change
+  nsTArray<mozilla::dom::OwningNonNull<nsIEditorObserver>> mEditorObservers;
+  // Listen to overall doc state (dirty or not, just created, etc)
+  nsTArray<mozilla::dom::OwningNonNull<nsIDocumentStateListener>> mDocStateListeners;
 
   nsSelectionState  mSavedSel;           // cached selection for nsAutoSelectionReset
   nsRangeUpdater    mRangeUpdater;       // utility class object for maintaining preserved ranges
 
   uint32_t          mModCount;     // number of modifications (for undo/redo stack)
   uint32_t          mFlags;        // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   int32_t           mUpdateCount;
--- a/editor/libeditor/nsEditorUtils.cpp
+++ b/editor/libeditor/nsEditorUtils.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsEditorUtils.h"
 
+#include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/Selection.h"
-#include "nsCOMArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsError.h"
 #include "nsIClipboardDragDropHookList.h"
 // hooks
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMDocument.h"
@@ -61,101 +61,63 @@ nsAutoSelectionReset::Abort()
     mEd->StopPreservingSelection();
 }
 
 
 /******************************************************************************
  * some helper classes for iterating the dom tree
  *****************************************************************************/
 
-nsDOMIterator::nsDOMIterator() :
-mIter(nullptr)
+nsDOMIterator::nsDOMIterator(nsRange& aRange)
+{
+  MOZ_ASSERT(aRange.GetStartParent(), "Invalid range");
+  mIter = NS_NewContentIterator();
+  DebugOnly<nsresult> res = mIter->Init(&aRange);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
+}
+
+nsDOMIterator::nsDOMIterator(nsINode& aNode)
+{
+  mIter = NS_NewContentIterator();
+  DebugOnly<nsresult> res = mIter->Init(&aNode);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
+}
+
+nsDOMIterator::nsDOMIterator()
 {
 }
-    
+
 nsDOMIterator::~nsDOMIterator()
 {
 }
-    
-nsresult
-nsDOMIterator::Init(nsRange* aRange)
-{
-  nsresult res;
-  mIter = do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res);
-  NS_ENSURE_SUCCESS(res, res);
-  NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE);
-  return mIter->Init(aRange);
-}
 
-nsresult
-nsDOMIterator::Init(nsIDOMNode* aNode)
-{
-  nsresult res;
-  mIter = do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res);
-  NS_ENSURE_SUCCESS(res, res);
-  NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE);
-  nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-  return mIter->Init(content);
-}
-
-nsresult
-nsDOMIterator::AppendList(nsBoolDomIterFunctor& functor,
-                          nsTArray<nsCOMPtr<nsINode>>& arrayOfNodes) const
+void
+nsDOMIterator::AppendList(const nsBoolDomIterFunctor& functor,
+                          nsTArray<OwningNonNull<nsINode>>& arrayOfNodes) const
 {
   // Iterate through dom and build list
-  while (!mIter->IsDone()) {
+  for (; !mIter->IsDone(); mIter->Next()) {
     nsCOMPtr<nsINode> node = mIter->GetCurrentNode();
-    NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
 
     if (functor(node)) {
-      arrayOfNodes.AppendElement(node);
+      arrayOfNodes.AppendElement(*node);
     }
-    mIter->Next();
   }
-  return NS_OK;
 }
 
-nsresult
-nsDOMIterator::AppendList(nsBoolDomIterFunctor& functor,
-                          nsCOMArray<nsIDOMNode>& arrayOfNodes) const
+nsDOMSubtreeIterator::nsDOMSubtreeIterator(nsRange& aRange)
 {
-  nsCOMPtr<nsIDOMNode> node;
-  
-  // iterate through dom and build list
-  while (!mIter->IsDone())
-  {
-    node = do_QueryInterface(mIter->GetCurrentNode());
-    NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
-
-    if (functor(node))
-    {
-      arrayOfNodes.AppendObject(node);
-    }
-    mIter->Next();
-  }
-  return NS_OK;
+  mIter = NS_NewContentSubtreeIterator();
+  DebugOnly<nsresult> res = mIter->Init(&aRange);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
 }
 
-nsDOMSubtreeIterator::nsDOMSubtreeIterator()
-{
-}
-    
 nsDOMSubtreeIterator::~nsDOMSubtreeIterator()
 {
 }
-    
-nsresult
-nsDOMSubtreeIterator::Init(nsRange* aRange)
-{
-  nsresult res;
-  mIter = do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
-  NS_ENSURE_SUCCESS(res, res);
-  NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE);
-  return mIter->Init(aRange);
-}
 
 /******************************************************************************
  * some general purpose editor utils
  *****************************************************************************/
 
 bool
 nsEditorUtils::IsDescendantOf(nsINode* aNode, nsINode* aParent, int32_t* aOffset)
 {
--- a/editor/libeditor/nsEditorUtils.h
+++ b/editor/libeditor/nsEditorUtils.h
@@ -14,19 +14,19 @@
 #include "nsIDOMNode.h"
 #include "nsIEditor.h"
 #include "nscore.h"
 
 class nsIAtom;
 class nsIContentIterator;
 class nsIDOMDocument;
 class nsRange;
-template <class E> class nsCOMArray;
 namespace mozilla {
 namespace dom {
+template <class T> class OwningNonNull;
 class Selection;
 }
 }
 
 /***************************************************************************
  * stack based helper class for batching a collection of txns inside a 
  * placeholder txn.
  */
@@ -162,52 +162,47 @@ class MOZ_STACK_CLASS nsAutoUpdateViewBa
 
 /******************************************************************************
  * some helper classes for iterating the dom tree
  *****************************************************************************/
 
 class nsBoolDomIterFunctor 
 {
   public:
-    virtual bool operator()(nsIDOMNode* aNode)=0;
-    bool operator()(nsINode* aNode)
-    {
-      return operator()(GetAsDOMNode(aNode));
-    }
+    virtual bool operator()(nsINode* aNode) const = 0;
 };
 
 class MOZ_STACK_CLASS nsDOMIterator
 {
   public:
-    nsDOMIterator();
+    explicit nsDOMIterator(nsRange& aRange);
+    explicit nsDOMIterator(nsINode& aNode);
     virtual ~nsDOMIterator();
-    
-    nsresult Init(nsRange* aRange);
-    nsresult Init(nsIDOMNode* aNode);
-    nsresult AppendList(nsBoolDomIterFunctor& functor,
-                        nsTArray<nsCOMPtr<nsINode>>& arrayOfNodes) const;
-    nsresult AppendList(nsBoolDomIterFunctor& functor,
-                        nsCOMArray<nsIDOMNode>& arrayOfNodes) const;
+
+    void AppendList(const nsBoolDomIterFunctor& functor,
+                    nsTArray<mozilla::dom::OwningNonNull<nsINode>>& arrayOfNodes) const;
   protected:
     nsCOMPtr<nsIContentIterator> mIter;
+
+    // For nsDOMSubtreeIterator
+    nsDOMIterator();
 };
 
 class MOZ_STACK_CLASS nsDOMSubtreeIterator : public nsDOMIterator
 {
   public:
-    nsDOMSubtreeIterator();
+    explicit nsDOMSubtreeIterator(nsRange& aRange);
     virtual ~nsDOMSubtreeIterator();
-
-    nsresult Init(nsRange* aRange);
 };
 
 class nsTrivialFunctor : public nsBoolDomIterFunctor
 {
   public:
-    virtual bool operator()(nsIDOMNode* aNode)  // used to build list of all nodes iterator covers
+    // Used to build list of all nodes iterator covers
+    virtual bool operator()(nsINode* aNode) const
     {
       return true;
     }
 };
 
 
 /******************************************************************************
  * general dom point utility struct
--- a/editor/libeditor/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/nsHTMLDataTransfer.cpp
@@ -2,24 +2,24 @@
 /* vim: set ts=2 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <string.h>
 
 #include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Base64.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Selection.h"
 #include "nsAString.h"
 #include "nsAutoPtr.h"
-#include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsEditRules.h"
@@ -97,49 +97,16 @@ using namespace mozilla::dom;
 
 // some little helpers
 static bool FindIntegerAfterString(const char *aLeadingString, 
                                      nsCString &aCStr, int32_t &foundNumber);
 static nsresult RemoveFragComments(nsCString &theStr);
 static void RemoveBodyAndHead(nsIDOMNode *aNode);
 static nsresult FindTargetNode(nsIDOMNode *aStart, nsCOMPtr<nsIDOMNode> &aResult);
 
-static nsCOMPtr<nsIDOMNode> GetListParent(nsIDOMNode* aNode)
-{
-  NS_ENSURE_TRUE(aNode, nullptr);
-  nsCOMPtr<nsIDOMNode> parent, tmp;
-  aNode->GetParentNode(getter_AddRefs(parent));
-  while (parent)
-  {
-    if (nsHTMLEditUtils::IsList(parent)) {
-      return parent;
-    }
-    parent->GetParentNode(getter_AddRefs(tmp));
-    parent = tmp;
-  }
-  return nullptr;
-}
-
-static nsCOMPtr<nsIDOMNode> GetTableParent(nsIDOMNode* aNode)
-{
-  NS_ENSURE_TRUE(aNode, nullptr);
-  nsCOMPtr<nsIDOMNode> parent, tmp;
-  aNode->GetParentNode(getter_AddRefs(parent));
-  while (parent)
-  {
-    if (nsHTMLEditUtils::IsTable(parent)) {
-      return parent;
-    }
-    parent->GetParentNode(getter_AddRefs(tmp));
-    parent = tmp;
-  }
-  return nullptr;
-}
-
-
 nsresult
 nsHTMLEditor::LoadHTML(const nsAString & aInputString)
 {
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
 
   // force IME commit; set up rules sniffing and batching
   ForceCompositionEnd();
   nsAutoEditBatch beginBatching(this);
@@ -316,23 +283,31 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
     rv = selection->Collapse(targetNode, targetOffset);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // we need to recalculate various things based on potentially new offsets
   // this is work to be completed at a later date (probably by jfrancis)
 
   // make a list of what nodes in docFrag we need to move
-  nsCOMArray<nsIDOMNode> nodeList;
-  rv = CreateListOfNodesToPaste(fragmentAsNode, nodeList,
-                                streamStartParent, streamStartOffset,
-                                streamEndParent, streamEndOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsTArray<OwningNonNull<nsINode>> nodeList;
+  nsCOMPtr<nsINode> fragmentAsNodeNode = do_QueryInterface(fragmentAsNode);
+  NS_ENSURE_STATE(fragmentAsNodeNode || !fragmentAsNode);
+  nsCOMPtr<nsINode> streamStartParentNode =
+    do_QueryInterface(streamStartParent);
+  NS_ENSURE_STATE(streamStartParentNode || !streamStartParent);
+  nsCOMPtr<nsINode> streamEndParentNode =
+    do_QueryInterface(streamEndParent);
+  NS_ENSURE_STATE(streamEndParentNode || !streamEndParent);
+  CreateListOfNodesToPaste(*static_cast<DocumentFragment*>(fragmentAsNodeNode.get()),
+                           nodeList,
+                           streamStartParentNode, streamStartOffset,
+                           streamEndParentNode, streamEndOffset);
 
-  if (nodeList.Count() == 0) {
+  if (nodeList.Length() == 0) {
     return NS_OK;
   }
 
   // Are there any table elements in the list?
   // node and offset for insertion
   nsCOMPtr<nsIDOMNode> parentNode;
   int32_t offsetOfNewNode;
 
@@ -347,19 +322,19 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
 
   if (cellSelectionMode)
   {
     // do we have table content to paste?  If so, we want to delete
     // the selected table cells and replace with new table elements;
     // but if not we want to delete _contents_ of cells and replace
     // with non-table elements.  Use cellSelectionMode bool to 
     // indicate results.
-    nsIDOMNode* firstNode = nodeList[0];
-    if (!nsHTMLEditUtils::IsTableElement(firstNode))
+    if (!nsHTMLEditUtils::IsTableElement(nodeList[0])) {
       cellSelectionMode = false;
+    }
   }
 
   if (!cellSelectionMode)
   {
     rv = DeleteSelectionAndPrepareToCreateNode();
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aClearStyle) {
@@ -397,17 +372,18 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
   {
     // The rules code (WillDoAction above) might have changed the selection.
     // refresh our memory...
     rv = GetStartNodeAndOffset(selection, getter_AddRefs(parentNode), &offsetOfNewNode);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_TRUE(parentNode, NS_ERROR_FAILURE);
 
     // Adjust position based on the first node we are going to insert.
-    NormalizeEOLInsertPosition(nodeList[0], address_of(parentNode), &offsetOfNewNode);
+    NormalizeEOLInsertPosition(GetAsDOMNode(nodeList[0]),
+                               address_of(parentNode), &offsetOfNewNode);
 
     // if there are any invisible br's after our insertion point, remove them.
     // this is because if there is a br at end of what we paste, it will make
     // the invisible br visible.
     nsWSRunObject wsObj(this, parentNode, offsetOfNewNode);
     if (wsObj.mEndReasonNode &&
         nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
         !IsVisBreak(wsObj.mEndReasonNode)) {
@@ -426,70 +402,67 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
       NS_ENSURE_SUCCESS(rv, rv);
       rv = parentNode->GetParentNode(getter_AddRefs(temp));
       NS_ENSURE_SUCCESS(rv, rv);
       parentNode = temp;
     }
 
     // build up list of parents of first node in list that are either
     // lists or tables.  First examine front of paste node list.
-    nsCOMArray<nsIDOMNode> startListAndTableArray;
-    rv = GetListAndTableParents(false, nodeList, startListAndTableArray);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsTArray<OwningNonNull<Element>> startListAndTableArray;
+    GetListAndTableParents(StartOrEnd::start, nodeList,
+                           startListAndTableArray);
 
     // remember number of lists and tables above us
     int32_t highWaterMark = -1;
-    if (startListAndTableArray.Count() > 0)
-    {
-      rv = DiscoverPartialListsAndTables(nodeList, startListAndTableArray, &highWaterMark);
-      NS_ENSURE_SUCCESS(rv, rv);
+    if (startListAndTableArray.Length() > 0) {
+      highWaterMark = DiscoverPartialListsAndTables(nodeList,
+                                                    startListAndTableArray);
     }
 
     // if we have pieces of tables or lists to be inserted, let's force the paste 
     // to deal with table elements right away, so that it doesn't orphan some 
     // table or list contents outside the table or list.
     if (highWaterMark >= 0)
     {
-      rv = ReplaceOrphanedStructure(false, nodeList, startListAndTableArray, highWaterMark);
-      NS_ENSURE_SUCCESS(rv, rv);
+      ReplaceOrphanedStructure(StartOrEnd::start, nodeList,
+                               startListAndTableArray, highWaterMark);
     }
 
     // Now go through the same process again for the end of the paste node list.
-    nsCOMArray<nsIDOMNode> endListAndTableArray;
-    rv = GetListAndTableParents(true, nodeList, endListAndTableArray);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsTArray<OwningNonNull<Element>> endListAndTableArray;
+    GetListAndTableParents(StartOrEnd::end, nodeList, endListAndTableArray);
     highWaterMark = -1;
 
     // remember number of lists and tables above us
-    if (endListAndTableArray.Count() > 0)
-    {
-      rv = DiscoverPartialListsAndTables(nodeList, endListAndTableArray, &highWaterMark);
-      NS_ENSURE_SUCCESS(rv, rv);
+    if (endListAndTableArray.Length() > 0) {
+      highWaterMark = DiscoverPartialListsAndTables(nodeList,
+                                                    endListAndTableArray);
     }
 
     // don't orphan partial list or table structure
     if (highWaterMark >= 0)
     {
-      rv = ReplaceOrphanedStructure(true, nodeList, endListAndTableArray, highWaterMark);
-      NS_ENSURE_SUCCESS(rv, rv);
+      ReplaceOrphanedStructure(StartOrEnd::end, nodeList,
+                               endListAndTableArray, highWaterMark);
     }
 
     // Loop over the node list and paste the nodes:
     nsCOMPtr<nsIDOMNode> parentBlock, lastInsertNode, insertedContextParent;
-    int32_t listCount = nodeList.Count();
+    int32_t listCount = nodeList.Length();
     int32_t j;
     if (IsBlockNode(parentNode))
       parentBlock = parentNode;
     else
       parentBlock = GetBlockNodeParent(parentNode);
 
     for (j=0; j<listCount; j++)
     {
       bool bDidInsert = false;
-      nsCOMPtr<nsIDOMNode> curNode = nodeList[j];
+      nsCOMPtr<nsIDOMNode> curNode = nodeList[j]->AsDOMNode();
 
       NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
       NS_ENSURE_TRUE(curNode != fragmentAsNode, NS_ERROR_FAILURE);
       NS_ENSURE_TRUE(!nsTextEditUtils::IsBody(curNode), NS_ERROR_FAILURE);
 
       if (insertedContextParent)
       {
         // if we had to insert something higher up in the paste hierarchy, we want to 
@@ -716,36 +689,35 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
         }
       }
     }
   }
 
   return mRules->DidDoAction(selection, &ruleInfo, rv);
 }
 
-nsresult
+NS_IMETHODIMP
 nsHTMLEditor::AddInsertionListener(nsIContentFilter *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
 
   // don't let a listener be added more than once
-  if (mContentFilters.IndexOfObject(aListener) == -1)
-  {
-    NS_ENSURE_TRUE(mContentFilters.AppendObject(aListener), NS_ERROR_FAILURE);
+  if (!mContentFilters.Contains(aListener)) {
+    mContentFilters.AppendElement(*aListener);
   }
 
   return NS_OK;
 }
 
-nsresult
+NS_IMETHODIMP
 nsHTMLEditor::RemoveInsertionListener(nsIContentFilter *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
 
-  NS_ENSURE_TRUE(mContentFilters.RemoveObject(aListener), NS_ERROR_FAILURE);
+  mContentFilters.RemoveElement(aListener);
 
   return NS_OK;
 }
  
 nsresult
 nsHTMLEditor::DoContentFilterCallback(const nsAString &aFlavor, 
                                       nsIDOMDocument *sourceDoc,
                                       bool aWillDeleteSelection,
@@ -755,27 +727,25 @@ nsHTMLEditor::DoContentFilterCallback(co
                                       nsIDOMNode **aFragEndNode, 
                                       int32_t *aFragEndOffset,
                                       nsIDOMNode **aTargetNode,
                                       int32_t *aTargetOffset,
                                       bool *aDoContinue)
 {
   *aDoContinue = true;
 
-  int32_t i;
-  nsIContentFilter *listener;
-  for (i=0; i < mContentFilters.Count() && *aDoContinue; i++)
-  {
-    listener = (nsIContentFilter *)mContentFilters[i];
-    if (listener)
-      listener->NotifyOfInsertion(aFlavor, nullptr, sourceDoc,
-                                  aWillDeleteSelection, aFragmentAsNode,
-                                  aFragStartNode, aFragStartOffset, 
-                                  aFragEndNode, aFragEndOffset,
-                                  aTargetNode, aTargetOffset, aDoContinue);
+  for (auto& listener : mContentFilters) {
+    if (!*aDoContinue) {
+      break;
+    }
+    listener->NotifyOfInsertion(aFlavor, nullptr, sourceDoc,
+                                aWillDeleteSelection, aFragmentAsNode,
+                                aFragStartNode, aFragStartOffset,
+                                aFragEndNode, aFragEndOffset, aTargetNode,
+                                aTargetOffset, aDoContinue);
   }
 
   return NS_OK;
 }
 
 bool
 nsHTMLEditor::IsInLink(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *outLink)
 {
@@ -2161,224 +2131,175 @@ nsresult nsHTMLEditor::ParseFragment(con
                               nsIParserUtils::SanitizerAllowStyle :
                               nsIParserUtils::SanitizerAllowComments);
     sanitizer.Sanitize(fragment);
   }
   *outNode = fragment.forget();
   return rv;
 }
 
-nsresult nsHTMLEditor::CreateListOfNodesToPaste(nsIDOMNode  *aFragmentAsNode,
-                                                nsCOMArray<nsIDOMNode>& outNodeList,
-                                                nsIDOMNode *aStartNode,
-                                                int32_t aStartOffset,
-                                                nsIDOMNode *aEndNode,
-                                                int32_t aEndOffset)
+void
+nsHTMLEditor::CreateListOfNodesToPaste(DocumentFragment& aFragment,
+                                       nsTArray<OwningNonNull<nsINode>>& outNodeList,
+                                       nsINode* aStartNode,
+                                       int32_t aStartOffset,
+                                       nsINode* aEndNode,
+                                       int32_t aEndOffset)
 {
-  NS_ENSURE_TRUE(aFragmentAsNode, NS_ERROR_NULL_POINTER);
-
-  nsresult rv;
-
-  // if no info was provided about the boundary between context and stream,
+  // If no info was provided about the boundary between context and stream,
   // then assume all is stream.
-  if (!aStartNode)
-  {
-    int32_t fragLen;
-    rv = GetLengthOfDOMNode(aFragmentAsNode, (uint32_t&)fragLen);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    aStartNode = aFragmentAsNode;
+  if (!aStartNode) {
+    aStartNode = &aFragment;
     aStartOffset = 0;
-    aEndNode = aFragmentAsNode;
-    aEndOffset = fragLen;
+    aEndNode = &aFragment;
+    aEndOffset = aFragment.Length();
   }
 
   nsRefPtr<nsRange> docFragRange;
-  rv = nsRange::CreateRange(aStartNode, aStartOffset, aEndNode, aEndOffset, getter_AddRefs(docFragRange));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = nsRange::CreateRange(aStartNode, aStartOffset,
+                                     aEndNode, aEndOffset,
+                                     getter_AddRefs(docFragRange));
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  NS_ENSURE_SUCCESS(rv, );
 
-  // now use a subtree iterator over the range to create a list of nodes
+  // Now use a subtree iterator over the range to create a list of nodes
   nsTrivialFunctor functor;
-  nsDOMSubtreeIterator iter;
-  rv = iter.Init(docFragRange);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return iter.AppendList(functor, outNodeList);
+  nsDOMSubtreeIterator iter(*docFragRange);
+  iter.AppendList(functor, outNodeList);
 }
 
-nsresult
-nsHTMLEditor::GetListAndTableParents(bool aEnd,
-                                     nsCOMArray<nsIDOMNode>& aListOfNodes,
-                                     nsCOMArray<nsIDOMNode>& outArray)
+void
+nsHTMLEditor::GetListAndTableParents(StartOrEnd aStartOrEnd,
+                                     nsTArray<OwningNonNull<nsINode>>& aNodeList,
+                                     nsTArray<OwningNonNull<Element>>& outArray)
 {
-  int32_t listCount = aListOfNodes.Count();
-  NS_ENSURE_TRUE(listCount > 0, NS_ERROR_FAILURE);  // no empty lists, please
-
-  // build up list of parents of first (or last) node in list
-  // that are either lists, or tables.
-  int32_t idx = 0;
-  if (aEnd) idx = listCount-1;
+  MOZ_ASSERT(aNodeList.Length());
 
-  nsCOMPtr<nsIDOMNode> pNode = aListOfNodes[idx];
-  while (pNode)
-  {
-    if (nsHTMLEditUtils::IsList(pNode) || nsHTMLEditUtils::IsTable(pNode))
-    {
-      NS_ENSURE_TRUE(outArray.AppendObject(pNode), NS_ERROR_FAILURE);
+  // Build up list of parents of first (or last) node in list that are either
+  // lists, or tables.
+  int32_t idx = aStartOrEnd == StartOrEnd::end ? aNodeList.Length() - 1 : 0;
+
+  for (nsCOMPtr<nsINode> node = aNodeList[idx]; node;
+       node = node->GetParentNode()) {
+    if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node)) {
+      outArray.AppendElement(*node->AsElement());
     }
-    nsCOMPtr<nsIDOMNode> parent;
-    pNode->GetParentNode(getter_AddRefs(parent));
-    pNode = parent;
   }
-  return NS_OK;
 }
 
-nsresult
-nsHTMLEditor::DiscoverPartialListsAndTables(nsCOMArray<nsIDOMNode>& aPasteNodes,
-                                            nsCOMArray<nsIDOMNode>& aListsAndTables,
-                                            int32_t *outHighWaterMark)
+int32_t
+nsHTMLEditor::DiscoverPartialListsAndTables(nsTArray<OwningNonNull<nsINode>>& aPasteNodes,
+                                            nsTArray<OwningNonNull<Element>>& aListsAndTables)
 {
-  NS_ENSURE_TRUE(outHighWaterMark, NS_ERROR_NULL_POINTER);
-  
-  *outHighWaterMark = -1;
-  int32_t listAndTableParents = aListsAndTables.Count();
+  int32_t ret = -1;
+  int32_t listAndTableParents = aListsAndTables.Length();
   
-  // scan insertion list for table elements (other than table).
-  int32_t listCount = aPasteNodes.Count();
-  int32_t j;  
-  for (j=0; j<listCount; j++)
-  {
-    nsCOMPtr<nsIDOMNode> curNode = aPasteNodes[j];
-
-    NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
-    if (nsHTMLEditUtils::IsTableElement(curNode) && !nsHTMLEditUtils::IsTable(curNode))
-    {
-      nsCOMPtr<nsIDOMNode> theTable = GetTableParent(curNode);
-      if (theTable)
-      {
-        int32_t indexT = aListsAndTables.IndexOf(theTable);
-        if (indexT >= 0)
-        {
-          *outHighWaterMark = indexT;
-          if (*outHighWaterMark == listAndTableParents-1) break;
+  // Scan insertion list for table elements (other than table).
+  for (auto& curNode : aPasteNodes) {
+    if (nsHTMLEditUtils::IsTableElement(curNode) &&
+        !curNode->IsHTMLElement(nsGkAtoms::table)) {
+      nsCOMPtr<Element> table = curNode->GetParentElement();
+      while (table && !table->IsHTMLElement(nsGkAtoms::table)) {
+        table = table->GetParentElement();
+      }
+      if (table) {
+        int32_t idx = aListsAndTables.IndexOf(table);
+        if (idx == -1) {
+          return ret;
         }
-        else
-        {
-          break;
+        ret = idx;
+        if (ret == listAndTableParents - 1) {
+          return ret;
         }
       }
     }
-    if (nsHTMLEditUtils::IsListItem(curNode))
-    {
-      nsCOMPtr<nsIDOMNode> theList = GetListParent(curNode);
-      if (theList)
-      {
-        int32_t indexL = aListsAndTables.IndexOf(theList);
-        if (indexL >= 0)
-        {
-          *outHighWaterMark = indexL;
-          if (*outHighWaterMark == listAndTableParents-1) break;
+    if (nsHTMLEditUtils::IsListItem(curNode)) {
+      nsCOMPtr<Element> list = curNode->GetParentElement();
+      while (list && !nsHTMLEditUtils::IsList(list)) {
+        list = list->GetParentElement();
+      }
+      if (list) {
+        int32_t idx = aListsAndTables.IndexOf(list);
+        if (idx == -1) {
+          return ret;
         }
-        else
-        {
-          break;
+        ret = idx;
+        if (ret == listAndTableParents - 1) {
+          return ret;
         }
       }
     }
   }
-  return NS_OK;
-}
-
-nsresult
-nsHTMLEditor::ScanForListAndTableStructure( bool aEnd,
-                                            nsCOMArray<nsIDOMNode>& aNodes,
-                                            nsIDOMNode *aListOrTable,
-                                            nsCOMPtr<nsIDOMNode> *outReplaceNode)
-{
-  NS_ENSURE_TRUE(aListOrTable, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(outReplaceNode, NS_ERROR_NULL_POINTER);
-
-  *outReplaceNode = 0;
-  
-  // look upward from first/last paste node for a piece of this list/table
-  int32_t listCount = aNodes.Count(), idx = 0;
-  if (aEnd) idx = listCount-1;
-  bool bList = nsHTMLEditUtils::IsList(aListOrTable);
-  
-  nsCOMPtr<nsIDOMNode>  pNode = aNodes[idx];
-  nsCOMPtr<nsIDOMNode>  originalNode = pNode;
-  while (pNode)
-  {
-    if ((bList && nsHTMLEditUtils::IsListItem(pNode)) ||
-        (!bList && (nsHTMLEditUtils::IsTableElement(pNode) && !nsHTMLEditUtils::IsTable(pNode))))
-    {
-      nsCOMPtr<nsIDOMNode> structureNode;
-      if (bList) structureNode = GetListParent(pNode);
-      else structureNode = GetTableParent(pNode);
-      if (structureNode == aListOrTable)
-      {
-        if (bList)
-          *outReplaceNode = structureNode;
-        else
-          *outReplaceNode = pNode;
-        break;
-      }
-    }
-    nsCOMPtr<nsIDOMNode> parent;
-    pNode->GetParentNode(getter_AddRefs(parent));
-    pNode = parent;
-  }
-  return NS_OK;
+  return ret;
 }
 
-nsresult
-nsHTMLEditor::ReplaceOrphanedStructure(bool aEnd,
-                                       nsCOMArray<nsIDOMNode>& aNodeArray,
-                                       nsCOMArray<nsIDOMNode>& aListAndTableArray,
+nsINode*
+nsHTMLEditor::ScanForListAndTableStructure(StartOrEnd aStartOrEnd,
+                                           nsTArray<OwningNonNull<nsINode>>& aNodes,
+                                           Element& aListOrTable)
+{
+  // Look upward from first/last paste node for a piece of this list/table
+  int32_t idx = aStartOrEnd == StartOrEnd::end ? aNodes.Length() - 1 : 0;
+  bool isList = nsHTMLEditUtils::IsList(&aListOrTable);
+  
+  for (nsCOMPtr<nsINode> node = aNodes[idx]; node;
+       node = node->GetParentNode()) {
+    if ((isList && nsHTMLEditUtils::IsListItem(node)) ||
+        (!isList && nsHTMLEditUtils::IsTableElement(node) &&
+                    !node->IsHTMLElement(nsGkAtoms::table))) {
+      nsCOMPtr<Element> structureNode = node->GetParentElement();
+      if (isList) {
+        while (structureNode && !nsHTMLEditUtils::IsList(structureNode)) {
+          structureNode = structureNode->GetParentElement();
+        }
+      } else {
+        while (structureNode &&
+               !structureNode->IsHTMLElement(nsGkAtoms::table)) {
+          structureNode = structureNode->GetParentElement();
+        }
+      }
+      if (structureNode == &aListOrTable) {
+        if (isList) {
+          return structureNode;
+        }
+        return node;
+      }
+    }
+  }
+  return nullptr;
+}
+
+void
+nsHTMLEditor::ReplaceOrphanedStructure(StartOrEnd aStartOrEnd,
+                                       nsTArray<OwningNonNull<nsINode>>& aNodeArray,
+                                       nsTArray<OwningNonNull<Element>>& aListAndTableArray,
                                        int32_t aHighWaterMark)
 {
-  nsCOMPtr<nsIDOMNode> curNode = aListAndTableArray[aHighWaterMark];
-  NS_ENSURE_TRUE(curNode, NS_ERROR_NULL_POINTER);
-
-  nsCOMPtr<nsIDOMNode> replaceNode, originalNode;
-
-  // find substructure of list or table that must be included in paste.
-  nsresult rv = ScanForListAndTableStructure(aEnd, aNodeArray,
-                                 curNode, address_of(replaceNode));
-  NS_ENSURE_SUCCESS(rv, rv);
+  OwningNonNull<Element> curNode = aListAndTableArray[aHighWaterMark];
 
-  // if we found substructure, paste it instead of its descendants
-  if (replaceNode)
-  {
-    // postprocess list to remove any descendants of this node
-    // so that we don't insert them twice.
-    nsCOMPtr<nsIDOMNode> endpoint;
-    do
-    {
-      endpoint = GetArrayEndpoint(aEnd, aNodeArray);
-      if (!endpoint) break;
-      if (nsEditorUtils::IsDescendantOf(endpoint, replaceNode))
-        aNodeArray.RemoveObject(endpoint);
-      else
-        break;
-    } while(endpoint);
+  // Find substructure of list or table that must be included in paste.
+  nsCOMPtr<nsINode> replaceNode =
+    ScanForListAndTableStructure(aStartOrEnd, aNodeArray, curNode);
 
-    // now replace the removed nodes with the structural parent
-    if (aEnd) aNodeArray.AppendObject(replaceNode);
-    else aNodeArray.InsertObjectAt(replaceNode, 0);
-  }
-  return NS_OK;
-}
-
-nsIDOMNode* nsHTMLEditor::GetArrayEndpoint(bool aEnd,
-                                           nsCOMArray<nsIDOMNode>& aNodeArray)
-{
-  int32_t listCount = aNodeArray.Count();
-  if (listCount <= 0) {
-    return nullptr;
+  if (!replaceNode) {
+    return;
   }
 
-  if (aEnd) {
-    return aNodeArray[listCount-1];
+  // If we found substructure, paste it instead of its descendants.
+  // Postprocess list to remove any descendants of this node so that we don't
+  // insert them twice.
+  while (aNodeArray.Length()) {
+    int32_t idx = aStartOrEnd == StartOrEnd::start ? 0
+                                                   : aNodeArray.Length() - 1;
+    OwningNonNull<nsINode> endpoint = aNodeArray[idx];
+    if (!nsEditorUtils::IsDescendantOf(endpoint, replaceNode)) {
+      break;
+    }
+    aNodeArray.RemoveElementAt(idx);
   }
 
-  return aNodeArray[0];
+  // Now replace the removed nodes with the structural parent
+  if (aStartOrEnd == StartOrEnd::end) {
+    aNodeArray.AppendElement(*replaceNode);
+  } else {
+    aNodeArray.InsertElementAt(0, *replaceNode);
+  }
 }
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -8,20 +8,20 @@
 
 #include <stdlib.h>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
-#include "nsCOMArray.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsEditor.h"
 #include "nsEditorUtils.h"
 #include "nsError.h"
@@ -101,61 +101,63 @@ IsStyleCachePreservingAction(EditAction 
          action == EditAction::makeDefListItem ||
          action == EditAction::insertElement ||
          action == EditAction::insertQuotation;
 }
  
 class nsTableCellAndListItemFunctor : public nsBoolDomIterFunctor
 {
   public:
-    virtual bool operator()(nsIDOMNode* aNode)  // used to build list of all li's, td's & th's iterator covers
+    // Used to build list of all li's, td's & th's iterator covers
+    virtual bool operator()(nsINode* aNode) const
     {
       if (nsHTMLEditUtils::IsTableCell(aNode)) return true;
       if (nsHTMLEditUtils::IsListItem(aNode)) return true;
       return false;
     }
 };
 
 class nsBRNodeFunctor : public nsBoolDomIterFunctor
 {
   public:
-    virtual bool operator()(nsIDOMNode* aNode)  
+    virtual bool operator()(nsINode* aNode) const
     {
-      if (nsTextEditUtils::IsBreak(aNode)) return true;
+      if (aNode->IsHTMLElement(nsGkAtoms::br)) {
+        return true;
+      }
       return false;
     }
 };
 
 class nsEmptyEditableFunctor : public nsBoolDomIterFunctor
 {
   public:
     explicit nsEmptyEditableFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
-    virtual bool operator()(nsIDOMNode* aNode)  
+    virtual bool operator()(nsINode* aNode) const
     {
       if (mHTMLEditor->IsEditable(aNode) &&
-        (nsHTMLEditUtils::IsListItem(aNode) ||
-        nsHTMLEditUtils::IsTableCellOrCaption(aNode)))
-      {
+          (nsHTMLEditUtils::IsListItem(aNode) ||
+           nsHTMLEditUtils::IsTableCellOrCaption(GetAsDOMNode(aNode)))) {
         bool bIsEmptyNode;
         nsresult res = mHTMLEditor->IsEmptyNode(aNode, &bIsEmptyNode, false, false);
         NS_ENSURE_SUCCESS(res, false);
         if (bIsEmptyNode)
           return true;
       }
       return false;
     }
   protected:
     nsHTMLEditor* mHTMLEditor;
 };
 
 class nsEditableTextFunctor : public nsBoolDomIterFunctor
 {
   public:
     explicit nsEditableTextFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
-    virtual bool operator()(nsIDOMNode* aNode)  
+    virtual bool operator()(nsINode* aNode) const
     {
       if (nsEditor::IsTextNode(aNode) && mHTMLEditor->IsEditable(aNode)) 
       {
         return true;
       }
       return false;
     }
   protected:
@@ -269,18 +271,17 @@ nsHTMLEditRules::Init(nsPlaintextEditor 
   nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this);
   if (!mDocChangeRange) {
     mDocChangeRange = new nsRange(node);
   }
 
   if (node->IsElement()) {
     ErrorResult rv;
     mDocChangeRange->SelectNode(*node, rv);
-    res = AdjustSpecialBreaks(node);
-    NS_ENSURE_SUCCESS(res, res);
+    AdjustSpecialBreaks();
   }
 
   // add ourselves as a listener to edit actions
   res = mHTMLEditor->AddEditActionListener(this);
 
   return res;
 }
 
@@ -440,33 +441,31 @@ nsHTMLEditRules::AfterEditInner(EditActi
   if (bDamagedRange && !((action == EditAction::undo) || (action == EditAction::redo)))
   {
     // don't let any txns in here move the selection around behind our back.
     // Note that this won't prevent explicit selection setting from working.
     NS_ENSURE_STATE(mHTMLEditor);
     nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
    
     // expand the "changed doc range" as needed
-    res = PromoteRange(mDocChangeRange, action);
-    NS_ENSURE_SUCCESS(res, res);
+    PromoteRange(*mDocChangeRange, action);
 
     // if we did a ranged deletion or handling backspace key, make sure we have
     // a place to put caret.
     // Note we only want to do this if the overall operation was deletion,
     // not if deletion was done along the way for EditAction::loadHTML, EditAction::insertText, etc.
     // That's why this is here rather than DidDeleteSelection().
     if ((action == EditAction::deleteSelection) && mDidRangedDelete)
     {
       res = InsertBRIfNeeded(selection);
       NS_ENSURE_SUCCESS(res, res);
     }  
     
     // add in any needed <br>s, and remove any unneeded ones.
-    res = AdjustSpecialBreaks();
-    NS_ENSURE_SUCCESS(res, res);
+    AdjustSpecialBreaks();
     
     // merge any adjacent text nodes
     if ( (action != EditAction::insertText &&
          action != EditAction::insertIMEText) )
     {
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->CollapseAdjacentTextNodes(mDocChangeRange);
       NS_ENSURE_SUCCESS(res, res);
@@ -686,43 +685,40 @@ nsHTMLEditRules::GetListState(bool *aMix
 {
   NS_ENSURE_TRUE(aMixed && aOL && aUL && aDL, NS_ERROR_NULL_POINTER);
   *aMixed = false;
   *aOL = false;
   *aUL = false;
   *aDL = false;
   bool bNonList = false;
   
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  nsresult res = GetListActionNodes(arrayOfNodes, false, true);
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  nsresult res = GetListActionNodes(arrayOfNodes, EntireList::no,
+                                    TouchContent::no);
   NS_ENSURE_SUCCESS(res, res);
 
   // Examine list type for nodes in selection.
-  int32_t listCount = arrayOfNodes.Count();
-  for (int32_t i = listCount - 1; i >= 0; --i) {
-    nsIDOMNode* curDOMNode = arrayOfNodes[i];
-    nsCOMPtr<dom::Element> curElement = do_QueryInterface(curDOMNode);
-
-    if (!curElement) {
+  for (const auto& curNode : arrayOfNodes) {
+    if (!curNode->IsElement()) {
       bNonList = true;
-    } else if (curElement->IsHTMLElement(nsGkAtoms::ul)) {
+    } else if (curNode->IsHTMLElement(nsGkAtoms::ul)) {
       *aUL = true;
-    } else if (curElement->IsHTMLElement(nsGkAtoms::ol)) {
+    } else if (curNode->IsHTMLElement(nsGkAtoms::ol)) {
       *aOL = true;
-    } else if (curElement->IsHTMLElement(nsGkAtoms::li)) {
-      if (dom::Element* parent = curElement->GetParentElement()) {
+    } else if (curNode->IsHTMLElement(nsGkAtoms::li)) {
+      if (dom::Element* parent = curNode->GetParentElement()) {
         if (parent->IsHTMLElement(nsGkAtoms::ul)) {
           *aUL = true;
         } else if (parent->IsHTMLElement(nsGkAtoms::ol)) {
           *aOL = true;
         }
       }
-    } else if (curElement->IsAnyOfHTMLElements(nsGkAtoms::dl,
-                                               nsGkAtoms::dt,
-                                               nsGkAtoms::dd)) {
+    } else if (curNode->IsAnyOfHTMLElements(nsGkAtoms::dl,
+                                            nsGkAtoms::dt,
+                                            nsGkAtoms::dd)) {
       *aDL = true;
     } else {
       bNonList = true;
     }
   }  
   
   // hokey arithmetic with booleans
   if ((*aUL + *aOL + *aDL + bNonList) > 1) {
@@ -737,39 +733,37 @@ nsHTMLEditRules::GetListItemState(bool *
 {
   NS_ENSURE_TRUE(aMixed && aLI && aDT && aDD, NS_ERROR_NULL_POINTER);
   *aMixed = false;
   *aLI = false;
   *aDT = false;
   *aDD = false;
   bool bNonList = false;
   
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  nsresult res = GetListActionNodes(arrayOfNodes, false, true);
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  nsresult res = GetListActionNodes(arrayOfNodes, EntireList::no,
+                                    TouchContent::no);
   NS_ENSURE_SUCCESS(res, res);
 
   // examine list type for nodes in selection
-  int32_t listCount = arrayOfNodes.Count();
-  for (int32_t i = listCount - 1; i >= 0; --i) {
-    nsIDOMNode* curNode = arrayOfNodes[i];
-    nsCOMPtr<dom::Element> element = do_QueryInterface(curNode);
-    if (!element) {
+  for (const auto& node : arrayOfNodes) {
+    if (!node->IsElement()) {
       bNonList = true;
-    } else if (element->IsAnyOfHTMLElements(nsGkAtoms::ul,
-                                            nsGkAtoms::ol,
-                                            nsGkAtoms::li)) {
+    } else if (node->IsAnyOfHTMLElements(nsGkAtoms::ul,
+                                         nsGkAtoms::ol,
+                                         nsGkAtoms::li)) {
       *aLI = true;
-    } else if (element->IsHTMLElement(nsGkAtoms::dt)) {
+    } else if (node->IsHTMLElement(nsGkAtoms::dt)) {
       *aDT = true;
-    } else if (element->IsHTMLElement(nsGkAtoms::dd)) {
+    } else if (node->IsHTMLElement(nsGkAtoms::dd)) {
       *aDD = true;
-    } else if (element->IsHTMLElement(nsGkAtoms::dl)) {
+    } else if (node->IsHTMLElement(nsGkAtoms::dl)) {
       // need to look inside dl and see which types of items it has
       bool bDT, bDD;
-      GetDefinitionListItemTypes(element, &bDT, &bDD);
+      GetDefinitionListItemTypes(node->AsElement(), &bDT, &bDD);
       *aDT |= bDT;
       *aDD |= bDD;
     } else {
       bNonList = true;
     }
   }  
   
   // hokey arithmetic with booleans
@@ -808,78 +802,75 @@ nsHTMLEditRules::GetAlignment(bool *aMix
   nsCOMPtr<nsINode> parent = nsEditor::GetNodeLocation(rootElem, &rootOffset);
   NS_ENSURE_STATE(mHTMLEditor);
   nsresult res = mHTMLEditor->GetStartNodeAndOffset(selection,
                                                     getter_AddRefs(parent),
                                                     &offset);
   NS_ENSURE_SUCCESS(res, res);
 
   // is the selection collapsed?
-  nsCOMPtr<nsIDOMNode> nodeToExamine;
+  nsCOMPtr<nsINode> nodeToExamine;
   if (selection->Collapsed()) {
     // if it is, we want to look at 'parent' and its ancestors
     // for divs with alignment on them
-    nodeToExamine = GetAsDOMNode(parent);
+    nodeToExamine = parent;
   }
   else if (!mHTMLEditor) {
     return NS_ERROR_UNEXPECTED;
   }
   else if (mHTMLEditor->IsTextNode(parent)) 
   {
     // if we are in a text node, then that is the node of interest
-    nodeToExamine = GetAsDOMNode(parent);
+    nodeToExamine = parent;
   } else if (parent->IsHTMLElement(nsGkAtoms::html) && offset == rootOffset) {
     // if we have selected the body, let's look at the first editable node
     NS_ENSURE_STATE(mHTMLEditor);
-    nodeToExamine =
-      GetAsDOMNode(mHTMLEditor->GetNextNode(parent, offset, true));
+    nodeToExamine = mHTMLEditor->GetNextNode(parent, offset, true);
   }
   else
   {
     nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-    res = GetPromotedRanges(selection, arrayOfRanges, EditAction::align);
-    NS_ENSURE_SUCCESS(res, res);
+    GetPromotedRanges(*selection, arrayOfRanges, EditAction::align);
 
     // use these ranges to construct a list of nodes to act on.
-    nsCOMArray<nsIDOMNode> arrayOfNodes;
+    nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
     res = GetNodesForOperation(arrayOfRanges, arrayOfNodes,
-                               EditAction::align, true);
+                               EditAction::align, TouchContent::no);
     NS_ENSURE_SUCCESS(res, res);                                 
-    nodeToExamine = arrayOfNodes.SafeObjectAt(0);
+    nodeToExamine = arrayOfNodes.SafeElementAt(0);
   }
 
   NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER);
 
   NS_NAMED_LITERAL_STRING(typeAttrName, "align");
   nsIAtom  *dummyProperty = nullptr;
-  nsCOMPtr<nsIDOMNode> blockParent;
+  nsCOMPtr<Element> blockParent;
   NS_ENSURE_STATE(mHTMLEditor);
   if (mHTMLEditor->IsBlockNode(nodeToExamine))
-    blockParent = nodeToExamine;
+    blockParent = nodeToExamine->AsElement();
   else {
     NS_ENSURE_STATE(mHTMLEditor);
     blockParent = mHTMLEditor->GetBlockNodeParent(nodeToExamine);
   }
 
   NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
 
   NS_ENSURE_STATE(mHTMLEditor);
   if (mHTMLEditor->IsCSSEnabled())
   {
-    nsCOMPtr<nsIContent> blockParentContent = do_QueryInterface(blockParent);
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (blockParentContent && 
-        mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParentContent, dummyProperty, &typeAttrName))
-    {
+    NS_ENSURE_STATE(mHTMLEditor);
+    if (mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParent,
+                                                          dummyProperty,
+                                                          &typeAttrName)) {
       // we are in CSS mode and we know how to align this element with CSS
       nsAutoString value;
       // let's get the value(s) of text-align or margin-left/margin-right
       NS_ENSURE_STATE(mHTMLEditor);
       mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet(
-        blockParentContent, dummyProperty, &typeAttrName, value,
+        blockParent, dummyProperty, &typeAttrName, value,
         nsHTMLCSSUtils::eComputed);
       if (value.EqualsLiteral("center") ||
           value.EqualsLiteral("-moz-center") ||
           value.EqualsLiteral("auto auto"))
       {
         *aAlign = nsIHTMLEditor::eCenter;
         return NS_OK;
       }
@@ -896,29 +887,27 @@ nsHTMLEditRules::GetAlignment(bool *aMix
         return NS_OK;
       }
       *aAlign = nsIHTMLEditor::eLeft;
       return NS_OK;
     }
   }
 
   // check up the ladder for divs with alignment
-  nsCOMPtr<nsIDOMNode> temp = nodeToExamine;
   bool isFirstNodeToExamine = true;
   while (nodeToExamine)
   {
     if (!isFirstNodeToExamine && nsHTMLEditUtils::IsTable(nodeToExamine))
     {
       // the node to examine is a table and this is not the first node
       // we examine; let's break here to materialize the 'inline-block'
       // behaviour of html tables regarding to text alignment
       return NS_OK;
     }
-    if (nsHTMLEditUtils::SupportsAlignAttr(nodeToExamine))
-    {
+    if (nsHTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(nodeToExamine))) {
       // check for alignment
       nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(nodeToExamine);
       if (elem)
       {
         nsAutoString typeAttrVal;
         res = elem->GetAttribute(NS_LITERAL_STRING("align"), typeAttrVal);
         ToLowerCase(typeAttrVal);
         if (NS_SUCCEEDED(res) && typeAttrVal.Length())
@@ -931,19 +920,17 @@ nsHTMLEditRules::GetAlignment(bool *aMix
             *aAlign = nsIHTMLEditor::eJustify;
           else
             *aAlign = nsIHTMLEditor::eLeft;
           return res;
         }
       }
     }
     isFirstNodeToExamine = false;
-    res = nodeToExamine->GetParentNode(getter_AddRefs(temp));
-    if (NS_FAILED(res)) temp = nullptr;
-    nodeToExamine = temp; 
+    nodeToExamine = nodeToExamine->GetParentNode(); 
   }
   return NS_OK;
 }
 
 static nsIAtom* MarginPropertyAtomForIndent(nsHTMLCSSUtils* aHTMLCSSUtils,
                                             nsIDOMNode* aNode) {
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
   NS_ENSURE_TRUE(node || !aNode, nsGkAtoms::marginLeft);
@@ -960,33 +947,27 @@ nsHTMLEditRules::GetIndentState(bool *aC
   *aCanIndent = true;    
   *aCanOutdent = false;
 
   // get selection
   NS_ENSURE_STATE(mHTMLEditor && mHTMLEditor->GetSelection());
   OwningNonNull<Selection> selection = *mHTMLEditor->GetSelection();
 
   // contruct a list of nodes to act on.
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  nsresult res = GetNodesFromSelection(selection, EditAction::indent,
-                                       arrayOfNodes, true);
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  nsresult res = GetNodesFromSelection(*selection, EditAction::indent,
+                                       arrayOfNodes, TouchContent::no);
   NS_ENSURE_SUCCESS(res, res);
 
   // examine nodes in selection for blockquotes or list elements;
   // these we can outdent.  Note that we return true for canOutdent
   // if *any* of the selection is outdentable, rather than all of it.
-  int32_t listCount = arrayOfNodes.Count();
-  int32_t i;
   NS_ENSURE_STATE(mHTMLEditor);
   bool useCSS = mHTMLEditor->IsCSSEnabled();
-  for (i=listCount-1; i>=0; i--)
-  {
-    nsCOMPtr<nsINode> curNode = do_QueryInterface(arrayOfNodes[i]);
-    NS_ENSURE_STATE(curNode || !arrayOfNodes[i]);
-    
+  for (auto& curNode : Reversed(arrayOfNodes)) {
     if (nsHTMLEditUtils::IsNodeThatCanOutdent(GetAsDOMNode(curNode))) {
       *aCanOutdent = true;
       break;
     }
     else if (useCSS) {
       // we are in CSS mode, indentation is done using the margin-left (or margin-right) property
       NS_ENSURE_STATE(mHTMLEditor);
       nsIAtom* marginProperty =
@@ -1067,80 +1048,71 @@ nsHTMLEditRules::GetParagraphState(bool 
   NS_ENSURE_TRUE(aMixed, NS_ERROR_NULL_POINTER);
   *aMixed = true;
   outFormat.Truncate(0);
   
   bool bMixed = false;
   // using "x" as an uninitialized value, since "" is meaningful
   nsAutoString formatStr(NS_LITERAL_STRING("x")); 
   
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  nsresult res = GetParagraphFormatNodes(arrayOfNodes, true);
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  nsresult res = GetParagraphFormatNodes(arrayOfNodes, TouchContent::no);
   NS_ENSURE_SUCCESS(res, res);
 
   // post process list.  We need to replace any block nodes that are not format
   // nodes with their content.  This is so we only have to look "up" the hierarchy
   // to find format nodes, instead of both up and down.
-  int32_t listCount = arrayOfNodes.Count();
-  int32_t i;
-  for (i=listCount-1; i>=0; i--)
-  {
-    nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
+  for (int32_t i = arrayOfNodes.Length() - 1; i >= 0; i--) {
+    auto& curNode = arrayOfNodes[i];
     nsAutoString format;
     // if it is a known format node we have it easy
-    if (IsBlockNode(curNode) && !nsHTMLEditUtils::IsFormatNode(curNode))
-    {
+    if (IsBlockNode(GetAsDOMNode(curNode)) &&
+        !nsHTMLEditUtils::IsFormatNode(curNode)) {
       // arrayOfNodes.RemoveObject(curNode);
       res = AppendInnerFormatNodes(arrayOfNodes, curNode);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
   
   // we might have an empty node list.  if so, find selection parent
   // and put that on the list
-  listCount = arrayOfNodes.Count();
-  if (!listCount)
-  {
-    nsCOMPtr<nsIDOMNode> selNode;
+  if (!arrayOfNodes.Length()) {
+    nsCOMPtr<nsINode> selNode;
     int32_t selOffset;
     NS_ENSURE_STATE(mHTMLEditor);
     nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
     NS_ENSURE_STATE(selection);
     NS_ENSURE_STATE(mHTMLEditor);
     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_TRUE(selNode, NS_ERROR_NULL_POINTER);
-    arrayOfNodes.AppendObject(selNode);
-    listCount = 1;
+    arrayOfNodes.AppendElement(*selNode);
   }
 
   // remember root node
   NS_ENSURE_STATE(mHTMLEditor);
   nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
   NS_ENSURE_TRUE(rootElem, NS_ERROR_NULL_POINTER);
 
   // loop through the nodes in selection and examine their paragraph format
-  for (i=listCount-1; i>=0; i--)
-  {
-    nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
+  for (auto& curNode : Reversed(arrayOfNodes)) {
     nsAutoString format;
     // if it is a known format node we have it easy
-    if (nsHTMLEditUtils::IsFormatNode(curNode))
-      GetFormatString(curNode, format);
-    else if (IsBlockNode(curNode))
-    {
+    if (nsHTMLEditUtils::IsFormatNode(curNode)) {
+      GetFormatString(GetAsDOMNode(curNode), format);
+    } else if (IsBlockNode(GetAsDOMNode(curNode))) {
       // this is a div or some other non-format block.
       // we should ignore it.  Its children were appended to this list
       // by AppendInnerFormatNodes() call above.  We will get needed
       // info when we examine them instead.
       continue;
     }
     else
     {
-      nsCOMPtr<nsIDOMNode> node, tmp = curNode;
+      nsCOMPtr<nsIDOMNode> node, tmp = GetAsDOMNode(curNode);
       tmp->GetParentNode(getter_AddRefs(node));
       while (node)
       {
         if (node == rootElem)
         {
           format.Truncate(0);
           break;
         }
@@ -1167,27 +1139,17 @@ nsHTMLEditRules::GetParagraphState(bool 
   }  
   
   *aMixed = bMixed;
   outFormat = formatStr;
   return res;
 }
 
 nsresult
-nsHTMLEditRules::AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
-                                        nsIDOMNode *aNode)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
-
-  return AppendInnerFormatNodes(aArray, node);
-}
-
-nsresult
-nsHTMLEditRules::AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
+nsHTMLEditRules::AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray,
                                         nsINode* aNode)
 {
   MOZ_ASSERT(aNode);
 
   // we only need to place any one inline inside this node onto 
   // the list.  They are all the same for purposes of determining
   // paragraph style.  We use foundInline to track this as we are 
   // going through the children in the loop below.
@@ -1196,21 +1158,21 @@ nsHTMLEditRules::AppendInnerFormatNodes(
        child;
        child = child->GetNextSibling()) {
     bool isBlock = IsBlockNode(child->AsDOMNode());
     bool isFormat = nsHTMLEditUtils::IsFormatNode(child);
     if (isBlock && !isFormat) {
       // if it's a div, etc, recurse
       AppendInnerFormatNodes(aArray, child);
     } else if (isFormat) {
-      aArray.AppendObject(child->AsDOMNode());
+      aArray.AppendElement(*child);
     } else if (!foundInline) {
       // if this is the first inline we've found, use it
       foundInline = true;      
-      aArray.AppendObject(child->AsDOMNode());
+      aArray.AppendElement(*child);
     }
   }
   return NS_OK;
 }
 
 nsresult 
 nsHTMLEditRules::GetFormatString(nsIDOMNode *aNode, nsAString &outFormat)
 {
@@ -2432,23 +2394,20 @@ nsHTMLEditRules::WillDeleteSelection(Sel
         // except table elements.
         join = true;
 
         uint32_t rangeCount = aSelection->RangeCount();
         for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
           OwningNonNull<nsRange> range = *aSelection->GetRangeAt(rangeIdx);
 
           // Build a list of nodes in the range
-          nsTArray<nsCOMPtr<nsINode>> arrayOfNodes;
+          nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
           nsTrivialFunctor functor;
-          nsDOMSubtreeIterator iter;
-          res = iter.Init(range);
-          NS_ENSURE_SUCCESS(res, res);
-          res = iter.AppendList(functor, arrayOfNodes);
-          NS_ENSURE_SUCCESS(res, res);
+          nsDOMSubtreeIterator iter(*range);
+          iter.AppendList(functor, arrayOfNodes);
 
           // Now that we have the list, delete non-table elements
           int32_t listCount = arrayOfNodes.Length();
           for (int32_t j = 0; j < listCount; j++) {
             nsCOMPtr<nsINode> somenode = do_QueryInterface(arrayOfNodes[0]);
             NS_ENSURE_STATE(somenode);
             DeleteNonTableElements(somenode);
             arrayOfNodes.RemoveElementAt(0);
@@ -2890,40 +2849,35 @@ nsHTMLEditRules::JoinBlocks(nsIDOMNode *
 *         nsIDOMNode *aLeftBlock         parent to receive moved content
 *         nsIDOMNode *aRightBlock        parent to provide moved content
 *         int32_t aLeftOffset            offset in aLeftBlock to move content to
 *         int32_t aRightOffset           offset in aRightBlock to move content from
 */
 nsresult
 nsHTMLEditRules::MoveBlock(nsIDOMNode *aLeftBlock, nsIDOMNode *aRightBlock, int32_t aLeftOffset, int32_t aRightOffset)
 {
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  nsCOMPtr<nsISupports> isupports;
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
   // GetNodesFromPoint is the workhorse that figures out what we wnat to move.
   nsresult res = GetNodesFromPoint(::DOMPoint(aRightBlock,aRightOffset),
-                                   EditAction::makeList, arrayOfNodes, true);
+                                   EditAction::makeList, arrayOfNodes,
+                                   TouchContent::no);
   NS_ENSURE_SUCCESS(res, res);
-  int32_t listCount = arrayOfNodes.Count();
-  int32_t i;
-  for (i=0; i<listCount; i++)
-  {
+  for (auto& curNode : arrayOfNodes) {
     // get the node to act on
-    nsIDOMNode* curNode = arrayOfNodes[i];
-    if (IsBlockNode(curNode))
-    {
+    if (IsBlockNode(GetAsDOMNode(curNode))) {
       // For block nodes, move their contents only, then delete block.
-      res = MoveContents(curNode, aLeftBlock, &aLeftOffset); 
+      res = MoveContents(GetAsDOMNode(curNode), aLeftBlock, &aLeftOffset); 
       NS_ENSURE_SUCCESS(res, res);
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->DeleteNode(curNode);
     }
     else
     {
       // otherwise move the content as is, checking against the dtd.
-      res = MoveNodeSmart(curNode, aLeftBlock, &aLeftOffset);
+      res = MoveNodeSmart(GetAsDOMNode(curNode), aLeftBlock, &aLeftOffset);
     }
   }
   return res;
 }
 
 /*****************************************************************************************************
 *    MoveNodeSmart: this method is used to move node aSource to (aDest,aOffset).
 *    DTD containment rules are followed throughout.  aOffset is updated to point _after_
@@ -3089,41 +3043,40 @@ nsHTMLEditRules::WillMakeList(Selection*
 
   *aHandled = true;
 
   res = NormalizeSelection(aSelection);
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_STATE(mHTMLEditor);
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
 
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  res = GetListActionNodes(arrayOfNodes, aEntireList);
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  res = GetListActionNodes(arrayOfNodes,
+                           aEntireList ? EntireList::yes : EntireList::no);
   NS_ENSURE_SUCCESS(res, res);
 
-  int32_t listCount = arrayOfNodes.Count();
-
   // check if all our nodes are <br>s, or empty inlines
   bool bOnlyBreaks = true;
-  for (int32_t j = 0; j < listCount; j++) {
-    nsIDOMNode* curNode = arrayOfNodes[j];
+  for (auto& curNode : arrayOfNodes) {
     // if curNode is not a Break or empty inline, we're done
-    if (!nsTextEditUtils::IsBreak(curNode) && !IsEmptyInline(curNode)) {
+    if (!nsTextEditUtils::IsBreak(curNode) &&
+        !IsEmptyInline(GetAsDOMNode(curNode))) {
       bOnlyBreaks = false;
       break;
     }
   }
 
   // if no nodes, we make empty list.  Ditto if the user tried to make a list
   // of some # of breaks.
-  if (!listCount || bOnlyBreaks) {
+  if (!arrayOfNodes.Length() || bOnlyBreaks) {
     // if only breaks, delete them
     if (bOnlyBreaks) {
-      for (int32_t j = 0; j < (int32_t)listCount; j++) {
+      for (auto& node : arrayOfNodes) {
         NS_ENSURE_STATE(mHTMLEditor);
-        res = mHTMLEditor->DeleteNode(arrayOfNodes[j]);
+        res = mHTMLEditor->DeleteNode(node);
         NS_ENSURE_SUCCESS(res, res);
       }
     }
 
     // get selection location
     NS_ENSURE_STATE(aSelection->RangeCount());
     nsCOMPtr<nsINode> parent = aSelection->GetRangeAt(0)->GetStartParent();
     int32_t offset = aSelection->GetRangeAt(0)->StartOffset();
@@ -3155,31 +3108,30 @@ nsHTMLEditRules::WillMakeList(Selection*
     selectionResetter.Abort();
     *aHandled = true;
     return res;
   }
 
   // if there is only one node in the array, and it is a list, div, or
   // blockquote, then look inside of it until we find inner list or content.
 
-  res = LookInsideDivBQandList(arrayOfNodes);
-  NS_ENSURE_SUCCESS(res, res);
+  LookInsideDivBQandList(arrayOfNodes);
 
   // Ok, now go through all the nodes and put then in the list,
   // or whatever is approriate.  Wohoo!
 
-  listCount = arrayOfNodes.Count();
+  uint32_t listCount = arrayOfNodes.Length();
   nsCOMPtr<nsINode> curParent;
   nsCOMPtr<Element> curList, prevListItem;
 
-  for (int32_t i = 0; i < listCount; i++) {
+  for (uint32_t i = 0; i < listCount; i++) {
     // here's where we actually figure out what to do
     nsCOMPtr<nsIDOMNode> newBlock;
-    nsCOMPtr<nsIContent> curNode = do_QueryInterface(arrayOfNodes[i]);
-    NS_ENSURE_STATE(curNode);
+    NS_ENSURE_STATE(arrayOfNodes[i]->IsContent());
+    nsCOMPtr<nsIContent> curNode = arrayOfNodes[i]->AsContent();
     int32_t offset;
     curParent = nsEditor::GetNodeLocation(curNode, &offset);
 
     // make sure we don't assemble content that is in different table cells
     // into the same list.  respect table cell boundaries when listifying.
     if (curList && InDifferentTableElements(curList, curNode)) {
       curList = nullptr;
     }
@@ -3289,22 +3241,21 @@ nsHTMLEditRules::WillMakeList(Selection*
       continue;
     }
 
     // if we hit a div clear our prevListItem, insert divs contents
     // into our node array, and remove the div
     if (curNode->IsHTMLElement(nsGkAtoms::div)) {
       prevListItem = nullptr;
       int32_t j = i + 1;
-      res = GetInnerContent(curNode->AsDOMNode(), arrayOfNodes, &j);
-      NS_ENSURE_SUCCESS(res, res);
+      GetInnerContent(*curNode, arrayOfNodes, &j);
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->RemoveContainer(curNode);
       NS_ENSURE_SUCCESS(res, res);
-      listCount = arrayOfNodes.Count();
+      listCount = arrayOfNodes.Length();
       continue;
     }
 
     // need to make a list to put things in if we haven't already,
     if (!curList) {
       res = SplitAsNeeded(listType, curParent, offset);
       NS_ENSURE_SUCCESS(res, res);
       NS_ENSURE_STATE(mHTMLEditor);
@@ -3372,61 +3323,54 @@ nsHTMLEditRules::WillRemoveList(Selectio
   *aHandled = true;
   
   nsresult res = NormalizeSelection(aSelection);
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_STATE(mHTMLEditor);
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
   
   nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-  res = GetPromotedRanges(aSelection, arrayOfRanges, EditAction::makeList);
-  NS_ENSURE_SUCCESS(res, res);
+  GetPromotedRanges(*aSelection, arrayOfRanges, EditAction::makeList);
   
   // use these ranges to contruct a list of nodes to act on.
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  res = GetListActionNodes(arrayOfNodes, false);
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  res = GetListActionNodes(arrayOfNodes, EntireList::no);
   NS_ENSURE_SUCCESS(res, res);                                 
                                      
   // Remove all non-editable nodes.  Leave them be.
-  int32_t listCount = arrayOfNodes.Count();
+  int32_t listCount = arrayOfNodes.Length();
   int32_t i;
   for (i=listCount-1; i>=0; i--)
   {
-    nsIDOMNode* testNode = arrayOfNodes[i];
+    OwningNonNull<nsINode> testNode = arrayOfNodes[i];
     NS_ENSURE_STATE(mHTMLEditor);
     if (!mHTMLEditor->IsEditable(testNode))
     {
-      arrayOfNodes.RemoveObjectAt(i);
+      arrayOfNodes.RemoveElementAt(i);
     }
   }
   
   // reset list count
-  listCount = arrayOfNodes.Count();
+  listCount = arrayOfNodes.Length();
   
   // Only act on lists or list items in the array
-  nsCOMPtr<nsIDOMNode> curParent;
-  for (i=0; i<listCount; i++)
-  {
+  for (auto& curNode : arrayOfNodes) {
     // here's where we actually figure out what to do
-    nsIDOMNode* curNode = arrayOfNodes[i];
-    int32_t offset;
-    curParent = nsEditor::GetNodeLocation(curNode, &offset);
-    
     if (nsHTMLEditUtils::IsListItem(curNode))  // unlist this listitem
     {
       bool bOutOfList;
       do
       {
-        res = PopListItem(curNode, &bOutOfList);
+        res = PopListItem(GetAsDOMNode(curNode), &bOutOfList);
         NS_ENSURE_SUCCESS(res, res);
       } while (!bOutOfList); // keep popping it out until it's not in a list anymore
     }
     else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, move list items out
     {
-      res = RemoveListStructure(curNode);
+      res = RemoveListStructure(GetAsDOMNode(curNode));
       NS_ENSURE_SUCCESS(res, res);
     }
   }
   return res;
 }
 
 
 nsresult
@@ -3463,35 +3407,34 @@ nsHTMLEditRules::WillMakeBasicBlock(Sele
   NS_ENSURE_STATE(mHTMLEditor);
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
   NS_ENSURE_STATE(mHTMLEditor);
   nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
   *aHandled = true;
   nsString tString(*aBlockType);
 
   // contruct a list of nodes to act on.
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  res = GetNodesFromSelection(aSelection, EditAction::makeBasicBlock,
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+  res = GetNodesFromSelection(*aSelection, EditAction::makeBasicBlock,
                               arrayOfNodes);
   NS_ENSURE_SUCCESS(res, res);
 
   // Remove all non-editable nodes.  Leave them be.
-  int32_t listCount = arrayOfNodes.Count();
+  int32_t listCount = arrayOfNodes.Length();
   int32_t i;
   for (i=listCount-1; i>=0; i--)
   {
     NS_ENSURE_STATE(mHTMLEditor);
-    if (!mHTMLEditor->IsEditable(arrayOfNodes[i]))
-    {
-      arrayOfNodes.RemoveObjectAt(i);
-    }
-  }
-  
+    if (!mHTMLEditor->IsEditable(arrayOfNodes[i])) {
+      arrayOfNodes.RemoveElementAt(i);
+    }
+  }
+
   // reset list count
-  listCount = arrayOfNodes.Count();
+  listCount = arrayOfNodes.Length();
   
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes))
   {
     nsCOMPtr<nsIDOMNode> theBlock;
     
     // get selection location
     NS_ENSURE_STATE(aSelection->RangeCount());
@@ -3539,66 +3482,64 @@ nsHTMLEditRules::WillMakeBasicBlock(Sele
         selectionResetter.Abort();  // to prevent selection reseter from overriding us.
         *aHandled = true;
       }
       // else nothing to do!
     }
     else  // we are making a block
     {   
       // consume a br, if needed
-      nsCOMPtr<nsIDOMNode> brNode;
       NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->GetNextHTMLNode(parent->AsDOMNode(), offset,
-                                         address_of(brNode), true);
+      nsCOMPtr<nsIContent> brNode =
+        mHTMLEditor->GetNextHTMLNode(parent, offset, true);
       NS_ENSURE_SUCCESS(res, res);
       if (brNode && nsTextEditUtils::IsBreak(brNode))
       {
         NS_ENSURE_STATE(mHTMLEditor);
         res = mHTMLEditor->DeleteNode(brNode);
         NS_ENSURE_SUCCESS(res, res);
         // we don't need to act on this node any more
-        arrayOfNodes.RemoveObject(brNode);
+        arrayOfNodes.RemoveElement(brNode);
       }
       // make sure we can put a block here
       res = SplitAsNeeded(blockType, parent, offset);
       NS_ENSURE_SUCCESS(res, res);
       NS_ENSURE_STATE(mHTMLEditor);
       theBlock = dont_AddRef(GetAsDOMNode(
         mHTMLEditor->CreateNode(blockType, parent, offset).take()));
       NS_ENSURE_STATE(theBlock);
       // remember our new block for postprocessing
       mNewBlock = theBlock;
       // delete anything that was in the list of nodes
-      for (int32_t j = arrayOfNodes.Count() - 1; j >= 0; --j) 
-      {
-        nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
+      while (!arrayOfNodes.IsEmpty()) {
+        OwningNonNull<nsINode> curNode = arrayOfNodes[0];
         NS_ENSURE_STATE(mHTMLEditor);
         res = mHTMLEditor->DeleteNode(curNode);
         NS_ENSURE_SUCCESS(res, res);
-        arrayOfNodes.RemoveObjectAt(0);
+        arrayOfNodes.RemoveElementAt(0);
       }
       // put selection in new block
       res = aSelection->Collapse(theBlock,0);
       selectionResetter.Abort();  // to prevent selection reseter from overriding us.
       *aHandled = true;
     }
     return res;    
   }
   else
   {
     // Ok, now go through all the nodes and make the right kind of blocks, 
     // or whatever is approriate.  Wohoo! 
     // Note: blockquote is handled a little differently
-    if (tString.EqualsLiteral("blockquote"))
+    if (tString.EqualsLiteral("blockquote")) {
       res = MakeBlockquote(arrayOfNodes);
-    else if (tString.EqualsLiteral("normal") ||
-             tString.IsEmpty() )
+    } else if (tString.EqualsLiteral("normal") || tString.IsEmpty()) {
       res = RemoveBlockStyle(arrayOfNodes);
-    else
-      res = ApplyBlockStyle(arrayOfNodes, aBlockType);
+    } else {
+      res = ApplyBlockStyle(arrayOfNodes, *blockType);
+    }
     return res;
   }
   return res;
 }
 
 nsresult 
 nsHTMLEditRules::DidMakeBasicBlock(Selection* aSelection,
                                    nsRulesInfo *aInfo, nsresult aResult)
@@ -3645,53 +3586,54 @@ nsHTMLEditRules::WillCSSIndent(Selection
   // we want to ignore result of WillInsert()
   *aCancel = false;
   *aHandled = true;
 
   res = NormalizeSelection(aSelection);
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_STATE(mHTMLEditor);
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
-  nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
+  nsTArray<OwningNonNull<nsRange>> arrayOfRanges;
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
   
   // short circuit: detect case of collapsed selection inside an <li>.
   // just sublist that <li>.  This prevents bug 97797.
   
-  nsCOMPtr<nsIDOMNode> liNode;
+  nsCOMPtr<Element> liNode;
   if (aSelection->Collapsed()) {
-    nsCOMPtr<nsIDOMNode> node, block;
+    nsCOMPtr<nsINode> node;
+    nsCOMPtr<Element> block;
     int32_t offset;
     NS_ENSURE_STATE(mHTMLEditor);
     nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
     NS_ENSURE_SUCCESS(res, res);
-    if (IsBlockNode(node)) {
-      block = node;
+    if (IsBlockNode(GetAsDOMNode(node))) {
+      block = node->AsElement();
     } else {
       NS_ENSURE_STATE(mHTMLEditor);
       block = mHTMLEditor->GetBlockNodeParent(node);
     }
     if (block && nsHTMLEditUtils::IsListItem(block))
       liNode = block;
   }
   
   if (liNode)
   {
-    arrayOfNodes.AppendObject(liNode);
+    arrayOfNodes.AppendElement(*liNode);
   }
   else
   {
     // convert the selection ranges into "promoted" selection ranges:
     // this basically just expands the range to include the immediate
     // block parent, and then further expands to include any ancestors
     // whose children are all in the range
-    res = GetNodesFromSelection(aSelection, EditAction::indent, arrayOfNodes);
+    res = GetNodesFromSelection(*aSelection, EditAction::indent, arrayOfNodes);
     NS_ENSURE_SUCCESS(res, res);
   }
-  
+
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes))
   {
     // get selection location
     NS_ENSURE_STATE(aSelection->RangeCount());
     nsCOMPtr<nsINode> parent = aSelection->GetRangeAt(0)->GetStartParent();
     int32_t offset = aSelection->GetRangeAt(0)->StartOffset();
     NS_ENSURE_STATE(parent);
@@ -3702,43 +3644,42 @@ nsHTMLEditRules::WillCSSIndent(Selection
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<Element> theBlock = mHTMLEditor->CreateNode(nsGkAtoms::div,
                                                          parent, offset);
     NS_ENSURE_STATE(theBlock);
     // remember our new block for postprocessing
     mNewBlock = theBlock->AsDOMNode();
     RelativeChangeIndentationOfElementNode(theBlock->AsDOMNode(), +1);
     // delete anything that was in the list of nodes
-    for (int32_t j = arrayOfNodes.Count() - 1; j >= 0; --j) 
-    {
-      nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
+    while (!arrayOfNodes.IsEmpty()) {
+      OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->DeleteNode(curNode);
       NS_ENSURE_SUCCESS(res, res);
-      arrayOfNodes.RemoveObjectAt(0);
+      arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     res = aSelection->Collapse(theBlock,0);
     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
     *aHandled = true;
     return res;
   }
   
   // Ok, now go through all the nodes and put them in a blockquote, 
   // or whatever is appropriate.  Wohoo!
   int32_t i;
   nsCOMPtr<nsINode> curParent;
   nsCOMPtr<Element> curList, curQuote;
   nsCOMPtr<nsIContent> sibling;
-  int32_t listCount = arrayOfNodes.Count();
+  int32_t listCount = arrayOfNodes.Length();
   for (i=0; i<listCount; i++)
   {
     // here's where we actually figure out what to do
-    nsCOMPtr<nsIContent> curNode = do_QueryInterface(arrayOfNodes[i]);
-    NS_ENSURE_STATE(!arrayOfNodes[i] || curNode);
+    NS_ENSURE_STATE(arrayOfNodes[i]->IsContent());
+    nsCOMPtr<nsIContent> curNode = arrayOfNodes[i]->AsContent();
 
     // Ignore all non-editable nodes.  Leave them be.
     NS_ENSURE_STATE(mHTMLEditor);
     if (!mHTMLEditor->IsEditable(curNode)) continue;
 
     curParent = curNode->GetParentNode();
     int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
     
@@ -3862,21 +3803,20 @@ nsHTMLEditRules::WillHTMLIndent(Selectio
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
   
   // convert the selection ranges into "promoted" selection ranges:
   // this basically just expands the range to include the immediate
   // block parent, and then further expands to include any ancestors
   // whose children are all in the range
   
   nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-  res = GetPromotedRanges(aSelection, arrayOfRanges, EditAction::indent);
-  NS_ENSURE_SUCCESS(res, res);
+  GetPromotedRanges(*aSelection, arrayOfRanges, EditAction::indent);
   
   // use these ranges to contruct a list of nodes to act on.
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
   res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::indent);
   NS_ENSURE_SUCCESS(res, res);                                 
                                      
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes))
   {
     // get selection location
     NS_ENSURE_STATE(aSelection->RangeCount());
@@ -3889,43 +3829,42 @@ nsHTMLEditRules::WillHTMLIndent(Selectio
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<Element> theBlock = mHTMLEditor->CreateNode(nsGkAtoms::blockquote,
                                                          parent, offset);
     NS_ENSURE_STATE(theBlock);
     // remember our new block for postprocessing
     mNewBlock = theBlock->AsDOMNode();
     // delete anything that was in the list of nodes
-    for (int32_t j = arrayOfNodes.Count() - 1; j >= 0; --j) 
-    {
-      nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
+    while (!arrayOfNodes.IsEmpty()) {
+      OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->DeleteNode(curNode);
       NS_ENSURE_SUCCESS(res, res);
-      arrayOfNodes.RemoveObjectAt(0);
+      arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     res = aSelection->Collapse(theBlock,0);
     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
     *aHandled = true;
     return res;
   }
 
   // Ok, now go through all the nodes and put them in a blockquote, 
   // or whatever is appropriate.  Wohoo!
   int32_t i;
   nsCOMPtr<nsINode> curParent;
   nsCOMPtr<nsIContent> sibling;
   nsCOMPtr<Element> curList, curQuote, indentedLI;
-  int32_t listCount = arrayOfNodes.Count();
+  int32_t listCount = arrayOfNodes.Length();
   for (i=0; i<listCount; i++)
   {
     // here's where we actually figure out what to do
-    nsCOMPtr<nsIContent> curNode = do_QueryInterface(arrayOfNodes[i]);
-    NS_ENSURE_STATE(!arrayOfNodes[i] || curNode);
+    NS_ENSURE_STATE(arrayOfNodes[i]->IsContent());
+    nsCOMPtr<nsIContent> curNode = arrayOfNodes[i]->AsContent();
 
     // Ignore all non-editable nodes.  Leave them be.
     NS_ENSURE_STATE(mHTMLEditor);
     if (!mHTMLEditor->IsEditable(curNode)) continue;
 
     curParent = curNode->GetParentNode();
     int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
      
@@ -4096,74 +4035,68 @@ nsHTMLEditRules::WillOutdent(Selection* 
   {
     NS_ENSURE_STATE(mHTMLEditor);
     nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
     
     // convert the selection ranges into "promoted" selection ranges:
     // this basically just expands the range to include the immediate
     // block parent, and then further expands to include any ancestors
     // whose children are all in the range
-    nsCOMArray<nsIDOMNode> arrayOfNodes;
-    res = GetNodesFromSelection(aSelection, EditAction::outdent,
+    nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+    res = GetNodesFromSelection(*aSelection, EditAction::outdent,
                                 arrayOfNodes);
     NS_ENSURE_SUCCESS(res, res);
 
     // Ok, now go through all the nodes and remove a level of blockquoting, 
     // or whatever is appropriate.  Wohoo!
 
     nsCOMPtr<nsIDOMNode> curBlockQuote, firstBQChild, lastBQChild;
     bool curBlockQuoteIsIndentedWithCSS = false;
-    int32_t listCount = arrayOfNodes.Count();
-    int32_t i;
-    for (i=0; i<listCount; i++)
-    {
+    for (auto& curNode : arrayOfNodes) {
       // here's where we actually figure out what to do
-      nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
-      nsCOMPtr<nsINode> curNode_ = do_QueryInterface(curNode);
-      NS_ENSURE_STATE(curNode_);
-      nsCOMPtr<nsINode> curParent = curNode_->GetParentNode();
-      int32_t offset = curParent ? curParent->IndexOf(curNode_) : -1;
+      nsCOMPtr<nsINode> curParent = curNode->GetParentNode();
+      int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
       
       // is it a blockquote?
-      if (nsHTMLEditUtils::IsBlockquote(curNode)) 
-      {
+      if (curNode->IsHTMLElement(nsGkAtoms::blockquote)) {
         // if it is a blockquote, remove it.
         // So we need to finish up dealng with any curBlockQuote first.
         if (curBlockQuote)
         {
           res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
                                    curBlockQuoteIsIndentedWithCSS,
                                    address_of(rememberedLeftBQ),
                                    address_of(rememberedRightBQ));
           NS_ENSURE_SUCCESS(res, res);
           curBlockQuote = 0;  firstBQChild = 0;  lastBQChild = 0;
           curBlockQuoteIsIndentedWithCSS = false;
         }
         NS_ENSURE_STATE(mHTMLEditor);
-        res = mHTMLEditor->RemoveBlockContainer(curNode);
+        res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(curNode));
         NS_ENSURE_SUCCESS(res, res);
         continue;
       }
       // is it a block with a 'margin' property?
-      if (useCSS && IsBlockNode(curNode))
-      {
+      if (useCSS && IsBlockNode(GetAsDOMNode(curNode))) {
         NS_ENSURE_STATE(mHTMLEditor);
-        nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode);
+        nsIAtom* marginProperty =
+          MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils,
+                                      GetAsDOMNode(curNode));
         nsAutoString value;
         NS_ENSURE_STATE(mHTMLEditor);
-        mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*curNode_,
+        mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*curNode,
                                                          *marginProperty,
                                                          value);
         float f;
         nsCOMPtr<nsIAtom> unit;
         NS_ENSURE_STATE(mHTMLEditor);
         mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
         if (f > 0)
         {
-          RelativeChangeIndentationOfElementNode(curNode, -1);
+          RelativeChangeIndentationOfElementNode(GetAsDOMNode(curNode), -1);
           continue;
         }
       }
       // is it a list item?
       if (nsHTMLEditUtils::IsListItem(curNode)) 
       {
         // if it is a list item, that means we are not outdenting whole list.
         // So we need to finish up dealing with any curBlockQuote, and then
@@ -4174,27 +4107,27 @@ nsHTMLEditRules::WillOutdent(Selection* 
                                    curBlockQuoteIsIndentedWithCSS,
                                    address_of(rememberedLeftBQ),
                                    address_of(rememberedRightBQ));
           NS_ENSURE_SUCCESS(res, res);
           curBlockQuote = 0;  firstBQChild = 0;  lastBQChild = 0;
           curBlockQuoteIsIndentedWithCSS = false;
         }
         bool bOutOfList;
-        res = PopListItem(curNode, &bOutOfList);
+        res = PopListItem(GetAsDOMNode(curNode), &bOutOfList);
         NS_ENSURE_SUCCESS(res, res);
         continue;
       }
       // do we have a blockquote that we are already committed to removing?
       if (curBlockQuote)
       {
         // if so, is this node a descendant?
-        if (nsEditorUtils::IsDescendantOf(curNode, curBlockQuote))
-        {
-          lastBQChild = curNode;
+        if (nsEditorUtils::IsDescendantOf(GetAsDOMNode(curNode),
+                                          curBlockQuote)) {
+          lastBQChild = GetAsDOMNode(curNode);
           continue;  // then we don't need to do anything different for this node
         }
         else
         {
           // otherwise, we have progressed beyond end of curBlockQuote,
           // so lets handle it now.  We need to remove the portion of 
           // curBlockQuote that contains [firstBQChild - lastBQChild].
           res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
@@ -4204,77 +4137,76 @@ nsHTMLEditRules::WillOutdent(Selection* 
           NS_ENSURE_SUCCESS(res, res);
           curBlockQuote = 0;  firstBQChild = 0;  lastBQChild = 0;
           curBlockQuoteIsIndentedWithCSS = false;
           // fall out and handle curNode
         }
       }
       
       // are we inside a blockquote?
-      nsCOMPtr<nsINode> n = curNode_;
+      nsCOMPtr<nsINode> n = curNode;
       curBlockQuoteIsIndentedWithCSS = false;
       // keep looking up the hierarchy as long as we don't hit the body or the
       // active editing host or a table element (other than an entire table)
       while (!n->IsHTMLElement(nsGkAtoms::body) && mHTMLEditor &&
              mHTMLEditor->IsDescendantOfEditorRoot(n) &&
              (n->IsHTMLElement(nsGkAtoms::table) ||
               !nsHTMLEditUtils::IsTableElement(n))) {
         if (!n->GetParentNode()) {
           break;
         }
         n = n->GetParentNode();
         if (n->IsHTMLElement(nsGkAtoms::blockquote)) {
           // if so, remember it, and remember first node we are taking out of it.
           curBlockQuote = GetAsDOMNode(n);
-          firstBQChild  = curNode;
-          lastBQChild   = curNode;
+          firstBQChild  = GetAsDOMNode(curNode);
+          lastBQChild   = GetAsDOMNode(curNode);
           break;
         }
         else if (useCSS)
         {
           NS_ENSURE_STATE(mHTMLEditor);
-          nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode);
+          nsIAtom* marginProperty =
+            MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils,
+                                        GetAsDOMNode(curNode));
           nsAutoString value;
           NS_ENSURE_STATE(mHTMLEditor);
           mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*n, *marginProperty,
                                                            value);
           float f;
           nsCOMPtr<nsIAtom> unit;
           NS_ENSURE_STATE(mHTMLEditor);
           mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
           if (f > 0 && !(nsHTMLEditUtils::IsList(curParent) && nsHTMLEditUtils::IsList(curNode)))
           {
             curBlockQuote = GetAsDOMNode(n);
-            firstBQChild  = curNode;
-            lastBQChild   = curNode;
+            firstBQChild  = GetAsDOMNode(curNode);
+            lastBQChild   = GetAsDOMNode(curNode);
             curBlockQuoteIsIndentedWithCSS = true;
             break;
           }
         }
       }
 
       if (!curBlockQuote)
       {
         // could not find an enclosing blockquote for this node.  handle list cases.
         if (nsHTMLEditUtils::IsList(curParent))  // move node out of list
         {
           if (nsHTMLEditUtils::IsList(curNode))  // just unwrap this sublist
           {
             NS_ENSURE_STATE(mHTMLEditor);
-            res = mHTMLEditor->RemoveBlockContainer(curNode);
+            res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(curNode));
             NS_ENSURE_SUCCESS(res, res);
           }
           // handled list item case above
         }
         else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out
         {
-          nsCOMPtr<nsIDOMNode> childDOM;
-          curNode->GetLastChild(getter_AddRefs(childDOM));
-          nsCOMPtr<nsIContent> child = do_QueryInterface(childDOM);
-          NS_ENSURE_STATE(!childDOM || child);
+          nsCOMPtr<nsIContent> child = curNode->GetLastChild();
           while (child)
           {
             if (nsHTMLEditUtils::IsListItem(child))
             {
               bool bOutOfList;
               res = PopListItem(GetAsDOMNode(child), &bOutOfList);
               NS_ENSURE_SUCCESS(res, res);
             }
@@ -4291,23 +4223,21 @@ nsHTMLEditRules::WillOutdent(Selection* 
             }
             else
             {
               // delete any non- list items for now
               NS_ENSURE_STATE(mHTMLEditor);
               res = mHTMLEditor->DeleteNode(child);
               NS_ENSURE_SUCCESS(res, res);
             }
-            curNode->GetLastChild(getter_AddRefs(childDOM));
-            child = do_QueryInterface(childDOM);
-            NS_ENSURE_STATE(!childDOM || child);
+            child = curNode->GetLastChild();
           }
           // delete the now-empty list
           NS_ENSURE_STATE(mHTMLEditor);
-          res = mHTMLEditor->RemoveBlockContainer(curNode);
+          res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(curNode));
           NS_ENSURE_SUCCESS(res, res);
         }
         else if (useCSS) {
           nsCOMPtr<nsIDOMElement> element;
           nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(curNode);
           if (textNode) {
             // We want to outdent the parent of text nodes
             nsCOMPtr<nsIDOMNode> parent;
@@ -4361,38 +4291,31 @@ nsHTMLEditRules::WillOutdent(Selection* 
       }
     }
     return NS_OK;
   }
   return res;
 }
 
 
-///////////////////////////////////////////////////////////////////////////
-// RemovePartOfBlock:  split aBlock and move aStartChild to aEndChild out
-//                     of aBlock.  return left side of block (if any) in
-//                     aLeftNode.  return right side of block (if any) in
-//                     aRightNode.  
-//                  
-nsresult 
-nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock, 
-                                   nsIDOMNode *aStartChild, 
-                                   nsIDOMNode *aEndChild,
-                                   nsCOMPtr<nsIDOMNode> *aLeftNode,
-                                   nsCOMPtr<nsIDOMNode> *aRightNode)
-{
-  nsCOMPtr<nsIDOMNode> middleNode;
-  nsresult res = SplitBlock(aBlock, aStartChild, aEndChild,
-                            aLeftNode, aRightNode,
-                            address_of(middleNode));
+///////////////////////////////////////////////////////////////////////////////
+// RemovePartOfBlock: Split aBlock and move aStartChild to aEndChild out of
+//                    aBlock.
+nsresult
+nsHTMLEditRules::RemovePartOfBlock(Element& aBlock,
+                                   nsIContent& aStartChild,
+                                   nsIContent& aEndChild)
+{
+  nsresult res = SplitBlock(aBlock.AsDOMNode(), aStartChild.AsDOMNode(),
+                            aEndChild.AsDOMNode());
   NS_ENSURE_SUCCESS(res, res);
-  // get rid of part of blockquote we are outdenting
+  // Get rid of part of blockquote we are outdenting
 
   NS_ENSURE_STATE(mHTMLEditor);
-  return mHTMLEditor->RemoveBlockContainer(aBlock);
+  return mHTMLEditor->RemoveBlockContainer(aBlock.AsDOMNode());
 }
 
 nsresult 
 nsHTMLEditRules::SplitBlock(nsIDOMNode *aBlock, 
                             nsIDOMNode *aStartChild, 
                             nsIDOMNode *aEndChild,
                             nsCOMPtr<nsIDOMNode> *aLeftNode,
                             nsCOMPtr<nsIDOMNode> *aRightNode,
@@ -4635,18 +4558,20 @@ nsHTMLEditRules::CreateStyleForInsertTex
         res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, nodeAsText,
                                                         0, -1);
         NS_ENSURE_SUCCESS(res, res);
       }
     }
 
     while (item) {
       NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr,
-                                                 &item->value);
+      nsCOMPtr<nsIContent> content = do_QueryInterface(node);
+      NS_ENSURE_STATE(content || !node);
+      res = mHTMLEditor->SetInlinePropertyOnNode(*content, *item->tag,
+                                                 &item->attr, item->value);
       NS_ENSURE_SUCCESS(res, res);
       item = mHTMLEditor->mTypeInState->TakeSetProperty();
     }
   }
   if (weDidSomething) {
     return aSelection->Collapse(node, offset);
   }
 
@@ -4700,31 +4625,30 @@ nsHTMLEditRules::WillAlign(Selection* aS
   NS_ENSURE_SUCCESS(res, res);
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
 
   // convert the selection ranges into "promoted" selection ranges:
   // this basically just expands the range to include the immediate
   // block parent, and then further expands to include any ancestors
   // whose children are all in the range
   *aHandled = true;
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  res = GetNodesFromSelection(aSelection, EditAction::align, arrayOfNodes);
+  nsTArray<OwningNonNull<nsINode>> nodeArray;
+  res = GetNodesFromSelection(*aSelection, EditAction::align, nodeArray);
   NS_ENSURE_SUCCESS(res, res);
 
   // if we don't have any nodes, or we have only a single br, then we are
   // creating an empty alignment div.  We have to do some different things for these.
   bool emptyDiv = false;
-  int32_t listCount = arrayOfNodes.Count();
+  int32_t listCount = nodeArray.Length();
   if (!listCount) emptyDiv = true;
   if (listCount == 1)
   {
-    nsCOMPtr<nsIDOMNode> theNode = arrayOfNodes[0];
-
-    if (nsHTMLEditUtils::SupportsAlignAttr(theNode))
-    {
+    OwningNonNull<nsINode> theNode = nodeArray[0];
+
+    if (nsHTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(theNode))) {
       // the node is a table element, an horiz rule, a paragraph, a div
       // or a section header; in HTML 4, it can directly carry the ALIGN
       // attribute and we don't need to make a div! If we are in CSS mode,
       // all the work is done in AlignBlock
       nsCOMPtr<nsIDOMElement> theElem = do_QueryInterface(theNode);
       res = AlignBlock(theElem, alignType, true);
       NS_ENSURE_SUCCESS(res, res);
       return NS_OK;
@@ -4735,19 +4659,19 @@ nsHTMLEditRules::WillAlign(Selection* aS
       // The special case emptyDiv code (below) that consumes BRs can
       // cause tables to split if the start node of the selection is
       // not in a table cell or caption, for example parent is a <tr>.
       // Avoid this unnecessary splitting if possible by leaving emptyDiv
       // FALSE so that we fall through to the normal case alignment code.
       //
       // XXX: It seems a little error prone for the emptyDiv special
       //      case code to assume that the start node of the selection
-      //      is the parent of the single node in the arrayOfNodes, as
+      //      is the parent of the single node in the nodeArray, as
       //      the paragraph above points out. Do we rely on the selection
-      //      start node because of the fact that arrayOfNodes can be empty?
+      //      start node because of the fact that nodeArray can be empty?
       //      We should probably revisit this issue. - kin
 
       nsCOMPtr<nsIDOMNode> parent;
       int32_t offset;
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
 
       if (!nsHTMLEditUtils::IsTableElement(parent) || nsHTMLEditUtils::IsTableCellOrCaption(parent))
@@ -4806,28 +4730,27 @@ nsHTMLEditRules::WillAlign(Selection* aS
     selectionResetter.Abort();  // don't reset our selection in this case.
     return res;
   }
 
   // Next we detect all the transitions in the array, where a transition
   // means that adjacent nodes in the array don't have the same parent.
 
   nsTArray<bool> transitionList;
-  res = MakeTransitionList(arrayOfNodes, transitionList);
-  NS_ENSURE_SUCCESS(res, res);                                 
+  MakeTransitionList(nodeArray, transitionList);
 
   // Ok, now go through all the nodes and give them an align attrib or put them in a div, 
   // or whatever is appropriate.  Wohoo!
 
   nsCOMPtr<nsINode> curParent;
   nsCOMPtr<Element> curDiv;
   bool useCSS = mHTMLEditor->IsCSSEnabled();
   for (int32_t i = 0; i < listCount; ++i) {
     // here's where we actually figure out what to do
-    nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
+    nsCOMPtr<nsIDOMNode> curNode = nodeArray[i]->AsDOMNode();
     nsCOMPtr<nsIContent> curContent = do_QueryInterface(curNode);
     NS_ENSURE_STATE(curContent);
 
     // Ignore all non-editable nodes.  Leave them be.
     if (!mHTMLEditor->IsEditable(curNode)) continue;
 
     curParent = curContent->GetParentNode();
     int32_t offset = curParent ? curParent->IndexOf(curContent) : -1;
@@ -4872,17 +4795,17 @@ nsHTMLEditRules::WillAlign(Selection* aS
                                                                 &attrName, alignType,
                                                                 &count, false);
         curDiv = 0;
         continue;
       }
       else if (nsHTMLEditUtils::IsList(curParent)) {
         // if we don't use CSS, add a contraint to list element : they have
         // to be inside another list, ie >= second level of nesting
-        res = AlignInnerBlocks(curNode, alignType);
+        res = AlignInnerBlocks(*curContent, alignType);
         NS_ENSURE_SUCCESS(res, res);
         curDiv = 0;
         continue;
       }
       // clear out curDiv so that we don't put nodes after this one into it
     }      
 
     // need to make a div to put things in if we haven't already,
@@ -4915,47 +4838,37 @@ nsHTMLEditRules::WillAlign(Selection* aS
     res = mHTMLEditor->MoveNode(curContent, curDiv, -1);
     NS_ENSURE_SUCCESS(res, res);
   }
 
   return res;
 }
 
 
-///////////////////////////////////////////////////////////////////////////
-// AlignInnerBlocks: align inside table cells or list items
-//       
+///////////////////////////////////////////////////////////////////////////////
+// AlignInnerBlocks: Align inside table cells or list items
+//
 nsresult
-nsHTMLEditRules::AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType)
-{
-  NS_ENSURE_TRUE(aNode && alignType, NS_ERROR_NULL_POINTER);
-  nsresult res;
-  
-  // gather list of table cells or list items
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
+nsHTMLEditRules::AlignInnerBlocks(nsINode& aNode, const nsAString* alignType)
+{
+  NS_ENSURE_TRUE(alignType, NS_ERROR_NULL_POINTER);
+
+  // Gather list of table cells or list items
+  nsTArray<OwningNonNull<nsINode>> nodeArray;
   nsTableCellAndListItemFunctor functor;
-  nsDOMIterator iter;
-  res = iter.Init(aNode);
-  NS_ENSURE_SUCCESS(res, res);
-  res = iter.AppendList(functor, arrayOfNodes);
-  NS_ENSURE_SUCCESS(res, res);
-  
-  // now that we have the list, align their contents as requested
-  int32_t listCount = arrayOfNodes.Count();
-  int32_t j;
-
-  for (j = 0; j < listCount; j++)
-  {
-    nsIDOMNode* node = arrayOfNodes[0];
-    res = AlignBlockContents(node, alignType);
+  nsDOMIterator iter(aNode);
+  iter.AppendList(functor, nodeArray);
+
+  // Now that we have the list, align their contents as requested
+  for (auto& node : nodeArray) {
+    nsresult res = AlignBlockContents(node->AsDOMNode(), alignType);
     NS_ENSURE_SUCCESS(res, res);
-    arrayOfNodes.RemoveObjectAt(0);
-  }
-
-  return res;  
+  }
+
+  return NS_OK;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
 // AlignBlockContents: align contents of a block element
 //                  
 nsresult
 nsHTMLEditRules::AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType)
@@ -5153,54 +5066,42 @@ nsHTMLEditRules::CheckForInvisibleBR(nsI
       *outBRNode = GetAsDOMNode(wsTester.mStartReasonNode);
     }
   }
 
   return NS_OK;
 }
 
 
-///////////////////////////////////////////////////////////////////////////
-// GetInnerContent: aList and aTbl allow the caller to specify what kind 
-//                  of content to "look inside".  If aTbl is true, look inside
-//                  any table content, and insert the inner content into the
-//                  supplied issupportsarray at offset aIndex.  
-//                  Similarly with aList and list content.
-//                  aIndex is updated to point past inserted elements.
-//                  
-nsresult
-nsHTMLEditRules::GetInnerContent(nsIDOMNode *aNode, nsCOMArray<nsIDOMNode> &outArrayOfNodes, 
-                                 int32_t *aIndex, bool aList, bool aTbl)
-{
-  nsCOMPtr<nsINode> aNode_ = do_QueryInterface(aNode);
-  NS_ENSURE_TRUE(aNode_ && aIndex, NS_ERROR_NULL_POINTER);
-
-  nsCOMPtr<nsIDOMNode> node =
-    GetAsDOMNode(mHTMLEditor->GetFirstEditableChild(*aNode_));
-  nsresult res = NS_OK;
-  while (NS_SUCCEEDED(res) && node)
-  {
-    if (  ( aList && (nsHTMLEditUtils::IsList(node)     || 
-                      nsHTMLEditUtils::IsListItem(node) ) )
-       || ( aTbl && nsHTMLEditUtils::IsTableElement(node) )  )
-    {
-      res = GetInnerContent(node, outArrayOfNodes, aIndex, aList, aTbl);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-    else
-    {
-      outArrayOfNodes.InsertObjectAt(node, *aIndex);
+////////////////////////////////////////////////////////////////////////////////
+// GetInnerContent: aLists and aTables allow the caller to specify what kind of
+//                  content to "look inside".  If aTables is Tables::yes, look
+//                  inside any table content, and insert the inner content into
+//                  the supplied issupportsarray at offset aIndex.  Similarly
+//                  with aLists and list content.  aIndex is updated to point
+//                  past inserted elements.
+//
+void
+nsHTMLEditRules::GetInnerContent(nsINode& aNode,
+                                 nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
+                                 int32_t* aIndex, Lists aLists, Tables aTables)
+{
+  MOZ_ASSERT(aIndex);
+
+  for (nsCOMPtr<nsIContent> node = mHTMLEditor->GetFirstEditableChild(aNode);
+       node; node = node->GetNextSibling()) {
+    if ((aLists == Lists::yes && (nsHTMLEditUtils::IsList(node) ||
+                                  nsHTMLEditUtils::IsListItem(node))) ||
+        (aTables == Tables::yes && nsHTMLEditUtils::IsTableElement(node))) {
+      GetInnerContent(*node, aOutArrayOfNodes, aIndex, aLists, aTables);
+    } else {
+      aOutArrayOfNodes.InsertElementAt(*aIndex, *node);
       (*aIndex)++;
     }
-    nsCOMPtr<nsIDOMNode> tmp;
-    res = node->GetNextSibling(getter_AddRefs(tmp));
-    node = tmp;
-  }
-
-  return res;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // ExpandSelectionForDeletion: this promotes our selection to include blocks
 // that have all their children selected.
 //                  
 nsresult
 nsHTMLEditRules::ExpandSelectionForDeletion(Selection* aSelection)
@@ -5713,491 +5614,384 @@ nsHTMLEditRules::GetPromotedPoint(RulesE
     NS_ENSURE_TRUE(mHTMLEditor, /* void */);
     nearNode = mHTMLEditor->GetNextHTMLNode(node, offset, true);
   }
   *outNode = node->AsDOMNode();
   *outOffset = offset;
 }
 
 
-///////////////////////////////////////////////////////////////////////////
-// GetPromotedRanges: run all the selection range endpoint through 
+///////////////////////////////////////////////////////////////////////////////
+// GetPromotedRanges: Run all the selection range endpoint through
 //                    GetPromotedPoint()
-//                       
-nsresult 
-nsHTMLEditRules::GetPromotedRanges(Selection* inSelection, 
-                                   nsTArray<nsRefPtr<nsRange>>& outArrayOfRanges, 
+//
+void
+nsHTMLEditRules::GetPromotedRanges(Selection& aSelection,
+                                   nsTArray<nsRefPtr<nsRange>>& outArrayOfRanges,
                                    EditAction inOperationType)
 {
-  NS_ENSURE_TRUE(inSelection, NS_ERROR_NULL_POINTER);
-
-  int32_t rangeCount;
-  nsresult res = inSelection->GetRangeCount(&rangeCount);
-  NS_ENSURE_SUCCESS(res, res);
-  
-  int32_t i;
-  nsRefPtr<nsRange> selectionRange;
-  nsRefPtr<nsRange> opRange;
-
-  for (i = 0; i < rangeCount; i++)
-  {
-    selectionRange = inSelection->GetRangeAt(i);
-    NS_ENSURE_STATE(selectionRange);
-
-    // clone range so we don't muck with actual selection ranges
-    opRange = selectionRange->CloneRange();
-
-    // make a new adjusted range to represent the appropriate block content.
-    // The basic idea is to push out the range endpoints
-    // to truly enclose the blocks that we will affect.
-    // This call alters opRange.
-    res = PromoteRange(opRange, inOperationType);
-    NS_ENSURE_SUCCESS(res, res);
-      
-    // stuff new opRange into array
+  uint32_t rangeCount = aSelection.RangeCount();
+
+  for (uint32_t i = 0; i < rangeCount; i++) {
+    nsRefPtr<nsRange> selectionRange = aSelection.GetRangeAt(i);
+    MOZ_ASSERT(selectionRange);
+
+    // Clone range so we don't muck with actual selection ranges
+    nsRefPtr<nsRange> opRange = selectionRange->CloneRange();
+
+    // Make a new adjusted range to represent the appropriate block content.
+    // The basic idea is to push out the range endpoints to truly enclose the
+    // blocks that we will affect.  This call alters opRange.
+    PromoteRange(*opRange, inOperationType);
+
+    // Stuff new opRange into array
     outArrayOfRanges.AppendElement(opRange);
   }
-  return res;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// PromoteRange: expand a range to include any parents for which all
-//               editable children are already in range. 
-//                       
-nsresult 
-nsHTMLEditRules::PromoteRange(nsRange* inRange, EditAction inOperationType)
-{
-  NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
-  nsresult res;
-  nsCOMPtr<nsIDOMNode> startNode, endNode;
-  int32_t startOffset, endOffset;
-  
-  res = inRange->GetStartContainer(getter_AddRefs(startNode));
-  NS_ENSURE_SUCCESS(res, res);
-  res = inRange->GetStartOffset(&startOffset);
-  NS_ENSURE_SUCCESS(res, res);
-  res = inRange->GetEndContainer(getter_AddRefs(endNode));
-  NS_ENSURE_SUCCESS(res, res);
-  res = inRange->GetEndOffset(&endOffset);
-  NS_ENSURE_SUCCESS(res, res);
-  
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// PromoteRange: Expand a range to include any parents for which all editable
+//               children are already in range.
+//
+void
+nsHTMLEditRules::PromoteRange(nsRange& aRange, EditAction aOperationType)
+{
+  NS_ENSURE_TRUE(mHTMLEditor, );
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  nsCOMPtr<nsINode> startNode = aRange.GetStartParent();
+  nsCOMPtr<nsINode> endNode = aRange.GetEndParent();
+  int32_t startOffset = aRange.StartOffset();
+  int32_t endOffset = aRange.EndOffset();
+
   // MOOSE major hack:
   // GetPromotedPoint doesn't really do the right thing for collapsed ranges
   // inside block elements that contain nothing but a solo <br>.  It's easier
   // to put a workaround here than to revamp GetPromotedPoint.  :-(
-  if ( (startNode == endNode) && (startOffset == endOffset))
-  {
-    nsCOMPtr<nsIDOMNode> block;
-    if (IsBlockNode(startNode)) {
-      block = startNode;
+  if (startNode == endNode && startOffset == endOffset) {
+    nsCOMPtr<Element> block;
+    if (IsBlockNode(GetAsDOMNode(startNode))) {
+      block = startNode->AsElement();
     } else {
-      NS_ENSURE_STATE(mHTMLEditor);
       block = mHTMLEditor->GetBlockNodeParent(startNode);
     }
-    if (block)
-    {
+    if (block) {
       bool bIsEmptyNode = false;
-      // check for the editing host
-      NS_ENSURE_STATE(mHTMLEditor);
-      nsIContent *rootContent = mHTMLEditor->GetActiveEditingHost();
-      nsCOMPtr<nsINode> rootNode = do_QueryInterface(rootContent);
-      nsCOMPtr<nsINode> blockNode = do_QueryInterface(block);
-      NS_ENSURE_TRUE(rootNode && blockNode, NS_ERROR_UNEXPECTED);
+      nsCOMPtr<nsIContent> root = mHTMLEditor->GetActiveEditingHost();
       // Make sure we don't go higher than our root element in the content tree
-      if (!nsContentUtils::ContentIsDescendantOf(rootNode, blockNode))
-      {
-        NS_ENSURE_STATE(mHTMLEditor);
-        res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
-      }
-      if (bIsEmptyNode)
-      {
-        uint32_t numChildren;
-        nsEditor::GetLengthOfDOMNode(block, numChildren); 
+      NS_ENSURE_TRUE(root, );
+      if (!nsContentUtils::ContentIsDescendantOf(root, block)) {
+        mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
+      }
+      if (bIsEmptyNode) {
         startNode = block;
         endNode = block;
         startOffset = 0;
-        endOffset = numChildren;
-      }
-    }
-  }
-
-  // make a new adjusted range to represent the appropriate block content.
-  // this is tricky.  the basic idea is to push out the range endpoints
-  // to truly enclose the blocks that we will affect
-  
+        endOffset = block->Length();
+      }
+    }
+  }
+
+  // Make a new adjusted range to represent the appropriate block content.
+  // This is tricky.  The basic idea is to push out the range endpoints to
+  // truly enclose the blocks that we will affect.
+
   nsCOMPtr<nsIDOMNode> opStartNode;
   nsCOMPtr<nsIDOMNode> opEndNode;
   int32_t opStartOffset, opEndOffset;
   nsRefPtr<nsRange> opRange;
-  
-  GetPromotedPoint(kStart, startNode, startOffset, inOperationType,
-                   address_of(opStartNode), &opStartOffset);
-  GetPromotedPoint(kEnd, endNode, endOffset, inOperationType,
+
+  GetPromotedPoint(kStart, GetAsDOMNode(startNode), startOffset,
+                   aOperationType, address_of(opStartNode), &opStartOffset);
+  GetPromotedPoint(kEnd, GetAsDOMNode(endNode), endOffset, aOperationType,
                    address_of(opEndNode), &opEndOffset);
 
   // Make sure that the new range ends up to be in the editable section.
-  NS_ENSURE_STATE(mHTMLEditor);
-  if (!mHTMLEditor->IsDescendantOfEditorRoot(nsEditor::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) ||
-      !mHTMLEditor || // Check again, since it may have gone away
-      !mHTMLEditor->IsDescendantOfEditorRoot(nsEditor::GetNodeAtRangeOffsetPoint(opEndNode, opEndOffset - 1))) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    return NS_OK;
-  }
-
-  res = inRange->SetStart(opStartNode, opStartOffset);
-  NS_ENSURE_SUCCESS(res, res);
-  res = inRange->SetEnd(opEndNode, opEndOffset);
-  return res;
-} 
+  if (!mHTMLEditor->IsDescendantOfEditorRoot(
+        nsEditor::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) ||
+      !mHTMLEditor->IsDescendantOfEditorRoot(
+        nsEditor::GetNodeAtRangeOffsetPoint(opEndNode, opEndOffset - 1))) {
+    return;
+  }
+
+  DebugOnly<nsresult> res = aRange.SetStart(opStartNode, opStartOffset);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
+  res = aRange.SetEnd(opEndNode, opEndOffset);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
+}
 
 class nsUniqueFunctor : public nsBoolDomIterFunctor
 {
 public:
-  explicit nsUniqueFunctor(nsCOMArray<nsIDOMNode> &aArray) : mArray(aArray)
+  explicit nsUniqueFunctor(nsTArray<OwningNonNull<nsINode>> &aArray) : mArray(aArray)
   {
   }
-  virtual bool operator()(nsIDOMNode* aNode)  // used to build list of all nodes iterator covers
+  // used to build list of all nodes iterator covers
+  virtual bool operator()(nsINode* aNode) const
   {
-    return mArray.IndexOf(aNode) < 0;
+    return !mArray.Contains(aNode);
   }
 
 private:
-  nsCOMArray<nsIDOMNode> &mArray;
+  nsTArray<OwningNonNull<nsINode>>& mArray;
 };
 
-///////////////////////////////////////////////////////////////////////////
-// GetNodesForOperation: run through the ranges in the array and construct 
-//                       a new array of nodes to be acted on.
-//                       
-nsresult 
-nsHTMLEditRules::GetNodesForOperation(nsTArray<nsRefPtr<nsRange>>& inArrayOfRanges, 
-                                      nsCOMArray<nsIDOMNode>& outArrayOfNodes, 
-                                      EditAction inOperationType,
-                                      bool aDontTouchContent)
-{
-  int32_t rangeCount = inArrayOfRanges.Length();
-  
-  int32_t i;
-  nsRefPtr<nsRange> opRange;
-
-  nsresult res = NS_OK;
-  
-  // bust up any inlines that cross our range endpoints,
-  // but only if we are allowed to touch content.
-  
-  if (!aDontTouchContent)
-  {
-    nsTArray<nsRefPtr<nsRangeStore>> rangeItemArray;
+///////////////////////////////////////////////////////////////////////////////
+// GetNodesForOperation: Run through the ranges in the array and construct a
+//                       new array of nodes to be acted on.
+//
+nsresult
+nsHTMLEditRules::GetNodesForOperation(nsTArray<nsRefPtr<nsRange>>& aArrayOfRanges,
+                                      nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
+                                      EditAction aOperationType,
+                                      TouchContent aTouchContent)
+{
+  NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  int32_t rangeCount = aArrayOfRanges.Length();
+  nsresult res;
+
+  // Bust up any inlines that cross our range endpoints, but only if we are
+  // allowed to touch content.
+
+  if (aTouchContent == TouchContent::yes) {
+    nsTArray<OwningNonNull<nsRangeStore>> rangeItemArray;
     rangeItemArray.AppendElements(rangeCount);
 
-    NS_ASSERTION(static_cast<uint32_t>(rangeCount) == rangeItemArray.Length(),
-                 "How did that happen?");
-
-    // first register ranges for special editor gravity
-    for (i = 0; i < rangeCount; i++)
-    {
-      opRange = inArrayOfRanges[0];
+    // First register ranges for special editor gravity
+    for (int32_t i = 0; i < rangeCount; i++) {
       rangeItemArray[i] = new nsRangeStore();
-      rangeItemArray[i]->StoreRange(opRange);
-      NS_ENSURE_STATE(mHTMLEditor);
+      rangeItemArray[i]->StoreRange(aArrayOfRanges[0]);
       mHTMLEditor->mRangeUpdater.RegisterRangeItem(rangeItemArray[i]);
-      inArrayOfRanges.RemoveElementAt(0);
-    }    
-    // now bust up inlines.  Safe to start at rangeCount-1, since we
-    // asserted we have enough items above.
-    for (i = rangeCount-1; i >= 0 && NS_SUCCEEDED(res); i--)
-    {
-      res = BustUpInlinesAtRangeEndpoints(*rangeItemArray[i]);
-    } 
-    // then unregister the ranges
-    for (i = 0; i < rangeCount; i++)
-    {
-      nsRangeStore* item = rangeItemArray[i];
-      NS_ENSURE_STATE(mHTMLEditor);
+      aArrayOfRanges.RemoveElementAt(0);
+    }
+    // Now bust up inlines.
+    for (auto& item : Reversed(rangeItemArray)) {
+      res = BustUpInlinesAtRangeEndpoints(*item);
+      if (NS_FAILED(res)) {
+        break;
+      }
+    }
+    // Then unregister the ranges
+    for (auto& item : rangeItemArray) {
       mHTMLEditor->mRangeUpdater.DropRangeItem(item);
-      opRange = item->GetRange();
-      inArrayOfRanges.AppendElement(opRange);
+      aArrayOfRanges.AppendElement(item->GetRange());
     }
     NS_ENSURE_SUCCESS(res, res);
   }
-  // gather up a list of all the nodes
-  for (i = 0; i < rangeCount; i++)
-  {
-    opRange = inArrayOfRanges[i];
-    
-    nsDOMSubtreeIterator iter;
-    res = iter.Init(opRange);
-    NS_ENSURE_SUCCESS(res, res);
-    if (outArrayOfNodes.Count() == 0) {
-      nsTrivialFunctor functor;
-      res = iter.AppendList(functor, outArrayOfNodes);
-      NS_ENSURE_SUCCESS(res, res);    
-    }
-    else {
-      // We don't want duplicates in outArrayOfNodes, so we use an
+  // Gather up a list of all the nodes
+  for (auto& range : aArrayOfRanges) {
+    nsDOMSubtreeIterator iter(*range);
+    if (aOutArrayOfNodes.Length() == 0) {
+      iter.AppendList(nsTrivialFunctor(), aOutArrayOfNodes);
+    } else {
+      // We don't want duplicates in aOutArrayOfNodes, so we use an
       // iterator/functor that only return nodes that are not already in
-      // outArrayOfNodes.
-      nsCOMArray<nsIDOMNode> nodes;
-      nsUniqueFunctor functor(outArrayOfNodes);
-      res = iter.AppendList(functor, nodes);
-      NS_ENSURE_SUCCESS(res, res);
-      if (!outArrayOfNodes.AppendObjects(nodes))
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-  }    
-
-  // certain operations should not act on li's and td's, but rather inside 
-  // them.  alter the list as needed
-  if (inOperationType == EditAction::makeBasicBlock) {
-    int32_t listCount = outArrayOfNodes.Count();
-    for (i=listCount-1; i>=0; i--)
-    {
-      nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
-      if (nsHTMLEditUtils::IsListItem(node))
-      {
-        int32_t j=i;
-        outArrayOfNodes.RemoveObjectAt(i);
-        res = GetInnerContent(node, outArrayOfNodes, &j);
-        NS_ENSURE_SUCCESS(res, res);
-      }
-    }
-  }
-  // indent/outdent already do something special for list items, but
-  // we still need to make sure we don't act on table elements
-  else if (inOperationType == EditAction::outdent ||
-           inOperationType == EditAction::indent ||
-           inOperationType == EditAction::setAbsolutePosition) {
-    int32_t listCount = outArrayOfNodes.Count();
-    for (i=listCount-1; i>=0; i--)
-    {
-      nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
-      if (nsHTMLEditUtils::IsTableElementButNotTable(node))
-      {
-        int32_t j=i;
-        outArrayOfNodes.RemoveObjectAt(i);
-        res = GetInnerContent(node, outArrayOfNodes, &j);
+      // aOutArrayOfNodes.
+      nsTArray<OwningNonNull<nsINode>> nodes;
+      iter.AppendList(nsUniqueFunctor(aOutArrayOfNodes), nodes);
+      aOutArrayOfNodes.AppendElements(nodes);
+    }
+  }
+
+  // Certain operations should not act on li's and td's, but rather inside
+  // them.  Alter the list as needed.
+  if (aOperationType == EditAction::makeBasicBlock) {
+    for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
+      OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
+      if (nsHTMLEditUtils::IsListItem(node)) {
+        int32_t j = i;
+        aOutArrayOfNodes.RemoveElementAt(i);
+        GetInnerContent(*node, aOutArrayOfNodes, &j);
+      }
+    }
+  // Indent/outdent already do something special for list items, but we still
+  // need to make sure we don't act on table elements
+  } else if (aOperationType == EditAction::outdent ||
+             aOperationType == EditAction::indent ||
+             aOperationType == EditAction::setAbsolutePosition) {
+    for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
+      OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
+      if (nsHTMLEditUtils::IsTableElementButNotTable(node)) {
+        int32_t j = i;
+        aOutArrayOfNodes.RemoveElementAt(i);
+        GetInnerContent(*node, aOutArrayOfNodes, &j);
+      }
+    }
+  }
+  // Outdent should look inside of divs.
+  if (aOperationType == EditAction::outdent &&
+      !mHTMLEditor->IsCSSEnabled()) {
+    for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
+      OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
+      if (node->IsHTMLElement(nsGkAtoms::div)) {
+        int32_t j = i;
+        aOutArrayOfNodes.RemoveElementAt(i);
+        GetInnerContent(*node, aOutArrayOfNodes, &j, Lists::no, Tables::no);
+      }
+    }
+  }
+
+
+  // Post-process the list to break up inline containers that contain br's, but
+  // only for operations that might care, like making lists or paragraphs
+  if (aOperationType == EditAction::makeBasicBlock ||
+      aOperationType == EditAction::makeList ||
+      aOperationType == EditAction::align ||
+      aOperationType == EditAction::setAbsolutePosition ||
+      aOperationType == EditAction::indent ||
+      aOperationType == EditAction::outdent) {
+    for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
+      OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
+      if (aTouchContent == TouchContent::yes &&
+          IsInlineNode(GetAsDOMNode(node)) && mHTMLEditor->IsContainer(node) &&
+          !mHTMLEditor->IsTextNode(node)) {
+        nsTArray<OwningNonNull<nsINode>> arrayOfInlines;
+        res = BustUpInlinesAtBRs(*node, arrayOfInlines);
         NS_ENSURE_SUCCESS(res, res);
-      }
-    }
-  }
-  // outdent should look inside of divs.
-  if (inOperationType == EditAction::outdent &&
-      (!mHTMLEditor || !mHTMLEditor->IsCSSEnabled())) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    int32_t listCount = outArrayOfNodes.Count();
-    for (i=listCount-1; i>=0; i--)
-    {
-      nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
-      if (nsHTMLEditUtils::IsDiv(node))
-      {
-        int32_t j=i;
-        outArrayOfNodes.RemoveObjectAt(i);
-        res = GetInnerContent(node, outArrayOfNodes, &j, false, false);
-        NS_ENSURE_SUCCESS(res, res);
-      }
-    }
-  }
-
-
-  // post process the list to break up inline containers that contain br's.
-  // but only for operations that might care, like making lists or para's...
-  if (inOperationType == EditAction::makeBasicBlock ||
-      inOperationType == EditAction::makeList ||
-      inOperationType == EditAction::align ||
-      inOperationType == EditAction::setAbsolutePosition ||
-      inOperationType == EditAction::indent ||
-      inOperationType == EditAction::outdent) {
-    int32_t listCount = outArrayOfNodes.Count();
-    for (i=listCount-1; i>=0; i--)
-    {
-      nsCOMPtr<nsIDOMNode> node = outArrayOfNodes[i];
-      if (!aDontTouchContent && IsInlineNode(node) &&
-          (!mHTMLEditor || mHTMLEditor->IsContainer(node)) &&
-          (!mHTMLEditor || !mHTMLEditor->IsTextNode(node)))
-      {
-        NS_ENSURE_STATE(mHTMLEditor);
-        nsCOMArray<nsIDOMNode> arrayOfInlines;
-        res = BustUpInlinesAtBRs(node, arrayOfInlines);
-        NS_ENSURE_SUCCESS(res, res);
-        // put these nodes in outArrayOfNodes, replacing the current node
-        outArrayOfNodes.RemoveObjectAt(i);
-        outArrayOfNodes.InsertObjectsAt(arrayOfInlines, i);
-      }
-    }
-  }
-  return res;
-}
-
-
-
-///////////////////////////////////////////////////////////////////////////
-// GetChildNodesForOperation: 
-//                       
-nsresult 
-nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode, 
-                                           nsCOMArray<nsIDOMNode>& outArrayOfNodes)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(inNode);
-  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
-
-  for (nsIContent* child = node->GetFirstChild();
-       child;
-       child = child->GetNextSibling()) {
-    nsIDOMNode* childNode = child->AsDOMNode();
-    if (!outArrayOfNodes.AppendObject(childNode)) {
-      return NS_ERROR_FAILURE;
+
+        // Put these nodes in aOutArrayOfNodes, replacing the current node
+        aOutArrayOfNodes.RemoveElementAt(i);
+        aOutArrayOfNodes.InsertElementsAt(i, arrayOfInlines);
+      }
     }
   }
   return NS_OK;
 }
 
 
-
-///////////////////////////////////////////////////////////////////////////
-// GetListActionNodes: 
-//                       
-nsresult 
-nsHTMLEditRules::GetListActionNodes(nsCOMArray<nsIDOMNode> &outArrayOfNodes, 
-                                    bool aEntireList,
-                                    bool aDontTouchContent)
-{
-  nsresult res = NS_OK;
-  
+void
+nsHTMLEditRules::GetChildNodesForOperation(nsINode& aNode,
+    nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes)
+{
+  for (nsCOMPtr<nsIContent> child = aNode.GetFirstChild();
+       child; child = child->GetNextSibling()) {
+    outArrayOfNodes.AppendElement(*child);
+  }
+}
+
+
+nsresult
+nsHTMLEditRules::GetListActionNodes(nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
+                                    EntireList aEntireList,
+                                    TouchContent aTouchContent)
+{
   NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
   nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-  // added this in so that ui code can ask to change an entire list, even if selection
-  // is only in part of it.  used by list item dialog.
-  if (aEntireList)
-  {       
+
+  // Added this in so that ui code can ask to change an entire list, even if
+  // selection is only in part of it.  used by list item dialog.
+  if (aEntireList == EntireList::yes) {
     uint32_t rangeCount = selection->RangeCount();
     for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
       nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
-      nsCOMPtr<nsIDOMNode> commonParent, parent, tmp;
-      range->GetCommonAncestorContainer(getter_AddRefs(commonParent));
-      if (commonParent)
-      {
-        parent = commonParent;
-        while (parent)
-        {
-          if (nsHTMLEditUtils::IsList(parent))
-          {
-            outArrayOfNodes.AppendObject(parent);
-            break;
-          }
-          parent->GetParentNode(getter_AddRefs(tmp));
-          parent = tmp;
+      for (nsCOMPtr<nsINode> parent = range->GetCommonAncestor();
+           parent; parent = parent->GetParentNode()) {
+        if (nsHTMLEditUtils::IsList(parent)) {
+          aOutArrayOfNodes.AppendElement(*parent);
+          break;
         }
       }
     }
-    // if we didn't find any nodes this way, then try the normal way.  perhaps the
-    // selection spans multiple lists but with no common list parent.
-    if (outArrayOfNodes.Count()) return NS_OK;
+    // If we didn't find any nodes this way, then try the normal way.  Perhaps
+    // the selection spans multiple lists but with no common list parent.
+    if (aOutArrayOfNodes.Length()) {
+      return NS_OK;
+    }
   }
 
   {
     // We don't like other people messing with our selection!
-    NS_ENSURE_STATE(mHTMLEditor);
     nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
 
     // contruct a list of nodes to act on.
-    res = GetNodesFromSelection(selection, EditAction::makeList,
-                                outArrayOfNodes, aDontTouchContent);
+    nsresult res = GetNodesFromSelection(*selection, EditAction::makeList,
+                                         aOutArrayOfNodes, aTouchContent);
     NS_ENSURE_SUCCESS(res, res);
   }
-               
-  // pre process our list of nodes...                      
-  int32_t listCount = outArrayOfNodes.Count();
-  int32_t i;
-  for (i=listCount-1; i>=0; i--)
-  {
-    nsCOMPtr<nsIDOMNode> testNode = outArrayOfNodes[i];
+
+  // Pre-process our list of nodes
+  for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
+    OwningNonNull<nsINode> testNode = aOutArrayOfNodes[i];
 
     // Remove all non-editable nodes.  Leave them be.
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (!mHTMLEditor->IsEditable(testNode))
-    {
-      outArrayOfNodes.RemoveObjectAt(i);
-    }
-    
-    // scan for table elements and divs.  If we find table elements other than table,
-    // replace it with a list of any editable non-table content.
-    if (nsHTMLEditUtils::IsTableElementButNotTable(testNode))
-    {
-      int32_t j=i;
-      outArrayOfNodes.RemoveObjectAt(i);
-      res = GetInnerContent(testNode, outArrayOfNodes, &j, false);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-  }
-
-  // if there is only one node in the array, and it is a list, div, or blockquote,
-  // then look inside of it until we find inner list or content.
-  res = LookInsideDivBQandList(outArrayOfNodes);
-  return res;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// LookInsideDivBQandList: 
-//                       
-nsresult 
-nsHTMLEditRules::LookInsideDivBQandList(nsCOMArray<nsIDOMNode>& aNodeArray)
-{
-  // if there is only one node in the array, and it is a list, div, or blockquote,
-  // then look inside of it until we find inner list or content.
-  int32_t listCount = aNodeArray.Count();
+    if (!mHTMLEditor->IsEditable(testNode)) {
+      aOutArrayOfNodes.RemoveElementAt(i);
+      continue;
+    }
+
+    // Scan for table elements and divs.  If we find table elements other than
+    // table, replace it with a list of any editable non-table content.
+    if (nsHTMLEditUtils::IsTableElementButNotTable(testNode)) {
+      int32_t j = i;
+      aOutArrayOfNodes.RemoveElementAt(i);
+      GetInnerContent(*testNode, aOutArrayOfNodes, &j, Lists::no);
+    }
+  }
+
+  // If there is only one node in the array, and it is a list, div, or
+  // blockquote, then look inside of it until we find inner list or content.
+  LookInsideDivBQandList(aOutArrayOfNodes);
+
+  return NS_OK;
+}
+
+
+void
+nsHTMLEditRules::LookInsideDivBQandList(nsTArray<OwningNonNull<nsINode>>& aNodeArray)
+{
+  NS_ENSURE_TRUE(mHTMLEditor, );
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  // If there is only one node in the array, and it is a list, div, or
+  // blockquote, then look inside of it until we find inner list or content.
+  int32_t listCount = aNodeArray.Length();
   if (listCount != 1) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsINode> curNode = do_QueryInterface(aNodeArray[0]);
-  NS_ENSURE_STATE(curNode);
-
-  while (curNode->IsElement() &&
-         (curNode->IsHTMLElement(nsGkAtoms::div) ||
-          nsHTMLEditUtils::IsList(curNode) ||
-          curNode->IsHTMLElement(nsGkAtoms::blockquote))) {
-    // dive as long as there is only one child, and it is a list, div, blockquote
-    NS_ENSURE_STATE(mHTMLEditor);
+    return;
+  }
+
+  OwningNonNull<nsINode> curNode = aNodeArray[0];
+
+  while (curNode->IsHTMLElement(nsGkAtoms::div) ||
+         nsHTMLEditUtils::IsList(curNode) ||
+         curNode->IsHTMLElement(nsGkAtoms::blockquote)) {
+    // Dive as long as there's only one child, and it's a list, div, blockquote
     uint32_t numChildren = mHTMLEditor->CountEditableChildren(curNode);
     if (numChildren != 1) {
       break;
     }
 
-    // keep diving
-    // XXX One would expect to dive into the one editable node.
-    nsIContent* tmp = curNode->GetFirstChild();
-    if (!tmp->IsElement()) {
+    // Keep diving!  XXX One would expect to dive into the one editable node.
+    nsCOMPtr<nsIContent> child = curNode->GetFirstChild();
+    if (!child->IsHTMLElement(nsGkAtoms::div) &&
+        !nsHTMLEditUtils::IsList(child) &&
+        !child->IsHTMLElement(nsGkAtoms::blockquote)) {
       break;
     }
 
-    dom::Element* element = tmp->AsElement();
-    if (!element->IsHTMLElement(nsGkAtoms::div) &&
-        !nsHTMLEditUtils::IsList(element) &&
-        !element->IsHTMLElement(nsGkAtoms::blockquote)) {
-      break;
-    }
-
-    // check editablility XXX floppy moose
-    curNode = tmp;
-  }
-
-  // we've found innermost list/blockquote/div: 
-  // replace the one node in the array with these nodes
-  aNodeArray.RemoveObjectAt(0);
+    // check editability XXX floppy moose
+    curNode = child;
+  }
+
+  // We've found innermost list/blockquote/div: replace the one node in the
+  // array with these nodes
+  aNodeArray.RemoveElementAt(0);
   if (curNode->IsAnyOfHTMLElements(nsGkAtoms::div,
                                    nsGkAtoms::blockquote)) {
     int32_t j = 0;
-    return GetInnerContent(curNode->AsDOMNode(), aNodeArray, &j, false, false);
-  }
-
-  aNodeArray.AppendObject(curNode->AsDOMNode());
-  return NS_OK;
+    GetInnerContent(*curNode, aNodeArray, &j, Lists::no, Tables::no);
+    return;
+  }
+
+  aNodeArray.AppendElement(*curNode);
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
 // GetDefinitionListItemTypes: 
 //                       
 void
 nsHTMLEditRules::GetDefinitionListItemTypes(dom::Element* aElement, bool* aDT, bool* aDD)
@@ -6214,59 +6008,52 @@ nsHTMLEditRules::GetDefinitionListItemTy
     if (child->IsHTMLElement(nsGkAtoms::dt)) {
       *aDT = true;
     } else if (child->IsHTMLElement(nsGkAtoms::dd)) {
       *aDD = true;
     }
   }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// GetParagraphFormatNodes: 
-//                       
-nsresult 
-nsHTMLEditRules::GetParagraphFormatNodes(nsCOMArray<nsIDOMNode>& outArrayOfNodes,
-                                         bool aDontTouchContent)
-{  
+nsresult
+nsHTMLEditRules::GetParagraphFormatNodes(nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
+                                         TouchContent aTouchContent)
+{
   NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
   nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
   NS_ENSURE_STATE(selection);
 
-  // contruct a list of nodes to act on.
-  nsresult res = GetNodesFromSelection(selection, EditAction::makeBasicBlock,
-                                       outArrayOfNodes, aDontTouchContent);
+  // Contruct a list of nodes to act on.
+  nsresult res = GetNodesFromSelection(*selection, EditAction::makeBasicBlock,
+                                       outArrayOfNodes, aTouchContent);
   NS_ENSURE_SUCCESS(res, res);
 
-  // pre process our list of nodes...                      
-  int32_t listCount = outArrayOfNodes.Count();
-  int32_t i;
-  for (i=listCount-1; i>=0; i--)
-  {
-    nsCOMPtr<nsIDOMNode> testNode = outArrayOfNodes[i];
+  // Pre-process our list of nodes
+  for (int32_t i = outArrayOfNodes.Length() - 1; i >= 0; i--) {
+    OwningNonNull<nsINode> testNode = outArrayOfNodes[i];
 
     // Remove all non-editable nodes.  Leave them be.
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (!mHTMLEditor->IsEditable(testNode))
-    {
-      outArrayOfNodes.RemoveObjectAt(i);
-    }
-    
-    // scan for table elements.  If we find table elements other than table,
-    // replace it with a list of any editable non-table content.  Ditto for list elements.
+    if (!mHTMLEditor->IsEditable(testNode)) {
+      outArrayOfNodes.RemoveElementAt(i);
+    }
+
+    // Scan for table elements.  If we find table elements other than table,
+    // replace it with a list of any editable non-table content.  Ditto for
+    // list elements.
     if (nsHTMLEditUtils::IsTableElement(testNode) ||
-        nsHTMLEditUtils::IsList(testNode) || 
-        nsHTMLEditUtils::IsListItem(testNode) )
-    {
-      int32_t j=i;
-      outArrayOfNodes.RemoveObjectAt(i);
-      res = GetInnerContent(testNode, outArrayOfNodes, &j);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-  }
-  return res;
+        nsHTMLEditUtils::IsList(testNode) ||
+        nsHTMLEditUtils::IsListItem(testNode)) {
+      int32_t j = i;
+      outArrayOfNodes.RemoveElementAt(i);
+      GetInnerContent(testNode, outArrayOfNodes, &j);
+    }
+  }
+  return NS_OK;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
 // BustUpInlinesAtRangeEndpoints: 
 //                       
 nsresult 
 nsHTMLEditRules::BustUpInlinesAtRangeEndpoints(nsRangeStore &item)
@@ -6310,91 +6097,77 @@ nsHTMLEditRules::BustUpInlinesAtRangeEnd
     item.startOffset = resultStartOffset;
   }
   
   return res;
 }
 
 
 
-///////////////////////////////////////////////////////////////////////////
-// BustUpInlinesAtBRs: 
-//                       
-nsresult 
-nsHTMLEditRules::BustUpInlinesAtBRs(nsIDOMNode *inNode, 
-                                    nsCOMArray<nsIDOMNode>& outArrayOfNodes)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(inNode);
-  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
-
-  // first step is to build up a list of all the break nodes inside 
-  // the inline container.
-  nsCOMArray<nsIDOMNode> arrayOfBreaks;
+nsresult
+nsHTMLEditRules::BustUpInlinesAtBRs(nsINode& aNode,
+                                    nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes)
+{
+  NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  // First build up a list of all the break nodes inside the inline container.
+  nsTArray<OwningNonNull<nsINode>> arrayOfBreaks;
   nsBRNodeFunctor functor;
-  nsDOMIterator iter;
-  nsresult res = iter.Init(inNode);
-  NS_ENSURE_SUCCESS(res, res);
-  res = iter.AppendList(functor, arrayOfBreaks);
-  NS_ENSURE_SUCCESS(res, res);
-  
-  // if there aren't any breaks, just put inNode itself in the array
-  int32_t listCount = arrayOfBreaks.Count();
-  if (!listCount)
-  {
-    if (!outArrayOfNodes.AppendObject(inNode))
-      return NS_ERROR_FAILURE;
-  }
-  else
-  {
-    // else we need to bust up inNode along all the breaks
-    nsCOMPtr<Element> breakNode;
-    nsCOMPtr<nsINode> inlineParentNode = node->GetParentNode();
-    nsCOMPtr<nsIDOMNode> leftNode;
-    nsCOMPtr<nsIDOMNode> rightNode;
-    nsCOMPtr<nsIDOMNode> splitDeepNode = inNode;
-    nsCOMPtr<nsIDOMNode> splitParentNode;
-    int32_t splitOffset, resultOffset, i;
-    
-    for (i=0; i< listCount; i++)
-    {
-      breakNode = do_QueryInterface(arrayOfBreaks[i]);
-      NS_ENSURE_TRUE(breakNode, NS_ERROR_NULL_POINTER);
-      NS_ENSURE_TRUE(splitDeepNode, NS_ERROR_NULL_POINTER);
-      splitParentNode = GetAsDOMNode(nsEditor::GetNodeLocation(breakNode,
-                                                               &splitOffset));
-      NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->SplitNodeDeep(splitDeepNode, splitParentNode, splitOffset,
-                          &resultOffset, false, address_of(leftNode), address_of(rightNode));
-      NS_ENSURE_SUCCESS(res, res);
-      // put left node in node list
-      if (leftNode)
-      {
-        // might not be a left node.  a break might have been at the very
-        // beginning of inline container, in which case splitnodedeep
-        // would not actually split anything
-        if (!outArrayOfNodes.AppendObject(leftNode))
-          return NS_ERROR_FAILURE;
-      }
-      // move break outside of container and also put in node list
-      NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->MoveNode(breakNode, inlineParentNode, resultOffset);
-      NS_ENSURE_SUCCESS(res, res);
-      if (!outArrayOfNodes.AppendObject(GetAsDOMNode(breakNode)))
-        return  NS_ERROR_FAILURE;
-      // now rightNode becomes the new node to split
-      splitDeepNode = rightNode;
-    }
-    // now tack on remaining rightNode, if any, to the list
-    if (rightNode)
-    {
-      if (!outArrayOfNodes.AppendObject(rightNode))
-        return NS_ERROR_FAILURE;
-    }
-  }
-  return res;
+  nsDOMIterator iter(aNode);
+  iter.AppendList(functor, arrayOfBreaks);
+
+  // If there aren't any breaks, just put inNode itself in the array
+  if (!arrayOfBreaks.Length()) {
+    aOutArrayOfNodes.AppendElement(aNode);
+    return NS_OK;
+  }
+
+  // Else we need to bust up inNode along all the breaks
+  nsCOMPtr<nsINode> inlineParentNode = aNode.GetParentNode();
+  nsCOMPtr<nsIDOMNode> splitDeepNode = GetAsDOMNode(&aNode);
+  nsCOMPtr<nsIDOMNode> leftDOMNode, rightDOMNode;
+
+  for (uint32_t i = 0; i < arrayOfBreaks.Length(); i++) {
+    OwningNonNull<Element> breakNode = *arrayOfBreaks[i]->AsElement();
+    NS_ENSURE_TRUE(splitDeepNode, NS_ERROR_NULL_POINTER);
+    nsCOMPtr<nsINode> splitParentNode = breakNode->GetParentNode();
+    int32_t splitOffset = splitParentNode ?
+      splitParentNode->IndexOf(breakNode) : -1;
+
+    int32_t resultOffset;
+    nsresult res = mHTMLEditor->SplitNodeDeep(splitDeepNode,
+        GetAsDOMNode(splitParentNode), splitOffset, &resultOffset, false,
+        address_of(leftDOMNode), address_of(rightDOMNode));
+    NS_ENSURE_SUCCESS(res, res);
+
+    // Put left node in node list
+    if (leftDOMNode) {
+      // Might not be a left node.  A break might have been at the very
+      // beginning of inline container, in which case SplitNodeDeep would not
+      // actually split anything
+      nsCOMPtr<nsINode> leftNode = do_QueryInterface(leftDOMNode);
+      NS_ENSURE_STATE(leftNode);
+      aOutArrayOfNodes.AppendElement(*leftNode);
+    }
+    // Move break outside of container and also put in node list
+    res = mHTMLEditor->MoveNode(breakNode, inlineParentNode, resultOffset);
+    NS_ENSURE_SUCCESS(res, res);
+    aOutArrayOfNodes.AppendElement(*breakNode);
+
+    // Now rightNode becomes the new node to split
+    splitDeepNode = rightDOMNode;
+  }
+  // Now tack on remaining rightNode, if any, to the list
+  if (rightDOMNode) {
+    nsCOMPtr<nsINode> rightNode = do_QueryInterface(rightDOMNode);
+    NS_ENSURE_STATE(rightNode);
+    aOutArrayOfNodes.AppendElement(*rightNode);
+  }
+  return NS_OK;
 }
 
 
 nsCOMPtr<nsIDOMNode> 
 nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode)
 {
   NS_ENSURE_TRUE(aNode, nullptr);
   if (IsBlockNode(aNode)) return nullptr;
@@ -6404,106 +6177,96 @@ nsHTMLEditRules::GetHighestInlineParent(
   {
     inlineNode = node;
     inlineNode->GetParentNode(getter_AddRefs(node));
   }
   return inlineNode;
 }
 
 
-///////////////////////////////////////////////////////////////////////////
-// GetNodesFromPoint: given a particular operation, construct a list  
-//                     of nodes from a point that will be operated on. 
-//                       
-nsresult 
-nsHTMLEditRules::GetNodesFromPoint(::DOMPoint point,
-                                   EditAction operation,
-                                   nsCOMArray<nsIDOMNode> &arrayOfNodes,
-                                   bool dontTouchContent)
-{
-  NS_ENSURE_STATE(point.node);
-  nsRefPtr<nsRange> range = new nsRange(point.node);
-  nsresult res = range->SetStart(point.node, point.offset);
-  NS_ENSURE_SUCCESS(res, res);
-  
-  // expand the range to include adjacent inlines
-  res = PromoteRange(range, operation);
-  NS_ENSURE_SUCCESS(res, res);
-      
-  // make array of ranges
+///////////////////////////////////////////////////////////////////////////////
+// GetNodesFromPoint: Given a particular operation, construct a list of nodes
+//                    from a point that will be operated on.
+//
+nsresult
+nsHTMLEditRules::GetNodesFromPoint(::DOMPoint aPoint,
+                                   EditAction aOperation,
+                                   nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
+                                   TouchContent aTouchContent)
+{
+  NS_ENSURE_STATE(aPoint.node);
+  nsRefPtr<nsRange> range = new nsRange(aPoint.node);
+  nsresult res = range->SetStart(aPoint.node, aPoint.offset);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
+
+  // Expand the range to include adjacent inlines
+  PromoteRange(*range, aOperation);
+
+  // Make array of ranges
   nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-  
-  // stuff new opRange into array
+
+  // Stuff new opRange into array
   arrayOfRanges.AppendElement(range);
-  
-  // use these ranges to contruct a list of nodes to act on.
-  res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent); 
-  return res;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// GetNodesFromSelection: given a particular operation, construct a list  
-//                     of nodes from the selection that will be operated on. 
-//                       
-nsresult 
-nsHTMLEditRules::GetNodesFromSelection(Selection* selection,
-                                       EditAction operation,
-                                       nsCOMArray<nsIDOMNode>& arrayOfNodes,
-                                       bool dontTouchContent)
-{
-  NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
-  nsresult res;
-  
-  // promote selection ranges
-  nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-  res = GetPromotedRanges(selection, arrayOfRanges, operation);
+
+  // Use these ranges to contruct a list of nodes to act on
+  res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, aOperation,
+                             aTouchContent);
   NS_ENSURE_SUCCESS(res, res);
-  
-  // use these ranges to contruct a list of nodes to act on.
-  res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent); 
-  return res;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// MakeTransitionList: detect all the transitions in the array, where a 
-//                     transition means that adjacent nodes in the array 
-//                     don't have the same parent.
-//                       
-nsresult 
-nsHTMLEditRules::MakeTransitionList(nsCOMArray<nsIDOMNode>& inArrayOfNodes, 
-                                    nsTArray<bool> &inTransitionArray)
-{
-  uint32_t listCount = inArrayOfNodes.Count();
-  inTransitionArray.EnsureLengthAtLeast(listCount);
-  uint32_t i;
-  nsCOMPtr<nsIDOMNode> prevElementParent;
-  nsCOMPtr<nsIDOMNode> curElementParent;
-  
-  for (i=0; i<listCount; i++)
-  {
-    nsIDOMNode* transNode = inArrayOfNodes[i];
-    transNode->GetParentNode(getter_AddRefs(curElementParent));
-    if (curElementParent != prevElementParent)
-    {
-      // different parents, or separated by <br>: transition point
-      inTransitionArray[i] = true;
-    }
-    else
-    {
-      // same parents: these nodes grew up together
-      inTransitionArray[i] = false;
-    }
-    prevElementParent = curElementParent;
-  }
+
+  return NS_OK;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// GetNodesFromSelection: Given a particular operation, construct a list of
+//                        nodes from the selection that will be operated on.
+//
+nsresult
+nsHTMLEditRules::GetNodesFromSelection(Selection& aSelection,
+                                       EditAction aOperation,
+                                       nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
+                                       TouchContent aTouchContent)
+{
+  // Promote selection ranges
+  nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
+  GetPromotedRanges(aSelection, arrayOfRanges, aOperation);
+
+  // Use these ranges to contruct a list of nodes to act on.
+  nsresult res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes,
+                                      aOperation, aTouchContent);
+  NS_ENSURE_SUCCESS(res, res);
+
   return NS_OK;
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// MakeTransitionList: Detect all the transitions in the array, where a
+//                     transition means that adjacent nodes in the array don't
+//                     have the same parent.
+void
+nsHTMLEditRules::MakeTransitionList(nsTArray<OwningNonNull<nsINode>>& aNodeArray,
+                                    nsTArray<bool>& aTransitionArray)
+{
+  nsCOMPtr<nsINode> prevParent;
+
+  aTransitionArray.EnsureLengthAtLeast(aNodeArray.Length());
+  for (uint32_t i = 0; i < aNodeArray.Length(); i++) {
+    if (aNodeArray[i]->GetParentNode() != prevParent) {
+      // Different parents: transition point
+      aTransitionArray[i] = true;
+    } else {
+      // Same parents: these nodes grew up together
+      aTransitionArray[i] = false;
+    }
+    prevParent = aNodeArray[i]->GetParentNode();
+  }
+}
+
+
 
 /********************************************************
  *  main implementation methods 
  ********************************************************/
  
 ///////////////////////////////////////////////////////////////////////////
 // IsInListItem: if aNode is the descendant of a listitem, return that li.
 //               But table element boundaries are stoppers on the search.
@@ -6984,377 +6747,297 @@ nsHTMLEditRules::ReturnInListItem(Select
       }
     }
   }
   res = aSelection->Collapse(aListItem,0);
   return res;
 }
 
 
-///////////////////////////////////////////////////////////////////////////
-// MakeBlockquote:  put the list of nodes into one or more blockquotes.  
-//                       
-nsresult 
-nsHTMLEditRules::MakeBlockquote(nsCOMArray<nsIDOMNode>& arrayOfNodes)
-{
-  // the idea here is to put the nodes into a minimal number of 
-  // blockquotes.  When the user blockquotes something, they expect
-  // one blockquote.  That may not be possible (for instance, if they
-  // have two table cells selected, you need two blockquotes inside the cells).
-  
-  nsresult res = NS_OK;
-  
-  nsCOMPtr<nsIDOMNode> curNode, newBlock;
-  nsCOMPtr<nsINode> curParent;
+///////////////////////////////////////////////////////////////////////////////
+// MakeBlockquote: Put the list of nodes into one or more blockquotes.
+//
+nsresult
+nsHTMLEditRules::MakeBlockquote(nsTArray<OwningNonNull<nsINode>>& aNodeArray)
+{
+  // The idea here is to put the nodes into a minimal number of blockquotes.
+  // When the user blockquotes something, they expect one blockquote.  That may
+  // not be possible (for instance, if they have two table cells selected, you
+  // need two blockquotes inside the cells).
+  nsresult res;
   nsCOMPtr<Element> curBlock;
-  int32_t offset;
-  int32_t listCount = arrayOfNodes.Count();
-  
-  nsCOMPtr<nsIDOMNode> prevParent;
-  
-  int32_t i;
-  for (i=0; i<listCount; i++)
-  {
-    // get the node to act on, and its location
-    curNode = arrayOfNodes[i];
-    nsCOMPtr<nsIContent> curContent = do_QueryInterface(curNode);
-    NS_ENSURE_STATE(curContent);
-    curParent = curContent->GetParentNode();
-    offset = curParent ? curParent->IndexOf(curContent) : -1;
-
-    // if the node is a table element or list item, dive inside
-    if (nsHTMLEditUtils::IsTableElementButNotTable(curNode) || 
-        nsHTMLEditUtils::IsListItem(curNode))
-    {
-      curBlock = 0;  // forget any previous block
-      // recursion time
-      nsCOMArray<nsIDOMNode> childArray;
-      res = GetChildNodesForOperation(curNode, childArray);
-      NS_ENSURE_SUCCESS(res, res);
+  nsCOMPtr<nsINode> prevParent;
+
+  for (auto& curNode : aNodeArray) {
+    // Get the node to act on, and its location
+    NS_ENSURE_STATE(curNode->IsContent());
+
+    // If the node is a table element or list item, dive inside
+    if (nsHTMLEditUtils::IsTableElementButNotTable(curNode) ||
+        nsHTMLEditUtils::IsListItem(curNode)) {
+      // Forget any previous block
+      curBlock = nullptr;
+      // Recursion time
+      nsTArray<OwningNonNull<nsINode>> childArray;
+      GetChildNodesForOperation(*curNode, childArray);
       res = MakeBlockquote(childArray);
       NS_ENSURE_SUCCESS(res, res);
     }
-    
-    // if the node has different parent than previous node,
-    // further nodes in a new parent
-    if (prevParent)
-    {
-      nsCOMPtr<nsIDOMNode> temp;
-      curNode->GetParentNode(getter_AddRefs(temp));
-      if (temp != prevParent)
-      {
-        curBlock = 0;  // forget any previous blockquote node we were using
-        prevParent = temp;
-      }
-    }
-    else     
-
-    {
-      curNode->GetParentNode(getter_AddRefs(prevParent));
-    }
-    
-    // if no curBlock, make one
-    if (!curBlock)
-    {
+
+    // If the node has different parent than previous node, further nodes in a
+    // new parent
+    if (prevParent) {
+      if (prevParent != curNode->GetParentNode()) {
+        // Forget any previous blockquote node we were using
+        curBlock = nullptr;
+        prevParent = curNode->GetParentNode();
+      }
+    } else {
+      prevParent = curNode->GetParentNode();
+    }
+
+    // If no curBlock, make one
+    if (!curBlock) {
+      nsCOMPtr<nsINode> curParent = curNode->GetParentNode();
+      int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
       res = SplitAsNeeded(*nsGkAtoms::blockquote, curParent, offset);
       NS_ENSURE_SUCCESS(res, res);
       NS_ENSURE_STATE(mHTMLEditor);
       curBlock = mHTMLEditor->CreateNode(nsGkAtoms::blockquote, curParent,
                                          offset);
       NS_ENSURE_STATE(curBlock);
       // remember our new block for postprocessing
       mNewBlock = curBlock->AsDOMNode();
       // note: doesn't matter if we set mNewBlock multiple times.
     }
-      
-    NS_ENSURE_STATE(mHTMLEditor);
-    res = mHTMLEditor->MoveNode(curContent, curBlock, -1);
+
+    NS_ENSURE_STATE(mHTMLEditor);
+    res = mHTMLEditor->MoveNode(curNode->AsContent(), curBlock, -1);
     NS_ENSURE_SUCCESS(res, res);
   }
-  return res;
-}
-
-
-
-///////////////////////////////////////////////////////////////////////////
-// RemoveBlockStyle:  make the nodes have no special block type.  
-//                       
-nsresult 
-nsHTMLEditRules::RemoveBlockStyle(nsCOMArray<nsIDOMNode>& arrayOfNodes)
-{
-  // intent of this routine is to be used for converting to/from
-  // headers, paragraphs, pre, and address.  Those blocks
-  // that pretty much just contain inline things...
-  
-  nsresult res = NS_OK;
-  
-  nsCOMPtr<nsIDOMNode> curBlock, firstNode, lastNode;
-  int32_t listCount = arrayOfNodes.Count();
-  for (int32_t i = 0; i < listCount; ++i) {
-    // get the node to act on, and its location
-    nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
-
-    nsCOMPtr<dom::Element> curElement = do_QueryInterface(curNode);
-
-    // if curNode is a address, p, header, address, or pre, remove it 
-    if (curElement && nsHTMLEditUtils::IsFormatNode(curElement)) {
-      // process any partial progress saved
-      if (curBlock)
-      {
-        res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+  return NS_OK;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// RemoveBlockStyle: Make the nodes have no special block type.
+nsresult
+nsHTMLEditRules::RemoveBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray)
+{
+  NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  // Intent of this routine is to be used for converting to/from headers,
+  // paragraphs, pre, and address.  Those blocks that pretty much just contain
+  // inline things...
+  nsresult res;
+
+  nsCOMPtr<Element> curBlock;
+  nsCOMPtr<nsIContent> firstNode, lastNode;
+  for (auto& curNode : aNodeArray) {
+    // If curNode is a address, p, header, address, or pre, remove it
+    if (nsHTMLEditUtils::IsFormatNode(curNode)) {
+      // Process any partial progress saved
+      if (curBlock) {
+        res = RemovePartOfBlock(*curBlock, *firstNode, *lastNode);
         NS_ENSURE_SUCCESS(res, res);
-        curBlock = 0;  firstNode = 0;  lastNode = 0;
-      }
-      // remove curent block
-      NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->RemoveBlockContainer(curNode); 
+        firstNode = lastNode = curBlock = nullptr;
+      }
+      // Remove current block
+      res = mHTMLEditor->RemoveBlockContainer(curNode->AsDOMNode());
       NS_ENSURE_SUCCESS(res, res);
-    } else if (curElement &&
-               (curElement->IsAnyOfHTMLElements(nsGkAtoms::table,
-                                                nsGkAtoms::tr,
-                                                nsGkAtoms::tbody,
-                                                nsGkAtoms::td,
-                                                nsGkAtoms::li,
-                                                nsGkAtoms::blockquote,
-                                                nsGkAtoms::div) ||
-                nsHTMLEditUtils::IsList(curElement))) {
-      // process any partial progress saved
-      if (curBlock)
-      {
-        res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+    } else if (curNode->IsAnyOfHTMLElements(nsGkAtoms::table,
+                                            nsGkAtoms::tr,
+                                            nsGkAtoms::tbody,
+                                            nsGkAtoms::td,
+                                            nsGkAtoms::li,
+                                            nsGkAtoms::blockquote,
+                                            nsGkAtoms::div) ||
+                nsHTMLEditUtils::IsList(curNode)) {
+      // Process any partial progress saved
+      if (curBlock) {
+        res = RemovePartOfBlock(*curBlock, *firstNode, *lastNode);
         NS_ENSURE_SUCCESS(res, res);
-        curBlock = 0;  firstNode = 0;  lastNode = 0;
-      }
-      // recursion time
-      nsCOMArray<nsIDOMNode> childArray;
-      res = GetChildNodesForOperation(curNode, childArray);
-      NS_ENSURE_SUCCESS(res, res);
+        firstNode = lastNode = curBlock = nullptr;
+      }
+      // Recursion time
+      nsTArray<OwningNonNull<nsINode>> childArray;
+      GetChildNodesForOperation(*curNode, childArray);
       res = RemoveBlockStyle(childArray);
       NS_ENSURE_SUCCESS(res, res);
-    }
-    else if (IsInlineNode(curNode))
-    {
-      if (curBlock)
-      {
-        // if so, is this node a descendant?
-        if (nsEditorUtils::IsDescendantOf(curNode, curBlock))
-        {
-          lastNode = curNode;
-          continue;  // then we don't need to do anything different for this node
+    } else if (IsInlineNode(GetAsDOMNode(curNode))) {
+      if (curBlock) {
+        // If so, is this node a descendant?
+        if (nsEditorUtils::IsDescendantOf(curNode, curBlock)) {
+          // Then we don't need to do anything different for this node
+          lastNode = curNode->AsContent();
+          continue;
+        } else {
+          // Otherwise, we have progressed beyond end of curBlock, so let's
+          // handle it now.  We need to remove the portion of curBlock that
+          // contains [firstNode - lastNode].
+          res = RemovePartOfBlock(*curBlock, *firstNode, *lastNode);
+          NS_ENSURE_SUCCESS(res, res);
+          firstNode = lastNode = curBlock = nullptr;
+          // Fall out and handle curNode
         }
-        else
-        {
-          // otherwise, we have progressed beyond end of curBlock,
-          // so lets handle it now.  We need to remove the portion of 
-          // curBlock that contains [firstNode - lastNode].
-          res = RemovePartOfBlock(curBlock, firstNode, lastNode);
-          NS_ENSURE_SUCCESS(res, res);
-          curBlock = 0;  firstNode = 0;  lastNode = 0;
-          // fall out and handle curNode
-        }
-      }
-      NS_ENSURE_STATE(mHTMLEditor);
+      }
       curBlock = mHTMLEditor->GetBlockNodeParent(curNode);
       if (curBlock && nsHTMLEditUtils::IsFormatNode(curBlock)) {
-        firstNode = curNode;  
-        lastNode = curNode;
-      }
-      else
-        curBlock = 0;  // not a block kind that we care about.
-    }
-    else
-    { // some node that is already sans block style.  skip over it and
-      // process any partial progress saved
-      if (curBlock)
-      {
-        res = RemovePartOfBlock(curBlock, firstNode, lastNode);
-        NS_ENSURE_SUCCESS(res, res);
-        curBlock = 0;  firstNode = 0;  lastNode = 0;
-      }
-    }
-  }
-  // process any partial progress saved
-  if (curBlock)
-  {
-    res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+        firstNode = lastNode = curNode->AsContent();
+      } else {
+        // Not a block kind that we care about.
+        curBlock = nullptr;
+      }
+    } else if (curBlock) {
+      // Some node that is already sans block style.  Skip over it and process
+      // any partial progress saved.
+      res = RemovePartOfBlock(*curBlock, *firstNode, *lastNode);
+      NS_ENSURE_SUCCESS(res, res);
+      firstNode = lastNode = curBlock = nullptr;
+    }
+  }
+  // Process any partial progress saved
+  if (curBlock) {
+    res = RemovePartOfBlock(*curBlock, *firstNode, *lastNode);
     NS_ENSURE_SUCCESS(res, res);
-    curBlock = 0;  firstNode = 0;  lastNode = 0;
-  }
-  return res;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// ApplyBlockStyle:  do whatever it takes to make the list of nodes into 
-//                   one or more blocks of type blockTag.  
-//                       
-nsresult 
-nsHTMLEditRules::ApplyBlockStyle(nsCOMArray<nsIDOMNode>& arrayOfNodes, const nsAString *aBlockTag)
-{
-  // intent of this routine is to be used for converting to/from
-  // headers, paragraphs, pre, and address.  Those blocks
-  // that pretty much just contain inline things...
-  
-  NS_ENSURE_TRUE(aBlockTag, NS_ERROR_NULL_POINTER);
-  nsCOMPtr<nsIAtom> blockTag = do_GetAtom(*aBlockTag);
-  nsresult res = NS_OK;
-  
-  nsCOMPtr<nsINode> curParent;
-  nsCOMPtr<nsIDOMNode> newBlock;
-  int32_t offset;
-  int32_t listCount = arrayOfNodes.Count();
-  nsString tString(*aBlockTag);////MJUDGE SCC NEED HELP
+    firstNode = lastNode = curBlock = nullptr;
+  }
+  return NS_OK;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ApplyBlockStyle: Do whatever it takes to make the list of nodes into one or
+//                  more blocks of type aBlockTag.
+nsresult
+nsHTMLEditRules::ApplyBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray,
+                                 nsIAtom& aBlockTag)
+{
+  // Intent of this routine is to be used for converting to/from headers,
+  // paragraphs, pre, and address.  Those blocks that pretty much just contain
+  // inline things...
+  NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  nsresult res;
 
   // Remove all non-editable nodes.  Leave them be.
-  int32_t j;
-  for (j=listCount-1; j>=0; j--)
-  {
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (!mHTMLEditor->IsEditable(arrayOfNodes[j]))
-    {
-      arrayOfNodes.RemoveObjectAt(j);
-    }
-  }
-  
-  // reset list count
-  listCount = arrayOfNodes.Count();
-  
+  for (int32_t i = aNodeArray.Length() - 1; i >= 0; i--) {
+    if (!mHTMLEditor->IsEditable(aNodeArray[i])) {
+      aNodeArray.RemoveElementAt(i);
+    }
+  }
+
+  nsCOMPtr<Element> newBlock;
+
   nsCOMPtr<Element> curBlock;
-  int32_t i;
-  for (i=0; i<listCount; i++)
-  {
-    // get the node to act on, and its location
-    nsCOMPtr<nsIContent> curNode = do_QueryInterface(arrayOfNodes[i]);
-    NS_ENSURE_STATE(curNode);
-    curParent = curNode->GetParentNode();
-    offset = curParent ? curParent->IndexOf(curNode) : -1;
-    nsAutoString curNodeTag;
-    curNode->NodeInfo()->NameAtom()->ToString(curNodeTag);
-    ToLowerCase(curNodeTag);
- 
-    // is it already the right kind of block?
-    if (curNodeTag == *aBlockTag)
-    {
-      curBlock = 0;  // forget any previous block used for previous inline nodes
-      continue;  // do nothing to this block
-    }
-        
-    // if curNode is a address, p, header, address, or pre, replace 
-    // it with a new block of correct type.
-    // xxx floppy moose: pre can't hold everything the others can
-    if (nsHTMLEditUtils::IsMozDiv(curNode)     ||
-        nsHTMLEditUtils::IsFormatNode(curNode))
-    {
-      curBlock = 0;  // forget any previous block used for previous inline nodes
-      NS_ENSURE_STATE(mHTMLEditor);
-      nsCOMPtr<Element> element = curNode->AsElement();
-      newBlock = dont_AddRef(GetAsDOMNode(
-        mHTMLEditor->ReplaceContainer(element, blockTag, nullptr, nullptr,
-                                      nsEditor::eCloneAttributes).take()));
+  for (auto& curNode : aNodeArray) {
+    nsCOMPtr<nsINode> curParent = curNode->GetParentNode();
+    int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
+
+    // Is it already the right kind of block?
+    if (curNode->IsHTMLElement(&aBlockTag)) {
+      // Forget any previous block used for previous inline nodes
+      curBlock = nullptr;
+      // Do nothing to this block
+      continue;
+    }
+
+    // If curNode is a address, p, header, address, or pre, replace it with a
+    // new block of correct type.
+    // XXX: pre can't hold everything the others can
+    if (nsHTMLEditUtils::IsMozDiv(curNode) ||
+        nsHTMLEditUtils::IsFormatNode(curNode)) {
+      // Forget any previous block used for previous inline nodes
+      curBlock = nullptr;
+      newBlock = mHTMLEditor->ReplaceContainer(curNode->AsElement(),
+                                               &aBlockTag, nullptr, nullptr,
+                                               nsEditor::eCloneAttributes);
       NS_ENSURE_STATE(newBlock);
-    }
-    else if (nsHTMLEditUtils::IsTable(curNode)                    || 
-             (curNodeTag.EqualsLiteral("tbody"))      ||
-             (curNodeTag.EqualsLiteral("tr"))         ||
-             (curNodeTag.EqualsLiteral("td"))         ||
-             nsHTMLEditUtils::IsList(curNode)                     ||
-             (curNodeTag.EqualsLiteral("li"))         ||
-             curNode->IsAnyOfHTMLElements(nsGkAtoms::blockquote,
-                                          nsGkAtoms::div)) {
-      curBlock = 0;  // forget any previous block used for previous inline nodes
-      // recursion time
-      nsCOMArray<nsIDOMNode> childArray;
-      res = GetChildNodesForOperation(GetAsDOMNode(curNode), childArray);
-      NS_ENSURE_SUCCESS(res, res);
-      int32_t childCount = childArray.Count();
-      if (childCount)
-      {
+    } else if (nsHTMLEditUtils::IsTable(curNode) ||
+               nsHTMLEditUtils::IsList(curNode) ||
+               curNode->IsAnyOfHTMLElements(nsGkAtoms::tbody,
+                                            nsGkAtoms::tr,
+                                            nsGkAtoms::td,
+                                            nsGkAtoms::li,
+                                            nsGkAtoms::blockquote,
+                                            nsGkAtoms::div)) {
+      // Forget any previous block used for previous inline nodes
+      curBlock = nullptr;
+      // Recursion time
+      nsTArray<OwningNonNull<nsINode>> childArray;
+      GetChildNodesForOperation(*curNode, childArray);
+      if (childArray.Length()) {
         res = ApplyBlockStyle(childArray, aBlockTag);
         NS_ENSURE_SUCCESS(res, res);
-      }
-      else
-      {
-        // make sure we can put a block here
-        res = SplitAsNeeded(*blockTag, curParent, offset);
+      } else {
+        // Make sure we can put a block here
+        res = SplitAsNeeded(aBlockTag, curParent, offset);
         NS_ENSURE_SUCCESS(res, res);
-        NS_ENSURE_STATE(mHTMLEditor);
         nsCOMPtr<Element> theBlock =
-          mHTMLEditor->CreateNode(blockTag, curParent, offset);
+          mHTMLEditor->CreateNode(&aBlockTag, curParent, offset);
         NS_ENSURE_STATE(theBlock);
-        // remember our new block for postprocessing
+        // Remember our new block for postprocessing
         mNewBlock = theBlock->AsDOMNode();
       }
-    }
-    
-    // if the node is a break, we honor it by putting further nodes in a new parent
-    else if (curNodeTag.EqualsLiteral("br"))
-    {
-      if (curBlock)
-      {
-        curBlock = 0;  // forget any previous block used for previous inline nodes
-        NS_ENSURE_STATE(mHTMLEditor);
+    } else if (curNode->IsHTMLElement(nsGkAtoms::br)) {
+      // If the node is a break, we honor it by putting further nodes in a new
+      // parent
+      if (curBlock) {
+        // Forget any previous block used for previous inline nodes
+        curBlock = nullptr;
         res = mHTMLEditor->DeleteNode(curNode);
         NS_ENSURE_SUCCESS(res, res);
-      }
-      else
-      {
-        // the break is the first (or even only) node we encountered.  Create a
+      } else {
+        // The break is the first (or even only) node we encountered.  Create a
         // block for it.
-        res = SplitAsNeeded(*blockTag, curParent, offset);
+        res = SplitAsNeeded(aBlockTag, curParent, offset);
         NS_ENSURE_SUCCESS(res, res);
-        NS_ENSURE_STATE(mHTMLEditor);
-        curBlock = mHTMLEditor->CreateNode(blockTag, curParent, offset);
+        curBlock = mHTMLEditor->CreateNode(&aBlockTag, curParent, offset);
         NS_ENSURE_STATE(curBlock);
-        // remember our new block for postprocessing
+        // Remember our new block for postprocessing
         mNewBlock = curBlock->AsDOMNode();
-        // note: doesn't matter if we set mNewBlock multiple times.
-        NS_ENSURE_STATE(mHTMLEditor);
-        res = mHTMLEditor->MoveNode(curNode, curBlock, -1);
+        // Note: doesn't matter if we set mNewBlock multiple times.
+        res = mHTMLEditor->MoveNode(curNode->AsContent(), curBlock, -1);
         NS_ENSURE_SUCCESS(res, res);
       }
-        
-    
-    // if curNode is inline, pull it into curBlock
-    // note: it's assumed that consecutive inline nodes in the 
-    // arrayOfNodes are actually members of the same block parent.
-    // this happens to be true now as a side effect of how
-    // arrayOfNodes is contructed, but some additional logic should
-    // be added here if that should change
-    
     } else if (IsInlineNode(GetAsDOMNode(curNode))) {
-      // if curNode is a non editable, drop it if we are going to <pre>
-      NS_ENSURE_STATE(mHTMLEditor);
-      if (tString.LowerCaseEqualsLiteral("pre") 
-        && (!mHTMLEditor->IsEditable(curNode)))
-        continue; // do nothing to this block
-      
-      // if no curBlock, make one
-      if (!curBlock)
-      {
-        res = SplitAsNeeded(*blockTag, curParent, offset);
+      // If curNode is inline, pull it into curBlock.  Note: it's assumed that
+      // consecutive inline nodes in aNodeArray are actually members of the
+      // same block parent.  This happens to be true now as a side effect of
+      // how aNodeArray is contructed, but some additional logic should be
+      // added here if that should change
+      //
+      // If curNode is a non editable, drop it if we are going to <pre>.
+      if (&aBlockTag == nsGkAtoms::pre && !mHTMLEditor->IsEditable(curNode)) {
+        // Do nothing to this block
+        continue;
+      }
+
+      // If no curBlock, make one
+      if (!curBlock) {
+        res = SplitAsNeeded(aBlockTag, curParent, offset);
         NS_ENSURE_SUCCESS(res, res);
-        NS_ENSURE_STATE(mHTMLEditor);
-        curBlock = mHTMLEditor->CreateNode(blockTag, curParent, offset);
+        curBlock = mHTMLEditor->CreateNode(&aBlockTag, curParent, offset);
         NS_ENSURE_STATE(curBlock);
-        // remember our new block for postprocessing
+        // Remember our new block for postprocessing
         mNewBlock = curBlock->AsDOMNode();
-        // note: doesn't matter if we set mNewBlock multiple times.
-      }
-      
-      // if curNode is a Break, replace it with a return if we are going to <pre>
-      // xxx floppy moose
- 
-      // this is a continuation of some inline nodes that belong together in
-      // the same block item.  use curBlock
-      NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->MoveNode(curNode, curBlock, -1);
+        // Note: doesn't matter if we set mNewBlock multiple times.
+      }
+
+      // XXX If curNode is a br, replace it with a return if going to <pre>
+
+      // This is a continuation of some inline nodes that belong together in
+      // the same block item.  Use curBlock.
+      res = mHTMLEditor->MoveNode(curNode->AsContent(), curBlock, -1);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
-  return res;
+  return NS_OK;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
 // SplitAsNeeded: Given a tag name, split inOutParent up to the point where we
 //                can insert the tag.  Adjust inOutParent and inOutOffset to
 //                point to new location for tag.
 nsresult
@@ -7592,50 +7275,36 @@ nsHTMLEditRules::ClearCachedStyles()
   // clear the mPresent bits in mCachedStyles array
   for (uint32_t j = 0; j < SIZE_STYLE_TABLE; j++) {
     mCachedStyles[j].mPresent = false;
     mCachedStyles[j].value.Truncate();
   }
 }
 
 
-nsresult 
-nsHTMLEditRules::AdjustSpecialBreaks(bool aSafeToAskFrames)
-{
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
-  nsCOMPtr<nsISupports> isupports;
-  int32_t nodeCount,j;
-  
-  // gather list of empty nodes
-  NS_ENSURE_STATE(mHTMLEditor);
+void
+nsHTMLEditRules::AdjustSpecialBreaks()
+{
+  NS_ENSURE_TRUE(mHTMLEditor, );
+
+  // Gather list of empty nodes
+  nsTArray<OwningNonNull<nsINode>> nodeArray;
   nsEmptyEditableFunctor functor(mHTMLEditor);
-  nsDOMIterator iter;
-  nsresult res = iter.Init(mDocChangeRange);
-  NS_ENSURE_SUCCESS(res, res);
-  res = iter.AppendList(functor, arrayOfNodes);
-  NS_ENSURE_SUCCESS(res, res);
-
-  // put moz-br's into these empty li's and td's
-  nodeCount = arrayOfNodes.Count();
-  for (j = 0; j < nodeCount; j++)
-  {
-    // need to put br at END of node.  It may have
-    // empty containers in it and still pass the "IsEmptynode" test,
-    // and we want the br's to be after them.  Also, we want the br
-    // to be after the selection if the selection is in this node.
-    uint32_t len;
-    nsCOMPtr<nsIDOMNode> theNode = arrayOfNodes[0];
-    arrayOfNodes.RemoveObjectAt(0);
-    res = nsEditor::GetLengthOfDOMNode(theNode, len);
-    NS_ENSURE_SUCCESS(res, res);
-    res = CreateMozBR(theNode, (int32_t)len);
-    NS_ENSURE_SUCCESS(res, res);
-  }
-  
-  return res;
+  nsDOMIterator iter(*mDocChangeRange);
+  iter.AppendList(functor, nodeArray);
+
+  // Put moz-br's into these empty li's and td's
+  for (auto& node : nodeArray) {
+    // Need to put br at END of node.  It may have empty containers in it and
+    // still pass the "IsEmptyNode" test, and we want the br's to be after
+    // them.  Also, we want the br to be after the selection if the selection
+    // is in this node.
+    nsresult res = CreateMozBR(node->AsDOMNode(), (int32_t)node->Length());
+    NS_ENSURE_SUCCESS(res, );
+  }
 }
 
 nsresult 
 nsHTMLEditRules::AdjustWhitespace(Selection* aSelection)
 {
   // get selection point
   nsCOMPtr<nsIDOMNode> selNode;
   int32_t selOffset;
@@ -8031,163 +7700,149 @@ nsHTMLEditRules::InDifferentTableElement
   while (aNode2 && !nsHTMLEditUtils::IsTableElement(aNode2)) {
     aNode2 = aNode2->GetParentNode();
   }
 
   return aNode1 != aNode2;
 }
 
 
-nsresult 
+nsresult
 nsHTMLEditRules::RemoveEmptyNodes()
 {
-  // some general notes on the algorithm used here: the goal is to examine all the
-  // nodes in mDocChangeRange, and remove the empty ones.  We do this by using a
-  // content iterator to traverse all the nodes in the range, and placing the empty
-  // nodes into an array.  After finishing the iteration, we delete the empty nodes
-  // in the array.  (they cannot be deleted as we find them becasue that would 
-  // invalidate the iterator.)  
+  NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  // Some general notes on the algorithm used here: the goal is to examine all
+  // the nodes in mDocChangeRange, and remove the empty ones.  We do this by
+  // using a content iterator to traverse all the nodes in the range, and
+  // placing the empty nodes into an array.  After finishing the iteration, we
+  // delete the empty nodes in the array.  (They cannot be deleted as we find
+  // them because that would invalidate the iterator.)
+  //
   // Since checking to see if a node is empty can be costly for nodes with many
-  // descendants, there are some optimizations made.  I rely on the fact that the
-  // iterator is post-order: it will visit children of a node before visiting the 
-  // parent node.  So if I find that a child node is not empty, I know that its
-  // parent is not empty without even checking.  So I put the parent on a "skipList"
-  // which is just a voidArray of nodes I can skip the empty check on.  If I 
-  // encounter a node on the skiplist, i skip the processing for that node and replace
-  // its slot in the skiplist with that node's parent.
-  // An interseting idea is to go ahead and regard parent nodes that are NOT on the
-  // skiplist as being empty (without even doing the IsEmptyNode check) on the theory
-  // that if they weren't empty, we would have encountered a non-empty child earlier
-  // and thus put this parent node on the skiplist.
-  // Unfortunately I can't use that strategy here, because the range may include 
-  // some children of a node while excluding others.  Thus I could find all the 
-  // _examined_ children empty, but still not have an empty parent.
-  
+  // descendants, there are some optimizations made.  I rely on the fact that
+  // the iterator is post-order: it will visit children of a node before
+  // visiting the parent node.  So if I find that a child node is not empty, I
+  // know that its parent is not empty without even checking.  So I put the
+  // parent on a "skipList" which is just a voidArray of nodes I can skip the
+  // empty check on.  If I encounter a node on the skiplist, i skip the
+  // processing for that node and replace its slot in the skiplist with that
+  // node's parent.
+  //
+  // An interesting idea is to go ahead and regard parent nodes that are NOT on
+  // the skiplist as being empty (without even doing the IsEmptyNode check) on
+  // the theory that if they weren't empty, we would have encountered a
+  // non-empty child earlier and thus put this parent node on the skiplist.
+  //
+  // Unfortunately I can't use that strategy here, because the range may
+  // include some children of a node while excluding others.  Thus I could find
+  // all the _examined_ children empty, but still not have an empty parent.
+
   // need an iterator
-  nsCOMPtr<nsIContentIterator> iter =
-                  do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
-  NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
-  
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+
   nsresult res = iter->Init(mDocChangeRange);
   NS_ENSURE_SUCCESS(res, res);
-  
-  nsCOMArray<nsINode> arrayOfEmptyNodes, arrayOfEmptyCites;
-  nsTArray<nsCOMPtr<nsINode> > skipList;
-
-  // check for empty nodes
+
+  nsTArray<OwningNonNull<nsINode>> arrayOfEmptyNodes, arrayOfEmptyCites, skipList;
+
+  // Check for empty nodes
   while (!iter->IsDone()) {
-    nsINode* node = iter->GetCurrentNode();
-    NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
-
-    nsINode* parent = node->GetParentNode();
+    OwningNonNull<nsINode> node = *iter->GetCurrentNode();
+
+    nsCOMPtr<nsINode> parent = node->GetParentNode();
 
     size_t idx = skipList.IndexOf(node);
     if (idx != skipList.NoIndex) {
-      // this node is on our skip list.  Skip processing for this node, 
-      // and replace its value in the skip list with the value of its parent
+      // This node is on our skip list.  Skip processing for this node, and
+      // replace its value in the skip list with the value of its parent
       skipList[idx] = parent;
     } else {
       bool bIsCandidate = false;
       bool bIsEmptyNode = false;
       bool bIsMailCite = false;
 
       if (node->IsElement()) {
-        dom::Element* element = node->AsElement();
-        if (element->IsHTMLElement(nsGkAtoms::body)) {
-          // don't delete the body
-        } else if ((bIsMailCite = nsHTMLEditUtils::IsMailCite(element))  ||
-                   element->IsHTMLElement(nsGkAtoms::a)                  ||
-                   nsHTMLEditUtils::IsInlineStyle(element)               ||
-                   nsHTMLEditUtils::IsList(element)                      ||
-                   element->IsHTMLElement(nsGkAtoms::div)) {
-          // only consider certain nodes to be empty for purposes of removal
+        if (node->IsHTMLElement(nsGkAtoms::body)) {
+          // Don't delete the body
+        } else if ((bIsMailCite = nsHTMLEditUtils::IsMailCite(node)) ||
+                   node->IsHTMLElement(nsGkAtoms::a) ||
+                   nsHTMLEditUtils::IsInlineStyle(node) ||
+                   nsHTMLEditUtils::IsList(node) ||
+                   node->IsHTMLElement(nsGkAtoms::div)) {
+          // Only consider certain nodes to be empty for purposes of removal
           bIsCandidate = true;
-        } else if (nsHTMLEditUtils::IsFormatNode(element) ||
-                   nsHTMLEditUtils::IsListItem(element)   ||
-                   element->IsHTMLElement(nsGkAtoms::blockquote)) {
-          // these node types are candidates if selection is not in them
-          // if it is one of these, don't delete if selection inside.
-          // this is so we can create empty headings, etc, for the
-          // user to type into.
+        } else if (nsHTMLEditUtils::IsFormatNode(node) ||
+                   nsHTMLEditUtils::IsListItem(node) ||
+                   node->IsHTMLElement(nsGkAtoms::blockquote)) {
+          // These node types are candidates if selection is not in them.  If
+          // it is one of these, don't delete if selection inside.  This is so
+          // we can create empty headings, etc., for the user to type into.
           bool bIsSelInNode;
           res = SelectionEndpointInNode(node, &bIsSelInNode);
           NS_ENSURE_SUCCESS(res, res);
-          if (!bIsSelInNode)
-          {
+          if (!bIsSelInNode) {
             bIsCandidate = true;
           }
         }
       }
-      
+
       if (bIsCandidate) {
-        // we delete mailcites even if they have a solo br in them
-        // other nodes we require to be empty
-        NS_ENSURE_STATE(mHTMLEditor);
+        // We delete mailcites even if they have a solo br in them.  Other
+        // nodes we require to be empty.
         res = mHTMLEditor->IsEmptyNode(node->AsDOMNode(), &bIsEmptyNode,
                                        bIsMailCite, true);
         NS_ENSURE_SUCCESS(res, res);
         if (bIsEmptyNode) {
           if (bIsMailCite) {
             // mailcites go on a separate list from other empty nodes
-            arrayOfEmptyCites.AppendObject(node);
+            arrayOfEmptyCites.AppendElement(*node);
           } else {
-            arrayOfEmptyNodes.AppendObject(node);
+            arrayOfEmptyNodes.AppendElement(*node);
           }
         }
       }
-      
+
       if (!bIsEmptyNode) {
         // put parent on skip list
-        skipList.AppendElement(parent);
+        skipList.AppendElement(*parent);
       }
     }
 
     iter->Next();
   }
-  
+
   // now delete the empty nodes
-  int32_t nodeCount = arrayOfEmptyNodes.Count();
-  for (int32_t j = 0; j < nodeCount; j++) {
-    nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyNodes[0]->AsDOMNode();
-    arrayOfEmptyNodes.RemoveObjectAt(0);
-    NS_ENSURE_STATE(mHTMLEditor);
+  for (auto& delNode : arrayOfEmptyNodes) {
     if (mHTMLEditor->IsModifiableNode(delNode)) {
-      NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->DeleteNode(delNode);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
-  
-  // now delete the empty mailcites
-  // this is a separate step because we want to pull out any br's and preserve them.
-  nodeCount = arrayOfEmptyCites.Count();
-  for (int32_t j = 0; j < nodeCount; j++) {
-    nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyCites[0]->AsDOMNode();
-    arrayOfEmptyCites.RemoveObjectAt(0);
+
+  // Now delete the empty mailcites.  This is a separate step because we want
+  // to pull out any br's and preserve them.
+  for (auto& delNode : arrayOfEmptyCites) {
     bool bIsEmptyNode;
-    NS_ENSURE_STATE(mHTMLEditor);
     res = mHTMLEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true);
     NS_ENSURE_SUCCESS(res, res);
-    if (!bIsEmptyNode)
-    {
-      // we are deleting a cite that has just a br.  We want to delete cite, 
+    if (!bIsEmptyNode) {
+      // We are deleting a cite that has just a br.  We want to delete cite,
       // but preserve br.
-      nsCOMPtr<nsIDOMNode> parent, brNode;
-      int32_t offset;
-      parent = nsEditor::GetNodeLocation(delNode, &offset);
-      NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->CreateBR(parent, offset, address_of(brNode));
-      NS_ENSURE_SUCCESS(res, res);
-    }
-    NS_ENSURE_STATE(mHTMLEditor);
+      nsCOMPtr<nsINode> parent = delNode->GetParentNode();
+      int32_t offset = parent ? parent->IndexOf(delNode) : -1;
+      nsCOMPtr<Element> br = mHTMLEditor->CreateBR(parent, offset);
+      NS_ENSURE_STATE(br);
+    }
     res = mHTMLEditor->DeleteNode(delNode);
     NS_ENSURE_SUCCESS(res, res);
   }
-  
-  return res;
+
+  return NS_OK;
 }
 
 nsresult
 nsHTMLEditRules::SelectionEndpointInNode(nsINode* aNode, bool* aResult)
 {
   NS_ENSURE_TRUE(aNode && aResult, NS_ERROR_NULL_POINTER);
 
   nsIDOMNode* node = aNode->AsDOMNode();
@@ -8245,43 +7900,43 @@ nsHTMLEditRules::IsEmptyInline(nsIDOMNod
     NS_ENSURE_TRUE(mHTMLEditor, false);
     mHTMLEditor->IsEmptyNode(aNode, &bEmpty);
     return bEmpty;
   }
   return false;
 }
 
 
-bool 
-nsHTMLEditRules::ListIsEmptyLine(nsCOMArray<nsIDOMNode> &arrayOfNodes)
-{
-  // we have a list of nodes which we are candidates for being moved
-  // into a new block.  Determine if it's anything more than a blank line.
-  // Look for editable content above and beyond one single BR.
-  int32_t listCount = arrayOfNodes.Count();
-  NS_ENSURE_TRUE(listCount, true);
-  nsCOMPtr<nsIDOMNode> somenode;
-  int32_t j, brCount=0;
-  for (j = 0; j < listCount; j++)
-  {
-    somenode = arrayOfNodes[j];
-    NS_ENSURE_TRUE(mHTMLEditor, false);
-    if (somenode && mHTMLEditor->IsEditable(somenode))
-    {
-      if (nsTextEditUtils::IsBreak(somenode))
-      {
-        // first break doesn't count
-        if (brCount) return false;
-        brCount++;
-      }
-      else if (IsEmptyInline(somenode)) 
-      {
-        // empty inline, keep looking
-      }
-      else return false;
+bool
+nsHTMLEditRules::ListIsEmptyLine(nsTArray<OwningNonNull<nsINode>>& aArrayOfNodes)
+{
+  // We have a list of nodes which we are candidates for being moved into a new
+  // block.  Determine if it's anything more than a blank line.  Look for
+  // editable content above and beyond one single BR.
+  NS_ENSURE_TRUE(aArrayOfNodes.Length(), true);
+
+  NS_ENSURE_TRUE(mHTMLEditor, false);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  int32_t brCount = 0;
+
+  for (auto& node : aArrayOfNodes) {
+    if (!mHTMLEditor->IsEditable(node)) {
+      continue;
+    }
+    if (nsTextEditUtils::IsBreak(node)) {
+      // First break doesn't count
+      if (brCount) {
+        return false;
+      }
+      brCount++;
+    } else if (IsEmptyInline(GetAsDOMNode(node))) {
+      // Empty inline, keep looking
+    } else {
+      return false;
     }
   }
   return true;
 }
 
 
 nsresult 
 nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, bool *aOutOfList)
@@ -9074,22 +8729,21 @@ nsHTMLEditRules::WillAbsolutePosition(Se
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
   
   // convert the selection ranges into "promoted" selection ranges:
   // this basically just expands the range to include the immediate
   // block parent, and then further expands to include any ancestors
   // whose children are all in the range
   
   nsTArray<nsRefPtr<nsRange>> arrayOfRanges;
-  res = GetPromotedRanges(aSelection, arrayOfRanges,
-                          EditAction::setAbsolutePosition);
-  NS_ENSURE_SUCCESS(res, res);
+  GetPromotedRanges(*aSelection, arrayOfRanges,
+                    EditAction::setAbsolutePosition);
   
   // use these ranges to contruct a list of nodes to act on.
-  nsCOMArray<nsIDOMNode> arrayOfNodes;
+  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
   res = GetNodesForOperation(arrayOfRanges, arrayOfNodes,
                              EditAction::setAbsolutePosition);
   NS_ENSURE_SUCCESS(res, res);                                 
                                      
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes))
   {
     // get selection location
@@ -9103,43 +8757,39 @@ nsHTMLEditRules::WillAbsolutePosition(Se
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<Element> thePositionedDiv =
       mHTMLEditor->CreateNode(nsGkAtoms::div, parent, offset);
     NS_ENSURE_STATE(thePositionedDiv);
     // remember our new block for postprocessing
     mNewBlock = thePositionedDiv->AsDOMNode();
     // delete anything that was in the list of nodes
-    for (int32_t j = arrayOfNodes.Count() - 1; j >= 0; --j) 
-    {
-      nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[0];
+    while (!arrayOfNodes.IsEmpty()) {
+      OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->DeleteNode(curNode);
       NS_ENSURE_SUCCESS(res, res);
-      arrayOfNodes.RemoveObjectAt(0);
+      arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     res = aSelection->Collapse(thePositionedDiv,0);
     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
     *aHandled = true;
     return res;
   }
 
   // Ok, now go through all the nodes and put them in a blockquote, 
   // or whatever is appropriate.  Wohoo!
-  int32_t i;
   nsCOMPtr<nsINode> curParent;
   nsCOMPtr<nsIDOMNode> indentedLI, sibling;
   nsCOMPtr<Element> curList, curPositionedDiv;
-  int32_t listCount = arrayOfNodes.Count();
-  for (i=0; i<listCount; i++)
-  {
+  for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) {
     // here's where we actually figure out what to do
-    nsCOMPtr<nsIContent> curNode = do_QueryInterface(arrayOfNodes[i]);
-    NS_ENSURE_STATE(curNode);
+    NS_ENSURE_STATE(arrayOfNodes[i]->IsContent());
+    nsCOMPtr<nsIContent> curNode = arrayOfNodes[i]->AsContent();
 
     // Ignore all non-editable nodes.  Leave them be.
     NS_ENSURE_STATE(mHTMLEditor);
     if (!mHTMLEditor->IsEditable(curNode)) continue;
 
     curParent = curNode->GetParentNode();
     int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
      
--- a/editor/libeditor/nsHTMLEditRules.h
+++ b/editor/libeditor/nsHTMLEditRules.h
@@ -32,17 +32,16 @@ class nsRange;
 class nsRulesInfo;
 namespace mozilla {
 namespace dom {
 class Element;
 class Selection;
 }  // namespace dom
 }  // namespace mozilla
 struct DOMPoint;
-template <class E> class nsCOMArray;
 
 struct StyleCache : public PropItem
 {
   bool mPresent;
   
   StyleCache() : PropItem(), mPresent(false) {
     MOZ_COUNT_CTOR(StyleCache);
   }
@@ -186,24 +185,27 @@ protected:
                                const nsAString* aBlockType, bool aEntireList,
                                bool* aCancel, bool* aHandled);
   nsresult WillMakeBasicBlock(mozilla::dom::Selection* aSelection,
                               const nsAString* aBlockType,
                               bool* aCancel, bool* aHandled);
   nsresult DidMakeBasicBlock(mozilla::dom::Selection* aSelection,
                              nsRulesInfo* aInfo, nsresult aResult);
   nsresult DidAbsolutePosition();
-  nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType);
+  nsresult AlignInnerBlocks(nsINode& aNode, const nsAString* alignType);
   nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType);
-  nsresult AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
+  nsresult AppendInnerFormatNodes(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aArray,
                                   nsINode* aNode);
-  nsresult AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
-                                  nsIDOMNode *aNode);
   nsresult GetFormatString(nsIDOMNode *aNode, nsAString &outFormat);
-  nsresult GetInnerContent(nsIDOMNode *aNode, nsCOMArray<nsIDOMNode>& outArrayOfNodes, int32_t *aIndex, bool aList = true, bool aTble = true);
+  enum class Lists { no, yes };
+  enum class Tables { no, yes };
+  void GetInnerContent(nsINode& aNode,
+                       nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aOutArrayOfNodes,
+                       int32_t* aIndex, Lists aLists = Lists::yes,
+                       Tables aTables = Tables::yes);
   already_AddRefed<nsIDOMNode> IsInListItem(nsIDOMNode* aNode);
   mozilla::dom::Element* IsInListItem(nsINode* aNode);
   nsresult ReturnInHeader(mozilla::dom::Selection* aSelection,
                           nsIDOMNode* aHeader, nsIDOMNode* aTextNode,
                           int32_t aOffset);
   nsresult ReturnInParagraph(mozilla::dom::Selection* aSelection,
                              nsIDOMNode* aHeader, nsIDOMNode* aTextNode,
                              int32_t aOffset, bool* aCancel, bool* aHandled);
@@ -212,21 +214,19 @@ protected:
                           mozilla::dom::Selection* aSelection,
                           nsCOMPtr<nsIDOMNode> *aSelNode, 
                           int32_t *aOffset);
   nsresult ReturnInListItem(mozilla::dom::Selection* aSelection,
                             nsIDOMNode* aHeader, nsIDOMNode* aTextNode,
                             int32_t aOffset);
   nsresult AfterEditInner(EditAction action,
                           nsIEditor::EDirection aDirection);
-  nsresult RemovePartOfBlock(nsIDOMNode *aBlock, 
-                             nsIDOMNode *aStartChild, 
-                             nsIDOMNode *aEndChild,
-                             nsCOMPtr<nsIDOMNode> *aLeftNode = 0,
-                             nsCOMPtr<nsIDOMNode> *aRightNode = 0);
+  nsresult RemovePartOfBlock(mozilla::dom::Element& aBlock,
+                             nsIContent& aStartChild,
+                             nsIContent& aEndChild);
   nsresult SplitBlock(nsIDOMNode *aBlock, 
                       nsIDOMNode *aStartChild, 
                       nsIDOMNode *aEndChild,
                       nsCOMPtr<nsIDOMNode> *aLeftNode = 0,
                       nsCOMPtr<nsIDOMNode> *aRightNode = 0,
                       nsCOMPtr<nsIDOMNode> *aMiddleNode = 0);
   nsresult OutdentPartOfBlock(nsIDOMNode *aBlock, 
                               nsIDOMNode *aStartChild, 
@@ -258,58 +258,65 @@ protected:
                                nsCOMPtr<nsIDOMNode> *outBRNode, int32_t aOffset=0);
   nsresult ExpandSelectionForDeletion(mozilla::dom::Selection* aSelection);
   bool IsFirstNode(nsIDOMNode *aNode);
   bool IsLastNode(nsIDOMNode *aNode);
   nsresult NormalizeSelection(mozilla::dom::Selection* aSelection);
   void GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode,
                         int32_t aOffset, EditAction actionID,
                         nsCOMPtr<nsIDOMNode>* outNode, int32_t* outOffset);
-  nsresult GetPromotedRanges(mozilla::dom::Selection* aSelection, 
-                             nsTArray<nsRefPtr<nsRange>>& outArrayOfRanges,
-                             EditAction inOperationType);
-  nsresult PromoteRange(nsRange* inRange, EditAction inOperationType);
-  nsresult GetNodesForOperation(nsTArray<nsRefPtr<nsRange>>& inArrayOfRanges, 
-                                nsCOMArray<nsIDOMNode>& outArrayOfNodes, 
-                                EditAction inOperationType,
-                                bool aDontTouchContent=false);
-  nsresult GetChildNodesForOperation(nsIDOMNode *inNode, 
-                                     nsCOMArray<nsIDOMNode>& outArrayOfNodes);
-  nsresult GetNodesFromPoint(::DOMPoint point,
-                             EditAction operation,
-                             nsCOMArray<nsIDOMNode>& arrayOfNodes,
-                             bool dontTouchContent);
-  nsresult GetNodesFromSelection(mozilla::dom::Selection* selection,
-                                 EditAction operation,
-                                 nsCOMArray<nsIDOMNode>& arrayOfNodes,
-                                 bool aDontTouchContent=false);
-  nsresult GetListActionNodes(nsCOMArray<nsIDOMNode> &outArrayOfNodes, bool aEntireList, bool aDontTouchContent=false);
+  void GetPromotedRanges(mozilla::dom::Selection& aSelection, 
+                         nsTArray<nsRefPtr<nsRange>>& outArrayOfRanges,
+                         EditAction inOperationType);
+  void PromoteRange(nsRange& aRange, EditAction inOperationType);
+  enum class TouchContent { no, yes };
+  nsresult GetNodesForOperation(nsTArray<nsRefPtr<nsRange>>& aArrayOfRanges,
+                                nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aOutArrayOfNodes,
+                                EditAction aOperationType,
+                                TouchContent aTouchContent = TouchContent::yes);
+  void GetChildNodesForOperation(nsINode& aNode,
+      nsTArray<mozilla::dom::OwningNonNull<nsINode>>& outArrayOfNodes);
+  nsresult GetNodesFromPoint(::DOMPoint aPoint,
+                             EditAction aOperation,
+                             nsTArray<mozilla::dom::OwningNonNull<nsINode>>& outArrayOfNodes,
+                             TouchContent aTouchContent);
+  nsresult GetNodesFromSelection(mozilla::dom::Selection& aSelection,
+                                 EditAction aOperation,
+                                 nsTArray<mozilla::dom::OwningNonNull<nsINode>>& outArrayOfNodes,
+                                 TouchContent aTouchContent = TouchContent::yes);
+  enum class EntireList { no, yes };
+  nsresult GetListActionNodes(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aOutArrayOfNodes,
+                              EntireList aEntireList,
+                              TouchContent aTouchContent = TouchContent::yes);
   void GetDefinitionListItemTypes(mozilla::dom::Element* aElement, bool* aDT, bool* aDD);
-  nsresult GetParagraphFormatNodes(nsCOMArray<nsIDOMNode>& outArrayOfNodes, bool aDontTouchContent=false);
-  nsresult LookInsideDivBQandList(nsCOMArray<nsIDOMNode>& aNodeArray);
+  nsresult GetParagraphFormatNodes(
+      nsTArray<mozilla::dom::OwningNonNull<nsINode>>& outArrayOfNodes,
+      TouchContent aTouchContent = TouchContent::yes);
+  void LookInsideDivBQandList(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeArray);
   nsresult BustUpInlinesAtRangeEndpoints(nsRangeStore &inRange);
-  nsresult BustUpInlinesAtBRs(nsIDOMNode *inNode, 
-                              nsCOMArray<nsIDOMNode>& outArrayOfNodes);
+  nsresult BustUpInlinesAtBRs(nsINode& aNode,
+                              nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aOutArrayOfNodes);
   nsCOMPtr<nsIDOMNode> GetHighestInlineParent(nsIDOMNode* aNode);
-  nsresult MakeTransitionList(nsCOMArray<nsIDOMNode>& inArrayOfNodes, 
-                              nsTArray<bool> &inTransitionArray);
-  nsresult RemoveBlockStyle(nsCOMArray<nsIDOMNode>& arrayOfNodes);
-  nsresult ApplyBlockStyle(nsCOMArray<nsIDOMNode>& arrayOfNodes, const nsAString *aBlockTag);
-  nsresult MakeBlockquote(nsCOMArray<nsIDOMNode>& arrayOfNodes);
+  void MakeTransitionList(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeArray,
+                          nsTArray<bool>& aTransitionArray);
+  nsresult RemoveBlockStyle(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeArray);
+  nsresult ApplyBlockStyle(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeArray,
+                           nsIAtom& aBlockTag);
+  nsresult MakeBlockquote(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeArray);
   nsresult SplitAsNeeded(nsIAtom& aTag, nsCOMPtr<nsINode>& inOutParent,
                          int32_t& inOutOffset);
   nsresult AddTerminatingBR(nsIDOMNode *aBlock);
   ::DOMPoint JoinNodesSmart(nsIContent& aNodeLeft, nsIContent& aNodeRight);
   mozilla::dom::Element* GetTopEnclosingMailCite(nsINode& aNode);
   nsresult PopListItem(nsIDOMNode *aListItem, bool *aOutOfList);
   nsresult RemoveListStructure(nsIDOMNode *aList);
   nsresult CacheInlineStyles(nsIDOMNode *aNode);
   nsresult ReapplyCachedStyles();
   void ClearCachedStyles();
-  nsresult AdjustSpecialBreaks(bool aSafeToAskFrames = false);
+  void AdjustSpecialBreaks();
   nsresult AdjustWhitespace(mozilla::dom::Selection* aSelection);
   nsresult PinSelectionToNewBlock(mozilla::dom::Selection* aSelection);
   nsresult CheckInterlinePosition(mozilla::dom::Selection* aSelection);
   nsresult AdjustSelection(mozilla::dom::Selection* aSelection,
                            nsIEditor::EDirection aAction);
   nsresult FindNearSelectableNode(nsIDOMNode *aSelNode, 
                                   int32_t aSelOffset, 
                                   nsIEditor::EDirection &aDirection,
@@ -324,17 +331,17 @@ protected:
   bool     InDifferentTableElements(nsIDOMNode* aNode1, nsIDOMNode* aNode2);
   bool     InDifferentTableElements(nsINode* aNode1, nsINode* aNode2);
   nsresult RemoveEmptyNodes();
   nsresult SelectionEndpointInNode(nsINode *aNode, bool *aResult);
   nsresult UpdateDocChangeRange(nsRange* aRange);
   nsresult ConfirmSelectionInBody();
   nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode);
   bool     IsEmptyInline(nsIDOMNode *aNode);
-  bool     ListIsEmptyLine(nsCOMArray<nsIDOMNode> &arrayOfNodes);
+  bool     ListIsEmptyLine(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& arrayOfNodes);
   nsresult RemoveAlignment(nsIDOMNode * aNode, const nsAString & aAlignType, bool aChildrenOnly);
   nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode, bool aStarts);
   nsresult AlignBlock(nsIDOMElement * aElement, const nsAString * aAlignType, bool aContentsOnly);
   nsresult RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, int8_t aRelativeChange);
   void DocumentModifiedWorker();
 
 // data members
 protected:
--- a/editor/libeditor/nsHTMLEditor.cpp
+++ b/editor/libeditor/nsHTMLEditor.cpp
@@ -190,17 +190,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBottomRightHandle)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActivatedHandle)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResizingShadow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResizingInfo)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResizedObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMouseMotionListenerP)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionListenerP)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResizeEventListenerP)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(objectResizeEventListeners)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectResizeEventListeners)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAbsolutelyPositionedObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGrabber)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPositioningShadow)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineEditedCell)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAddColumnBeforeButton)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRemoveColumnButton)
@@ -2983,18 +2983,16 @@ nsHTMLEditor::GetStyleSheetForURL(const 
 NS_IMETHODIMP
 nsHTMLEditor::GetURLForStyleSheet(CSSStyleSheet* aStyleSheet,
                                   nsAString &aURL)
 {
   // is it already in the list?
   int32_t foundIndex = mStyleSheets.IndexOf(aStyleSheet);
 
   // Don't fail if we don't find it in our list
-  // Note: mStyleSheets is nsCOMArray, so its IndexOf() method
-  // returns -1 on failure.
   if (foundIndex == -1)
     return NS_OK;
 
   // Found it in the list!
   aURL = mStyleSheetURLs[foundIndex];
   return NS_OK;
 }
 
@@ -4498,206 +4496,166 @@ nsHTMLEditor::SetIsCSSEnabled(bool aIsCS
 
   return SetFlags(flags);
 }
 
 // Set the block background color
 nsresult
 nsHTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
 {
-  if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
+  NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
   ForceCompositionEnd();
 
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
 
   nsRefPtr<Selection> selection = GetSelection();
+  NS_ENSURE_STATE(selection);
 
   bool isCollapsed = selection->Collapsed();
 
   nsAutoEditBatch batchIt(this);
-  nsAutoRules beginRulesSniffing(this, EditAction::insertElement, nsIEditor::eNext);
+  nsAutoRules beginRulesSniffing(this, EditAction::insertElement,
+                                 nsIEditor::eNext);
   nsAutoSelectionReset selectionResetter(selection, this);
   nsAutoTxnsConserveSelection dontSpazMySelection(this);
-  
+
   bool cancel, handled;
   nsTextRulesInfo ruleInfo(EditAction::setTextProperty);
   nsresult res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   NS_ENSURE_SUCCESS(res, res);
-  if (!cancel && !handled)
-  {
-    // loop thru the ranges in the selection
-    nsAutoString bgcolor; bgcolor.AssignLiteral("bgcolor");
-    uint32_t rangeCount = selection->RangeCount();
-    for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
-      nsCOMPtr<nsIDOMNode> cachedBlockParent = nullptr;
-      nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
+  if (!cancel && !handled) {
+    // Loop through the ranges in the selection
+    NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor");
+    for (uint32_t i = 0; i < selection->RangeCount(); i++) {
+      nsRefPtr<nsRange> range = selection->GetRangeAt(i);
       NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
-      
-      // check for easy case: both range endpoints in same text node
-      nsCOMPtr<nsIDOMNode> startNode, endNode;
-      int32_t startOffset, endOffset;
-      res = range->GetStartContainer(getter_AddRefs(startNode));
-      NS_ENSURE_SUCCESS(res, res);
-      res = range->GetEndContainer(getter_AddRefs(endNode));
-      NS_ENSURE_SUCCESS(res, res);
-      res = range->GetStartOffset(&startOffset);
-      NS_ENSURE_SUCCESS(res, res);
-      res = range->GetEndOffset(&endOffset);
-      NS_ENSURE_SUCCESS(res, res);
-      if ((startNode == endNode) && IsTextNode(startNode))
-      {
-        // let's find the block container of the text node
-        nsCOMPtr<nsIDOMNode> blockParent;
-        blockParent = GetBlockNodeParent(startNode);
-        // and apply the background color to that block container
+
+      nsCOMPtr<Element> cachedBlockParent;
+
+      // Check for easy case: both range endpoints in same text node
+      nsCOMPtr<nsINode> startNode = range->GetStartParent();
+      int32_t startOffset = range->StartOffset();
+      nsCOMPtr<nsINode> endNode = range->GetEndParent();
+      int32_t endOffset = range->EndOffset();
+      if (startNode == endNode && IsTextNode(startNode)) {
+        // Let's find the block container of the text node
+        nsCOMPtr<Element> blockParent = GetBlockNodeParent(startNode);
+        // And apply the background color to that block container
         if (blockParent && cachedBlockParent != blockParent) {
           cachedBlockParent = blockParent;
-          nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
-          int32_t count;
-          res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
-          NS_ENSURE_SUCCESS(res, res);
+          mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
+                                                     &bgcolor, &aColor, false);
         }
-      }
-      else if ((startNode == endNode) && nsTextEditUtils::IsBody(startNode) && isCollapsed)
-      {
-        // we have no block in the document, let's apply the background to the body 
-        nsCOMPtr<nsIDOMElement> element = do_QueryInterface(startNode);
-        int32_t count;
-        res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
-        NS_ENSURE_SUCCESS(res, res);
-      }
-      else if ((startNode == endNode) && (((endOffset-startOffset) == 1) || (!startOffset && !endOffset)))
-      {
-        // a unique node is selected, let's also apply the background color
-        // to the containing block, possibly the node itself
-        nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startNode, startOffset);
-        bool isBlock =false;
-        res = NodeIsBlockStatic(selectedNode, &isBlock);
-        NS_ENSURE_SUCCESS(res, res);
-        nsCOMPtr<nsIDOMNode> blockParent = selectedNode;
-        if (!isBlock) {
+      } else if (startNode == endNode &&
+                 startNode->IsHTMLElement(nsGkAtoms::body) && isCollapsed) {
+        // No block in the document, let's apply the background to the body
+        mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(startNode->AsElement(),
+                                                   nullptr, &bgcolor, &aColor,
+                                                   false);
+      } else if (startNode == endNode && (endOffset - startOffset == 1 ||
+                                          (!startOffset && !endOffset))) {
+        // A unique node is selected, let's also apply the background color to
+        // the containing block, possibly the node itself
+        nsCOMPtr<nsIContent> selectedNode = startNode->GetChildAt(startOffset);
+        nsCOMPtr<Element> blockParent;
+        if (NodeIsBlockStatic(selectedNode)) {
+          blockParent = selectedNode->AsElement();
+        } else {
           blockParent = GetBlockNodeParent(selectedNode);
         }
         if (blockParent && cachedBlockParent != blockParent) {
           cachedBlockParent = blockParent;
-          nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
-          int32_t count;
-          res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
-          NS_ENSURE_SUCCESS(res, res);
+          mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
+                                                     &bgcolor, &aColor, false);
         }
-      }
-      else
-      {
-        // not the easy case.  range not contained in single text node. 
-        // there are up to three phases here.  There are all the nodes
-        // reported by the subtree iterator to be processed.  And there
-        // are potentially a starting textnode and an ending textnode
-        // which are only partially contained by the range.
-        
-        // lets handle the nodes reported by the iterator.  These nodes
-        // are entirely contained in the selection range.  We build up
-        // a list of them (since doing operations on the document during
-        // iteration would perturb the iterator).
-
-        nsCOMPtr<nsIContentIterator> iter =
-          do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
-        NS_ENSURE_SUCCESS(res, res);
-        NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
-
-        nsCOMArray<nsIDOMNode> arrayOfNodes;
-        nsCOMPtr<nsIDOMNode> node;
-                
-        // iterate range and build up array
+      } else {
+        // Not the easy case.  Range not contained in single text node.  There
+        // are up to three phases here.  There are all the nodes reported by
+        // the subtree iterator to be processed.  And there are potentially a
+        // starting textnode and an ending textnode which are only partially
+        // contained by the range.
+
+        // Let's handle the nodes reported by the iterator.  These nodes are
+        // entirely contained in the selection range.  We build up a list of
+        // them (since doing operations on the document during iteration would
+        // perturb the iterator).
+
+        OwningNonNull<nsIContentIterator> iter =
+          NS_NewContentSubtreeIterator();
+
+        nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
+        nsCOMPtr<nsINode> node;
+
+        // Iterate range and build up array
         res = iter->Init(range);
-        // init returns an error if no nodes in range.
-        // this can easily happen with the subtree 
-        // iterator if the selection doesn't contain
-        // any *whole* nodes.
-        if (NS_SUCCEEDED(res))
-        {
-          while (!iter->IsDone())
-          {
+        // Init returns an error if no nodes in range.  This can easily happen
+        // with the subtree iterator if the selection doesn't contain any
+        // *whole* nodes.
+        if (NS_SUCCEEDED(res)) {
+          for (; !iter->IsDone(); iter->Next()) {
             node = do_QueryInterface(iter->GetCurrentNode());
             NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
-            if (IsEditable(node))
-            {
-              arrayOfNodes.AppendObject(node);
+            if (IsEditable(node)) {
+              arrayOfNodes.AppendElement(*node);
             }
-
-            iter->Next();
           }
         }
-        // first check the start parent of the range to see if it needs to 
-        // be separately handled (it does if it's a text node, due to how the
+        // First check the start parent of the range to see if it needs to be
+        // separately handled (it does if it's a text node, due to how the
         // subtree iterator works - it will not have reported it).
-        if (IsTextNode(startNode) && IsEditable(startNode))
-        {
-          nsCOMPtr<nsIDOMNode> blockParent;
-          blockParent = GetBlockNodeParent(startNode);
+        if (IsTextNode(startNode) && IsEditable(startNode)) {
+          nsCOMPtr<Element> blockParent = GetBlockNodeParent(startNode);
           if (blockParent && cachedBlockParent != blockParent) {
             cachedBlockParent = blockParent;
-            nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
-            int32_t count;
-            res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
-            NS_ENSURE_SUCCESS(res, res);
+            mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
+                                                       &bgcolor, &aColor,
+                                                       false);
           }
         }
-        
-        // then loop through the list, set the property on each node
-        int32_t listCount = arrayOfNodes.Count();
-        int32_t j;
-        for (j = 0; j < listCount; j++)
-        {
-          node = arrayOfNodes[j];
-          // do we have a block here ?
-          bool isBlock =false;
-          res = NodeIsBlockStatic(node, &isBlock);
-          NS_ENSURE_SUCCESS(res, res);
-          nsCOMPtr<nsIDOMNode> blockParent = node;
-          if (!isBlock) {
-            // no we don't, let's find the block ancestor
+
+        // Then loop through the list, set the property on each node
+        for (auto& node : arrayOfNodes) {
+          nsCOMPtr<Element> blockParent;
+          if (NodeIsBlockStatic(node)) {
+            blockParent = node->AsElement();
+          } else {
             blockParent = GetBlockNodeParent(node);
           }
           if (blockParent && cachedBlockParent != blockParent) {
             cachedBlockParent = blockParent;
-            nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
-            int32_t count;
-            // and set the property on it
-            res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
-            NS_ENSURE_SUCCESS(res, res);
+            mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
+                                                       &bgcolor, &aColor,
+                                                       false);
           }
         }
         arrayOfNodes.Clear();
-        
-        // last check the end parent of the range to see if it needs to 
-        // be separately handled (it does if it's a text node, due to how the
+
+        // Last, check the end parent of the range to see if it needs to be
+        // separately handled (it does if it's a text node, due to how the
         // subtree iterator works - it will not have reported it).
-        if (IsTextNode(endNode) && IsEditable(endNode))
-        {
-          nsCOMPtr<nsIDOMNode> blockParent;
-          blockParent = GetBlockNodeParent(endNode);
+        if (IsTextNode(endNode) && IsEditable(endNode)) {
+          nsCOMPtr<Element> blockParent = GetBlockNodeParent(endNode);
           if (blockParent && cachedBlockParent != blockParent) {
             cachedBlockParent = blockParent;
-            nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
-            int32_t count;
-            res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
-            NS_ENSURE_SUCCESS(res, res);
+            mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
+                                                       &bgcolor, &aColor,
+                                                       false);
           }
         }
       }
     }
   }
-  if (!cancel)
-  {
-    // post-process
+  if (!cancel) {
+    // Post-process
     res = mRules->DidDoAction(selection, &ruleInfo, res);
+    NS_ENSURE_SUCCESS(res, res);
   }
-  return res;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::SetBackgroundColor(const nsAString& aColor)
 {
   nsresult res;
   if (IsCSSEnabled()) {
     // if we are in CSS mode, we have to apply the background color to the
--- a/editor/libeditor/nsHTMLEditor.h
+++ b/editor/libeditor/nsHTMLEditor.h
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsHTMLEditor_h__
 #define nsHTMLEditor_h__
 
 #include "nsCOMPtr.h"
-#include "nsCOMArray.h"
 #include "nsPlaintextEditor.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsITableEditor.h"
 #include "nsIEditorMailSupport.h"
 #include "nsIEditorStyleSheets.h"
 
 #include "nsEditor.h"
@@ -36,28 +35,32 @@
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "nsAttrName.h"
 #include "nsStubMutationObserver.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/Element.h"
 
+class nsDocumentFragment;
 class nsIDOMKeyEvent;
 class nsITransferable;
 class nsIClipboard;
 class TypeInState;
 class nsIContentFilter;
 class nsILinkHandler;
 class nsTableOuterFrame;
 class nsIDOMRange;
 class nsRange;
 struct PropItem;
 
 namespace mozilla {
+namespace dom {
+template<class T> class OwningNonNull;
+}
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
 
 /**
  * The HTML editor implementation.<br>
  * Use to edit HTML document represented as a DOM tree. 
@@ -586,39 +589,37 @@ protected:
                                         nsCOMPtr<nsIDOMNode> *outEndNode,
                                         int32_t *outStartOffset,
                                         int32_t *outEndOffset,
                                         bool aTrustedInput);
   nsresult   ParseFragment(const nsAString & aStr, nsIAtom* aContextLocalName,
                            nsIDocument* aTargetDoc,
                            nsCOMPtr<nsIDOMNode> *outNode,
                            bool aTrustedInput);
-  nsresult   CreateListOfNodesToPaste(nsIDOMNode  *aFragmentAsNode,
-                                      nsCOMArray<nsIDOMNode>& outNodeList,
-                                      nsIDOMNode *aStartNode,
+  void       CreateListOfNodesToPaste(mozilla::dom::DocumentFragment& aFragment,
+                                      nsTArray<mozilla::dom::OwningNonNull<nsINode>>& outNodeList,
+                                      nsINode* aStartNode,
                                       int32_t aStartOffset,
-                                      nsIDOMNode *aEndNode,
+                                      nsINode* aEndNode,
                                       int32_t aEndOffset);
   nsresult CreateTagStack(nsTArray<nsString> &aTagStack,
                           nsIDOMNode *aNode);
-  nsresult GetListAndTableParents( bool aEnd, 
-                                   nsCOMArray<nsIDOMNode>& aListOfNodes,
-                                   nsCOMArray<nsIDOMNode>& outArray);
-  nsresult DiscoverPartialListsAndTables(nsCOMArray<nsIDOMNode>& aPasteNodes,
-                                         nsCOMArray<nsIDOMNode>& aListsAndTables,
-                                         int32_t *outHighWaterMark);
-  nsresult ScanForListAndTableStructure(bool aEnd,
-                                        nsCOMArray<nsIDOMNode>& aNodes,
-                                        nsIDOMNode *aListOrTable,
-                                        nsCOMPtr<nsIDOMNode> *outReplaceNode);
-  nsresult ReplaceOrphanedStructure( bool aEnd,
-                                     nsCOMArray<nsIDOMNode>& aNodeArray,
-                                     nsCOMArray<nsIDOMNode>& aListAndTableArray,
-                                     int32_t aHighWaterMark);
-  nsIDOMNode* GetArrayEndpoint(bool aEnd, nsCOMArray<nsIDOMNode>& aNodeArray);
+  enum class StartOrEnd { start, end };
+  void GetListAndTableParents(StartOrEnd aStartOrEnd,
+                              nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeList,
+                              nsTArray<mozilla::dom::OwningNonNull<mozilla::dom::Element>>& outArray);
+  int32_t DiscoverPartialListsAndTables(nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aPasteNodes,
+                                        nsTArray<mozilla::dom::OwningNonNull<mozilla::dom::Element>>& aListsAndTables);
+  nsINode* ScanForListAndTableStructure(StartOrEnd aStartOrEnd,
+                                        nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodes,
+                                        mozilla::dom::Element& aListOrTable);
+  void ReplaceOrphanedStructure(StartOrEnd aStartOrEnd,
+                                nsTArray<mozilla::dom::OwningNonNull<nsINode>>& aNodeArray,
+                                nsTArray<mozilla::dom::OwningNonNull<mozilla::dom::Element>>& aListAndTableArray,
+                                int32_t aHighWaterMark);
 
   /* small utility routine to test if a break node is visible to user */
   bool     IsVisBreak(nsINode* aNode);
   bool     IsVisBreak(nsIDOMNode *aNode);
 
   /* utility routine to possibly adjust the insertion position when 
      inserting a block level element */
   void NormalizeEOLInsertPosition(nsIDOMNode *firstNodeToInsert,
@@ -628,41 +629,38 @@ protected:
   /* small utility routine to test the eEditorReadonly bit */
   bool IsModifiable();
 
   /* helpers for block transformations */
   nsresult MakeDefinitionItem(const nsAString & aItemType);
   nsresult InsertBasicBlock(const nsAString & aBlockType);
   
   /* increase/decrease the font size of selection */
-  nsresult RelativeFontChange( int32_t aSizeChange);
+  enum class FontSize { incr, decr };
+  nsresult RelativeFontChange(FontSize aDir);
   
   /* helper routines for font size changing */
   nsresult RelativeFontChangeOnTextNode( int32_t aSizeChange, 
                                          nsIDOMCharacterData *aTextNode, 
                                          int32_t aStartOffset,
                                          int32_t aEndOffset);
   nsresult RelativeFontChangeOnNode(int32_t aSizeChange, nsIContent* aNode);
   nsresult RelativeFontChangeHelper(int32_t aSizeChange, nsINode* aNode);
 
   /* helper routines for inline style */
   nsresult SetInlinePropertyOnTextNode(mozilla::dom::Text& aData,
                                        int32_t aStartOffset,
                                        int32_t aEndOffset,
                                        nsIAtom& aProperty,
                                        const nsAString* aAttribute,
                                        const nsAString& aValue);
-  nsresult SetInlinePropertyOnNode( nsIDOMNode *aNode,
-                                    nsIAtom *aProperty, 
-                                    const nsAString *aAttribute,
-                                    const nsAString *aValue);
-  nsresult SetInlinePropertyOnNode(nsIContent* aNode,
-                                   nsIAtom* aProperty,
+  nsresult SetInlinePropertyOnNode(nsIContent& aNode,
+                                   nsIAtom& aProperty,
                                    const nsAString* aAttribute,
-                                   const nsAString* aValue);
+                                   const nsAString& aValue);
 
   nsresult PromoteInlineRange(nsRange* aRange);
   nsresult PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange* aRange);
   nsresult SplitStyleAboveRange(nsRange* aRange,
                                 nsIAtom *aProperty, 
                                 const nsAString *aAttribute);
   nsresult SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
                                 int32_t *aOffset,
@@ -753,17 +751,17 @@ protected:
                                    bool aClearStyle = true);
 
   nsresult ClearStyle(nsCOMPtr<nsIDOMNode>* aNode, int32_t* aOffset,
                       nsIAtom* aProperty, const nsAString* aAttribute);
 
 // Data members
 protected:
 
-  nsCOMArray<nsIContentFilter> mContentFilters;
+  nsTArray<mozilla::dom::OwningNonNull<nsIContentFilter>> mContentFilters;
 
   nsRefPtr<TypeInState>        mTypeInState;
 
   bool mCRInParagraphCreatesParagraph;
 
   bool mCSSAware;
   nsAutoPtr<nsHTMLCSSUtils> mHTMLCSSUtils;
 
@@ -843,17 +841,17 @@ protected:
   nsCOMPtr<mozilla::dom::Element> mResizingInfo;
 
   nsCOMPtr<mozilla::dom::Element> mResizedObject;
 
   nsCOMPtr<nsIDOMEventListener>  mMouseMotionListenerP;
   nsCOMPtr<nsISelectionListener> mSelectionListenerP;
   nsCOMPtr<nsIDOMEventListener>  mResizeEventListenerP;
 
-  nsCOMArray<nsIHTMLObjectResizeListener> objectResizeEventListeners;
+  nsTArray<mozilla::dom::OwningNonNull<nsIHTMLObjectResizeListener>> mObjectResizeEventListeners;
 
   int32_t mOriginalX;
   int32_t mOriginalY;
 
   int32_t mResizedObjectX;
   int32_t mResizedObjectY;
   int32_t mResizedObjectWidth;
   int32_t mResizedObjectHeight;
@@ -954,20 +952,20 @@ friend class nsWSRunObject;
 friend class nsHTMLEditorEventListener;
 
 private:
   // Helpers
   bool IsSimpleModifiableNode(nsIContent* aContent,
                               nsIAtom* aProperty,
                               const nsAString* aAttribute,
                               const nsAString* aValue);
-  nsresult SetInlinePropertyOnNodeImpl(nsIContent* aNode,
-                                       nsIAtom* aProperty,
+  nsresult SetInlinePropertyOnNodeImpl(nsIContent& aNode,
+                                       nsIAtom& aProperty,
                                        const nsAString* aAttribute,
-                                       const nsAString* aValue);
+                                       const nsAString& aValue);
   typedef enum { eInserted, eAppended } InsertedOrAppended;
   void DoContentInserted(nsIDocument* aDocument, nsIContent* aContainer,
                          nsIContent* aChild, int32_t aIndexInContainer,
                          InsertedOrAppended aInsertedOrAppended);
   already_AddRefed<mozilla::dom::Element> GetElementOrParentByTagName(
       const nsAString& aTagName, nsINode* aNode);
   already_AddRefed<mozilla::dom::Element> CreateElementWithDefaults(
       const nsAString& aTagName);
--- a/editor/libeditor/nsHTMLEditorStyle.cpp
+++ b/editor/libeditor/nsHTMLEditorStyle.cpp
@@ -5,17 +5,16 @@
 #include "TypeInState.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAttrName.h"
 #include "nsAutoPtr.h"
-#include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsCaseTreatment.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsEditRules.h"
 #include "nsEditor.h"
 #include "nsEditorUtils.h"
 #include "nsError.h"
@@ -104,61 +103,57 @@ NS_IMETHODIMP nsHTMLEditor::RemoveAllDef
     delete mDefaultStyles[j];
   }
   mDefaultStyles.Clear();
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
-nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty,
+nsHTMLEditor::SetInlineProperty(nsIAtom* aProperty,
                                 const nsAString& aAttribute,
                                 const nsAString& aValue)
 {
-  if (!aProperty) {
-    return NS_ERROR_NULL_POINTER;
-  }
-  if (!mRules) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
+  NS_ENSURE_TRUE(aProperty, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
+  nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
   ForceCompositionEnd();
 
   nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   if (selection->Collapsed()) {
-    // manipulating text attributes on a collapsed selection only sets state
+    // Manipulating text attributes on a collapsed selection only sets state
     // for the next text insertion
     mTypeInState->SetProp(aProperty, aAttribute, aValue);
     return NS_OK;
   }
 
   nsAutoEditBatch batchIt(this);
   nsAutoRules beginRulesSniffing(this, EditAction::insertElement, nsIEditor::eNext);
   nsAutoSelectionReset selectionResetter(selection, this);
   nsAutoTxnsConserveSelection dontSpazMySelection(this);
 
   bool cancel, handled;
   nsTextRulesInfo ruleInfo(EditAction::setTextProperty);
   // Protect the edit rules object from dying
-  nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
   nsresult res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   NS_ENSURE_SUCCESS(res, res);
   if (!cancel && !handled) {
-    // loop thru the ranges in the selection
+    // Loop through the ranges in the selection
     uint32_t rangeCount = selection->RangeCount();
-    for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
+    for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
       nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
 
-      // adjust range to include any ancestors whose children are entirely
+      // Adjust range to include any ancestors whose children are entirely
       // selected
       res = PromoteInlineRange(range);
       NS_ENSURE_SUCCESS(res, res);
 
-      // check for easy case: both range endpoints in same text node
+      // Check for easy case: both range endpoints in same text node
       nsCOMPtr<nsINode> startNode = range->GetStartParent();
       nsCOMPtr<nsINode> endNode = range->GetEndParent();
       if (startNode && startNode == endNode && startNode->GetAsText()) {
         res = SetInlinePropertyOnTextNode(*startNode->GetAsText(),
                                           range->StartOffset(),
                                           range->EndOffset(),
                                           *aProperty, &aAttribute, aValue);
         NS_ENSURE_SUCCESS(res, res);
@@ -171,72 +166,64 @@ nsHTMLEditor::SetInlineProperty(nsIAtom 
       // starting textnode and an ending textnode which are only partially
       // contained by the range.
 
       // Let's handle the nodes reported by the iterator.  These nodes are
       // entirely contained in the selection range.  We build up a list of them
       // (since doing operations on the document during iteration would perturb
       // the iterator).
 
-      nsCOMPtr<nsIContentIterator> iter =
-        do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
-      NS_ENSURE_SUCCESS(res, res);
-      NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
+      OwningNonNull<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
 
-      nsCOMArray<nsIDOMNode> arrayOfNodes;
+      nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
 
-      // iterate range and build up array
+      // Iterate range and build up array
       res = iter->Init(range);
       // Init returns an error if there are no nodes in range.  This can easily
       // happen with the subtree iterator if the selection doesn't contain any
       // *whole* nodes.
       if (NS_SUCCEEDED(res)) {
-        nsCOMPtr<nsIDOMNode> node;
         for (; !iter->IsDone(); iter->Next()) {
-          node = do_QueryInterface(iter->GetCurrentNode());
-          NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
+          OwningNonNull<nsINode> node = *iter->GetCurrentNode();
 
-          if (IsEditable(node)) {
-            arrayOfNodes.AppendObject(node);
+          if (node->IsContent() && IsEditable(node)) {
+            arrayOfNodes.AppendElement(*node->AsContent());
           }
         }
       }
-      // first check the start parent of the range to see if it needs to
-      // be separately handled (it does if it's a text node, due to how the
+      // First check the start parent of the range to see if it needs to be
+      // separately handled (it does if it's a text node, due to how the
       // subtree iterator works - it will not have reported it).
       if (startNode && startNode->GetAsText() && IsEditable(startNode)) {
         res = SetInlinePropertyOnTextNode(*startNode->GetAsText(),
                                           range->StartOffset(),
                                           startNode->Length(), *aProperty,
                                           &aAttribute, aValue);
         NS_ENSURE_SUCCESS(res, res);
       }
 
-      // then loop through the list, set the property on each node
-      int32_t listCount = arrayOfNodes.Count();
-      int32_t j;
-      for (j = 0; j < listCount; j++) {
-        res = SetInlinePropertyOnNode(arrayOfNodes[j], aProperty,
-                                      &aAttribute, &aValue);
+      // Then loop through the list, set the property on each node
+      for (auto& node : arrayOfNodes) {
+        res = SetInlinePropertyOnNode(*node, *aProperty, &aAttribute, aValue);
         NS_ENSURE_SUCCESS(res, res);
       }
 
-      // last check the end parent of the range to see if it needs to
-      // be separately handled (it does if it's a text node, due to how the
+      // Last check the end parent of the range to see if it needs to be
+      // separately handled (it does if it's a text node, due to how the
       // subtree iterator works - it will not have reported it).
       if (endNode && endNode->GetAsText() && IsEditable(endNode)) {
         res = SetInlinePropertyOnTextNode(*endNode->GetAsText(), 0,
                                           range->EndOffset(), *aProperty,
                                           &aAttribute, aValue);
         NS_ENSURE_SUCCESS(res, res);
       }
     }
   }
   if (!cancel) {
-    // post-process
+    // Post-process
     return mRules->DidDoAction(selection, &ruleInfo, res);
   }
   return NS_OK;
 }
 
 
 
 // Helper function for SetInlinePropertyOn*: is aNode a simple old <b>, <font>,
@@ -371,192 +358,163 @@ nsHTMLEditor::SetInlinePropertyOnTextNod
     sibling = GetNextHTMLSibling(text);
     if (IsSimpleModifiableNode(sibling, &aProperty, aAttribute, &aValue)) {
       // Following sib is already right kind of inline node; slide this over
       return MoveNode(text, sibling, 0);
     }
   }
 
   // Reparent the node inside inline node with appropriate {attribute,value}
-  return SetInlinePropertyOnNode(text, &aProperty, aAttribute, &aValue);
+  return SetInlinePropertyOnNode(*text, aProperty, aAttribute, aValue);
 }
 
 
 nsresult
-nsHTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent* aNode,
-                                          nsIAtom* aProperty,
+nsHTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode,
+                                          nsIAtom& aProperty,
                                           const nsAString* aAttribute,
-                                          const nsAString* aValue)
+                                          const nsAString& aValue)
 {
-  MOZ_ASSERT(aNode && aProperty);
-  MOZ_ASSERT(aValue);
-
   nsCOMPtr<nsIAtom> attrAtom = aAttribute ? do_GetAtom(*aAttribute) : nullptr;
 
   // If this is an element that can't be contained in a span, we have to
   // recurse to its children.
-  if (!TagCanContain(*nsGkAtoms::span, *aNode)) {
-    if (aNode->HasChildren()) {
-      nsCOMArray<nsIContent> arrayOfNodes;
+  if (!TagCanContain(*nsGkAtoms::span, aNode)) {
+    if (aNode.HasChildren()) {
+      nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
 
       // Populate the list.
-      for (nsIContent* child = aNode->GetFirstChild();
+      for (nsCOMPtr<nsIContent> child = aNode.GetFirstChild();
            child;
            child = child->GetNextSibling()) {
         if (IsEditable(child) && !IsEmptyTextNode(this, child)) {
-          arrayOfNodes.AppendObject(child);
+          arrayOfNodes.AppendElement(*child);
         }
       }
 
       // Then loop through the list, set the property on each node.
-      int32_t listCount = arrayOfNodes.Count();
-      for (int32_t j = 0; j < listCount; ++j) {
-        nsresult rv = SetInlinePropertyOnNode(arrayOfNodes[j], aProperty,
-                                              aAttribute, aValue);
+      for (auto& node : arrayOfNodes) {
+        nsresult rv = SetInlinePropertyOnNode(node, aProperty, aAttribute,
+                                              aValue);
         NS_ENSURE_SUCCESS(rv, rv);
       }
     }
     return NS_OK;
   }
 
   // First check if there's an adjacent sibling we can put our node into.
   nsresult res;
-  nsCOMPtr<nsIContent> previousSibling = GetPriorHTMLSibling(aNode);
-  nsCOMPtr<nsIContent> nextSibling = GetNextHTMLSibling(aNode);
-  if (IsSimpleModifiableNode(previousSibling, aProperty, aAttribute, aValue)) {
-    res = MoveNode(aNode, previousSibling, -1);
+  nsCOMPtr<nsIContent> previousSibling = GetPriorHTMLSibling(&aNode);
+  nsCOMPtr<nsIContent> nextSibling = GetNextHTMLSibling(&aNode);
+  if (IsSimpleModifiableNode(previousSibling, &aProperty, aAttribute, &aValue)) {
+    res = MoveNode(&aNode, previousSibling, -1);
     NS_ENSURE_SUCCESS(res, res);
-    if (IsSimpleModifiableNode(nextSibling, aProperty, aAttribute, aValue)) {
+    if (IsSimpleModifiableNode(nextSibling, &aProperty, aAttribute, &aValue)) {
       res = JoinNodes(*previousSibling, *nextSibling);
       NS_ENSURE_SUCCESS(res, res);
     }
     return NS_OK;
   }
-  if (IsSimpleModifiableNode(nextSibling, aProperty, aAttribute, aValue)) {
-    res = MoveNode(aNode, nextSibling, 0);
+  if (IsSimpleModifiableNode(nextSibling, &aProperty, aAttribute, &aValue)) {
+    res = MoveNode(&aNode, nextSibling, 0);
     NS_ENSURE_SUCCESS(res, res);
     return NS_OK;
   }
 
-  // don't need to do anything if property already set on node
-  if (mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute)) {
+  // Don't need to do anything if property already set on node
+  if (mHTMLCSSUtils->IsCSSEditableProperty(&aNode, &aProperty, aAttribute)) {
     if (mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(
-          aNode, aProperty, aAttribute, *aValue, nsHTMLCSSUtils::eComputed)) {
+          &aNode, &aProperty, aAttribute, aValue, nsHTMLCSSUtils::eComputed)) {
       return NS_OK;
     }
-  } else if (IsTextPropertySetByContent(aNode, aProperty,
-                                        aAttribute, aValue)) {
+  } else if (IsTextPropertySetByContent(&aNode, &aProperty,
+                                        aAttribute, &aValue)) {
     return NS_OK;
   }
 
   bool useCSS = (IsCSSEnabled() &&
-                 mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute)) ||
+                 mHTMLCSSUtils->IsCSSEditableProperty(&aNode, &aProperty, aAttribute)) ||
                 // bgcolor is always done using CSS
                 aAttribute->EqualsLiteral("bgcolor");
 
   if (useCSS) {
     nsCOMPtr<dom::Element> tmp;
     // We only add style="" to <span>s with no attributes (bug 746515).  If we
     // don't have one, we need to make one.
-    if (aNode->IsHTMLElement(nsGkAtoms::span) &&
-        !aNode->AsElement()->GetAttrCount()) {
-      tmp = aNode->AsElement();
+    if (aNode.IsHTMLElement(nsGkAtoms::span) &&
+        !aNode.AsElement()->GetAttrCount()) {
+      tmp = aNode.AsElement();
     } else {
-      tmp = InsertContainerAbove(aNode, nsGkAtoms::span);
+      tmp = InsertContainerAbove(&aNode, nsGkAtoms::span);
       NS_ENSURE_STATE(tmp);
     }
 
     // Add the CSS styles corresponding to the HTML style request
     int32_t count;
     res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(tmp->AsDOMNode(),
-                                                     aProperty, aAttribute,
-                                                     aValue, &count, false);
+                                                     &aProperty, aAttribute,
+                                                     &aValue, &count, false);
     NS_ENSURE_SUCCESS(res, res);
     return NS_OK;
   }
 
   // is it already the right kind of node, but with wrong attribute?
-  if (aNode->IsHTMLElement(aProperty)) {
+  if (aNode.IsHTMLElement(&aProperty)) {
     // Just set the attribute on it.
-    nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
-    return SetAttribute(elem, *aAttribute, *aValue);
+    nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(&aNode);
+    return SetAttribute(elem, *aAttribute, aValue);
   }
 
   // ok, chuck it in its very own container
-  nsCOMPtr<Element> tmp = InsertContainerAbove(aNode, aProperty, attrAtom,
-                                               aValue);
+  nsCOMPtr<Element> tmp = InsertContainerAbove(&aNode, &aProperty, attrAtom,
+                                               &aValue);
   NS_ENSURE_STATE(tmp);
 
   return NS_OK;
 }
 
 
 nsresult
-nsHTMLEditor::SetInlinePropertyOnNode(nsIDOMNode *aNode,
-                                      nsIAtom *aProperty,
-                                      const nsAString *aAttribute,
-                                      const nsAString *aValue)
+nsHTMLEditor::SetInlinePropertyOnNode(nsIContent& aNode,
+                                      nsIAtom& aProperty,
+                                      const nsAString* aAttribute,
+                                      const nsAString& aValue)
 {
-  // Before setting the property, we remove it if it's already set.
-  // RemoveStyleInside might remove the node we're looking at or some of its
-  // descendants, however, in which case we want to set the property on
-  // whatever wound up in its place.  We have to save the original siblings and
-  // parent to figure this out.
-  NS_ENSURE_TRUE(aNode && aProperty, NS_ERROR_NULL_POINTER);
-
-  nsCOMPtr<nsIContent> node = do_QueryInterface(aNode);
-  NS_ENSURE_STATE(node);
+  nsCOMPtr<nsIContent> previousSibling = aNode.GetPreviousSibling(),
+                       nextSibling = aNode.GetNextSibling();
+  NS_ENSURE_STATE(aNode.GetParentNode());
+  OwningNonNull<nsINode> parent = *aNode.GetParentNode();
 
-  return SetInlinePropertyOnNode(node, aProperty, aAttribute, aValue);
-}
-
-nsresult
-nsHTMLEditor::SetInlinePropertyOnNode(nsIContent* aNode,
-                                      nsIAtom* aProperty,
-                                      const nsAString* aAttribute,
-                                      const nsAString* aValue)
-{
-  MOZ_ASSERT(aNode);
-  MOZ_ASSERT(aProperty);
-
-  nsCOMPtr<nsIContent> previousSibling = aNode->GetPreviousSibling(),
-                       nextSibling = aNode->GetNextSibling();
-  nsCOMPtr<nsINode> parent = aNode->GetParentNode();
-  NS_ENSURE_STATE(parent);
-
-  nsresult res = RemoveStyleInside(aNode->AsDOMNode(), aProperty, aAttribute);
+  nsresult res = RemoveStyleInside(aNode.AsDOMNode(), &aProperty, aAttribute);
   NS_ENSURE_SUCCESS(res, res);
 
-  if (aNode->GetParentNode()) {
+  if (aNode.GetParentNode()) {
     // The node is still where it was
     return SetInlinePropertyOnNodeImpl(aNode, aProperty,
                                        aAttribute, aValue);
   }
 
   // It's vanished.  Use the old siblings for reference to construct a
   // list.  But first, verify that the previous/next siblings are still
   // where we expect them; otherwise we have to give up.
   if ((previousSibling && previousSibling->GetParentNode() != parent) ||
       (nextSibling && nextSibling->GetParentNode() != parent)) {
     return NS_ERROR_UNEXPECTED;
   }
-  nsCOMArray<nsIContent> nodesToSet;
+  nsTArray<OwningNonNull<nsIContent>> nodesToSet;
   nsCOMPtr<nsIContent> cur = previousSibling
     ? previousSibling->GetNextSibling() : parent->GetFirstChild();
-  while (cur && cur != nextSibling) {
+  for (; cur && cur != nextSibling; cur = cur->GetNextSibling()) {
     if (IsEditable(cur)) {
-      nodesToSet.AppendObject(cur);
+      nodesToSet.AppendElement(*cur);
     }
-    cur = cur->GetNextSibling();
   }
 
-  int32_t nodesToSetCount = nodesToSet.Count();
-  for (int32_t k = 0; k < nodesToSetCount; k++) {
-    res = SetInlinePropertyOnNodeImpl(nodesToSet[k], aProperty,
-                                      aAttribute, aValue);
+  for (auto& node : nodesToSet) {
+    res = SetInlinePropertyOnNodeImpl(node, aProperty, aAttribute, aValue);
     NS_ENSURE_SUCCESS(res, res);
   }
 
   return NS_OK;
 }
 
 
 nsresult
@@ -1411,177 +1369,153 @@ nsHTMLEditor::RemoveInlinePropertyImpl(n
                   nsHTMLCSSUtils::eComputed) &&
               // startNode's computed style indicates the CSS equivalence to
               // the HTML style to remove is applied; but we found no element
               // in the ancestors of startNode carrying specified styles;
               // assume it comes from a rule and let's try to insert a span
               // "inverting" the style
               mHTMLCSSUtils->IsCSSInvertible(*aProperty, aAttribute)) {
             NS_NAMED_LITERAL_STRING(value, "-moz-editor-invert-value");
-            SetInlinePropertyOnNode(node->AsContent(), aProperty,
-                                    aAttribute, &value);
+            SetInlinePropertyOnNode(*node->AsContent(), *aProperty,
+                                    aAttribute, value);
           }
         }
       }
     }
   }
   if (!cancel) {
     // Post-process
     res = mRules->DidDoAction(selection, &ruleInfo, res);
     NS_ENSURE_SUCCESS(res, res);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsHTMLEditor::IncreaseFontSize()
 {
-  return RelativeFontChange(1);
+  return RelativeFontChange(FontSize::incr);
 }
 
 NS_IMETHODIMP nsHTMLEditor::DecreaseFontSize()
 {
-  return RelativeFontChange(-1);
+  return RelativeFontChange(FontSize::decr);
 }
 
 nsresult
-nsHTMLEditor::RelativeFontChange( int32_t aSizeChange)
+nsHTMLEditor::RelativeFontChange(FontSize aDir)
 {
-  // Can only change font size by + or - 1
-  if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
-    return NS_ERROR_ILLEGAL_VALUE;
-  
   ForceCompositionEnd();
 
-  // Get the selection 
+  // Get the selection
   nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-  // Is the selection collapsed?
-  // if it's collapsed set typing state
+  // If selection is collapsed, set typing state
   if (selection->Collapsed()) {
-    nsCOMPtr<nsIAtom> atom;
-    if (aSizeChange == 1) {
-      atom = nsGkAtoms::big;
-    } else {
-      atom = nsGkAtoms::small;
-    }
+    nsIAtom& atom = aDir == FontSize::incr ? *nsGkAtoms::big :
+                                             *nsGkAtoms::small;
 
     // Let's see in what kind of element the selection is
-    int32_t offset;
-    nsCOMPtr<nsINode> selectedNode;
-    GetStartNodeAndOffset(selection, getter_AddRefs(selectedNode), &offset);
-    if (selectedNode && IsTextNode(selectedNode)) {
-      selectedNode = selectedNode->GetParentNode();
+    NS_ENSURE_TRUE(selection->RangeCount() &&
+                   selection->GetRangeAt(0)->GetStartParent(), NS_OK);
+    OwningNonNull<nsINode> selectedNode =
+      *selection->GetRangeAt(0)->GetStartParent();
+    if (IsTextNode(selectedNode)) {
+      NS_ENSURE_TRUE(selectedNode->GetParentNode(), NS_OK);
+      selectedNode = *selectedNode->GetParentNode();
     }
-    NS_ENSURE_TRUE(selectedNode, NS_OK);
-    if (!CanContainTag(*selectedNode, *atom)) {
+    if (!CanContainTag(selectedNode, atom)) {
       return NS_OK;
     }
 
-    // manipulating text attributes on a collapsed selection only sets state for the next text insertion
-    mTypeInState->SetProp(atom, EmptyString(), EmptyString());
+    // Manipulating text attributes on a collapsed selection only sets state
+    // for the next text insertion
+    mTypeInState->SetProp(&atom, EmptyString(), EmptyString());
     return NS_OK;
   }
-  
-  // wrap with txn batching, rules sniffing, and selection preservation code
+
+  // Wrap with txn batching, rules sniffing, and selection preservation code
   nsAutoEditBatch batchIt(this);
-  nsAutoRules beginRulesSniffing(this, EditAction::setTextProperty, nsIEditor::eNext);
+  nsAutoRules beginRulesSniffing(this, EditAction::setTextProperty,
+                                 nsIEditor::eNext);
   nsAutoSelectionReset selectionResetter(selection, this);
   nsAutoTxnsConserveSelection dontSpazMySelection(this);
 
-  // loop thru the ranges in the selection
+  // Loop through the ranges in the selection
   uint32_t rangeCount = selection->RangeCount();
   for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
     nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
 
-    // adjust range to include any ancestors who's children are entirely selected
+    // Adjust range to include any ancestors with entirely selected children
     nsresult res = PromoteInlineRange(range);
     NS_ENSURE_SUCCESS(res, res);
-    
-    // check for easy case: both range endpoints in same text node
-    nsCOMPtr<nsIDOMNode> startNode, endNode;
-    res = range->GetStartContainer(getter_AddRefs(startNode));
-    NS_ENSURE_SUCCESS(res, res);
-    res = range->GetEndContainer(getter_AddRefs(endNode));
-    NS_ENSURE_SUCCESS(res, res);
-    if ((startNode == endNode) && IsTextNode(startNode))
-    {
-      int32_t startOffset, endOffset;
-      range->GetStartOffset(&startOffset);
-      range->GetEndOffset(&endOffset);
-      nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
-      res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, endOffset);
+
+    // Check for easy case: both range endpoints in same text node
+    nsCOMPtr<nsINode> startNode = range->GetStartParent();
+    nsCOMPtr<nsINode> endNode = range->GetEndParent();
+    if (startNode == endNode && IsTextNode(startNode)) {
+      res = RelativeFontChangeOnTextNode(aDir == FontSize::incr ? +1 : -1,
+          static_cast<nsIDOMCharacterData*>(startNode->AsDOMNode()),
+          range->StartOffset(), range->EndOffset());
       NS_ENSURE_SUCCESS(res, res);
-    }
-    else
-    {
-      // not the easy case.  range not contained in single text node. 
-      // there are up to three phases here.  There are all the nodes
-      // reported by the subtree iterator to be processed.  And there
-      // are potentially a starting textnode and an ending textnode
-      // which are only partially contained by the range.
-      
-      // lets handle the nodes reported by the iterator.  These nodes
-      // are entirely contained in the selection range.  We build up
-      // a list of them (since doing operations on the document during
-      // iteration would perturb the iterator).
+    } else {
+      // Not the easy case.  Range not contained in single text node.  There
+      // are up to three phases here.  There are all the nodes reported by the
+      // subtree iterator to be processed.  And there are potentially a
+      // starting textnode and an ending textnode which are only partially
+      // contained by the range.
 
-      nsCOMPtr<nsIContentIterator> iter =
-        do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
-      NS_ENSURE_SUCCESS(res, res);
-      NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
+      // Let's handle the nodes reported by the iterator.  These nodes are
+      // entirely contained in the selection range.  We build up a list of them
+      // (since doing operations on the document during iteration would perturb
+      // the iterator).
 
-      // iterate range and build up array
+      OwningNonNull<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+
+      // Iterate range and build up array
       res = iter->Init(range);
       if (NS_SUCCEEDED(res)) {
-        nsCOMArray<nsIContent> arrayOfNodes;
-        while (!iter->IsDone()) {
+        nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
+        for (; !iter->IsDone(); iter->Next()) {
           NS_ENSURE_TRUE(iter->GetCurrentNode()->IsContent(), NS_ERROR_FAILURE);
-          nsCOMPtr<nsIContent> node = iter->GetCurrentNode()->AsContent();
+          OwningNonNull<nsIContent> node = *iter->GetCurrentNode()->AsContent();
 
           if (IsEditable(node)) {
-            arrayOfNodes.AppendObject(node);
+            arrayOfNodes.AppendElement(node);
           }
-
-          iter->Next();
         }
-        
-        // now that we have the list, do the font size change on each node
-        int32_t listCount = arrayOfNodes.Count();
-        for (int32_t j = 0; j < listCount; ++j) {
-          nsIContent* node = arrayOfNodes[j];
-          res = RelativeFontChangeOnNode(aSizeChange, node);
+
+        // Now that we have the list, do the font size change on each node
+        for (auto& node : arrayOfNodes) {
+          res = RelativeFontChangeOnNode(aDir == FontSize::incr ? +1 : -1,
+                                         node);
           NS_ENSURE_SUCCESS(res, res);
         }
-        arrayOfNodes.Clear();
       }
-      // now check the start and end parents of the range to see if they need to 
-      // be separately handled (they do if they are text nodes, due to how the
-      // subtree iterator works - it will not have reported them).
-      if (IsTextNode(startNode) && IsEditable(startNode))
-      {
-        nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
-        int32_t startOffset;
-        uint32_t textLen;
-        range->GetStartOffset(&startOffset);
-        nodeAsText->GetLength(&textLen);
-        res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, textLen);
+      // Now check the start and end parents of the range to see if they need
+      // to be separately handled (they do if they are text nodes, due to how
+      // the subtree iterator works - it will not have reported them).
+      if (IsTextNode(startNode) && IsEditable(startNode)) {
+        res = RelativeFontChangeOnTextNode(aDir == FontSize::incr ? +1 : -1,
+            static_cast<nsIDOMCharacterData*>(startNode->AsDOMNode()),
+            range->StartOffset(), startNode->Length());
         NS_ENSURE_SUCCESS(res, res);
       }
-      if (IsTextNode(endNode) && IsEditable(endNode))
-      {
+      if (IsTextNode(endNode) && IsEditable(endNode)) {
         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(endNode);
         int32_t endOffset;
         range->GetEndOffset(&endOffset);
-        res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, 0, endOffset);
+        res = RelativeFontChangeOnTextNode(aDir == FontSize::incr ? +1 : -1,
+            static_cast<nsIDOMCharacterData*>(startNode->AsDOMNode()),
+            0, range->EndOffset());
         NS_ENSURE_SUCCESS(res, res);
       }
     }
   }
-  
-  return NS_OK;  
+
+  return NS_OK;
 }
 
 nsresult
 nsHTMLEditor::RelativeFontChangeOnTextNode( int32_t aSizeChange, 
                                             nsIDOMCharacterData *aTextNode, 
                                             int32_t aStartOffset,
                                             int32_t aEndOffset)
 {
--- a/editor/libeditor/nsHTMLObjectResizer.cpp
+++ b/editor/libeditor/nsHTMLObjectResizer.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsAutoPtr.h"
-#include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsEditorUtils.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLCSSUtils.h"
 #include "nsHTMLEditUtils.h"
 #include "nsHTMLEditor.h"
@@ -494,24 +493,18 @@ nsHTMLEditor::HideShadowAndInfo()
     mResizingInfo->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
                            NS_LITERAL_STRING("hidden"), true);
 }
 
 nsresult
 nsHTMLEditor::StartResizing(nsIDOMElement *aHandle)
 {
   // First notify the listeners if any
-  int32_t listenersCount = objectResizeEventListeners.Count();
-  if (listenersCount) {
-    nsCOMPtr<nsIHTMLObjectResizeListener> listener;
-    int32_t index;
-    for (index = 0; index < listenersCount; index++) {
-      listener = objectResizeEventListeners[index];
-      listener->OnStartResizing(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)));
-    }
+  for (auto& listener : mObjectResizeEventListeners) {
+    listener->OnStartResizing(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)));
   }
 
   mIsResizing = true;
   mActivatedHandle = do_QueryInterface(aHandle);
   NS_ENSURE_STATE(mActivatedHandle || !aHandle);
   mActivatedHandle->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_activated,
                             NS_LITERAL_STRING("true"), true);
 
@@ -971,26 +964,20 @@ nsHTMLEditor::SetFinalSize(int32_t aX, i
     if (setWidth)
       mHTMLCSSUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::width,
                                        EmptyString());
     if (setHeight)
       mHTMLCSSUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::height,
                                        EmptyString());
   }
   // finally notify the listeners if any
-  int32_t listenersCount = objectResizeEventListeners.Count();
-  if (listenersCount) {
-    nsCOMPtr<nsIHTMLObjectResizeListener> listener;
-    int32_t index;
-    for (index = 0; index < listenersCount; index++) {
-      listener = objectResizeEventListeners[index];
-      listener->OnEndResizing(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)),
-                              mResizedObjectWidth, mResizedObjectHeight,
-                              width, height);
-    }
+  for (auto& listener : mObjectResizeEventListeners) {
+    listener->OnEndResizing(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)),
+                            mResizedObjectWidth, mResizedObjectHeight, width,
+                            height);
   }
 
   // keep track of that size
   mResizedObjectWidth  = width;
   mResizedObjectHeight = height;
 
   RefreshResizers();
 }
@@ -1016,34 +1003,32 @@ nsHTMLEditor::SetObjectResizingEnabled(b
   mIsObjectResizingEnabled = aObjectResizingEnabled;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::AddObjectResizeEventListener(nsIHTMLObjectResizeListener * aListener)
 {
   NS_ENSURE_ARG_POINTER(aListener);
-  if (objectResizeEventListeners.Count() &&
-      objectResizeEventListeners.IndexOf(aListener) != -1) {
+  if (mObjectResizeEventListeners.Contains(aListener)) {
     /* listener already registered */
     NS_ASSERTION(false,
                  "trying to register an already registered object resize event listener");
     return NS_OK;
   }
-  objectResizeEventListeners.AppendObject(aListener);
+  mObjectResizeEventListeners.AppendElement(*aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::RemoveObjectResizeEventListener(nsIHTMLObjectResizeListener * aListener)
 {
   NS_ENSURE_ARG_POINTER(aListener);
-  if (!objectResizeEventListeners.Count() ||
-      objectResizeEventListeners.IndexOf(aListener) == -1) {
+  if (!mObjectResizeEventListeners.Contains(aListener)) {
     /* listener was not registered */
     NS_ASSERTION(false,
                  "trying to remove an object resize event listener that was not already registered");
     return NS_OK;
   }
-  objectResizeEventListeners.RemoveObject(aListener);
+  mObjectResizeEventListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -72,17 +72,17 @@ skip-if(B2G||Mulet) fails-if(Android) ne
 == spellcheck-comma-valid.html spellcheck-comma-valid-ref.html
 == spellcheck-hyphen-multiple-valid.html spellcheck-hyphen-multiple-valid-ref.html
 skip-if(B2G||Mulet) fails-if(Android) needs-focus != spellcheck-hyphen-multiple-invalid.html spellcheck-hyphen-multiple-invalid-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == spellcheck-dotafterquote-valid.html spellcheck-dotafterquote-valid-ref.html
 == spellcheck-url-valid.html spellcheck-url-valid-ref.html
 == unneeded_scroll.html unneeded_scroll-ref.html
 skip-if(B2G||Mulet) == caret_on_presshell_reinit.html caret_on_presshell_reinit-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) == 642800.html 642800-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,2824) == 642800.html 642800-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == selection_visibility_after_reframe.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-3.html selection_visibility_after_reframe-ref.html
 == 672709.html 672709-ref.html
 == 338427-1.html 338427-1-ref.html
 skip-if(Android||B2G||Mulet) needs-focus == 674212-spellcheck.html 674212-spellcheck-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(Android||B2G||Mulet) needs-focus == 338427-2.html 338427-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(Android||B2G||Mulet) needs-focus == 338427-3.html 338427-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -1009,16 +1009,20 @@ SyncObjectD3D11::FinalizeFrame()
   }
 
   if (mD3D10SyncedTextures.size()) {
     RefPtr<IDXGIKeyedMutex> mutex;
     hr = mD3D10Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
     hr = mutex->AcquireSync(0, 20000);
 
     if (hr == WAIT_TIMEOUT) {
+      if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+        gfxWarning() << "AcquireSync timed out because of device reset.";
+        return;
+      }
       MOZ_CRASH();
     }
 
     D3D10_BOX box;
     box.front = box.top = box.left = 0;
     box.back = box.bottom = box.right = 1;
 
     ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
@@ -1033,16 +1037,20 @@ SyncObjectD3D11::FinalizeFrame()
   }
 
   if (mD3D11SyncedTextures.size()) {
     RefPtr<IDXGIKeyedMutex> mutex;
     hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
     hr = mutex->AcquireSync(0, 20000);
 
     if (hr == WAIT_TIMEOUT) {
+      if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+        gfxWarning() << "AcquireSync timed out because of device reset.";
+        return;
+      }
       MOZ_CRASH();
     }
 
     D3D11_BOX box;
     box.front = box.top = box.left = 0;
     box.back = box.bottom = box.right = 1;
 
     ID3D11Device* dev = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
--- a/image/src/ProgressTracker.cpp
+++ b/image/src/ProgressTracker.cpp
@@ -82,26 +82,24 @@ CheckProgressConsistency(Progress aProgr
   if (aProgress & FLAG_HAS_ERROR) {
     // No preconditions.
   }
 }
 
 void
 ProgressTracker::SetImage(Image* aImage)
 {
-  MutexAutoLock lock(mImageMutex);
   MOZ_ASSERT(aImage, "Setting null image");
   MOZ_ASSERT(!mImage, "Setting image when we already have one");
   mImage = aImage;
 }
 
 void
 ProgressTracker::ResetImage()
 {
-  MutexAutoLock lock(mImageMutex);
   MOZ_ASSERT(mImage, "Resetting image when it's already null!");
   mImage = nullptr;
 }
 
 uint32_t
 ProgressTracker::GetImageStatus() const
 {
   uint32_t status = imgIRequest::STATUS_NONE;
@@ -180,19 +178,18 @@ class AsyncNotifyRunnable : public nsRun
 };
 
 void
 ProgressTracker::Notify(IProgressObserver* aObserver)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
 #ifdef PR_LOGGING
-  nsRefPtr<Image> image = GetImage();
-  if (image && image->GetURI()) {
-    nsRefPtr<ImageURL> uri(image->GetURI());
+  if (mImage && mImage->GetURI()) {
+    nsRefPtr<ImageURL> uri(mImage->GetURI());
     nsAutoCString spec;
     uri->GetSpec(spec);
     LOG_FUNC_WITH_PARAM(GetImgLog(),
                         "ProgressTracker::Notify async", "uri", spec.get());
   } else {
     LOG_FUNC_WITH_PARAM(GetImgLog(),
                         "ProgressTracker::Notify async", "uri", "<unknown>");
   }
@@ -249,20 +246,19 @@ class AsyncNotifyCurrentStateRunnable : 
 };
 
 void
 ProgressTracker::NotifyCurrentState(IProgressObserver* aObserver)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
 #ifdef PR_LOGGING
-  nsRefPtr<Image> image = GetImage();
   nsAutoCString spec;
-  if (image && image->GetURI()) {
-    image->GetURI()->GetSpec(spec);
+  if (mImage && mImage->GetURI()) {
+    mImage->GetURI()->GetSpec(spec);
   }
   LOG_FUNC_WITH_PARAM(GetImgLog(),
                       "ProgressTracker::NotifyCurrentState", "uri", spec.get());
 #endif
 
   aObserver->SetNotificationsDeferred(true);
 
   nsCOMPtr<nsIRunnable> ev = new AsyncNotifyCurrentStateRunnable(this,
@@ -366,51 +362,49 @@ ProgressTracker::SyncNotifyProgress(Prog
   }
 
   // Apply the changes.
   mProgress |= progress;
 
   CheckProgressConsistency(mProgress);
 
   // Send notifications.
-  SyncNotifyInternal(mObservers, HasImage(), progress, aInvalidRect);
+  SyncNotifyInternal(mObservers, !!mImage, progress, aInvalidRect);
 
   if (progress & FLAG_HAS_ERROR) {
     FireFailureNotification();
   }
 }
 
 void
 ProgressTracker::SyncNotify(IProgressObserver* aObserver)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsRefPtr<Image> image = GetImage();
-
 #ifdef PR_LOGGING
   nsAutoCString spec;
-  if (image && image->GetURI()) {
-    image->GetURI()->GetSpec(spec);
+  if (mImage && mImage->GetURI()) {
+    mImage->GetURI()->GetSpec(spec);
   }
   LOG_SCOPE_WITH_PARAM(GetImgLog(),
                        "ProgressTracker::SyncNotify", "uri", spec.get());
 #endif
 
   nsIntRect rect;
-  if (image) {
-    if (NS_FAILED(image->GetWidth(&rect.width)) ||
-        NS_FAILED(image->GetHeight(&rect.height))) {
+  if (mImage) {
+    if (NS_FAILED(mImage->GetWidth(&rect.width)) ||
+        NS_FAILED(mImage->GetHeight(&rect.height))) {
       // Either the image has no intrinsic size, or it has an error.
       rect = GetMaxSizedIntRect();
     }
   }
 
   ObserverArray array;
   array.AppendElement(aObserver);
-  SyncNotifyInternal(array, !!image, mProgress, rect);
+  SyncNotifyInternal(array, !!mImage, mProgress, rect);
 }
 
 void
 ProgressTracker::EmulateRequestFinished(IProgressObserver* aObserver)
 {
   MOZ_ASSERT(NS_IsMainThread(),
              "SyncNotifyState and mObservers are not threadsafe");
   nsRefPtr<IProgressObserver> kungFuDeathGrip(aObserver);
@@ -512,22 +506,21 @@ ProgressTracker::OnImageAvailable()
 
 void
 ProgressTracker::FireFailureNotification()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Some kind of problem has happened with image decoding.
   // Report the URI to net:failed-to-process-uri-conent observers.
-  nsRefPtr<Image> image = GetImage();
-  if (image) {
+  if (mImage) {
     // Should be on main thread, so ok to create a new nsIURI.
     nsCOMPtr<nsIURI> uri;
     {
-      nsRefPtr<ImageURL> threadsafeUriData = image->GetURI();
+      nsRefPtr<ImageURL> threadsafeUriData = mImage->GetURI();
       uri = threadsafeUriData ? threadsafeUriData->ToIURI() : nullptr;
     }
     if (uri) {
       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
       if (os) {
         os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
       }
     }
--- a/image/src/ProgressTracker.h
+++ b/image/src/ProgressTracker.h
@@ -2,17 +2,16 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_image_src_ProgressTracker_h
 #define mozilla_image_src_ProgressTracker_h
 
-#include "mozilla/Mutex.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/WeakPtr.h"
 #include "nsCOMPtr.h"
 #include "nsTObserverArray.h"
 #include "nsThreadUtils.h"
 #include "nsRect.h"
 #include "IProgressObserver.h"
 
@@ -72,25 +71,23 @@ class ProgressTracker : public mozilla::
 {
   virtual ~ProgressTracker() { }
 
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(ProgressTracker)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProgressTracker)
 
   ProgressTracker()
-    : mImageMutex("ProgressTracker::mImage")
-    , mImage(nullptr)
+    : mImage(nullptr)
     , mProgress(NoProgress)
   { }
 
-  bool HasImage() const { MutexAutoLock lock(mImageMutex); return mImage; }
+  bool HasImage() const { return mImage; }
   already_AddRefed<Image> GetImage() const
   {
-    MutexAutoLock lock(mImageMutex);
     nsRefPtr<Image> image = mImage;
     return image.forget();
   }
 
   // Get the current image status (as in imgIRequest).
   uint32_t GetImageStatus() const;
 
   // Get the current Progress.
@@ -188,19 +185,17 @@ private:
   // Main thread only, since notifications are expected on the main thread, and
   // mObservers is not threadsafe.
   static void SyncNotifyInternal(ObserverArray& aObservers,
                                  bool aHasImage, Progress aProgress,
                                  const nsIntRect& aInvalidRect);
 
   nsCOMPtr<nsIRunnable> mRunnable;
 
-  // mImage is a weak ref; it should be set to null when the image goes out of
-  // scope. mImageMutex protects mImage.
-  mutable Mutex mImageMutex;
+  // This weak ref should be set null when the image goes out of scope.
   Image* mImage;
 
   // List of observers attached to the image. Each observer represents a
   // consumer using the image. Array and/or individual elements should only be
   // accessed on the main thread.
   ObserverArray mObservers;
 
   Progress mProgress;
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -532,18 +532,38 @@ js::Nursery::collectToFixedPoint(MinorCo
         }
     }
 }
 
 MOZ_ALWAYS_INLINE void
 js::Nursery::traceObject(MinorCollectionTracer* trc, JSObject* obj)
 {
     const Class* clasp = obj->getClass();
-    if (clasp->trace)
+    if (clasp->trace) {
+        if (clasp->trace == InlineTypedObject::obj_trace) {
+            TypeDescr* descr = &obj->as<InlineTypedObject>().typeDescr();
+            if (descr->hasTraceList()) {
+                markTraceList(trc, descr->traceList(),
+                              obj->as<InlineTypedObject>().inlineTypedMem());
+            }
+            return;
+        }
+        if (clasp == &UnboxedPlainObject::class_) {
+            JSObject** pexpando = obj->as<UnboxedPlainObject>().addressOfExpando();
+            if (*pexpando)
+                markObject(trc, pexpando);
+            const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
+            if (layout.traceList()) {
+                markTraceList(trc, layout.traceList(),
+                              obj->as<UnboxedPlainObject>().data());
+            }
+            return;
+        }
         clasp->trace(trc, obj);
+    }
 
     MOZ_ASSERT(obj->isNative() == clasp->isNative());
     if (!clasp->isNative())
         return;
     NativeObject* nobj = &obj->as<NativeObject>();
 
     // Note: the contents of copy on write elements pointers are filled in
     // during parsing and cannot contain nursery pointers.
@@ -574,26 +594,52 @@ js::Nursery::markSlots(MinorCollectionTr
 
 MOZ_ALWAYS_INLINE void
 js::Nursery::markSlot(MinorCollectionTracer* trc, HeapSlot* slotp)
 {
     if (!slotp->isObject())
         return;
 
     JSObject* obj = &slotp->toObject();
-    if (!IsInsideNursery(obj))
-        return;
-
-    if (getForwardedPointer(&obj)) {
+    if (markObject(trc, &obj))
         slotp->unsafeGet()->setObject(*obj);
-        return;
-    }
+}
 
-    JSObject* tenured = static_cast<JSObject*>(moveToTenured(trc, obj));
-    slotp->unsafeGet()->setObject(*tenured);
+MOZ_ALWAYS_INLINE void
+js::Nursery::markTraceList(MinorCollectionTracer* trc, const int32_t* traceList, uint8_t* memory)
+{
+    while (*traceList != -1) {
+        // Strings are not in the nursery and do not need tracing.
+        traceList++;
+    }
+    traceList++;
+    while (*traceList != -1) {
+        JSObject** pobj = reinterpret_cast<JSObject **>(memory + *traceList);
+        markObject(trc, pobj);
+        traceList++;
+    }
+    traceList++;
+    while (*traceList != -1) {
+        HeapSlot* pslot = reinterpret_cast<HeapSlot *>(memory + *traceList);
+        markSlot(trc, pslot);
+        traceList++;
+    }
+}
+
+MOZ_ALWAYS_INLINE bool
+js::Nursery::markObject(MinorCollectionTracer* trc, JSObject** pobj)
+{
+    if (!IsInsideNursery(*pobj))
+        return false;
+
+    if (getForwardedPointer(pobj))
+        return true;
+
+    *pobj = static_cast<JSObject*>(moveToTenured(trc, *pobj));
+    return true;
 }
 
 void*
 js::Nursery::moveToTenured(MinorCollectionTracer* trc, JSObject* src)
 {
 
     AllocKind dstKind = src->allocKindForTenure(*this);
     Zone* zone = src->zone();
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -308,16 +308,19 @@ class Nursery
      * Move the object at |src| in the Nursery to an already-allocated cell
      * |dst| in Tenured.
      */
     void collectToFixedPoint(gc::MinorCollectionTracer* trc, TenureCountCache& tenureCounts);
     MOZ_ALWAYS_INLINE void traceObject(gc::MinorCollectionTracer* trc, JSObject* src);
     MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer* trc, HeapSlot* vp, uint32_t nslots);
     MOZ_ALWAYS_INLINE void markSlots(gc::MinorCollectionTracer* trc, HeapSlot* vp, HeapSlot* end);
     MOZ_ALWAYS_INLINE void markSlot(gc::MinorCollectionTracer* trc, HeapSlot* slotp);
+    MOZ_ALWAYS_INLINE void markTraceList(gc::MinorCollectionTracer* trc,
+                                         const int32_t* traceList, uint8_t* memory);
+    MOZ_ALWAYS_INLINE bool markObject(gc::MinorCollectionTracer* trc, JSObject** pobj);
     void* moveToTenured(gc::MinorCollectionTracer* trc, JSObject* src);
     size_t moveObjectToTenured(gc::MinorCollectionTracer* trc, JSObject* dst, JSObject* src,
                                gc::AllocKind dstKind);
     size_t moveElementsToTenured(NativeObject* dst, NativeObject* src, gc::AllocKind dstKind);
     size_t moveSlotsToTenured(NativeObject* dst, NativeObject* src, gc::AllocKind dstKind);
 
     /* Handle relocation of slots/elements pointers stored in Ion frames. */
     void setForwardingPointer(void* oldData, void* newData, bool direct);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -10125,16 +10125,27 @@ TryAttachStringSplit(JSContext* cx, ICCa
     RootedString argString(cx, args[0].toString());
     RootedArrayObject obj(cx, &res.toObject().as<ArrayObject>());
     RootedValue arr(cx);
 
     // Copy the array before storing in stub.
     if (!CopyArray(cx, obj, &arr))
         return false;
 
+    // Atomize all elements of the array.
+    RootedArrayObject arrObj(cx, &arr.toObject().as<ArrayObject>());
+    uint32_t initLength = arrObj->length();
+    for (uint32_t i = 0; i < initLength; i++) {
+        JSAtom* str = js::AtomizeString(cx, arrObj->getDenseElement(i).toString());
+        if (!str)
+            return false;
+
+        arrObj->setDenseElement(i, StringValue(str));
+    }
+
     ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                           script->pcToOffset(pc), thisString, argString,
                                           arr);
     ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
     stub->addNewStub(newStub);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -12868,52 +12868,30 @@ IonBuilder::storeReferenceTypedObjectVal
 
     current->add(store);
     return true;
 }
 
 MConstant*
 IonBuilder::constant(const Value& v)
 {
-    // For performance reason (TLS) and error code handling (AtomizeString), we
-    // should prefer the specialized frunction constantMaybeAtomize instead of
-    // constant.
     MOZ_ASSERT(!v.isString() || v.toString()->isAtom(),
-               "To handle non-atomized strings, you should use constantMaybeAtomize instead of constant.");
-    if (v.isString() && MOZ_UNLIKELY(!v.toString()->isAtom())) {
-        MConstant* cst = constantMaybeAtomize(v);
-        if (!cst)
-            js::CrashAtUnhandlableOOM("Use constantMaybeAtomize.");
-        return cst;
-    }
+               "Handle non-atomized strings outside IonBuilder.");
 
     MConstant* c = MConstant::New(alloc(), v, constraints());
     current->add(c);
     return c;
 }
 
 MConstant*
 IonBuilder::constantInt(int32_t i)
 {
     return constant(Int32Value(i));
 }
 
-MConstant*
-IonBuilder::constantMaybeAtomize(const Value& v)
-{
-    if (!v.isString() || v.toString()->isAtom())
-        return constant(v);
-
-    JSContext* cx = GetJitContext()->cx;
-    JSAtom* atom = js::AtomizeString(cx, v.toString());
-    if (!atom)
-        return nullptr;
-    return constant(StringValue(atom));
-}
-
 MDefinition*
 IonBuilder::getCallee()
 {
     if (inliningDepth_ == 0) {
         MInstruction* callee = MCallee::New(alloc());
         current->add(callee);
         return callee;
     }
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -348,19 +348,16 @@ class IonBuilder
     void rewriteParameters();
     bool initScopeChain(MDefinition* callee = nullptr);
     bool initArgumentsObject();
     bool pushConstant(const Value& v);
 
     MConstant* constant(const Value& v);
     MConstant* constantInt(int32_t i);
 
-    // Note: This function might return nullptr in case of failure.
-    MConstant* constantMaybeAtomize(const Value& v);
-
     // Improve the type information at tests
     bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test);
     bool improveTypesAtCompare(MCompare* ins, bool trueBranch, MTest* test);
     bool improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch, MTest* test);
     bool improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* test);
 
     // Used to detect triangular structure at test.
     bool detectAndOrStructure(MPhi* ins, bool* branchIsTrue);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1562,24 +1562,21 @@ IonBuilder::inlineConstantStringSplit(Ca
 
     if (!key.maybeTypes()->hasType(TypeSet::StringType()))
         return InliningStatus_NotInlined;
 
     uint32_t initLength = templateObject->as<ArrayObject>().length();
     if (templateObject->getDenseInitializedLength() != initLength)
         return InliningStatus_NotInlined;
 
-    JSContext* cx = GetJitContext()->cx;
     Vector<MConstant*, 0, SystemAllocPolicy> arrayValues;
     for (uint32_t i = 0; i < initLength; i++) {
-        JSAtom* str = js::AtomizeString(cx, templateObject->getDenseElement(i).toString());
-        if (!str)
-            return InliningStatus_Error;
-
-        MConstant* value = MConstant::New(alloc(), StringValue(str), constraints());
+        Value str = templateObject->getDenseElement(i);
+        MOZ_ASSERT(str.toString()->isAtom());
+        MConstant* value = MConstant::New(alloc(), str, constraints());
         if (!TypeSetIncludes(key.maybeTypes(), value->type(), value->resultTypeSet()))
             return InliningStatus_NotInlined;
 
         if (!arrayValues.append(value))
             return InliningStatus_Error;
     }
     callInfo.setImplicitlyUsedUnchecked();
 
@@ -2767,42 +2764,41 @@ IonBuilder::inlineBoundFunction(CallInfo
 
     if (gc::IsInsideNursery(scriptedTarget))
         return InliningStatus_NotInlined;
 
     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
         const Value val = target->getBoundFunctionArgument(i);
         if (val.isObject() && gc::IsInsideNursery(&val.toObject()))
             return InliningStatus_NotInlined;
+        if (val.isString() && !val.toString()->isAtom())
+            return InliningStatus_NotInlined;
     }
 
     const Value thisVal = target->getBoundFunctionThis();
     if (thisVal.isObject() && gc::IsInsideNursery(&thisVal.toObject()))
         return InliningStatus_NotInlined;
+    if (thisVal.isString() && !thisVal.toString()->isAtom())
+        return InliningStatus_NotInlined;
 
     size_t argc = target->getBoundFunctionArgumentCount() + nativeCallInfo.argc();
     if (argc > ARGS_LENGTH_MAX)
         return InliningStatus_NotInlined;
 
     nativeCallInfo.thisArg()->setImplicitlyUsedUnchecked();
 
     CallInfo callInfo(alloc(), nativeCallInfo.constructing());
     callInfo.setFun(constant(ObjectValue(*scriptedTarget)));
-    MConstant* thisConst = constantMaybeAtomize(thisVal);
-    if (!thisConst)
-        return InliningStatus_Error;
-    callInfo.setThis(thisConst);
+    callInfo.setThis(constant(thisVal));
 
     if (!callInfo.argv().reserve(argc))
         return InliningStatus_Error;
 
     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
-        MConstant* argConst = constantMaybeAtomize(target->getBoundFunctionArgument(i));
-        if (!argConst)
-            return InliningStatus_Error;
+        MConstant* argConst = constant(target->getBoundFunctionArgument(i));
         callInfo.argv().infallibleAppend(argConst);
     }
     for (size_t i = 0; i < nativeCallInfo.argc(); i++)
         callInfo.argv().infallibleAppend(nativeCallInfo.getArg(i));
 
     if (!makeCall(scriptedTarget, callInfo))
         return InliningStatus_Error;
 
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -899,17 +899,17 @@ TypeSet::intersectSets(TemporaryTypeSet*
             if (b->getObject(i))
                 res->addType(ObjectType(b->getObject(i)), alloc);
         }
         return res;
     }
 
     if (b->unknownObject()) {
         for (size_t i = 0; i < a->getObjectCount(); i++) {
-            if (b->getObject(i))
+            if (a->getObject(i))
                 res->addType(ObjectType(a->getObject(i)), alloc);
         }
         return res;
     }
 
     MOZ_ASSERT(!a->unknownObject() && !b->unknownObject());
 
     for (size_t i = 0; i < a->getObjectCount(); i++) {
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -228,16 +228,21 @@ class UnboxedPlainObject : public JSObje
     UnboxedExpandoObject* maybeExpando() const {
         return expando_;
     }
 
     void initExpando() {
         expando_ = nullptr;
     }
 
+    // For use during GC.
+    JSObject** addressOfExpando() {
+        return reinterpret_cast<JSObject**>(&expando_);
+    }
+
     bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const;
 
     static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj);
 
     bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v);
     Value getValue(const UnboxedLayout::Property& property);
 
     static bool convertToNative(JSContext* cx, JSObject* obj);
--- a/layout/reftests/abs-pos/reftest.list
+++ b/layout/reftests/abs-pos/reftest.list
@@ -44,19 +44,19 @@ skip-if((B2G&&browserIsRemote)||Mulet) !
 == table-footer-group-3.html table-internal-3-ref.html
 == table-footer-group-4.html table-internal-4-ref.html
 == table-footer-group-5.html table-internal-5-ref.html
 == table-footer-group-6.html table-internal-6-ref.html
 == table-footer-group-7.html table-internal-7-ref.html
 == continuation-positioned-inline-1.html continuation-positioned-inline-ref.html
 == continuation-positioned-inline-2.html continuation-positioned-inline-ref.html
 == scrollframe-1.html scrollframe-1-ref.html
-skip-if(B2G||Mulet) fuzzy-if(Android,9,185) == scrollframe-2.html scrollframe-2-ref.html #bug 756530 # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(Android,9,185) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,107) == scrollframe-2.html scrollframe-2-ref.html #bug 756530 # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(gtk2Widget,1,8) == select-1.html select-1-ref.html
 fuzzy-if(gtk2Widget,1,8) == select-1-dynamic.html select-1-ref.html
 == select-2.html select-2-ref.html
-fuzzy-if(gtk2Widget,1,19) fuzzy-if(Android||B2G,17,726) == select-3.html select-3-ref.html
+fuzzy-if(gtk2Widget,1,19) fuzzy-if(Android||B2G,17,726) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,98) == select-3.html select-3-ref.html
 == multi-column-1.html multi-column-1-ref.html
 == button-1.html button-1-ref.html
 == button-2.html button-2-ref.html
 == relative-row-animation-1.html relative-row-animation-1-ref.html
 fuzzy-if(Android&&AndroidVersion>=15,12,50) == fixed-pos-auto-offset-1a.html fixed-pos-auto-offset-1-ref.html
 fuzzy-if(Android&&AndroidVersion>=15,12,50) == fixed-pos-auto-offset-1b.html fixed-pos-auto-offset-1-ref.html
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -31,17 +31,17 @@ fails-if(Android||B2G) == center-scaling
 == border-image-width-1b.html border-image-width-1-ref.html
 == border-image-width-1c.html border-image-width-1-ref.html
 == border-image-width-large.html border-image-width-large-ref.html
 == border-image-outset-1a.html border-image-outset-1-ref.html
 == border-image-outset-1b.html border-image-outset-1-ref.html
 == border-image-outset-1c.html border-image-outset-1-ref.html
 == border-image-nofill-1.html border-image-nofill-1-ref.html
 == border-image-outset-resize-1.html border-image-outset-resize-1-ref.html
-== border-image-outset-move-1.html border-image-outset-move-1-ref.html
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,445) == border-image-outset-move-1.html border-image-outset-move-1-ref.html
 == border-image-style-none.html border-image-style-none-ref.html
 == border-image-style-none-length.html border-image-style-none-length-ref.html
 == border-image-style-none-auto.html border-image-style-none-auto-ref.html
 
 # border images with gradients
 == border-image-linear-gradient.html border-image-linear-gradient-ref.html
 fuzzy(1,98) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html
 fuzzy(1,149) fuzzy-if(OSX,1,10595) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -66,17 +66,17 @@ fuzzy-if(true,1,33) fuzzy-if(cocoaWidget
 # Table elements
 == table-collapse-1.html table-collapse-1-ref.html # border-radius is ignored on internal table elements
 # when border-collapse: collapse
 
 fuzzy-if(azureQuartz,1,3) skip-if(B2G||Mulet) == invalidate-1a.html invalidate-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(azureQuartz,1,3) skip-if(B2G||Mulet) == invalidate-1b.html invalidate-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 
 # test that border-radius is reduced for scrollbars
-skip-if(B2G||Mulet) fails-if(Android) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,12,12) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) == scrollbar-clamping-2.html scrollbar-clamping-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 
 # Test for bad corner joins.
 fuzzy-if(true,1,1) == corner-joins-1.xhtml corner-joins-1-ref.xhtml
 skip-if(B2G||Mulet) random-if(winWidget) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop
 
 skip-if(B2G||Mulet) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(Android&&browserIsRemote,7,146) fuzzy-if(Android&&!browserIsRemote,166,400) fails-if(Android&&AndroidVersion==15) == scroll-1.html scroll-1-ref.html # see bug 732535 #Bug 959166 # Initial mulet triage: parity with B2G/B2G Desktop
 
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1570,17 +1570,17 @@ random-if(!winWidget) fails-if(winWidget
 == 577838-1.html 577838-1-ref.html
 == 577838-2.html 577838-2-ref.html
 == 579323-1.html 579323-1-ref.html
 == 579349-1.html 579349-1-ref.html
 == 579655-1.html 579655-1-ref.html
 skip-if(!haveTestPlugin) skip-if(B2G||Mulet) fails-if(Android) == 579808-1.html 579808-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) random-if(layersGPUAccelerated) == 579985-1.html 579985-1-ref.html # bug 623452 for WinXP; this bug was only for a regression in BasicLayers anyway # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) skip-if(Android) == 580160-1.html 580160-1-ref.html # bug 920927 for Android; issues without the test-plugin # Initial mulet triage: parity with B2G/B2G Desktop
-HTTP(..) == 580863-1.html 580863-1-ref.html
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,255,13) HTTP(..) == 580863-1.html 580863-1-ref.html
 skip-if(B2G||Mulet) fails-if(Android) random-if(layersGPUAccelerated) == 581317-1.html 581317-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 581579-1.html 581579-1-ref.html
 == 582037-1a.html 582037-1-ref.html
 == 582037-1b.html 582037-1-ref.html
 skip-if(B2G||Mulet) fuzzy-if(Android,3,256) == 582037-2a.html 582037-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(Android,3,256) == 582037-2b.html 582037-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 asserts(1-2) == 582146-1.html about:blank
 skip-if(B2G||Mulet) == 582476-1.svg 582476-1-ref.svg # Initial mulet triage: parity with B2G/B2G Desktop
@@ -1666,17 +1666,17 @@ HTTP(..) == 635639-2.html 635639-2-ref.h
 random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!
 fuzzy-if(Android&&AndroidVersion>=15,8,500) == 637852-1.html 637852-1-ref.html
 fuzzy-if(Android&&AndroidVersion>=15,8,500) == 637852-2.html 637852-2-ref.html
 fuzzy-if(Android&&AndroidVersion>=15,8,500) == 637852-3.html 637852-3-ref.html
 skip-if(B2G||Mulet) == 641770-1.html 641770-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 641856-1.html 641856-1-ref.html
 == 645491-1.html 645491-1-ref.html
 == 645768-1.html 645768-1-ref.html
-fails-if(layersGPUAccelerated&&cocoaWidget) fails-if(Android&&AndroidVersion<15&&AndroidVersion!=10) == 650228-1.html 650228-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
+fails-if(layersGPUAccelerated&&cocoaWidget) fails-if(Android&&AndroidVersion<15&&AndroidVersion!=10) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,41,260) == 650228-1.html 650228-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 needs-focus == 652301-1a.html 652301-1-ref.html
 needs-focus == 652301-1b.html 652301-1-ref.html
 == 652775-1.html 652775-1-ref.html
 == 653930-1.html 653930-1-ref.html
 HTTP(..) == 654057-1.html 654057-1-ref.html
 fails-if(layersGPUAccelerated&&cocoaWidget) fails-if(Android&&AndroidVersion==15) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 655549-1.html 655549-1-ref.html
 == 655836-1.html 655836-1-ref.html
@@ -1751,17 +1751,17 @@ fuzzy-if(Android,8,608) == 811301-1.html
 == 814677.html 814677-ref.html
 skip-if(B2G||Mulet) == 814952-1.html 814952-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(Android,4,400) == 815593-1.html 815593-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 816359-1.html 816359-1-ref.html
 == 816458-1.html 816458-1-ref.html
 == 816948-1.html 816948-1-ref.html
 == 817019-1.html about:blank
 skip-if(B2G||Mulet) == 818276-1.html 818276-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-fuzzy-if(asyncPanZoom,190,27) == 825999.html 825999-ref.html
+fuzzy-if(asyncPanZoom,190,510) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,510) == 825999.html 825999-ref.html
 == 827577-1a.html 827577-1-ref.html
 == 827577-1b.html 827577-1-ref.html
 == 827799-1.html about:blank
 == 829958.html 829958-ref.html
 == 836844-1.html 836844-1-ref.html
 == 841192-1.html 841192-1-ref.html
 == 844178.html 844178-ref.html
 fuzzy-if(OSX,1,364) == 846144-1.html 846144-1-ref.html
@@ -1801,17 +1801,17 @@ fuzzy-if(B2G,1,7) == 942672-1.html 94267
 == 956513-1.svg 956513-1-ref.svg
 == 944291-1.html 944291-1-ref.html
 == 950436-1.html 950436-1-ref.html
 == 957770-1.svg 957770-1-ref.svg
 == 960277-1.html 960277-1-ref.html
 == 961887-1.html 961887-1-ref.html
 == 961887-2.html 961887-2-ref.html
 == 961887-3.html 961887-3-ref.html
-pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,145) == 966992-1.html 966992-1-ref.html
+pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,145) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,3712) == 966992-1.html 966992-1-ref.html
 skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
 skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above
 == 978911-1.svg 978911-1-ref.svg
 == 983084-1.html 983084-1-ref.html
 == 983084-2.html 983084-2-ref.html
 == 983084-3.html 983084-1-ref.html
 == 983691-1.html 983691-ref.html
 HTTP(..) == 983985-1.html 983985-1-ref.html
--- a/layout/reftests/css-ui-invalid/select/reftest.list
+++ b/layout/reftests/css-ui-invalid/select/reftest.list
@@ -5,14 +5,14 @@ needs-focus == select-disabled.html sele
 skip-if(B2G||Mulet) needs-focus == select-dyn-disabled.html select-disabled-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 needs-focus == select-dyn-not-disabled.html select-ref.html
 needs-focus == select-required-invalid-1.html select-required-ref.html
 needs-focus == select-required-invalid-2.html select-required-ref.html
 needs-focus == select-required-invalid-changed-1.html select-required-ref.html
 needs-focus == select-required-invalid-changed-2.html select-required-ref.html
 needs-focus == select-required-valid.html select-required-ref.html
 needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
-needs-focus == select-required-multiple-invalid-changed.html select-required-multiple-ref.html
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,84,77) needs-focus == select-required-multiple-invalid-changed.html select-required-multiple-ref.html
 needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
 skip-if(B2G||Mulet) fails-if(Android) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
 needs-focus == select-novalidate.html select-required-ref.html
--- a/layout/reftests/css-ui-valid/select/reftest.list
+++ b/layout/reftests/css-ui-valid/select/reftest.list
@@ -6,13 +6,13 @@ needs-focus == select-dyn-disabled.html 
 needs-focus == select-dyn-not-disabled.html select-ref.html
 needs-focus == select-required-invalid.html select-required-ref.html
 needs-focus == select-required-valid-1.html select-required-ref.html
 needs-focus == select-required-valid-2.html select-required-ref.html
 needs-focus == select-required-valid-changed-1.html select-required-ref.html
 needs-focus == select-required-valid-changed-2.html select-required-ref.html
 needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
 needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
-fuzzy(64,4) needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html
+fuzzy(64,4) fuzzy-if(asyncPanZoom&&layersGPUAccelerated,84,77) needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html
 fails-if(Android||B2G||Mulet) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fails-if(Android||B2G||Mulet) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
 needs-focus == select-novalidate.html select-required-ref.html
--- a/layout/reftests/font-inflation/reftest.list
+++ b/layout/reftests/font-inflation/reftest.list
@@ -32,17 +32,17 @@ test-pref(font.size.inflation.emPerLine,
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == input-text-2-noheight.html input-text-2-noheight-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == input-text-3-height.html input-text-3-height-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == input-text-3-noheight.html input-text-3-noheight-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == textarea-1.html textarea-1-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == textarea-2.html textarea-2-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == textarea-3.html textarea-3-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == css-transform-1.html css-transform-1-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == css-transform-2.html css-transform-2-ref.html
-skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == container-with-clamping.html container-with-clamping-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,1764) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == container-with-clamping.html container-with-clamping-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) load video-1.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-min-1.html intrinsic-min-1-ref.html
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-max-1.html intrinsic-max-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1a.html intrinsic-fit-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1b.html intrinsic-fit-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1c.html intrinsic-fit-1c-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2a.html intrinsic-fit-1a-ref.html
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2b.html intrinsic-fit-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
--- a/layout/reftests/forms/fieldset/reftest.list
+++ b/layout/reftests/forms/fieldset/reftest.list
@@ -1,14 +1,14 @@
 == dynamic-legend-scroll-1.html dynamic-legend-scroll-1-ref.html
 == fieldset-hidden-1.html fieldset-hidden-1-ref.html
 == fieldset-intrinsic-width-1.html fieldset-intrinsic-width-1-ref.html
 == fieldset-percentage-padding-1.html fieldset-percentage-padding-1-ref.html
 == fieldset-scroll-1.html fieldset-scroll-1-ref.html
 == fieldset-scrolled-1.html fieldset-scrolled-1-ref.html
 random-if(B2G||Mulet) == fieldset-overflow-auto-1.html fieldset-overflow-auto-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-fuzzy-if(winWidget&&!layersGPUAccelerated,102,205) == positioned-container-1.html positioned-container-1-ref.html
+fuzzy-if(winWidget&&!layersGPUAccelerated,102,221) == positioned-container-1.html positioned-container-1-ref.html
 == relpos-legend-1.html relpos-legend-1-ref.html
 == relpos-legend-2.html relpos-legend-2-ref.html
 test-pref(layout.css.sticky.enabled,true) skip-if((B2G&&browserIsRemote)||Mulet) == sticky-legend-1.html sticky-legend-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == abs-pos-child-sizing.html abs-pos-child-sizing-ref.html
 == overflow-hidden.html overflow-hidden-ref.html
 == legend-rtl.html legend-rtl-ref.html
--- a/layout/reftests/forms/input/text/reftest.list
+++ b/layout/reftests/forms/input/text/reftest.list
@@ -1,10 +1,10 @@
 == bounds-1.html bounds-1-ref.html
-== size-1.html size-1-ref.html
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,84) == size-1.html size-1-ref.html
 skip-if(B2G||Mulet) == size-2.html size-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP(..) == baseline-1.html baseline-1-ref.html
 skip-if((B2G&&browserIsRemote)||Mulet) HTTP(..) == centering-1.xul centering-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if((B2G&&browserIsRemote)||Mulet) == dynamic-height-1.xul dynamic-height-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
 needs-focus == select.html select-ref.html
 == intrinsic-size.html intrinsic-size-ref.html
 == line-height-0.5.html line-height-1.0.html
 != line-height-1.5.html line-height-1.0.html
--- a/layout/reftests/forms/placeholder/reftest.list
+++ b/layout/reftests/forms/placeholder/reftest.list
@@ -11,17 +11,17 @@
 == placeholder-1-text.html placeholder-visible-ref.html
 == placeholder-1-password.html placeholder-visible-ref.html
 == placeholder-1-textarea.html placeholder-visible-textarea-ref.html
 == placeholder-2.html placeholder-visible-ref.html
 == placeholder-2-textarea.html placeholder-visible-textarea-ref.html
 == placeholder-3.html placeholder-overridden-ref.html
 == placeholder-4.html placeholder-overridden-ref.html
 == placeholder-5.html placeholder-visible-ref.html
-fuzzy-if(winWidget,160,7) == placeholder-6.html placeholder-overflow-ref.html
+fuzzy-if(winWidget,160,7) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,146,299) == placeholder-6.html placeholder-overflow-ref.html
 skip-if(B2G||Mulet) == placeholder-6-textarea.html placeholder-overflow-textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 # needs-focus == placeholder-7.html placeholder-focus-ref.html
 # needs-focus == placeholder-8.html placeholder-focus-ref.html
 # needs-focus == placeholder-9.html placeholder-focus-ref.html
 needs-focus == placeholder-10.html placeholder-visible-ref.html
 == placeholder-11.html placeholder-visible-ref.html
 == placeholder-12.html placeholder-visible-ref.html
 == placeholder-13.html placeholder-visible-ref.html
--- a/layout/reftests/forms/textarea/reftest.list
+++ b/layout/reftests/forms/textarea/reftest.list
@@ -5,10 +5,10 @@ skip-if(B2G||Mulet) fails-if(Android) !=
 skip-if(B2G||Mulet) fails-if(Android) != ltr-scrollbar.html rtl-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) != ltr.html no-resize.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) fails-if(gtk2Widget) != rtl.html no-resize.html # bug 834724 # Initial mulet triage: parity with B2G/B2G Desktop
 == rtl.html rtl-dynamic-attr.html
 == rtl.html rtl-dynamic-style.html
 == rtl.html in-dynamic-rtl-doc.html
 == setvalue-framereconstruction-1.html setvalue-framereconstruction-ref.html
-== padding-scrollbar-placement.html padding-scrollbar-placement-ref.html
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,4168) == padding-scrollbar-placement.html padding-scrollbar-placement-ref.html
 == various-cols.html various-cols-ref.html
--- a/layout/reftests/position-dynamic-changes/relative/reftest.list
+++ b/layout/reftests/position-dynamic-changes/relative/reftest.list
@@ -1,5 +1,5 @@
-fuzzy-if(cocoaWidget,1,2) fuzzy-if(d2d,47,26) == move-right-bottom.html move-right-bottom-ref.html
-fuzzy-if(cocoaWidget,1,2) == move-top-left.html move-top-left-ref.html # Bug 688545
-fuzzy-if(cocoaWidget,1,3) == move-right-bottom-table.html move-right-bottom-table-ref.html
-fuzzy-if(cocoaWidget,1,3) == move-top-left-table.html move-top-left-table-ref.html # Bug 688545
+fuzzy-if(cocoaWidget,1,2) fuzzy-if(d2d,47,26) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,492) == move-right-bottom.html move-right-bottom-ref.html
+fuzzy-if(cocoaWidget,1,2) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,492) == move-top-left.html move-top-left-ref.html # Bug 688545
+fuzzy-if(cocoaWidget,1,3) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,492) == move-right-bottom-table.html move-right-bottom-table-ref.html
+fuzzy-if(cocoaWidget,1,3) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,492) == move-top-left-table.html move-top-left-table-ref.html # Bug 688545
 == percent.html percent-ref.html
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -22,16 +22,16 @@ skip-if(Android) pref(layout.css.scroll-
 skip-if((B2G&&browserIsRemote)||Mulet) HTTP == simple-1.html simple-1.html?ref # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) HTTP == subpixel-1.html#d subpixel-1-ref.html#d # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(Android,4,120) HTTP == text-1.html text-1.html?ref
 fuzzy-if(Android,4,120) HTTP == text-2.html?up text-2.html?ref
 skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,251,722) fuzzy-if(d2d,1,4) HTTP == transformed-1.html transformed-1.html?ref # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP == transformed-1.html?up transformed-1.html?ref
 fuzzy-if(Android,5,20000) == uncovering-1.html uncovering-1-ref.html
 fuzzy-if(Android,5,20000) == uncovering-2.html uncovering-2-ref.html
-skip-if(B2G||Mulet) == less-than-scrollbar-height.html less-than-scrollbar-height-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,3721) == less-than-scrollbar-height.html less-than-scrollbar-height-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == huge-horizontal-overflow.html huge-horizontal-overflow-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == huge-vertical-overflow.html huge-vertical-overflow-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-== iframe-scrolling-attr-1.html iframe-scrolling-attr-ref.html
-skip-if((B2G&&browserIsRemote)||Mulet) == iframe-scrolling-attr-2.html iframe-scrolling-attr-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,6818) == iframe-scrolling-attr-1.html iframe-scrolling-attr-ref.html
+skip-if((B2G&&browserIsRemote)||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,6818) == iframe-scrolling-attr-2.html iframe-scrolling-attr-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == frame-scrolling-attr-1.html frame-scrolling-attr-ref.html
-== frame-scrolling-attr-2.html frame-scrolling-attr-ref.html
+fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,2420) == frame-scrolling-attr-2.html frame-scrolling-attr-ref.html
 == move-item.html move-item-ref.html # bug 1125750
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,26 +1,26 @@
 skip-if(B2G||Mulet) == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == line-clipping.html line-clipping-ref.html
 fuzzy-if(Android,16,244) skip-if(B2G||Mulet) HTTP(..) == marker-basic.html marker-basic-ref.html  # Bug 1128229 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) HTTP(..) == marker-string.html marker-string-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtk2Widget) fuzzy-if(gtk2Widget,1,104) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
-skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(OSX==1008,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html
 skip-if(B2G||Mulet) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
-skip-if(B2G||Mulet) HTTP(..) == block-padding.html block-padding-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,1724) HTTP(..) == block-padding.html block-padding-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP(..) == quirks-decorations.html quirks-decorations-ref.html
 HTTP(..) == quirks-line-height.html quirks-line-height-ref.html
 HTTP(..) == standards-decorations.html standards-decorations-ref.html
 HTTP(..) == standards-line-height.html standards-line-height-ref.html
 skip-if(B2G||Mulet) random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) HTTP(..) == selection.html selection-ref.html # bug 668849 # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP(..) == marker-shadow.html marker-shadow-ref.html
 == aligned-baseline.html aligned-baseline-ref.html
 skip-if(Android||B2G) == clipped-elements.html clipped-elements-ref.html
 HTTP(..) == theme-overflow.html theme-overflow-ref.html
 skip-if(B2G||Mulet) HTTP(..) == table-cell.html table-cell-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(Mulet) HTTP(..) == two-value-syntax.html two-value-syntax-ref.html # MULET: Bug 1144079: Re-enable Mulet mochitests and reftests taskcluster-specific disables
 skip-if(B2G||Mulet) HTTP(..) == single-value.html single-value-ref.html  # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) HTTP(..) == atomic-under-marker.html atomic-under-marker-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-fuzzy(1,702) skip-if(Android||B2G||Mulet) HTTP(..) == xulscroll.html xulscroll-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+fuzzy(1,702) skip-if(Android||B2G||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,12352) HTTP(..) == xulscroll.html xulscroll-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP(..) == combobox-zoom.html combobox-zoom-ref.html
--- a/media/libvpx/update.py
+++ b/media/libvpx/update.py
@@ -323,17 +323,17 @@ platform_files = [
     'vp8_rtcd.h',
     'vp9_rtcd.h',
     'vpx_config.asm',
     'vpx_config.h',
     'vpx_scale_rtcd.h',
 ]
 
 def prepare_upstream(prefix, commit=None):
-    upstream_url = 'https://gerrit.chromium.org/gerrit/webm/libvpx'
+    upstream_url = 'https://chromium.googlesource.com/webm/libvpx'
     if os.path.exists(prefix):
         print "Using existing repo in '%s'" % prefix
         os.chdir(prefix)
         subprocess.call(['git', 'fetch', upstream_url, prefix])
     else:
         subprocess.call(['git', 'clone', upstream_url, prefix])
         os.chdir(prefix)
     if commit:
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -167,16 +167,19 @@ static DllBlockInfo sWindowsDllBlocklist
 
   // Flash crashes with RealNetworks RealDownloader, bug 1132663
   { "rndlnpshimswf.dll", ALL_VERSIONS },
   { "rndlmainbrowserrecordplugin.dll", ALL_VERSIONS },
 
   // Crashes with CyberLink YouCam, bug 1136968
   { "ycwebcamerasource.ax", MAKE_VERSION(2, 0, 0, 1611) },
 
+  // Old version of WebcamMax crashes WebRTC, bug 1130061
+  { "vwcsource.ax", MAKE_VERSION(1, 5, 0, 0) },
+
   { nullptr, 0 }
 };
 
 #ifndef STATUS_DLL_NOT_FOUND
 #define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
 #endif
 
 // define this for very verbose dll load debug spew
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -2303,17 +2303,17 @@ GeckoDriver.prototype.getElementRect = f
  *     Reference ID to the element that will be checked.
  * @param {string} value
  *     Value to send to the element.
  */
 GeckoDriver.prototype.sendKeysToElement = function(cmd, resp) {
   let {id, value} = cmd.parameters;
 
   if (!value) {
-    throw new IllegalArgumentError(`Expected character sequence: ${value}`);
+    throw new InvalidArgumentError(`Expected character sequence: ${value}`);
   }
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, win);
       utils.sendKeysToElement(
           win,
@@ -2336,17 +2336,17 @@ GeckoDriver.prototype.sendKeysToElement 
 
         if (el.type == "file") {
           Cu.importGlobalProperties(["File"]);
           let fs = Array.prototype.slice.call(el.files);
           let file;
           try {
             file = new File(val);
           } catch (e) {
-            err = new IllegalArgumentError(`File not found: ${val}`);
+            err = new InvalidArgumentError(`File not found: ${val}`);
           }
           fs.push(file);
           el.mozSetFileArray(fs);
         } else {
           el.value = val;
         }
       }.bind(this);
 
--- a/testing/marionette/driver/requirements.txt
+++ b/testing/marionette/driver/requirements.txt
@@ -1,1 +1,2 @@
-marionette-transport == 0.4
\ No newline at end of file
+marionette-transport == 0.4
+mozrunner >= 6.2
--- a/testing/marionette/driver/setup.py
+++ b/testing/marionette/driver/setup.py
@@ -1,11 +1,11 @@
 from setuptools import setup, find_packages
 
-version = '0.4'
+version = '0.5'
 
 # dependencies
 with open('requirements.txt') as f:
     deps = f.read().splitlines()
 
 setup(name='marionette_driver',
       version=version,
       description="Marionette Driver",
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -6,17 +6,17 @@
 
 const {results: Cr, utils: Cu} = Components;
 
 const errors = [
   "ElementNotAccessibleError",
   "ElementNotVisibleError",
   "FrameSendFailureError",
   "FrameSendNotInitializedError",
-  "IllegalArgumentError",
+  "InvalidArgumentError",
   "InvalidElementStateError",
   "InvalidSelectorError",
   "InvalidSessionIdError",
   "JavaScriptError",
   "NoAlertOpenError",
   "NoSuchElementError",
   "NoSuchFrameError",
   "NoSuchWindowError",
@@ -166,22 +166,22 @@ this.FrameSendNotInitializedError = func
   WebDriverError.call(this, this.message);
   this.name = "FrameSendNotInitializedError";
   this.status = "frame send not initialized error";
   this.frame = frame;
   this.errMsg = `${this.message} ${this.frame}; frame has closed.`;
 };
 FrameSendNotInitializedError.prototype = Object.create(WebDriverError.prototype);
 
-this.IllegalArgumentError = function(msg) {
+this.InvalidArgumentError = function(msg) {
   WebDriverError.call(this, msg);
-  this.name = "IllegalArgumentError";
-  this.status = "illegal argument";
+  this.name = "InvalidArgumentError";
+  this.status = "invalid argument";
 };
-IllegalArgumentError.prototype = Object.create(WebDriverError.prototype);
+InvalidArgumentError.prototype = Object.create(WebDriverError.prototype);
 
 this.InvalidElementStateError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "InvalidElementStateError";
   this.status = "invalid element state";
 };
 InvalidElementStateError.prototype = Object.create(WebDriverError.prototype);
 
@@ -191,17 +191,16 @@ this.InvalidSelectorError = function(msg
   this.status = "invalid selector";
 };
 InvalidSelectorError.prototype = Object.create(WebDriverError.prototype);
 
 this.InvalidSessionIdError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "InvalidSessionIdError";
   this.status = "invalid session id";
-  this.code = 13;
 };
 InvalidSessionIdError.prototype = Object.create(WebDriverError.prototype);
 
 /**
  * Creates an error message for a JavaScript error thrown during
  * executeScript or executeAsyncScript.
  *
  * @param {Error} err
@@ -302,17 +301,16 @@ this.TimeoutError = function(msg) {
   this.status = "timeout";
 };
 TimeoutError.prototype = Object.create(WebDriverError.prototype);
 
 this.UnableToSetCookieError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "UnableToSetCookieError";
   this.status = "unable to set cookie";
-  this.code = 25;
 };
 UnableToSetCookieError.prototype = Object.create(WebDriverError.prototype);
 
 this.UnknownCommandError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "UnknownCommandError";
   this.status = "unknown command";
 };
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -1557,17 +1557,17 @@ function sendKeysToElement(msg) {
     //
     // this extra branch can be removed when the e10s bug 1149998 is fixed
     if (isRemoteBrowser()) {
       let fs = Array.prototype.slice.call(el.files);
       let file;
       try {
         file = new File(p);
       } catch (e) {
-        let err = new IllegalArgumentError(`File not found: ${val}`);
+        let err = new InvalidArgumentError(`File not found: ${val}`);
         sendError(err, command_id);
         return;
       }
       fs.push(file);
 
       let wel = new SpecialPowers(utils.window).wrap(el);
       wel.mozSetFileArray(fs);
     } else {
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -432,16 +432,17 @@ STUB(gtk_widget_has_grab)
 STUB(gtk_widget_hide)
 STUB(gtk_widget_is_focus)
 STUB(gtk_widget_is_toplevel)
 STUB(gtk_widget_map)
 STUB(gtk_widget_realize)
 STUB(gtk_widget_reparent)
 STUB(gtk_widget_set_allocation)
 STUB(gtk_widget_set_app_paintable)
+STUB(gtk_window_set_auto_startup_notification)
 STUB(gtk_widget_set_can_focus)
 STUB(gtk_widget_set_direction)
 STUB(gtk_widget_set_double_buffered)
 STUB(gtk_widget_set_has_window)
 STUB(gtk_widget_set_mapped)
 STUB(gtk_widget_set_name)
 STUB(gtk_widget_set_parent)
 STUB(gtk_widget_set_parent_window)
--- a/xpcom/glue/nsThreadUtils.cpp
+++ b/xpcom/glue/nsThreadUtils.cpp
@@ -88,77 +88,16 @@ NS_NewThread(nsIThread** aResult, nsIRun
     }
   }
 
   *aResult = nullptr;
   thread.swap(*aResult);
   return NS_OK;
 }
 
-#if defined(MOZ_NUWA_PROCESS) && !defined(XPCOM_GLUE_AVOID_NSPR)
-
-namespace {
-class IgnoreThreadStatusRunnable : public nsIRunnable
-{
-public:
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIRUNNABLE
-
-private:
-  virtual ~IgnoreThreadStatusRunnable() = default;
-};
-
-NS_IMPL_ISUPPORTS(IgnoreThreadStatusRunnable, nsIRunnable)
-
-NS_IMETHODIMP IgnoreThreadStatusRunnable::Run(void)
-{
-#ifdef MOZILLA_INTERNAL_API
-  nsThreadManager::get()->SetIgnoreThreadStatus();
-  return NS_OK;
-#endif
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-} // Anonymous namespace.
-#endif // defined(MOZ_NUWA_PROCESS) && !defined(XPCOM_GLUE_AVOID_NSPR)
-
-NS_METHOD
-NS_NewUnmonitoredThread(nsIThread** aResult,
-                        nsIRunnable* aEvent,
-                        uint32_t aStackSize)
-{
-#if defined(MOZ_NUWA_PROCESS) && !defined(XPCOM_GLUE_AVOID_NSPR)
-  // Hold a ref while dispatching the initial event to match NS_NewThread()
-  nsCOMPtr<nsIThread> thread;
-  nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr, aStackSize);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsCOMPtr<nsIRunnable> ignoreme = new IgnoreThreadStatusRunnable();
-  rv = thread->Dispatch(ignoreme, NS_DISPATCH_NORMAL);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  if (aEvent) {
-    rv = thread->Dispatch(aEvent, NS_DISPATCH_NORMAL);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  *aResult = nullptr;
-  thread.swap(*aResult);
-  return rv;
-#else
-  return NS_NewThread(aResult, aEvent, aStackSize);
-#endif
-}
-
 NS_METHOD
 NS_GetCurrentThread(nsIThread** aResult)
 {
 #ifdef MOZILLA_INTERNAL_API
   return nsThreadManager::get()->nsThreadManager::GetCurrentThread(aResult);
 #else
   nsresult rv;
   nsCOMPtr<nsIThreadManager> mgr =
--- a/xpcom/glue/nsThreadUtils.h
+++ b/xpcom/glue/nsThreadUtils.h
@@ -57,27 +57,16 @@ NS_SetThreadName(nsIThread* aThread, con
  *   Indicates that the given name is not unique.
  */
 extern NS_METHOD
 NS_NewThread(nsIThread** aResult,
              nsIRunnable* aInitialEvent = nullptr,
              uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
 
 /**
- * Create a new thread that is ignored in thread status monitoring by default on
- * platforms with Nuwa process enabled. On non-Nuwa platforms, this function is
- * identical to NS_NewThread().
- */
-extern NS_METHOD
-NS_NewUnmonitoredThread(nsIThread** aResult,
-                        nsIRunnable* aInitialEvent = nullptr,
-                        uint32_t aStackSize =
-                                 nsIThreadManager::DEFAULT_STACK_SIZE);
-
-/**
  * Creates a named thread, otherwise the same as NS_NewThread
  */
 template<size_t LEN>
 inline NS_METHOD
 NS_NewNamedThread(const char (&aName)[LEN],
                   nsIThread** aResult,
                   nsIRunnable* aInitialEvent = nullptr,
                   uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE)