Bug 1289620 - Separate presshell attachment and detachment in nsPresContext. r=heycam

This commit is contained in:
Bobby Holley 2016-07-26 17:43:56 -07:00
Родитель 64639661c1
Коммит 1764385b32
3 изменённых файлов: 94 добавлений и 84 удалений

Просмотреть файл

@ -335,7 +335,7 @@ nsPresContext::Destroy()
nsPresContext::~nsPresContext()
{
NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
SetShell(nullptr);
DetachShell();
Destroy();
}
@ -903,92 +903,101 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
// Note: We don't hold a reference on the shell; it has a reference to
// us
void
nsPresContext::SetShell(nsIPresShell* aShell)
nsPresContext::AttachShell(nsIPresShell* aShell)
{
MOZ_ASSERT(!mShell);
mShell = aShell;
// Since CounterStyleManager is also the name of a method of
// nsPresContext, it is necessary to prefix the class with the mozilla
// namespace here.
mCounterStyleManager = new mozilla::CounterStyleManager(this);
nsIDocument *doc = mShell->GetDocument();
NS_ASSERTION(doc, "expect document here");
if (doc) {
// Have to update PresContext's mDocument before calling any other methods.
mDocument = doc;
}
// Initialize our state from the user preferences, now that we
// have a presshell, and hence a document.
GetUserPreferences();
if (doc) {
nsIURI *docURI = doc->GetDocumentURI();
if (IsDynamic() && docURI) {
bool isChrome = false;
bool isRes = false;
docURI->SchemeIs("chrome", &isChrome);
docURI->SchemeIs("resource", &isRes);
if (!isChrome && !isRes)
mImageAnimationMode = mImageAnimationModePref;
else
mImageAnimationMode = imgIContainer::kNormalAnimMode;
}
if (mLangService) {
doc->AddCharSetObserver(this);
UpdateCharSet(doc->GetDocumentCharacterSet());
}
}
}
void
nsPresContext::DetachShell()
{
// Remove ourselves as the charset observer from the shell's doc, because
// this shell may be going away for good.
nsIDocument *doc = mShell ? mShell->GetDocument() : nullptr;
if (doc) {
doc->RemoveCharSetObserver(this);
}
// The counter style manager's destructor needs to deallocate with the
// presshell arena. Disconnect it before nulling out the shell.
//
// XXXbholley: Given recent refactorings, it probably makes more sense to
// just null our mShell at the bottom of this function. I'm leaving it
// this way to preserve the old ordering, but I doubt anything would break.
if (mCounterStyleManager) {
mCounterStyleManager->Disconnect();
mCounterStyleManager = nullptr;
}
if (mShell) {
// Remove ourselves as the charset observer from the shell's doc, because
// this shell may be going away for good.
nsIDocument *doc = mShell->GetDocument();
if (doc) {
doc->RemoveCharSetObserver(this);
}
mShell = nullptr;
if (mEffectCompositor) {
mEffectCompositor->Disconnect();
mEffectCompositor = nullptr;
}
if (mTransitionManager) {
mTransitionManager->Disconnect();
mTransitionManager = nullptr;
}
if (mAnimationManager) {
mAnimationManager->Disconnect();
mAnimationManager = nullptr;
}
if (mRestyleManager) {
mRestyleManager->Disconnect();
mRestyleManager = nullptr;
}
if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
mRefreshDriver->Disconnect();
// Can't null out the refresh driver here.
}
mShell = aShell;
if (IsRoot()) {
nsRootPresContext* thisRoot = static_cast<nsRootPresContext*>(this);
if (mShell) {
// Since CounterStyleManager is also the name of a method of
// nsPresContext, it is necessary to prefix the class with the mozilla
// namespace here.
mCounterStyleManager = new mozilla::CounterStyleManager(this);
// Have to cancel our plugin geometry timer, because the
// callback for that depends on a non-null presshell.
thisRoot->CancelApplyPluginGeometryTimer();
nsIDocument *doc = mShell->GetDocument();
NS_ASSERTION(doc, "expect document here");
if (doc) {
// Have to update PresContext's mDocument before calling any other methods.
mDocument = doc;
}
// Initialize our state from the user preferences, now that we
// have a presshell, and hence a document.
GetUserPreferences();
if (doc) {
nsIURI *docURI = doc->GetDocumentURI();
if (IsDynamic() && docURI) {
bool isChrome = false;
bool isRes = false;
docURI->SchemeIs("chrome", &isChrome);
docURI->SchemeIs("resource", &isRes);
if (!isChrome && !isRes)
mImageAnimationMode = mImageAnimationModePref;
else
mImageAnimationMode = imgIContainer::kNormalAnimMode;
}
if (mLangService) {
doc->AddCharSetObserver(this);
UpdateCharSet(doc->GetDocumentCharacterSet());
}
}
} else {
if (mEffectCompositor) {
mEffectCompositor->Disconnect();
mEffectCompositor = nullptr;
}
if (mTransitionManager) {
mTransitionManager->Disconnect();
mTransitionManager = nullptr;
}
if (mAnimationManager) {
mAnimationManager->Disconnect();
mAnimationManager = nullptr;
}
if (mRestyleManager) {
mRestyleManager->Disconnect();
mRestyleManager = nullptr;
}
if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
mRefreshDriver->Disconnect();
// Can't null out the refresh driver here.
}
if (IsRoot()) {
nsRootPresContext* thisRoot = static_cast<nsRootPresContext*>(this);
// Have to cancel our plugin geometry timer, because the
// callback for that depends on a non-null presshell.
thisRoot->CancelApplyPluginGeometryTimer();
// The did-paint timer also depends on a non-null pres shell.
thisRoot->CancelDidPaintTimer();
}
// The did-paint timer also depends on a non-null pres shell.
thisRoot->CancelDidPaintTimer();
}
}

Просмотреть файл

@ -160,10 +160,11 @@ public:
nsresult Init(nsDeviceContext* aDeviceContext);
/**
* Set the presentation shell that this context is bound to.
* Set and detach presentation shell that this context is bound to.
* A presentation context may only be bound to a single shell.
*/
void SetShell(nsIPresShell* aShell);
void AttachShell(nsIPresShell* aShell);
void DetachShell();
nsPresContextType Type() const { return mType; }

Просмотреть файл

@ -879,7 +879,7 @@ PresShell::Init(nsIDocument* aDocument,
// Bind the context to the presentation shell.
mPresContext = aPresContext;
aPresContext->SetShell(this);
aPresContext->AttachShell(this);
// Now we can initialize the style set. Make sure to set the member before
// calling Init, since various subroutines need to find the style set off
@ -1241,12 +1241,12 @@ PresShell::Destroy()
// (a) before mFrameArena's destructor runs so that our
// mAllocatedPointers becomes empty and doesn't trip the assertion
// in ~PresShell,
// (b) before the mPresContext->SetShell(nullptr) below, so
// (b) before the mPresContext->DetachShell() below, so
// that when we clear the ArenaRefPtrs they'll still be able to
// get back to this PresShell to deregister themselves (e.g. note
// how nsStyleContext::Arena returns the PresShell got from its
// rule node's nsPresContext, which would return null if we'd already
// called mPresContext->SetShell(nullptr)), and
// called mPresContext->DetachShell()), and
// (c) before the mStyleSet->BeginShutdown() call just below, so that
// the nsStyleContexts don't complain they're being destroyed later
// than the rule tree is.
@ -1304,7 +1304,7 @@ PresShell::Destroy()
if (mPresContext) {
// Clear out the prescontext's property table -- since our frame tree is
// now dead, we shouldn't be looking up any more properties in that table.
// We want to do this before we call SetShell() on the prescontext, so
// We want to do this before we call DetachShell() on the prescontext, so
// property destructors can usefully call GetPresShell() on the
// prescontext.
mPresContext->PropertyTable()->DeleteAll();
@ -1323,7 +1323,7 @@ PresShell::Destroy()
// We hold a reference to the pres context, and it holds a weak link back
// to us. To avoid the pres context having a dangling reference, set its
// pres shell to nullptr
mPresContext->SetShell(nullptr);
mPresContext->DetachShell();
// Clear the link handler (weak reference) as well
mPresContext->SetLinkHandler(nullptr);