tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 7327b348bc17d738ef574344d23b9098a3188d83
parent 7a28250b0fb54e67b44de756b226faaf69223494
Author: Cristian Tuns <ctuns@mozilla.com>
Date:   Mon, 27 Oct 2025 04:50:52 -0400

Revert "Bug 1767228 - Add showPicker Support for Input with Data List. r=emilio,credential-management-reviewers,dimi" for causing mochitest failures in test_input_text_show_picker.html

This reverts commit 5d7a4cf9ed9c80f1ba4a3b846fd9661fd7d1cd14.

Revert "Bug 1767228 - Refactor: Rename nsFormFillController focusedElement to controlledElement. r=emilio,credential-management-reviewers,dimi"

This reverts commit 427097407647f4af6fb5526a802e6cd6273d665d.

Diffstat:
Mbrowser/extensions/formautofill/test/browser/browser_cancel_attribute_change_task.js | 2+-
Mdom/html/HTMLInputElement.cpp | 20++------------------
Mdom/html/HTMLInputElement.h | 2+-
Mdom/html/test/forms/mochitest.toml | 3---
Ddom/html/test/forms/test_input_text_show_picker.html | 56--------------------------------------------------------
Dtesting/web-platform/tests/html/semantics/forms/the-input-element/show-picker-does-not-focus.html | 29-----------------------------
Mtoolkit/components/formautofill/FormAutofillChild.sys.mjs | 4++--
Mtoolkit/components/formautofill/FormAutofillContent.sys.mjs | 4++--
Mtoolkit/components/passwordmgr/LoginManagerChild.sys.mjs | 18+++++++++---------
Mtoolkit/components/satchel/nsFormFillController.cpp | 157+++++++++++++++++++++++++++++++++++++------------------------------------------
Mtoolkit/components/satchel/nsFormFillController.h | 4++--
Mtoolkit/components/satchel/nsIFormFillController.idl | 2+-
12 files changed, 94 insertions(+), 207 deletions(-)

diff --git a/browser/extensions/formautofill/test/browser/browser_cancel_attribute_change_task.js b/browser/extensions/formautofill/test/browser/browser_cancel_attribute_change_task.js @@ -58,7 +58,7 @@ add_task( "@mozilla.org/satchel/form-fill-controller;1" ].getService(Ci.nsIFormFillController); Assert.equal( - formFillController.controlledElement?.id, + formFillController.focusedElement?.id, "address-level1", "formFillController has correct focusedInput" ); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp @@ -65,7 +65,6 @@ #include "nsIEditor.h" #include "nsIFilePicker.h" #include "nsIFormControl.h" -#include "nsIFormFillController.h" #include "nsIFrame.h" #include "nsIMutationObserver.h" #include "nsIPromptCollection.h" @@ -5900,7 +5899,7 @@ void HTMLInputElement::ShowPicker(ErrorResult& aRv) { // InitFilePicker() and InitColorPicker() consume it themselves, // so only consume in this function if not those. - // Step 5. If element's type attribute is in the File Upload state, then run + // Step 4. If element's type attribute is in the File Upload state, then run // these steps in parallel: if (mType == FormControlType::InputFile) { FilePickerType type = FILE_PICKER_FILE; @@ -5912,11 +5911,9 @@ void HTMLInputElement::ShowPicker(ErrorResult& aRv) { return; } - // Step 6. Otherwise, the user agent should show any relevant user interface + // Step 5. Otherwise, the user agent should show any relevant user interface // for selecting a value for element, in the way it normally would when the // user interacts with the control - - // Step 6 for color if (mType == FormControlType::InputColor) { InitColorPicker(); return; @@ -5929,7 +5926,6 @@ void HTMLInputElement::ShowPicker(ErrorResult& aRv) { return; } - // Step 6 for date and time types if (IsDateTimeTypeSupported(mType)) { if (CreatesDateTimeWidget()) { if (RefPtr<Element> dateTimeBoxElement = GetDateTimeBoxElement()) { @@ -5944,18 +5940,6 @@ void HTMLInputElement::ShowPicker(ErrorResult& aRv) { GetDateTimeInputBoxValue(value); OpenDateTimePicker(value); } - return; - } - - // Step 6 for input elements with a suggestions source element. - // I.e. show the autocomplete dropdown based on the list attribute. - // XXX Form-fill support on android is bug 1535985. - if (IsSingleLineTextControl(true) && GetList()) { - if (nsCOMPtr<nsIFormFillController> controller = - do_GetService("@mozilla.org/satchel/form-fill-controller;1")) { - controller->SetControlledElement(this); - controller->ShowPopup(); - } } } diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h @@ -720,7 +720,7 @@ class HTMLInputElement final : public TextControlElement, SelectionMode aSelectMode, ErrorResult& aRv); - MOZ_CAN_RUN_SCRIPT void ShowPicker(ErrorResult& aRv); + void ShowPicker(ErrorResult& aRv); bool WebkitDirectoryAttr() const { return HasAttr(nsGkAtoms::webkitdirectory); diff --git a/dom/html/test/forms/mochitest.toml b/dom/html/test/forms/mochitest.toml @@ -135,9 +135,6 @@ skip-if = ["os == 'mac' && os_version == '10.15' && processor == 'x86_64' && deb ["test_input_setting_value.html"] -["test_input_text_show_picker.html"] -skip-if = ["os == 'android'"] # Bug 1535985 - ["test_input_textarea_set_value_no_scroll.html"] ["test_input_time_key_events.html"] diff --git a/dom/html/test/forms/test_input_text_show_picker.html b/dom/html/test/forms/test_input_text_show_picker.html @@ -1,56 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <meta charset="utf-8"> - <title>input.showPicker() with datalist shows the autocomplete popup</title> - <script src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> - <script> - const controller = SpecialPowers.Cc["@mozilla.org/autocomplete/controller;1"].getService( - SpecialPowers.Ci.nsIAutoCompleteController - ); - - async function testWithInputType(aType) { - const inp = document.querySelector("input"); - inp.type = aType; - - ok(!controller.input?.popupOpen, `Initially no input popup`); - - SpecialPowers.wrap(document).notifyUserGestureActivation(); - inp.showPicker(); - - await SimpleTest.promiseWaitForCondition( - () => controller.input?.popupOpen, - `input[type=${aType}] popup was not opened` - ); - ok(controller.input?.popupOpen, `input[type=${aType}] popup open`); - - inp.type = "date"; - await SimpleTest.promiseWaitForCondition( - () => !controller.input?.popupOpen, - `input[type=${aType}] popup was closed` - ); - } - - SimpleTest.waitForExplicitFinish(); - window.onload = async function() { - for (const type of ["text", "search", "email", "url", "tel", "number"]) { - await testWithInputType(type); - } - SimpleTest.finish(); - }; - </script> -</head> -<body> -<p id="display"></p> -<div id="content" style="display: none"></div> -<pre id="test"></pre> - -<input list="id-list" /> -<datalist id="id-list"> - <option value="Chocolate"></option> - <option value="Coconut"></option> -</datalist> - -</body> -</html> diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-does-not-focus.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-does-not-focus.html @@ -1,29 +0,0 @@ -<!DOCTYPE html> -<title>Test showPicker() does not focus the element</title> -<meta name="timeout" content="long"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-vendor.js"></script> - -<body> -<script type=module> -import inputTypes from "./input-types.js"; - -function createElement(t, type) { - const input = document.createElement("input"); - input.type = type; - document.body.append(input); - t.add_cleanup(() => input.remove()); - return input; -} - -for (const inputType of inputTypes) { - promise_test(async (t) => { - const input = createElement(t, inputType); - await test_driver.bless('show picker'); - input.showPicker(); - assert_not_equals(input, document.activeElement, "Input element was not focused"); - }, `input[type=${inputType}].showPicker() does not focus the element`); -} -</script> diff --git a/toolkit/components/formautofill/FormAutofillChild.sys.mjs b/toolkit/components/formautofill/FormAutofillChild.sys.mjs @@ -138,7 +138,7 @@ export class FormAutofillChild extends JSWindowActorChild { this.#markAsAutofillField(fieldDetail); if ( - fieldDetail.element == lazy.FormAutofillContent.controlledElement && + fieldDetail.element == lazy.FormAutofillContent.focusedElement && !isUpdate ) { this.showPopupIfEmpty(fieldDetail.element, fieldDetail.fieldName); @@ -494,7 +494,7 @@ export class FormAutofillChild extends JSWindowActorChild { this._hasDOMContentLoadedHandler = true; doc.addEventListener( "DOMContentLoaded", - () => this.onFocusIn(lazy.FormAutofillContent.controlledElement), + () => this.onFocusIn(lazy.FormAutofillContent.focusedElement), { once: true } ); } diff --git a/toolkit/components/formautofill/FormAutofillContent.sys.mjs b/toolkit/components/formautofill/FormAutofillContent.sys.mjs @@ -30,8 +30,8 @@ export var FormAutofillContent = { return Services.cpmm.sharedData.get("FormAutofill:savedFieldNames"); }, - get controlledElement() { - return formFillController.controlledElement; + get focusedElement() { + return formFillController.focusedElement; }, /** diff --git a/toolkit/components/passwordmgr/LoginManagerChild.sys.mjs b/toolkit/components/passwordmgr/LoginManagerChild.sys.mjs @@ -1401,19 +1401,19 @@ export class LoginManagerChild extends JSWindowActorChild { break; } case "PasswordManager:OnFieldAutoComplete": { - const { controlledElement } = lazy.gFormFillService; + const { focusedElement } = lazy.gFormFillService; const login = lazy.LoginHelper.vanillaObjectToLogin(msg.data); - this.onFieldAutoComplete(controlledElement, login); + this.onFieldAutoComplete(focusedElement, login); break; } case "PasswordManager:FillGeneratedPassword": { - const { controlledElement } = lazy.gFormFillService; - this.filledWithGeneratedPassword(controlledElement); + const { focusedElement } = lazy.gFormFillService; + this.filledWithGeneratedPassword(focusedElement); break; } case "PasswordManager:FillRelayUsername": { - const { controlledElement } = lazy.gFormFillService; - this.fillRelayUsername(controlledElement, msg.data); + const { focusedElement } = lazy.gFormFillService; + this.fillRelayUsername(focusedElement, msg.data); break; } } @@ -1428,7 +1428,7 @@ export class LoginManagerChild extends JSWindowActorChild { return; } - if (inputElement != lazy.gFormFillService.controlledElement) { + if (inputElement != lazy.gFormFillService.focusedElement) { lazy.log("Could not open popup on input that's no longer focused."); return; } @@ -3090,9 +3090,9 @@ export class LoginManagerChild extends JSWindowActorChild { Glean.pwmgr.formAutofillResult[autofillResult].add(1); if (usernameField) { - let controlledElement = lazy.gFormFillService.controlledElement; + let focusedElement = lazy.gFormFillService.focusedElement; if ( - usernameField == controlledElement && + usernameField == focusedElement && ![ AUTOFILL_RESULT.FILLED, AUTOFILL_RESULT.FILLED_USERNAME_ONLY_FORM, diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp @@ -67,7 +67,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormFillController) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormFillController) nsFormFillController::nsFormFillController() - : mControlledElement(nullptr), + : mFocusedElement(nullptr), mRestartAfterAttributeChangeTask(nullptr), mListNode(nullptr), // The amount of time a context menu event supresses showing a @@ -99,9 +99,9 @@ nsFormFillController::~nsFormFillController() { mListNode->RemoveMutationObserver(this); mListNode = nullptr; } - if (mControlledElement) { - MaybeRemoveMutationObserver(mControlledElement); - mControlledElement = nullptr; + if (mFocusedElement) { + MaybeRemoveMutationObserver(mFocusedElement); + mFocusedElement = nullptr; } RemoveForDocument(nullptr); } @@ -128,7 +128,7 @@ void nsFormFillController::AttributeChanged(mozilla::dom::Element* aElement, if ((aAttribute == nsGkAtoms::type || aAttribute == nsGkAtoms::readonly || aAttribute == nsGkAtoms::autocomplete) && aNameSpaceID == kNameSpaceID_None) { - RefPtr<Element> controlledElement(mControlledElement); + RefPtr<Element> focusedElement(mFocusedElement); // Reset the current state of the controller, unconditionally. StopControllingInput(); // Then restart based on the new values. We have to delay this @@ -141,7 +141,7 @@ void nsFormFillController::AttributeChanged(mozilla::dom::Element* aElement, mozilla::NewCancelableRunnableMethod<RefPtr<Element>>( "nsFormFillController::MaybeStartControllingInput", this, &nsFormFillController::MaybeStartControllingInputScheduled, - controlledElement); + focusedElement); RefPtr<Runnable> addrefedRunnable = mRestartAfterAttributeChangeTask; aElement->OwnerDoc()->Dispatch(addrefedRunnable.forget()); } @@ -217,8 +217,8 @@ void nsFormFillController::NodeWillBeDestroyed(nsINode* aNode) { if (aNode == mListNode) { mListNode = nullptr; RevalidateDataList(); - } else if (aNode == mControlledElement) { - mControlledElement = nullptr; + } else if (aNode == mFocusedElement) { + mFocusedElement = nullptr; } } @@ -258,7 +258,7 @@ nsFormFillController::MarkAsAutoCompletableField(Element* aElement) { EnablePreview(aElement); if (nsFocusManager::GetFocusedElementStatic() == aElement) { - if (!mControlledElement) { + if (!mFocusedElement) { MaybeStartControllingInput(aElement); } else { // See `MarkAsLoginManagerField` for why this is needed. @@ -271,29 +271,8 @@ nsFormFillController::MarkAsAutoCompletableField(Element* aElement) { } NS_IMETHODIMP -nsFormFillController::SetControlledElement(Element* aElement) { - if (!aElement || - !aElement->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) { - return NS_OK; - } - - MaybeStartControllingInput(aElement); - - // Bail if we didn't start controlling the input. - if (!mControlledElement) { - return NS_OK; - } - - // if there is a delayed task to restart the controller after an attribute - // change, cancel it to prevent it overriding the controlled input - MaybeCancelAttributeChangeTask(); - - return NS_OK; -} - -NS_IMETHODIMP -nsFormFillController::GetControlledElement(Element** aElement) { - *aElement = mControlledElement; +nsFormFillController::GetFocusedElement(Element** aElement) { + *aElement = mFocusedElement; NS_IF_ADDREF(*aElement); return NS_OK; } @@ -335,9 +314,9 @@ nsFormFillController::SetPopupOpen(bool aPopupOpen) { if (mFocusedPopup) { if (aPopupOpen) { // make sure input field is visible before showing popup (bug 320938) - nsCOMPtr<nsIContent> content = mControlledElement; + nsCOMPtr<nsIContent> content = mFocusedElement; NS_ENSURE_STATE(content); - nsCOMPtr<nsIDocShell> docShell = GetDocShellForInput(mControlledElement); + nsCOMPtr<nsIDocShell> docShell = GetDocShellForInput(mFocusedElement); NS_ENSURE_STATE(docShell); RefPtr<PresShell> presShell = docShell->GetPresShell(); NS_ENSURE_STATE(presShell); @@ -349,7 +328,7 @@ nsFormFillController::SetPopupOpen(bool aPopupOpen) { // mFocusedPopup can be destroyed after ScrollContentIntoView, see bug // 420089 if (mFocusedPopup) { - mFocusedPopup->OpenAutocompletePopup(this, mControlledElement); + mFocusedPopup->OpenAutocompletePopup(this, mFocusedElement); } } else { mFocusedPopup->ClosePopup(); @@ -449,17 +428,17 @@ nsFormFillController::SetSearchParam(const nsAString& aSearchParam) { NS_IMETHODIMP nsFormFillController::GetSearchParam(nsAString& aSearchParam) { - if (!mControlledElement) { + if (!mFocusedElement) { NS_WARNING( - "mControlledElement is null for some reason! avoiding a crash. should " + "mFocusedElement is null for some reason! avoiding a crash. should " "find " "out why... - ben"); return NS_ERROR_FAILURE; // XXX why? fix me. } - GetName(mControlledElement, aSearchParam); + GetName(mFocusedElement, aSearchParam); if (aSearchParam.IsEmpty()) { - mControlledElement->GetId(aSearchParam); + mFocusedElement->GetId(aSearchParam); } return NS_OK; @@ -487,8 +466,8 @@ nsFormFillController::GetSearchAt(uint32_t index, nsACString& _retval) { NS_IMETHODIMP nsFormFillController::GetTextValue(nsAString& aTextValue) { - if (mControlledElement) { - GetValue(mControlledElement, aTextValue); + if (mFocusedElement) { + GetValue(mFocusedElement, aTextValue); } else { aTextValue.Truncate(); } @@ -497,9 +476,9 @@ nsFormFillController::GetTextValue(nsAString& aTextValue) { NS_IMETHODIMP nsFormFillController::SetTextValue(const nsAString& aTextValue) { - if (mControlledElement) { + if (mFocusedElement) { mSuppressOnInput = true; - SetUserInput(mControlledElement, aTextValue, + SetUserInput(mFocusedElement, aTextValue, *nsContentUtils::GetSystemPrincipal()); mSuppressOnInput = false; } @@ -509,32 +488,32 @@ nsFormFillController::SetTextValue(const nsAString& aTextValue) { NS_IMETHODIMP nsFormFillController::GetSelectionStart(int32_t* aSelectionStart) { - if (!mControlledElement) { + if (!mFocusedElement) { return NS_ERROR_UNEXPECTED; } ErrorResult rv; - *aSelectionStart = GetSelectionStartInternal(mControlledElement, rv); + *aSelectionStart = GetSelectionStartInternal(mFocusedElement, rv); return rv.StealNSResult(); } NS_IMETHODIMP nsFormFillController::GetSelectionEnd(int32_t* aSelectionEnd) { - if (!mControlledElement) { + if (!mFocusedElement) { return NS_ERROR_UNEXPECTED; } ErrorResult rv; - *aSelectionEnd = GetSelectionEndInternal(mControlledElement, rv); + *aSelectionEnd = GetSelectionEndInternal(mFocusedElement, rv); return rv.StealNSResult(); } MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP nsFormFillController::SelectTextRange(int32_t aStartIndex, int32_t aEndIndex) { - if (!mControlledElement) { + if (!mFocusedElement) { return NS_ERROR_UNEXPECTED; } - RefPtr<Element> controlledElement(mControlledElement); + RefPtr<Element> focusedInput(mFocusedElement); ErrorResult rv; - SetSelectionRange(controlledElement, aStartIndex, aEndIndex, rv); + SetSelectionRange(focusedInput, aStartIndex, aEndIndex, rv); return rv.StealNSResult(); } @@ -546,7 +525,7 @@ nsFormFillController::OnSearchComplete() { return NS_OK; } NS_IMETHODIMP nsFormFillController::OnTextEntered(Event* aEvent) { - NS_ENSURE_TRUE(mControlledElement, NS_OK); + NS_ENSURE_TRUE(mFocusedElement, NS_OK); return NS_OK; } @@ -564,12 +543,12 @@ nsFormFillController::GetConsumeRollupEvent(bool* aConsumeRollupEvent) { NS_IMETHODIMP nsFormFillController::GetInPrivateContext(bool* aInPrivateContext) { - if (!mControlledElement) { + if (!mFocusedElement) { *aInPrivateContext = false; return NS_OK; } - RefPtr<Document> doc = mControlledElement->OwnerDoc(); + RefPtr<Document> doc = mFocusedElement->OwnerDoc(); nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext(); *aInPrivateContext = loadContext && loadContext->UsePrivateBrowsing(); return NS_OK; @@ -583,8 +562,8 @@ nsFormFillController::GetNoRollupOnCaretMove(bool* aNoRollupOnCaretMove) { NS_IMETHODIMP nsFormFillController::GetNoRollupOnEmptySearch(bool* aNoRollupOnEmptySearch) { - if (mControlledElement && mFocusedPopup) { - return mFocusedPopup->GetNoRollupOnEmptySearch(mControlledElement, + if (mFocusedElement && mFocusedPopup) { + return mFocusedPopup->GetNoRollupOnEmptySearch(mFocusedElement, aNoRollupOnEmptySearch); } @@ -613,37 +592,36 @@ nsFormFillController::StartSearch(const nsAString& aSearchString, const nsAString& aSearchParam, nsIAutoCompleteResult* aPreviousResult, nsIAutoCompleteObserver* aListener) { - MOZ_LOG(sLogger, LogLevel::Debug, ("StartSearch for %p", mControlledElement)); + MOZ_LOG(sLogger, LogLevel::Debug, ("StartSearch for %p", mFocusedElement)); mLastListener = aListener; - if (mControlledElement && mFocusedPopup) { - if (mAutoCompleteInputs.Get(mControlledElement) || - HasBeenTypePassword(mControlledElement)) { + if (mFocusedElement && mFocusedPopup) { + if (mAutoCompleteInputs.Get(mFocusedElement) || + HasBeenTypePassword(mFocusedElement)) { MOZ_LOG(sLogger, LogLevel::Debug, ("StartSearch: formautofill or login field")); - return mFocusedPopup->StartSearch(aSearchString, mControlledElement, - this); + return mFocusedPopup->StartSearch(aSearchString, mFocusedElement, this); } } MOZ_LOG(sLogger, LogLevel::Debug, ("StartSearch: form history field")); - bool addDataList = IsTextControl(mControlledElement); + bool addDataList = IsTextControl(mFocusedElement); if (addDataList) { MaybeObserveDataListMutations(); } - return mFocusedPopup->StartSearch(aSearchString, mControlledElement, this); + return mFocusedPopup->StartSearch(aSearchString, mFocusedElement, this); } void nsFormFillController::MaybeObserveDataListMutations() { - // If an <input> is controlled, check if it has a list="<datalist>" which can + // If an <input> is focused, check if it has a list="<datalist>" which can // provide the list of suggestions. - if (mControlledElement) { - Element* list = GetList(mControlledElement); + if (mFocusedElement) { + Element* list = GetList(mFocusedElement); // Add a mutation observer to check for changes to the items in the // <datalist> and update the suggestions accordingly. @@ -770,7 +748,7 @@ nsFormFillController::HandleEvent(Event* aEvent) { return NS_OK; } case eBlur: - if (mControlledElement && !StaticPrefs::ui_popup_disable_autohide()) { + if (mFocusedElement && !StaticPrefs::ui_popup_disable_autohide()) { StopControllingInput(); } return NS_OK; @@ -799,7 +777,7 @@ nsFormFillController::HandleEvent(Event* aEvent) { return NS_OK; } - if (mControlledElement && doc == mControlledElement->OwnerDoc()) { + if (mFocusedElement && doc == mFocusedElement->OwnerDoc()) { StopControllingInput(); } @@ -846,9 +824,9 @@ void nsFormFillController::RemoveForDocument(Document* aDoc) { for (auto iter = mAutoCompleteInputs.Iter(); !iter.Done(); iter.Next()) { const nsINode* key = iter.Key(); if (key && (!aDoc || key->OwnerDoc() == aDoc)) { - // mControlledElement's observer is tracked separately, so don't remove it + // mFocusedElement's observer is tracked separately, so don't remove it // here. - if (key != mControlledElement) { + if (key != mFocusedElement) { const_cast<nsINode*>(key)->RemoveMutationObserver(this); } iter.Remove(); @@ -885,7 +863,21 @@ void nsFormFillController::MaybeStartControllingInput(Element* aElement) { } nsresult nsFormFillController::HandleFocus(Element* aElement) { - MOZ_TRY(SetControlledElement(aElement)); + if (!aElement || + !aElement->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) { + return NS_OK; + } + + MaybeStartControllingInput(aElement); + + // Bail if we didn't start controlling the input. + if (!mFocusedElement) { + return NS_OK; + } + + // if there is a delayed task to restart the controller after an attribute + // change, cancel it to prevent it overriding the focused input + MaybeCancelAttributeChangeTask(); // If this focus doesn't follow a right click within our specified // threshold then show the autocomplete popup for all password fields. @@ -895,7 +887,7 @@ nsresult nsFormFillController::HandleFocus(Element* aElement) { // multiple input forms and the fact that a mousedown into an already focused // field does not trigger another focus. - if (!HasBeenTypePassword(mControlledElement)) { + if (!HasBeenTypePassword(mFocusedElement)) { return NS_OK; } @@ -983,8 +975,8 @@ nsresult nsFormFillController::KeyDown(Event* aEvent) { // Get the writing-mode of the relevant input element, // so that we can remap arrow keys if necessary. mozilla::WritingMode wm; - if (mControlledElement) { - nsIFrame* frame = mControlledElement->GetPrimaryFrame(); + if (mFocusedElement) { + nsIFrame* frame = mFocusedElement->GetPrimaryFrame(); if (frame) { wm = frame->GetWritingMode(); } @@ -1128,22 +1120,21 @@ void nsFormFillController::StartControllingInput(Element* aElement) { mFocusedPopup = popup; aElement->AddMutationObserverUnlessExists(this); - mControlledElement = aElement; + mFocusedElement = aElement; - if (Element* list = GetList(mControlledElement)) { + if (Element* list = GetList(mFocusedElement)) { list->AddMutationObserverUnlessExists(this); mListNode = list; } - if (!ReadOnly(mControlledElement)) { + if (!ReadOnly(mFocusedElement)) { nsCOMPtr<nsIAutoCompleteController> controller = mController; controller->SetInput(this); } } bool nsFormFillController::IsFocusedInputControlled() const { - return mControlledElement && mController && !ReadOnly(mControlledElement) && - nsFocusManager::GetFocusedElementStatic() == mControlledElement; + return mFocusedElement && mController && !ReadOnly(mFocusedElement); } void nsFormFillController::StopControllingInput() { @@ -1168,10 +1159,10 @@ void nsFormFillController::StopControllingInput() { } MOZ_LOG(sLogger, LogLevel::Verbose, - ("StopControllingInput: Stopped controlling %p", mControlledElement)); - if (mControlledElement) { - MaybeRemoveMutationObserver(mControlledElement); - mControlledElement = nullptr; + ("StopControllingInput: Stopped controlling %p", mFocusedElement)); + if (mFocusedElement) { + MaybeRemoveMutationObserver(mFocusedElement); + mFocusedElement = nullptr; } if (mFocusedPopup) { diff --git a/toolkit/components/satchel/nsFormFillController.h b/toolkit/components/satchel/nsFormFillController.h @@ -72,7 +72,7 @@ class nsFormFillController final : public nsIFormFillController, bool IsFocusedInputControlled() const; MOZ_CAN_RUN_SCRIPT - nsresult HandleFocus(mozilla::dom::Element* aElement); + nsresult HandleFocus(mozilla::dom::Element* aInput); void AttachListeners(mozilla::dom::EventTarget* aEventTarget); @@ -110,7 +110,7 @@ class nsFormFillController final : public nsIFormFillController, // members ////////////////////////////////////////// nsCOMPtr<nsIAutoCompleteController> mController; - mozilla::dom::Element* mControlledElement; + mozilla::dom::Element* mFocusedElement; RefPtr<mozilla::CancelableRunnable> mRestartAfterAttributeChangeTask; // mListNode is a <datalist> element which, is set, has the form fill diff --git a/toolkit/components/satchel/nsIFormFillController.idl b/toolkit/components/satchel/nsIFormFillController.idl @@ -26,7 +26,7 @@ interface nsIFormFillController : nsISupports /* * The input or textarea element the form fill controller is currently bound to. */ - [setter_can_run_script] attribute Element controlledElement; + readonly attribute Element focusedElement; /* * Whether the autocomplete popup on a password field was automatically opened