| Index: chrome/browser/password_manager/password_store_mac.cc
|
| diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
|
| index 96518ffb46c3524bb441264a80799338b5a8df07..45875a1d33c84659561ab9a28aa71d1ea74fc689 100644
|
| --- a/chrome/browser/password_manager/password_store_mac.cc
|
| +++ b/chrome/browser/password_manager/password_store_mac.cc
|
| @@ -195,6 +195,46 @@ void AppendSecondToFirst(ScopedVector<autofill::PasswordForm>* first,
|
| second->weak_clear();
|
| }
|
|
|
| +// Returns the best match for |base_form| from |keychain_forms|, or nullptr if
|
| +// there is no suitable match.
|
| +const PasswordForm* BestKeychainFormForForm(
|
| + const PasswordForm& base_form,
|
| + const std::vector<PasswordForm*>& keychain_forms) {
|
| + const PasswordForm* partial_match = nullptr;
|
| + for (const auto* keychain_form : keychain_forms) {
|
| + // TODO(stuartmorgan): We should really be scoring path matches and picking
|
| + // the best, rather than just checking exact-or-not (although in practice
|
| + // keychain items with paths probably came from us).
|
| + if (internal_keychain_helpers::FormsMatchForMerge(
|
| + base_form, *keychain_form,
|
| + internal_keychain_helpers::FUZZY_FORM_MATCH)) {
|
| + if (base_form.origin == keychain_form->origin) {
|
| + return keychain_form;
|
| + } else if (!partial_match) {
|
| + partial_match = keychain_form;
|
| + }
|
| + }
|
| + }
|
| + return partial_match;
|
| +}
|
| +
|
| +// Iterates over all elements in |forms|, passes the pointed to objects to
|
| +// |move_form|, and clears |forms| efficiently. FormMover needs to be a callable
|
| +// entity, accepting scoped_ptr<autofill::PasswordForm> as its sole argument.
|
| +template <typename FormMover>
|
| +inline void MoveAllFormsOut(ScopedVector<autofill::PasswordForm>* forms,
|
| + FormMover mover) {
|
| + for (autofill::PasswordForm* form_ptr : *forms) {
|
| + mover(scoped_ptr<autofill::PasswordForm>(form_ptr));
|
| + }
|
| + // We moved the ownership of every form out of |forms|. For performance
|
| + // reasons, we can just weak_clear it, instead of nullptr-ing the respective
|
| + // elements and letting the vector's destructor to go through the list once
|
| + // more. This was tested on a benchmark, and seemed to make a difference on
|
| + // Mac.
|
| + forms->weak_clear();
|
| +}
|
| +
|
| } // namespace
|
|
|
| #pragma mark -
|
| @@ -402,40 +442,20 @@ bool FormsMatchForMerge(const PasswordForm& form_a,
|
| form_a.username_value == form_b.username_value;
|
| }
|
|
|
| -// Returns an the best match for |base_form| from |keychain_forms|, or NULL if
|
| -// there is no suitable match.
|
| -PasswordForm* BestKeychainFormForForm(
|
| - const PasswordForm& base_form,
|
| - const std::vector<PasswordForm*>* keychain_forms) {
|
| - PasswordForm* partial_match = NULL;
|
| - for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin();
|
| - i != keychain_forms->end(); ++i) {
|
| - // TODO(stuartmorgan): We should really be scoring path matches and picking
|
| - // the best, rather than just checking exact-or-not (although in practice
|
| - // keychain items with paths probably came from us).
|
| - if (FormsMatchForMerge(base_form, *(*i), FUZZY_FORM_MATCH)) {
|
| - if (base_form.origin == (*i)->origin) {
|
| - return *i;
|
| - } else if (!partial_match) {
|
| - partial_match = *i;
|
| - }
|
| - }
|
| - }
|
| - return partial_match;
|
| -}
|
| -
|
| // Moves entries from |forms| that are blacklist entries into |blacklist|.
|
| void ExtractBlacklistForms(ScopedVector<autofill::PasswordForm>* forms,
|
| ScopedVector<autofill::PasswordForm>* blacklist) {
|
| blacklist->reserve(blacklist->size() + forms->size());
|
| ScopedVector<autofill::PasswordForm> non_blacklist;
|
| - for (auto& form : *forms) {
|
| + // Move forms in either |non_blacklist| or |blacklist|, depending on whether
|
| + // they are blacklisted by the user.
|
| + MoveAllFormsOut(forms, [&non_blacklist, blacklist](
|
| + scoped_ptr<autofill::PasswordForm> form) {
|
| if (form->blacklisted_by_user)
|
| - blacklist->push_back(form);
|
| + blacklist->push_back(form.release());
|
| else
|
| - non_blacklist.push_back(form);
|
| - form = nullptr;
|
| - }
|
| + non_blacklist.push_back(form.release());
|
| + });
|
| forms->swap(non_blacklist);
|
| }
|
|
|
| @@ -455,19 +475,24 @@ void MergePasswordForms(ScopedVector<autofill::PasswordForm>* keychain_forms,
|
| // Merge the normal entries.
|
| ScopedVector<autofill::PasswordForm> unused_database_forms;
|
| unused_database_forms.reserve(database_forms->size());
|
| - std::set<autofill::PasswordForm*> used_keychain_forms;
|
| - for (auto& db_form : *database_forms) {
|
| - PasswordForm* best_match =
|
| - BestKeychainFormForForm(*db_form, &keychain_forms->get());
|
| + std::set<const autofill::PasswordForm*> used_keychain_forms;
|
| + // Move all database forms to either |merged_forms| or
|
| + // |unused_database_forms|, based on whether they have a match in the keychain
|
| + // forms or not. If there is a match, add its password to the DB form and
|
| + // mark the keychain form as used.
|
| + MoveAllFormsOut(database_forms, [keychain_forms, &used_keychain_forms,
|
| + merged_forms, &unused_database_forms](
|
| + scoped_ptr<autofill::PasswordForm> form) {
|
| + const PasswordForm* best_match =
|
| + BestKeychainFormForForm(*form, keychain_forms->get());
|
| if (best_match) {
|
| used_keychain_forms.insert(best_match);
|
| - db_form->password_value = best_match->password_value;
|
| - merged_forms->push_back(db_form);
|
| + form->password_value = best_match->password_value;
|
| + merged_forms->push_back(form.release());
|
| } else {
|
| - unused_database_forms.push_back(db_form);
|
| + unused_database_forms.push_back(form.release());
|
| }
|
| - db_form = nullptr;
|
| - }
|
| + });
|
| database_forms->swap(unused_database_forms);
|
|
|
| // Clear out all the Keychain entries we used.
|
| @@ -522,18 +547,19 @@ void GetPasswordsForForms(const AppleKeychain& keychain,
|
| // matching PasswordForm using its corresponding SecKeychainItemRef.
|
| ScopedVector<autofill::PasswordForm> unused_db_forms;
|
| unused_db_forms.reserve(database_forms->size());
|
| - for (auto& db_form : *database_forms) {
|
| + // Move database forms with a password stored in |keychain| to |passwords|,
|
| + // including the password. The rest is moved to |unused_db_forms|.
|
| + MoveAllFormsOut(database_forms,
|
| + [&keychain, &item_form_pairs, passwords, &unused_db_forms](
|
| + scoped_ptr<autofill::PasswordForm> form) {
|
| ScopedVector<autofill::PasswordForm> keychain_matches =
|
| - ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *db_form);
|
| + ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *form);
|
|
|
| ScopedVector<autofill::PasswordForm> db_form_container;
|
| - db_form_container.push_back(db_form);
|
| - db_form = nullptr;
|
| + db_form_container.push_back(form.release());
|
| MergePasswordForms(&keychain_matches, &db_form_container, passwords);
|
| - unused_db_forms.insert(unused_db_forms.end(), db_form_container.begin(),
|
| - db_form_container.end());
|
| - db_form_container.weak_clear();
|
| - }
|
| + AppendSecondToFirst(&unused_db_forms, &db_form_container);
|
| + });
|
| database_forms->swap(unused_db_forms);
|
|
|
| STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
|
| @@ -582,8 +608,7 @@ bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form,
|
| &is_secure, &security_domain)) {
|
| return false;
|
| }
|
| - return internal_keychain_helpers::FormsMatchForMerge(
|
| - query_form, other_form, STRICT_FORM_MATCH);
|
| + return FormsMatchForMerge(query_form, other_form, STRICT_FORM_MATCH);
|
| }
|
|
|
| ScopedVector<autofill::PasswordForm> ExtractPasswordsMergeableWithForm(
|
| @@ -597,7 +622,7 @@ ScopedVector<autofill::PasswordForm> ExtractPasswordsMergeableWithForm(
|
| // Create a new object, since the caller is responsible for deleting the
|
| // returned forms.
|
| scoped_ptr<PasswordForm> form_with_password(new PasswordForm());
|
| - internal_keychain_helpers::FillPasswordFormFromKeychainItem(
|
| + FillPasswordFormFromKeychainItem(
|
| keychain, *(i->first), form_with_password.get(),
|
| true); // Load password attributes and data.
|
| // Do not include blacklisted items found in the keychain.
|
| @@ -1052,10 +1077,7 @@ void PasswordStoreMac::GetLoginsImpl(
|
| ScopedVector<PasswordForm> keychain_blacklist_forms;
|
| internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms,
|
| &keychain_blacklist_forms);
|
| - matched_forms.insert(matched_forms.end(),
|
| - keychain_forms.begin(),
|
| - keychain_forms.end());
|
| - keychain_forms.weak_clear();
|
| + AppendSecondToFirst(&matched_forms, &keychain_forms);
|
|
|
| if (!database_forms.empty()) {
|
| RemoveDatabaseForms(database_forms.get());
|
| @@ -1169,7 +1191,5 @@ void PasswordStoreMac::CleanOrphanedForms(
|
| RemoveDatabaseForms(database_forms.get());
|
|
|
| // Move the orphaned DB forms to the output parameter.
|
| - orphaned_forms->insert(orphaned_forms->end(), database_forms.begin(),
|
| - database_forms.end());
|
| - database_forms.weak_clear();
|
| + AppendSecondToFirst(orphaned_forms, &database_forms);
|
| }
|
|
|