Bug 1333333 - Label runnables in the HTML parser (again). r=billm. draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Tue, 27 Jun 2017 10:38:30 -0700
changeset 600776 7bc7df4514fbd2a78b8231fd8a64dc809a927296
parent 600673 f165f830468d42546e03a1770286db0ef561ff1e
child 600885 902c73c4c3c15d8cd02a1386b880936ec990b47e
push id65869
push userbmo:hsivonen@hsivonen.fi
push dateTue, 27 Jun 2017 20:35:49 +0000
reviewersbillm
bugs1333333
milestone56.0a1
Bug 1333333 - Label runnables in the HTML parser (again). r=billm. MozReview-Commit-ID: 1Z89LSr46dN
parser/html/moz.build
parser/html/nsHtml5RefPtr.h
parser/html/nsHtml5StreamListener.h
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5StreamParser.h
parser/html/nsHtml5StreamParserPtr.h
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOperation.cpp
--- a/parser/html/moz.build
+++ b/parser/html/moz.build
@@ -30,21 +30,21 @@ EXPORTS += [
     'nsHtml5Module.h',
     'nsHtml5NamedCharacters.h',
     'nsHtml5NamedCharactersAccel.h',
     'nsHtml5OplessBuilder.h',
     'nsHtml5OwningUTF16Buffer.h',
     'nsHtml5Parser.h',
     'nsHtml5PlainTextUtils.h',
     'nsHtml5Portability.h',
-    'nsHtml5RefPtr.h',
     'nsHtml5Speculation.h',
     'nsHtml5SpeculativeLoad.h',
     'nsHtml5StreamListener.h',
     'nsHtml5StreamParser.h',
+    'nsHtml5StreamParserPtr.h',
     'nsHtml5String.h',
     'nsHtml5StringParser.h',
     'nsHtml5SVGLoadDispatcher.h',
     'nsHtml5TreeOperation.h',
     'nsHtml5TreeOpExecutor.h',
     'nsHtml5TreeOpStage.h',
     'nsHtml5UTF16Buffer.h',
     'nsHtml5UTF16BufferHSupplement.h',
deleted file mode 100644
--- a/parser/html/nsHtml5RefPtr.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsHtml5RefPtr_h
-#define nsHtml5RefPtr_h
-
-#include "nsThreadUtils.h"
-
-template <class T>
-class nsHtml5RefPtrReleaser : public mozilla::Runnable
-  {
-    private:
-      T* mPtr;
-    public:
-      explicit nsHtml5RefPtrReleaser(T* aPtr)
-          : mozilla::Runnable("nsHtml5RefPtrReleaser")
-          , mPtr(aPtr)
-        {}
-      NS_IMETHOD Run() override
-        {
-          mPtr->Release();
-          return NS_OK;
-        }
-  };
-
-// template <class T> class nsHtml5RefPtrGetterAddRefs;
-
-/**
- * Like nsRefPtr except release is proxied to the main thread. Mostly copied
- * from nsRefPtr.
- */
-template <class T>
-class nsHtml5RefPtr
-  {
-    private:
-
-      void
-      assign_with_AddRef( T* rawPtr )
-        {
-          if ( rawPtr )
-            rawPtr->AddRef();
-          assign_assuming_AddRef(rawPtr);
-        }
-
-      void**
-      begin_assignment()
-        {
-          assign_assuming_AddRef(0);
-          return reinterpret_cast<void**>(&mRawPtr);
-        }
-
-      void
-      assign_assuming_AddRef( T* newPtr )
-        {
-          T* oldPtr = mRawPtr;
-          mRawPtr = newPtr;
-          if ( oldPtr )
-            release(oldPtr);
-        }
-
-      void
-      release( T* aPtr )
-        {
-          nsCOMPtr<nsIRunnable> releaser = new nsHtml5RefPtrReleaser<T>(aPtr);
-          if (NS_FAILED(NS_DispatchToMainThread(releaser))) 
-            {
-              NS_WARNING("Failed to dispatch releaser event.");
-            }
-        }
-
-    private:
-      T* mRawPtr;
-
-    public:
-      typedef T element_type;
-      
-     ~nsHtml5RefPtr()
-        {
-          if ( mRawPtr )
-            release(mRawPtr);
-        }
-
-        // Constructors
-
-      nsHtml5RefPtr()
-            : mRawPtr(0)
-          // default constructor
-        {
-        }
-
-      nsHtml5RefPtr( const nsHtml5RefPtr<T>& aSmartPtr )
-            : mRawPtr(aSmartPtr.mRawPtr)
-          // copy-constructor
-        {
-          if ( mRawPtr )
-            mRawPtr->AddRef();
-        }
-
-      explicit nsHtml5RefPtr( T* aRawPtr )
-            : mRawPtr(aRawPtr)
-          // construct from a raw pointer (of the right type)
-        {
-          if ( mRawPtr )
-            mRawPtr->AddRef();
-        }
-
-      explicit nsHtml5RefPtr( const already_AddRefed<T>& aSmartPtr )
-            : mRawPtr(aSmartPtr.mRawPtr)
-          // construct from |dont_AddRef(expr)|
-        {
-        }
-
-        // Assignment operators
-
-      nsHtml5RefPtr<T>&
-      operator=( const nsHtml5RefPtr<T>& rhs )
-          // copy assignment operator
-        {
-          assign_with_AddRef(rhs.mRawPtr);
-          return *this;
-        }
-
-      nsHtml5RefPtr<T>&
-      operator=( T* rhs )
-          // assign from a raw pointer (of the right type)
-        {
-          assign_with_AddRef(rhs);
-          return *this;
-        }
-
-      nsHtml5RefPtr<T>&
-      operator=( const already_AddRefed<T>& rhs )
-          // assign from |dont_AddRef(expr)|
-        {
-          assign_assuming_AddRef(rhs.mRawPtr);
-          return *this;
-        }
-
-        // Other pointer operators
-
-      void
-      swap( nsHtml5RefPtr<T>& rhs )
-          // ...exchange ownership with |rhs|; can save a pair of refcount operations
-        {
-          T* temp = rhs.mRawPtr;
-          rhs.mRawPtr = mRawPtr;
-          mRawPtr = temp;
-        }
-
-      void
-      swap( T*& rhs )
-          // ...exchange ownership with |rhs|; can save a pair of refcount operations
-        {
-          T* temp = rhs;
-          rhs = mRawPtr;
-          mRawPtr = temp;
-        }
-
-      already_AddRefed<T>
-      forget()
-          // return the value of mRawPtr and null out mRawPtr. Useful for
-          // already_AddRefed return values.
-        {
-          T* temp = 0;
-          swap(temp);
-          return temp;
-        }
-
-      template <typename I>
-      void
-      forget( I** rhs)
-          // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
-          // Useful to avoid unnecessary AddRef/Release pairs with "out"
-          // parameters where rhs bay be a T** or an I** where I is a base class
-          // of T.
-        {
-          NS_ASSERTION(rhs, "Null pointer passed to forget!");
-          *rhs = mRawPtr;
-          mRawPtr = 0;
-        }
-
-      T*
-      get() const
-          /*
-            Prefer the implicit conversion provided automatically by |operator T*() const|.
-            Use |get()| to resolve ambiguity or to get a castable pointer.
-          */
-        {
-          return const_cast<T*>(mRawPtr);
-        }
-
-      operator T*() const
-          /*
-            ...makes an |nsHtml5RefPtr| act like its underlying raw pointer type whenever it
-            is used in a context where a raw pointer is expected.  It is this operator
-            that makes an |nsHtml5RefPtr| substitutable for a raw pointer.
-
-            Prefer the implicit use of this operator to calling |get()|, except where
-            necessary to resolve ambiguity.
-          */
-        {
-          return get();
-        }
-
-      T*
-      operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
-        {
-          NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator->().");
-          return get();
-        }
-
-      nsHtml5RefPtr<T>*
-      get_address()
-          // This is not intended to be used by clients.  See |address_of|
-          // below.
-        {
-          return this;
-        }
-
-      const nsHtml5RefPtr<T>*
-      get_address() const
-          // This is not intended to be used by clients.  See |address_of|
-          // below.
-        {
-          return this;
-        }
-
-    public:
-      T&
-      operator*() const
-        {
-          NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator*().");
-          return *get();
-        }
-
-      T**
-      StartAssignment()
-        {
-#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
-          return reinterpret_cast<T**>(begin_assignment());
-#else
-          assign_assuming_AddRef(0);
-          return reinterpret_cast<T**>(&mRawPtr);
-#endif
-        }
-  };
-
-template <class T>
-inline
-nsHtml5RefPtr<T>*
-address_of( nsHtml5RefPtr<T>& aPtr )
-  {
-    return aPtr.get_address();
-  }
-
-template <class T>
-inline
-const nsHtml5RefPtr<T>*
-address_of( const nsHtml5RefPtr<T>& aPtr )
-  {
-    return aPtr.get_address();
-  }
-
-template <class T>
-class nsHtml5RefPtrGetterAddRefs
-    /*
-      ...
-
-      This class is designed to be used for anonymous temporary objects in the
-      argument list of calls that return COM interface pointers, e.g.,
-
-        nsHtml5RefPtr<IFoo> fooP;
-        ...->GetAddRefedPointer(getter_AddRefs(fooP))
-
-      DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE.  Use |getter_AddRefs()| instead.
-
-      When initialized with a |nsHtml5RefPtr|, as in the example above, it returns
-      a |void**|, a |T**|, or an |nsISupports**| as needed, that the
-      outer call (|GetAddRefedPointer| in this case) can fill in.
-
-      This type should be a nested class inside |nsHtml5RefPtr<T>|.
-    */
-  {
-    public:
-      explicit
-      nsHtml5RefPtrGetterAddRefs( nsHtml5RefPtr<T>& aSmartPtr )
-          : mTargetSmartPtr(aSmartPtr)
-        {
-          // nothing else to do
-        }
-
-      operator void**()
-        {
-          return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
-        }
-
-      operator T**()
-        {
-          return mTargetSmartPtr.StartAssignment();
-        }
-
-      T*&
-      operator*()
-        {
-          return *(mTargetSmartPtr.StartAssignment());
-        }
-
-    private:
-      nsHtml5RefPtr<T>& mTargetSmartPtr;
-  };
-
-template <class T>
-inline
-nsHtml5RefPtrGetterAddRefs<T>
-getter_AddRefs( nsHtml5RefPtr<T>& aSmartPtr )
-    /*
-      Used around a |nsHtml5RefPtr| when 
-      ...makes the class |nsHtml5RefPtrGetterAddRefs<T>| invisible.
-    */
-  {
-    return nsHtml5RefPtrGetterAddRefs<T>(aSmartPtr);
-  }
-
-
-
-  // Comparing two |nsHtml5RefPtr|s
-
-template <class T, class U>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, const nsHtml5RefPtr<U>& rhs )
-  {
-    return static_cast<const T*>(lhs.get()) == static_cast<const U*>(rhs.get());
-  }
-
-
-template <class T, class U>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, const nsHtml5RefPtr<U>& rhs )
-  {
-    return static_cast<const T*>(lhs.get()) != static_cast<const U*>(rhs.get());
-  }
-
-
-  // Comparing an |nsHtml5RefPtr| to a raw pointer
-
-template <class T, class U>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, const U* rhs )
-  {
-    return static_cast<const T*>(lhs.get()) == static_cast<const U*>(rhs);
-  }
-
-template <class T, class U>
-inline
-bool
-operator==( const U* lhs, const nsHtml5RefPtr<T>& rhs )
-  {
-    return static_cast<const U*>(lhs) == static_cast<const T*>(rhs.get());
-  }
-
-template <class T, class U>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, const U* rhs )
-  {
-    return static_cast<const T*>(lhs.get()) != static_cast<const U*>(rhs);
-  }
-
-template <class T, class U>
-inline
-bool
-operator!=( const U* lhs, const nsHtml5RefPtr<T>& rhs )
-  {
-    return static_cast<const U*>(lhs) != static_cast<const T*>(rhs.get());
-  }
-
-template <class T, class U>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, U* rhs )
-  {
-    return static_cast<const T*>(lhs.get()) == const_cast<const U*>(rhs);
-  }
-
-template <class T, class U>
-inline
-bool
-operator==( U* lhs, const nsHtml5RefPtr<T>& rhs )
-  {
-    return const_cast<const U*>(lhs) == static_cast<const T*>(rhs.get());
-  }
-
-template <class T, class U>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, U* rhs )
-  {
-    return static_cast<const T*>(lhs.get()) != const_cast<const U*>(rhs);
-  }
-
-template <class T, class U>
-inline
-bool
-operator!=( U* lhs, const nsHtml5RefPtr<T>& rhs )
-  {
-    return const_cast<const U*>(lhs) != static_cast<const T*>(rhs.get());
-  }
-
-
-
-  // Comparing an |nsHtml5RefPtr| to |0|
-
-template <class T>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, decltype(nullptr) )
-  {
-    return lhs.get() == nullptr;
-  }
-
-template <class T>
-inline
-bool
-operator==( decltype(nullptr), const nsHtml5RefPtr<T>& rhs )
-  {
-    return nullptr == rhs.get();
-  }
-
-template <class T>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, decltype(nullptr) )
-  {
-    return lhs.get() != nullptr;
-  }
-
-template <class T>
-inline
-bool
-operator!=( decltype(nullptr), const nsHtml5RefPtr<T>& rhs )
-  {
-    return nullptr != rhs.get();
-  }
-
-#endif // !defined(nsHtml5RefPtr_h)
--- a/parser/html/nsHtml5StreamListener.h
+++ b/parser/html/nsHtml5StreamListener.h
@@ -2,35 +2,35 @@
  * 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 nsHtml5StreamListener_h
 #define nsHtml5StreamListener_h
 
 #include "nsIStreamListener.h"
 #include "nsIThreadRetargetableStreamListener.h"
-#include "nsHtml5RefPtr.h"
+#include "nsHtml5StreamParserPtr.h"
 #include "nsHtml5StreamParser.h"
 
 /**
  * The purpose of this class is to reconcile the problem that
  * nsHtml5StreamParser is a cycle collection participant, which means that it
  * can only be refcounted on the main thread, but
  * nsIThreadRetargetableStreamListener can be refcounted from another thread,
  * so nsHtml5StreamParser being an nsIThreadRetargetableStreamListener was
  * a memory corruption problem.
  *
- * mDelegate is an nsHtml5RefPtr, which releases the object that it points
+ * mDelegate is an nsHtml5StreamParserPtr, which releases the object that it points
  * to from a runnable on the main thread. DropDelegate() is only called on
  * the main thread. This call will finish before the main-thread derefs the
  * nsHtml5StreamListener itself, so there is no risk of another thread making
  * the refcount of nsHtml5StreamListener go to zero and running the destructor
  * concurrently. Other than that, the thread-safe nsISupports implementation
  * takes care of the destructor not running concurrently from different
- * threads, so there is no need to have a mutex around nsHtml5RefPtr to
+ * threads, so there is no need to have a mutex around nsHtml5StreamParserPtr to
  * prevent it from double-releasing nsHtml5StreamParser.
  */
 class nsHtml5StreamListener : public nsIStreamListener,
                               public nsIThreadRetargetableStreamListener
 {
 public:
   explicit nsHtml5StreamListener(nsHtml5StreamParser* aDelegate);
 
@@ -44,12 +44,12 @@ public:
     return mDelegate;
   }
 
   void DropDelegate();
 
 private:
   virtual ~nsHtml5StreamListener();
 
-  nsHtml5RefPtr<nsHtml5StreamParser> mDelegate;
+  nsHtml5StreamParserPtr mDelegate;
 };
 
 #endif // nsHtml5StreamListener_h
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -10,30 +10,31 @@
 #include "mozilla/Encoding.h"
 #include "nsContentUtils.h"
 #include "nsHtml5Tokenizer.h"
 #include "nsIHttpChannel.h"
 #include "nsHtml5Parser.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5AtomTable.h"
 #include "nsHtml5Module.h"
-#include "nsHtml5RefPtr.h"
+#include "nsHtml5StreamParserPtr.h"
 #include "nsIScriptError.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "nsHtml5Highlighter.h"
 #include "expat_config.h"
 #include "expat.h"
 #include "nsINestedURI.h"
 #include "nsCharsetSource.h"
 #include "nsIWyciwygChannel.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsPrintfCString.h"
 #include "nsNetUtil.h"
 #include "nsXULAppAPI.h"
+#include "mozilla/SchedulerGroup.h"
 
 using namespace mozilla;
 
 int32_t nsHtml5StreamParser::sTimerInitialDelay = 120;
 int32_t nsHtml5StreamParser::sTimerSubsequentDelay = 120;
 
 // static
 void
@@ -47,22 +48,22 @@ nsHtml5StreamParser::InitializeStatics()
 
 /*
  * Note that nsHtml5StreamParser implements cycle collecting AddRef and
  * Release. Therefore, nsHtml5StreamParser must never be refcounted from
  * the parser thread!
  *
  * To work around this limitation, runnables posted by the main thread to the
  * parser thread hold their reference to the stream parser in an
- * nsHtml5RefPtr. Upon creation, nsHtml5RefPtr addrefs the object it holds
+ * nsHtml5StreamParserPtr. Upon creation, nsHtml5StreamParserPtr addrefs the object it holds
  * just like a regular nsRefPtr. This is OK, since the creation of the
- * runnable and the nsHtml5RefPtr happens on the main thread.
+ * runnable and the nsHtml5StreamParserPtr happens on the main thread.
  *
  * When the runnable is done on the parser thread, the destructor of
- * nsHtml5RefPtr runs there. It doesn't call Release on the held object
+ * nsHtml5StreamParserPtr runs there. It doesn't call Release on the held object
  * directly. Instead, it posts another runnable back to the main thread where
  * that runnable calls Release on the wrapped object.
  *
  * When posting runnables in the other direction, the runnables have to be
  * created on the main thread when nsHtml5StreamParser is instantiated and
  * held for the lifetime of the nsHtml5StreamParser. This works, because the
  * same runnabled can be dispatched multiple times and currently runnables
  * posted from the parser thread to main thread don't need to wrap any
@@ -950,18 +951,24 @@ nsHtml5StreamParser::OnStartRequest(nsIR
 
   rv = NS_OK;
 
   // The line below means that the encoding can end up being wrong if
   // a view-source URL is loaded without having the encoding hint from a
   // previous normal load in the history.
   mReparseForbidden = !(mMode == NORMAL || mMode == PLAIN_TEXT);
 
+  mDocGroup = mExecutor->GetDocument()->GetDocGroup();
+
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mRequest, &rv));
   if (NS_SUCCEEDED(rv)) {
+    // Non-HTTP channels are bogus enough that we let them work with unlabeled
+    // runnables for now. Asserting for HTTP channels only.
+    MOZ_ASSERT(mDocGroup || mMode == LOAD_AS_DATA, "How come the doc group is still null?");
+
     nsAutoCString method;
     Unused << httpChannel->GetRequestMethod(method);
     // XXX does Necko have a way to renavigate POST, etc. without hitting
     // the network?
     if (!method.EqualsLiteral("GET")) {
       // This is the old Gecko behavior but the HTML5 spec disagrees.
       // Don't reparse on POST.
       mReparseForbidden = true;
@@ -1054,17 +1061,18 @@ nsHtml5StreamParser::DoStopRequest()
   }
 
   ParseAvailableData();
 }
 
 class nsHtml5RequestStopper : public Runnable
 {
   private:
-    nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
+    nsHtml5StreamParserPtr mStreamParser;
+
   public:
     explicit nsHtml5RequestStopper(nsHtml5StreamParser* aStreamParser)
       : Runnable("nsHtml5RequestStopper")
       , mStreamParser(aStreamParser)
     {}
     NS_IMETHOD Run() override
     {
       mozilla::MutexAutoLock autoLock(mStreamParser->mTokenizerMutex);
@@ -1140,19 +1148,20 @@ nsHtml5StreamParser::DoDataAvailable(con
       "nsHtml5StreamParser::DoDataAvailable");
   }
   mFlushTimerArmed = true;
 }
 
 class nsHtml5DataAvailable : public Runnable
 {
   private:
-    nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
-    UniquePtr<uint8_t[]>               mData;
-    uint32_t                           mLength;
+    nsHtml5StreamParserPtr mStreamParser;
+    UniquePtr<uint8_t[]> mData;
+    uint32_t mLength;
+
   public:
     nsHtml5DataAvailable(nsHtml5StreamParser* aStreamParser,
                          UniquePtr<uint8_t[]> aData,
                          uint32_t             aLength)
       : Runnable("nsHtml5DataAvailable")
       , mStreamParser(aStreamParser)
       , mData(Move(aData))
       , mLength(aLength)
@@ -1337,19 +1346,17 @@ nsHtml5StreamParser::FlushTreeOpsAndDisa
     }
     mFlushTimerArmed = false;
   }
   if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
     mTokenizer->FlushViewSource();
   }
   mTreeBuilder->Flush();
   nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
-  if (NS_FAILED(mExecutor->GetDocument()->Dispatch("nsHtml5ExecutorFlusher",
-                                                   TaskCategory::Other,
-                                                   runnable.forget()))) {
+  if (NS_FAILED(DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
     NS_WARNING("failed to dispatch executor flush event");
   }
 }
 
 void
 nsHtml5StreamParser::ParseAvailableData()
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
@@ -1370,21 +1377,25 @@ nsHtml5StreamParser::ParseAvailableData(
           case STREAM_BEING_READ:
             // never release the last buffer.
             if (!mSpeculating) {
               // reuse buffer space if not speculating
               mFirstBuffer->setStart(0);
               mFirstBuffer->setEnd(0);
             }
             mTreeBuilder->FlushLoads();
-            // Dispatch this runnable unconditionally, because the loads
-            // that need flushing may have been flushed earlier even if the
-            // flush right above here did nothing.
-            if (NS_FAILED(NS_DispatchToMainThread(mLoadFlusher))) {
-              NS_WARNING("failed to dispatch load flush event");
+            {
+              // Dispatch this runnable unconditionally, because the loads
+              // that need flushing may have been flushed earlier even if the
+              // flush right above here did nothing.
+              nsCOMPtr<nsIRunnable> runnable(mLoadFlusher);
+              if (NS_FAILED(
+                    DispatchToMain("nsHtml5LoadFlusher", runnable.forget()))) {
+                NS_WARNING("failed to dispatch load flush event");
+              }
             }
             return; // no more data for now but expecting more
           case STREAM_ENDED:
             if (mAtEOF) {
               return;
             }
             mAtEOF = true;
             if (mCharsetSource < kCharsetFromMetaTag) {
@@ -1471,17 +1482,18 @@ nsHtml5StreamParser::ParseAvailableData(
     }
     continue;
   }
 }
 
 class nsHtml5StreamParserContinuation : public Runnable
 {
 private:
-  nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
+  nsHtml5StreamParserPtr mStreamParser;
+
 public:
   explicit nsHtml5StreamParserContinuation(nsHtml5StreamParser* aStreamParser)
     : Runnable("nsHtml5StreamParserContinuation")
     , mStreamParser(aStreamParser)
   {}
   NS_IMETHOD Run() override
   {
     mozilla::MutexAutoLock autoLock(mStreamParser->mTokenizerMutex);
@@ -1635,17 +1647,18 @@ nsHtml5StreamParser::ContinueAfterFailed
   if (NS_FAILED(mEventTarget->Dispatch(event, nsIThread::DISPATCH_NORMAL))) {
     NS_WARNING("Failed to dispatch nsHtml5StreamParserContinuation");
   }
 }
 
 class nsHtml5TimerKungFu : public Runnable
 {
 private:
-  nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
+  nsHtml5StreamParserPtr mStreamParser;
+
 public:
   explicit nsHtml5TimerKungFu(nsHtml5StreamParser* aStreamParser)
     : Runnable("nsHtml5TimerKungFu")
     , mStreamParser(aStreamParser)
   {}
   NS_IMETHOD Run() override
   {
     mozilla::MutexAutoLock flushTimerLock(mStreamParser->mFlushTimerMutex);
@@ -1668,20 +1681,20 @@ nsHtml5StreamParser::DropTimer()
    * the thread where nsTimerImpl::Fire would run. It's not safe to
    * dispatch a runnable to cancel the timer from the destructor of this
    * class, because the timer has a weak (void*) pointer back to this instance
    * of the stream parser and having the timer fire before the runnable
    * cancels it would make the timer access a deleted object.
    *
    * This DropTimer method addresses these issues. This method must be called
    * on the main thread before the destructor of this class is reached.
-   * The nsHtml5TimerKungFu object has an nsHtml5RefPtr that addrefs this
+   * The nsHtml5TimerKungFu object has an nsHtml5StreamParserPtr that addrefs this
    * stream parser object to keep it alive until the runnable is done.
    * The runnable cancels the timer on the parser thread, drops the timer
-   * and lets nsHtml5RefPtr send a runnable back to the main thread to
+   * and lets nsHtml5StreamParserPtr send a runnable back to the main thread to
    * release the stream parser.
    */
   mozilla::MutexAutoLock flushTimerLock(mFlushTimerMutex);
   if (mFlushTimer) {
     nsCOMPtr<nsIRunnable> event = new nsHtml5TimerKungFu(this);
     if (NS_FAILED(mEventTarget->Dispatch(event, nsIThread::DISPATCH_NORMAL))) {
       NS_WARNING("Failed to dispatch TimerKungFu event");
     }
@@ -1712,37 +1725,54 @@ nsHtml5StreamParser::TimerFlush()
 
   if (IsTerminatedOrInterrupted()) {
     return;
   }
 
   if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
     mTreeBuilder->Flush(); // delete useless ops
     if (mTokenizer->FlushViewSource()) {
-       if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
-         NS_WARNING("failed to dispatch executor flush event");
-       }
-     }
+      nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
+      if (NS_FAILED(
+            DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
+        NS_WARNING("failed to dispatch executor flush event");
+      }
+    }
   } else {
     // we aren't speculating and we don't know when new data is
     // going to arrive. Send data to the main thread.
     if (mTreeBuilder->Flush(true)) {
-      if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
+      nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
+      if (NS_FAILED(
+            DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
         NS_WARNING("failed to dispatch executor flush event");
       }
     }
   }
 }
 
 void
 nsHtml5StreamParser::MarkAsBroken(nsresult aRv)
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   mTokenizerMutex.AssertCurrentThreadOwns();
 
   Terminate();
   mTreeBuilder->MarkAsBroken(aRv);
   mozilla::DebugOnly<bool> hadOps = mTreeBuilder->Flush(false);
   NS_ASSERTION(hadOps, "Should have had the markAsBroken op!");
-  if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
+  nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
+  if (NS_FAILED(DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
     NS_WARNING("failed to dispatch executor flush event");
   }
 }
+
+nsresult
+nsHtml5StreamParser::DispatchToMain(const char* aName,
+                                    already_AddRefed<nsIRunnable>&& aRunnable)
+{
+  nsCOMPtr<nsIRunnable> runnable(aRunnable);
+  if (mDocGroup) {
+    return mDocGroup->Dispatch(aName, TaskCategory::Network, runnable.forget());
+  }
+  return SchedulerGroup::UnlabeledDispatch(
+    aName, TaskCategory::Network, runnable.forget());
+}
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -16,16 +16,17 @@
 #include "nsIInputStream.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/UniquePtr.h"
 #include "nsHtml5AtomTable.h"
 #include "nsHtml5Speculation.h"
 #include "nsISerialEventTarget.h"
 #include "nsITimer.h"
 #include "nsICharsetDetector.h"
+#include "mozilla/dom/DocGroup.h"
 
 class nsHtml5Parser;
 
 #define NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE 1024
 #define NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE 1024
 
 enum eParserMode {
   /**
@@ -104,59 +105,60 @@ enum eHtml5StreamState {
 class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
   template <typename T> using NotNull = mozilla::NotNull<T>;
   using Encoding = mozilla::Encoding;
 
   friend class nsHtml5RequestStopper;
   friend class nsHtml5DataAvailable;
   friend class nsHtml5StreamParserContinuation;
   friend class nsHtml5TimerKungFu;
-
-  public:
-    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
-                                             nsICharsetDetectionObserver)
+  friend class nsHtml5StreamParserPtr;
 
-    static void InitializeStatics();
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
+                                           nsICharsetDetectionObserver)
 
-    nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
-                        nsHtml5Parser* aOwner,
-                        eParserMode aMode);
+  static void InitializeStatics();
 
-    // Methods that nsHtml5StreamListener calls
-    nsresult CheckListenerChain();
+  nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
+                      nsHtml5Parser* aOwner,
+                      eParserMode aMode);
 
-    nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
+  // Methods that nsHtml5StreamListener calls
+  nsresult CheckListenerChain();
+
+  nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
 
-    nsresult OnDataAvailable(nsIRequest* aRequest,
-                             nsISupports* aContext,
-                             nsIInputStream* aInStream,
-                             uint64_t aSourceOffset,
-                             uint32_t aLength);
+  nsresult OnDataAvailable(nsIRequest* aRequest,
+                           nsISupports* aContext,
+                           nsIInputStream* aInStream,
+                           uint64_t aSourceOffset,
+                           uint32_t aLength);
 
-    nsresult OnStopRequest(nsIRequest* aRequest,
-                           nsISupports* aContext,
-                           nsresult status);
+  nsresult OnStopRequest(nsIRequest* aRequest,
+                         nsISupports* aContext,
+                         nsresult status);
 
-    // nsICharsetDetectionObserver
-    /**
+  // nsICharsetDetectionObserver
+  /**
      * Chardet calls this to report the detection result
      */
-    NS_IMETHOD Notify(const char* aCharset, nsDetectionConfident aConf) override;
+  NS_IMETHOD Notify(const char* aCharset, nsDetectionConfident aConf) override;
 
-    // EncodingDeclarationHandler
-    // https://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/common/EncodingDeclarationHandler.java
-    /**
+  // EncodingDeclarationHandler
+  // https://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/common/EncodingDeclarationHandler.java
+  /**
      * Tree builder uses this to report a late <meta charset>
      */
-    bool internalEncodingDeclaration(nsHtml5String aEncoding);
+  bool internalEncodingDeclaration(nsHtml5String aEncoding);
 
-    // Not from an external interface
+  // Not from an external interface
 
-    /**
+  /**
      *  Call this method once you've created a parser, and want to instruct it
      *  about what charset to load
      *
      *  @param   aEncoding the charset of a document
      *  @param   aCharsetSource the source of the charset
      */
     inline void SetDocumentCharset(NotNull<const Encoding*> aEncoding,
                                    int32_t aSource) {
@@ -379,16 +381,23 @@ class nsHtml5StreamParser final : public
      * small (so most pages are not affected) but small enough that we don't end
      * up with failed speculations over and over in pathological cases.
      */
     bool IsSpeculationEnabled()
     {
         return mSpeculationFailureCount < 100;
     }
 
+    /**
+     * Dispatch an event to a Quantum DOM main thread-ish thread.
+     * (Not the parser thread.)
+     */
+    nsresult DispatchToMain(const char* aName,
+                            already_AddRefed<nsIRunnable>&& aRunnable);
+
     nsCOMPtr<nsIRequest>          mRequest;
     nsCOMPtr<nsIRequestObserver>  mObserver;
 
     /**
      * The document title to use if this turns out to be a View Source parser.
      */
     nsCString                     mViewSourceTitle;
 
@@ -446,16 +455,21 @@ class nsHtml5StreamParser final : public
                       // a buffer of the size NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE
 
     /**
      * The tree operation executor
      */
     nsHtml5TreeOpExecutor*        mExecutor;
 
     /**
+     * The same as mExecutor->mDocument->mDocGroup.
+     */
+    RefPtr<mozilla::dom::DocGroup> mDocGroup;
+
+    /**
      * The HTML5 tree builder
      */
     nsAutoPtr<nsHtml5TreeBuilder> mTreeBuilder;
 
     /**
      * The HTML5 tokenizer
      */
     nsAutoPtr<nsHtml5Tokenizer>   mTokenizer;
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5StreamParserPtr.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef nsHtml5StreamParserPtr_h
+#define nsHtml5StreamParserPtr_h
+#include "nsThreadUtils.h"
+#include "mozilla/dom/DocGroup.h"
+
+class nsHtml5StreamParserReleaser : public mozilla::Runnable
+{
+private:
+  nsHtml5StreamParser* mPtr;
+
+public:
+  explicit nsHtml5StreamParserReleaser(nsHtml5StreamParser* aPtr)
+    : mozilla::Runnable("nsHtml5StreamParserReleaser")
+    , mPtr(aPtr)
+  {
+  }
+  NS_IMETHOD Run() override
+  {
+    mPtr->Release();
+    return NS_OK;
+  }
+};
+/**
+ * Like nsRefPtr except release is proxied to the main
+ * thread. Mostly copied from nsRefPtr.
+ */
+class nsHtml5StreamParserPtr
+{
+private:
+  void assign_with_AddRef(nsHtml5StreamParser* rawPtr)
+  {
+    if (rawPtr)
+      rawPtr->AddRef();
+    assign_assuming_AddRef(rawPtr);
+  }
+  void** begin_assignment()
+  {
+    assign_assuming_AddRef(0);
+    return reinterpret_cast<void**>(&mRawPtr);
+  }
+  void assign_assuming_AddRef(nsHtml5StreamParser* newPtr)
+  {
+    nsHtml5StreamParser* oldPtr = mRawPtr;
+    mRawPtr = newPtr;
+    if (oldPtr)
+      release(oldPtr);
+  }
+  void release(nsHtml5StreamParser* aPtr)
+  {
+    nsCOMPtr<nsIRunnable> releaser = new nsHtml5StreamParserReleaser(aPtr);
+    if (NS_FAILED(aPtr->DispatchToMain("nsHtml5StreamParserReleaser",
+                                       releaser.forget()))) {
+      NS_WARNING("Failed to dispatch releaser event.");
+    }
+  }
+
+private:
+  nsHtml5StreamParser* mRawPtr;
+
+public:
+  ~nsHtml5StreamParserPtr()
+  {
+    if (mRawPtr)
+      release(mRawPtr);
+  }
+  // Constructors
+  nsHtml5StreamParserPtr()
+    : mRawPtr(0)
+  // default constructor
+  {
+  }
+  nsHtml5StreamParserPtr(const nsHtml5StreamParserPtr& aSmartPtr)
+    : mRawPtr(aSmartPtr.mRawPtr)
+  // copy-constructor
+  {
+    if (mRawPtr)
+      mRawPtr->AddRef();
+  }
+  explicit nsHtml5StreamParserPtr(nsHtml5StreamParser* aRawPtr)
+    : mRawPtr(aRawPtr)
+  // construct from a raw pointer (of the right type)
+  {
+    if (mRawPtr)
+      mRawPtr->AddRef();
+  }
+  // Assignment operators
+  nsHtml5StreamParserPtr& operator=(const nsHtml5StreamParserPtr& rhs)
+  // copy assignment operator
+  {
+    assign_with_AddRef(rhs.mRawPtr);
+    return *this;
+  }
+  nsHtml5StreamParserPtr& operator=(nsHtml5StreamParser* rhs)
+  // assign from a raw pointer (of the right type)
+  {
+    assign_with_AddRef(rhs);
+    return *this;
+  }
+  // Other pointer operators
+  void swap(nsHtml5StreamParserPtr& rhs)
+  // ...exchange ownership with |rhs|; can save a pair of refcount operations
+  {
+    nsHtml5StreamParser* temp = rhs.mRawPtr;
+    rhs.mRawPtr = mRawPtr;
+    mRawPtr = temp;
+  }
+  void swap(nsHtml5StreamParser*& rhs)
+  // ...exchange ownership with |rhs|; can save a pair of refcount operations
+  {
+    nsHtml5StreamParser* temp = rhs;
+    rhs = mRawPtr;
+    mRawPtr = temp;
+  }
+  template<typename I>
+  void forget(I** rhs)
+  // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
+  // Useful to avoid unnecessary AddRef/Release pairs with "out"
+  // parameters where rhs bay be a T** or an I** where I is a base class
+  // of T.
+  {
+    NS_ASSERTION(rhs, "Null pointer passed to forget!");
+    *rhs = mRawPtr;
+    mRawPtr = 0;
+  }
+  nsHtml5StreamParser* get() const
+  /*
+            Prefer the implicit conversion provided automatically by |operator nsHtml5StreamParser*() const|.
+            Use |get()| to resolve ambiguity or to get a castable pointer.
+          */
+  {
+    return const_cast<nsHtml5StreamParser*>(mRawPtr);
+  }
+  operator nsHtml5StreamParser*() const
+  /*
+            ...makes an |nsHtml5StreamParserPtr| act like its underlying raw pointer type whenever it
+            is used in a context where a raw pointer is expected.  It is this operator
+            that makes an |nsHtml5StreamParserPtr| substitutable for a raw pointer.
+            Prefer the implicit use of this operator to calling |get()|, except where
+            necessary to resolve ambiguity.
+          */
+  {
+    return get();
+  }
+  nsHtml5StreamParser* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
+  {
+    NS_PRECONDITION(
+      mRawPtr != 0,
+      "You can't dereference a NULL nsHtml5StreamParserPtr with operator->().");
+    return get();
+  }
+  nsHtml5StreamParserPtr* get_address()
+  // This is not intended to be used by clients.  See |address_of|
+  // below.
+  {
+    return this;
+  }
+  const nsHtml5StreamParserPtr* get_address() const
+  // This is not intended to be used by clients.  See |address_of|
+  // below.
+  {
+    return this;
+  }
+
+public:
+  nsHtml5StreamParser& operator*() const
+  {
+    NS_PRECONDITION(
+      mRawPtr != 0,
+      "You can't dereference a NULL nsHtml5StreamParserPtr with operator*().");
+    return *get();
+  }
+  nsHtml5StreamParser** StartAssignment()
+  {
+#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
+    return reinterpret_cast<nsHtml5StreamParser**>(begin_assignment());
+#else
+    assign_assuming_AddRef(0);
+    return reinterpret_cast<nsHtml5StreamParser**>(&mRawPtr);
+#endif
+  }
+};
+
+inline nsHtml5StreamParserPtr*
+address_of(nsHtml5StreamParserPtr& aPtr)
+{
+  return aPtr.get_address();
+}
+
+inline const nsHtml5StreamParserPtr*
+address_of(const nsHtml5StreamParserPtr& aPtr)
+{
+  return aPtr.get_address();
+}
+
+class nsHtml5StreamParserPtrGetterAddRefs
+/*
+      ...
+      This class is designed to be used for anonymous temporary objects in the
+      argument list of calls that return COM interface pointers, e.g.,
+        nsHtml5StreamParserPtr<IFoo> fooP;
+        ...->GetAddRefedPointer(getter_AddRefs(fooP))
+      DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE.  Use |getter_AddRefs()| instead.
+      When initialized with a |nsHtml5StreamParserPtr|, as in the example above, it returns
+      a |void**|, a |T**|, or an |nsISupports**| as needed, that the
+      outer call (|GetAddRefedPointer| in this case) can fill in.
+      This type should be a nested class inside |nsHtml5StreamParserPtr<T>|.
+    */
+{
+public:
+  explicit nsHtml5StreamParserPtrGetterAddRefs(
+    nsHtml5StreamParserPtr& aSmartPtr)
+    : mTargetSmartPtr(aSmartPtr)
+  {
+    // nothing else to do
+  }
+  operator void**()
+  {
+    return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
+  }
+  operator nsHtml5StreamParser**() { return mTargetSmartPtr.StartAssignment(); }
+  nsHtml5StreamParser*& operator*()
+  {
+    return *(mTargetSmartPtr.StartAssignment());
+  }
+
+private:
+  nsHtml5StreamParserPtr& mTargetSmartPtr;
+};
+
+inline nsHtml5StreamParserPtrGetterAddRefs
+getter_AddRefs(nsHtml5StreamParserPtr& aSmartPtr)
+/*
+      Used around a |nsHtml5StreamParserPtr| when 
+      ...makes the class |nsHtml5StreamParserPtrGetterAddRefs| invisible.
+    */
+{
+  return nsHtml5StreamParserPtrGetterAddRefs(aSmartPtr);
+}
+
+// Comparing an |nsHtml5StreamParserPtr| to |0|
+
+inline bool
+operator==(const nsHtml5StreamParserPtr& lhs, decltype(nullptr))
+{
+  return lhs.get() == nullptr;
+}
+
+inline bool
+operator==(decltype(nullptr), const nsHtml5StreamParserPtr& rhs)
+{
+  return nullptr == rhs.get();
+}
+
+inline bool
+operator!=(const nsHtml5StreamParserPtr& lhs, decltype(nullptr))
+{
+  return lhs.get() != nullptr;
+}
+
+inline bool
+operator!=(decltype(nullptr), const nsHtml5StreamParserPtr& rhs)
+{
+  return nullptr != rhs.get();
+}
+#endif // !defined(nsHtml5StreamParserPtr_h)
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -234,20 +234,24 @@ nsHtml5TreeOpExecutor::MarkAsBroken(nsre
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   mBroken = aReason;
   if (mStreamParser) {
     mStreamParser->Terminate();
   }
   // We are under memory pressure, but let's hope the following allocation
   // works out so that we get to terminate and clean up the parser from
   // a safer point.
-  if (mParser) { // can mParser ever be null here?
-    MOZ_ALWAYS_SUCCEEDS(
-      NS_DispatchToMainThread(NewRunnableMethod("nsHtml5Parser::Terminate",
-                                                GetParser(), &nsHtml5Parser::Terminate)));
+  if (mParser && mDocument) { // can mParser ever be null here?
+    nsCOMPtr<nsIRunnable> terminator =
+      NewRunnableMethod("nsHtml5Parser::Terminate", GetParser(), &nsHtml5Parser::Terminate);
+    if (NS_FAILED(mDocument->Dispatch("nsHtml5Parser::Terminate",
+                                      TaskCategory::Network,
+                                      terminator.forget()))) {
+      NS_WARNING("failed to dispatch executor flush event");
+    }
   }
   return aReason;
 }
 
 void
 FlushTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   RefPtr<nsHtml5TreeOpExecutor> ex = gBackgroundFlushList->popFirst();
@@ -261,19 +265,19 @@ FlushTimerCallback(nsITimer* aTimer, voi
     NS_RELEASE(gFlushTimer);
   }
 }
 
 void
 nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync()
 {
   if (!mDocument || !mDocument->IsInBackgroundWindow()) {
-    nsCOMPtr<nsIRunnable> flusher = new nsHtml5ExecutorReflusher(this);  
+    nsCOMPtr<nsIRunnable> flusher = new nsHtml5ExecutorReflusher(this);
     if (NS_FAILED(mDocument->Dispatch("nsHtml5ExecutorReflusher",
-                                      TaskCategory::Other,
+                                      TaskCategory::Network,
                                       flusher.forget()))) {
       NS_WARNING("failed to dispatch executor flush event");
     }
   } else {
     if (!gBackgroundFlushList) {
       gBackgroundFlushList = new mozilla::LinkedList<nsHtml5TreeOpExecutor>();
     }
     if (!isInList()) {
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -609,19 +609,18 @@ nsHtml5TreeOperation::DoneCreatingElemen
 {
   aNode->DoneCreatingElement();
 }
 
 void
 nsHtml5TreeOperation::SvgLoad(nsIContent* aNode)
 {
   nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
-  if (NS_FAILED(aNode->OwnerDoc()->Dispatch("nsHtml5SVGLoadDispatcher",
-                                            TaskCategory::Other,
-                                            event.forget()))) {
+  if (NS_FAILED(aNode->OwnerDoc()->Dispatch(
+        "nsHtml5SVGLoadDispatcher", TaskCategory::Network, event.forget()))) {
     NS_WARNING("failed to dispatch svg load dispatcher");
   }
 }
 
 void
 nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
 {
   nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);