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"
14 using base::UTF8ToUTF16
;
19 // A form field that can parse a full name field.
20 class FullNameField
: public NameField
{
22 static scoped_ptr
<FullNameField
> Parse(AutofillScanner
* scanner
);
26 bool ClassifyField(ServerFieldTypeMap
* map
) const override
;
29 explicit FullNameField(AutofillField
* field
);
31 AutofillField
* field_
;
33 DISALLOW_COPY_AND_ASSIGN(FullNameField
);
36 // A form field that can parse a first and last name field.
37 class FirstLastNameField
: public NameField
{
39 static scoped_ptr
<FirstLastNameField
> ParseSpecificName(
40 AutofillScanner
* scanner
);
41 static scoped_ptr
<FirstLastNameField
> ParseComponentNames(
42 AutofillScanner
* scanner
);
43 static scoped_ptr
<FirstLastNameField
> Parse(AutofillScanner
* scanner
);
47 bool ClassifyField(ServerFieldTypeMap
* map
) const override
;
52 AutofillField
* first_name_
;
53 AutofillField
* middle_name_
; // Optional.
54 AutofillField
* last_name_
;
55 bool middle_initial_
; // True if middle_name_ is a middle initial.
57 DISALLOW_COPY_AND_ASSIGN(FirstLastNameField
);
63 scoped_ptr
<FormField
> NameField::Parse(AutofillScanner
* scanner
) {
67 // Try FirstLastNameField first since it's more specific.
68 scoped_ptr
<FormField
> field
= FirstLastNameField::Parse(scanner
);
70 field
= FullNameField::Parse(scanner
);
74 // This is overriden in concrete subclasses.
75 bool NameField::ClassifyField(ServerFieldTypeMap
* map
) const {
80 scoped_ptr
<FullNameField
> FullNameField::Parse(AutofillScanner
* scanner
) {
81 // Exclude e.g. "username" or "nickname" fields.
82 scanner
->SaveCursor();
83 bool should_ignore
= ParseField(scanner
, UTF8ToUTF16(kNameIgnoredRe
), NULL
);
88 // Searching for any label containing the word "name" is too general;
89 // for example, Travelocity_Edit travel profile.html contains a field
90 // "Travel Profile Name".
91 AutofillField
* field
= NULL
;
92 if (ParseField(scanner
, UTF8ToUTF16(kNameRe
), &field
))
93 return make_scoped_ptr(new FullNameField(field
));
98 bool FullNameField::ClassifyField(ServerFieldTypeMap
* map
) const {
99 return AddClassification(field_
, NAME_FULL
, map
);
102 FullNameField::FullNameField(AutofillField
* field
) : field_(field
) {
105 scoped_ptr
<FirstLastNameField
> FirstLastNameField::ParseSpecificName(
106 AutofillScanner
* scanner
) {
107 // Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html)
108 // have the label "Name" followed by two or three text fields.
109 scoped_ptr
<FirstLastNameField
> v(new FirstLastNameField
);
110 scanner
->SaveCursor();
112 AutofillField
* next
= NULL
;
113 if (ParseField(scanner
, UTF8ToUTF16(kNameSpecificRe
), &v
->first_name_
) &&
114 ParseEmptyLabel(scanner
, &next
)) {
115 if (ParseEmptyLabel(scanner
, &v
->last_name_
)) {
116 // There are three name fields; assume that the middle one is a
117 // middle initial (it is, at least, on SmithsonianCheckout.html).
118 v
->middle_name_
= next
;
119 v
->middle_initial_
= true;
120 } else { // only two name fields
121 v
->last_name_
= next
;
132 scoped_ptr
<FirstLastNameField
> FirstLastNameField::ParseComponentNames(
133 AutofillScanner
* scanner
) {
134 scoped_ptr
<FirstLastNameField
> v(new FirstLastNameField
);
135 scanner
->SaveCursor();
137 // A fair number of pages use the names "fname" and "lname" for naming
138 // first and last name fields (examples from the test suite:
139 // BESTBUY_COM - Sign In2.html; Crate and Barrel Check Out.html;
140 // dell_checkout1.html). At least one UK page (The China Shop2.html)
141 // asks, in stuffy English style, for just initials and a surname,
142 // so we match "initials" here (and just fill in a first name there,
144 // The ".*first$" matches fields ending in "first" (example in sample8.html).
145 // The ".*last$" matches fields ending in "last" (example in sample8.html).
147 // Allow name fields to appear in any order.
148 while (!scanner
->IsEnd()) {
149 // Skip over any unrelated fields, e.g. "username" or "nickname".
150 if (ParseFieldSpecifics(scanner
, UTF8ToUTF16(kNameIgnoredRe
),
151 MATCH_DEFAULT
| MATCH_SELECT
, NULL
)) {
155 if (!v
->first_name_
&&
156 ParseField(scanner
, UTF8ToUTF16(kFirstNameRe
), &v
->first_name_
)) {
160 // We check for a middle initial before checking for a middle name
161 // because at least one page (PC Connection.html) has a field marked
162 // as both (the label text is "MI" and the element name is
163 // "txtmiddlename"); such a field probably actually represents a
165 if (!v
->middle_name_
&&
166 ParseField(scanner
, UTF8ToUTF16(kMiddleInitialRe
), &v
->middle_name_
)) {
167 v
->middle_initial_
= true;
171 if (!v
->middle_name_
&&
172 ParseField(scanner
, UTF8ToUTF16(kMiddleNameRe
), &v
->middle_name_
)) {
176 if (!v
->last_name_
&&
177 ParseField(scanner
, UTF8ToUTF16(kLastNameRe
), &v
->last_name_
)) {
184 // Consider the match to be successful if we detected both first and last name
186 if (v
->first_name_
&& v
->last_name_
)
194 scoped_ptr
<FirstLastNameField
> FirstLastNameField::Parse(
195 AutofillScanner
* scanner
) {
196 scoped_ptr
<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