Commit 774332ae authored by Vasilii Sukhanov's avatar Vasilii Sukhanov Committed by Commit Bot

Create a separate structure that tracks the current generation status for a

field in PasswordGenerationAgent.

Currently |generation_element_| has a double meaning. It's an element that
should trigger the automatic generation. However, if a manual generation is
triggered then it's overwritten by a password field. That's confusing.
The CL decouples the field that should trigger the automatic generation from
whatever is happening right now on a random password field.
In the future that will allow us to have multiple generation elements
simultaneously. For now it fixes 870220 where the manual generation on the
ambiguous field was suppressing the automatic generation on it.

Bug: 870220,852309
Change-Id: I6a3edd351e615289f6271fda5a45f6ff47e653af
Reviewed-on: https://chromium-review.googlesource.com/c/1310713Reviewed-by: default avatarVadym Doroshenko <dvadym@chromium.org>
Commit-Queue: Vasilii Sukhanov <vasilii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#605668}
parent e22b4b7d
......@@ -254,23 +254,28 @@ IN_PROC_BROWSER_TEST_F(PasswordGenerationInteractiveTest,
PopupShownManuallyAndPasswordErased) {
NavigateToFile("/password/password_form.html");
FocusPasswordField();
// Focus the field that is not the first password field. The first one is
// considered "automatic" generation field.
ASSERT_TRUE(content::ExecuteScript(
WebContents(), "document.getElementById('password_redirect').focus()"));
// The same flow happens when user generates a password from the context menu.
password_manager_util::UserTriggeredManualGenerationFromContextMenu(
ChromePasswordManagerClient::FromWebContents(WebContents()));
WaitForPopupStatusChange();
EXPECT_TRUE(GenerationPopupShowing());
SendKeyToPopup(ui::VKEY_DOWN);
SendKeyToPopup(ui::VKEY_RETURN);
// Wait until the password is filled.
WaitForNonEmptyFieldValue("password_field");
WaitForNonEmptyFieldValue("password_redirect");
// Re-focusing the password field should show the editing popup.
FocusPasswordField();
ASSERT_TRUE(content::ExecuteScript(
WebContents(), "document.getElementById('password_redirect').focus()"));
EXPECT_TRUE(EditingPopupShowing());
// Delete the password. The generation prompt should not be visible.
SimulateUserDeletingFieldContent("password_field");
SimulateUserDeletingFieldContent("password_redirect");
WaitForPopupStatusChange();
EXPECT_FALSE(EditingPopupShowing());
EXPECT_FALSE(GenerationPopupShowing());
......
......@@ -789,6 +789,23 @@ TEST_F(PasswordGenerationAgentTest, ManualGenerationNoFormTest) {
ExpectManualGenerationAvailable("second_password", false);
}
TEST_F(PasswordGenerationAgentTest, ManualGenerationDoesntSuppressAutomatic) {
LoadHTMLWithUserGesture(kAccountCreationFormHTML);
SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
SetAccountCreationFormsDetectedMessage(password_generation_,
GetMainFrame()->GetDocument(), 0, 1);
ExpectAutomaticGenerationAvailable("first_password", true);
// The browser may show a standard password dropdown with the "Generate"
// option. In this case manual generation is triggered.
password_generation_->UserTriggeredGeneratePassword();
// Move the focus away to somewhere.
FocusField("address");
// Moving the focus back should trigger the automatic generation again.
ExpectAutomaticGenerationAvailable("first_password", true);
}
TEST_F(PasswordGenerationAgentTest, PresavingGeneratedPassword) {
const struct {
const char* form;
......
......@@ -170,26 +170,81 @@ void CopyElementValueToOtherInputElements(
} // namespace
PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData(
linked_ptr<PasswordForm> password_form,
std::vector<WebInputElement> passwords)
: form(password_form), password_elements(std::move(passwords)) {}
PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData(
const AccountCreationFormData& other) = default;
PasswordGenerationAgent::AccountCreationFormData::~AccountCreationFormData() {}
// Contains information about a form for which generation is possible.
struct PasswordGenerationAgent::AccountCreationFormData {
PasswordForm form;
std::vector<blink::WebInputElement> password_elements;
AccountCreationFormData(PasswordForm password_form,
std::vector<blink::WebInputElement> passwords)
: form(std::move(password_form)),
password_elements(std::move(passwords)) {}
AccountCreationFormData(AccountCreationFormData&& rhs) = default;
~AccountCreationFormData() = default;
DISALLOW_COPY_AND_ASSIGN(AccountCreationFormData);
};
// Contains information about generation status for an element for the
// lifetime of the possible interaction.
struct PasswordGenerationAgent::GenerationItemInfo {
GenerationItemInfo(const AccountCreationFormData& creation_form_data,
const blink::WebInputElement& generation_element)
: generation_element_(generation_element) {
form_ = creation_form_data.form;
password_elements_ = creation_form_data.password_elements;
}
GenerationItemInfo(blink::WebInputElement generation_element,
PasswordForm form,
std::vector<blink::WebInputElement> password_elements)
: generation_element_(std::move(generation_element)),
form_(std::move(form)),
password_elements_(std::move(password_elements)) {}
~GenerationItemInfo() = default;
// Element where we want to trigger password generation UI.
blink::WebInputElement generation_element_;
// Password form for the generation element.
PasswordForm form_;
// All the password elements in the form.
std::vector<blink::WebInputElement> password_elements_;
// If the password field at |generation_element_| contains a generated
// password.
bool password_is_generated_ = false;
// True if the last password generation was manually triggered.
bool is_manually_triggered_ = false;
// True if a password was generated and the user edited it. Used for UMA
// stats.
bool password_edited_ = false;
// True if the generation popup was shown during this navigation. Used to
// track UMA stats per page visit rather than per display, since the former
// is more interesting.
// TODO(crbug.com/845458): Remove this or change the description of the
// logged event as calling AutomaticgenerationStatusChanged will no longer
// imply that a popup is shown. This could instead be logged with the
// metrics collected on the browser process.
bool generation_popup_shown_ = false;
// True if the editing popup was shown during this navigation. Used to track
// UMA stats per page rather than per display, since the former is more
// interesting.
bool editing_popup_shown_ = false;
DISALLOW_COPY_AND_ASSIGN(GenerationItemInfo);
};
PasswordGenerationAgent::PasswordGenerationAgent(
content::RenderFrame* render_frame,
PasswordAutofillAgent* password_agent,
blink::AssociatedInterfaceRegistry* registry)
: content::RenderFrameObserver(render_frame),
password_is_generated_(false),
is_manually_triggered_(false),
password_edited_(false),
generation_popup_shown_(false),
editing_popup_shown_(false),
enabled_(password_generation::IsPasswordGenerationEnabled()),
mark_generation_element_(
base::CommandLine::ForCurrentProcess()->HasSwitch(
......@@ -201,7 +256,8 @@ PasswordGenerationAgent::PasswordGenerationAgent(
&PasswordGenerationAgent::BindRequest, base::Unretained(this)));
password_agent_->SetPasswordGenerationAgent(this);
}
PasswordGenerationAgent::~PasswordGenerationAgent() {}
PasswordGenerationAgent::~PasswordGenerationAgent() = default;
void PasswordGenerationAgent::BindRequest(
mojom::PasswordGenerationAgentAssociatedRequest request) {
......@@ -213,58 +269,42 @@ void PasswordGenerationAgent::DidCommitProvisionalLoad(
ui::PageTransition transition) {
if (is_same_document_navigation)
return;
password_is_generated_ = false;
generation_element_.Reset();
last_focused_password_element_.Reset();
}
void PasswordGenerationAgent::DidFinishDocumentLoad() {
// Update stats for main frame navigation.
if (!render_frame()->GetWebFrame()->Parent()) {
// Log statistics after navigation so that we only log once per page.
if (enabled_ || generation_form_data_) {
if (generation_form_data_ &&
!generation_form_data_->password_elements.empty()) {
password_generation::LogPasswordGenerationEvent(
password_generation::SIGN_UP_DETECTED);
} else {
password_generation::LogPasswordGenerationEvent(
password_generation::NO_SIGN_UP_DETECTED);
}
if (password_edited_) {
if (automatic_generation_form_data_ &&
!automatic_generation_form_data_->password_elements.empty()) {
password_generation::LogPasswordGenerationEvent(
password_generation::SIGN_UP_DETECTED);
} else {
password_generation::LogPasswordGenerationEvent(
password_generation::NO_SIGN_UP_DETECTED);
}
if (current_generation_item_) {
if (current_generation_item_->password_edited_) {
password_generation::LogPasswordGenerationEvent(
password_generation::PASSWORD_EDITED);
}
if (generation_popup_shown_) {
if (current_generation_item_->generation_popup_shown_) {
password_generation::LogPasswordGenerationEvent(
password_generation::GENERATION_POPUP_SHOWN);
}
if (editing_popup_shown_) {
if (current_generation_item_->editing_popup_shown_) {
password_generation::LogPasswordGenerationEvent(
password_generation::EDITING_POPUP_SHOWN);
}
}
// In every navigation, the IPC message sent by the password autofill
// manager to query whether the current form is blacklisted or not happens
// when the document load finishes, so we need to clear previous states
// here before we hear back from the browser. We only clear this state on
// main frame load as we don't want subframe loads to clear state that we
// have received from the main frame. Note that we assume there is only one
// account creation form, but there could be multiple password forms in
// each frame.
not_blacklisted_password_form_origins_.clear();
generation_enabled_forms_.clear();
generation_element_.Reset();
possible_account_creation_forms_.clear();
generation_form_data_.reset();
password_is_generated_ = false;
password_edited_ = false;
generation_popup_shown_ = false;
editing_popup_shown_ = false;
is_manually_triggered_ = false;
}
possible_account_creation_forms_.clear();
not_blacklisted_password_form_origins_.clear();
generation_enabled_forms_.clear();
automatic_generation_form_data_.reset();
automatic_generation_element_.Reset();
current_generation_item_.reset();
last_focused_password_element_.Reset();
}
void PasswordGenerationAgent::DidFinishDocumentLoad() {
FindPossibleGenerationForm();
}
......@@ -286,11 +326,14 @@ void PasswordGenerationAgent::OnDynamicFormsSeen() {
void PasswordGenerationAgent::OnFieldAutofilled(
const WebInputElement& password_element) {
if (password_is_generated_ && generation_element_ == password_element) {
if (current_generation_item_ &&
current_generation_item_->password_is_generated_ &&
current_generation_item_->generation_element_ == password_element) {
password_generation::LogPasswordGenerationEvent(
password_generation::PASSWORD_DELETED_BY_AUTOFILLING);
PasswordNoLongerGenerated();
generation_element_.SetShouldRevealPassword(false);
current_generation_item_->generation_element_.SetShouldRevealPassword(
false);
}
}
......@@ -304,7 +347,7 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
return;
// If we have already found a signup form for this page, no need to continue.
if (generation_form_data_)
if (automatic_generation_form_data_)
return;
WebLocalFrame* web_frame = render_frame()->GetWebFrame();
......@@ -334,8 +377,8 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
web_frame->GetDocument().All(), nullptr)
: form_util::ExtractAutofillableElementsInForm(web_form),
&passwords)) {
possible_account_creation_forms_.emplace_back(
make_linked_ptr(form.first.release()), std::move(passwords));
possible_account_creation_forms_.emplace_back(std::move(*form.first),
std::move(passwords));
}
}
......@@ -368,12 +411,13 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
// static cast is workaround for linker error.
DCHECK_LE(static_cast<size_t>(kMinimumLengthForEditedPassword),
password.size());
password_is_generated_ = true;
password_edited_ = false;
DCHECK(current_generation_item_);
current_generation_item_->password_is_generated_ = true;
current_generation_item_->password_edited_ = false;
password_generation::LogPasswordGenerationEvent(
password_generation::PASSWORD_ACCEPTED);
LogMessage(Logger::STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED);
for (auto& password_element : generation_form_data_->password_elements) {
for (auto& password_element : current_generation_item_->password_elements_) {
password_element.SetAutofillValue(blink::WebString::FromUTF16(password));
// setAutofillValue() above may have resulted in JavaScript closing the
// frame.
......@@ -390,7 +434,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
// Call UpdateStateForTextChange after the corresponding PasswordFormManager
// is notified that the password was generated.
for (auto& password_element : generation_form_data_->password_elements) {
for (auto& password_element : current_generation_item_->password_elements_) {
// Needed to notify password_autofill_agent that the content of the field
// has changed. Without this we will overwrite the generated
// password with an Autofilled password when saving.
......@@ -401,20 +445,22 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
std::unique_ptr<PasswordForm>
PasswordGenerationAgent::CreatePasswordFormToPresave() {
DCHECK(!generation_element_.IsNull());
DCHECK(current_generation_item_);
DCHECK(!current_generation_item_->generation_element_.IsNull());
// Since the form for presaving should match a form in the browser, create it
// with the same algorithm (to match html attributes, action, etc.), but
// change username and password values.
std::unique_ptr<PasswordForm> password_form;
if (!generation_element_.Form().IsNull()) {
password_form =
password_agent_->GetPasswordFormFromWebForm(generation_element_.Form());
if (!current_generation_item_->generation_element_.Form().IsNull()) {
password_form = password_agent_->GetPasswordFormFromWebForm(
current_generation_item_->generation_element_.Form());
} else {
password_form = password_agent_->GetPasswordFormFromUnownedInputElements();
}
if (password_form) {
password_form->type = PasswordForm::TYPE_GENERATED;
password_form->password_value = generation_element_.Value().Utf16();
password_form->password_value =
current_generation_item_->generation_element_.Value().Utf16();
}
return password_form;
......@@ -433,21 +479,23 @@ void PasswordGenerationAgent::UserTriggeredGeneratePassword() {
autofill::password_generation::PasswordGenerationUIData
password_generation_ui_data(
render_frame()->GetRenderView()->ElementBoundsInWindow(
generation_element_),
generation_element_.MaxLength(),
generation_element_.NameForAutofill().Utf16(),
GetTextDirectionForElement(generation_element_),
*generation_form_data_->form);
current_generation_item_->generation_element_),
current_generation_item_->generation_element_.MaxLength(),
current_generation_item_->generation_element_.NameForAutofill()
.Utf16(),
GetTextDirectionForElement(
current_generation_item_->generation_element_),
current_generation_item_->form_);
// TODO(crbug.com/845458): remove it. The renderer should never invoke the
// prompt directly.
GetPasswordManagerClient()->ShowManualPasswordGenerationPopup(
password_generation_ui_data);
generation_popup_shown_ = true;
current_generation_item_->generation_popup_shown_ = true;
}
}
void PasswordGenerationAgent::DetermineGenerationElement() {
if (generation_form_data_) {
if (automatic_generation_form_data_) {
LogMessage(Logger::STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND);
return;
}
......@@ -462,7 +510,7 @@ void PasswordGenerationAgent::DetermineGenerationElement() {
// Note that no messages will be sent if this feature is disabled
// (e.g. password saving is disabled).
for (auto& possible_form_data : possible_account_creation_forms_) {
PasswordForm* possible_password_form = possible_form_data.form.get();
PasswordForm* possible_password_form = &possible_form_data.form;
const PasswordFormGenerationData* generation_data = nullptr;
std::vector<WebInputElement> password_elements;
......@@ -502,17 +550,25 @@ void PasswordGenerationAgent::DetermineGenerationElement() {
return;
}
generation_form_data_.reset(new AccountCreationFormData(
automatic_generation_form_data_.reset(new AccountCreationFormData(
possible_form_data.form, std::move(password_elements)));
generation_element_ = generation_form_data_->password_elements[0];
automatic_generation_element_ =
automatic_generation_form_data_->password_elements[0];
if (mark_generation_element_)
generation_element_.SetAttribute("password_creation_field", "1");
generation_element_.SetAttribute("aria-autocomplete", "list");
automatic_generation_element_.SetAttribute("password_creation_field",
"1");
automatic_generation_element_.SetAttribute("aria-autocomplete", "list");
password_generation::LogPasswordGenerationEvent(
password_generation::GENERATION_AVAILABLE);
possible_account_creation_forms_.clear();
if (!current_generation_item_) {
// If the manual generation hasn't started, set
// |automatic_generation_element_| as the current generation field.
current_generation_item_.reset(new GenerationItemInfo(
*automatic_generation_form_data_, automatic_generation_element_));
}
GetPasswordManagerClient()->GenerationAvailableForForm(
*generation_form_data_->form);
automatic_generation_form_data_->form);
return;
}
}
......@@ -540,7 +596,6 @@ bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() {
if (!password_form)
return false;
generation_element_ = last_focused_password_element_;
std::vector<WebInputElement> password_elements;
GetAccountCreationPasswordFields(control_elements, &password_elements);
password_elements = FindPasswordElementsForGeneration(
......@@ -551,9 +606,12 @@ bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() {
last_focused_password_element_.NameForAutofill().Utf16(),
last_focused_password_element_.FormControlTypeForAutofill()
.Utf8())));
generation_form_data_.reset(new AccountCreationFormData(
make_linked_ptr(password_form.release()), password_elements));
is_manually_triggered_ = true;
current_generation_item_.reset(new GenerationItemInfo(
last_focused_password_element_, std::move(*password_form),
std::move(password_elements)));
// |automatic_generation_element_| should always generate the UI.
current_generation_item_->is_manually_triggered_ =
(last_focused_password_element_ != automatic_generation_element_);
return true;
}
......@@ -572,18 +630,22 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged(
const WebInputElement* element = ToWebInputElement(&web_element);
if (element && element->IsPasswordFieldForAutofill())
last_focused_password_element_ = *element;
if (!element || *element != generation_element_) {
if (!element || !current_generation_item_ ||
*element != current_generation_item_->generation_element_) {
return false;
}
if (password_is_generated_) {
if (generation_element_.Value().length() <
if (current_generation_item_->password_is_generated_) {
if (current_generation_item_->generation_element_.Value().length() <
kMinimumLengthForEditedPassword) {
PasswordNoLongerGenerated();
if (generation_element_.Value().IsEmpty())
generation_element_.SetShouldRevealPassword(false);
if (current_generation_item_->generation_element_.Value().IsEmpty())
current_generation_item_->generation_element_.SetShouldRevealPassword(
false);
} else {
generation_element_.SetShouldRevealPassword(true);
current_generation_item_->generation_element_.SetShouldRevealPassword(
true);
ShowEditingPopup();
}
return true;
......@@ -604,23 +666,23 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged(
void PasswordGenerationAgent::DidEndTextFieldEditing(
const blink::WebInputElement& element) {
if (!element.IsNull() && element == generation_element_) {
if (!element.IsNull() && current_generation_item_ &&
element == current_generation_item_->generation_element_) {
AutomaticGenerationStatusChanged(false);
generation_element_.SetShouldRevealPassword(false);
current_generation_item_->generation_element_.SetShouldRevealPassword(
false);
}
}
bool PasswordGenerationAgent::TextDidChangeInTextField(
const WebInputElement& element) {
if (element != generation_element_) {
if (!(current_generation_item_ &&
current_generation_item_->generation_element_ == element)) {
// Presave the username if it has been changed.
// TODO(crbug.com/879713): investigate why the following DCHECKs can be
// triggered.
DCHECK(!element.IsNull());
DCHECK(!password_is_generated_ || !generation_element_.IsNull());
if (password_is_generated_ && !element.IsNull() &&
!generation_element_.IsNull() &&
(element.Form() == generation_element_.Form())) {
if (current_generation_item_ &&
current_generation_item_->password_is_generated_ && !element.IsNull() &&
element.Form() ==
current_generation_item_->generation_element_.Form()) {
std::unique_ptr<PasswordForm> presaved_form(
CreatePasswordFormToPresave());
if (presaved_form)
......@@ -629,18 +691,21 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
return false;
}
if (element.Value().IsEmpty())
generation_element_.SetShouldRevealPassword(false);
if (element.Value().IsEmpty()) {
current_generation_item_->generation_element_.SetShouldRevealPassword(
false);
}
if (!password_is_generated_ &&
if (!current_generation_item_->password_is_generated_ &&
element.Value().length() > kMaximumCharsForGenerationOffer) {
// User has rejected the feature and has started typing a password.
GenerationRejectedByTyping();
} else {
const bool leave_editing_state =
password_is_generated_ &&
current_generation_item_->password_is_generated_ &&
element.Value().length() < kMinimumLengthForEditedPassword;
if (!password_is_generated_ || leave_editing_state) {
if (!current_generation_item_->password_is_generated_ ||
leave_editing_state) {
// The call may pop up a generation prompt, replacing the editing prompt
// if it was previously shown.
MaybeOfferAutomaticGeneration();
......@@ -649,11 +714,11 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
// Tell the browser that the state isn't "editing" anymore. The browser
// should hide the editing prompt if it wasn't replaced above.
PasswordNoLongerGenerated();
} else if (password_is_generated_) {
password_edited_ = true;
} else if (current_generation_item_->password_is_generated_) {
current_generation_item_->password_edited_ = true;
// Mirror edits to any confirmation password fields.
CopyElementValueToOtherInputElements(
&element, &generation_form_data_->password_elements);
&element, &current_generation_item_->password_elements_);
std::unique_ptr<PasswordForm> presaved_form(
CreatePasswordFormToPresave());
if (presaved_form) {
......@@ -666,26 +731,30 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
void PasswordGenerationAgent::MaybeOfferAutomaticGeneration() {
// TODO(crbug.com/852309): Add this check to the generation element class.
if (!is_manually_triggered_) {
if (!current_generation_item_->is_manually_triggered_) {
AutomaticGenerationStatusChanged(true /* available */);
}
}
void PasswordGenerationAgent::AutomaticGenerationStatusChanged(bool available) {
if (available) {
if (!render_frame() || generation_element_.IsNull())
if (!render_frame())
return;
DCHECK(current_generation_item_);
DCHECK(!current_generation_item_->generation_element_.IsNull());
LogMessage(
Logger::STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE);
autofill::password_generation::PasswordGenerationUIData
password_generation_ui_data(
render_frame()->GetRenderView()->ElementBoundsInWindow(
generation_element_),
generation_element_.MaxLength(),
generation_element_.NameForAutofill().Utf16(),
GetTextDirectionForElement(generation_element_),
*generation_form_data_->form);
generation_popup_shown_ = true;
current_generation_item_->generation_element_),
current_generation_item_->generation_element_.MaxLength(),
current_generation_item_->generation_element_.NameForAutofill()
.Utf16(),
GetTextDirectionForElement(
current_generation_item_->generation_element_),
current_generation_item_->form_);
current_generation_item_->generation_popup_shown_ = true;
GetPasswordManagerClient()->AutomaticGenerationStatusChanged(
true, password_generation_ui_data);
} else {
......@@ -700,9 +769,9 @@ void PasswordGenerationAgent::ShowEditingPopup() {
return;
GetPasswordManagerClient()->ShowPasswordEditingPopup(
render_frame()->GetRenderView()->ElementBoundsInWindow(
generation_element_),
current_generation_item_->generation_element_),
*CreatePasswordFormToPresave());
editing_popup_shown_ = true;
current_generation_item_->editing_popup_shown_ = true;
}
void PasswordGenerationAgent::GenerationRejectedByTyping() {
......@@ -710,17 +779,19 @@ void PasswordGenerationAgent::GenerationRejectedByTyping() {
}
void PasswordGenerationAgent::PasswordNoLongerGenerated() {
DCHECK(password_is_generated_);
DCHECK(current_generation_item_);
DCHECK(current_generation_item_->password_is_generated_);
// Do not treat the password as generated, either here or in the browser.
password_is_generated_ = false;
password_edited_ = false;
for (WebInputElement& password : generation_form_data_->password_elements)
current_generation_item_->password_is_generated_ = false;
current_generation_item_->password_edited_ = false;
for (WebInputElement& password : current_generation_item_->password_elements_)
password.SetAutofillState(WebAutofillState::kNotFilled);
password_generation::LogPasswordGenerationEvent(
password_generation::PASSWORD_DELETED);
// Clear all other password fields.
for (WebInputElement& element : generation_form_data_->password_elements) {
if (generation_element_ != element)
for (WebInputElement& element :
current_generation_item_->password_elements_) {
if (current_generation_item_->generation_element_ != element)
element.SetAutofillValue(blink::WebString());
}
std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
......
......@@ -13,7 +13,6 @@
#include <vector>
#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "components/autofill/content/common/autofill_agent.mojom.h"
#include "components/autofill/content/common/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
......@@ -95,16 +94,11 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
void set_enabled(bool enabled) { enabled_ = enabled; }
private:
struct AccountCreationFormData {
linked_ptr<PasswordForm> form;
std::vector<blink::WebInputElement> password_elements;
AccountCreationFormData(
linked_ptr<PasswordForm> form,
std::vector<blink::WebInputElement> password_elements);
AccountCreationFormData(const AccountCreationFormData& other);
~AccountCreationFormData();
};
// Contains information about a form for which generation is possible.
struct AccountCreationFormData;
// Contains information about generation status for an element for the
// lifetime of the possible interaction.
struct GenerationItemInfo;
typedef std::vector<AccountCreationFormData> AccountCreationFormDataList;
......@@ -123,9 +117,10 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
// |possible_account_creation_form_|.
void FindPossibleGenerationForm();
// Helper function to decide if |passwords_| contains password fields for
// an account creation form. Sets |generation_element_| to the field that
// we want to trigger the generation UI on.
// Helper function to decide if |possible_account_creation_forms_| contains
// password fields for an account creation form. Sets
// |automatic_generation_element_| to the field that we want to trigger the
// generation UI on.
void DetermineGenerationElement();
// Helper function which takes care of the form processing and collecting the
......@@ -186,48 +181,27 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
// forms will not be sent if the feature is disabled.
std::vector<autofill::PasswordFormGenerationData> generation_enabled_forms_;
// Data for form which generation is allowed on.
std::unique_ptr<AccountCreationFormData> generation_form_data_;
// Data for form which automatic generation is allowed on.
std::unique_ptr<AccountCreationFormData> automatic_generation_form_data_;
// Element where we want to trigger automatic password generation UI on.
blink::WebInputElement automatic_generation_element_;
// Element where we want to trigger password generation UI.
blink::WebInputElement generation_element_;
// Contains the current element where generation is offered at the moment. It
// can be either automatic or manual password generation.
std::unique_ptr<GenerationItemInfo> current_generation_item_;
// Password element that had focus last. Since Javascript could change focused
// element after the user triggered a generation request, it is better to save
// the last focused password element.
blink::WebInputElement last_focused_password_element_;
// If the password field at |generation_element_| contains a generated
// password.
bool password_is_generated_;
// True if the last password generation was manually triggered.
bool is_manually_triggered_;
// True if a password was generated and the user edited it. Used for UMA
// stats.
bool password_edited_;
// True if the generation popup was shown during this navigation. Used to
// track UMA stats per page visit rather than per display, since the former
// is more interesting.
// TODO(crbug.com/845458): Remove this or change the description of the
// logged event as calling AutomaticgenerationStatusChanged will no longer
// imply that a popup is shown. This could instead be logged with the
// metrics collected on the browser process.
bool generation_popup_shown_;
// True if the editing popup was shown during this navigation. Used to track
// UMA stats per page rather than per display, since the former is more
// interesting.
bool editing_popup_shown_;
// If this feature is enabled. Controlled by Finch.
bool enabled_;
// True iff the generation element should be marked with special HTML
// attribute (only for experimental purposes).
bool mark_generation_element_;
const bool mark_generation_element_;
// Unowned pointer. Used to notify PassowrdAutofillAgent when values
// in password fields are updated.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment