1 // Copyright 2013 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.
5 #include "components/autofill/core/browser/name_field.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/autofill/core/browser/autofill_regex_constants.h"
11 #include "components/autofill/core/browser/autofill_scanner.h"
12 #include "components/autofill/core/browser/autofill_type.h"
13 #include "ui/base/l10n/l10n_util.h"
15 using base::UTF8ToUTF16;
20 // A form field that can parse a full name field.
21 class FullNameField : public NameField {
23 static FullNameField* Parse(AutofillScanner* scanner);
27 bool ClassifyField(ServerFieldTypeMap* map) const override;
30 explicit FullNameField(AutofillField* field);
32 AutofillField* field_;
34 DISALLOW_COPY_AND_ASSIGN(FullNameField);
37 // A form field that can parse a first and last name field.
38 class FirstLastNameField : public NameField {
40 static FirstLastNameField* ParseSpecificName(AutofillScanner* scanner);
41 static FirstLastNameField* ParseComponentNames(AutofillScanner* scanner);
42 static FirstLastNameField* Parse(AutofillScanner* scanner);
46 bool ClassifyField(ServerFieldTypeMap* map) const override;
51 AutofillField* first_name_;
52 AutofillField* middle_name_; // Optional.
53 AutofillField* last_name_;
54 bool middle_initial_; // True if middle_name_ is a middle initial.
56 DISALLOW_COPY_AND_ASSIGN(FirstLastNameField);
61 FormField* NameField::Parse(AutofillScanner* scanner) {
65 // Try FirstLastNameField first since it's more specific.
66 NameField* field = FirstLastNameField::Parse(scanner);
68 field = FullNameField::Parse(scanner);
72 // This is overriden in concrete subclasses.
73 bool NameField::ClassifyField(ServerFieldTypeMap* map) const {
77 FullNameField* FullNameField::Parse(AutofillScanner* scanner) {
78 // Exclude e.g. "username" or "nickname" fields.
79 scanner->SaveCursor();
80 bool should_ignore = ParseField(scanner,
81 UTF8ToUTF16(autofill::kNameIgnoredRe), NULL);
86 // Searching for any label containing the word "name" is too general;
87 // for example, Travelocity_Edit travel profile.html contains a field
88 // "Travel Profile Name".
89 AutofillField* field = NULL;
90 if (ParseField(scanner, UTF8ToUTF16(autofill::kNameRe), &field))
91 return new FullNameField(field);
96 bool FullNameField::ClassifyField(ServerFieldTypeMap* map) const {
97 return AddClassification(field_, NAME_FULL, map);
100 FullNameField::FullNameField(AutofillField* field) : field_(field) {
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();
110 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;
130 FirstLastNameField* FirstLastNameField::ParseComponentNames(
131 AutofillScanner* scanner) {
132 scoped_ptr<FirstLastNameField> v(new FirstLastNameField);
133 scanner->SaveCursor();
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,
142 // The ".*first$" matches fields ending in "first" (example in sample8.html).
143 // The ".*last$" matches fields ending in "last" (example in sample8.html).
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)) {
153 if (!v->first_name_ &&
154 ParseField(scanner, UTF8ToUTF16(autofill::kFirstNameRe),
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
164 if (!v->middle_name_ &&
165 ParseField(scanner, UTF8ToUTF16(autofill::kMiddleInitialRe),
167 v->middle_initial_ = true;
171 if (!v->middle_name_ &&
172 ParseField(scanner, UTF8ToUTF16(autofill::kMiddleNameRe),
177 if (!v->last_name_ &&
178 ParseField(scanner, UTF8ToUTF16(autofill::kLastNameRe),
186 // Consider the match to be successful if we detected both first and last name
188 if (v->first_name_ && v->last_name_)
195 FirstLastNameField* FirstLastNameField::Parse(AutofillScanner* scanner) {
196 FirstLastNameField* field = ParseSpecificName(scanner);
198 field = ParseComponentNames(scanner);
202 FirstLastNameField::FirstLastNameField()
206 middle_initial_(false) {
209 bool FirstLastNameField::ClassifyField(ServerFieldTypeMap* map) const {
210 bool ok = AddClassification(first_name_, NAME_FIRST, map);
211 ok = ok && AddClassification(last_name_, NAME_LAST, map);
212 ServerFieldType type = middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE;
213 ok = ok && AddClassification(middle_name_, type, map);
217 } // namespace autofill