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