| Index: chrome/browser/autofill/autofill_manager.cc
|
| diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
|
| index 9b8ec0b5083b65f35e46be78e697e7faa477e709..e5754a70045626fddc7ecdceadeef96aa03b16ea 100644
|
| --- a/chrome/browser/autofill/autofill_manager.cc
|
| +++ b/chrome/browser/autofill/autofill_manager.cc
|
| @@ -11,6 +11,7 @@
|
| #include <set>
|
| #include <utility>
|
|
|
| +#include "base/bind.h"
|
| #include "base/command_line.h"
|
| #include "base/logging.h"
|
| #include "base/string16.h"
|
| @@ -44,6 +45,7 @@
|
| #include "chrome/common/pref_names.h"
|
| #include "chrome/common/url_constants.h"
|
| #include "content/browser/renderer_host/render_view_host.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| #include "content/public/browser/notification_service.h"
|
| #include "content/public/browser/notification_source.h"
|
| #include "googleurl/src/gurl.h"
|
| @@ -127,6 +129,40 @@ bool FormIsHTTPS(const FormStructure& form) {
|
| return form.source_url().SchemeIs(chrome::kHttpsScheme);
|
| }
|
|
|
| +// Uses the existing personal data in |profiles| and |credit_cards| to determine
|
| +// possible field types for the |submitted_form|. This is potentially
|
| +// expensive -- on the order of 50ms even for a small set of |stored_data|.
|
| +// Hence, it should not run on the UI thread -- to avoid locking up the UI --
|
| +// nor on the IO thread -- to avoid blocking IPC calls.
|
| +void DeterminePossibleFieldTypesForUpload(
|
| + const std::vector<AutofillProfile>& profiles,
|
| + const std::vector<CreditCard>& credit_cards,
|
| + FormStructure* submitted_form) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| +
|
| + // For each field in the |submitted_form|, extract the value. Then for each
|
| + // profile or credit card, identify any stored types that match the value.
|
| + for (size_t i = 0; i < submitted_form->field_count(); ++i) {
|
| + AutofillField* field = submitted_form->field(i);
|
| + string16 value = CollapseWhitespace(field->value, false);
|
| +
|
| + FieldTypeSet matching_types;
|
| + for (std::vector<AutofillProfile>::const_iterator it = profiles.begin();
|
| + it != profiles.end(); ++it) {
|
| + it->GetMatchingTypes(value, &matching_types);
|
| + }
|
| + for (std::vector<CreditCard>::const_iterator it = credit_cards.begin();
|
| + it != credit_cards.end(); ++it) {
|
| + it->GetMatchingTypes(value, &matching_types);
|
| + }
|
| +
|
| + if (matching_types.empty())
|
| + matching_types.insert(UNKNOWN_TYPE);
|
| +
|
| + field->set_possible_types(matching_types);
|
| + }
|
| +}
|
| +
|
| // Check for unidentified forms among those with the most query or upload
|
| // requests. If found, present an infobar prompting the user to send Google
|
| // Feedback identifying these forms. Only executes if the appropriate flag is
|
| @@ -219,8 +255,6 @@ AutofillManager::AutofillManager(TabContentsWrapper* tab_contents)
|
| user_did_autofill_(false),
|
| user_did_edit_autofilled_field_(false),
|
| external_delegate_(NULL) {
|
| - DCHECK(tab_contents);
|
| -
|
| // |personal_data_| is NULL when using TestTabContents.
|
| personal_data_ = PersonalDataManagerFactory::GetForProfile(
|
| tab_contents->profile()->GetOriginalProfile());
|
| @@ -282,53 +316,81 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) {
|
| return handled;
|
| }
|
|
|
| -void AutofillManager::OnFormSubmitted(const FormData& form,
|
| +bool AutofillManager::OnFormSubmitted(const FormData& form,
|
| const TimeTicks& timestamp) {
|
| // Let AutoComplete know as well.
|
| tab_contents_wrapper_->autocomplete_history_manager()->OnFormSubmitted(form);
|
|
|
| if (!IsAutofillEnabled())
|
| - return;
|
| + return false;
|
|
|
| if (tab_contents()->browser_context()->IsOffTheRecord())
|
| - return;
|
| + return false;
|
|
|
| // Don't save data that was submitted through JavaScript.
|
| if (!form.user_submitted)
|
| - return;
|
| + return false;
|
|
|
| // Grab a copy of the form data.
|
| - FormStructure submitted_form(form);
|
| + scoped_ptr<FormStructure> submitted_form(new FormStructure(form));
|
|
|
| // Disregard forms that we wouldn't ever autofill in the first place.
|
| - if (!submitted_form.ShouldBeParsed(true))
|
| - return;
|
| + if (!submitted_form->ShouldBeParsed(true))
|
| + return false;
|
|
|
| // Ignore forms not present in our cache. These are typically forms with
|
| // wonky JavaScript that also makes them not auto-fillable.
|
| FormStructure* cached_submitted_form;
|
| if (!FindCachedForm(form, &cached_submitted_form))
|
| - return;
|
| - submitted_form.UpdateFromCache(*cached_submitted_form);
|
| + return false;
|
| +
|
| + submitted_form->UpdateFromCache(*cached_submitted_form);
|
| + if (submitted_form->IsAutofillable(true))
|
| + ImportFormData(*submitted_form);
|
|
|
| // Only upload server statistics and UMA metrics if at least some local data
|
| // is available to use as a baseline.
|
| - if (!personal_data_->profiles().empty() ||
|
| - !personal_data_->credit_cards().empty()) {
|
| - DeterminePossibleFieldTypesForUpload(&submitted_form);
|
| - submitted_form.LogQualityMetrics(*metric_logger_,
|
| - forms_loaded_timestamp_,
|
| - initial_interaction_timestamp_,
|
| - timestamp);
|
| -
|
| - if (submitted_form.ShouldBeCrowdsourced())
|
| - UploadFormData(submitted_form);
|
| - }
|
| + const std::vector<AutofillProfile*>& profiles = personal_data_->profiles();
|
| + const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
|
| + if (!profiles.empty() || !credit_cards.empty()) {
|
| + // Copy the profile and credit card data, so that it can be accessed on a
|
| + // separate thread.
|
| + std::vector<AutofillProfile> copied_profiles;
|
| + copied_profiles.reserve(profiles.size());
|
| + for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin();
|
| + it != profiles.end(); ++it) {
|
| + copied_profiles.push_back(**it);
|
| + }
|
|
|
| - if (!submitted_form.IsAutofillable(true))
|
| - return;
|
| + std::vector<CreditCard> copied_credit_cards;
|
| + copied_credit_cards.reserve(credit_cards.size());
|
| + for (std::vector<CreditCard*>::const_iterator it = credit_cards.begin();
|
| + it != credit_cards.end(); ++it) {
|
| + copied_credit_cards.push_back(**it);
|
| + }
|
|
|
| - ImportFormData(submitted_form);
|
| + // TODO(isherman): Ideally, we should not be using the FILE thread here.
|
| + // Per jar@, this is a good compromise for now, as we don't currently have a
|
| + // broad consensus on how to support such one-off background tasks.
|
| +
|
| + // Note that ownership of |submitted_form| is passed to the second task,
|
| + // using |base::Owned|.
|
| + FormStructure* raw_submitted_form = submitted_form.get();
|
| + BrowserThread::PostTaskAndReply(
|
| + BrowserThread::FILE, FROM_HERE,
|
| + base::Bind(&DeterminePossibleFieldTypesForUpload,
|
| + copied_profiles,
|
| + copied_credit_cards,
|
| + raw_submitted_form),
|
| + base::Bind(&AutofillManager::UploadFormDataAsyncCallback,
|
| + this,
|
| + base::Owned(submitted_form.release()),
|
| + forms_loaded_timestamp_,
|
| + initial_interaction_timestamp_,
|
| + timestamp));
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
|
| @@ -627,35 +689,6 @@ bool AutofillManager::IsAutofillEnabled() const {
|
| return profile->GetPrefs()->GetBoolean(prefs::kAutofillEnabled);
|
| }
|
|
|
| -void AutofillManager::DeterminePossibleFieldTypesForUpload(
|
| - FormStructure* submitted_form) {
|
| - // Combine all the profiles and credit cards stored in |personal_data_| into
|
| - // one vector for ease of iteration.
|
| - const std::vector<AutofillProfile*>& profiles = personal_data_->profiles();
|
| - const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
|
| - std::vector<FormGroup*> stored_data;
|
| - stored_data.insert(stored_data.end(), profiles.begin(), profiles.end());
|
| - stored_data.insert(stored_data.end(), credit_cards.begin(),
|
| - credit_cards.end());
|
| -
|
| - // For each field in the |submitted_form|, extract the value. Then for each
|
| - // profile or credit card, identify any stored types that match the value.
|
| - for (size_t i = 0; i < submitted_form->field_count(); i++) {
|
| - AutofillField* field = submitted_form->field(i);
|
| - string16 value = CollapseWhitespace(field->value, false);
|
| - FieldTypeSet matching_types;
|
| - for (std::vector<FormGroup*>::const_iterator it = stored_data.begin();
|
| - it != stored_data.end(); ++it) {
|
| - (*it)->GetMatchingTypes(value, &matching_types);
|
| - }
|
| -
|
| - if (matching_types.empty())
|
| - matching_types.insert(UNKNOWN_TYPE);
|
| -
|
| - field->set_possible_types(matching_types);
|
| - }
|
| -}
|
| -
|
| void AutofillManager::SendAutofillTypePredictions(
|
| const std::vector<FormStructure*>& forms) const {
|
| if (!CommandLine::ForCurrentProcess()->HasSwitch(
|
| @@ -691,6 +724,24 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
|
| }
|
| }
|
|
|
| +// Note that |submitted_form| is passed as a pointer rather than as a reference
|
| +// so that we can get memory management right across threads. Note also that we
|
| +// explicitly pass in all the time stamps of interest, as the cached ones might
|
| +// get reset before this method executes.
|
| +void AutofillManager::UploadFormDataAsyncCallback(
|
| + const FormStructure* submitted_form,
|
| + const TimeTicks& load_time,
|
| + const TimeTicks& interaction_time,
|
| + const TimeTicks& submission_time) {
|
| + submitted_form->LogQualityMetrics(*metric_logger_,
|
| + load_time,
|
| + interaction_time,
|
| + submission_time);
|
| +
|
| + if (submitted_form->ShouldBeCrowdsourced())
|
| + UploadFormData(*submitted_form);
|
| +}
|
| +
|
| void AutofillManager::UploadFormData(const FormStructure& submitted_form) {
|
| if (disable_download_manager_requests_)
|
| return;
|
|
|