Bug 1387243 Part 1: Split nsDocument::EndLoad into a part that runs unconditionally, and a part that runs only when there is a matching BeginLoad call.
MozReview-Commit-ID: 8Pn6i2f0cez
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1348,16 +1348,17 @@ nsIDocument::nsIDocument()
mGetUserFontSetCalled(false),
mPostedFlushUserFontSet(false),
mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false),
mFrameRequestCallbacksScheduled(false),
mIsTopLevelContentDocument(false),
mIsContentDocument(false),
mMightHaveStaleServoData(false),
+ mDidCallBeginLoad(false),
mIsScopedStyleEnabled(eScopedStyle_Unknown),
mCompatMode(eCompatibility_FullStandards),
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
mStyleBackendType(StyleBackendType::None),
#ifdef MOZILLA_INTERNAL_API
mVisibilityState(dom::VisibilityState::Hidden),
#else
mDummy(0),
@@ -5156,16 +5157,19 @@ nsDocument::EndUpdate(nsUpdateType aUpda
MaybeEndOutermostXBLUpdate();
MaybeInitializeFinalizeFrameLoaders();
}
void
nsDocument::BeginLoad()
{
+ MOZ_ASSERT(!mDidCallBeginLoad);
+ mDidCallBeginLoad = true;
+
// Block onload here to prevent having to deal with blocking and
// unblocking it while we know the document is loading.
BlockOnload();
mDidFireDOMContentLoaded = false;
BlockDOMContentLoaded();
if (mScriptLoader) {
mScriptLoader->BeginDeferringScripts();
@@ -5414,26 +5418,44 @@ nsDocument::DispatchContentLoadedEvents(
}
UnblockOnload(true);
}
void
nsDocument::EndLoad()
{
+ // EndLoad may have been called without a matching call to BeginLoad, in the
+ // case of a failed parse (for example, due to timeout). In such a case, we
+ // still want to execute part of this code to do appropriate cleanup, but we
+ // gate part of it because it is intended to match 1-for-1 with calls to
+ // BeginLoad. We have an explicit flag bit for this purpose, since it's
+ // complicated and error prone to derive this condition from other related
+ // flags that can be manipulated outside of a BeginLoad/EndLoad pair.
+
+ // Part 1: Code that always executes to cleanup end of parsing, whether
+ // that parsing was successful or not.
+
// Drop the ref to our parser, if any, but keep hold of the sink so that we
// can flush it from FlushPendingNotifications as needed. We might have to
// do that to get a StartLayout() to happen.
if (mParser) {
mWeakSink = do_GetWeakReference(mParser->GetContentSink());
mParser = nullptr;
}
NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
+ // Part 2: Code that only executes when this EndLoad matches a BeginLoad.
+
+ if (!mDidCallBeginLoad) {
+ return;
+ }
+ mDidCallBeginLoad = false;
+
UnblockDOMContentLoaded();
}
void
nsDocument::UnblockDOMContentLoaded()
{
MOZ_ASSERT(mBlockDOMContentLoaded);
if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3301,16 +3301,19 @@ protected:
bool mIsTopLevelContentDocument : 1;
bool mIsContentDocument : 1;
// True if there may be Servo element data on Elements in the document that
// were created for a pres shell that no longer exists.
bool mMightHaveStaleServoData : 1;
+ // True if we have called BeginLoad and are expecting a paired EndLoad call.
+ bool mDidCallBeginLoad : 1;
+
// Whether <style scoped> support is enabled in this document.
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
unsigned int mIsScopedStyleEnabled : 2;
// Compatibility mode
nsCompatibility mCompatMode;
// Our readyState