OLD | NEW |
---|---|
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 Loading... | |
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 relevant field in the given |section| |
197 // The "relevant" fields in |form| are ones corresponding to fields in | 103 // within |form| is auto-filled. If |is_credit_card_section| is true, only |
198 // |form_structure| with indices in the range [section_start, section_end). | 104 // considers credit card fields; otherwise, only considers non-credit card |
105 // fields. | |
199 bool SectionIsAutofilled(const FormStructure* form_structure, | 106 bool SectionIsAutofilled(const FormStructure* form_structure, |
dhollowa
2011/08/11 01:39:46
This kinda hurts my brains. Seems like intermingl
Ilya Sherman
2011/08/11 03:33:48
Done.
| |
200 const webkit_glue::FormData& form, | 107 const webkit_glue::FormData& form, |
201 size_t section_start, | 108 const string16& section, |
202 size_t section_end) { | 109 bool is_credit_card_section) { |
203 // TODO(isherman): It would be nice to share most of this code with the loop | 110 // 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 | 111 // in |OnFillAutofillFormData()|, but I don't see a particularly clean way to |
205 // that. | 112 // do that. |
206 | 113 |
207 // The list of fields in |form_structure| and |form.fields| often match | 114 // The list of fields in |form_structure| and |form.fields| often match |
208 // directly and we can fill these corresponding fields; however, when the | 115 // directly and we can fill these corresponding fields; however, when the |
209 // |form_structure| and |form.fields| do not match directly we search | 116 // |form_structure| and |form.fields| do not match directly we search |
210 // ahead in the |form_structure| for the matching field. | 117 // ahead in the |form_structure| for the matching field. |
211 for (size_t i = section_start, j = 0; | 118 for (size_t i = 0, j = 0; |
212 i < section_end && j < form.fields.size(); | 119 i < form_structure->field_count() && j < form.fields.size(); |
213 j++) { | 120 j++) { |
214 size_t k = i; | 121 size_t k = i; |
215 | 122 |
216 // Search forward in the |form_structure| for a corresponding field. | 123 // Search forward in the |form_structure| for a corresponding field. |
217 while (k < form_structure->field_count() && | 124 while (k < form_structure->field_count() && |
218 *form_structure->field(k) != form.fields[j]) { | 125 (form_structure->field(k)->section() != section || |
126 *form_structure->field(k) != form.fields[j])) { | |
219 k++; | 127 k++; |
220 } | 128 } |
221 | 129 |
222 // If we didn't find a match, continue on to the next |form| field. | 130 // If we didn't find a match, continue on to the next |form| field. |
223 if (k >= form_structure->field_count()) | 131 if (k >= form_structure->field_count()) |
224 continue; | 132 continue; |
225 | 133 |
226 AutofillType autofill_type(form_structure->field(k)->type()); | 134 // We found a matching field in the |form_structure|, so on the next |
135 // iteration we should proceed to the next |form_structure| field. | |
136 ++i; | |
137 | |
138 AutofillFieldType field_type = form_structure->field(k)->type(); | |
139 | |
140 // Fields of unknown type should never be autofilled. | |
141 if (field_type == UNKNOWN_TYPE) | |
142 continue; | |
143 | |
144 // Only consider fields of the relevant type. | |
145 bool is_credit_card_field = | |
146 (AutofillType(field_type).group() == AutofillType::CREDIT_CARD); | |
147 if (is_credit_card_field != is_credit_card_section) | |
148 continue; | |
149 | |
227 if (form.fields[j].is_autofilled) | 150 if (form.fields[j].is_autofilled) |
228 return true; | 151 return true; |
229 | |
230 // We found a matching field in the |form_structure| so we | |
231 // proceed to the next |form| field, and the next |form_structure|. | |
232 ++i; | |
233 } | 152 } |
234 | 153 |
235 return false; | 154 return false; |
236 } | 155 } |
237 | 156 |
238 bool FormIsHTTPS(FormStructure* form) { | 157 bool FormIsHTTPS(FormStructure* form) { |
239 return form->source_url().SchemeIs(chrome::kHttpsScheme); | 158 return form->source_url().SchemeIs(chrome::kHttpsScheme); |
240 } | 159 } |
241 | 160 |
242 // Check for unidentified forms among those with the most query or upload | 161 // Check for unidentified forms among those with the most query or upload |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
488 if (!form_structure->IsAutofillable(true)) | 407 if (!form_structure->IsAutofillable(true)) |
489 warning = IDS_AUTOFILL_WARNING_FORM_DISABLED; | 408 warning = IDS_AUTOFILL_WARNING_FORM_DISABLED; |
490 else if (is_filling_credit_card && !FormIsHTTPS(form_structure)) | 409 else if (is_filling_credit_card && !FormIsHTTPS(form_structure)) |
491 warning = IDS_AUTOFILL_WARNING_INSECURE_CONNECTION; | 410 warning = IDS_AUTOFILL_WARNING_INSECURE_CONNECTION; |
492 if (warning) { | 411 if (warning) { |
493 values.assign(1, l10n_util::GetStringUTF16(warning)); | 412 values.assign(1, l10n_util::GetStringUTF16(warning)); |
494 labels.assign(1, string16()); | 413 labels.assign(1, string16()); |
495 icons.assign(1, string16()); | 414 icons.assign(1, string16()); |
496 unique_ids.assign(1, -1); | 415 unique_ids.assign(1, -1); |
497 } else { | 416 } else { |
498 size_t section_start, section_end; | 417 AutofillType::FieldTypeGroup field_type_group = |
499 FindSectionBounds(*form_structure, *autofill_field, | 418 AutofillType(autofill_field->type()).group(); |
500 is_filling_credit_card, §ion_start, §ion_end); | 419 bool section_is_autofilled = |
501 | 420 SectionIsAutofilled(form_structure, form, |
502 bool section_is_autofilled = SectionIsAutofilled(form_structure, | 421 autofill_field->section(), |
503 form, | 422 field_type_group == AutofillType::CREDIT_CARD); |
504 section_start, | |
505 section_end); | |
506 if (section_is_autofilled) { | 423 if (section_is_autofilled) { |
507 // If the relevant section is auto-filled and the renderer is querying | 424 // 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. | 425 // for suggestions, then the user is editing the value of a field. |
509 // In this case, mimic autocomplete: don't display labels or icons, | 426 // In this case, mimic autocomplete: don't display labels or icons, |
510 // as that information is redundant. | 427 // as that information is redundant. |
511 labels.assign(labels.size(), string16()); | 428 labels.assign(labels.size(), string16()); |
512 icons.assign(icons.size(), string16()); | 429 icons.assign(icons.size(), string16()); |
513 } | 430 } |
514 | 431 |
515 // When filling credit card suggestions, the values and labels are | 432 // When filling credit card suggestions, the values and labels are |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
583 credit_card = *iter; | 500 credit_card = *iter; |
584 break; | 501 break; |
585 } | 502 } |
586 } | 503 } |
587 DCHECK(credit_card); | 504 DCHECK(credit_card); |
588 } | 505 } |
589 | 506 |
590 if (!profile && !credit_card) | 507 if (!profile && !credit_card) |
591 return; | 508 return; |
592 | 509 |
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 §ion_start, §ion_end); | |
597 | |
598 FormData result = form; | 510 FormData result = form; |
599 | 511 |
600 // If the relevant section is auto-filled, we should fill |field| but not the | 512 // If the relevant section is auto-filled, we should fill |field| but not the |
601 // rest of the form. | 513 // rest of the form. |
602 if (SectionIsAutofilled(form_structure, form, section_start, section_end)) { | 514 bool is_credit_card_section = |
515 AutofillType(autofill_field->type()).group() == AutofillType::CREDIT_CARD; | |
516 if (SectionIsAutofilled(form_structure, form, autofill_field->section(), | |
517 is_credit_card_section)) { | |
603 for (std::vector<FormField>::iterator iter = result.fields.begin(); | 518 for (std::vector<FormField>::iterator iter = result.fields.begin(); |
604 iter != result.fields.end(); ++iter) { | 519 iter != result.fields.end(); ++iter) { |
605 if ((*iter) == field) { | 520 if ((*iter) == field) { |
606 AutofillFieldType field_type = autofill_field->type(); | 521 AutofillFieldType field_type = autofill_field->type(); |
607 if (profile) { | 522 if (profile) { |
608 DCHECK_NE(AutofillType::CREDIT_CARD, | 523 DCHECK_NE(AutofillType::CREDIT_CARD, |
609 AutofillType(field_type).group()); | 524 AutofillType(field_type).group()); |
610 FillFormField(profile, field_type, profile_guid.second, &(*iter)); | 525 FillFormField(profile, field_type, profile_guid.second, &(*iter)); |
611 } else { | 526 } else { |
612 DCHECK_EQ(AutofillType::CREDIT_CARD, | 527 DCHECK_EQ(AutofillType::CREDIT_CARD, |
613 AutofillType(field_type).group()); | 528 AutofillType(field_type).group()); |
614 FillCreditCardFormField(credit_card, field_type, &(*iter)); | 529 FillCreditCardFormField(credit_card, field_type, &(*iter)); |
615 } | 530 } |
616 break; | 531 break; |
617 } | 532 } |
618 } | 533 } |
619 | 534 |
620 host->Send(new AutofillMsg_FormDataFilled(host->routing_id(), query_id, | 535 host->Send(new AutofillMsg_FormDataFilled(host->routing_id(), query_id, |
621 result)); | 536 result)); |
622 return; | 537 return; |
623 } | 538 } |
624 | 539 |
625 // The list of fields in |form_structure| and |result.fields| often match | 540 // The list of fields in |form_structure| and |result.fields| often match |
626 // directly and we can fill these corresponding fields; however, when the | 541 // directly and we can fill these corresponding fields; however, when the |
627 // |form_structure| and |result.fields| do not match directly we search | 542 // |form_structure| and |result.fields| do not match directly we search |
628 // ahead in the |form_structure| for the matching field. | 543 // ahead in the |form_structure| for the matching field. |
629 // See unit tests: AutofillManagerTest.FormChangesRemoveField and | 544 // See unit tests: AutofillManagerTest.FormChangesRemoveField and |
630 // AutofillManagerTest.FormChangesAddField for usage. | 545 // AutofillManagerTest.FormChangesAddField for usage. |
631 for (size_t i = section_start, j = 0; | 546 for (size_t i = 0, j = 0; |
632 i < section_end && j < result.fields.size(); | 547 i < form_structure->field_count() && j < result.fields.size(); |
633 j++) { | 548 j++) { |
634 size_t k = i; | 549 size_t k = i; |
635 | 550 |
636 // Search forward in the |form_structure| for a corresponding field. | 551 // Search forward in the |form_structure| for a corresponding field. |
637 while (k < section_end && *form_structure->field(k) != result.fields[j]) { | 552 while (k < form_structure->field_count() && |
553 (form_structure->field(k)->section() != autofill_field->section() || | |
554 *form_structure->field(k) != result.fields[j])) { | |
638 k++; | 555 k++; |
639 } | 556 } |
640 | 557 |
641 // If we've found a match then fill the |result| field with the found | 558 // If we've found a match then fill the |result| field with the found |
642 // field in the |form_structure|. | 559 // field in the |form_structure|. |
643 if (k >= section_end) | 560 if (k >= form_structure->field_count()) |
644 continue; | 561 continue; |
645 | 562 |
646 AutofillFieldType field_type = form_structure->field(k)->type(); | 563 AutofillFieldType field_type = form_structure->field(k)->type(); |
647 FieldTypeGroup field_group_type = AutofillType(field_type).group(); | 564 FieldTypeGroup field_group_type = AutofillType(field_type).group(); |
648 if (field_group_type != AutofillType::NO_GROUP) { | 565 if (field_group_type != AutofillType::NO_GROUP) { |
649 if (profile) { | 566 if (profile && field_group_type != AutofillType::CREDIT_CARD) { |
650 DCHECK_NE(AutofillType::CREDIT_CARD, field_group_type); | |
651 // If the field being filled is the field that the user initiated the | 567 // If the field being filled is the field that the user initiated the |
652 // fill from, then take the multi-profile "variant" into account. | 568 // fill from, then take the multi-profile "variant" into account. |
653 // Otherwise fill with the default (zeroth) variant. | 569 // Otherwise fill with the default (zeroth) variant. |
654 if (result.fields[j] == field) { | 570 if (result.fields[j] == field) { |
655 FillFormField(profile, field_type, profile_guid.second, | 571 FillFormField(profile, field_type, profile_guid.second, |
656 &result.fields[j]); | 572 &result.fields[j]); |
657 } else { | 573 } else { |
658 FillFormField(profile, field_type, 0, &result.fields[j]); | 574 FillFormField(profile, field_type, 0, &result.fields[j]); |
659 } | 575 } |
660 } else { | 576 } else if (credit_card && field_group_type == AutofillType::CREDIT_CARD) { |
661 DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type); | |
662 FillCreditCardFormField(credit_card, field_type, &result.fields[j]); | 577 FillCreditCardFormField(credit_card, field_type, &result.fields[j]); |
663 } | 578 } |
664 } | 579 } |
665 | 580 |
666 // We found a matching field in the |form_structure| so we | 581 // We found a matching field in the |form_structure| so we |
667 // proceed to the next |result| field, and the next |form_structure|. | 582 // proceed to the next |result| field, and the next |form_structure|. |
668 ++i; | 583 ++i; |
669 } | 584 } |
670 | 585 |
671 autofilled_form_signatures_.push_front(form_structure->FormSignature()); | 586 autofilled_form_signatures_.push_front(form_structure->FormSignature()); |
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1170 void AutofillManager::UnpackGUIDs(int id, | 1085 void AutofillManager::UnpackGUIDs(int id, |
1171 GUIDPair* cc_guid, | 1086 GUIDPair* cc_guid, |
1172 GUIDPair* profile_guid) { | 1087 GUIDPair* profile_guid) { |
1173 int cc_id = id >> std::numeric_limits<unsigned short>::digits & | 1088 int cc_id = id >> std::numeric_limits<unsigned short>::digits & |
1174 std::numeric_limits<unsigned short>::max(); | 1089 std::numeric_limits<unsigned short>::max(); |
1175 int profile_id = id & std::numeric_limits<unsigned short>::max(); | 1090 int profile_id = id & std::numeric_limits<unsigned short>::max(); |
1176 | 1091 |
1177 *cc_guid = IDToGUID(cc_id); | 1092 *cc_guid = IDToGUID(cc_id); |
1178 *profile_guid = IDToGUID(profile_id); | 1093 *profile_guid = IDToGUID(profile_id); |
1179 } | 1094 } |
OLD | NEW |