Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: chrome/browser/autofill/autofill_manager.cc

Issue 7613015: Add preliminary Autofill support for 'autocompletetype' sections. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Line unwrapping Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autofill/autofill_manager.h" 5 #include "chrome/browser/autofill/autofill_manager.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <map> 10 #include <map>
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 unique_ids_copy.push_back((*unique_ids)[i]); 91 unique_ids_copy.push_back((*unique_ids)[i]);
92 } 92 }
93 } 93 }
94 94
95 values->swap(values_copy); 95 values->swap(values_copy);
96 labels->swap(labels_copy); 96 labels->swap(labels_copy);
97 icons->swap(icons_copy); 97 icons->swap(icons_copy);
98 unique_ids->swap(unique_ids_copy); 98 unique_ids->swap(unique_ids_copy);
99 } 99 }
100 100
101 // Precondition: |form| should be the cached version of the form that is to be
102 // autofilled, and |field| should be the field in the |form| that corresponds to
103 // the initiating field. |is_filling_credit_card| should be true if filling
104 // credit card data, false otherwise.
105 // Fills |section_start| and |section_end| so that [section_start, section_end)
106 // gives the bounds of logical section within |form| that includes |field|.
107 // Logical sections are identified by two heuristics:
108 // 1. The fields in the section must all be profile or credit card fields,
109 // depending on whether |is_filling_credit_card| is true.
110 // 2. A logical section should not include multiple fields of the same autofill
111 // type (except for adjacent repeated fields and phone/fax numbers, as
112 // described below).
113 void FindSectionBounds(const FormStructure& form,
114 const AutofillField& field,
115 bool is_filling_credit_card,
116 size_t* section_start,
117 size_t* section_end) {
118 DCHECK(section_start);
119 DCHECK(section_end);
120
121 // By default, the relevant section is the entire form.
122 *section_start = 0;
123 *section_end = form.field_count();
124
125 std::set<AutofillFieldType> seen_types;
126 bool initiating_field_is_in_current_section = false;
127 AutofillFieldType previous_type = UNKNOWN_TYPE;
128 for (size_t i = 0; i < form.field_count(); ++i) {
129 const AutofillField* current_field = form.field(i);
130 const AutofillFieldType current_type =
131 AutofillType::GetEquivalentFieldType(current_field->type());
132
133 bool already_saw_current_type = seen_types.count(current_type) > 0;
134 // Forms often ask for multiple phone numbers -- e.g. both a daytime and
135 // evening phone number. Our phone and fax number detection is also
136 // generally a little off. Hence, ignore both field types as a signal here.
137 AutofillType::FieldTypeGroup current_type_group =
138 AutofillType(current_type).group();
139 if (current_type_group == AutofillType::PHONE_HOME ||
140 current_type_group == AutofillType::PHONE_FAX)
141 already_saw_current_type = false;
142
143 // Some forms have adjacent fields of the same type. Two common examples:
144 // * Forms with two email fields, where the second is meant to "confirm"
145 // the first.
146 // * Forms with a <select> menu for states in some countries, and a
147 // freeform <input> field for states in other countries. (Usually, only
148 // one of these two will be visible for any given choice of country.)
149 // Generally, adjacent fields of the same type belong in the same logical
150 // section.
151 if (current_type == previous_type)
152 already_saw_current_type = false;
153
154 previous_type = current_type;
155
156 // Fields of unknown type don't help us to distinguish sections.
157 if (current_type == UNKNOWN_TYPE)
158 continue;
159
160 // If we are filling credit card data, the relevant section should include
161 // only credit card fields; and similarly for profile data.
162 bool is_credit_card_field = current_type_group == AutofillType::CREDIT_CARD;
163 bool is_appropriate_type = is_credit_card_field == is_filling_credit_card;
164
165 if (already_saw_current_type || !is_appropriate_type) {
166 if (initiating_field_is_in_current_section) {
167 // We reached the end of the section containing the initiating field.
168 *section_end = i;
169 break;
170 }
171
172 // We reached the end of a section, so start a new section.
173 seen_types.clear();
174
175 // Only include the current field in the new section if it matches the
176 // type of data we are filling.
177 if (is_appropriate_type) {
178 *section_start = i;
179 } else {
180 *section_start = i + 1;
181 continue;
182 }
183 }
184
185 seen_types.insert(current_type);
186
187 if (current_field == &field)
188 initiating_field_is_in_current_section = true;
189 }
190
191 // We should have found the initiating field.
192 DCHECK(initiating_field_is_in_current_section);
193 }
194
195 // Precondition: |form_structure| and |form| should correspond to the same 101 // Precondition: |form_structure| and |form| should correspond to the same
196 // logical form. Returns true if the relevant portion of |form| is auto-filled. 102 // logical form. Returns true if any field in the given |section| within |form|
197 // The "relevant" fields in |form| are ones corresponding to fields in 103 // is auto-filled.
198 // |form_structure| with indices in the range [section_start, section_end).
199 bool SectionIsAutofilled(const FormStructure* form_structure, 104 bool SectionIsAutofilled(const FormStructure* form_structure,
200 const webkit_glue::FormData& form, 105 const webkit_glue::FormData& form,
201 size_t section_start, 106 const string16& section) {
202 size_t section_end) {
203 // TODO(isherman): It would be nice to share most of this code with the loop 107 // TODO(isherman): It would be nice to share most of this code with the loop
204 // in |FillAutofillFormData()|, but I don't see a particularly clean way to do 108 // in |OnFillAutofillFormData()|, but I don't see a particularly clean way to
205 // that. 109 // do that.
206 110
207 // The list of fields in |form_structure| and |form.fields| often match 111 // The list of fields in |form_structure| and |form.fields| often match
208 // directly and we can fill these corresponding fields; however, when the 112 // directly and we can fill these corresponding fields; however, when the
209 // |form_structure| and |form.fields| do not match directly we search 113 // |form_structure| and |form.fields| do not match directly we search
210 // ahead in the |form_structure| for the matching field. 114 // ahead in the |form_structure| for the matching field.
211 for (size_t i = section_start, j = 0; 115 for (size_t i = 0, j = 0;
212 i < section_end && j < form.fields.size(); 116 i < form_structure->field_count() && j < form.fields.size();
213 j++) { 117 j++) {
214 size_t k = i; 118 size_t k = i;
215 119
216 // Search forward in the |form_structure| for a corresponding field. 120 // Search forward in the |form_structure| for a corresponding field.
217 while (k < form_structure->field_count() && 121 while (k < form_structure->field_count() &&
218 *form_structure->field(k) != form.fields[j]) { 122 (form_structure->field(k)->section() != section ||
123 *form_structure->field(k) != form.fields[j])) {
219 k++; 124 k++;
220 } 125 }
221 126
222 // If we didn't find a match, continue on to the next |form| field. 127 // If we didn't find a match, continue on to the next |form| field.
223 if (k >= form_structure->field_count()) 128 if (k >= form_structure->field_count())
224 continue; 129 continue;
225 130
226 AutofillType autofill_type(form_structure->field(k)->type());
227 if (form.fields[j].is_autofilled) 131 if (form.fields[j].is_autofilled)
228 return true; 132 return true;
229 133
230 // We found a matching field in the |form_structure| so we 134 // We found a matching field in the |form_structure|, so on the next
231 // proceed to the next |form| field, and the next |form_structure|. 135 // iteration we should proceed to the next |form_structure| field.
232 ++i; 136 ++i;
233 } 137 }
234 138
235 return false; 139 return false;
236 } 140 }
237 141
238 bool FormIsHTTPS(FormStructure* form) { 142 bool FormIsHTTPS(FormStructure* form) {
239 return form->source_url().SchemeIs(chrome::kHttpsScheme); 143 return form->source_url().SchemeIs(chrome::kHttpsScheme);
240 } 144 }
241 145
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 if (!form_structure->IsAutofillable(true)) 392 if (!form_structure->IsAutofillable(true))
489 warning = IDS_AUTOFILL_WARNING_FORM_DISABLED; 393 warning = IDS_AUTOFILL_WARNING_FORM_DISABLED;
490 else if (is_filling_credit_card && !FormIsHTTPS(form_structure)) 394 else if (is_filling_credit_card && !FormIsHTTPS(form_structure))
491 warning = IDS_AUTOFILL_WARNING_INSECURE_CONNECTION; 395 warning = IDS_AUTOFILL_WARNING_INSECURE_CONNECTION;
492 if (warning) { 396 if (warning) {
493 values.assign(1, l10n_util::GetStringUTF16(warning)); 397 values.assign(1, l10n_util::GetStringUTF16(warning));
494 labels.assign(1, string16()); 398 labels.assign(1, string16());
495 icons.assign(1, string16()); 399 icons.assign(1, string16());
496 unique_ids.assign(1, -1); 400 unique_ids.assign(1, -1);
497 } else { 401 } else {
498 size_t section_start, section_end; 402 bool section_is_autofilled =
499 FindSectionBounds(*form_structure, *autofill_field, 403 SectionIsAutofilled(form_structure, form,
500 is_filling_credit_card, &section_start, &section_end); 404 autofill_field->section());
501
502 bool section_is_autofilled = SectionIsAutofilled(form_structure,
503 form,
504 section_start,
505 section_end);
506 if (section_is_autofilled) { 405 if (section_is_autofilled) {
507 // If the relevant section is auto-filled and the renderer is querying 406 // If the relevant section is auto-filled and the renderer is querying
508 // for suggestions, then the user is editing the value of a field. 407 // for suggestions, then the user is editing the value of a field.
509 // In this case, mimic autocomplete: don't display labels or icons, 408 // In this case, mimic autocomplete: don't display labels or icons,
510 // as that information is redundant. 409 // as that information is redundant.
511 labels.assign(labels.size(), string16()); 410 labels.assign(labels.size(), string16());
512 icons.assign(icons.size(), string16()); 411 icons.assign(icons.size(), string16());
513 } 412 }
514 413
515 // When filling credit card suggestions, the values and labels are 414 // When filling credit card suggestions, the values and labels are
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 credit_card = *iter; 482 credit_card = *iter;
584 break; 483 break;
585 } 484 }
586 } 485 }
587 DCHECK(credit_card); 486 DCHECK(credit_card);
588 } 487 }
589 488
590 if (!profile && !credit_card) 489 if (!profile && !credit_card)
591 return; 490 return;
592 491
593 // Find the section of the form that we are autofilling.
594 size_t section_start, section_end;
595 FindSectionBounds(*form_structure, *autofill_field, (credit_card != NULL),
596 &section_start, &section_end);
597
598 FormData result = form; 492 FormData result = form;
599 493
600 // If the relevant section is auto-filled, we should fill |field| but not the 494 // If the relevant section is auto-filled, we should fill |field| but not the
601 // rest of the form. 495 // rest of the form.
602 if (SectionIsAutofilled(form_structure, form, section_start, section_end)) { 496 if (SectionIsAutofilled(form_structure, form, autofill_field->section())) {
603 for (std::vector<FormField>::iterator iter = result.fields.begin(); 497 for (std::vector<FormField>::iterator iter = result.fields.begin();
604 iter != result.fields.end(); ++iter) { 498 iter != result.fields.end(); ++iter) {
605 if ((*iter) == field) { 499 if ((*iter) == field) {
606 AutofillFieldType field_type = autofill_field->type(); 500 AutofillFieldType field_type = autofill_field->type();
607 if (profile) { 501 if (profile) {
608 DCHECK_NE(AutofillType::CREDIT_CARD, 502 DCHECK_NE(AutofillType::CREDIT_CARD,
609 AutofillType(field_type).group()); 503 AutofillType(field_type).group());
610 FillFormField(profile, field_type, profile_guid.second, &(*iter)); 504 FillFormField(profile, field_type, profile_guid.second, &(*iter));
611 } else { 505 } else {
612 DCHECK_EQ(AutofillType::CREDIT_CARD, 506 DCHECK_EQ(AutofillType::CREDIT_CARD,
613 AutofillType(field_type).group()); 507 AutofillType(field_type).group());
614 FillCreditCardFormField(credit_card, field_type, &(*iter)); 508 FillCreditCardFormField(credit_card, field_type, &(*iter));
615 } 509 }
616 break; 510 break;
617 } 511 }
618 } 512 }
619 513
620 host->Send(new AutofillMsg_FormDataFilled(host->routing_id(), query_id, 514 host->Send(new AutofillMsg_FormDataFilled(host->routing_id(), query_id,
621 result)); 515 result));
622 return; 516 return;
623 } 517 }
624 518
625 // The list of fields in |form_structure| and |result.fields| often match 519 // The list of fields in |form_structure| and |result.fields| often match
626 // directly and we can fill these corresponding fields; however, when the 520 // directly and we can fill these corresponding fields; however, when the
627 // |form_structure| and |result.fields| do not match directly we search 521 // |form_structure| and |result.fields| do not match directly we search
628 // ahead in the |form_structure| for the matching field. 522 // ahead in the |form_structure| for the matching field.
629 // See unit tests: AutofillManagerTest.FormChangesRemoveField and 523 // See unit tests: AutofillManagerTest.FormChangesRemoveField and
630 // AutofillManagerTest.FormChangesAddField for usage. 524 // AutofillManagerTest.FormChangesAddField for usage.
631 for (size_t i = section_start, j = 0; 525 for (size_t i = 0, j = 0;
632 i < section_end && j < result.fields.size(); 526 i < form_structure->field_count() && j < result.fields.size();
633 j++) { 527 j++) {
634 size_t k = i; 528 size_t k = i;
635 529
636 // Search forward in the |form_structure| for a corresponding field. 530 // Search forward in the |form_structure| for a corresponding field.
637 while (k < section_end && *form_structure->field(k) != result.fields[j]) { 531 while (k < form_structure->field_count() &&
532 (form_structure->field(k)->section() != autofill_field->section() ||
533 *form_structure->field(k) != result.fields[j])) {
638 k++; 534 k++;
639 } 535 }
640 536
641 // If we've found a match then fill the |result| field with the found 537 // If we've found a match then fill the |result| field with the found
642 // field in the |form_structure|. 538 // field in the |form_structure|.
643 if (k >= section_end) 539 if (k >= form_structure->field_count())
644 continue; 540 continue;
645 541
646 AutofillFieldType field_type = form_structure->field(k)->type(); 542 AutofillFieldType field_type = form_structure->field(k)->type();
647 FieldTypeGroup field_group_type = AutofillType(field_type).group(); 543 FieldTypeGroup field_group_type = AutofillType(field_type).group();
648 if (field_group_type != AutofillType::NO_GROUP) { 544 if (field_group_type != AutofillType::NO_GROUP) {
649 if (profile) { 545 if (profile) {
650 DCHECK_NE(AutofillType::CREDIT_CARD, field_group_type); 546 DCHECK_NE(AutofillType::CREDIT_CARD, field_group_type);
651 // If the field being filled is the field that the user initiated the 547 // If the field being filled is the field that the user initiated the
652 // fill from, then take the multi-profile "variant" into account. 548 // fill from, then take the multi-profile "variant" into account.
653 // Otherwise fill with the default (zeroth) variant. 549 // Otherwise fill with the default (zeroth) variant.
654 if (result.fields[j] == field) { 550 if (result.fields[j] == field) {
655 FillFormField(profile, field_type, profile_guid.second, 551 FillFormField(profile, field_type, profile_guid.second,
656 &result.fields[j]); 552 &result.fields[j]);
657 } else { 553 } else {
658 FillFormField(profile, field_type, 0, &result.fields[j]); 554 FillFormField(profile, field_type, 0, &result.fields[j]);
659 } 555 }
660 } else { 556 } else {
661 DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type); 557 DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type);
662 FillCreditCardFormField(credit_card, field_type, &result.fields[j]); 558 FillCreditCardFormField(credit_card, field_type, &result.fields[j]);
663 } 559 }
664 } 560 }
665 561
666 // We found a matching field in the |form_structure| so we 562 // We found a matching field in the |form_structure|, so on the next
667 // proceed to the next |result| field, and the next |form_structure|. 563 // iteration we should proceed to the next |form_structure| field.
668 ++i; 564 ++i;
669 } 565 }
670 566
671 autofilled_form_signatures_.push_front(form_structure->FormSignature()); 567 autofilled_form_signatures_.push_front(form_structure->FormSignature());
672 // Only remember the last few forms that we've seen, both to avoid false 568 // Only remember the last few forms that we've seen, both to avoid false
673 // positives and to avoid wasting memory. 569 // positives and to avoid wasting memory.
674 if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember) 570 if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember)
675 autofilled_form_signatures_.pop_back(); 571 autofilled_form_signatures_.pop_back();
676 572
677 host->Send(new AutofillMsg_FormDataFilled( 573 host->Send(new AutofillMsg_FormDataFilled(
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after
1170 void AutofillManager::UnpackGUIDs(int id, 1066 void AutofillManager::UnpackGUIDs(int id,
1171 GUIDPair* cc_guid, 1067 GUIDPair* cc_guid,
1172 GUIDPair* profile_guid) { 1068 GUIDPair* profile_guid) {
1173 int cc_id = id >> std::numeric_limits<unsigned short>::digits & 1069 int cc_id = id >> std::numeric_limits<unsigned short>::digits &
1174 std::numeric_limits<unsigned short>::max(); 1070 std::numeric_limits<unsigned short>::max();
1175 int profile_id = id & std::numeric_limits<unsigned short>::max(); 1071 int profile_id = id & std::numeric_limits<unsigned short>::max();
1176 1072
1177 *cc_guid = IDToGUID(cc_id); 1073 *cc_guid = IDToGUID(cc_id);
1178 *profile_guid = IDToGUID(profile_id); 1074 *profile_guid = IDToGUID(profile_id);
1179 } 1075 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/autofill_manager.h ('k') | chrome/browser/autofill/autofill_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698