- add sources.
[platform/framework/web/crosswalk.git] / src / components / autofill / core / browser / name_field.cc
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.
4
5 #include "components/autofill/core/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/core/browser/autofill_regex_constants.h"
12 #include "components/autofill/core/browser/autofill_scanner.h"
13 #include "components/autofill/core/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(ServerFieldTypeMap* 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(ServerFieldTypeMap* 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(ServerFieldTypeMap* 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(ServerFieldTypeMap* 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(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);
214   return ok;
215 }
216
217 }  // namespace autofill