This commit is contained in:
Cameron Kaiser 2017-07-22 21:47:40 -07:00
parent b1cfd7830c
commit 61ec438893
2 changed files with 86 additions and 32 deletions

View File

@ -629,6 +629,15 @@ nsDocumentViewer::Init(nsIWidget* aParentWidget,
nsresult
nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow)
{
// We assert this because initializing the pres shell could otherwise cause
// re-entrancy into nsDocumentViewer methods, which might cause a different
// pres shell to be created. Callers of InitPresentationStuff should ensure
// the call is appropriately bounded by an nsAutoScriptBlocker to decide
// when it is safe for these re-entrant calls to be made.
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
"InitPresentationStuff must only be called when scripts are "
"blocked");
if (GetIsPrintPreview())
return NS_OK;
@ -1652,6 +1661,10 @@ nsDocumentViewer::Destroy()
// The document was not put in the bfcache
// Protect against pres shell destruction running scripts and re-entrantly
// creating a new presentation.
nsAutoScriptBlocker scriptBlocker;
if (mPresShell) {
DestroyPresShell();
}
@ -1817,6 +1830,10 @@ nsDocumentViewer::SetDocumentInternal(nsIDocument* aDocument,
// Replace the current pres shell with a new shell for the new document
// Protect against pres shell destruction running scripts and re-entrantly
// creating a new presentation.
nsAutoScriptBlocker scriptBlocker;
if (mPresShell) {
DestroyPresShell();
}
@ -2014,7 +2031,17 @@ nsDocumentViewer::Show(void)
}
}
// Hold on to the document so we can use it after the script blocker below
// has been released (which might re-entrantly call into other
// nsDocumentViewer methods).
nsCOMPtr<nsIDocument> document = mDocument;
if (mDocument && !mPresShell) {
// The InitPresentationStuff call below requires a script blocker, because
// its PresShell::Initialize call can cause scripts to run and therefore
// re-entrant calls to nsDocumentViewer methods to be made.
nsAutoScriptBlocker scriptBlocker;
NS_ASSERTION(!mWindow, "Window already created but no presshell?");
nsCOMPtr<nsIBaseWindow> base_win(mContainer);
@ -2076,7 +2103,7 @@ nsDocumentViewer::Show(void)
// Notify observers that a new page has been shown. This will get run
// from the event loop after we actually draw the page.
NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument));
NS_DispatchToMainThread(new nsDocumentShownDispatcher(document));
return NS_OK;
}
@ -2113,24 +2140,23 @@ nsDocumentViewer::Hide(void)
mPresShell->CaptureHistoryState(getter_AddRefs(layoutState));
}
{
// Do not run ScriptRunners queued by DestroyPresShell() in the intermediate
// state before we're done destroying PresShell, PresContext, ViewManager, etc.
nsAutoScriptBlocker scriptBlocker;
DestroyPresShell();
// Do not run ScriptRunners queued by DestroyPresShell() in the intermediate
// state before we're done destroying PresShell, PresContext, ViewManager, etc.
nsAutoScriptBlocker scriptBlocker;
DestroyPresContext();
DestroyPresShell();
mViewManager = nullptr;
mWindow = nullptr;
mDeviceContext = nullptr;
mParentWidget = nullptr;
DestroyPresContext();
nsCOMPtr<nsIBaseWindow> base_win(mContainer);
mViewManager = nullptr;
mWindow = nullptr;
mDeviceContext = nullptr;
mParentWidget = nullptr;
if (base_win && !mAttachedToParent) {
base_win->SetParentWidget(nullptr);
}
nsCOMPtr<nsIBaseWindow> base_win(mContainer);
if (base_win && !mAttachedToParent) {
base_win->SetParentWidget(nullptr);
}
return NS_OK;
@ -4153,9 +4179,14 @@ nsDocumentViewer::SetIsPrintPreview(bool aIsPrintPreview)
SetIsPrintingInDocShellTree(docShell, aIsPrintPreview, true);
}
if (!aIsPrintPreview) {
// Dispatch the 'afterprint' event now, if pending:
mBeforeAndAfterPrint = nullptr;
}
#endif
// Protect against pres shell destruction running scripts.
nsAutoScriptBlocker scriptBlocker;
if (!aIsPrintPreview) {
if (mPresShell) {
DestroyPresShell();
@ -4284,6 +4315,11 @@ NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aP
// reftests that require a paginated context
mIsPageMode = aPageMode;
// The DestroyPresShell call requires a script blocker, since the
// PresShell::Destroy call it does can cause scripts to run, which could
// re-entrantly call methods on the nsDocumentViewer.
nsAutoScriptBlocker scriptBlocker;
if (mPresShell) {
DestroyPresShell();
}
@ -4344,6 +4380,13 @@ nsDocumentViewer::SetIsHidden(bool aHidden)
void
nsDocumentViewer::DestroyPresShell()
{
// We assert this because destroying the pres shell could otherwise cause
// re-entrancy into nsDocumentViewer methods, and all callers of
// DestroyPresShell need to do other cleanup work afterwards before it
// is safe for those re-entrant method calls to be made.
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
"DestroyPresShell must only be called when scripts are blocked");
// Break circular reference (or something)
mPresShell->EndObservingDocument();
@ -4351,7 +4394,6 @@ nsDocumentViewer::DestroyPresShell()
if (selection && mSelectionListener)
selection->RemoveSelectionListener(mSelectionListener);
nsAutoScriptBlocker scriptBlocker;
mPresShell->Destroy();
mPresShell = nullptr;
}
@ -4380,6 +4422,10 @@ nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager,
nsPresContext* aPresContext,
nsIPresShell* aPresShell)
{
// Protect against pres shell destruction running scripts and re-entrantly
// creating a new presentation.
nsAutoScriptBlocker scriptBlocker;
if (mPresShell) {
DestroyPresShell();
}

View File

@ -1601,6 +1601,24 @@ PresShell::EndObservingDocument()
char* nsPresShell_ReflowStackPointerTop;
#endif
class XBLConstructorRunner : public nsRunnable
{
public:
explicit XBLConstructorRunner(nsIDocument* aDocument)
: mDocument(aDocument)
{
}
NS_IMETHOD Run() override
{
mDocument->BindingManager()->ProcessAttachedQueue();
return NS_OK;
}
private:
nsCOMPtr<nsIDocument> mDocument;
};
nsresult
PresShell::Initialize(nscoord aWidth, nscoord aHeight)
{
@ -1698,24 +1716,14 @@ PresShell::Initialize(nscoord aWidth, nscoord aHeight)
mFrameConstructor->EndUpdate();
}
// nsAutoScriptBlocker going out of scope may have killed us too
// nsAutoCauseReflowNotifier (which sets up a script blocker) going out of
// scope may have killed us too
NS_ENSURE_STATE(!mHaveShutDown);
// Run the XBL binding constructors for any new frames we've constructed
mDocument->BindingManager()->ProcessAttachedQueue();
// Constructors may have killed us too
NS_ENSURE_STATE(!mHaveShutDown);
// Now flush out pending restyles before we actually reflow, in
// case XBL constructors changed styles somewhere.
{
nsAutoScriptBlocker scriptBlocker;
mPresContext->RestyleManager()->ProcessPendingRestyles();
}
// And that might have run _more_ XBL constructors
NS_ENSURE_STATE(!mHaveShutDown);
// Run the XBL binding constructors for any new frames we've constructed.
// (Do this in a script runner, since our caller might have a script
// blocker on the stack.)
nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
}
NS_ASSERTION(rootFrame, "How did that happen?");