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