Bug 1378754 - Don't clear marked fields in nsFormFillController upon a persisted pagehide. r=smaug
While moving to a new window (using SwapDocShells), a pagehide event[1] is dispatched causing nsFormFillController to clean up mPwmgrInputs and mAutofillInputs for the document. This commit changes the pagehide handler to not clear the hash tables or mutation observers with persisted=true (which would also fix the same bug in password manager autocomplete).
This approach comes at the cost of increased memory (hash table entries for fields in session history) but would reduce CPU usage compared to the alternative of re-marking password manager and autofill fields upon every pageshow event. This approach also solves the issue of autofill and password manager autocomplete not working after session history navigation.
[1] https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/SwapDocShells
MozReview-Commit-ID: 8DFWuFynDex
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -6,16 +6,17 @@
#include "nsFormFillController.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
#include "mozilla/dom/HTMLInputElement.h"
+#include "mozilla/dom/PageTransitionEvent.h"
#include "mozilla/Logging.h"
#include "nsIFormAutoComplete.h"
#include "nsIInputListAutoComplete.h"
#include "nsIAutoCompleteSimpleResult.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
@@ -976,31 +977,38 @@ nsFormFillController::HandleEvent(nsIDOM
}
if (mFocusedInput) {
if (doc == mFocusedInputNode->OwnerDoc()) {
StopControllingInput();
}
}
- RemoveForDocument(doc);
+ // Only remove the observer notifications and marked autofill and password
+ // manager fields if the page isn't going to be persisted (i.e. it's being
+ // unloaded) so that appropriate autocomplete handling works with bfcache.
+ bool persisted = aEvent->InternalDOMEvent()->AsPageTransitionEvent()->Persisted();
+ if (!persisted) {
+ RemoveForDocument(doc);
+ }
}
break;
default:
// Handling the default case to shut up stupid -Wswitch warnings.
// One day compilers will be smarter...
break;
}
return NS_OK;
}
void
nsFormFillController::RemoveForDocument(nsIDocument* aDoc)
{
+ MOZ_LOG(sLogger, LogLevel::Verbose, ("RemoveForDocument: %p", aDoc));
for (auto iter = mPwmgrInputs.Iter(); !iter.Done(); iter.Next()) {
const nsINode* key = iter.Key();
if (key && (!aDoc || key->OwnerDoc() == aDoc)) {
// mFocusedInputNode's observer is tracked separately, so don't remove it
// here.
if (key != mFocusedInputNode) {
const_cast<nsINode*>(key)->RemoveMutationObserver(this);
}