Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: chrome/browser/autofill/form_structure.cc

Issue 7613015: Add preliminary Autofill support for 'autocompletetype' sections. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Precompute credit card vs. address sections Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/form_structure.h" 5 #include "chrome/browser/autofill/form_structure.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 if (autocomplete_type == ASCIIToUTF16("cc-exp-year")) { 214 if (autocomplete_type == ASCIIToUTF16("cc-exp-year")) {
215 if (field.max_length == 2) 215 if (field.max_length == 2)
216 *autofill_type = CREDIT_CARD_EXP_2_DIGIT_YEAR; 216 *autofill_type = CREDIT_CARD_EXP_2_DIGIT_YEAR;
217 else 217 else
218 *autofill_type = CREDIT_CARD_EXP_4_DIGIT_YEAR; 218 *autofill_type = CREDIT_CARD_EXP_4_DIGIT_YEAR;
219 return true; 219 return true;
220 } 220 }
221 221
222 if (autocomplete_type == ASCIIToUTF16("cc-exp")) { 222 if (autocomplete_type == ASCIIToUTF16("cc-exp")) {
223 // TODO(isherman): Choose variant based on HTML5 validation regex. 223 // TODO(isherman): Choose variant based on HTML5 validation regex.
224 *autofill_type = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; 224 *autofill_type = CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
225 return true; 225 return true;
226 } 226 }
227 227
228 return false; 228 return false;
229 } 229 }
230 230
231 // Classifies each field in |fields| based upon its |autocompletetype|
232 // attribute, if the attribute is available. The association is stored into
233 // |map|. Returns |true| if the attribute is available (and non-empty) for at
234 // least one field.
235 bool ParseAutocompletetypeAttributes(const std::vector<AutofillField*>& fields,
236 FieldTypeMap* map) {
237 bool found_attribute = false;
238 for (std::vector<AutofillField*>::const_iterator field = fields.begin();
239 field != fields.end(); ++field) {
240 if ((*field)->autocomplete_type.empty())
241 continue;
242
243 found_attribute = true;
244 std::vector<string16> types;
245 Tokenize((*field)->autocomplete_type, ASCIIToUTF16(" "), &types);
246
247 // TODO(isherman): Handle sections: http://crbug.com/92121
248 for (std::vector<string16>::const_iterator type = types.begin();
249 type != types.end(); ++type) {
250 AutofillFieldType autofill_type = UNKNOWN_TYPE;
251 if (ConvertToAutofillFieldType(**field, *type, &autofill_type)) {
252 map->insert(make_pair((*field)->unique_name(), autofill_type));
253 break;
254 }
255 }
256 }
257
258 return found_attribute;
259 }
260
261 } // namespace 231 } // namespace
262 232
263 FormStructure::FormStructure(const FormData& form) 233 FormStructure::FormStructure(const FormData& form)
264 : form_name_(form.name), 234 : form_name_(form.name),
265 source_url_(form.origin), 235 source_url_(form.origin),
266 target_url_(form.action), 236 target_url_(form.action),
267 autofill_count_(0), 237 autofill_count_(0),
268 upload_required_(USE_UPLOAD_RATES), 238 upload_required_(USE_UPLOAD_RATES),
269 server_experiment_id_("no server response"), 239 server_experiment_id_("no server response"),
270 has_author_specified_types_(false) { 240 has_author_specified_types_(false) {
(...skipping 18 matching lines...) Expand all
289 } else { 259 } else {
290 // Either the method is 'get', or we don't know. In this case we default 260 // Either the method is 'get', or we don't know. In this case we default
291 // to GET. 261 // to GET.
292 method_ = GET; 262 method_ = GET;
293 } 263 }
294 } 264 }
295 265
296 FormStructure::~FormStructure() {} 266 FormStructure::~FormStructure() {}
297 267
298 void FormStructure::DetermineHeuristicTypes() { 268 void FormStructure::DetermineHeuristicTypes() {
299 autofill_count_ = 0;
300
301 FieldTypeMap field_type_map;
302
303 // First, try to detect field types based on the fields' |autocompletetype| 269 // First, try to detect field types based on the fields' |autocompletetype|
304 // attributes. If there is at least one form field with this attribute, don't 270 // attributes. If there is at least one form field with this attribute, don't
305 // try to apply other heuristics to match fields in this form. 271 // try to apply other heuristics to match fields in this form.
306 has_author_specified_types_ = 272 bool found_sections;
307 ParseAutocompletetypeAttributes(fields_.get(), &field_type_map); 273 ParseAutocompletetypeAttributes(&has_author_specified_types_,
308 if (!has_author_specified_types_) 274 &found_sections);
275
276 if (!has_author_specified_types_) {
277 FieldTypeMap field_type_map;
309 FormField::ParseFormFields(fields_.get(), &field_type_map); 278 FormField::ParseFormFields(fields_.get(), &field_type_map);
279 for (size_t index = 0; index < field_count(); index++) {
280 AutofillField* field = fields_[index];
281 FieldTypeMap::iterator iter = field_type_map.find(field->unique_name());
282 if (iter != field_type_map.end())
283 field->set_heuristic_type(iter->second);
284 }
285 }
310 286
311 for (size_t index = 0; index < field_count(); index++) { 287 UpdateAutofillCount();
312 AutofillField* field = fields_[index];
313 FieldTypeMap::iterator iter = field_type_map.find(field->unique_name());
314 288
315 AutofillFieldType heuristic_autofill_type; 289 if (!found_sections)
316 if (iter == field_type_map.end()) { 290 IdentifySections();
317 heuristic_autofill_type = UNKNOWN_TYPE;
318 } else {
319 heuristic_autofill_type = iter->second;
320 ++autofill_count_;
321 }
322 291
323 field->set_heuristic_type(heuristic_autofill_type); 292 // Ensure that credit card and address fields are in separate sections.
293 // This simplifies the section-aware logic in autofill_manager.cc.
294 for (std::vector<AutofillField*>::iterator field = fields_->begin();
295 field != fields_->end(); ++field) {
296 AutofillType::FieldTypeGroup field_type_group =
297 AutofillType((*field)->type()).group();
298 if (field_type_group == AutofillType::CREDIT_CARD)
299 (*field)->set_section((*field)->section() + ASCIIToUTF16("-cc"));
300 else
301 (*field)->set_section((*field)->section() + ASCIIToUTF16("-default"));
324 } 302 }
325 } 303 }
326 304
327 bool FormStructure::EncodeUploadRequest( 305 bool FormStructure::EncodeUploadRequest(
328 const FieldTypeSet& available_field_types, 306 const FieldTypeSet& available_field_types,
329 bool form_was_autofilled, 307 bool form_was_autofilled,
330 std::string* encoded_xml) const { 308 std::string* encoded_xml) const {
331 if (!ShouldBeCrowdsourced()) { 309 if (!ShouldBeCrowdsourced()) {
332 NOTREACHED(); 310 NOTREACHED();
333 return false; 311 return false;
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 } else { 823 } else {
846 buzz::XmlElement *field_element = new buzz::XmlElement( 824 buzz::XmlElement *field_element = new buzz::XmlElement(
847 buzz::QName(kXMLElementField)); 825 buzz::QName(kXMLElementField));
848 field_element->SetAttr(buzz::QName(kAttributeSignature), 826 field_element->SetAttr(buzz::QName(kAttributeSignature),
849 field->FieldSignature()); 827 field->FieldSignature());
850 encompassing_xml_element->AddElement(field_element); 828 encompassing_xml_element->AddElement(field_element);
851 } 829 }
852 } 830 }
853 return true; 831 return true;
854 } 832 }
833
834 void FormStructure::ParseAutocompletetypeAttributes(bool* found_attribute,
835 bool* found_sections) {
836 *found_attribute = false;
837 *found_sections = false;
838 for (std::vector<AutofillField*>::iterator field = fields_->begin();
839 field != fields_->end(); ++field) {
840 if ((*field)->autocomplete_type.empty())
841 continue;
842
843 *found_attribute = true;
844 std::vector<string16> types;
845 Tokenize((*field)->autocomplete_type, ASCIIToUTF16(" "), &types);
846
847 // Look for a named section.
848 const string16 kSectionPrefix = ASCIIToUTF16("section-");
849 if (!types.empty() && StartsWith(types.front(), kSectionPrefix, true)) {
850 *found_sections = true;
851 (*field)->set_section(types.front().substr(kSectionPrefix.size()));
852 }
853
854 // Look for specified types.
855 for (std::vector<string16>::const_iterator type = types.begin();
856 type != types.end(); ++type) {
857 AutofillFieldType autofill_type = UNKNOWN_TYPE;
858 if (ConvertToAutofillFieldType(**field, *type, &autofill_type)) {
859 (*field)->set_heuristic_type(autofill_type);
860 break;
861 }
862 }
863 }
864 }
865
866 void FormStructure::IdentifySections() {
867 if (fields_.empty())
868 return;
869
870 // Name sections after the first field in the section.
871 string16 current_section = fields_->front()->unique_name();
872
873 // Keep track of the types we've seen in this section.
874 std::set<AutofillFieldType> seen_types;
875 AutofillFieldType previous_type = UNKNOWN_TYPE;
876
877 for (std::vector<AutofillField*>::iterator field = fields_->begin();
878 field != fields_->end(); ++field) {
879 const AutofillFieldType current_type =
880 AutofillType::GetEquivalentFieldType((*field)->type());
881
882 bool already_saw_current_type = seen_types.count(current_type) > 0;
883
884 // Forms often ask for multiple phone numbers -- e.g. both a daytime and
885 // evening phone number. Our phone and fax number detection is also
886 // generally a little off. Hence, ignore both field types as a signal here.
887 AutofillType::FieldTypeGroup current_type_group =
888 AutofillType(current_type).group();
889 if (current_type_group == AutofillType::PHONE_HOME ||
890 current_type_group == AutofillType::PHONE_FAX)
891 already_saw_current_type = false;
892
893 // Some forms have adjacent fields of the same type. Two common examples:
894 // * Forms with two email fields, where the second is meant to "confirm"
895 // the first.
896 // * Forms with a <select> menu for states in some countries, and a
897 // freeform <input> field for states in other countries. (Usually, only
898 // one of these two will be visible for any given choice of country.)
899 // Generally, adjacent fields of the same type belong in the same logical
900 // section.
901 if (current_type == previous_type)
902 already_saw_current_type = false;
903
904 previous_type = current_type;
905
906 if (current_type != UNKNOWN_TYPE && already_saw_current_type) {
907 // We reached the end of a section, so start a new section.
908 seen_types.clear();
909 current_section = (*field)->unique_name();
910 }
911
912 seen_types.insert(current_type);
913 (*field)->set_section(current_section);
914 }
915 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698