author | prathiksha <prathikshaprasadsuman@gmail.com> |
Wed, 06 Feb 2019 23:50:04 -0800 | |
changeset 457532 | bcfe1e75c5016b7e5fed79c13d97eec73434b289 |
parent 457531 | 4fe6c3dcad6373481c96bb8bde8b43631ee9a95b |
child 457533 | 04eecadabb485bd398c6c37e258ba47b946e7982 |
push id | 111739 |
push user | mozilla@noorenberghe.ca |
push date | Thu, 07 Feb 2019 07:59:17 +0000 |
treeherder | mozilla-inbound@bcfe1e75c501 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | MattN |
bugs | 1189524 |
milestone | 67.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -56,17 +56,17 @@ addEventListener("DOMInputPasswordAdded" LoginManagerContent.onDOMInputPasswordAdded(event, content); let formLike = LoginFormFactory.createFromField(event.originalTarget); InsecurePasswordUtils.reportInsecurePasswords(formLike); }); addEventListener("DOMAutoComplete", function(event) { if (shouldIgnoreLoginManagerEvent(event)) { return; } - LoginManagerContent.onUsernameInput(event); + LoginManagerContent.onDOMAutoComplete(event); }); ContentMetaHandler.init(this); // This is a temporary hack to prevent regressions (bug 1471327). void content; addEventListener("DOMWindowFocus", function(event) {
--- a/mobile/android/components/BrowserCLH.js +++ b/mobile/android/components/BrowserCLH.js @@ -209,25 +209,17 @@ BrowserCLH.prototype = { } this.LoginManagerContent.onDOMInputPasswordAdded(event, event.target.ownerGlobal.top); }, options); aWindow.addEventListener("DOMAutoComplete", event => { if (shouldIgnoreLoginManagerEvent(event)) { return; } - this.LoginManagerContent.onUsernameInput(event); - }, options); - - aWindow.addEventListener("blur", event => { - if (ChromeUtils.getClassName(event.target) !== "HTMLInputElement" || - shouldIgnoreLoginManagerEvent(event)) { - return; - } - this.LoginManagerContent.onUsernameInput(event); + this.LoginManagerContent.onDOMAutoComplete(event); }, options); aWindow.addEventListener("pageshow", event => { // XXXbz what about non-HTML documents?? if (ChromeUtils.getClassName(event.target) == "HTMLDocument") { this.LoginManagerContent.onPageShow(event, event.target.defaultView.top); } }, options);
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -5,16 +5,17 @@ "use strict"; var EXPORTED_SYMBOLS = [ "LoginManagerContent", "LoginFormFactory", "UserAutoCompleteResult" ]; const PASSWORD_INPUT_ADDED_COALESCING_THRESHOLD_MS = 1; const AUTOCOMPLETE_AFTER_RIGHT_CLICK_THRESHOLD_MS = 400; +const AUTOFILL_STATE = "-moz-autofill"; const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); const {PrivateBrowsingUtils} = ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); const {PromiseUtils} = ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm"); ChromeUtils.defineModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm"); ChromeUtils.defineModuleGetter(this, "FormLikeFactory", @@ -600,52 +601,59 @@ var LoginManagerContent = { return; } log("maybeOpenAutocompleteAfterFocus: Opening the autocomplete popup"); this._formFillService.showPopup(); }, /** - * Listens for DOMAutoComplete and blur events on an input field. + * Listens for DOMAutoComplete event on login form. */ - onUsernameInput(event) { + onDOMAutoComplete(event) { if (!event.isTrusted) { return; } if (!gEnabled) { return; } - var acInputField = event.target; + let acInputField = event.target; // This is probably a bit over-conservatative. if (ChromeUtils.getClassName(acInputField.ownerDocument) != "HTMLDocument") { return; } - if (!LoginHelper.isUsernameFieldType(acInputField)) { + if (!LoginFormFactory.createFromField(acInputField)) { return; } - var acForm = LoginFormFactory.createFromField(acInputField); - if (!acForm) { - return; + if (LoginHelper.isUsernameFieldType(acInputField)) { + this.onUsernameInput(event); } + }, + + /** + * Calls fill form on the username field. + */ + onUsernameInput(event) { + let acInputField = event.target; // If the username is blank, bail out now -- we don't want // fillForm() to try filling in a login without a username // to filter on (bug 471906). if (!acInputField.value) { return; } log("onUsernameInput from", event.type); + let acForm = LoginFormFactory.createFromField(acInputField); let doc = acForm.ownerDocument; let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI); let recipes = LoginRecipesContent.getRecipes(formOrigin, doc.defaultView); // Make sure the username field fillForm will use is the // same field as the autocomplete was activated on. var [usernameField, passwordField, ignored] = this._getFormFields(acForm, false, recipes); @@ -993,16 +1001,38 @@ var LoginManagerContent = { formSubmitURL, usernameField: mockUsername, newPasswordField: mockPassword, oldPasswordField: mockOldPassword, openerTopWindowID, }); }, + /** Remove login field highlight when its value is cleared or overwritten. + */ + _removeFillFieldHighlight(event) { + let winUtils = event.target.ownerGlobal.windowUtils; + winUtils.removeManuallyManagedState(event.target, AUTOFILL_STATE); + }, + + /** + * Highlight login fields on autocomplete or autofill on page load. + * @param {Node} element that needs highlighting. + */ + _highlightFilledField(element) { + let winUtils = element.ownerGlobal.windowUtils; + + winUtils.addManuallyManagedState(element, AUTOFILL_STATE); + // Remove highlighting when the field is changed. + element.addEventListener("input", this._removeFillFieldHighlight, { + mozSystemGroup: true, + once: true, + }); + }, + /** * Attempt to find the username and password fields in a form, and fill them * in using the provided logins and recipes. * * @param {LoginForm} form * @param {nsILoginInfo[]} foundLogins an array of nsILoginInfo that could be used for the form * @param {Set} recipes a set of recipes that could be used to affect how the @@ -1243,18 +1273,22 @@ var LoginManagerContent = { let userNameDiffers = selectedLogin.username != usernameField.value; // Don't replace the username if it differs only in case, and the user triggered // this autocomplete. We assume that if it was user-triggered the entered text // is desired. let userEnteredDifferentCase = userTriggered && userNameDiffers && usernameField.value.toLowerCase() == selectedLogin.username.toLowerCase(); - if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) { - usernameField.setUserInput(selectedLogin.username); + if (!disabledOrReadOnly) { + if (!userEnteredDifferentCase && userNameDiffers) { + usernameField.setUserInput(selectedLogin.username); + } + + this._highlightFilledField(usernameField); } } let doc = form.ownerDocument; if (passwordField.value != selectedLogin.password) { passwordField.setUserInput(selectedLogin.password); let autoFilledLogin = { guid: selectedLogin.QueryInterface(Ci.nsILoginMetaInfo).guid, @@ -1262,16 +1296,18 @@ var LoginManagerContent = { usernameField: usernameField ? Cu.getWeakReference(usernameField) : null, password: selectedLogin.password, passwordField: Cu.getWeakReference(passwordField), }; log("Saving autoFilledLogin", autoFilledLogin.guid, "for", form.rootElement); this.stateForDocument(doc).fillsByRootElement.set(form.rootElement, autoFilledLogin); } + this._highlightFilledField(passwordField); + log("_fillForm succeeded"); autofillResult = AUTOFILL_RESULT.FILLED; let win = doc.defaultView; let messageManager = win.docShell.messageManager; messageManager.sendAsyncMessage("LoginStats:LoginFillSuccessful"); } finally { if (autofillResult == -1) {
--- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini +++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini @@ -16,21 +16,26 @@ support-files = ../browser/formless_basic.html ../browser/form_cross_origin_secure_action.html auth2/authenticate.sjs pwmgr_common.js pwmgr_common_parent.js ../authenticate.sjs skip-if = toolkit == 'android' && !isFennec # Don't run on GeckoView +[test_autocomplete_highlight.html] +scheme = https +skip-if = toolkit == 'android' # autocomplete [test_autocomplete_https_upgrade.html] skip-if = toolkit == 'android' # autocomplete [test_autocomplete_sandboxed.html] scheme = https skip-if = toolkit == 'android' # autocomplete +[test_autofill_highlight.html] +scheme = https [test_autofill_https_upgrade.html] skip-if = toolkit == 'android' # Bug 1259768 [test_autofill_sandboxed.html] scheme = https skip-if = toolkit == 'android' [test_autofill_password-only.html] [test_autofocus_js.html] skip-if = toolkit == 'android' # autocomplete
new file mode 100644 --- /dev/null +++ b/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test form field autofill highlight</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script> + <script type="text/javascript" src="../../../satchel/test/satchel_common.js"></script> + <script type="text/javascript" src="pwmgr_common.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +runInParent(function initLogins() { + const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); + + let login1 = Cc["@mozilla.org/login-manager/loginInfo;1"] + .createInstance(Ci.nsILoginInfo); + login1.init("https://example.com", "https://autocomplete", null, + "user1", "pass1", "", ""); + + let login2 = Cc["@mozilla.org/login-manager/loginInfo;1"] + .createInstance(Ci.nsILoginInfo); + login2.init("https://example.com", "https://autocomplete", null, + "user2", "pass2", "", ""); + + Services.logins.addLogin(login1); + Services.logins.addLogin(login2); +}); + +</script> +<body> +<p id="display"></p> +<div id="content"> + <form id="form1" action="https://autocomplete" onsubmit="return false;"> + <input type="text" id="uname"> + <input type="password" id="pword"> + <button type="submit">Submit</button> + </form> +<pre id="test"> +<script> +let {ContentTaskUtils} = SpecialPowers.Cu.import("resource://testing-common/ContentTaskUtils.jsm", {}); + +add_task(async function test_field_highlight_on_autocomplete() { + // Test username autocomplete. + let username = document.getElementById("uname"); + let password = document.getElementById("pword"); + + username.focus(); + + let shownPromise = promiseACShown(); + synthesizeKey("KEY_ArrowDown"); + await shownPromise; + synthesizeKey("KEY_ArrowDown"); + await synthesizeKey("KEY_Enter"); + + await ContentTaskUtils.waitForCondition(() => { + return document.defaultView.getComputedStyle(username).getPropertyValue("filter") !== "none"; + }, "Highlight was successfully applied to the username field on username autocomplete"); + + isnot(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none", + "Highlight was successfully applied to the password field on username autocomplete"); + + // Clear existing highlight on login fields. We check by pressing the tab key after backspace + // (by shifting focus to the next element) because the tab key is known to cause a bug where the + // highlight is applied once again. + username.focus(); + synthesizeKey("KEY_Backspace"); + synthesizeKey("KEY_Tab"); + is(document.defaultView.getComputedStyle(username).getPropertyValue("filter"), "none", + "Highlight was successfully removed on the username field"); + + synthesizeKey("KEY_Backspace"); + synthesizeKey("KEY_Tab"); + is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none", + "Highlight was successfully removed on the password field"); +}); +</script> +</body> +</html> +
new file mode 100644 --- /dev/null +++ b/toolkit/components/passwordmgr/test/mochitest/test_autofill_highlight.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test form field autofill highlight</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script> + <script type="text/javascript" src="pwmgr_common.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +runInParent(function initLogins() { + const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); + + let login1 = Cc["@mozilla.org/login-manager/loginInfo;1"] + .createInstance(Ci.nsILoginInfo); + login1.init("https://example.com", "https://autofill", null, + "user1", "pass1", "", ""); + + Services.logins.addLogin(login1); +}); +</script> +<body> +<p id="display"></p> + +<div id="content"> + <form id="form1" action="https://autofill" onsubmit="return false;"> + <input type="text" id="uname"> + <input type="password" id="pword"> + <button type="submit">Submit</button> + </form> + +<pre id="test"> +<script> +let {ContentTaskUtils} = SpecialPowers.Cu.import("resource://testing-common/ContentTaskUtils.jsm", {}); + +add_task(async function test_field_highlight_on_autofill() { + let username = document.getElementById("uname"); + let password = document.getElementById("pword"); + + await ContentTaskUtils.waitForCondition(() => { + return document.defaultView.getComputedStyle(username).getPropertyValue("filter") !== "none"; + }, "Highlight was successfully applied to the username field on page load autofill"); + + isnot(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none", + "Highlight was successfully applied to the password field on page load autofill"); + + // Test that initiating a change on the input value will remove the highlight. We check by pressing + // the tab key after backspace(by shifting focus to the next element) because the tab key is known to + // cause a bug where the highlight is applied once again. + username.focus(); + synthesizeKey("KEY_Backspace"); + synthesizeKey("KEY_Tab"); + + let computedStyle = document.defaultView.getComputedStyle(username); + is(computedStyle.getPropertyValue("filter"), "none", "Highlight was successfully removed on change in value of username input element"); + + synthesizeKey("KEY_Backspace"); + synthesizeKey("KEY_Tab"); + computedStyle = document.defaultView.getComputedStyle(password); + is(computedStyle.getPropertyValue("filter"), "none", "Highlight was successfully removed on change in value of password input element"); +}); +</script> +</body> +</html> +
--- a/toolkit/components/passwordmgr/test/mochitest/test_autofill_https_upgrade.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_autofill_https_upgrade.html @@ -1,17 +1,16 @@ <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Test autocomplete on an HTTPS page using upgraded HTTP logins</title> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script> - <script type="text/javascript" src="../../../satchel/test/satchel_common.js"></script> <script type="text/javascript" src="pwmgr_common.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <script> const MISSING_ACTION_PATH = TESTS_DIR + "mochitest/form_basic.html"; const CROSS_ORIGIN_SECURE_PATH = TESTS_DIR + "mochitest/form_cross_origin_secure_action.html";