зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1333990: Part 2d - Add a utility to block HTML parsing until sandbox scripts are ready. r=hsivonen,billm
In order to asynchronously load content scripts that need to run very early in the page load cycle, before any ordinary page scripts, we need to be able to block parsing from the document-element-inserted listener. Since the script loader operates by returning promises, blocking on promise resolution is the simplest way to achieve this. MozReview-Commit-ID: CTWlyrP6dqG --HG-- extra : rebase_source : 28ce713a6450c223f9b2089e6c6e8c78284ef8af
This commit is contained in:
Родитель
250fd89a21
Коммит
8d2a5ab915
|
@ -75,6 +75,8 @@
|
|||
#include "nsIDOMComment.h"
|
||||
#include "mozilla/dom/DocumentType.h"
|
||||
#include "mozilla/dom/NodeIterator.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/TreeWalker.h"
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
|
@ -2744,6 +2746,13 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIParser>
|
||||
nsDocument::CreatorParserOrNull()
|
||||
{
|
||||
nsCOMPtr<nsIParser> parser = mParser;
|
||||
return parser.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::StopDocumentLoad()
|
||||
{
|
||||
|
@ -10514,6 +10523,78 @@ nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv)
|
|||
}
|
||||
}
|
||||
|
||||
class UnblockParsingPromiseHandler final : public PromiseNativeHandler
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit UnblockParsingPromiseHandler(nsIDocument* aDocument, Promise* aPromise)
|
||||
: mDocument(aDocument)
|
||||
, mPromise(aPromise)
|
||||
{
|
||||
nsCOMPtr<nsIParser> parser = mDocument->CreatorParserOrNull();
|
||||
if (parser) {
|
||||
parser->BlockParser();
|
||||
} else {
|
||||
mDocument = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
MaybeUnblockParser();
|
||||
|
||||
mPromise->MaybeResolve(aCx, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
MaybeUnblockParser();
|
||||
|
||||
mPromise->MaybeReject(aCx, aValue);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~UnblockParsingPromiseHandler()
|
||||
{
|
||||
MaybeUnblockParser();
|
||||
}
|
||||
|
||||
private:
|
||||
void MaybeUnblockParser() {
|
||||
if (mDocument) {
|
||||
nsCOMPtr<nsIParser> parser = mDocument->CreatorParserOrNull();
|
||||
if (parser) {
|
||||
parser->UnblockParser();
|
||||
parser->ContinueInterruptedParsingAsync();
|
||||
}
|
||||
mDocument = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<nsIDocument> mDocument;
|
||||
RefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(UnblockParsingPromiseHandler)
|
||||
|
||||
already_AddRefed<Promise>
|
||||
nsIDocument::BlockParsing(OwningNonNull<Promise> aPromise,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<Promise> resultPromise = Promise::Create(aPromise->GetParentObject(), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PromiseNativeHandler> promiseHandler = new UnblockParsingPromiseHandler(this, resultPromise);
|
||||
aPromise->AppendNativeHandler(promiseHandler);
|
||||
|
||||
return resultPromise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsIDocument::GetMozDocumentURIIfNotForErrorPages()
|
||||
{
|
||||
|
|
|
@ -537,6 +537,8 @@ public:
|
|||
|
||||
virtual void ApplySettingsFromCSP(bool aSpeculative) override;
|
||||
|
||||
virtual already_AddRefed<nsIParser> CreatorParserOrNull() override;
|
||||
|
||||
/**
|
||||
* Set the principal responsible for this document.
|
||||
*/
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsIDocumentObserver.h" // for typedef (nsUpdateType)
|
||||
#include "nsILoadGroup.h" // for member (in nsCOMPtr)
|
||||
#include "nsINode.h" // for base class
|
||||
#include "nsIParser.h"
|
||||
#include "nsIScriptGlobalObject.h" // for member (in nsCOMPtr)
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
|
@ -359,6 +360,8 @@ public:
|
|||
*/
|
||||
virtual void ApplySettingsFromCSP(bool aSpeculative) = 0;
|
||||
|
||||
virtual already_AddRefed<nsIParser> CreatorParserOrNull() = 0;
|
||||
|
||||
/**
|
||||
* Return the referrer policy of the document. Return "default" if there's no
|
||||
* valid meta referrer tag found in the document.
|
||||
|
@ -2784,6 +2787,9 @@ public:
|
|||
|
||||
void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv);
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise> BlockParsing(mozilla::OwningNonNull<mozilla::dom::Promise> aPromise,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
|
||||
|
||||
// ParentNode
|
||||
|
|
|
@ -379,6 +379,10 @@ partial interface Document {
|
|||
|
||||
[ChromeOnly] readonly attribute nsILoadGroup? documentLoadGroup;
|
||||
|
||||
// Blocks the initial document parser until the given promise is settled.
|
||||
[ChromeOnly, Throws]
|
||||
Promise<any> blockParsing(Promise<any> promise);
|
||||
|
||||
// like documentURI, except that for error pages, it returns the URI we were
|
||||
// trying to load when we hit an error, rather than the error page's own URI.
|
||||
[ChromeOnly] readonly attribute URI? mozDocumentURIIfNotForErrorPages;
|
||||
|
|
Загрузка…
Ссылка в новой задаче