Merge mozilla-inbound to mozilla-central. a=merge
authorDaniel Varga <dvarga@mozilla.com>
Sun, 21 Apr 2019 00:46:34 +0300
changeset 470301 72be82c6809e2cc187e5cffdff0c3e686c564a57
parent 470300 581755bf88997188199042fd77a45336bda434d9 (current diff)
parent 470298 e9be442c871e173a409f3b969f5bcea0e1ae4d71 (diff)
child 470302 2f7d2b9798c226df217f96a5d9a9862798647792
child 470304 076077f53326a60ce878f3057cfeb00db15c927a
push id112856
push userdvarga@mozilla.com
push dateSat, 20 Apr 2019 21:53:58 +0000
treeherdermozilla-inbound@72be82c6809e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
72be82c6809e / 68.0a1 / 20190420214758 / files
nightly linux64
72be82c6809e / 68.0a1 / 20190420214758 / files
nightly mac
72be82c6809e / 68.0a1 / 20190420214758 / files
nightly win32
72be82c6809e / 68.0a1 / 20190420214758 / files
nightly win64
72be82c6809e / 68.0a1 / 20190420214758 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
--- a/browser/extensions/formautofill/test/mochitest/formautofill_common.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
@@ -112,18 +112,19 @@ function checkFieldValue(elem, expectedV
   is(elem.value, String(expectedValue), "Checking " + elem.id + " field");
 }
 
 function triggerAutofillAndCheckProfile(profile) {
   const adaptedProfile = _getAdaptedProfile(profile);
   const promises = [];
 
   for (const [fieldName, value] of Object.entries(adaptedProfile)) {
+    info(`triggerAutofillAndCheckProfile: ${fieldName}`);
     const element = document.getElementById(fieldName);
-    const expectingEvent = document.activeElement == element ? "DOMAutoComplete" : "change";
+    const expectingEvent = document.activeElement == element ? "input" : "change";
     const checkFieldAutofilled = Promise.all([
       new Promise(resolve => element.addEventListener("input", (event) => {
         if (element.tagName == "INPUT" && element.type == "text") {
           ok(event instanceof InputEvent,
              `"input" event should be dispatched with InputEvent interface on ${element.tagName}`);
           is(event.inputType, "insertReplacementText",
              "inputType value should be \"insertReplacementText\"");
           is(event.data, String(value),
--- a/browser/extensions/formautofill/test/mochitest/test_multi_locale_CA_address_form.html
+++ b/browser/extensions/formautofill/test/mochitest/test_multi_locale_CA_address_form.html
@@ -75,17 +75,17 @@ function checkElementFilled(element, exp
         resolve();
       }, {once: true});
     }),
   ];
 }
 
 function checkAutoCompleteInputFilled(element, expectedvalue) {
   return new Promise(resolve => {
-    element.addEventListener("DOMAutoComplete", function onChange() {
+    element.addEventListener("input", function onInput() {
       is(element.value, expectedvalue, "Checking " + element.name + " field");
       resolve();
     }, {once: true});
   });
 }
 
 function checkFormFilled(selector, address) {
   info("expecting form filled");
@@ -120,49 +120,49 @@ add_task(async function setup() {
   // without `supportedCountries` allowing Canada
   await SpecialPowers.pushPrefEnv({"set": [["extensions.formautofill.supportedCountries", "US,CA"]]});
 
   await setupAddressStorage();
 });
 
 // Autofill the address with address level 1 code.
 add_task(async function autofill_with_level1_code() {
-  await setInput("#organization-en", "Mozilla Toronto");
+  await setInput("#organization-en", "Mozilla Toront");
   synthesizeKey("KEY_ArrowDown");
   await expectPopup();
 
   synthesizeKey("KEY_ArrowDown");
   // Replace address level 1 code with full name in English for test result
   let result = Object.assign({}, MOCK_STORAGE[1], {"address-level1": "Ontario"});
   await checkFormFilled("#form-en", result);
 
-  await setInput("#organization-fr", "Mozilla Vancouver");
+  await setInput("#organization-fr", "Mozilla Vancouve");
   synthesizeKey("KEY_ArrowDown");
   await expectPopup();
 
   synthesizeKey("KEY_ArrowDown");
   // Replace address level 1 code with full name in French for test result
   result = Object.assign({}, MOCK_STORAGE[0], {"address-level1": "Colombie-Britannique"});
   await checkFormFilled("#form-fr", result);
   document.querySelector("#form-en").reset();
   document.querySelector("#form-fr").reset();
 });
 
 // Autofill the address with address level 1 full name.
 add_task(async function autofill_with_level1_full_name() {
-  await setInput("#organization-en", "ExpoCité");
+  await setInput("#organization-en", "ExpoCit");
   synthesizeKey("KEY_ArrowDown");
   await expectPopup();
 
   synthesizeKey("KEY_ArrowDown");
   // Replace address level 1 code with full name in French for test result
   let result = Object.assign({}, MOCK_STORAGE[3], {"address-level1": "Quebec"});
   await checkFormFilled("#form-en", result);
 
-  await setInput("#organization-fr", "Prince of Wales Northern Heritage");
+  await setInput("#organization-fr", "Prince of Wales");
   synthesizeKey("KEY_ArrowDown");
   await expectPopup();
 
   synthesizeKey("KEY_ArrowDown");
   // Replace address level 1 code with full name in English for test result
   result = Object.assign({}, MOCK_STORAGE[2], {"address-level1": "Territoires du Nord-Ouest"});
   await checkFormFilled("#form-fr", result);
 });
--- a/dom/svg/DOMSVGAngle.cpp
+++ b/dom/svg/DOMSVGAngle.cpp
@@ -60,17 +60,18 @@ float DOMSVGAngle::ValueInSpecifiedUnits
   }
   return mVal->mBaseVal;
 }
 
 void DOMSVGAngle::SetValueInSpecifiedUnits(float aValue, ErrorResult& rv) {
   if (mType == AnimValue) {
     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return;
-  } else if (mType == BaseValue) {
+  }
+  if (mType == BaseValue) {
     mVal->SetBaseValueInSpecifiedUnits(aValue, mSVGElement);
   } else {
     mVal->mBaseVal = aValue;
   }
 }
 
 void DOMSVGAngle::NewValueSpecifiedUnits(uint16_t unitType,
                                          float valueInSpecifiedUnits,
--- a/dom/svg/DOMSVGLength.cpp
+++ b/dom/svg/DOMSVGLength.cpp
@@ -207,18 +207,19 @@ float DOMSVGLength::GetValue(ErrorResult
     Element()->FlushAnimations();  // May make HasOwner() == false
   }
   if (HasOwner()) {
     float value = InternalItem().GetValueInUserUnits(Element(), Axis());
     if (!IsFinite(value)) {
       aRv.Throw(NS_ERROR_FAILURE);
     }
     return value;
-  } else if (mUnit == SVGLength_Binding::SVG_LENGTHTYPE_NUMBER ||
-             mUnit == SVGLength_Binding::SVG_LENGTHTYPE_PX) {
+  }
+  if (mUnit == SVGLength_Binding::SVG_LENGTHTYPE_NUMBER ||
+      mUnit == SVGLength_Binding::SVG_LENGTHTYPE_PX) {
     return mValue;
   }
   // else [SVGWG issue] Can't convert this length's value to user units
   // ReportToConsole
   aRv.Throw(NS_ERROR_FAILURE);
   return 0.0f;
 }
 
--- a/dom/svg/SVGAnimatedLength.cpp
+++ b/dom/svg/SVGAnimatedLength.cpp
@@ -37,21 +37,18 @@ static const nsStaticAtom* const unitMap
     nsGkAtoms::pc};
 
 static SVGAttrTearoffTable<SVGAnimatedLength, DOMSVGAnimatedLength>
     sSVGAnimatedLengthTearoffTable;
 
 /* Helper functions */
 
 static bool IsValidUnitType(uint16_t unit) {
-  if (unit > SVGLength_Binding::SVG_LENGTHTYPE_UNKNOWN &&
-      unit <= SVGLength_Binding::SVG_LENGTHTYPE_PC)
-    return true;
-
-  return false;
+  return unit > SVGLength_Binding::SVG_LENGTHTYPE_UNKNOWN &&
+         unit <= SVGLength_Binding::SVG_LENGTHTYPE_PC;
 }
 
 static void GetUnitString(nsAString& unit, uint16_t unitType) {
   if (IsValidUnitType(unitType)) {
     if (unitMap[unitType]) {
       unitMap[unitType]->ToString(unit);
     }
     return;
--- a/dom/svg/SVGAnimatedOrient.cpp
+++ b/dom/svg/SVGAnimatedOrient.cpp
@@ -71,19 +71,17 @@ class MOZ_RAII AutoChangeOrientNotifier 
   SVGAnimatedOrient* const mOrient;
   SVGElement* const mSVGElement;
   nsAttrValue mEmptyOrOldValue;
   bool mDoSetAttr;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 static bool IsValidAngleUnitType(uint16_t unit) {
-  if (unit > SVG_ANGLETYPE_UNKNOWN && unit <= SVG_ANGLETYPE_GRAD) return true;
-
-  return false;
+  return unit > SVG_ANGLETYPE_UNKNOWN && unit <= SVG_ANGLETYPE_GRAD;
 }
 
 static void GetAngleUnitString(nsAString& unit, uint16_t unitType) {
   if (IsValidAngleUnitType(unitType)) {
     if (angleUnitMap[unitType]) {
       angleUnitMap[unitType]->ToString(unit);
     }
     return;
--- a/dom/svg/SVGPolyElement.cpp
+++ b/dom/svg/SVGPolyElement.cpp
@@ -53,19 +53,17 @@ SVGPolyElement::IsAttributeMapped(const 
 bool SVGPolyElement::HasValidDimensions() const {
   return !mPoints.GetAnimValue().IsEmpty();
 }
 
 //----------------------------------------------------------------------
 // SVGGeometryElement methods
 
 bool SVGPolyElement::AttributeDefinesGeometry(const nsAtom* aName) {
-  if (aName == nsGkAtoms::points) return true;
-
-  return false;
+  return aName == nsGkAtoms::points;
 }
 
 void SVGPolyElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
   const SVGPointList& points = mPoints.GetAnimValue();
 
   if (!points.Length()) return;
 
   float px = points[0].mX, py = points[0].mY, prevAngle = 0.0;
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -212,19 +212,18 @@ bool SVGSVGElement::AnimationsPaused() {
   return root && root->IsPausedByType(SMILTimeContainer::PAUSE_SCRIPT);
 }
 
 float SVGSVGElement::GetCurrentTimeAsFloat() {
   SMILTimeContainer* root = GetTimedDocumentRoot();
   if (root) {
     double fCurrentTimeMs = double(root->GetCurrentTimeAsSMILTime());
     return (float)(fCurrentTimeMs / PR_MSEC_PER_SEC);
-  } else {
-    return 0.f;
   }
+  return 0.f;
 }
 
 void SVGSVGElement::SetCurrentTime(float seconds) {
   if (mTimedDocumentRoot) {
     // Make sure the timegraph is up-to-date
     FlushAnimations();
     double fMilliseconds = double(seconds) * PR_MSEC_PER_SEC;
     // Round to nearest whole number before converting, to avoid precision
@@ -636,17 +635,18 @@ SVGViewElement* SVGSVGElement::GetCurren
   return nullptr;
 }
 
 const SVGAnimatedViewBox& SVGSVGElement::GetViewBoxInternal() const {
   SVGViewElement* viewElement = GetCurrentViewElement();
 
   if (viewElement && viewElement->mViewBox.HasRect()) {
     return viewElement->mViewBox;
-  } else if (mSVGView && mSVGView->mViewBox.HasRect()) {
+  }
+  if (mSVGView && mSVGView->mViewBox.HasRect()) {
     return mSVGView->mViewBox;
   }
 
   return mViewBox;
 }
 
 SVGAnimatedTransformList* SVGSVGElement::GetTransformInternal() const {
   return (mSVGView && mSVGView->mTransforms) ? mSVGView->mTransforms
--- a/dom/svg/SVGTransformableElement.cpp
+++ b/dom/svg/SVGTransformableElement.cpp
@@ -202,40 +202,39 @@ already_AddRefed<SVGIRect> SVGTransforma
     return NS_NewSVGRect(this, ToRect(rec));
   }
 
   if (!NS_SVGNewGetBBoxEnabled()) {
     return NS_NewSVGRect(
         this, ToRect(nsSVGUtils::GetBBox(
                   frame, nsSVGUtils::eBBoxIncludeFillGeometry |
                              nsSVGUtils::eUseUserSpaceOfUseElement)));
-  } else {
-    uint32_t flags = 0;
-    if (aOptions.mFill) {
-      flags |= nsSVGUtils::eBBoxIncludeFill;
-    }
-    if (aOptions.mStroke) {
-      flags |= nsSVGUtils::eBBoxIncludeStroke;
-    }
-    if (aOptions.mMarkers) {
-      flags |= nsSVGUtils::eBBoxIncludeMarkers;
-    }
-    if (aOptions.mClipped) {
-      flags |= nsSVGUtils::eBBoxIncludeClipped;
-    }
-    if (flags == 0) {
-      return NS_NewSVGRect(this, 0, 0, 0, 0);
-    }
-    if (flags == nsSVGUtils::eBBoxIncludeMarkers ||
-        flags == nsSVGUtils::eBBoxIncludeClipped) {
-      flags |= nsSVGUtils::eBBoxIncludeFill;
-    }
-    flags |= nsSVGUtils::eUseUserSpaceOfUseElement;
-    return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame, flags)));
+  }
+  uint32_t flags = 0;
+  if (aOptions.mFill) {
+    flags |= nsSVGUtils::eBBoxIncludeFill;
+  }
+  if (aOptions.mStroke) {
+    flags |= nsSVGUtils::eBBoxIncludeStroke;
+  }
+  if (aOptions.mMarkers) {
+    flags |= nsSVGUtils::eBBoxIncludeMarkers;
   }
+  if (aOptions.mClipped) {
+    flags |= nsSVGUtils::eBBoxIncludeClipped;
+  }
+  if (flags == 0) {
+    return NS_NewSVGRect(this, 0, 0, 0, 0);
+  }
+  if (flags == nsSVGUtils::eBBoxIncludeMarkers ||
+      flags == nsSVGUtils::eBBoxIncludeClipped) {
+    flags |= nsSVGUtils::eBBoxIncludeFill;
+  }
+  flags |= nsSVGUtils::eUseUserSpaceOfUseElement;
+  return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame, flags)));
 }
 
 already_AddRefed<SVGMatrix> SVGTransformableElement::GetCTM() {
   Document* currentDoc = GetComposedDoc();
   if (currentDoc) {
     // Flush all pending notifications so that our frames are up to date
     currentDoc->FlushPendingNotifications(FlushType::Layout);
   }
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -211,21 +211,17 @@ static bool IsTextContentElement(nsICont
     return !parent || !IsTextContentElement(parent);
   }
 
   if (aContent->IsSVGElement(nsGkAtoms::textPath)) {
     nsIContent* parent = GetFirstNonAAncestor(aContent->GetParent());
     return parent && parent->IsSVGElement(nsGkAtoms::text);
   }
 
-  if (aContent->IsAnyOfSVGElements(nsGkAtoms::a, nsGkAtoms::tspan)) {
-    return true;
-  }
-
-  return false;
+  return aContent->IsAnyOfSVGElements(nsGkAtoms::a, nsGkAtoms::tspan);
 }
 
 /**
  * Returns whether the specified frame is an nsTextFrame that has some text
  * content.
  */
 static bool IsNonEmptyTextFrame(nsIFrame* aFrame) {
   nsTextFrame* textFrame = do_QueryFrame(aFrame);
@@ -3236,23 +3232,19 @@ static int32_t GetCaretOffset(nsCaret* a
  */
 static bool ShouldPaintCaret(const TextRenderedRun& aThisRun, nsCaret* aCaret) {
   int32_t caretOffset = GetCaretOffset(aCaret);
 
   if (caretOffset < 0) {
     return false;
   }
 
-  if (uint32_t(caretOffset) >= aThisRun.mTextFrameContentOffset &&
-      uint32_t(caretOffset) <
-          aThisRun.mTextFrameContentOffset + aThisRun.mTextFrameContentLength) {
-    return true;
-  }
-
-  return false;
+  return uint32_t(caretOffset) >= aThisRun.mTextFrameContentOffset &&
+         uint32_t(caretOffset) < aThisRun.mTextFrameContentOffset +
+                                     aThisRun.mTextFrameContentLength;
 }
 
 void SVGTextFrame::PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
                             imgDrawingParams& aImgParams,
                             const nsIntRect* aDirtyRect) {
   DrawTarget& aDrawTarget = *aContext.GetDrawTarget();
   nsIFrame* kid = PrincipalChildList().FirstChild();
   if (!kid) {
--- a/layout/svg/nsCSSFilterInstance.cpp
+++ b/layout/svg/nsCSSFilterInstance.cpp
@@ -15,17 +15,18 @@
 #include "nsTArray.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 static float ClampFactor(float aFactor) {
   if (aFactor > 1) {
     return 1;
-  } else if (aFactor < 0) {
+  }
+  if (aFactor < 0) {
     MOZ_ASSERT_UNREACHABLE("A negative value should not have been parsed.");
     return 0;
   }
 
   return aFactor;
 }
 
 nsCSSFilterInstance::nsCSSFilterInstance(
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -120,17 +120,18 @@ nsresult nsSVGImageFrame::AttributeChang
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y ||
         aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) {
       nsLayoutUtils::PostRestyleEvent(
           mContent->AsElement(), RestyleHint{0},
           nsChangeHint_InvalidateRenderingObservers);
       nsSVGUtils::ScheduleReflowSVG(this);
       return NS_OK;
-    } else if (aAttribute == nsGkAtoms::preserveAspectRatio) {
+    }
+    if (aAttribute == nsGkAtoms::preserveAspectRatio) {
       // We don't paint the content of the image using display lists, therefore
       // we have to invalidate for this children-only transform changes since
       // there is no layer tree to notice that the transform changed and
       // recomposite.
       InvalidateFrame();
       return NS_OK;
     }
   }
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1204,20 +1204,17 @@ bool nsSVGUtils::CanOptimizeOpacity(nsIF
     return false;
   }
 
   if (nsLayoutUtils::HasAnimationOfPropertySet(
           aFrame, nsCSSPropertyIDSet::OpacityProperties())) {
     return false;
   }
 
-  if (!style->HasFill() || !HasStroke(aFrame)) {
-    return true;
-  }
-  return false;
+  return !style->HasFill() || !HasStroke(aFrame);
 }
 
 gfxMatrix nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix& aMatrix,
                                            SVGAnimatedEnumeration* aUnits,
                                            nsIFrame* aFrame, uint32_t aFlags) {
   if (aFrame && aUnits->GetAnimValue() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     gfxRect bbox = GetBBox(aFrame, aFlags);
     gfxMatrix tm = aMatrix;
--- a/mobile/android/components/LoginManagerPrompter.js
+++ b/mobile/android/components/LoginManagerPrompter.js
@@ -102,36 +102,38 @@ LoginManagerPrompter.prototype = {
   // setting this attribute is ignored because Android does not consider
   // opener windows when displaying login notifications
   set opener(aOpener) { },
 
   /*
    * promptToSavePassword
    *
    */
-  promptToSavePassword: function(aLogin) {
-    this._showSaveLoginNotification(aLogin);
+  promptToSavePassword: function(aLogin, dismissed) {
+    this._showSaveLoginNotification(aLogin, dismissed);
       Services.telemetry.getHistogramById("PWMGR_PROMPT_REMEMBER_ACTION").add(PROMPT_DISPLAYED);
     Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
   },
 
   /*
    * _showLoginNotification
    *
    * Displays a notification doorhanger.
    * @param aBody
    *        String message to be displayed in the doorhanger
    * @param aButtons
    *        Buttons to display with the doorhanger
    * @param aUsername
    *        Username string used in creating a doorhanger action
    * @param aPassword
    *        Password string used in creating a doorhanger action
+   * @param dismissed
+   *        A boolean indicating if a prompt is dismissed by default.
    */
-  _showLoginNotification: function(aBody, aButtons, aUsername, aPassword) {
+  _showLoginNotification: function(aBody, aButtons, aUsername, aPassword, dismissed = false) {
     let actionText = {
       text: aUsername,
       type: "EDIT",
       bundle: { username: aUsername,
       password: aPassword },
     };
 
     // The page we're going to hasn't loaded yet, so we want to persist
@@ -140,31 +142,32 @@ LoginManagerPrompter.prototype = {
     // Sites like Gmail perform a funky redirect dance before you end up
     // at the post-authentication page. I don't see a good way to
     // heuristically determine when to ignore such location changes, so
     // we'll try ignoring location changes based on a time interval.
     let options = {
       persistWhileVisible: true,
       timeout: Date.now() + 10000,
       actionText: actionText,
+      dismissed,
     };
 
     let win = (this._browser && this._browser.contentWindow) || this._window;
     DoorHanger.show(win, aBody, "password", aButtons, options, "LOGIN");
   },
 
   /*
    * _showSaveLoginNotification
    *
    * Displays a notification doorhanger (rather than a popup), to allow the user to
    * save the specified login. This allows the user to see the results of
    * their login, and only save a login which they know worked.
    *
    */
-  _showSaveLoginNotification: function(aLogin) {
+  _showSaveLoginNotification: function(aLogin, dismissed) {
     let brandShortName = this._strBundle.brand.GetStringFromName("brandShortName");
     let notificationText  = this._getLocalizedString("saveLogin", [brandShortName]);
 
     // The callbacks in |buttons| have a closure to access the variables
     // in scope here; set one to |Services.logins| so we can get back to pwmgr
     // without a getService() call.
     var pwmgr = Services.logins;
     let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_REMEMBER_ACTION");
@@ -186,41 +189,41 @@ LoginManagerPrompter.prototype = {
           }
           pwmgr.addLogin(aLogin);
           promptHistogram.add(PROMPT_ADD);
         },
         positive: true,
       },
     ];
 
-    this._showLoginNotification(notificationText, buttons, aLogin.username, aLogin.password);
+    this._showLoginNotification(notificationText, buttons, aLogin.username, aLogin.password, dismissed);
   },
 
   /*
    * promptToChangePassword
    *
    * Called when we think we detect a password change for an existing
    * login, when the form being submitted contains multiple password
    * fields.
    *
    */
-  promptToChangePassword: function(aOldLogin, aNewLogin) {
+  promptToChangePassword: function(aOldLogin, aNewLogin, dismissed) {
     this._showChangeLoginNotification(aOldLogin, aNewLogin.password);
     Services.telemetry.getHistogramById("PWMGR_PROMPT_UPDATE_ACTION").add(PROMPT_DISPLAYED);
     let oldGUID = aOldLogin.QueryInterface(Ci.nsILoginMetaInfo).guid;
     Services.obs.notifyObservers(aNewLogin, "passwordmgr-prompt-change", oldGUID);
   },
 
   /*
    * _showChangeLoginNotification
    *
    * Shows the Change Password notification doorhanger.
    *
    */
-  _showChangeLoginNotification: function(aOldLogin, aNewPassword) {
+  _showChangeLoginNotification: function(aOldLogin, aNewPassword, dismissed) {
     var notificationText;
     if (aOldLogin.username) {
       let displayUser = this._sanitizeUsername(aOldLogin.username);
       notificationText  = this._getLocalizedString("updatePassword", [displayUser]);
     } else {
       notificationText  = this._getLocalizedString("updatePasswordNoUser");
     }
 
@@ -242,17 +245,17 @@ LoginManagerPrompter.prototype = {
           self._updateLogin(aOldLogin, password);
 
           promptHistogram.add(PROMPT_UPDATE);
         },
         positive: true,
       },
     ];
 
-    this._showLoginNotification(notificationText, buttons, aOldLogin.username, aNewPassword);
+    this._showLoginNotification(notificationText, buttons, aOldLogin.username, aNewPassword, dismissed);
   },
 
   /*
    * promptToChangePasswordWithUsernames
    *
    * Called when we detect a password change in a form submission, but we
    * don't know which existing login (username) it's for. Asks the user
    * to select a username and confirm the password change.
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp
@@ -1268,17 +1268,17 @@ nsresult nsAutoCompleteController::Enter
     input->SelectTextRange(value.Length(), value.Length());
     SetSearchStringInternal(value);
   }
 
   obsSvc->NotifyObservers(input, "autocomplete-did-enter-text", nullptr);
   ClosePopup();
 
   bool cancel;
-  bool itemWasSelected = selectedIndex >= 0;
+  bool itemWasSelected = selectedIndex >= 0 && !value.IsEmpty();
   input->OnTextEntered(aEvent, itemWasSelected, &cancel);
 
   return NS_OK;
 }
 
 nsresult nsAutoCompleteController::RevertTextValue() {
   // StopSearch() can call PostSearchCleanup() which might result
   // in a blur event, which could null out mInput, so we need to check it
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -16,16 +16,17 @@ var EXPORTED_SYMBOLS = ["LoginManagerCon
 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");
+const {CreditCard} = ChromeUtils.import("resource://gre/modules/CreditCard.jsm");
 
 ChromeUtils.defineModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm");
 ChromeUtils.defineModuleGetter(this, "FormLikeFactory",
                                "resource://gre/modules/FormLikeFactory.jsm");
 ChromeUtils.defineModuleGetter(this, "LoginFormFactory",
                                "resource://gre/modules/LoginFormFactory.jsm");
 ChromeUtils.defineModuleGetter(this, "LoginRecipesContent",
                                "resource://gre/modules/LoginRecipes.jsm");
@@ -1154,25 +1155,37 @@ var LoginManagerContent = {
     });
 
     // Make sure to pass the opener's top ID in case it was in a frame.
     let openerTopWindowID = null;
     if (win.opener) {
       openerTopWindowID = win.opener.top.windowUtils.outerWindowID;
     }
 
+    // Dismiss prompt if the username field is a credit card number AND
+    // if the password field is a three digit number. Also dismiss prompt if
+    // the password is a credit card number and the password field has attribute
+    // autocomplete="cc-number".
+    let dismissedPrompt = false;
+    let newPasswordFieldValue = newPasswordField.value;
+    if ((CreditCard.isValidNumber(usernameValue) && newPasswordFieldValue.trim().match(/^[0-9]{3}$/)) ||
+        (CreditCard.isValidNumber(newPasswordFieldValue) && newPasswordField.getAutocompleteInfo().fieldName == "cc-number")) {
+      dismissedPrompt = true;
+    }
+
     let autoFilledLogin = this.stateForDocument(doc).fillsByRootElement.get(form.rootElement);
     messageManager.sendAsyncMessage("PasswordManager:onFormSubmit",
                                     { hostname,
                                       formSubmitURL,
                                       autoFilledLoginGuid: autoFilledLogin && autoFilledLogin.guid,
                                       usernameField: mockUsername,
                                       newPasswordField: mockPassword,
                                       oldPasswordField: mockOldPassword,
                                       openerTopWindowID,
+                                      dismissedPrompt,
                                     });
   },
 
   /** 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);
--- a/toolkit/components/passwordmgr/LoginManagerParent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerParent.jsm
@@ -95,16 +95,17 @@ var LoginManagerParent = {
         // TODO Verify msg.target's principals against the formOrigin?
         this.onFormSubmit({hostname: data.hostname,
                            formSubmitURL: data.formSubmitURL,
                            autoFilledLoginGuid: data.autoFilledLoginGuid,
                            usernameField: data.usernameField,
                            newPasswordField: data.newPasswordField,
                            oldPasswordField: data.oldPasswordField,
                            openerTopWindowID: data.openerTopWindowID,
+                           dismissedPrompt: data.dismissedPrompt,
                            target: msg.target});
         break;
       }
 
       case "PasswordManager:insecureLoginFormPresent": {
         this.setHasInsecureLoginForms(msg.target, data.hasInsecureLoginForms);
         break;
       }
@@ -298,17 +299,17 @@ var LoginManagerParent = {
       requestId,
       logins: jsLogins,
     });
   },
 
   onFormSubmit({hostname, formSubmitURL, autoFilledLoginGuid,
                 usernameField, newPasswordField,
                 oldPasswordField, openerTopWindowID,
-                target}) {
+                dismissedPrompt, target}) {
     function getPrompter() {
       var prompterSvc = Cc["@mozilla.org/login-manager/prompter;1"].
                         createInstance(Ci.nsILoginManagerPrompter);
       prompterSvc.init(target.ownerGlobal);
       prompterSvc.browser = target;
 
       for (let win of Services.wm.getEnumerator(null)) {
         let tabbrowser = win.gBrowser;
@@ -382,17 +383,17 @@ var LoginManagerParent = {
           log("(Not prompting to save/change since we have no username and the " +
               "only saved password matches the new password)");
           return;
         }
 
         formLogin.username      = oldLogin.username;
         formLogin.usernameField = oldLogin.usernameField;
 
-        prompter.promptToChangePassword(oldLogin, formLogin);
+        prompter.promptToChangePassword(oldLogin, formLogin, dismissedPrompt);
       } else {
         // Note: It's possible that that we already have the correct u+p saved
         // but since we don't have the username, we don't know if the user is
         // changing a second account to the new password so we ask anyways.
 
         prompter.promptToChangePasswordWithUsernames(
           logins, logins.length, formLogin);
       }
@@ -440,32 +441,31 @@ var LoginManagerParent = {
 
     if (existingLogin) {
       log("Found an existing login matching this form submission");
 
       // Change password if needed.
       if (existingLogin.password != formLogin.password) {
         log("...passwords differ, prompting to change.");
         prompter = getPrompter();
-        prompter.promptToChangePassword(existingLogin, formLogin);
+        prompter.promptToChangePassword(existingLogin, formLogin, dismissedPrompt);
       } else if (!existingLogin.username && formLogin.username) {
         log("...empty username update, prompting to change.");
         prompter = getPrompter();
-        prompter.promptToChangePassword(existingLogin, formLogin);
+        prompter.promptToChangePassword(existingLogin, formLogin, dismissedPrompt);
       } else {
         recordLoginUse(existingLogin);
       }
 
       return;
     }
 
-
     // Prompt user to save login (via dialog or notification bar)
     prompter = getPrompter();
-    prompter.promptToSavePassword(formLogin);
+    prompter.promptToSavePassword(formLogin, dismissedPrompt);
   },
 
   /**
    * Maps all the <browser> elements for tabs in the parent process to the
    * current state used to display tab-specific UI.
    *
    * This mapping is not updated in case a web page is moved to a different
    * chrome window by the swapDocShells method. In this case, it is possible
--- a/toolkit/components/passwordmgr/LoginManagerPrompter.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerPrompter.jsm
@@ -807,22 +807,22 @@ LoginManagerPrompter.prototype = {
   set browser(aBrowser) {
     this._browser = aBrowser;
   },
 
   set openerBrowser(aOpenerBrowser) {
     this._openerBrowser = aOpenerBrowser;
   },
 
-  promptToSavePassword(aLogin) {
+  promptToSavePassword(aLogin, dismissed) {
     this.log("promptToSavePassword");
     var notifyObj = this._getPopupNote();
     if (notifyObj) {
       this._showLoginCaptureDoorhanger(aLogin, "password-save", {
-        dismissed: this._inPrivateBrowsing,
+        dismissed: this._inPrivateBrowsing || dismissed,
       });
       Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
     } else {
       this._showSaveLoginDialog(aLogin);
     }
   },
 
   /**
@@ -1171,47 +1171,53 @@ LoginManagerPrompter.prototype = {
    * Called when we think we detect a password or username change for
    * an existing login, when the form being submitted contains multiple
    * password fields.
    *
    * @param {nsILoginInfo} aOldLogin
    *                       The old login we may want to update.
    * @param {nsILoginInfo} aNewLogin
    *                       The new login from the page form.
+   * @param dismissed
+   *        A boolean indicating if the prompt should be automatically
+   *        dismissed on being shown.
    */
-  promptToChangePassword(aOldLogin, aNewLogin) {
+  promptToChangePassword(aOldLogin, aNewLogin, dismissed) {
     this.log("promptToChangePassword");
     let notifyObj = this._getPopupNote();
 
     if (notifyObj) {
       this._showChangeLoginNotification(notifyObj, aOldLogin,
-                                        aNewLogin);
+                                        aNewLogin, dismissed);
     } else {
       this._showChangeLoginDialog(aOldLogin, aNewLogin);
     }
   },
 
   /**
    * Shows the Change Password popup notification.
    *
    * @param aNotifyObj
    *        A popup notification.
    *
    * @param aOldLogin
    *        The stored login we want to update.
    *
    * @param aNewLogin
    *        The login object with the changes we want to make.
+   * @param dismissed
+   *        A boolean indicating if the prompt should be automatically
+   *        dismissed on being shown.
    */
-  _showChangeLoginNotification(aNotifyObj, aOldLogin, aNewLogin) {
+  _showChangeLoginNotification(aNotifyObj, aOldLogin, aNewLogin, dismissed = false) {
     aOldLogin.hostname = aNewLogin.hostname;
     aOldLogin.formSubmitURL = aNewLogin.formSubmitURL;
     aOldLogin.password = aNewLogin.password;
     aOldLogin.username = aNewLogin.username;
-    this._showLoginCaptureDoorhanger(aOldLogin, "password-change");
+    this._showLoginCaptureDoorhanger(aOldLogin, "password-change", {dismissed});
 
     let oldGUID = aOldLogin.QueryInterface(Ci.nsILoginMetaInfo).guid;
     Services.obs.notifyObservers(aNewLogin, "passwordmgr-prompt-change", oldGUID);
   },
 
 
   /**
    * Shows the Change Password dialog.
--- a/toolkit/components/passwordmgr/nsILoginManagerPrompter.idl
+++ b/toolkit/components/passwordmgr/nsILoginManagerPrompter.idl
@@ -44,30 +44,37 @@ interface nsILoginManagerPrompter : nsIS
    */
   attribute Element openerBrowser;
 
   /**
    * Ask the user if they want to save a login (Yes, Never, Not Now)
    *
    * @param aLogin
    *        The login to be saved.
+   * @param dismissed
+   *        A boolean value indicating whether the save logins doorhanger should
+   *        be dismissed automatically when shown.
    */
-  void promptToSavePassword(in nsILoginInfo aLogin);
+  void promptToSavePassword(in nsILoginInfo aLogin, in boolean dismissed);
 
   /**
    * Ask the user if they want to change a login's password or username.
    * If the user consents, modifyLogin() will be called.
    *
    * @param aOldLogin
    *        The existing login (with the old password).
    * @param aNewLogin
    *        The new login.
+   * @param dismissed
+   *        A boolean value indicating whether the save logins doorhanger should
+   *        be dismissed automatically when shown.
    */
   void promptToChangePassword(in nsILoginInfo aOldLogin,
-                              in nsILoginInfo aNewLogin);
+                              in nsILoginInfo aNewLogin,
+                              in boolean dismissed);
 
   /**
    * Ask the user if they want to change the password for one of
    * multiple logins, when the caller can't determine exactly which
    * login should be changed. If the user consents, modifyLogin() will
    * be called.
    *
    * @param logins
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -44,16 +44,17 @@ support-files =
   subtst_notifications_11.html
   subtst_notifications_11_popup.html
 skip-if = os == "linux" # Bug 1312981, bug 1313136
 [browser_context_menu_autocomplete_interaction.js]
 skip-if = verify
 [browser_username_select_dialog.js]
 support-files =
   subtst_notifications_change_p.html
+[browser_doorhanger_dismissed_for_ccnumber.js]
 [browser_DOMFormHasPassword.js]
 [browser_DOMInputPasswordAdded.js]
 skip-if = (os == "linux") || (os == "mac") # Bug 1337606
 [browser_exceptions_dialog.js]
 [browser_focus_before_first_DOMContentLoaded.js]
 support-files =
   file_focus_before_DOMContentLoaded.sjs
 [browser_formless_submit_chrome.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_dismissed_for_ccnumber.js
@@ -0,0 +1,115 @@
+"use strict";
+
+const TEST_HOSTNAME = "https://example.com";
+const BASIC_FORM_PAGE_PATH = DIRECTORY_PATH + "form_basic.html";
+
+function getSubmitMessage() {
+  info("getSubmitMessage");
+  return new Promise((resolve, reject) => {
+    Services.mm.addMessageListener("PasswordManager:onFormSubmit", function onFormSubmit() {
+      Services.mm.removeMessageListener("PasswordManager:onFormSubmit", onFormSubmit);
+      resolve();
+    });
+  });
+}
+
+add_task(async function test_doorhanger_dismissal_un() {
+  let url = TEST_HOSTNAME + BASIC_FORM_PAGE_PATH;
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url,
+  }, async function test_un_value_as_ccnumber(browser) {
+    // If the username field has a credit card number and if
+    // the password field is a three digit numberic value,
+    // we automatically dismiss the save logins prompt on submission.
+
+    let processedPromise = getSubmitMessage();
+    ContentTask.spawn(browser, null, async () => {
+      content.document.getElementById("form-basic-username").setUserInput("4111111111111111");
+      content.document.getElementById("form-basic-password").setUserInput("123");
+
+      content.document.getElementById("form-basic-submit").click();
+    });
+    await processedPromise;
+
+    let notif = getCaptureDoorhanger("password-save");
+    ok(notif, "got notification popup");
+    ok(notif.dismissed, "notification popup was automatically dismissed");
+  });
+});
+
+add_task(async function test_doorhanger_dismissal_pw() {
+  let url = TEST_HOSTNAME + BASIC_FORM_PAGE_PATH;
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url,
+  }, async function test_pw_value_as_ccnumber(browser) {
+    // If the password field has a credit card number and if
+    // the password field is also tagged autocomplete="cc-number",
+    // we automatically dismiss the save logins prompt on submission.
+
+    let processedPromise = getSubmitMessage();
+    ContentTask.spawn(browser, null, async () => {
+      content.document.getElementById("form-basic-username").setUserInput("aaa");
+      content.document.getElementById("form-basic-password").setUserInput("4111111111111111");
+      content.document.getElementById("form-basic-password").setAttribute("autocomplete", "cc-number");
+
+      content.document.getElementById("form-basic-submit").click();
+    });
+    await processedPromise;
+
+    let notif = getCaptureDoorhanger("password-save");
+    ok(notif, "got notification popup");
+    ok(notif.dismissed, "notification popup was automatically dismissed");
+  });
+});
+
+add_task(async function test_doorhanger_shown_on_un_with_invalid_ccnumber() {
+  let url = TEST_HOSTNAME + BASIC_FORM_PAGE_PATH;
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url,
+  }, async function test_un_with_invalid_cc_number(browser) {
+    // If the username field has a CC number that is invalid,
+    // we show the doorhanger to save logins like we usually do.
+
+    let processedPromise = getSubmitMessage();
+    ContentTask.spawn(browser, null, async () => {
+      content.document.getElementById("form-basic-username").value = "1234123412341234";
+      content.document.getElementById("form-basic-password").value = "411";
+
+      content.document.getElementById("form-basic-submit").click();
+    });
+    await processedPromise;
+
+    let notif = getCaptureDoorhanger("password-save");
+    ok(notif, "got notification popup");
+    ok(!notif.dismissed, "notification popup was not automatically dismissed");
+  });
+});
+
+add_task(async function test_doorhanger_dismissal_on_change() {
+  let url = TEST_HOSTNAME + BASIC_FORM_PAGE_PATH;
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url,
+  }, async function test_change_in_pw(browser) {
+    let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
+                                                 Ci.nsILoginInfo, "init");
+    let login = new nsLoginInfo("https://example.org", "https://example.org", null,
+                                "4111111111111111", "111", "form-basic-username", "form-basic-password");
+    Services.logins.addLogin(login);
+
+    let processedPromise = getSubmitMessage();
+    ContentTask.spawn(browser, null, async () => {
+      content.document.getElementById("form-basic-password").setUserInput("111");
+      content.document.getElementById("form-basic-submit").click();
+    });
+    await processedPromise;
+
+    let notif = getCaptureDoorhanger("password-save");
+    ok(notif, "got notification popup");
+    ok(notif.dismissed, "notification popup was automatically dismissed");
+  });
+});
+
--- a/toolkit/components/passwordmgr/test/browser/browser_notifications_2.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_notifications_2.js
@@ -30,16 +30,17 @@ add_task(async function test_empty_passw
     await promiseShown;
 
     let notificationElement = PopupNotifications.panel.childNodes[0];
     let passwordTextbox = notificationElement.querySelector("#password-notification-password");
 
     // Synthesize input to empty the field
     passwordTextbox.focus();
     await EventUtils.synthesizeKey("KEY_ArrowRight");
+    await EventUtils.synthesizeKey("KEY_ArrowRight");
     await EventUtils.synthesizeKey("KEY_Backspace");
     await EventUtils.synthesizeKey("KEY_Backspace");
 
     let mainActionButton = notificationElement.button;
     Assert.ok(mainActionButton.disabled, "Main action button is disabled");
   });
 });
 
--- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
+++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
@@ -22,16 +22,19 @@ support-files =
   ../authenticate.sjs
 skip-if = toolkit == 'android' && !is_fennec # Don't run on GeckoView
 
 # Note: new tests should use scheme = https unless they have a specific reason not to
 
 [test_autocomplete_highlight.html]
 scheme = https
 skip-if = toolkit == 'android' # autocomplete
+[test_autocomplete_highlight_non_login.html]
+scheme = https
+skip-if = toolkit == 'android' # autocomplete
 [test_autocomplete_https_upgrade.html]
 skip-if = toolkit == 'android' # autocomplete
 [test_autocomplete_password_open.html]
 scheme = https
 skip-if = toolkit == 'android' # autocomplete
 [test_autocomplete_sandboxed.html]
 scheme = https
 skip-if = toolkit == 'android' # autocomplete
--- a/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight.html
@@ -100,13 +100,16 @@ add_task(async function test_field_highl
   // Clear existing highlight on the password field. We check by pressing the tab key after backspace
   // (by shifting focus to the next element) because the tab key was known to cause a bug where the
   // highlight is applied once again. See Bug 1526522.
   synthesizeKey("KEY_Backspace");
   synthesizeKey("KEY_Tab");
 
   is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none",
      "Highlight was successfully removed on the password field");
+
+  // Clear login fields.
+  username.value = "";
+  password.value = "";
 });
 </script>
 </body>
 </html>
-
copy from toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight.html
copy to toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight_non_login.html
--- a/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_autocomplete_highlight_non_login.html
@@ -5,108 +5,117 @@
   <title>Test form field autofill highlight</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="/tests/SimpleTest/EventUtils.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>
+SimpleTest.requestFlakyTimeout("Giving a chance for the unexpected field highlight to occur");
 let readyPromise = registerRunTests();
 
 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,
+  login1.init("http://example.com", "http://autocomplete", null,
               "user1", "pass1", "", "");
 
   let login2 = Cc["@mozilla.org/login-manager/loginInfo;1"]
                         .createInstance(Ci.nsILoginInfo);
-  login2.init("https://example.com", "https://autocomplete", null,
+  login2.init("http://example.com", "http://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;">
+  <form id="form1" action="http://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", {});
+let username = document.getElementById("uname");
+let password = document.getElementById("pword");
 
 add_task(async function setup() {
   ok(readyPromise, "check promise is available");
   await readyPromise;
+
+  await SpecialPowers.pushPrefEnv({"set": [["security.insecure_field_warning.contextual.enabled", true]]});
+});
+
+add_task(async function test_field_highlight_on_pw_field_autocomplete_insecureWarning() {
+  // Press enter on insecure warning and check.
+  password.focus();
+  let shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown"); // open popup
+  await shownPromise;
+  synthesizeKey("KEY_ArrowDown"); // insecure warning
+  synthesizeKey("KEY_Enter");
+
+  await new Promise(resolve => setTimeout(resolve, 1000));
+  is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none",
+     "Highlight is not applied to the password field if enter key is pressed on the insecure warning item");
+  is(document.defaultView.getComputedStyle(username).getPropertyValue("filter"), "none",
+     "Highlight is not applied to the username field if enter key is pressed on the insecure warning item");
+
+  // Press tab on insecure warning and check.
+  password.focus();
+  shownPromise = promiseACShown();
+  synthesizeKey("KEY_ArrowDown"); // open popup
+  await shownPromise;
+  synthesizeKey("KEY_ArrowDown"); // insecure warning
+  synthesizeKey("KEY_Tab");
+
+  await new Promise(resolve => setTimeout(resolve, 1000));
+  is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none",
+     "Highlight is not applied to the password field if tab key is pressed on the insecure warning item");
+  is(document.defaultView.getComputedStyle(username).getPropertyValue("filter"), "none",
+     "Highlight is not applied to the username field if tab key is pressed on the insecure warning item");
 });
 
-add_task(async function test_field_highlight_on_autocomplete() {
-  // Test username autocomplete.
-  let username = document.getElementById("uname");
-  let password = document.getElementById("pword");
-
-  username.focus();
-
+add_task(async function test_field_highlight_on_pw_field_autocomplete_footer() {
+  // Press enter on the footer and check.
+  password.focus();
   let shownPromise = promiseACShown();
-  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_ArrowDown"); // open popup
   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");
+  synthesizeKey("KEY_ArrowUp"); // footer
+  synthesizeKey("KEY_Enter");
 
-  // 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 was known to cause a bug where the
-  // highlight is applied once again. See Bug 1526522.
-  username.focus();
-  synthesizeKey("KEY_Backspace");
-  synthesizeKey("KEY_Tab");
+  await new Promise(resolve => setTimeout(resolve, 1000));
+  is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none",
+     "Highlight is not applied to the password field if enter key is pressed on the footer item");
   is(document.defaultView.getComputedStyle(username).getPropertyValue("filter"), "none",
-     "Highlight was successfully removed on the username field");
+     "Highlight is not applied to the username field if enter key is pressed on the footer item");
 
-  synthesizeKey("KEY_Backspace");
-  synthesizeKey("KEY_Tab");
-  is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none",
-     "Highlight was successfully removed on the password field");
+  runInParent(function cleanUpWindow() {
+    const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+    let window = Services.wm.getMostRecentWindow("Toolkit:PasswordManager");
+    window.close();
+  });
 
-  // Clear login fields.
-  username.value = "";
-  password.value = "";
-
-  // Test password field autocomplete.
+  // Press tab on the footer and check.
   password.focus();
   shownPromise = promiseACShown();
-  synthesizeKey("KEY_ArrowDown");
+  synthesizeKey("KEY_ArrowDown"); // open popup
   await shownPromise;
-  synthesizeKey("KEY_ArrowDown");
-  synthesizeKey("KEY_Enter");
-
-  await ContentTaskUtils.waitForCondition(() => {
-    return document.defaultView.getComputedStyle(password).getPropertyValue("filter") !== "none";
-  }, "Highlight was successfully applied to the password field on password autocomplete");
-
-  // Clear existing highlight on the password field. We check by pressing the tab key after backspace
-  // (by shifting focus to the next element) because the tab key was known to cause a bug where the
-  // highlight is applied once again. See Bug 1526522.
-  synthesizeKey("KEY_Backspace");
+  synthesizeKey("KEY_ArrowUp"); // footer
   synthesizeKey("KEY_Tab");
 
+  await new Promise(resolve => setTimeout(resolve, 1000));
   is(document.defaultView.getComputedStyle(password).getPropertyValue("filter"), "none",
-     "Highlight was successfully removed on the password field");
+     "Highlight is not applied to the password field if tab key is pressed on the footer item");
+  is(document.defaultView.getComputedStyle(username).getPropertyValue("filter"), "none",
+     "Highlight is not applied to the username field if tab key is pressed on the insecure warning item");
 });
 </script>
 </body>
 </html>
-