Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "components/autofill/core/browser/form_structure.h" | 5 #include "components/autofill/core/browser/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/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 const char kAcceptedFeaturesExperiment[] = "e"; // e=experiments | 50 const char kAcceptedFeaturesExperiment[] = "e"; // e=experiments |
| 51 const char kAcceptedFeaturesAutocheckoutExperiment[] = "a,e"; // a=autocheckout | 51 const char kAcceptedFeaturesAutocheckoutExperiment[] = "a,e"; // a=autocheckout |
| 52 const char kClientVersion[] = "6.1.1715.1442/en (GGLL)"; | 52 const char kClientVersion[] = "6.1.1715.1442/en (GGLL)"; |
| 53 const char kXMLDeclaration[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; | 53 const char kXMLDeclaration[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; |
| 54 const char kXMLElementAutofillQuery[] = "autofillquery"; | 54 const char kXMLElementAutofillQuery[] = "autofillquery"; |
| 55 const char kXMLElementAutofillUpload[] = "autofillupload"; | 55 const char kXMLElementAutofillUpload[] = "autofillupload"; |
| 56 const char kXMLElementFieldAssignments[] = "fieldassignments"; | 56 const char kXMLElementFieldAssignments[] = "fieldassignments"; |
| 57 const char kXMLElementField[] = "field"; | 57 const char kXMLElementField[] = "field"; |
| 58 const char kXMLElementFields[] = "fields"; | 58 const char kXMLElementFields[] = "fields"; |
| 59 const char kXMLElementForm[] = "form"; | 59 const char kXMLElementForm[] = "form"; |
| 60 const char kBillingSection[] = "billing"; | 60 const char kBillingMode[] = "billing"; |
| 61 const char kShippingSection[] = "shipping"; | 61 const char kShippingMode[] = "shipping"; |
| 62 | 62 |
| 63 // Stip away >= 5 consecutive digits. | 63 // Stip away >= 5 consecutive digits. |
| 64 const char kIgnorePatternInFieldName[] = "\\d{5,}+"; | 64 const char kIgnorePatternInFieldName[] = "\\d{5,}+"; |
| 65 | 65 |
| 66 // Helper for |EncodeUploadRequest()| that creates a bit field corresponding to | 66 // Helper for |EncodeUploadRequest()| that creates a bit field corresponding to |
| 67 // |available_field_types| and returns the hex representation as a string. | 67 // |available_field_types| and returns the hex representation as a string. |
| 68 std::string EncodeFieldTypes(const NativeFieldTypeSet& available_field_types) { | 68 std::string EncodeFieldTypes(const NativeFieldTypeSet& available_field_types) { |
| 69 // There are |MAX_VALID_FIELD_TYPE| different field types and 8 bits per byte, | 69 // There are |MAX_VALID_FIELD_TYPE| different field types and 8 bits per byte, |
| 70 // so we need ceil(MAX_VALID_FIELD_TYPE / 8) bytes to encode the bit field. | 70 // so we need ceil(MAX_VALID_FIELD_TYPE / 8) bytes to encode the bit field. |
| 71 const size_t kNumBytes = (MAX_VALID_FIELD_TYPE + 0x7) / 8; | 71 const size_t kNumBytes = (MAX_VALID_FIELD_TYPE + 0x7) / 8; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 // specified in the implementation section of http://is.gd/whatwg_autocomplete | 158 // specified in the implementation section of http://is.gd/whatwg_autocomplete |
| 159 // Note that "fax" and "pager" are intentionally ignored, as Chrome does not | 159 // Note that "fax" and "pager" are intentionally ignored, as Chrome does not |
| 160 // support filling either type of information. | 160 // support filling either type of information. |
| 161 bool IsContactTypeHint(const std::string& token) { | 161 bool IsContactTypeHint(const std::string& token) { |
| 162 return token == "home" || token == "work" || token == "mobile"; | 162 return token == "home" || token == "work" || token == "mobile"; |
| 163 } | 163 } |
| 164 | 164 |
| 165 // Returns |true| iff the |token| is a type hint appropriate for a field of the | 165 // Returns |true| iff the |token| is a type hint appropriate for a field of the |
| 166 // given |field_type|, as specified in the implementation section of | 166 // given |field_type|, as specified in the implementation section of |
| 167 // http://is.gd/whatwg_autocomplete | 167 // http://is.gd/whatwg_autocomplete |
| 168 // TODO(isherman): This should use HTML field types, not native ones. | |
| 169 bool ContactTypeHintMatchesFieldType(const std::string& token, | 168 bool ContactTypeHintMatchesFieldType(const std::string& token, |
| 170 NativeFieldType field_type) { | 169 HtmlFieldType field_type) { |
| 171 // The "home" and "work" type hints are only appropriate for email and phone | 170 // The "home" and "work" type hints are only appropriate for email and phone |
| 172 // number field types. | 171 // number field types. |
| 173 if (token == "home" || token == "work") { | 172 if (token == "home" || token == "work") { |
| 174 return field_type == EMAIL_ADDRESS || | 173 return field_type == HTML_TYPE_EMAIL || |
| 175 (field_type >= PHONE_HOME_NUMBER && | 174 (field_type >= HTML_TYPE_TEL && |
| 176 field_type <= PHONE_HOME_WHOLE_NUMBER); | 175 field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX); |
| 177 } | 176 } |
| 178 | 177 |
| 179 // The "mobile" type hint is only appropriate for phone number field types. | 178 // The "mobile" type hint is only appropriate for phone number field types. |
| 180 // Note that "fax" and "pager" are intentionally ignored, as Chrome does not | 179 // Note that "fax" and "pager" are intentionally ignored, as Chrome does not |
| 181 // support filling either type of information. | 180 // support filling either type of information. |
| 182 if (token == "mobile") { | 181 if (token == "mobile") { |
| 183 return field_type >= PHONE_HOME_NUMBER && | 182 return field_type >= HTML_TYPE_TEL && |
| 184 field_type <= PHONE_HOME_WHOLE_NUMBER; | 183 field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX; |
| 185 } | 184 } |
| 186 | 185 |
| 187 return false; | 186 return false; |
| 188 } | 187 } |
| 189 | 188 |
| 190 // Returns the Chrome Autofill-supported field type corresponding to the given | 189 // Returns the Chrome Autofill-supported field type corresponding to the given |
| 191 // |autocomplete_type|, if there is one, in the context of the given |field|. | 190 // |autocomplete_type|, if there is one, in the context of the given |field|. |
| 192 // Chrome Autofill supports a subset of the field types listed at | 191 // Chrome Autofill supports a subset of the field types listed at |
| 193 // http://is.gd/whatwg_autocomplete | 192 // http://is.gd/whatwg_autocomplete |
| 194 // TODO(isherman): This should use HTML field types, not native ones. | 193 HtmlFieldType FieldTypeFromAutocompleteType( |
|
Evan Stade
2013/08/05 18:47:24
maybe you should rename this to FieldTypeFromAutoc
Ilya Sherman
2013/08/06 05:05:39
Done.
| |
| 195 NativeFieldType FieldTypeFromAutocompleteType( | |
| 196 const std::string& autocomplete_type, | 194 const std::string& autocomplete_type, |
| 197 const AutofillField& field) { | 195 const AutofillField& field) { |
| 198 if (autocomplete_type == "name") | 196 if (autocomplete_type == "name") |
| 199 return NAME_FULL; | 197 return HTML_TYPE_NAME; |
| 200 | 198 |
| 201 if (autocomplete_type == "given-name") | 199 if (autocomplete_type == "given-name") |
| 202 return NAME_FIRST; | 200 return HTML_TYPE_GIVEN_NAME; |
| 203 | 201 |
| 204 if (autocomplete_type == "additional-name") { | 202 if (autocomplete_type == "additional-name") { |
| 205 if (field.max_length == 1) | 203 if (field.max_length == 1) |
| 206 return NAME_MIDDLE_INITIAL; | 204 return HTML_TYPE_ADDITIONAL_NAME_INITIAL; |
| 207 else | 205 else |
| 208 return NAME_MIDDLE; | 206 return HTML_TYPE_ADDITIONAL_NAME; |
| 209 } | 207 } |
| 210 | 208 |
| 211 if (autocomplete_type == "family-name") | 209 if (autocomplete_type == "family-name") |
| 212 return NAME_LAST; | 210 return HTML_TYPE_FAMILY_NAME; |
| 213 | |
| 214 if (autocomplete_type == "honorific-suffix") | |
| 215 return NAME_SUFFIX; | |
| 216 | 211 |
| 217 if (autocomplete_type == "organization") | 212 if (autocomplete_type == "organization") |
| 218 return COMPANY_NAME; | 213 return HTML_TYPE_ORGANIZATION; |
| 214 | |
| 215 if (autocomplete_type == "street-address") | |
| 216 return HTML_TYPE_STREET_ADDRESS; | |
| 219 | 217 |
| 220 if (autocomplete_type == "address-line1") | 218 if (autocomplete_type == "address-line1") |
| 221 return ADDRESS_HOME_LINE1; | 219 return HTML_TYPE_ADDRESS_LINE1; |
| 222 | 220 |
| 223 if (autocomplete_type == "address-line2") | 221 if (autocomplete_type == "address-line2") |
| 224 return ADDRESS_HOME_LINE2; | 222 return HTML_TYPE_ADDRESS_LINE2; |
| 225 | 223 |
| 226 if (autocomplete_type == "locality") | 224 if (autocomplete_type == "locality") |
| 227 return ADDRESS_HOME_CITY; | 225 return HTML_TYPE_LOCALITY; |
| 228 | 226 |
| 229 if (autocomplete_type == "region") | 227 if (autocomplete_type == "region") |
| 230 return ADDRESS_HOME_STATE; | 228 return HTML_TYPE_REGION; |
| 231 | 229 |
| 232 if (autocomplete_type == "country") | 230 if (autocomplete_type == "country") |
| 233 return ADDRESS_HOME_COUNTRY; | 231 return HTML_TYPE_COUNTRY_CODE; |
| 232 | |
| 233 if (autocomplete_type == "country-name") | |
| 234 return HTML_TYPE_COUNTRY_NAME; | |
| 234 | 235 |
| 235 if (autocomplete_type == "postal-code") | 236 if (autocomplete_type == "postal-code") |
| 236 return ADDRESS_HOME_ZIP; | 237 return HTML_TYPE_POSTAL_CODE; |
| 237 | 238 |
| 238 if (autocomplete_type == "cc-name") | 239 if (autocomplete_type == "cc-name") |
| 239 return CREDIT_CARD_NAME; | 240 return HTML_TYPE_CREDIT_CARD_NAME; |
| 240 | 241 |
| 241 if (autocomplete_type == "cc-number") | 242 if (autocomplete_type == "cc-number") |
| 242 return CREDIT_CARD_NUMBER; | 243 return HTML_TYPE_CREDIT_CARD_NUMBER; |
| 243 | 244 |
| 244 if (autocomplete_type == "cc-exp") { | 245 if (autocomplete_type == "cc-exp") { |
| 245 if (field.max_length == 5) | 246 if (field.max_length == 5) |
| 246 return CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; | 247 return HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; |
| 247 else | 248 else |
| 248 return CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR; | 249 return HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR; |
| 249 } | 250 } |
| 250 | 251 |
| 251 if (autocomplete_type == "cc-exp-month") | 252 if (autocomplete_type == "cc-exp-month") |
| 252 return CREDIT_CARD_EXP_MONTH; | 253 return HTML_TYPE_CREDIT_CARD_EXP_MONTH; |
| 253 | 254 |
| 254 if (autocomplete_type == "cc-exp-year") { | 255 if (autocomplete_type == "cc-exp-year") { |
| 255 if (field.max_length == 2) | 256 if (field.max_length == 2) |
| 256 return CREDIT_CARD_EXP_2_DIGIT_YEAR; | 257 return HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR; |
| 257 else | 258 else |
| 258 return CREDIT_CARD_EXP_4_DIGIT_YEAR; | 259 return HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR; |
| 259 } | 260 } |
| 260 | 261 |
| 261 if (autocomplete_type == "cc-csc") | 262 if (autocomplete_type == "cc-csc") |
| 262 return CREDIT_CARD_VERIFICATION_CODE; | 263 return HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE; |
| 263 | 264 |
| 264 if (autocomplete_type == "cc-type") | 265 if (autocomplete_type == "cc-type") |
| 265 return CREDIT_CARD_TYPE; | 266 return HTML_TYPE_CREDIT_CARD_TYPE; |
| 266 | 267 |
| 267 if (autocomplete_type == "tel") | 268 if (autocomplete_type == "tel") |
| 268 return PHONE_HOME_WHOLE_NUMBER; | 269 return HTML_TYPE_TEL; |
| 269 | 270 |
| 270 if (autocomplete_type == "tel-country-code") | 271 if (autocomplete_type == "tel-country-code") |
| 271 return PHONE_HOME_COUNTRY_CODE; | 272 return HTML_TYPE_TEL_COUNTRY_CODE; |
| 272 | 273 |
| 273 if (autocomplete_type == "tel-national") | 274 if (autocomplete_type == "tel-national") |
| 274 return PHONE_HOME_CITY_AND_NUMBER; | 275 return HTML_TYPE_TEL_NATIONAL; |
| 275 | 276 |
| 276 if (autocomplete_type == "tel-area-code") | 277 if (autocomplete_type == "tel-area-code") |
| 277 return PHONE_HOME_CITY_CODE; | 278 return HTML_TYPE_TEL_AREA_CODE; |
| 278 | 279 |
| 279 if (autocomplete_type == "tel-local") | 280 if (autocomplete_type == "tel-local") |
| 280 return PHONE_HOME_NUMBER; | 281 return HTML_TYPE_TEL_LOCAL; |
| 281 | 282 |
| 282 if (autocomplete_type == "tel-local-prefix") | 283 if (autocomplete_type == "tel-local-prefix") |
| 283 return PHONE_HOME_NUMBER; | 284 return HTML_TYPE_TEL_LOCAL_PREFIX; |
| 284 | 285 |
| 285 if (autocomplete_type == "tel-local-suffix") | 286 if (autocomplete_type == "tel-local-suffix") |
| 286 return PHONE_HOME_NUMBER; | 287 return HTML_TYPE_TEL_LOCAL_SUFFIX; |
| 287 | 288 |
| 288 if (autocomplete_type == "email") | 289 if (autocomplete_type == "email") |
| 289 return EMAIL_ADDRESS; | 290 return HTML_TYPE_EMAIL; |
| 290 | 291 |
| 291 return UNKNOWN_TYPE; | 292 return HTML_TYPE_UNKNOWN; |
| 292 } | 293 } |
| 293 | 294 |
| 294 std::string StripDigitsIfRequired(const base::string16& input) { | 295 std::string StripDigitsIfRequired(const base::string16& input) { |
| 295 UErrorCode status = U_ZERO_ERROR; | 296 UErrorCode status = U_ZERO_ERROR; |
| 296 CR_DEFINE_STATIC_LOCAL(icu::UnicodeString, icu_pattern, | 297 CR_DEFINE_STATIC_LOCAL(icu::UnicodeString, icu_pattern, |
| 297 (kIgnorePatternInFieldName)); | 298 (kIgnorePatternInFieldName)); |
| 298 CR_DEFINE_STATIC_LOCAL(icu::RegexMatcher, matcher, | 299 CR_DEFINE_STATIC_LOCAL(icu::RegexMatcher, matcher, |
| 299 (icu_pattern, UREGEX_CASE_INSENSITIVE, status)); | 300 (icu_pattern, UREGEX_CASE_INSENSITIVE, status)); |
| 300 DCHECK_EQ(status, U_ZERO_ERROR); | 301 DCHECK_EQ(status, U_ZERO_ERROR); |
| 301 | 302 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 | 371 |
| 371 FormStructure::~FormStructure() {} | 372 FormStructure::~FormStructure() {} |
| 372 | 373 |
| 373 void FormStructure::DetermineHeuristicTypes( | 374 void FormStructure::DetermineHeuristicTypes( |
| 374 const AutofillMetrics& metric_logger) { | 375 const AutofillMetrics& metric_logger) { |
| 375 // First, try to detect field types based on each field's |autocomplete| | 376 // First, try to detect field types based on each field's |autocomplete| |
| 376 // attribute value. If there is at least one form field that specifies an | 377 // attribute value. If there is at least one form field that specifies an |
| 377 // autocomplete type hint, don't try to apply other heuristics to match fields | 378 // autocomplete type hint, don't try to apply other heuristics to match fields |
| 378 // in this form. | 379 // in this form. |
| 379 bool has_author_specified_sections; | 380 bool has_author_specified_sections; |
| 380 ParseFieldTypesFromAutocompleteAttributes(PARSE_FOR_AUTOFILL, | 381 ParseFieldTypesFromAutocompleteAttributes(&has_author_specified_types_, |
| 381 &has_author_specified_types_, | |
| 382 &has_author_specified_sections); | 382 &has_author_specified_sections); |
| 383 | 383 |
| 384 if (!has_author_specified_types_) { | 384 if (!has_author_specified_types_) { |
| 385 NativeFieldTypeMap field_type_map; | 385 NativeFieldTypeMap field_type_map; |
| 386 FormField::ParseFormFields(fields_.get(), &field_type_map); | 386 FormField::ParseFormFields(fields_.get(), &field_type_map); |
| 387 for (size_t i = 0; i < field_count(); ++i) { | 387 for (size_t i = 0; i < field_count(); ++i) { |
| 388 AutofillField* field = fields_[i]; | 388 AutofillField* field = fields_[i]; |
| 389 NativeFieldTypeMap::iterator iter = | 389 NativeFieldTypeMap::iterator iter = |
| 390 field_type_map.find(field->unique_name()); | 390 field_type_map.find(field->unique_name()); |
| 391 if (iter != field_type_map.end()) | 391 if (iter != field_type_map.end()) |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 break; | 600 break; |
| 601 | 601 |
| 602 // UNKNOWN_TYPE is reserved for use by the client. | 602 // UNKNOWN_TYPE is reserved for use by the client. |
| 603 DCHECK_NE(current_info->field_type, UNKNOWN_TYPE); | 603 DCHECK_NE(current_info->field_type, UNKNOWN_TYPE); |
| 604 | 604 |
| 605 NativeFieldType heuristic_type = (*field)->heuristic_type(); | 605 NativeFieldType heuristic_type = (*field)->heuristic_type(); |
| 606 if (heuristic_type != UNKNOWN_TYPE) | 606 if (heuristic_type != UNKNOWN_TYPE) |
| 607 heuristics_detected_fillable_field = true; | 607 heuristics_detected_fillable_field = true; |
| 608 | 608 |
| 609 (*field)->set_server_type(current_info->field_type); | 609 (*field)->set_server_type(current_info->field_type); |
| 610 if (heuristic_type != (*field)->Type().native_type()) | 610 if (heuristic_type != (*field)->Type().GetEquivalentNativeType()) |
| 611 query_response_overrode_heuristics = true; | 611 query_response_overrode_heuristics = true; |
| 612 | 612 |
| 613 // Copy default value into the field if available. | 613 // Copy default value into the field if available. |
| 614 if (!current_info->default_value.empty()) | 614 if (!current_info->default_value.empty()) |
| 615 (*field)->set_default_value(current_info->default_value); | 615 (*field)->set_default_value(current_info->default_value); |
| 616 | 616 |
| 617 ++current_info; | 617 ++current_info; |
| 618 } | 618 } |
| 619 | 619 |
| 620 form->UpdateAutofillCount(); | 620 form->UpdateAutofillCount(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 form.experiment_id = form_structure->server_experiment_id_; | 652 form.experiment_id = form_structure->server_experiment_id_; |
| 653 | 653 |
| 654 for (std::vector<AutofillField*>::const_iterator field = | 654 for (std::vector<AutofillField*>::const_iterator field = |
| 655 form_structure->fields_.begin(); | 655 form_structure->fields_.begin(); |
| 656 field != form_structure->fields_.end(); ++field) { | 656 field != form_structure->fields_.end(); ++field) { |
| 657 form.data.fields.push_back(FormFieldData(**field)); | 657 form.data.fields.push_back(FormFieldData(**field)); |
| 658 | 658 |
| 659 FormFieldDataPredictions annotated_field; | 659 FormFieldDataPredictions annotated_field; |
| 660 annotated_field.signature = (*field)->FieldSignature(); | 660 annotated_field.signature = (*field)->FieldSignature(); |
| 661 annotated_field.heuristic_type = | 661 annotated_field.heuristic_type = |
| 662 AutofillType::FieldTypeToString((*field)->heuristic_type()); | 662 AutofillType((*field)->heuristic_type()).ToString(); |
| 663 annotated_field.server_type = | 663 annotated_field.server_type = |
| 664 AutofillType::FieldTypeToString((*field)->server_type()); | 664 AutofillType((*field)->server_type()).ToString(); |
| 665 annotated_field.overall_type = | 665 annotated_field.overall_type = (*field)->Type().ToString(); |
| 666 AutofillType::FieldTypeToString((*field)->Type().native_type()); | |
| 667 form.fields.push_back(annotated_field); | 666 form.fields.push_back(annotated_field); |
| 668 } | 667 } |
| 669 | 668 |
| 670 forms->push_back(form); | 669 forms->push_back(form); |
| 671 } | 670 } |
| 672 } | 671 } |
| 673 | 672 |
| 674 std::string FormStructure::FormSignature() const { | 673 std::string FormStructure::FormSignature() const { |
| 675 std::string scheme(target_url_.scheme()); | 674 std::string scheme(target_url_.scheme()); |
| 676 std::string host(target_url_.host()); | 675 std::string host(target_url_.host()); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 825 // Collapse field types that Chrome treats as identical, e.g. home and | 824 // Collapse field types that Chrome treats as identical, e.g. home and |
| 826 // billing address fields. | 825 // billing address fields. |
| 827 NativeFieldTypeSet collapsed_field_types; | 826 NativeFieldTypeSet collapsed_field_types; |
| 828 for (NativeFieldTypeSet::const_iterator it = field_types.begin(); | 827 for (NativeFieldTypeSet::const_iterator it = field_types.begin(); |
| 829 it != field_types.end(); | 828 it != field_types.end(); |
| 830 ++it) { | 829 ++it) { |
| 831 // Since we currently only support US phone numbers, the (city code + main | 830 // Since we currently only support US phone numbers, the (city code + main |
| 832 // digits) number is almost always identical to the whole phone number. | 831 // digits) number is almost always identical to the whole phone number. |
| 833 // TODO(isherman): Improve this logic once we add support for | 832 // TODO(isherman): Improve this logic once we add support for |
| 834 // international numbers. | 833 // international numbers. |
| 835 if (*it == PHONE_HOME_CITY_AND_NUMBER) | 834 if (*it == PHONE_HOME_CITY_AND_NUMBER) { |
| 836 collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER); | 835 collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER); |
| 837 else | 836 } else { |
| 838 collapsed_field_types.insert(AutofillType::GetEquivalentFieldType(*it)); | 837 collapsed_field_types.insert( |
| 838 AutofillType(*it).GetEquivalentNativeType()); | |
| 839 } | |
| 839 } | 840 } |
| 840 | 841 |
| 841 // Capture the field's type, if it is unambiguous. | 842 // Capture the field's type, if it is unambiguous. |
| 842 NativeFieldType field_type = UNKNOWN_TYPE; | 843 NativeFieldType field_type = UNKNOWN_TYPE; |
| 843 if (collapsed_field_types.size() == 1) | 844 if (collapsed_field_types.size() == 1) |
| 844 field_type = *collapsed_field_types.begin(); | 845 field_type = *collapsed_field_types.begin(); |
| 845 | 846 |
| 846 NativeFieldType heuristic_type = field->heuristic_type(); | 847 NativeFieldType heuristic_type = |
| 847 NativeFieldType server_type = field->server_type(); | 848 AutofillType(field->heuristic_type()).GetEquivalentNativeType(); |
| 848 NativeFieldType predicted_type = field->Type().native_type(); | 849 NativeFieldType server_type = |
| 850 AutofillType(field->server_type()).GetEquivalentNativeType(); | |
| 851 NativeFieldType predicted_type = field->Type().GetEquivalentNativeType(); | |
| 849 | 852 |
| 850 // Log heuristic, server, and overall type quality metrics, independently of | 853 // Log heuristic, server, and overall type quality metrics, independently of |
| 851 // whether the field was autofilled. | 854 // whether the field was autofilled. |
| 852 if (heuristic_type == UNKNOWN_TYPE) { | 855 if (heuristic_type == UNKNOWN_TYPE) { |
| 853 metric_logger.LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN, | 856 metric_logger.LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN, |
| 854 field_type, experiment_id); | 857 field_type, experiment_id); |
| 855 } else if (field_types.count(heuristic_type)) { | 858 } else if (field_types.count(heuristic_type)) { |
| 856 metric_logger.LogHeuristicTypePrediction(AutofillMetrics::TYPE_MATCH, | 859 metric_logger.LogHeuristicTypePrediction(AutofillMetrics::TYPE_MATCH, |
| 857 field_type, experiment_id); | 860 field_type, experiment_id); |
| 858 } else { | 861 } else { |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1073 break; | 1076 break; |
| 1074 case FormStructure::FIELD_ASSIGNMENTS: | 1077 case FormStructure::FIELD_ASSIGNMENTS: |
| 1075 EncodeFieldForFieldAssignments(*field, encompassing_xml_element); | 1078 EncodeFieldForFieldAssignments(*field, encompassing_xml_element); |
| 1076 break; | 1079 break; |
| 1077 } | 1080 } |
| 1078 } | 1081 } |
| 1079 return true; | 1082 return true; |
| 1080 } | 1083 } |
| 1081 | 1084 |
| 1082 void FormStructure::ParseFieldTypesFromAutocompleteAttributes( | 1085 void FormStructure::ParseFieldTypesFromAutocompleteAttributes( |
| 1083 ParseTarget parse_target, | |
| 1084 bool* found_types, | 1086 bool* found_types, |
| 1085 bool* found_sections) { | 1087 bool* found_sections) { |
| 1086 const std::string kDefaultSection = "-default"; | 1088 const std::string kDefaultSection = "-default"; |
| 1087 | 1089 |
| 1088 *found_types = false; | 1090 *found_types = false; |
| 1089 *found_sections = false; | 1091 *found_sections = false; |
| 1090 for (std::vector<AutofillField*>::iterator it = fields_.begin(); | 1092 for (std::vector<AutofillField*>::iterator it = fields_.begin(); |
| 1091 it != fields_.end(); ++it) { | 1093 it != fields_.end(); ++it) { |
| 1092 AutofillField* field = *it; | 1094 AutofillField* field = *it; |
| 1093 | 1095 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1125 // Tokenize the attribute value. Per the spec, the tokens are parsed in | 1127 // Tokenize the attribute value. Per the spec, the tokens are parsed in |
| 1126 // reverse order. | 1128 // reverse order. |
| 1127 std::vector<std::string> tokens; | 1129 std::vector<std::string> tokens; |
| 1128 Tokenize(autocomplete_attribute, " ", &tokens); | 1130 Tokenize(autocomplete_attribute, " ", &tokens); |
| 1129 | 1131 |
| 1130 // The final token must be the field type. | 1132 // The final token must be the field type. |
| 1131 // If it is not one of the known types, abort. | 1133 // If it is not one of the known types, abort. |
| 1132 DCHECK(!tokens.empty()); | 1134 DCHECK(!tokens.empty()); |
| 1133 std::string field_type_token = tokens.back(); | 1135 std::string field_type_token = tokens.back(); |
| 1134 tokens.pop_back(); | 1136 tokens.pop_back(); |
| 1135 NativeFieldType field_type = | 1137 HtmlFieldType field_type = |
| 1136 FieldTypeFromAutocompleteType(field_type_token, *field); | 1138 FieldTypeFromAutocompleteType(field_type_token, *field); |
| 1137 if (field_type == UNKNOWN_TYPE) | 1139 if (field_type == HTML_TYPE_UNKNOWN) |
| 1138 continue; | 1140 continue; |
| 1139 | 1141 |
| 1140 // The preceding token, if any, may be a type hint. | 1142 // The preceding token, if any, may be a type hint. |
| 1141 if (!tokens.empty() && IsContactTypeHint(tokens.back())) { | 1143 if (!tokens.empty() && IsContactTypeHint(tokens.back())) { |
| 1142 // If it is, it must match the field type; otherwise, abort. | 1144 // If it is, it must match the field type; otherwise, abort. |
| 1143 // Note that an invalid token invalidates the entire attribute value, even | 1145 // Note that an invalid token invalidates the entire attribute value, even |
| 1144 // if the other tokens are valid. | 1146 // if the other tokens are valid. |
| 1145 if (!ContactTypeHintMatchesFieldType(tokens.back(), field_type)) | 1147 if (!ContactTypeHintMatchesFieldType(tokens.back(), field_type)) |
| 1146 continue; | 1148 continue; |
| 1147 | 1149 |
| 1148 // Chrome Autofill ignores these type hints. | 1150 // Chrome Autofill ignores these type hints. |
| 1149 tokens.pop_back(); | 1151 tokens.pop_back(); |
| 1150 } | 1152 } |
| 1151 | 1153 |
| 1152 // The preceding token, if any, may be a fixed string that is either | 1154 // The preceding token, if any, may be a fixed string that is either |
| 1153 // "shipping" or "billing". Chrome Autofill treats these as implicit | 1155 // "shipping" or "billing". Chrome Autofill treats these as implicit |
| 1154 // section name suffixes. | 1156 // section name suffixes. |
| 1155 DCHECK_EQ(kDefaultSection, field->section()); | 1157 DCHECK_EQ(kDefaultSection, field->section()); |
| 1156 std::string section = field->section(); | 1158 std::string section = field->section(); |
| 1157 if (!tokens.empty() && | 1159 HtmlFieldMode mode = HTML_MODE_NONE; |
| 1158 (tokens.back() == kShippingSection || | 1160 if (!tokens.empty()) { |
| 1159 tokens.back() == kBillingSection)) { | 1161 if (tokens.back() == kShippingMode) |
| 1160 // Set Autofill field type to billing if section is billing. | 1162 mode = HTML_MODE_SHIPPING; |
| 1161 if (tokens.back() == kBillingSection) { | 1163 else if (tokens.back() == kBillingMode) |
| 1162 field_type = AutofillType::GetEquivalentBillingFieldType(field_type); | 1164 mode = HTML_MODE_BILLING; |
| 1165 } | |
| 1163 | 1166 |
| 1164 // The Autofill dialog uses the type CREDIT_CARD_NAME to refer to both | 1167 if (mode != HTML_MODE_NONE) { |
| 1165 // the credit card holder's name and the name on the billing address. | |
| 1166 if (parse_target == PARSE_FOR_AUTOFILL_DIALOG && | |
| 1167 field_type == NAME_FULL) { | |
| 1168 field_type = CREDIT_CARD_NAME; | |
| 1169 } | |
| 1170 } | |
| 1171 | |
| 1172 section = "-" + tokens.back(); | 1168 section = "-" + tokens.back(); |
| 1173 tokens.pop_back(); | 1169 tokens.pop_back(); |
| 1174 } | 1170 } |
| 1175 | 1171 |
| 1176 // The preceding token, if any, may be a named section. | 1172 // The preceding token, if any, may be a named section. |
| 1177 const std::string kSectionPrefix = "section-"; | 1173 const std::string kSectionPrefix = "section-"; |
| 1178 if (!tokens.empty() && | 1174 if (!tokens.empty() && |
| 1179 StartsWithASCII(tokens.back(), kSectionPrefix, true)) { | 1175 StartsWithASCII(tokens.back(), kSectionPrefix, true)) { |
| 1180 // Prepend this section name to the suffix set in the preceding block. | 1176 // Prepend this section name to the suffix set in the preceding block. |
| 1181 section = tokens.back().substr(kSectionPrefix.size()) + section; | 1177 section = tokens.back().substr(kSectionPrefix.size()) + section; |
| 1182 tokens.pop_back(); | 1178 tokens.pop_back(); |
| 1183 } | 1179 } |
| 1184 | 1180 |
| 1185 // No other tokens are allowed. If there are any remaining, abort. | 1181 // No other tokens are allowed. If there are any remaining, abort. |
| 1186 if (!tokens.empty()) | 1182 if (!tokens.empty()) |
| 1187 continue; | 1183 continue; |
| 1188 | 1184 |
| 1189 if (section != kDefaultSection) { | 1185 if (section != kDefaultSection) { |
| 1190 *found_sections = true; | 1186 *found_sections = true; |
| 1191 field->set_section(section); | 1187 field->set_section(section); |
| 1192 } | 1188 } |
| 1193 | 1189 |
| 1194 // No errors encountered while parsing! | 1190 // No errors encountered while parsing! |
| 1195 // Update the |field|'s type based on what was parsed from the attribute. | 1191 // Update the |field|'s type based on what was parsed from the attribute. |
| 1196 field->set_heuristic_type(field_type); | 1192 field->SetHtmlType(field_type, mode); |
| 1197 if (field_type_token == "tel-local-prefix") | |
| 1198 field->set_phone_part(AutofillField::PHONE_PREFIX); | |
| 1199 else if (field_type_token == "tel-local-suffix") | |
| 1200 field->set_phone_part(AutofillField::PHONE_SUFFIX); | |
| 1201 } | 1193 } |
| 1202 } | 1194 } |
| 1203 | 1195 |
| 1204 void FormStructure::IdentifySections(bool has_author_specified_sections) { | 1196 void FormStructure::IdentifySections(bool has_author_specified_sections) { |
| 1205 if (fields_.empty()) | 1197 if (fields_.empty()) |
| 1206 return; | 1198 return; |
| 1207 | 1199 |
| 1208 if (!has_author_specified_sections) { | 1200 if (!has_author_specified_sections) { |
| 1209 // Name sections after the first field in the section. | 1201 // Name sections after the first field in the section. |
| 1210 base::string16 current_section = fields_.front()->unique_name(); | 1202 base::string16 current_section = fields_.front()->unique_name(); |
| 1211 | 1203 |
| 1212 // Keep track of the types we've seen in this section. | 1204 // Keep track of the types we've seen in this section. |
| 1213 std::set<NativeFieldType> seen_types; | 1205 std::set<NativeFieldType> seen_types; |
| 1214 NativeFieldType previous_type = UNKNOWN_TYPE; | 1206 NativeFieldType previous_type = UNKNOWN_TYPE; |
| 1215 | 1207 |
| 1216 for (std::vector<AutofillField*>::iterator field = fields_.begin(); | 1208 for (std::vector<AutofillField*>::iterator field = fields_.begin(); |
| 1217 field != fields_.end(); ++field) { | 1209 field != fields_.end(); ++field) { |
| 1218 const NativeFieldType current_type = | 1210 const NativeFieldType current_type = |
| 1219 AutofillType::GetEquivalentFieldType((*field)->Type().native_type()); | 1211 (*field)->Type().GetApproximateNativeFieldType(); |
| 1220 | 1212 |
| 1221 bool already_saw_current_type = seen_types.count(current_type) > 0; | 1213 bool already_saw_current_type = seen_types.count(current_type) > 0; |
| 1222 | 1214 |
| 1223 // Forms often ask for multiple phone numbers -- e.g. both a daytime and | 1215 // Forms often ask for multiple phone numbers -- e.g. both a daytime and |
| 1224 // evening phone number. Our phone number detection is also generally a | 1216 // evening phone number. Our phone number detection is also generally a |
| 1225 // little off. Hence, ignore this field type as a signal here. | 1217 // little off. Hence, ignore this field type as a signal here. |
| 1226 if (AutofillType(current_type).group() == PHONE_HOME) | 1218 if (AutofillType(current_type).group() == PHONE_HOME) |
| 1227 already_saw_current_type = false; | 1219 already_saw_current_type = false; |
| 1228 | 1220 |
| 1229 // Some forms have adjacent fields of the same type. Two common examples: | 1221 // Some forms have adjacent fields of the same type. Two common examples: |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1257 field != fields_.end(); ++field) { | 1249 field != fields_.end(); ++field) { |
| 1258 FieldTypeGroup field_type_group = (*field)->Type().group(); | 1250 FieldTypeGroup field_type_group = (*field)->Type().group(); |
| 1259 if (field_type_group == CREDIT_CARD) | 1251 if (field_type_group == CREDIT_CARD) |
| 1260 (*field)->set_section((*field)->section() + "-cc"); | 1252 (*field)->set_section((*field)->section() + "-cc"); |
| 1261 else | 1253 else |
| 1262 (*field)->set_section((*field)->section() + "-default"); | 1254 (*field)->set_section((*field)->section() + "-default"); |
| 1263 } | 1255 } |
| 1264 } | 1256 } |
| 1265 | 1257 |
| 1266 } // namespace autofill | 1258 } // namespace autofill |
| OLD | NEW |