mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Bug 1333333 - Label runnables in the HTML parser (again). r=billm.
MozReview-Commit-ID: 1Z89LSr46dN --HG-- extra : rebase_source : 4f7e31741fcfe65d6e6e44f3f0df9c9d6df31e7d
This commit is contained in:
parent
c0c4a86de4
commit
29ef683ca2
@ -35,11 +35,11 @@ EXPORTS += [
|
||||
'nsHtml5Parser.h',
|
||||
'nsHtml5PlainTextUtils.h',
|
||||
'nsHtml5Portability.h',
|
||||
'nsHtml5RefPtr.h',
|
||||
'nsHtml5Speculation.h',
|
||||
'nsHtml5SpeculativeLoad.h',
|
||||
'nsHtml5StreamListener.h',
|
||||
'nsHtml5StreamParser.h',
|
||||
'nsHtml5StreamParserPtr.h',
|
||||
'nsHtml5String.h',
|
||||
'nsHtml5StringParser.h',
|
||||
'nsHtml5SVGLoadDispatcher.h',
|
||||
|
@ -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)
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "nsHtml5RefPtr.h"
|
||||
#include "nsHtml5StreamParserPtr.h"
|
||||
#include "nsHtml5StreamParser.h"
|
||||
|
||||
/**
|
||||
@ -18,14 +18,14 @@
|
||||
* 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,
|
||||
@ -49,7 +49,7 @@ public:
|
||||
private:
|
||||
virtual ~nsHtml5StreamListener();
|
||||
|
||||
nsHtml5RefPtr<nsHtml5StreamParser> mDelegate;
|
||||
nsHtml5StreamParserPtr mDelegate;
|
||||
};
|
||||
|
||||
#endif // nsHtml5StreamListener_h
|
||||
|
@ -15,7 +15,7 @@
|
||||
#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"
|
||||
@ -29,6 +29,7 @@
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/SchedulerGroup.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -52,12 +53,12 @@ nsHtml5StreamParser::InitializeStatics()
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
@ -955,8 +956,14 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
// 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
|
||||
@ -1059,7 +1066,8 @@ nsHtml5StreamParser::DoStopRequest()
|
||||
class nsHtml5RequestStopper : public Runnable
|
||||
{
|
||||
private:
|
||||
nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
|
||||
nsHtml5StreamParserPtr mStreamParser;
|
||||
|
||||
public:
|
||||
explicit nsHtml5RequestStopper(nsHtml5StreamParser* aStreamParser)
|
||||
: Runnable("nsHtml5RequestStopper")
|
||||
@ -1145,9 +1153,10 @@ nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength)
|
||||
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,
|
||||
@ -1342,9 +1351,7 @@ nsHtml5StreamParser::FlushTreeOpsAndDisarmTimer()
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
@ -1375,11 +1382,15 @@ nsHtml5StreamParser::ParseAvailableData()
|
||||
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:
|
||||
@ -1476,7 +1487,8 @@ nsHtml5StreamParser::ParseAvailableData()
|
||||
class nsHtml5StreamParserContinuation : public Runnable
|
||||
{
|
||||
private:
|
||||
nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
|
||||
nsHtml5StreamParserPtr mStreamParser;
|
||||
|
||||
public:
|
||||
explicit nsHtml5StreamParserContinuation(nsHtml5StreamParser* aStreamParser)
|
||||
: Runnable("nsHtml5StreamParserContinuation")
|
||||
@ -1640,7 +1652,8 @@ nsHtml5StreamParser::ContinueAfterFailedCharsetSwitch()
|
||||
class nsHtml5TimerKungFu : public Runnable
|
||||
{
|
||||
private:
|
||||
nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
|
||||
nsHtml5StreamParserPtr mStreamParser;
|
||||
|
||||
public:
|
||||
explicit nsHtml5TimerKungFu(nsHtml5StreamParser* aStreamParser)
|
||||
: Runnable("nsHtml5TimerKungFu")
|
||||
@ -1673,10 +1686,10 @@ nsHtml5StreamParser::DropTimer()
|
||||
*
|
||||
* 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);
|
||||
@ -1717,15 +1730,19 @@ nsHtml5StreamParser::TimerFlush()
|
||||
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");
|
||||
}
|
||||
}
|
||||
@ -1742,7 +1759,20 @@ nsHtml5StreamParser::MarkAsBroken(nsresult aRv)
|
||||
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());
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "nsISerialEventTarget.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
|
||||
class nsHtml5Parser;
|
||||
|
||||
@ -109,49 +110,50 @@ class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
|
||||
friend class nsHtml5DataAvailable;
|
||||
friend class nsHtml5StreamParserContinuation;
|
||||
friend class nsHtml5TimerKungFu;
|
||||
friend class nsHtml5StreamParserPtr;
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
|
||||
nsICharsetDetectionObserver)
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
|
||||
nsICharsetDetectionObserver)
|
||||
|
||||
static void InitializeStatics();
|
||||
static void InitializeStatics();
|
||||
|
||||
nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
|
||||
nsHtml5Parser* aOwner,
|
||||
eParserMode aMode);
|
||||
nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
|
||||
nsHtml5Parser* aOwner,
|
||||
eParserMode aMode);
|
||||
|
||||
// Methods that nsHtml5StreamListener calls
|
||||
nsresult CheckListenerChain();
|
||||
// Methods that nsHtml5StreamListener calls
|
||||
nsresult CheckListenerChain();
|
||||
|
||||
nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
|
||||
nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
|
||||
|
||||
nsresult OnDataAvailable(nsIRequest* aRequest,
|
||||
nsISupports* aContext,
|
||||
nsIInputStream* aInStream,
|
||||
uint64_t aSourceOffset,
|
||||
uint32_t aLength);
|
||||
|
||||
nsresult OnStopRequest(nsIRequest* aRequest,
|
||||
nsresult OnDataAvailable(nsIRequest* aRequest,
|
||||
nsISupports* aContext,
|
||||
nsresult status);
|
||||
nsIInputStream* aInStream,
|
||||
uint64_t aSourceOffset,
|
||||
uint32_t aLength);
|
||||
|
||||
// nsICharsetDetectionObserver
|
||||
/**
|
||||
nsresult OnStopRequest(nsIRequest* aRequest,
|
||||
nsISupports* aContext,
|
||||
nsresult status);
|
||||
|
||||
// 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
|
||||
*
|
||||
@ -384,6 +386,13 @@ class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
|
||||
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;
|
||||
|
||||
@ -450,6 +459,11 @@ class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
|
||||
*/
|
||||
nsHtml5TreeOpExecutor* mExecutor;
|
||||
|
||||
/**
|
||||
* The same as mExecutor->mDocument->mDocGroup.
|
||||
*/
|
||||
RefPtr<mozilla::dom::DocGroup> mDocGroup;
|
||||
|
||||
/**
|
||||
* The HTML5 tree builder
|
||||
*/
|
||||
|
269
parser/html/nsHtml5StreamParserPtr.h
Normal file
269
parser/html/nsHtml5StreamParserPtr.h
Normal file
@ -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)
|
@ -239,10 +239,14 @@ nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason)
|
||||
// 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;
|
||||
}
|
||||
@ -266,9 +270,9 @@ 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");
|
||||
}
|
||||
|
@ -614,9 +614,8 @@ 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");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user