From d99eab0d9db7673c0ca6473020d49d15ee146c89 Mon Sep 17 00:00:00 2001 From: MeladJM Date: Tue, 22 Jul 2025 03:21:45 +0800 Subject: [PATCH] Issue #2790 - Part 2: Address BZ bugs: 1355438 and 1341230 --- dom/base/nsDOMWindowUtils.cpp | 24 +++++++++++++++++++ dom/base/nsDOMWindowUtils.h | 2 ++ dom/html/HTMLInputElement.cpp | 8 +++++++ dom/html/HTMLTextAreaElement.cpp | 8 +++++++ dom/interfaces/base/nsIDOMWindowUtils.idl | 14 +++++++++++ layout/style/nsCSSPseudoClassList.h | 3 +++ layout/style/res/forms.css | 6 +++++ .../FormAutofillContentService.js | 20 ++++++++++++++++ 8 files changed, 85 insertions(+) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 37e9018fa0..27791100dc 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -4058,3 +4058,27 @@ nsTranslationNodeList::GetLength(uint32_t* aRetVal) *aRetVal = mLength; return NS_OK; } + +NS_IMETHODIMP +nsDOMWindowUtils::AddElementEventState(nsIDOMElement* aElement, uint64_t aState) +{ + NS_ENSURE_ARG_POINTER(aElement); + nsCOMPtr content = do_QueryInterface(aElement); + if (!content) { + return NS_ERROR_INVALID_ARG; + } + content->AddStates(mozilla::EventStates(aState)); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::RemoveElementEventState(nsIDOMElement* aElement, uint64_t aState) +{ + NS_ENSURE_ARG_POINTER(aElement); + nsCOMPtr content = do_QueryInterface(aElement); + if (!content) { + return NS_ERROR_INVALID_ARG; + } + content->RemoveStates(mozilla::EventStates(aState)); + return NS_OK; +} diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h index a398646a91..ef827be41c 100644 --- a/dom/base/nsDOMWindowUtils.h +++ b/dom/base/nsDOMWindowUtils.h @@ -63,6 +63,8 @@ public: explicit nsDOMWindowUtils(nsGlobalWindow *aWindow); NS_DECL_ISUPPORTS NS_DECL_NSIDOMWINDOWUTILS + NS_IMETHOD AddElementEventState(nsIDOMElement* aElement, uint64_t aState) override; + NS_IMETHOD RemoveElementEventState(nsIDOMElement* aElement, uint64_t aState) override; protected: ~nsDOMWindowUtils(); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 6a0979fce0..c3287ba387 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -2835,10 +2835,16 @@ HTMLInputElement::SetUserInput(const nsAString& aValue) void HTMLInputElement::SetAutofilled(bool aAutofilled) { + printf("🔍 AUTOFILL C++: SetAutofilled called with aAutofilled=%s\n", aAutofilled ? "true" : "false"); + if (aAutofilled) { + printf("🔍 AUTOFILL C++: Adding NS_EVENT_STATE_AUTOFILL state\n"); AddStates(NS_EVENT_STATE_AUTOFILL); + printf("🔍 AUTOFILL C++: State added successfully\n"); } else { + printf("🔍 AUTOFILL C++: Removing NS_EVENT_STATE_AUTOFILL state\n"); RemoveStates(NS_EVENT_STATE_AUTOFILL); + printf("🔍 AUTOFILL C++: State removed successfully\n"); } } @@ -8519,7 +8525,9 @@ HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) // Clear autofilled state if this was an interactive user change if (aWasInteractiveUserChange && State().HasState(NS_EVENT_STATE_AUTOFILL)) { + printf("🔍 AUTOFILL C++: User changed autofilled input, clearing state\n"); RemoveStates(NS_EVENT_STATE_AUTOFILL); + printf("🔍 AUTOFILL C++: Autofill state cleared from input\n"); } UpdateAllValidityStates(aNotify); diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index e34e56975f..8876a0cb44 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -369,10 +369,16 @@ HTMLTextAreaElement::SetUserInput(const nsAString& aValue) void HTMLTextAreaElement::SetAutofilled(bool aAutofilled) { + printf("🔍 AUTOFILL C++: HTMLTextAreaElement::SetAutofilled called with aAutofilled=%s\n", aAutofilled ? "true" : "false"); + if (aAutofilled) { + printf("🔍 AUTOFILL C++: Adding NS_EVENT_STATE_AUTOFILL state to textarea\n"); AddStates(NS_EVENT_STATE_AUTOFILL); + printf("🔍 AUTOFILL C++: State added successfully to textarea\n"); } else { + printf("🔍 AUTOFILL C++: Removing NS_EVENT_STATE_AUTOFILL state from textarea\n"); RemoveStates(NS_EVENT_STATE_AUTOFILL); + printf("🔍 AUTOFILL C++: State removed successfully from textarea\n"); } } @@ -1645,7 +1651,9 @@ HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange // Clear autofilled state if this was an interactive user change if (aWasInteractiveUserChange && State().HasState(NS_EVENT_STATE_AUTOFILL)) { + printf("🔍 AUTOFILL C++: User changed autofilled textarea, clearing state\n"); RemoveStates(NS_EVENT_STATE_AUTOFILL); + printf("🔍 AUTOFILL C++: Autofill state cleared from textarea\n"); } // Update the validity state diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 1289bd940d..cd695cf186 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1944,6 +1944,20 @@ interface nsIDOMWindowUtils : nsISupports { const long MOUSE_BUTTONS_5TH_BUTTON = 0x10; // Buttons are not specified, will be calculated from |aButton|. const long MOUSE_BUTTONS_NOT_SPECIFIED = -1; + + /** + * Add an EventState bit to an element (privileged only). + * @param element The element to modify. + * @param state The EventState bit (see EventStates.h, e.g. NS_EVENT_STATE_AUTOFILL). + */ + void addElementEventState(in nsIDOMElement element, in unsigned long long state); + + /** + * Remove an EventState bit from an element (privileged only). + * @param element The element to modify. + * @param state The EventState bit. + */ + void removeElementEventState(in nsIDOMElement element, in unsigned long long state); }; [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)] diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index b763be1283..196c5d9f26 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -277,6 +277,9 @@ CSS_STATE_PSEUDO_CLASS(mozMeterSubSubOptimum, ":-moz-meter-sub-sub-optimum", 0, // Those values should be parsed but do nothing. CSS_STATE_PSEUDO_CLASS(mozPlaceholder, ":-moz-placeholder", 0, "", NS_EVENT_STATE_IGNORE) +// Internal-only pseudo-class for autofill highlight +CSS_STATE_PSEUDO_CLASS(mozAutofillHighlight, ":-moz-autofill-highlight", CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "", NS_EVENT_STATE_AUTOFILL) + #ifdef DEFINED_CSS_STATE_PSEUDO_CLASS #undef DEFINED_CSS_STATE_PSEUDO_CLASS #undef CSS_STATE_PSEUDO_CLASS diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css index e94d347687..8a09796f25 100644 --- a/layout/style/res/forms.css +++ b/layout/style/res/forms.css @@ -1149,3 +1149,9 @@ input[type="date"], input[type="time"] { overflow: hidden !important; } + +/* Autofill highlight for internal-only pseudo-class */ +input:-moz-autofill-highlight, +textarea:-moz-autofill-highlight { + background-color: #ffff99 !important; +} diff --git a/toolkit/components/formautofill/FormAutofillContentService.js b/toolkit/components/formautofill/FormAutofillContentService.js index 273697f221..d5afd8062f 100644 --- a/toolkit/components/formautofill/FormAutofillContentService.js +++ b/toolkit/components/formautofill/FormAutofillContentService.js @@ -11,6 +11,8 @@ "use strict"; +console.log('🔍 AUTOFILL: FormAutofillContentService.js loaded'); + const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Services.jsm"); @@ -130,7 +132,9 @@ FormHandler.prototype = { return "cancel"; } + console.log('🔍 AUTOFILL: About to call autofillFormFields with result:', result); this.autofillFormFields(result); + console.log('🔍 AUTOFILL: autofillFormFields completed'); return "success"; }), @@ -226,22 +230,38 @@ FormHandler.prototype = { * } */ autofillFormFields: function (aAutofillResult) { + console.log('🔍 AUTOFILL: autofillFormFields called with', aAutofillResult); + for (let field of aAutofillResult.fields) { + console.log('🔍 AUTOFILL: Processing field', field); + // Get the field details, if it was processed by the user interface. let fieldDetail = this.fieldDetails .find(f => f.section == field.section && f.addressType == field.addressType && f.contactType == field.contactType && f.fieldName == field.fieldName); + + console.log('🔍 AUTOFILL: Found fieldDetail?', !!fieldDetail, fieldDetail); + if (!fieldDetail) { + console.log('🔍 AUTOFILL: No fieldDetail found, skipping'); continue; } + console.log('🔍 AUTOFILL: Setting value on element', fieldDetail.element); fieldDetail.element.value = field.value; // Set the autofilled state on the element + console.log('🔍 AUTOFILL: Checking if setAutofilled exists on element'); + console.log('🔍 AUTOFILL: setAutofilled type:', typeof fieldDetail.element.setAutofilled); + if (typeof fieldDetail.element.setAutofilled === 'function') { + console.log('🔍 AUTOFILL: Calling setAutofilled(true) on element'); fieldDetail.element.setAutofilled(true); + console.log('🔍 AUTOFILL: setAutofilled(true) called successfully'); + } else { + console.log('🔍 AUTOFILL: setAutofilled is not a function on this element'); } } },