OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/autofill/autofill_manager.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <limits> | |
10 #include <map> | |
11 #include <set> | |
12 #include <utility> | |
13 | |
14 #include "base/bind.h" | |
15 #include "base/command_line.h" | |
16 #include "base/guid.h" | |
17 #include "base/logging.h" | |
18 #include "base/prefs/pref_service.h" | |
19 #include "base/string16.h" | |
20 #include "base/string_util.h" | |
21 #include "base/threading/sequenced_worker_pool.h" | |
22 #include "base/utf_string_conversions.h" | |
23 #include "chrome/browser/autofill/autocheckout/whitelist_manager.h" | |
24 #include "chrome/browser/autofill/autocheckout_manager.h" | |
25 #include "chrome/browser/autofill/autocomplete_history_manager.h" | |
26 #include "chrome/browser/autofill/autofill_country.h" | |
27 #include "chrome/browser/autofill/autofill_external_delegate.h" | |
28 #include "chrome/browser/autofill/autofill_field.h" | |
29 #include "chrome/browser/autofill/autofill_manager_delegate.h" | |
30 #include "chrome/browser/autofill/autofill_metrics.h" | |
31 #include "chrome/browser/autofill/autofill_profile.h" | |
32 #include "chrome/browser/autofill/autofill_type.h" | |
33 #include "chrome/browser/autofill/credit_card.h" | |
34 #include "chrome/browser/autofill/form_structure.h" | |
35 #include "chrome/browser/autofill/password_generator.h" | |
36 #include "chrome/browser/autofill/personal_data_manager.h" | |
37 #include "chrome/browser/autofill/personal_data_manager_factory.h" | |
38 #include "chrome/browser/autofill/phone_number.h" | |
39 #include "chrome/browser/autofill/phone_number_i18n.h" | |
40 #include "chrome/common/chrome_notification_types.h" | |
41 #include "components/autofill/common/autofill_messages.h" | |
42 #include "components/autofill/common/autofill_pref_names.h" | |
43 #include "components/autofill/common/autofill_switches.h" | |
44 #include "components/autofill/common/form_data.h" | |
45 #include "components/autofill/common/form_data_predictions.h" | |
46 #include "components/autofill/common/form_field_data.h" | |
47 #include "components/autofill/common/password_form_fill_data.h" | |
48 #include "components/user_prefs/pref_registry_syncable.h" | |
49 #include "content/public/browser/browser_context.h" | |
50 #include "content/public/browser/browser_thread.h" | |
51 #include "content/public/browser/notification_service.h" | |
52 #include "content/public/browser/notification_source.h" | |
53 #include "content/public/browser/render_view_host.h" | |
54 #include "content/public/browser/web_contents.h" | |
55 #include "content/public/browser/web_contents_view.h" | |
56 #include "content/public/common/url_constants.h" | |
57 #include "googleurl/src/gurl.h" | |
58 #include "grit/generated_resources.h" | |
59 #include "ipc/ipc_message_macros.h" | |
60 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" | |
61 #include "ui/base/l10n/l10n_util.h" | |
62 #include "ui/gfx/rect.h" | |
63 | |
64 typedef PersonalDataManager::GUIDPair GUIDPair; | |
65 | |
66 using base::TimeTicks; | |
67 using content::BrowserThread; | |
68 using content::RenderViewHost; | |
69 using WebKit::WebFormElement; | |
70 | |
71 namespace { | |
72 | |
73 const char* kAutofillManagerWebContentsUserDataKey = "web_contents_autofill"; | |
74 | |
75 // We only send a fraction of the forms to upload server. | |
76 // The rate for positive/negative matches potentially could be different. | |
77 const double kAutofillPositiveUploadRateDefaultValue = 0.20; | |
78 const double kAutofillNegativeUploadRateDefaultValue = 0.20; | |
79 | |
80 const size_t kMaxRecentFormSignaturesToRemember = 3; | |
81 | |
82 // Set a conservative upper bound on the number of forms we are willing to | |
83 // cache, simply to prevent unbounded memory consumption. | |
84 const size_t kMaxFormCacheSize = 100; | |
85 | |
86 // Removes duplicate suggestions whilst preserving their original order. | |
87 void RemoveDuplicateSuggestions(std::vector<string16>* values, | |
88 std::vector<string16>* labels, | |
89 std::vector<string16>* icons, | |
90 std::vector<int>* unique_ids) { | |
91 DCHECK_EQ(values->size(), labels->size()); | |
92 DCHECK_EQ(values->size(), icons->size()); | |
93 DCHECK_EQ(values->size(), unique_ids->size()); | |
94 | |
95 std::set<std::pair<string16, string16> > seen_suggestions; | |
96 std::vector<string16> values_copy; | |
97 std::vector<string16> labels_copy; | |
98 std::vector<string16> icons_copy; | |
99 std::vector<int> unique_ids_copy; | |
100 | |
101 for (size_t i = 0; i < values->size(); ++i) { | |
102 const std::pair<string16, string16> suggestion((*values)[i], (*labels)[i]); | |
103 if (seen_suggestions.insert(suggestion).second) { | |
104 values_copy.push_back((*values)[i]); | |
105 labels_copy.push_back((*labels)[i]); | |
106 icons_copy.push_back((*icons)[i]); | |
107 unique_ids_copy.push_back((*unique_ids)[i]); | |
108 } | |
109 } | |
110 | |
111 values->swap(values_copy); | |
112 labels->swap(labels_copy); | |
113 icons->swap(icons_copy); | |
114 unique_ids->swap(unique_ids_copy); | |
115 } | |
116 | |
117 // Precondition: |form_structure| and |form| should correspond to the same | |
118 // logical form. Returns true if any field in the given |section| within |form| | |
119 // is auto-filled. | |
120 bool SectionIsAutofilled(const FormStructure& form_structure, | |
121 const FormData& form, | |
122 const std::string& section) { | |
123 DCHECK_EQ(form_structure.field_count(), form.fields.size()); | |
124 for (size_t i = 0; i < form_structure.field_count(); ++i) { | |
125 if (form_structure.field(i)->section() == section && | |
126 form.fields[i].is_autofilled) { | |
127 return true; | |
128 } | |
129 } | |
130 | |
131 return false; | |
132 } | |
133 | |
134 bool FormIsHTTPS(const FormStructure& form) { | |
135 return form.source_url().SchemeIs(chrome::kHttpsScheme); | |
136 } | |
137 | |
138 // Uses the existing personal data in |profiles| and |credit_cards| to determine | |
139 // possible field types for the |submitted_form|. This is potentially | |
140 // expensive -- on the order of 50ms even for a small set of |stored_data|. | |
141 // Hence, it should not run on the UI thread -- to avoid locking up the UI -- | |
142 // nor on the IO thread -- to avoid blocking IPC calls. | |
143 void DeterminePossibleFieldTypesForUpload( | |
144 const std::vector<AutofillProfile>& profiles, | |
145 const std::vector<CreditCard>& credit_cards, | |
146 const std::string& app_locale, | |
147 FormStructure* submitted_form) { | |
148 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
149 | |
150 // For each field in the |submitted_form|, extract the value. Then for each | |
151 // profile or credit card, identify any stored types that match the value. | |
152 for (size_t i = 0; i < submitted_form->field_count(); ++i) { | |
153 AutofillField* field = submitted_form->field(i); | |
154 string16 value = CollapseWhitespace(field->value, false); | |
155 | |
156 FieldTypeSet matching_types; | |
157 for (std::vector<AutofillProfile>::const_iterator it = profiles.begin(); | |
158 it != profiles.end(); ++it) { | |
159 it->GetMatchingTypes(value, app_locale, &matching_types); | |
160 } | |
161 for (std::vector<CreditCard>::const_iterator it = credit_cards.begin(); | |
162 it != credit_cards.end(); ++it) { | |
163 it->GetMatchingTypes(value, app_locale, &matching_types); | |
164 } | |
165 | |
166 if (matching_types.empty()) | |
167 matching_types.insert(UNKNOWN_TYPE); | |
168 | |
169 field->set_possible_types(matching_types); | |
170 } | |
171 } | |
172 | |
173 } // namespace | |
174 | |
175 // static | |
176 void AutofillManager::CreateForWebContentsAndDelegate( | |
177 content::WebContents* contents, | |
178 autofill::AutofillManagerDelegate* delegate) { | |
179 if (FromWebContents(contents)) | |
180 return; | |
181 | |
182 contents->SetUserData(kAutofillManagerWebContentsUserDataKey, | |
183 new AutofillManager(contents, delegate)); | |
184 } | |
185 | |
186 // static | |
187 AutofillManager* AutofillManager::FromWebContents( | |
188 content::WebContents* contents) { | |
189 return static_cast<AutofillManager*>( | |
190 contents->GetUserData(kAutofillManagerWebContentsUserDataKey)); | |
191 } | |
192 | |
193 AutofillManager::AutofillManager(content::WebContents* web_contents, | |
194 autofill::AutofillManagerDelegate* delegate) | |
195 : content::WebContentsObserver(web_contents), | |
196 manager_delegate_(delegate), | |
197 personal_data_(delegate->GetPersonalDataManager()), | |
198 download_manager_(web_contents->GetBrowserContext(), this), | |
199 disable_download_manager_requests_(false), | |
200 autocomplete_history_manager_(web_contents), | |
201 autocheckout_manager_(this), | |
202 metric_logger_(new AutofillMetrics), | |
203 has_logged_autofill_enabled_(false), | |
204 has_logged_address_suggestions_count_(false), | |
205 did_show_suggestions_(false), | |
206 user_did_type_(false), | |
207 user_did_autofill_(false), | |
208 user_did_edit_autofilled_field_(false), | |
209 password_generation_enabled_(false), | |
210 external_delegate_(NULL), | |
211 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
212 RegisterWithSyncService(); | |
213 registrar_.Init(manager_delegate_->GetPrefs()); | |
214 registrar_.Add( | |
215 prefs::kPasswordGenerationEnabled, | |
216 base::Bind(&AutofillManager::OnPasswordGenerationEnabledChanged, | |
217 base::Unretained(this))); | |
218 } | |
219 | |
220 AutofillManager::~AutofillManager() { | |
221 } | |
222 | |
223 // static | |
224 void AutofillManager::RegisterUserPrefs(PrefRegistrySyncable* registry) { | |
225 registry->RegisterBooleanPref(prefs::kAutofillEnabled, | |
226 true, | |
227 PrefRegistrySyncable::SYNCABLE_PREF); | |
228 registry->RegisterBooleanPref(prefs::kPasswordGenerationEnabled, | |
229 true, | |
230 PrefRegistrySyncable::SYNCABLE_PREF); | |
231 #if defined(OS_MACOSX) | |
232 registry->RegisterBooleanPref(prefs::kAutofillAuxiliaryProfilesEnabled, | |
233 true, | |
234 PrefRegistrySyncable::SYNCABLE_PREF); | |
235 #else | |
236 registry->RegisterBooleanPref(prefs::kAutofillAuxiliaryProfilesEnabled, | |
237 false, | |
238 PrefRegistrySyncable::UNSYNCABLE_PREF); | |
239 #endif | |
240 registry->RegisterDoublePref(prefs::kAutofillPositiveUploadRate, | |
241 kAutofillPositiveUploadRateDefaultValue, | |
242 PrefRegistrySyncable::UNSYNCABLE_PREF); | |
243 registry->RegisterDoublePref(prefs::kAutofillNegativeUploadRate, | |
244 kAutofillNegativeUploadRateDefaultValue, | |
245 PrefRegistrySyncable::UNSYNCABLE_PREF); | |
246 } | |
247 | |
248 void AutofillManager::RegisterWithSyncService() { | |
249 // TODO(joi): If/when SupportsWebData supports structured | |
250 // destruction ordering, we could use a base::Unretained here and | |
251 // just unsubscribe in our destructor. As is, we can't guarantee | |
252 // that the delegate doesn't get destroyed (by WebContent's | |
253 // SupportsUserData) right before the AutofillManager. | |
254 manager_delegate_->SetSyncStateChangedCallback(base::Bind( | |
255 &AutofillManager::OnSyncStateChanged, weak_ptr_factory_.GetWeakPtr())); | |
256 } | |
257 | |
258 void AutofillManager::SendPasswordGenerationStateToRenderer( | |
259 content::RenderViewHost* host, bool enabled) { | |
260 host->Send(new AutofillMsg_PasswordGenerationEnabled(host->GetRoutingID(), | |
261 enabled)); | |
262 } | |
263 | |
264 // In order for password generation to be enabled, we need to make sure: | |
265 // (1) Password sync is enabled, | |
266 // (2) Password manager is enabled, and | |
267 // (3) Password generation preference check box is checked. | |
268 void AutofillManager::UpdatePasswordGenerationState( | |
269 content::RenderViewHost* host, | |
270 bool new_renderer) { | |
271 bool saving_passwords_enabled = manager_delegate_->IsSavingPasswordsEnabled(); | |
272 bool preference_checked = manager_delegate_->GetPrefs()->GetBoolean( | |
273 prefs::kPasswordGenerationEnabled); | |
274 | |
275 bool new_password_generation_enabled = | |
276 manager_delegate_->IsPasswordSyncEnabled() && | |
277 saving_passwords_enabled && | |
278 preference_checked; | |
279 | |
280 if (new_password_generation_enabled != password_generation_enabled_ || | |
281 new_renderer) { | |
282 password_generation_enabled_ = new_password_generation_enabled; | |
283 SendPasswordGenerationStateToRenderer(host, password_generation_enabled_); | |
284 } | |
285 } | |
286 | |
287 void AutofillManager::RenderViewCreated(content::RenderViewHost* host) { | |
288 UpdatePasswordGenerationState(host, true); | |
289 } | |
290 | |
291 void AutofillManager::OnPasswordGenerationEnabledChanged() { | |
292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
293 UpdatePasswordGenerationState(web_contents()->GetRenderViewHost(), false); | |
294 } | |
295 | |
296 void AutofillManager::OnSyncStateChanged() { | |
297 // It is possible for sync state to change during tab contents destruction. | |
298 // In this case, we don't need to update the renderer since it's going away. | |
299 if (web_contents() && web_contents()->GetRenderViewHost()) { | |
300 UpdatePasswordGenerationState(web_contents()->GetRenderViewHost(), | |
301 false); | |
302 } | |
303 } | |
304 | |
305 void AutofillManager::DidNavigateMainFrame( | |
306 const content::LoadCommittedDetails& details, | |
307 const content::FrameNavigateParams& params) { | |
308 Reset(); | |
309 } | |
310 | |
311 void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) { | |
312 // TODO(jrg): consider passing delegate into the ctor. That won't | |
313 // work if the delegate has a pointer to the AutofillManager, but | |
314 // future directions may not need such a pointer. | |
315 external_delegate_ = delegate; | |
316 autocomplete_history_manager_.SetExternalDelegate(delegate); | |
317 } | |
318 | |
319 bool AutofillManager::IsNativeUiEnabled() { | |
320 return external_delegate_ != NULL; | |
321 } | |
322 | |
323 bool AutofillManager::OnMessageReceived(const IPC::Message& message) { | |
324 bool handled = true; | |
325 IPC_BEGIN_MESSAGE_MAP(AutofillManager, message) | |
326 IPC_MESSAGE_HANDLER(AutofillHostMsg_FormsSeen, OnFormsSeen) | |
327 IPC_MESSAGE_HANDLER(AutofillHostMsg_FormSubmitted, OnFormSubmitted) | |
328 IPC_MESSAGE_HANDLER(AutofillHostMsg_TextFieldDidChange, | |
329 OnTextFieldDidChange) | |
330 IPC_MESSAGE_HANDLER(AutofillHostMsg_QueryFormFieldAutofill, | |
331 OnQueryFormFieldAutofill) | |
332 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowAutofillDialog, | |
333 OnShowAutofillDialog) | |
334 IPC_MESSAGE_HANDLER(AutofillHostMsg_FillAutofillFormData, | |
335 OnFillAutofillFormData) | |
336 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidPreviewAutofillFormData, | |
337 OnDidPreviewAutofillFormData) | |
338 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidFillAutofillFormData, | |
339 OnDidFillAutofillFormData) | |
340 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidShowAutofillSuggestions, | |
341 OnDidShowAutofillSuggestions) | |
342 IPC_MESSAGE_HANDLER(AutofillHostMsg_DidEndTextFieldEditing, | |
343 OnDidEndTextFieldEditing) | |
344 IPC_MESSAGE_HANDLER(AutofillHostMsg_HideAutofillPopup, | |
345 OnHideAutofillPopup) | |
346 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup, | |
347 OnShowPasswordGenerationPopup) | |
348 IPC_MESSAGE_HANDLER(AutofillHostMsg_AddPasswordFormMapping, | |
349 OnAddPasswordFormMapping) | |
350 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordSuggestions, | |
351 OnShowPasswordSuggestions) | |
352 IPC_MESSAGE_HANDLER(AutofillHostMsg_SetDataList, | |
353 OnSetDataList) | |
354 IPC_MESSAGE_HANDLER(AutofillHostMsg_RequestAutocomplete, | |
355 OnRequestAutocomplete) | |
356 IPC_MESSAGE_HANDLER(AutofillHostMsg_ClickFailed, | |
357 OnClickFailed) | |
358 IPC_MESSAGE_UNHANDLED(handled = false) | |
359 IPC_END_MESSAGE_MAP() | |
360 | |
361 return handled; | |
362 } | |
363 | |
364 void AutofillManager::WebContentsDestroyed(content::WebContents* web_contents) { | |
365 // Unsubscribe. | |
366 manager_delegate_->SetSyncStateChangedCallback(base::Closure()); | |
367 } | |
368 | |
369 bool AutofillManager::OnFormSubmitted(const FormData& form, | |
370 const TimeTicks& timestamp) { | |
371 // Let AutoComplete know as well. | |
372 autocomplete_history_manager_.OnFormSubmitted(form); | |
373 | |
374 if (!IsAutofillEnabled()) | |
375 return false; | |
376 | |
377 if (web_contents()->GetBrowserContext()->IsOffTheRecord()) | |
378 return false; | |
379 | |
380 // Don't save data that was submitted through JavaScript. | |
381 if (!form.user_submitted) | |
382 return false; | |
383 | |
384 // Grab a copy of the form data. | |
385 scoped_ptr<FormStructure> submitted_form( | |
386 new FormStructure(form, GetAutocheckoutURLPrefix())); | |
387 | |
388 // Disregard forms that we wouldn't ever autofill in the first place. | |
389 if (!submitted_form->ShouldBeParsed(true)) | |
390 return false; | |
391 | |
392 // Ignore forms not present in our cache. These are typically forms with | |
393 // wonky JavaScript that also makes them not auto-fillable. | |
394 FormStructure* cached_submitted_form; | |
395 if (!FindCachedForm(form, &cached_submitted_form)) | |
396 return false; | |
397 | |
398 submitted_form->UpdateFromCache(*cached_submitted_form); | |
399 if (submitted_form->IsAutofillable(true)) | |
400 ImportFormData(*submitted_form); | |
401 | |
402 // Only upload server statistics and UMA metrics if at least some local data | |
403 // is available to use as a baseline. | |
404 const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); | |
405 const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards(); | |
406 if (!profiles.empty() || !credit_cards.empty()) { | |
407 // Copy the profile and credit card data, so that it can be accessed on a | |
408 // separate thread. | |
409 std::vector<AutofillProfile> copied_profiles; | |
410 copied_profiles.reserve(profiles.size()); | |
411 for (std::vector<AutofillProfile*>::const_iterator it = profiles.begin(); | |
412 it != profiles.end(); ++it) { | |
413 copied_profiles.push_back(**it); | |
414 } | |
415 | |
416 std::vector<CreditCard> copied_credit_cards; | |
417 copied_credit_cards.reserve(credit_cards.size()); | |
418 for (std::vector<CreditCard*>::const_iterator it = credit_cards.begin(); | |
419 it != credit_cards.end(); ++it) { | |
420 copied_credit_cards.push_back(**it); | |
421 } | |
422 | |
423 // Note that ownership of |submitted_form| is passed to the second task, | |
424 // using |base::Owned|. | |
425 FormStructure* raw_submitted_form = submitted_form.get(); | |
426 BrowserThread::GetBlockingPool()->PostTaskAndReply( | |
427 FROM_HERE, | |
428 base::Bind(&DeterminePossibleFieldTypesForUpload, | |
429 copied_profiles, | |
430 copied_credit_cards, | |
431 AutofillCountry::ApplicationLocale(), | |
432 raw_submitted_form), | |
433 base::Bind(&AutofillManager::UploadFormDataAsyncCallback, | |
434 weak_ptr_factory_.GetWeakPtr(), | |
435 base::Owned(submitted_form.release()), | |
436 forms_loaded_timestamp_, | |
437 initial_interaction_timestamp_, | |
438 timestamp)); | |
439 } | |
440 | |
441 return true; | |
442 } | |
443 | |
444 void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms, | |
445 const TimeTicks& timestamp) { | |
446 autocheckout_manager_.OnFormsSeen(); | |
447 bool enabled = IsAutofillEnabled(); | |
448 if (!has_logged_autofill_enabled_) { | |
449 metric_logger_->LogIsAutofillEnabledAtPageLoad(enabled); | |
450 has_logged_autofill_enabled_ = true; | |
451 } | |
452 | |
453 if (!enabled) | |
454 return; | |
455 | |
456 forms_loaded_timestamp_ = timestamp; | |
457 ParseForms(forms); | |
458 } | |
459 | |
460 void AutofillManager::OnTextFieldDidChange(const FormData& form, | |
461 const FormFieldData& field, | |
462 const TimeTicks& timestamp) { | |
463 FormStructure* form_structure = NULL; | |
464 AutofillField* autofill_field = NULL; | |
465 if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field)) | |
466 return; | |
467 | |
468 if (!user_did_type_) { | |
469 user_did_type_ = true; | |
470 metric_logger_->LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE); | |
471 } | |
472 | |
473 if (autofill_field->is_autofilled) { | |
474 autofill_field->is_autofilled = false; | |
475 metric_logger_->LogUserHappinessMetric( | |
476 AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD); | |
477 | |
478 if (!user_did_edit_autofilled_field_) { | |
479 user_did_edit_autofilled_field_ = true; | |
480 metric_logger_->LogUserHappinessMetric( | |
481 AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE); | |
482 } | |
483 } | |
484 | |
485 UpdateInitialInteractionTimestamp(timestamp); | |
486 } | |
487 | |
488 void AutofillManager::OnQueryFormFieldAutofill(int query_id, | |
489 const FormData& form, | |
490 const FormFieldData& field, | |
491 const gfx::RectF& bounding_box, | |
492 bool display_warning) { | |
493 std::vector<string16> values; | |
494 std::vector<string16> labels; | |
495 std::vector<string16> icons; | |
496 std::vector<int> unique_ids; | |
497 | |
498 if (external_delegate_) { | |
499 external_delegate_->OnQuery(query_id, | |
500 form, | |
501 field, | |
502 bounding_box, | |
503 display_warning); | |
504 } | |
505 | |
506 RenderViewHost* host = NULL; | |
507 FormStructure* form_structure = NULL; | |
508 AutofillField* autofill_field = NULL; | |
509 if (GetHost(&host) && | |
510 GetCachedFormAndField(form, field, &form_structure, &autofill_field) && | |
511 // Don't send suggestions for forms that aren't auto-fillable. | |
512 form_structure->IsAutofillable(false)) { | |
513 AutofillFieldType type = autofill_field->type(); | |
514 bool is_filling_credit_card = | |
515 (AutofillType(type).group() == AutofillType::CREDIT_CARD); | |
516 if (is_filling_credit_card) { | |
517 GetCreditCardSuggestions( | |
518 field, type, &values, &labels, &icons, &unique_ids); | |
519 } else { | |
520 GetProfileSuggestions( | |
521 form_structure, field, type, &values, &labels, &icons, &unique_ids); | |
522 } | |
523 | |
524 DCHECK_EQ(values.size(), labels.size()); | |
525 DCHECK_EQ(values.size(), icons.size()); | |
526 DCHECK_EQ(values.size(), unique_ids.size()); | |
527 | |
528 if (!values.empty()) { | |
529 // Don't provide Autofill suggestions when Autofill is disabled, and don't | |
530 // provide credit card suggestions for non-HTTPS pages. However, provide a | |
531 // warning to the user in these cases. | |
532 int warning = 0; | |
533 if (!form_structure->IsAutofillable(true)) | |
534 warning = IDS_AUTOFILL_WARNING_FORM_DISABLED; | |
535 else if (is_filling_credit_card && !FormIsHTTPS(*form_structure)) | |
536 warning = IDS_AUTOFILL_WARNING_INSECURE_CONNECTION; | |
537 if (warning) { | |
538 values.assign(1, l10n_util::GetStringUTF16(warning)); | |
539 labels.assign(1, string16()); | |
540 icons.assign(1, string16()); | |
541 unique_ids.assign(1, | |
542 WebKit::WebAutofillClient::MenuItemIDWarningMessage); | |
543 } else { | |
544 bool section_is_autofilled = | |
545 SectionIsAutofilled(*form_structure, form, | |
546 autofill_field->section()); | |
547 if (section_is_autofilled) { | |
548 // If the relevant section is auto-filled and the renderer is querying | |
549 // for suggestions, then the user is editing the value of a field. | |
550 // In this case, mimic autocomplete: don't display labels or icons, | |
551 // as that information is redundant. | |
552 labels.assign(labels.size(), string16()); | |
553 icons.assign(icons.size(), string16()); | |
554 } | |
555 | |
556 // When filling credit card suggestions, the values and labels are | |
557 // typically obfuscated, which makes detecting duplicates hard. Since | |
558 // duplicates only tend to be a problem when filling address forms | |
559 // anyway, only don't de-dup credit card suggestions. | |
560 if (!is_filling_credit_card) | |
561 RemoveDuplicateSuggestions(&values, &labels, &icons, &unique_ids); | |
562 | |
563 // The first time we show suggestions on this page, log the number of | |
564 // suggestions shown. | |
565 if (!has_logged_address_suggestions_count_ && !section_is_autofilled) { | |
566 metric_logger_->LogAddressSuggestionsCount(values.size()); | |
567 has_logged_address_suggestions_count_ = true; | |
568 } | |
569 } | |
570 } | |
571 | |
572 // If form is known to be at the start of the autofillable flow (i.e, when | |
573 // Autofill server said so), then trigger payments UI while also returning | |
574 // standard autofill suggestions to renderer process. | |
575 if (autocheckout_manager_.IsStartOfAutofillableFlow()) { | |
576 bool bubble_shown = | |
577 autocheckout_manager_.MaybeShowAutocheckoutBubble( | |
578 form.origin, | |
579 form.ssl_status, | |
580 web_contents()->GetView()->GetContentNativeView(), | |
581 bounding_box); | |
582 if (bubble_shown) | |
583 return; | |
584 } | |
585 } | |
586 | |
587 // Add the results from AutoComplete. They come back asynchronously, so we | |
588 // hand off what we generated and they will send the results back to the | |
589 // renderer. | |
590 autocomplete_history_manager_.OnGetAutocompleteSuggestions( | |
591 query_id, field.name, field.value, values, labels, icons, unique_ids); | |
592 } | |
593 | |
594 void AutofillManager::OnFillAutofillFormData(int query_id, | |
595 const FormData& form, | |
596 const FormFieldData& field, | |
597 int unique_id) { | |
598 RenderViewHost* host = NULL; | |
599 const FormGroup* form_group = NULL; | |
600 size_t variant = 0; | |
601 FormStructure* form_structure = NULL; | |
602 AutofillField* autofill_field = NULL; | |
603 // NOTE: GetHost may invalidate |form_group| because it causes the | |
604 // PersonalDataManager to reload Mac address book entries. Thus it must | |
605 // come before GetProfileOrCreditCard. | |
606 if (!GetHost(&host) || | |
607 !GetProfileOrCreditCard(unique_id, &form_group, &variant) || | |
608 !GetCachedFormAndField(form, field, &form_structure, &autofill_field)) | |
609 return; | |
610 | |
611 DCHECK(host); | |
612 DCHECK(form_structure); | |
613 DCHECK(autofill_field); | |
614 | |
615 FormData result = form; | |
616 | |
617 // If the relevant section is auto-filled, we should fill |field| but not the | |
618 // rest of the form. | |
619 if (SectionIsAutofilled(*form_structure, form, autofill_field->section())) { | |
620 for (std::vector<FormFieldData>::iterator iter = result.fields.begin(); | |
621 iter != result.fields.end(); ++iter) { | |
622 if ((*iter) == field) { | |
623 form_group->FillFormField(*autofill_field, variant, &(*iter)); | |
624 // Mark the cached field as autofilled, so that we can detect when a | |
625 // user edits an autofilled field (for metrics). | |
626 autofill_field->is_autofilled = true; | |
627 break; | |
628 } | |
629 } | |
630 | |
631 host->Send(new AutofillMsg_FormDataFilled(host->GetRoutingID(), query_id, | |
632 result)); | |
633 return; | |
634 } | |
635 | |
636 // Cache the field type for the field from which the user initiated autofill. | |
637 FieldTypeGroup initiating_group_type = | |
638 AutofillType(autofill_field->type()).group(); | |
639 DCHECK_EQ(form_structure->field_count(), form.fields.size()); | |
640 for (size_t i = 0; i < form_structure->field_count(); ++i) { | |
641 if (form_structure->field(i)->section() != autofill_field->section()) | |
642 continue; | |
643 | |
644 DCHECK_EQ(*form_structure->field(i), result.fields[i]); | |
645 | |
646 const AutofillField* cached_field = form_structure->field(i); | |
647 FieldTypeGroup field_group_type = | |
648 AutofillType(cached_field->type()).group(); | |
649 if (field_group_type != AutofillType::NO_GROUP) { | |
650 // If the field being filled is either | |
651 // (a) the field that the user initiated the fill from, or | |
652 // (b) part of the same logical unit, e.g. name or phone number, | |
653 // then take the multi-profile "variant" into account. | |
654 // Otherwise fill with the default (zeroth) variant. | |
655 size_t use_variant = 0; | |
656 if (result.fields[i] == field || | |
657 field_group_type == initiating_group_type) { | |
658 use_variant = variant; | |
659 } | |
660 form_group->FillFormField(*cached_field, | |
661 use_variant, | |
662 &result.fields[i]); | |
663 // Mark the cached field as autofilled, so that we can detect when a user | |
664 // edits an autofilled field (for metrics). | |
665 form_structure->field(i)->is_autofilled = true; | |
666 } | |
667 } | |
668 | |
669 autofilled_form_signatures_.push_front(form_structure->FormSignature()); | |
670 // Only remember the last few forms that we've seen, both to avoid false | |
671 // positives and to avoid wasting memory. | |
672 if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember) | |
673 autofilled_form_signatures_.pop_back(); | |
674 | |
675 host->Send(new AutofillMsg_FormDataFilled( | |
676 host->GetRoutingID(), query_id, result)); | |
677 } | |
678 | |
679 void AutofillManager::OnShowAutofillDialog() { | |
680 manager_delegate_->ShowAutofillSettings(); | |
681 } | |
682 | |
683 void AutofillManager::OnDidPreviewAutofillFormData() { | |
684 content::NotificationService::current()->Notify( | |
685 chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA, | |
686 content::Source<RenderViewHost>(web_contents()->GetRenderViewHost()), | |
687 content::NotificationService::NoDetails()); | |
688 } | |
689 | |
690 void AutofillManager::OnDidFillAutofillFormData(const TimeTicks& timestamp) { | |
691 content::NotificationService::current()->Notify( | |
692 chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA, | |
693 content::Source<RenderViewHost>(web_contents()->GetRenderViewHost()), | |
694 content::NotificationService::NoDetails()); | |
695 | |
696 metric_logger_->LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL); | |
697 if (!user_did_autofill_) { | |
698 user_did_autofill_ = true; | |
699 metric_logger_->LogUserHappinessMetric( | |
700 AutofillMetrics::USER_DID_AUTOFILL_ONCE); | |
701 } | |
702 | |
703 UpdateInitialInteractionTimestamp(timestamp); | |
704 } | |
705 | |
706 void AutofillManager::OnDidShowAutofillSuggestions(bool is_new_popup) { | |
707 content::NotificationService::current()->Notify( | |
708 chrome::NOTIFICATION_AUTOFILL_DID_SHOW_SUGGESTIONS, | |
709 content::Source<RenderViewHost>(web_contents()->GetRenderViewHost()), | |
710 content::NotificationService::NoDetails()); | |
711 | |
712 if (is_new_popup) { | |
713 metric_logger_->LogUserHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN); | |
714 | |
715 if (!did_show_suggestions_) { | |
716 did_show_suggestions_ = true; | |
717 metric_logger_->LogUserHappinessMetric( | |
718 AutofillMetrics::SUGGESTIONS_SHOWN_ONCE); | |
719 } | |
720 } | |
721 } | |
722 | |
723 void AutofillManager::OnHideAutofillPopup() { | |
724 if (IsNativeUiEnabled()) | |
725 manager_delegate_->HideAutofillPopup(); | |
726 } | |
727 | |
728 void AutofillManager::OnShowPasswordGenerationPopup( | |
729 const gfx::Rect& bounds, | |
730 int max_length, | |
731 const content::PasswordForm& form) { | |
732 password_generator_.reset(new autofill::PasswordGenerator(max_length)); | |
733 manager_delegate_->ShowPasswordGenerationBubble( | |
734 bounds, form, password_generator_.get()); | |
735 } | |
736 | |
737 void AutofillManager::RemoveAutofillProfileOrCreditCard(int unique_id) { | |
738 const FormGroup* form_group = NULL; | |
739 size_t variant = 0; | |
740 if (!GetProfileOrCreditCard(unique_id, &form_group, &variant)) { | |
741 NOTREACHED(); | |
742 return; | |
743 } | |
744 | |
745 // TODO(csharp): If we are dealing with a variant only the variant should | |
746 // be deleted, instead of doing nothing. | |
747 // http://crbug.com/124211 | |
748 if (variant != 0) | |
749 return; | |
750 | |
751 personal_data_->RemoveByGUID(form_group->GetGUID()); | |
752 } | |
753 | |
754 void AutofillManager::RemoveAutocompleteEntry(const string16& name, | |
755 const string16& value) { | |
756 autocomplete_history_manager_.OnRemoveAutocompleteEntry(name, value); | |
757 } | |
758 | |
759 content::WebContents* AutofillManager::GetWebContents() const { | |
760 return web_contents(); | |
761 } | |
762 | |
763 const std::vector<FormStructure*>& AutofillManager::GetFormStructures() { | |
764 return form_structures_.get(); | |
765 } | |
766 | |
767 void AutofillManager::ShowRequestAutocompleteDialog( | |
768 const FormData& form, | |
769 const GURL& source_url, | |
770 const content::SSLStatus& ssl_status, | |
771 autofill::DialogType dialog_type, | |
772 const base::Callback<void(const FormStructure*)>& callback) { | |
773 manager_delegate_->ShowRequestAutocompleteDialog( | |
774 form, source_url, ssl_status, *metric_logger_, dialog_type, callback); | |
775 } | |
776 | |
777 void AutofillManager::RequestAutocompleteDialogClosed() { | |
778 manager_delegate_->RequestAutocompleteDialogClosed(); | |
779 } | |
780 | |
781 void AutofillManager::OnAddPasswordFormMapping( | |
782 const FormFieldData& form, | |
783 const PasswordFormFillData& fill_data) { | |
784 if (external_delegate_) | |
785 external_delegate_->AddPasswordFormMapping(form, fill_data); | |
786 } | |
787 | |
788 void AutofillManager::OnShowPasswordSuggestions( | |
789 const FormFieldData& field, | |
790 const gfx::RectF& bounds, | |
791 const std::vector<string16>& suggestions) { | |
792 if (external_delegate_) | |
793 external_delegate_->OnShowPasswordSuggestions(suggestions, field, bounds); | |
794 } | |
795 | |
796 void AutofillManager::OnSetDataList(const std::vector<string16>& values, | |
797 const std::vector<string16>& labels, | |
798 const std::vector<string16>& icons, | |
799 const std::vector<int>& unique_ids) { | |
800 if (labels.size() != values.size() || | |
801 icons.size() != values.size() || | |
802 unique_ids.size() != values.size()) { | |
803 return; | |
804 } | |
805 if (external_delegate_) { | |
806 external_delegate_->SetCurrentDataListValues(values, | |
807 labels, | |
808 icons, | |
809 unique_ids); | |
810 } | |
811 } | |
812 | |
813 void AutofillManager::OnRequestAutocomplete( | |
814 const FormData& form, | |
815 const GURL& frame_url, | |
816 const content::SSLStatus& ssl_status) { | |
817 if (!IsAutofillEnabled()) { | |
818 ReturnAutocompleteResult(WebFormElement::AutocompleteResultErrorDisabled, | |
819 FormData()); | |
820 return; | |
821 } | |
822 | |
823 base::Callback<void(const FormStructure*)> callback = | |
824 base::Bind(&AutofillManager::ReturnAutocompleteData, | |
825 weak_ptr_factory_.GetWeakPtr()); | |
826 ShowRequestAutocompleteDialog( | |
827 form, frame_url, ssl_status, | |
828 autofill::DIALOG_TYPE_REQUEST_AUTOCOMPLETE, callback); | |
829 } | |
830 | |
831 void AutofillManager::ReturnAutocompleteResult( | |
832 WebFormElement::AutocompleteResult result, const FormData& form_data) { | |
833 // web_contents() will be NULL when the interactive autocomplete is closed due | |
834 // to a tab or browser window closing. | |
835 if (!web_contents()) | |
836 return; | |
837 | |
838 RenderViewHost* host = web_contents()->GetRenderViewHost(); | |
839 if (!host) | |
840 return; | |
841 | |
842 host->Send(new AutofillMsg_RequestAutocompleteResult(host->GetRoutingID(), | |
843 result, | |
844 form_data)); | |
845 } | |
846 | |
847 void AutofillManager::ReturnAutocompleteData(const FormStructure* result) { | |
848 RequestAutocompleteDialogClosed(); | |
849 if (!result) { | |
850 ReturnAutocompleteResult(WebFormElement::AutocompleteResultErrorCancel, | |
851 FormData()); | |
852 } else { | |
853 ReturnAutocompleteResult(WebFormElement::AutocompleteResultSuccess, | |
854 result->ToFormData()); | |
855 } | |
856 } | |
857 | |
858 void AutofillManager::OnLoadedServerPredictions( | |
859 const std::string& response_xml) { | |
860 scoped_ptr<autofill::AutocheckoutPageMetaData> page_meta_data( | |
861 new autofill::AutocheckoutPageMetaData()); | |
862 | |
863 // Parse and store the server predictions. | |
864 FormStructure::ParseQueryResponse(response_xml, | |
865 form_structures_.get(), | |
866 page_meta_data.get(), | |
867 *metric_logger_); | |
868 | |
869 autocheckout_manager_.OnLoadedPageMetaData(page_meta_data.Pass()); | |
870 | |
871 // If the corresponding flag is set, annotate forms with the predicted types. | |
872 SendAutofillTypePredictions(form_structures_.get()); | |
873 } | |
874 | |
875 void AutofillManager::OnDidEndTextFieldEditing() { | |
876 if (external_delegate_) | |
877 external_delegate_->DidEndTextFieldEditing(); | |
878 } | |
879 | |
880 void AutofillManager::OnClickFailed(autofill::AutocheckoutStatus status) { | |
881 // TODO(ahutter): Plug into WalletClient. | |
882 } | |
883 | |
884 std::string AutofillManager::GetAutocheckoutURLPrefix() const { | |
885 if (!web_contents()) | |
886 return std::string(); | |
887 | |
888 autofill::autocheckout::WhitelistManager* whitelist_manager = | |
889 autofill::autocheckout::WhitelistManager::GetForBrowserContext( | |
890 web_contents()->GetBrowserContext()); | |
891 return whitelist_manager->GetMatchedURLPrefix(web_contents()->GetURL()); | |
892 } | |
893 | |
894 bool AutofillManager::IsAutofillEnabled() const { | |
895 return manager_delegate_->GetPrefs()->GetBoolean(prefs::kAutofillEnabled); | |
896 } | |
897 | |
898 void AutofillManager::SendAutofillTypePredictions( | |
899 const std::vector<FormStructure*>& forms) const { | |
900 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
901 switches::kShowAutofillTypePredictions)) | |
902 return; | |
903 | |
904 RenderViewHost* host = web_contents()->GetRenderViewHost(); | |
905 if (!host) | |
906 return; | |
907 | |
908 std::vector<FormDataPredictions> type_predictions; | |
909 FormStructure::GetFieldTypePredictions(forms, &type_predictions); | |
910 host->Send( | |
911 new AutofillMsg_FieldTypePredictionsAvailable(host->GetRoutingID(), | |
912 type_predictions)); | |
913 } | |
914 | |
915 void AutofillManager::ImportFormData(const FormStructure& submitted_form) { | |
916 const CreditCard* imported_credit_card; | |
917 if (!personal_data_->ImportFormData(submitted_form, &imported_credit_card)) | |
918 return; | |
919 | |
920 // If credit card information was submitted, we need to confirm whether to | |
921 // save it. | |
922 if (imported_credit_card) { | |
923 manager_delegate_->ConfirmSaveCreditCard( | |
924 *metric_logger_, | |
925 *imported_credit_card, | |
926 base::Bind(&PersonalDataManager::SaveImportedCreditCard, | |
927 base::Unretained(personal_data_), *imported_credit_card)); | |
928 } | |
929 } | |
930 | |
931 // Note that |submitted_form| is passed as a pointer rather than as a reference | |
932 // so that we can get memory management right across threads. Note also that we | |
933 // explicitly pass in all the time stamps of interest, as the cached ones might | |
934 // get reset before this method executes. | |
935 void AutofillManager::UploadFormDataAsyncCallback( | |
936 const FormStructure* submitted_form, | |
937 const TimeTicks& load_time, | |
938 const TimeTicks& interaction_time, | |
939 const TimeTicks& submission_time) { | |
940 submitted_form->LogQualityMetrics(*metric_logger_, | |
941 load_time, | |
942 interaction_time, | |
943 submission_time); | |
944 | |
945 if (submitted_form->ShouldBeCrowdsourced()) | |
946 UploadFormData(*submitted_form); | |
947 } | |
948 | |
949 void AutofillManager::UploadFormData(const FormStructure& submitted_form) { | |
950 if (disable_download_manager_requests_) | |
951 return; | |
952 | |
953 // Check if the form is among the forms that were recently auto-filled. | |
954 bool was_autofilled = false; | |
955 std::string form_signature = submitted_form.FormSignature(); | |
956 for (std::list<std::string>::const_iterator it = | |
957 autofilled_form_signatures_.begin(); | |
958 it != autofilled_form_signatures_.end() && !was_autofilled; | |
959 ++it) { | |
960 if (*it == form_signature) | |
961 was_autofilled = true; | |
962 } | |
963 | |
964 FieldTypeSet non_empty_types; | |
965 personal_data_->GetNonEmptyTypes(&non_empty_types); | |
966 | |
967 download_manager_.StartUploadRequest(submitted_form, was_autofilled, | |
968 non_empty_types); | |
969 } | |
970 | |
971 void AutofillManager::Reset() { | |
972 form_structures_.clear(); | |
973 has_logged_autofill_enabled_ = false; | |
974 has_logged_address_suggestions_count_ = false; | |
975 did_show_suggestions_ = false; | |
976 user_did_type_ = false; | |
977 user_did_autofill_ = false; | |
978 user_did_edit_autofilled_field_ = false; | |
979 forms_loaded_timestamp_ = TimeTicks(); | |
980 initial_interaction_timestamp_ = TimeTicks(); | |
981 | |
982 if (external_delegate_) | |
983 external_delegate_->Reset(); | |
984 } | |
985 | |
986 AutofillManager::AutofillManager(content::WebContents* web_contents, | |
987 autofill::AutofillManagerDelegate* delegate, | |
988 PersonalDataManager* personal_data) | |
989 : content::WebContentsObserver(web_contents), | |
990 manager_delegate_(delegate), | |
991 personal_data_(personal_data), | |
992 download_manager_(web_contents->GetBrowserContext(), this), | |
993 disable_download_manager_requests_(true), | |
994 autocomplete_history_manager_(web_contents), | |
995 autocheckout_manager_(this), | |
996 metric_logger_(new AutofillMetrics), | |
997 has_logged_autofill_enabled_(false), | |
998 has_logged_address_suggestions_count_(false), | |
999 did_show_suggestions_(false), | |
1000 user_did_type_(false), | |
1001 user_did_autofill_(false), | |
1002 user_did_edit_autofilled_field_(false), | |
1003 password_generation_enabled_(false), | |
1004 external_delegate_(NULL), | |
1005 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
1006 DCHECK(web_contents); | |
1007 DCHECK(manager_delegate_); | |
1008 RegisterWithSyncService(); | |
1009 // Test code doesn't need registrar_. | |
1010 } | |
1011 | |
1012 void AutofillManager::set_metric_logger(const AutofillMetrics* metric_logger) { | |
1013 metric_logger_.reset(metric_logger); | |
1014 } | |
1015 | |
1016 bool AutofillManager::GetHost(RenderViewHost** host) const { | |
1017 if (!IsAutofillEnabled()) | |
1018 return false; | |
1019 | |
1020 // No autofill data to return if the profiles are empty. | |
1021 if (personal_data_->GetProfiles().empty() && | |
1022 personal_data_->credit_cards().empty()) { | |
1023 return false; | |
1024 } | |
1025 | |
1026 *host = web_contents()->GetRenderViewHost(); | |
1027 if (!*host) | |
1028 return false; | |
1029 | |
1030 return true; | |
1031 } | |
1032 | |
1033 bool AutofillManager::GetProfileOrCreditCard( | |
1034 int unique_id, | |
1035 const FormGroup** form_group, | |
1036 size_t* variant) const { | |
1037 // Unpack the |unique_id| into component parts. | |
1038 GUIDPair credit_card_guid; | |
1039 GUIDPair profile_guid; | |
1040 UnpackGUIDs(unique_id, &credit_card_guid, &profile_guid); | |
1041 DCHECK(!base::IsValidGUID(credit_card_guid.first) || | |
1042 !base::IsValidGUID(profile_guid.first)); | |
1043 | |
1044 // Find the profile that matches the |profile_guid|, if one is specified. | |
1045 // Otherwise find the credit card that matches the |credit_card_guid|, | |
1046 // if specified. | |
1047 if (base::IsValidGUID(profile_guid.first)) { | |
1048 *form_group = personal_data_->GetProfileByGUID(profile_guid.first); | |
1049 *variant = profile_guid.second; | |
1050 } else if (base::IsValidGUID(credit_card_guid.first)) { | |
1051 *form_group = | |
1052 personal_data_->GetCreditCardByGUID(credit_card_guid.first); | |
1053 *variant = credit_card_guid.second; | |
1054 } | |
1055 | |
1056 return !!*form_group; | |
1057 } | |
1058 | |
1059 bool AutofillManager::FindCachedForm(const FormData& form, | |
1060 FormStructure** form_structure) const { | |
1061 // Find the FormStructure that corresponds to |form|. | |
1062 // Scan backward through the cached |form_structures_|, as updated versions of | |
1063 // forms are added to the back of the list, whereas original versions of these | |
1064 // forms might appear toward the beginning of the list. The communication | |
1065 // protocol with the crowdsourcing server does not permit us to discard the | |
1066 // original versions of the forms. | |
1067 *form_structure = NULL; | |
1068 for (std::vector<FormStructure*>::const_reverse_iterator iter = | |
1069 form_structures_.rbegin(); | |
1070 iter != form_structures_.rend(); ++iter) { | |
1071 if (**iter == form) { | |
1072 *form_structure = *iter; | |
1073 | |
1074 // The same form might be cached with multiple field counts: in some | |
1075 // cases, non-autofillable fields are filtered out, whereas in other cases | |
1076 // they are not. To avoid thrashing the cache, keep scanning until we | |
1077 // find a cached version with the same number of fields, if there is one. | |
1078 if ((*iter)->field_count() == form.fields.size()) | |
1079 break; | |
1080 } | |
1081 } | |
1082 | |
1083 if (!(*form_structure)) | |
1084 return false; | |
1085 | |
1086 return true; | |
1087 } | |
1088 | |
1089 bool AutofillManager::GetCachedFormAndField(const FormData& form, | |
1090 const FormFieldData& field, | |
1091 FormStructure** form_structure, | |
1092 AutofillField** autofill_field) { | |
1093 // Find the FormStructure that corresponds to |form|. | |
1094 // If we do not have this form in our cache but it is parseable, we'll add it | |
1095 // in the call to |UpdateCachedForm()|. | |
1096 if (!FindCachedForm(form, form_structure) && | |
1097 !FormStructure(form, GetAutocheckoutURLPrefix()).ShouldBeParsed(false)) { | |
1098 return false; | |
1099 } | |
1100 | |
1101 // Update the cached form to reflect any dynamic changes to the form data, if | |
1102 // necessary. | |
1103 if (!UpdateCachedForm(form, *form_structure, form_structure)) | |
1104 return false; | |
1105 | |
1106 // No data to return if there are no auto-fillable fields. | |
1107 if (!(*form_structure)->autofill_count()) | |
1108 return false; | |
1109 | |
1110 // Find the AutofillField that corresponds to |field|. | |
1111 *autofill_field = NULL; | |
1112 for (std::vector<AutofillField*>::const_iterator iter = | |
1113 (*form_structure)->begin(); | |
1114 iter != (*form_structure)->end(); ++iter) { | |
1115 if ((**iter) == field) { | |
1116 *autofill_field = *iter; | |
1117 break; | |
1118 } | |
1119 } | |
1120 | |
1121 // Even though we always update the cache, the field might not exist if the | |
1122 // website disables autocomplete while the user is interacting with the form. | |
1123 // See http://crbug.com/160476 | |
1124 return *autofill_field != NULL; | |
1125 } | |
1126 | |
1127 bool AutofillManager::UpdateCachedForm(const FormData& live_form, | |
1128 const FormStructure* cached_form, | |
1129 FormStructure** updated_form) { | |
1130 bool needs_update = | |
1131 (!cached_form || | |
1132 live_form.fields.size() != cached_form->field_count()); | |
1133 for (size_t i = 0; !needs_update && i < cached_form->field_count(); ++i) { | |
1134 needs_update = *cached_form->field(i) != live_form.fields[i]; | |
1135 } | |
1136 | |
1137 if (!needs_update) | |
1138 return true; | |
1139 | |
1140 if (form_structures_.size() >= kMaxFormCacheSize) | |
1141 return false; | |
1142 | |
1143 // Add the new or updated form to our cache. | |
1144 form_structures_.push_back( | |
1145 new FormStructure(live_form, GetAutocheckoutURLPrefix())); | |
1146 *updated_form = *form_structures_.rbegin(); | |
1147 (*updated_form)->DetermineHeuristicTypes(*metric_logger_); | |
1148 | |
1149 // If we have cached data, propagate it to the updated form. | |
1150 if (cached_form) { | |
1151 std::map<string16, const AutofillField*> cached_fields; | |
1152 for (size_t i = 0; i < cached_form->field_count(); ++i) { | |
1153 const AutofillField* field = cached_form->field(i); | |
1154 cached_fields[field->unique_name()] = field; | |
1155 } | |
1156 | |
1157 for (size_t i = 0; i < (*updated_form)->field_count(); ++i) { | |
1158 AutofillField* field = (*updated_form)->field(i); | |
1159 std::map<string16, const AutofillField*>::iterator cached_field = | |
1160 cached_fields.find(field->unique_name()); | |
1161 if (cached_field != cached_fields.end()) { | |
1162 field->set_server_type(cached_field->second->server_type()); | |
1163 field->is_autofilled = cached_field->second->is_autofilled; | |
1164 } | |
1165 } | |
1166 | |
1167 // Note: We _must not_ remove the original version of the cached form from | |
1168 // the list of |form_structures_|. Otherwise, we break parsing of the | |
1169 // crowdsourcing server's response to our query. | |
1170 } | |
1171 | |
1172 // Annotate the updated form with its predicted types. | |
1173 std::vector<FormStructure*> forms(1, *updated_form); | |
1174 SendAutofillTypePredictions(forms); | |
1175 | |
1176 return true; | |
1177 } | |
1178 | |
1179 void AutofillManager::GetProfileSuggestions( | |
1180 FormStructure* form, | |
1181 const FormFieldData& field, | |
1182 AutofillFieldType type, | |
1183 std::vector<string16>* values, | |
1184 std::vector<string16>* labels, | |
1185 std::vector<string16>* icons, | |
1186 std::vector<int>* unique_ids) const { | |
1187 std::vector<AutofillFieldType> field_types(form->field_count()); | |
1188 for (size_t i = 0; i < form->field_count(); ++i) { | |
1189 field_types[i] = form->field(i)->type(); | |
1190 } | |
1191 std::vector<GUIDPair> guid_pairs; | |
1192 | |
1193 personal_data_->GetProfileSuggestions( | |
1194 type, field.value, field.is_autofilled, field_types, | |
1195 values, labels, icons, &guid_pairs); | |
1196 | |
1197 for (size_t i = 0; i < guid_pairs.size(); ++i) { | |
1198 unique_ids->push_back(PackGUIDs(GUIDPair(std::string(), 0), | |
1199 guid_pairs[i])); | |
1200 } | |
1201 } | |
1202 | |
1203 void AutofillManager::GetCreditCardSuggestions( | |
1204 const FormFieldData& field, | |
1205 AutofillFieldType type, | |
1206 std::vector<string16>* values, | |
1207 std::vector<string16>* labels, | |
1208 std::vector<string16>* icons, | |
1209 std::vector<int>* unique_ids) const { | |
1210 std::vector<GUIDPair> guid_pairs; | |
1211 personal_data_->GetCreditCardSuggestions( | |
1212 type, field.value, values, labels, icons, &guid_pairs); | |
1213 | |
1214 for (size_t i = 0; i < guid_pairs.size(); ++i) { | |
1215 unique_ids->push_back(PackGUIDs(guid_pairs[i], GUIDPair(std::string(), 0))); | |
1216 } | |
1217 } | |
1218 | |
1219 void AutofillManager::ParseForms(const std::vector<FormData>& forms) { | |
1220 std::vector<FormStructure*> non_queryable_forms; | |
1221 std::string autocheckout_url_prefix = GetAutocheckoutURLPrefix(); | |
1222 for (std::vector<FormData>::const_iterator iter = forms.begin(); | |
1223 iter != forms.end(); ++iter) { | |
1224 scoped_ptr<FormStructure> form_structure( | |
1225 new FormStructure(*iter, autocheckout_url_prefix)); | |
1226 if (!form_structure->ShouldBeParsed(false)) | |
1227 continue; | |
1228 | |
1229 form_structure->DetermineHeuristicTypes(*metric_logger_); | |
1230 | |
1231 // Set aside forms with method GET or author-specified types, so that they | |
1232 // are not included in the query to the server. | |
1233 if (form_structure->ShouldBeCrowdsourced()) | |
1234 form_structures_.push_back(form_structure.release()); | |
1235 else | |
1236 non_queryable_forms.push_back(form_structure.release()); | |
1237 } | |
1238 | |
1239 // If none of the forms were parsed, no use querying the server. | |
1240 if (!form_structures_.empty() && !disable_download_manager_requests_) { | |
1241 download_manager_.StartQueryRequest(form_structures_.get(), | |
1242 *metric_logger_); | |
1243 } | |
1244 | |
1245 for (std::vector<FormStructure*>::const_iterator iter = | |
1246 non_queryable_forms.begin(); | |
1247 iter != non_queryable_forms.end(); ++iter) { | |
1248 form_structures_.push_back(*iter); | |
1249 } | |
1250 | |
1251 if (!form_structures_.empty()) | |
1252 metric_logger_->LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED); | |
1253 | |
1254 // For the |non_queryable_forms|, we have all the field type info we're ever | |
1255 // going to get about them. For the other forms, we'll wait until we get a | |
1256 // response from the server. | |
1257 SendAutofillTypePredictions(non_queryable_forms); | |
1258 } | |
1259 | |
1260 int AutofillManager::GUIDToID(const GUIDPair& guid) const { | |
1261 if (!base::IsValidGUID(guid.first)) | |
1262 return 0; | |
1263 | |
1264 std::map<GUIDPair, int>::const_iterator iter = guid_id_map_.find(guid); | |
1265 if (iter == guid_id_map_.end()) { | |
1266 int id = guid_id_map_.size() + 1; | |
1267 guid_id_map_[guid] = id; | |
1268 id_guid_map_[id] = guid; | |
1269 return id; | |
1270 } else { | |
1271 return iter->second; | |
1272 } | |
1273 } | |
1274 | |
1275 const GUIDPair AutofillManager::IDToGUID(int id) const { | |
1276 if (id == 0) | |
1277 return GUIDPair(std::string(), 0); | |
1278 | |
1279 std::map<int, GUIDPair>::const_iterator iter = id_guid_map_.find(id); | |
1280 if (iter == id_guid_map_.end()) { | |
1281 NOTREACHED(); | |
1282 return GUIDPair(std::string(), 0); | |
1283 } | |
1284 | |
1285 return iter->second; | |
1286 } | |
1287 | |
1288 // When sending IDs (across processes) to the renderer we pack credit card and | |
1289 // profile IDs into a single integer. Credit card IDs are sent in the high | |
1290 // word and profile IDs are sent in the low word. | |
1291 int AutofillManager::PackGUIDs(const GUIDPair& cc_guid, | |
1292 const GUIDPair& profile_guid) const { | |
1293 int cc_id = GUIDToID(cc_guid); | |
1294 int profile_id = GUIDToID(profile_guid); | |
1295 | |
1296 DCHECK(cc_id <= std::numeric_limits<unsigned short>::max()); | |
1297 DCHECK(profile_id <= std::numeric_limits<unsigned short>::max()); | |
1298 | |
1299 return cc_id << std::numeric_limits<unsigned short>::digits | profile_id; | |
1300 } | |
1301 | |
1302 // When receiving IDs (across processes) from the renderer we unpack credit card | |
1303 // and profile IDs from a single integer. Credit card IDs are stored in the | |
1304 // high word and profile IDs are stored in the low word. | |
1305 void AutofillManager::UnpackGUIDs(int id, | |
1306 GUIDPair* cc_guid, | |
1307 GUIDPair* profile_guid) const { | |
1308 int cc_id = id >> std::numeric_limits<unsigned short>::digits & | |
1309 std::numeric_limits<unsigned short>::max(); | |
1310 int profile_id = id & std::numeric_limits<unsigned short>::max(); | |
1311 | |
1312 *cc_guid = IDToGUID(cc_id); | |
1313 *profile_guid = IDToGUID(profile_id); | |
1314 } | |
1315 | |
1316 void AutofillManager::UpdateInitialInteractionTimestamp( | |
1317 const TimeTicks& interaction_timestamp) { | |
1318 if (initial_interaction_timestamp_.is_null() || | |
1319 interaction_timestamp < initial_interaction_timestamp_) { | |
1320 initial_interaction_timestamp_ = interaction_timestamp; | |
1321 } | |
1322 } | |
OLD | NEW |