Chromium Code Reviews| 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 |