From 0922145c255bf2503d3b2dd5f8f1e813338ba990 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Sat, 24 Jan 2015 12:37:47 -0500 Subject: [PATCH] Bug 1110557. r=mak, r=gavin, a=bkerensa --- .../components/satchel/nsFormFillController.cpp | 67 +++++++++++++++------- toolkit/components/satchel/nsFormFillController.h | 5 ++ 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index 315fc68..676ad84 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -61,6 +61,7 @@ nsFormFillController::nsFormFillController() : mSuppressOnInput(false) { mController = do_GetService("@mozilla.org/autocomplete/controller;1"); + MOZ_ASSERT(mController); } struct PwmgrInputsEnumData @@ -104,6 +105,21 @@ nsFormFillController::AttributeChanged(nsIDocument* aDocument, int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType) { + if ((aAttribute == nsGkAtoms::type || aAttribute == nsGkAtoms::readonly || + aAttribute == nsGkAtoms::autocomplete) && + aNameSpaceID == kNameSpaceID_None) { + nsCOMPtr focusedInput(mFocusedInput); + // Reset the current state of the controller, unconditionally. + StopControllingInput(); + // Then restart based on the new values. We have to delay this + // to avoid ending up in an endless loop due to re-registering our + // mutation observer (which would notify us again for *this* event). + nsCOMPtr event = + NS_NewRunnableMethodWithArg> + (this, &nsFormFillController::MaybeStartControllingInput, focusedInput); + NS_DispatchToCurrentThread(event); + } + if (mListNode && mListNode->Contains(aElement)) { RevalidateDataList(); } @@ -841,28 +857,26 @@ nsFormFillController::RemoveForDocumentEnumerator(const nsINode* aKey, return PL_DHASH_NEXT; } -nsresult -nsFormFillController::Focus(nsIDOMEvent* aEvent) +void +nsFormFillController::MaybeStartControllingInput(nsIDOMHTMLInputElement* aInput) { - nsCOMPtr input = do_QueryInterface( - aEvent->InternalDOMEvent()->GetTarget()); - nsCOMPtr inputNode = do_QueryInterface(input); + nsCOMPtr inputNode = do_QueryInterface(aInput); if (!inputNode) - return NS_OK; + return; - nsCOMPtr formControl = do_QueryInterface(input); + nsCOMPtr formControl = do_QueryInterface(aInput); if (!formControl || !formControl->IsSingleLineTextControl(true)) - return NS_OK; + return; bool isReadOnly = false; - input->GetReadOnly(&isReadOnly); + aInput->GetReadOnly(&isReadOnly); if (isReadOnly) - return NS_OK; + return; - bool autocomplete = nsContentUtils::IsAutocompleteEnabled(input); + bool autocomplete = nsContentUtils::IsAutocompleteEnabled(aInput); nsCOMPtr datalist; - input->GetList(getter_AddRefs(datalist)); + aInput->GetList(getter_AddRefs(datalist)); bool hasList = datalist != nullptr; bool dummy; @@ -871,9 +885,16 @@ nsFormFillController::Focus(nsIDOMEvent* aEvent) isPwmgrInput = true; if (isPwmgrInput || hasList || autocomplete) { - StartControllingInput(input); + StartControllingInput(aInput); } +} +nsresult +nsFormFillController::Focus(nsIDOMEvent* aEvent) +{ + nsCOMPtr input = do_QueryInterface( + aEvent->InternalDOMEvent()->GetTarget()); + MaybeStartControllingInput(input); return NS_OK; } @@ -1087,6 +1108,10 @@ nsFormFillController::StartControllingInput(nsIDOMHTMLInputElement *aInput) // Make sure we're not still attached to an input StopControllingInput(); + if (!mController) { + return; + } + // Find the currently focused docShell nsCOMPtr docShell = GetDocShellForInput(aInput); int32_t index = GetIndexOfDocShell(docShell); @@ -1129,13 +1154,15 @@ nsFormFillController::StopControllingInput() mListNode = nullptr; } - // Reset the controller's input, but not if it has been switched - // to another input already, which might happen if the user switches - // focus by clicking another autocomplete textbox - nsCOMPtr input; - mController->GetInput(getter_AddRefs(input)); - if (input == this) - mController->SetInput(nullptr); + if (mController) { + // Reset the controller's input, but not if it has been switched + // to another input already, which might happen if the user switches + // focus by clicking another autocomplete textbox + nsCOMPtr input; + mController->GetInput(getter_AddRefs(input)); + if (input == this) + mController->SetInput(nullptr); + } if (mFocusedInputNode) { MaybeRemoveMutationObserver(mFocusedInputNode); diff --git a/toolkit/components/satchel/nsFormFillController.h b/toolkit/components/satchel/nsFormFillController.h index b60d28d..8c3ba26 100644 --- a/toolkit/components/satchel/nsFormFillController.h +++ b/toolkit/components/satchel/nsFormFillController.h @@ -62,6 +62,11 @@ protected: void StartControllingInput(nsIDOMHTMLInputElement *aInput); void StopControllingInput(); + /** + * Checks that aElement is a type of element we want to fill, then calls + * StartControllingInput on it. + */ + void MaybeStartControllingInput(nsIDOMHTMLInputElement* aElement); nsresult PerformInputListAutoComplete(nsIAutoCompleteResult* aPreviousResult); -- 2.2.1