| 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/name_field.h" | 5 #include "chrome/browser/autofill/name_field.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 11 #include "chrome/browser/autofill/autofill_ecml.h" |
| 11 #include "chrome/browser/autofill/autofill_scanner.h" | 12 #include "chrome/browser/autofill/autofill_scanner.h" |
| 12 #include "chrome/browser/autofill/autofill_type.h" | 13 #include "chrome/browser/autofill/autofill_type.h" |
| 13 #include "grit/autofill_resources.h" | 14 #include "grit/autofill_resources.h" |
| 14 #include "ui/base/l10n/l10n_util.h" | 15 #include "ui/base/l10n/l10n_util.h" |
| 15 | 16 |
| 17 using autofill::GetEcmlPattern; |
| 18 |
| 19 namespace { |
| 20 |
| 21 // A form field that can parse a full name field. |
| 22 class FullNameField : public NameField { |
| 23 public: |
| 24 static FullNameField* Parse(AutofillScanner* scanner); |
| 25 |
| 26 protected: |
| 27 // FormField: |
| 28 virtual bool ClassifyField(FieldTypeMap* map) const OVERRIDE; |
| 29 |
| 30 private: |
| 31 explicit FullNameField(const AutofillField* field); |
| 32 |
| 33 const AutofillField* field_; |
| 34 |
| 35 DISALLOW_COPY_AND_ASSIGN(FullNameField); |
| 36 }; |
| 37 |
| 38 // A form field that can parse a first and last name field. |
| 39 class FirstLastNameField : public NameField { |
| 40 public: |
| 41 static FirstLastNameField* ParseSpecificName(AutofillScanner* scanner); |
| 42 static FirstLastNameField* ParseComponentNames(AutofillScanner* scanner); |
| 43 static FirstLastNameField* ParseEcmlName(AutofillScanner* scanner); |
| 44 static FirstLastNameField* Parse(AutofillScanner* scanner, bool is_ecml); |
| 45 |
| 46 protected: |
| 47 // FormField: |
| 48 virtual bool ClassifyField(FieldTypeMap* map) const OVERRIDE; |
| 49 |
| 50 private: |
| 51 FirstLastNameField(); |
| 52 |
| 53 const AutofillField* first_name_; |
| 54 const AutofillField* middle_name_; // Optional. |
| 55 const AutofillField* last_name_; |
| 56 bool middle_initial_; // True if middle_name_ is a middle initial. |
| 57 |
| 58 DISALLOW_COPY_AND_ASSIGN(FirstLastNameField); |
| 59 }; |
| 60 |
| 61 } // namespace |
| 62 |
| 16 NameField* NameField::Parse(AutofillScanner* scanner, bool is_ecml) { | 63 NameField* NameField::Parse(AutofillScanner* scanner, bool is_ecml) { |
| 17 if (scanner->IsEnd()) | 64 if (scanner->IsEnd()) |
| 18 return NULL; | 65 return NULL; |
| 19 | 66 |
| 20 // Try FirstLastNameField first since it's more specific. | 67 // Try FirstLastNameField first since it's more specific. |
| 21 NameField* field = FirstLastNameField::Parse(scanner, is_ecml); | 68 NameField* field = FirstLastNameField::Parse(scanner, is_ecml); |
| 22 if (!field && !is_ecml) | 69 if (!field && !is_ecml) |
| 23 field = FullNameField::Parse(scanner); | 70 field = FullNameField::Parse(scanner); |
| 24 return field; | 71 return field; |
| 25 } | 72 } |
| 26 | 73 |
| 27 bool FullNameField::GetFieldInfo(FieldTypeMap* field_type_map) const { | 74 // This is overriden in concrete subclasses. |
| 28 return Add(field_type_map, field_, NAME_FULL); | 75 bool NameField::ClassifyField(FieldTypeMap* map) const { |
| 76 return false; |
| 29 } | 77 } |
| 30 | 78 |
| 31 FullNameField* FullNameField::Parse(AutofillScanner* scanner) { | 79 FullNameField* FullNameField::Parse(AutofillScanner* scanner) { |
| 32 // Exclude labels containing the string "username", which typically | 80 // Exclude labels containing the string "username", which typically |
| 33 // denotes a login ID rather than the user's actual name. | 81 // denotes a login ID rather than the user's actual name. |
| 34 const AutofillField* field = scanner->Cursor(); | 82 scanner->SaveCursor(); |
| 35 if (Match(field, l10n_util::GetStringUTF16(IDS_AUTOFILL_USERNAME_RE), false)) | 83 bool is_username = ParseField( |
| 84 scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_USERNAME_RE), NULL); |
| 85 scanner->Rewind(); |
| 86 if (is_username) |
| 36 return NULL; | 87 return NULL; |
| 37 | 88 |
| 38 // Searching for any label containing the word "name" is too general; | 89 // Searching for any label containing the word "name" is too general; |
| 39 // for example, Travelocity_Edit travel profile.html contains a field | 90 // for example, Travelocity_Edit travel profile.html contains a field |
| 40 // "Travel Profile Name". | 91 // "Travel Profile Name". |
| 41 if (ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_RE), | 92 const AutofillField* field = NULL; |
| 42 &field)) | 93 if (ParseField(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_RE), |
| 94 &field)) |
| 43 return new FullNameField(field); | 95 return new FullNameField(field); |
| 44 | 96 |
| 45 return NULL; | 97 return NULL; |
| 46 } | 98 } |
| 47 | 99 |
| 100 bool FullNameField::ClassifyField(FieldTypeMap* map) const { |
| 101 return AddClassification(field_, NAME_FULL, map); |
| 102 } |
| 103 |
| 48 FullNameField::FullNameField(const AutofillField* field) | 104 FullNameField::FullNameField(const AutofillField* field) |
| 49 : field_(field) { | 105 : field_(field) { |
| 50 } | 106 } |
| 51 | 107 |
| 52 bool FirstLastNameField::GetFieldInfo(FieldTypeMap* field_type_map) const { | |
| 53 bool ok = Add(field_type_map, first_name_, NAME_FIRST); | |
| 54 ok = ok && Add(field_type_map, last_name_, NAME_LAST); | |
| 55 AutofillFieldType type = middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE; | |
| 56 ok = ok && Add(field_type_map, middle_name_, type); | |
| 57 return ok; | |
| 58 } | |
| 59 | |
| 60 FirstLastNameField* FirstLastNameField::ParseSpecificName( | 108 FirstLastNameField* FirstLastNameField::ParseSpecificName( |
| 61 AutofillScanner* scanner) { | 109 AutofillScanner* scanner) { |
| 62 // Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html) | 110 // Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html) |
| 63 // have the label "Name" followed by two or three text fields. | 111 // have the label "Name" followed by two or three text fields. |
| 64 scoped_ptr<FirstLastNameField> v(new FirstLastNameField); | 112 scoped_ptr<FirstLastNameField> v(new FirstLastNameField); |
| 65 scanner->SaveCursor(); | 113 scanner->SaveCursor(); |
| 66 | 114 |
| 67 const AutofillField* next; | 115 const AutofillField* next; |
| 68 if (ParseText(scanner, | 116 if (ParseField(scanner, |
| 69 l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_SPECIFIC_RE), | 117 l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_SPECIFIC_RE), |
| 70 &v->first_name_) && | 118 &v->first_name_) && |
| 71 ParseEmptyText(scanner, &next)) { | 119 ParseEmptyLabel(scanner, &next)) { |
| 72 if (ParseEmptyText(scanner, &v->last_name_)) { | 120 if (ParseEmptyLabel(scanner, &v->last_name_)) { |
| 73 // There are three name fields; assume that the middle one is a | 121 // There are three name fields; assume that the middle one is a |
| 74 // middle initial (it is, at least, on SmithsonianCheckout.html). | 122 // middle initial (it is, at least, on SmithsonianCheckout.html). |
| 75 v->middle_name_ = next; | 123 v->middle_name_ = next; |
| 76 v->middle_initial_ = true; | 124 v->middle_initial_ = true; |
| 77 } else { // only two name fields | 125 } else { // only two name fields |
| 78 v->last_name_ = next; | 126 v->last_name_ = next; |
| 79 } | 127 } |
| 80 | 128 |
| 81 return v.release(); | 129 return v.release(); |
| 82 } | 130 } |
| 83 | 131 |
| 84 scanner->Rewind(); | 132 scanner->Rewind(); |
| 85 return NULL; | 133 return NULL; |
| 86 } | 134 } |
| 87 | 135 |
| 88 FirstLastNameField* FirstLastNameField::ParseComponentNames( | 136 FirstLastNameField* FirstLastNameField::ParseComponentNames( |
| 89 AutofillScanner* scanner) { | 137 AutofillScanner* scanner) { |
| 90 scoped_ptr<FirstLastNameField> v(new FirstLastNameField); | 138 scoped_ptr<FirstLastNameField> v(new FirstLastNameField); |
| 91 scanner->SaveCursor(); | 139 scanner->SaveCursor(); |
| 92 | 140 |
| 93 // A fair number of pages use the names "fname" and "lname" for naming | 141 // A fair number of pages use the names "fname" and "lname" for naming |
| 94 // first and last name fields (examples from the test suite: | 142 // first and last name fields (examples from the test suite: |
| 95 // BESTBUY_COM - Sign In2.html; Crate and Barrel Check Out.html; | 143 // BESTBUY_COM - Sign In2.html; Crate and Barrel Check Out.html; |
| 96 // dell_checkout1.html). At least one UK page (The China Shop2.html) | 144 // dell_checkout1.html). At least one UK page (The China Shop2.html) |
| 97 // asks, in stuffy English style, for just initials and a surname, | 145 // asks, in stuffy English style, for just initials and a surname, |
| 98 // so we match "initials" here (and just fill in a first name there, | 146 // so we match "initials" here (and just fill in a first name there, |
| 99 // American-style). | 147 // American-style). |
| 100 // The ".*first$" matches fields ending in "first" (example in sample8.html). | 148 // The ".*first$" matches fields ending in "first" (example in sample8.html). |
| 101 if (!ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_FIRST_NAME_RE), | 149 if (!ParseField(scanner, |
| 102 &v->first_name_)) | 150 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIRST_NAME_RE), |
| 151 &v->first_name_)) { |
| 103 return NULL; | 152 return NULL; |
| 153 } |
| 104 | 154 |
| 105 // We check for a middle initial before checking for a middle name | 155 // We check for a middle initial before checking for a middle name |
| 106 // because at least one page (PC Connection.html) has a field marked | 156 // because at least one page (PC Connection.html) has a field marked |
| 107 // as both (the label text is "MI" and the element name is | 157 // as both (the label text is "MI" and the element name is |
| 108 // "txtmiddlename"); such a field probably actually represents a | 158 // "txtmiddlename"); such a field probably actually represents a |
| 109 // middle initial. | 159 // middle initial. |
| 110 if (ParseText(scanner, | 160 if (ParseField(scanner, |
| 111 l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_INITIAL_RE), | 161 l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_INITIAL_RE), |
| 112 &v->middle_name_)) { | 162 &v->middle_name_)) { |
| 113 v->middle_initial_ = true; | 163 v->middle_initial_ = true; |
| 114 } else { | 164 } else { |
| 115 ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_NAME_RE), | 165 ParseField(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_NAME_RE), |
| 116 &v->middle_name_); | 166 &v->middle_name_); |
| 117 } | 167 } |
| 118 | 168 |
| 119 // The ".*last$" matches fields ending in "last" (example in sample8.html). | 169 // The ".*last$" matches fields ending in "last" (example in sample8.html). |
| 120 if (ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_LAST_NAME_RE), | 170 if (ParseField(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_LAST_NAME_RE), |
| 121 &v->last_name_)) { | 171 &v->last_name_)) { |
| 122 return v.release(); | 172 return v.release(); |
| 123 } | 173 } |
| 124 | 174 |
| 125 scanner->Rewind(); | 175 scanner->Rewind(); |
| 126 return NULL; | 176 return NULL; |
| 127 } | 177 } |
| 128 | 178 |
| 129 FirstLastNameField* FirstLastNameField::ParseEcmlName( | 179 FirstLastNameField* FirstLastNameField::ParseEcmlName( |
| 130 AutofillScanner* scanner) { | 180 AutofillScanner* scanner) { |
| 131 scoped_ptr<FirstLastNameField> field(new FirstLastNameField); | 181 scoped_ptr<FirstLastNameField> field(new FirstLastNameField); |
| 132 scanner->SaveCursor(); | 182 scanner->SaveCursor(); |
| 133 | 183 |
| 134 string16 pattern = GetEcmlPattern(kEcmlShipToFirstName, | 184 string16 pattern = GetEcmlPattern(kEcmlShipToFirstName, |
| 135 kEcmlBillToFirstName, '|'); | 185 kEcmlBillToFirstName, '|'); |
| 136 if (!ParseText(scanner, pattern, &field->first_name_)) | 186 if (!ParseField(scanner, pattern, &field->first_name_)) |
| 137 return NULL; | 187 return NULL; |
| 138 | 188 |
| 139 pattern = GetEcmlPattern(kEcmlShipToMiddleName, kEcmlBillToMiddleName, '|'); | 189 pattern = GetEcmlPattern(kEcmlShipToMiddleName, kEcmlBillToMiddleName, '|'); |
| 140 ParseText(scanner, pattern, &field->middle_name_); | 190 ParseField(scanner, pattern, &field->middle_name_); |
| 141 | 191 |
| 142 pattern = GetEcmlPattern(kEcmlShipToLastName, kEcmlBillToLastName, '|'); | 192 pattern = GetEcmlPattern(kEcmlShipToLastName, kEcmlBillToLastName, '|'); |
| 143 if (ParseText(scanner, pattern, &field->last_name_)) | 193 if (ParseField(scanner, pattern, &field->last_name_)) |
| 144 return field.release(); | 194 return field.release(); |
| 145 | 195 |
| 146 scanner->Rewind(); | 196 scanner->Rewind(); |
| 147 return NULL; | 197 return NULL; |
| 148 } | 198 } |
| 149 | 199 |
| 150 FirstLastNameField* FirstLastNameField::Parse(AutofillScanner* scanner, | 200 FirstLastNameField* FirstLastNameField::Parse(AutofillScanner* scanner, |
| 151 bool is_ecml) { | 201 bool is_ecml) { |
| 152 if (is_ecml) | 202 if (is_ecml) |
| 153 return ParseEcmlName(scanner); | 203 return ParseEcmlName(scanner); |
| 154 | 204 |
| 155 FirstLastNameField* field = ParseSpecificName(scanner); | 205 FirstLastNameField* field = ParseSpecificName(scanner); |
| 156 if (!field) | 206 if (!field) |
| 157 field = ParseComponentNames(scanner); | 207 field = ParseComponentNames(scanner); |
| 158 return field; | 208 return field; |
| 159 } | 209 } |
| 160 | 210 |
| 161 FirstLastNameField::FirstLastNameField() | 211 FirstLastNameField::FirstLastNameField() |
| 162 : first_name_(NULL), | 212 : first_name_(NULL), |
| 163 middle_name_(NULL), | 213 middle_name_(NULL), |
| 164 last_name_(NULL), | 214 last_name_(NULL), |
| 165 middle_initial_(false) { | 215 middle_initial_(false) { |
| 166 } | 216 } |
| 217 |
| 218 bool FirstLastNameField::ClassifyField(FieldTypeMap* map) const { |
| 219 bool ok = AddClassification(first_name_, NAME_FIRST, map); |
| 220 ok = ok && AddClassification(last_name_, NAME_LAST, map); |
| 221 AutofillFieldType type = middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE; |
| 222 ok = ok && AddClassification(middle_name_, type, map); |
| 223 return ok; |
| 224 } |
| OLD | NEW |