mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1518252 - Block layout on Fluent. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D17334 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
9359df8494
commit
5e38c8a5a5
@ -1339,7 +1339,8 @@ Document::Document(const char* aContentType)
|
||||
mThrowOnDynamicMarkupInsertionCounter(0),
|
||||
mIgnoreOpensDuringUnloadCounter(0),
|
||||
mDocLWTheme(Doc_Theme_Uninitialized),
|
||||
mSavedResolution(1.0f) {
|
||||
mSavedResolution(1.0f),
|
||||
mPendingInitialTranslation(false) {
|
||||
MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
|
||||
|
||||
SetIsInDocument();
|
||||
@ -3131,6 +3132,8 @@ void Document::LocalizationLinkAdded(Element* aLinkElement) {
|
||||
// will be resolved once the end of l10n resource
|
||||
// container is reached.
|
||||
mL10nResources.AppendElement(href);
|
||||
|
||||
mPendingInitialTranslation = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3173,11 +3176,30 @@ void Document::OnL10nResourceContainerParsed() {
|
||||
}
|
||||
|
||||
void Document::TriggerInitialDocumentTranslation() {
|
||||
// Let's call it again, in case the resource
|
||||
// container has not been closed, and only
|
||||
// now we're closing the document.
|
||||
OnL10nResourceContainerParsed();
|
||||
|
||||
if (mDocumentL10n) {
|
||||
mDocumentL10n->TriggerInitialDocumentTranslation();
|
||||
}
|
||||
}
|
||||
|
||||
void Document::InitialDocumentTranslationCompleted() {
|
||||
mPendingInitialTranslation = false;
|
||||
|
||||
nsCOMPtr<nsIContentSink> sink;
|
||||
if (mParser) {
|
||||
sink = mParser->GetContentSink();
|
||||
} else {
|
||||
sink = do_QueryReferent(mWeakSink);
|
||||
}
|
||||
if (sink) {
|
||||
sink->InitialDocumentTranslationCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
bool Document::IsWebAnimationsEnabled(JSContext* aCx, JSObject* /*unused*/) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@ -8141,7 +8163,6 @@ void Document::SetReadyStateInternal(ReadyState rs) {
|
||||
mXULPersist->Init();
|
||||
}
|
||||
}
|
||||
TriggerInitialDocumentTranslation();
|
||||
}
|
||||
|
||||
RecordNavigationTiming(rs);
|
||||
|
@ -3425,13 +3425,12 @@ class Document : public nsINode,
|
||||
*/
|
||||
void LocalizationLinkRemoved(Element* aLinkElement);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This method should be collect as soon as the
|
||||
* This method should be called as soon as the
|
||||
* parsing of the document is completed.
|
||||
*
|
||||
* In HTML this happens when readyState becomes
|
||||
* `interactive`.
|
||||
* In HTML/XHTML this happens when we finish parsing
|
||||
* the document element.
|
||||
* In XUL it happens at `DoneWalking`, during
|
||||
* `MozBeforeInitialXULLayout`.
|
||||
*
|
||||
@ -3440,6 +3439,18 @@ class Document : public nsINode,
|
||||
*/
|
||||
void TriggerInitialDocumentTranslation();
|
||||
|
||||
/**
|
||||
* This method is called when the initial translation
|
||||
* of the document is completed.
|
||||
*
|
||||
* It unblocks the layout.
|
||||
*
|
||||
* This method is virtual so that XULDocument can
|
||||
* override it.
|
||||
*/
|
||||
virtual void InitialDocumentTranslationCompleted();
|
||||
|
||||
protected:
|
||||
RefPtr<mozilla::dom::DocumentL10n> mDocumentL10n;
|
||||
|
||||
private:
|
||||
@ -4513,9 +4524,13 @@ class Document : public nsINode,
|
||||
// Pres shell resolution saved before entering fullscreen mode.
|
||||
float mSavedResolution;
|
||||
|
||||
bool mPendingInitialTranslation;
|
||||
|
||||
public:
|
||||
// Needs to be public because the bindings code pokes at it.
|
||||
js::ExpandoAndGeneration mExpandoAndGeneration;
|
||||
|
||||
bool HasPendingInitialTranslation() { return mPendingInitialTranslation; }
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(Document, NS_IDOCUMENT_IID)
|
||||
|
@ -1170,8 +1170,9 @@ void nsContentSink::StartLayout(bool aIgnorePendingSheets) {
|
||||
|
||||
mDeferredLayoutStart = true;
|
||||
|
||||
if (!aIgnorePendingSheets && WaitForPendingSheets()) {
|
||||
// Bail out; we'll start layout when the sheets load
|
||||
if (!aIgnorePendingSheets &&
|
||||
(WaitForPendingSheets() || mDocument->HasPendingInitialTranslation())) {
|
||||
// Bail out; we'll start layout when the sheets and l10n load
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1073,6 +1073,8 @@ nsresult nsXMLContentSink::HandleEndElement(const char16_t* aName,
|
||||
// probably need to deal here.... (and stop appending them on open).
|
||||
mState = eXMLContentSinkState_InEpilog;
|
||||
|
||||
mDocument->TriggerInitialDocumentTranslation();
|
||||
|
||||
// We might have had no occasion to start layout yet. Do so now.
|
||||
MaybeStartLayout(false);
|
||||
}
|
||||
@ -1407,6 +1409,10 @@ nsresult nsXMLContentSink::AddText(const char16_t* aText, int32_t aLength) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXMLContentSink::InitialDocumentTranslationCompleted() {
|
||||
StartLayout(false);
|
||||
}
|
||||
|
||||
void nsXMLContentSink::FlushPendingNotifications(FlushType aType) {
|
||||
// Only flush tags if we're not doing the notification ourselves
|
||||
// (since we aren't reentrant)
|
||||
|
@ -67,6 +67,7 @@ class nsXMLContentSink : public nsContentSink,
|
||||
NS_IMETHOD WillInterrupt(void) override;
|
||||
NS_IMETHOD WillResume(void) override;
|
||||
NS_IMETHOD SetParser(nsParserBase* aParser) override;
|
||||
virtual void InitialDocumentTranslationCompleted() override;
|
||||
virtual void FlushPendingNotifications(mozilla::FlushType aType) override;
|
||||
virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
|
||||
virtual nsISupports* GetTarget() override;
|
||||
|
@ -449,6 +449,11 @@ void XULDocument::AddElementToDocumentPost(Element* aElement) {
|
||||
}
|
||||
}
|
||||
|
||||
void XULDocument::InitialDocumentTranslationCompleted() {
|
||||
mPendingInitialTranslation = false;
|
||||
MaybeDoneWalking();
|
||||
}
|
||||
|
||||
void XULDocument::AddSubtreeToDocument(nsIContent* aContent) {
|
||||
MOZ_ASSERT(aContent->GetComposedDoc() == this, "Element not in doc!");
|
||||
|
||||
@ -958,15 +963,26 @@ nsresult XULDocument::ResumeWalk() {
|
||||
mXULPersist->Init();
|
||||
|
||||
mStillWalking = false;
|
||||
if (mPendingSheets == 0) {
|
||||
rv = DoneWalking();
|
||||
return MaybeDoneWalking();
|
||||
}
|
||||
|
||||
nsresult XULDocument::MaybeDoneWalking() {
|
||||
if (mPendingSheets > 0 || mStillWalking) {
|
||||
return NS_OK;
|
||||
}
|
||||
return rv;
|
||||
|
||||
if (mPendingInitialTranslation) {
|
||||
TriggerInitialDocumentTranslation();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoneWalking();
|
||||
}
|
||||
|
||||
nsresult XULDocument::DoneWalking() {
|
||||
MOZ_ASSERT(mPendingSheets == 0, "there are sheets to be loaded");
|
||||
MOZ_ASSERT(!mStillWalking, "walk not done");
|
||||
MOZ_ASSERT(!mPendingInitialTranslation, "translation pending");
|
||||
|
||||
// XXXldb This is where we should really be setting the chromehidden
|
||||
// attribute.
|
||||
@ -983,18 +999,10 @@ nsresult XULDocument::DoneWalking() {
|
||||
|
||||
NotifyPossibleTitleChange(false);
|
||||
|
||||
// For performance reasons, we want to trigger the DocumentL10n's
|
||||
// `TriggerInitialDocumentTranslation` within the same microtask that will
|
||||
// be created for a `MozBeforeInitialXULLayout` event listener.
|
||||
AddEventListener(NS_LITERAL_STRING("MozBeforeInitialXULLayout"),
|
||||
mDocumentL10n, true, false);
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(
|
||||
this, ToSupports(this), NS_LITERAL_STRING("MozBeforeInitialXULLayout"),
|
||||
CanBubble::eYes, Cancelable::eNo);
|
||||
|
||||
RemoveEventListener(NS_LITERAL_STRING("MozBeforeInitialXULLayout"),
|
||||
mDocumentL10n, true);
|
||||
|
||||
// Before starting layout, check whether we're a toplevel chrome
|
||||
// window. If we are, setup some state so that we don't have to restyle
|
||||
@ -1039,9 +1047,7 @@ XULDocument::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
|
||||
|
||||
--mPendingSheets;
|
||||
|
||||
if (!mStillWalking && mPendingSheets == 0) {
|
||||
return DoneWalking();
|
||||
}
|
||||
return MaybeDoneWalking();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -76,6 +76,8 @@ class XULDocument final : public XMLDocument,
|
||||
|
||||
virtual void EndLoad() override;
|
||||
|
||||
virtual void InitialDocumentTranslationCompleted() override;
|
||||
|
||||
// nsIMutationObserver interface
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
@ -296,7 +298,15 @@ class XULDocument final : public XMLDocument,
|
||||
nsresult ResumeWalk();
|
||||
|
||||
/**
|
||||
* Called at the end of ResumeWalk() and from StyleSheetLoaded().
|
||||
* Called at the end of ResumeWalk(), from StyleSheetLoaded(),
|
||||
* and from DocumentL10n.
|
||||
* If walking, stylesheets and l10n are not blocking, it
|
||||
* will trigger `DoneWalking()`.
|
||||
*/
|
||||
nsresult MaybeDoneWalking();
|
||||
|
||||
/**
|
||||
* Called from `MaybeDoneWalking()`.
|
||||
* Expects that both the prototype document walk is complete and
|
||||
* all referenced stylesheets finished loading.
|
||||
*/
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "mozilla/dom/DocumentL10n.h"
|
||||
#include "mozilla/dom/DocumentL10nBinding.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "nsQueryObject.h"
|
||||
@ -60,18 +59,12 @@ void PromiseResolver::RejectedCallback(JSContext* aCx,
|
||||
|
||||
PromiseResolver::~PromiseResolver() { mPromise = nullptr; }
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DocumentL10n)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DocumentL10n)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DocumentL10n)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DocumentL10n, mDocument, mDOMLocalization,
|
||||
mReady)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DocumentL10n, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DocumentL10n, Release)
|
||||
|
||||
DocumentL10n::DocumentL10n(Document* aDocument)
|
||||
: mDocument(aDocument), mState(DocumentL10nState::Initialized) {}
|
||||
|
||||
@ -140,19 +133,6 @@ already_AddRefed<Promise> DocumentL10n::MaybeWrapPromise(
|
||||
return docPromise.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentL10n::HandleEvent(Event* aEvent) {
|
||||
#ifdef DEBUG
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
MOZ_ASSERT(eventType.EqualsLiteral("MozBeforeInitialXULLayout"));
|
||||
#endif
|
||||
|
||||
TriggerInitialDocumentTranslation();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t DocumentL10n::AddResourceIds(nsTArray<nsString>& aResourceIds) {
|
||||
uint32_t ret = 0;
|
||||
mDOMLocalization->AddResourceIds(aResourceIds, false, &ret);
|
||||
@ -312,13 +292,16 @@ class L10nReadyHandler final : public PromiseNativeHandler {
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(L10nReadyHandler)
|
||||
|
||||
explicit L10nReadyHandler(Promise* aPromise) : mPromise(aPromise) {}
|
||||
explicit L10nReadyHandler(Promise* aPromise, Document* aDocument)
|
||||
: mPromise(aPromise), mDocument(aDocument) {}
|
||||
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
|
||||
mDocument->InitialDocumentTranslationCompleted();
|
||||
mPromise->MaybeResolveWithUndefined();
|
||||
}
|
||||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
|
||||
mDocument->InitialDocumentTranslationCompleted();
|
||||
mPromise->MaybeRejectWithUndefined();
|
||||
}
|
||||
|
||||
@ -326,6 +309,7 @@ class L10nReadyHandler final : public PromiseNativeHandler {
|
||||
~L10nReadyHandler() = default;
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
RefPtr<Document> mDocument;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(L10nReadyHandler, mPromise)
|
||||
@ -351,7 +335,8 @@ void DocumentL10n::TriggerInitialDocumentTranslation() {
|
||||
|
||||
RefPtr<Promise> promise;
|
||||
mDOMLocalization->TranslateRoots(getter_AddRefs(promise));
|
||||
RefPtr<PromiseNativeHandler> l10nReadyHandler = new L10nReadyHandler(mReady);
|
||||
RefPtr<PromiseNativeHandler> l10nReadyHandler =
|
||||
new L10nReadyHandler(mReady, mDocument);
|
||||
promise->AppendNativeHandler(l10nReadyHandler);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
@ -53,11 +52,10 @@ enum class DocumentL10nState { Initialized = 0, InitialTranslationTriggered };
|
||||
* instance of mozIDOMLocalization and maintains a single promise
|
||||
* which gets resolved the first time the document gets translated.
|
||||
*/
|
||||
class DocumentL10n final : public nsIDOMEventListener, public nsWrapperCache {
|
||||
class DocumentL10n final : public nsWrapperCache {
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DocumentL10n)
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DocumentL10n)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DocumentL10n)
|
||||
|
||||
public:
|
||||
explicit DocumentL10n(Document* aDocument);
|
||||
|
@ -170,6 +170,7 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated) {
|
||||
}
|
||||
|
||||
if (!destroying) {
|
||||
mDocument->TriggerInitialDocumentTranslation();
|
||||
nsContentSink::StartLayout(false);
|
||||
}
|
||||
}
|
||||
@ -228,6 +229,10 @@ nsHtml5TreeOpExecutor::SetParser(nsParserBase* aParser) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsHtml5TreeOpExecutor::InitialDocumentTranslationCompleted() {
|
||||
nsContentSink::StartLayout(false);
|
||||
}
|
||||
|
||||
void nsHtml5TreeOpExecutor::FlushPendingNotifications(FlushType aType) {
|
||||
if (aType >= FlushType::EnsurePresShellInitAndFrames) {
|
||||
// Bug 577508 / 253951
|
||||
|
@ -136,6 +136,8 @@ class nsHtml5TreeOpExecutor final
|
||||
*/
|
||||
NS_IMETHOD WillResume() override;
|
||||
|
||||
virtual void InitialDocumentTranslationCompleted() override;
|
||||
|
||||
/**
|
||||
* Sets the parser.
|
||||
*/
|
||||
|
@ -130,6 +130,8 @@ class nsIContentSink : public nsISupports {
|
||||
* Posts a runnable that continues parsing.
|
||||
*/
|
||||
virtual void ContinueInterruptedParsingAsync() {}
|
||||
|
||||
virtual void InitialDocumentTranslationCompleted() {}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentSink, NS_ICONTENT_SINK_IID)
|
||||
|
Loading…
Reference in New Issue
Block a user