Bug 894215 part 3. Make sure we don't bfcache pages that get mutated after we capture their state. r=smaug

This commit is contained in:
Boris Zbarsky 2018-05-18 23:37:56 -04:00
Родитель 6f273bf6d2
Коммит 69f3dde06c
1 изменённых файлов: 121 добавлений и 0 удалений

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

@ -26,6 +26,7 @@
#include "nsIWritablePropertyBag2.h"
#include "nsSubDocumentFrame.h"
#include "nsGenericHTMLElement.h"
#include "nsStubMutationObserver.h"
#include "nsILinkHandler.h"
#include "nsISelectionListener.h"
@ -203,6 +204,108 @@ private:
nsDocumentViewer* mDocViewer;
};
namespace viewer_detail {
/**
* Mutation observer for use until we hand ourselves over to our SHEntry.
*/
class BFCachePreventionObserver final : public nsStubMutationObserver
{
public:
explicit BFCachePreventionObserver(nsIDocument* aDocument)
: mDocument(aDocument)
{
}
NS_DECL_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
// Stop observing the document.
void Disconnect();
private:
~BFCachePreventionObserver() = default;
// Helper for the work that needs to happen when mutations happen.
void MutationHappened();
nsIDocument* mDocument; // Weak; we get notified if it dies
};
NS_IMPL_ISUPPORTS(BFCachePreventionObserver, nsIMutationObserver)
void
BFCachePreventionObserver::CharacterDataChanged(nsIContent* aContent,
const CharacterDataChangeInfo&)
{
MutationHappened();
}
void
BFCachePreventionObserver::AttributeChanged(Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue)
{
MutationHappened();
}
void
BFCachePreventionObserver::ContentAppended(nsIContent* aFirstNewContent)
{
MutationHappened();
}
void
BFCachePreventionObserver::ContentInserted(nsIContent* aChild)
{
MutationHappened();
}
void
BFCachePreventionObserver::ContentRemoved(nsIContent* aChild,
nsIContent* aPreviousSibling)
{
MutationHappened();
}
void
BFCachePreventionObserver::NodeWillBeDestroyed(const nsINode* aNode)
{
mDocument = nullptr;
}
void
BFCachePreventionObserver::Disconnect()
{
if (mDocument) {
mDocument->RemoveMutationObserver(this);
// It will no longer tell us when it goes away, so make sure we're
// not holding a dangling ref.
mDocument = nullptr;
}
}
void
BFCachePreventionObserver::MutationHappened()
{
MOZ_ASSERT(mDocument,
"How can we not have a document but be getting notified for mutations?");
mDocument->DisallowBFCaching();
Disconnect();
}
} // namespace viewer_detail
using viewer_detail::BFCachePreventionObserver;
//-------------------------------------------------------------
class nsDocumentViewer final : public nsIContentViewer,
@ -340,6 +443,9 @@ protected:
nsCOMPtr<nsIContentViewer> mPreviousViewer;
nsCOMPtr<nsISHEntry> mSHEntry;
// Observer that will prevent bfcaching if it gets notified. This
// is non-null precisely when mSHEntry is non-null.
RefPtr<BFCachePreventionObserver> mBFCachePreventionObserver;
nsIWidget* mParentWidget; // purposely won't be ref counted. May be null
bool mAttachedToParent; // view is attached to the parent widget
@ -1562,6 +1668,14 @@ nsDocumentViewer::Close(nsISHEntry *aSHEntry)
if (!mDocument)
return NS_OK;
if (mSHEntry) {
if (mBFCachePreventionObserver) {
mBFCachePreventionObserver->Disconnect();
}
mBFCachePreventionObserver = new BFCachePreventionObserver(mDocument);
mDocument->AddMutationObserver(mBFCachePreventionObserver);
}
#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
// Turn scripting back on
// after PrintPreview had turned it off
@ -1664,6 +1778,13 @@ nsDocumentViewer::Destroy()
mAutoBeforeAndAfterPrint = nullptr;
#endif
// We want to make sure to disconnect mBFCachePreventionObserver before we
// Sanitize() below.
if (mBFCachePreventionObserver) {
mBFCachePreventionObserver->Disconnect();
mBFCachePreventionObserver = nullptr;
}
if (mSHEntry && mDocument && !mDocument->IsBFCachingAllowed()) {
// Just drop the SHEntry now and pretend like we never even tried to bfcache
// this viewer. This should only happen when someone calls