summaryrefslogtreecommitdiff
path: root/chromium/components/autofill
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/components/autofill
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
downloadqtwebengine-chromium-189d4fd8fad9e3c776873be51938cd31a42b6177.tar.gz
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/autofill')
-rw-r--r--chromium/components/autofill/DIR_METADATA4
-rw-r--r--chromium/components/autofill/OWNERS3
-rw-r--r--chromium/components/autofill/android/BUILD.gn28
-rw-r--r--chromium/components/autofill/android/provider/BUILD.gn14
-rw-r--r--chromium/components/autofill/android/provider/DEPS3
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.cc52
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.h6
-rw-r--r--chromium/components/autofill/android/provider/form_data_android.cc16
-rw-r--r--chromium/components/autofill/android/provider/form_data_android.h3
-rw-r--r--chromium/components/autofill/android/provider/form_field_data_android.cc60
-rw-r--r--chromium/components/autofill/android/provider/form_field_data_android.h16
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java74
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java45
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java89
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java110
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java52
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl22
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl22
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/OWNERS2
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/README.md53
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.aidl7
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.java88
-rw-r--r--chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java8
-rw-r--r--chromium/components/autofill/android/provider/test_support/BUILD.gn41
-rw-r--r--chromium/components/autofill/android/provider/test_support/autofill_provider_test_helper.cc173
-rw-r--r--chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java57
-rw-r--r--chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java64
-rw-r--r--chromium/components/autofill/content/browser/BUILD.gn3
-rw-r--r--chromium/components/autofill/content/browser/DEPS3
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc119
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h26
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc36
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc3
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc1
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_agent.mojom4
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_driver.mojom2
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc31
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h14
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc195
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.h38
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc21
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc1
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.cc1
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc6
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h22
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc2
-rw-r--r--chromium/components/autofill/content/renderer/prefilled_values_detector.cc149
-rw-r--r--chromium/components/autofill/content/renderer/prefilled_values_detector.h7
-rw-r--r--chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn46
-rw-r--r--chromium/components/autofill/core/browser/DEPS4
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager.cc54
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager.h50
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc49
-rw-r--r--chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc25
-rw-r--r--chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h39
-rw-r--r--chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc34
-rw-r--r--chromium/components/autofill/core/browser/address_rewriter.cc4
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager.cc24
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc82
-rw-r--r--chromium/components/autofill/core/browser/autofill_browser_util.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_browser_util.h7
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.cc15
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h54
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util.cc50
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc17
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.h25
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc134
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc1
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc42
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.h33
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.cc313
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.h171
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.cc44
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.h36
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc22
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc47
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc841
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h170
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc762
-rw-r--r--chromium/components/autofill/core/browser/autofill_merge_unittest.cc20
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc368
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h151
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc582
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.cc28
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc85
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validation_util.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.h12
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider_unittest.cc92
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc164
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.h3
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.cc13
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc196
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h95
-rw-r--r--chromium/components/autofill/core/browser/autofill_type.cc60
-rw-r--r--chromium/components/autofill/core/browser/autofill_type_unittest.cc30
-rw-r--r--chromium/components/autofill/core/browser/data_model/address.cc60
-rw-r--r--chromium/components/autofill/core/browser/data_model/address.h6
-rw-r--r--chromium/components/autofill/core/browser/data_model/address_unittest.cc51
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.cc5
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.h4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.cc182
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.h11
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc87
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc70
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc13
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc70
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.h5
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc312
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h93
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc190
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.cc77
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.h85
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc585
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc100
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h2
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_test_utils.cc4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc76
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc40
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.h10
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils_unittest.cc11
-rw-r--r--chromium/components/autofill/core/browser/data_model/contact_info.cc114
-rw-r--r--chromium/components/autofill/core/browser/data_model/contact_info.h11
-rw-r--r--chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc127
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.cc19
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc22
-rw-r--r--chromium/components/autofill/core/browser/data_model/phone_number.cc4
-rw-r--r--chromium/components/autofill/core/browser/field_filler.cc195
-rw-r--r--chromium/components/autofill/core/browser/field_filler.h18
-rw-r--r--chromium/components/autofill/core/browser/field_filler_unittest.cc358
-rw-r--r--chromium/components/autofill/core/browser/field_types.cc3
-rw-r--r--chromium/components/autofill/core/browser/field_types.h39
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc110
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.h3
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc410
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.cc443
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.h66
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc506
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc8
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h19
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc172
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.h9
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc944
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.cc9
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.h3
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/field_candidates.h5
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.cc54
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.h19
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc130
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.cc175
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.h13
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc532
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc129
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.h112
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.cc12
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.h5
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc232
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.cc6
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.h5
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc65
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.cc2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.h3
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc66
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.cc36
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.h3
-rw-r--r--chromium/components/autofill/core/browser/form_processing/label_processing_util.cc108
-rw-r--r--chromium/components/autofill/core/browser/form_processing/label_processing_util.h24
-rw-r--r--chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc117
-rw-r--r--chromium/components/autofill/core/browser/form_processing/name_processing_util.cc239
-rw-r--r--chromium/components/autofill/core/browser/form_processing/name_processing_util.h64
-rw-r--r--chromium/components/autofill/core/browser/form_processing/name_processing_util_unittest.cc338
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc713
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h114
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc635
-rw-r--r--chromium/components/autofill/core/browser/form_types.cc39
-rw-r--r--chromium/components/autofill/core/browser/form_types.h16
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc48
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.h41
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc31
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h5
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc46
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc142
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h87
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc218
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.cc2
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/geo/subkey_requester.cc6
-rw-r--r--chromium/components/autofill/core/browser/logging/log_router.cc10
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns.h16
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc79
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc67
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc77
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h31
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc245
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json435
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc36
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h23
-rwxr-xr-xchromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py114
-rw-r--r--chromium/components/autofill/core/browser/payments/OWNERS1
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc56
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager.h15
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc179
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc103
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h70
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc9
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc23
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc15
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h3
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc12
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h3
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc26
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc33
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h2
-rw-r--r--chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc3
-rw-r--r--chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h2
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.cc13
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.h20
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc30
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc10
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h2
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc9
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc34
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc6
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h9
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc14
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h11
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc33
-rw-r--r--chromium/components/autofill/core/browser/payments/test_strike_database.h1
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc540
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h127
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc455
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_cleaner.h164
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc380
-rw-r--r--chromium/components/autofill/core/browser/proto/api_v1.proto6
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto13
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc24
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h19
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.cc57
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.h24
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.cc26
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.h3
-rw-r--r--chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc53
-rw-r--r--chromium/components/autofill/core/browser/ui/accessory_sheet_data.h41
-rw-r--r--chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter.cc15
-rw-r--r--chromium/components/autofill/core/browser/ui/address_email_form_label_formatter.cc9
-rw-r--r--chromium/components/autofill/core/browser/ui/address_form_label_formatter.cc2
-rw-r--r--chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter.cc9
-rw-r--r--chromium/components/autofill/core/browser/ui/contact_form_label_formatter.cc7
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter.cc8
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter_utils.cc35
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter_utils.h5
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc6
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc16
-rw-r--r--chromium/components/autofill/core/browser/ui/suggestion.h4
-rw-r--r--chromium/components/autofill/core/browser/ui/suggestion_selection.cc5
-rw-r--r--chromium/components/autofill/core/browser/validation.cc14
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc10
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc84
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc1
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc69
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc5
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc134
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h10
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc42
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc8
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn2
-rw-r--r--chromium/components/autofill/core/common/autofill_constants.h12
-rw-r--r--chromium/components/autofill/core/common/autofill_data_validation.cc60
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc150
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h28
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.cc51
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.h8
-rw-r--r--chromium/components/autofill/core/common/autofill_util.cc4
-rw-r--r--chromium/components/autofill/core/common/autofill_util.h2
-rw-r--r--chromium/components/autofill/core/common/dense_set.h37
-rw-r--r--chromium/components/autofill/core/common/dense_set_unittest.cc128
-rw-r--r--chromium/components/autofill/core/common/field_data_manager.cc27
-rw-r--r--chromium/components/autofill/core/common/field_data_manager.h16
-rw-r--r--chromium/components/autofill/core/common/field_data_manager_unittest.cc29
-rw-r--r--chromium/components/autofill/core/common/form_data.cc2
-rw-r--r--chromium/components/autofill/core/common/form_field_data.cc2
-rw-r--r--chromium/components/autofill/core/common/form_field_data.h4
-rw-r--r--chromium/components/autofill/core/common/language_code.h45
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types.mojom2
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc2
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h4
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc6
-rw-r--r--chromium/components/autofill/core/common/signatures.cc4
-rw-r--r--chromium/components/autofill/ios/browser/BUILD.gn5
-rw-r--r--chromium/components/autofill/ios/browser/DEPS2
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm76
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent_unittests.mm140
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.h2
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.mm4
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.h1
-rw-r--r--chromium/components/autofill/ios/browser/js_suggestion_manager.h146
-rw-r--r--chromium/components/autofill/ios/browser/js_suggestion_manager.mm184
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm14
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_tab_helper.h2
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm6
-rw-r--r--chromium/components/autofill/ios/form_util/form_unittest.mm5
-rw-r--r--chromium/components/autofill/ios/form_util/resources/fill.js16
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form.js3
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form_handlers.js134
-rw-r--r--chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm6
328 files changed, 14492 insertions, 8604 deletions
diff --git a/chromium/components/autofill/DIR_METADATA b/chromium/components/autofill/DIR_METADATA
new file mode 100644
index 00000000000..3994ddc84af
--- /dev/null
+++ b/chromium/components/autofill/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "UI>Browser>Autofill"
+}
+team_email: "chrome-autofill@google.com"
diff --git a/chromium/components/autofill/OWNERS b/chromium/components/autofill/OWNERS
index ed9d92879d4..d2870efd3f4 100644
--- a/chromium/components/autofill/OWNERS
+++ b/chromium/components/autofill/OWNERS
@@ -10,6 +10,3 @@ mahmadi@chromium.org
rogerm@chromium.org
sebsg@chromium.org
tmartino@chromium.org
-
-# COMPONENT: UI>Browser>Autofill
-# TEAM: chrome-autofill@google.com
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
index 9f15164b1a8..2234539df90 100644
--- a/chromium/components/autofill/android/BUILD.gn
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -36,14 +36,15 @@ java_cpp_enum("autofill_core_browser_java_enums") {
]
}
-android_library("autofill_java") {
+android_library("full_autofill_java") {
deps = [
":autofill_java_resources",
+ ":payments_autofill_java",
"//base:base_java",
"//content/public/android:content_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
- "//third_party/android_deps:androidx_core_core_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+ "//third_party/androidx:androidx_core_core_java",
"//ui/android:ui_no_recycler_view_java",
]
sources = [
@@ -52,9 +53,24 @@ android_library("autofill_java") {
"java/src/org/chromium/components/autofill/AutofillDropdownFooter.java",
"java/src/org/chromium/components/autofill/AutofillPopup.java",
"java/src/org/chromium/components/autofill/AutofillSuggestion.java",
- "java/src/org/chromium/components/autofill/Completable.java",
- "java/src/org/chromium/components/autofill/EditableOption.java",
]
srcjar_deps = [ ":autofill_core_browser_java_enums" ]
resources_package = "org.chromium.components.autofill"
}
+
+# A library containing the minimal deps for payments, so that ui_java_resources
+# doesn't have to be pulled in.
+android_library("payments_autofill_java") {
+ sources = [
+ "java/src/org/chromium/components/autofill/Completable.java",
+ "java/src/org/chromium/components/autofill/EditableOption.java",
+ ]
+ deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
+}
+
+java_group("autofill_java") {
+ deps = [
+ ":full_autofill_java",
+ ":payments_autofill_java",
+ ]
+}
diff --git a/chromium/components/autofill/android/provider/BUILD.gn b/chromium/components/autofill/android/provider/BUILD.gn
index bff1710270d..1050f6ad624 100644
--- a/chromium/components/autofill/android/provider/BUILD.gn
+++ b/chromium/components/autofill/android/provider/BUILD.gn
@@ -5,7 +5,17 @@
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+android_aidl("autofill_aidl") {
+ import_include = [ "java/src" ]
+ sources = [
+ "java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl",
+ "java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl",
+ "java/src/org/chromium/components/autofill_public/ViewType.aidl",
+ ]
+}
+
android_library("java") {
+ srcjar_deps = [ ":autofill_aidl" ]
deps = [
"//base:base_java",
"//base:jni_java",
@@ -13,17 +23,19 @@ android_library("java") {
"//components/autofill/core/common/mojom:mojo_types_java",
"//components/version_info/android:version_constants_java",
"//content/public/android:content_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
"//ui/android:ui_no_recycler_view_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
sources = [
"java/src/org/chromium/components/autofill/AutofillActionModeCallback.java",
+ "java/src/org/chromium/components/autofill/AutofillHintsService.java",
"java/src/org/chromium/components/autofill/AutofillManagerWrapper.java",
"java/src/org/chromium/components/autofill/AutofillProvider.java",
"java/src/org/chromium/components/autofill/AutofillProviderUMA.java",
"java/src/org/chromium/components/autofill/FormData.java",
"java/src/org/chromium/components/autofill/FormFieldData.java",
+ "java/src/org/chromium/components/autofill_public/ViewType.java",
]
}
diff --git a/chromium/components/autofill/android/provider/DEPS b/chromium/components/autofill/android/provider/DEPS
new file mode 100644
index 00000000000..1bc851ebbbd
--- /dev/null
+++ b/chromium/components/autofill/android/provider/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/autofill/content",
+]
diff --git a/chromium/components/autofill/android/provider/autofill_provider_android.cc b/chromium/components/autofill/android/provider/autofill_provider_android.cc
index 157142cde47..652a4fe4ce0 100644
--- a/chromium/components/autofill/android/provider/autofill_provider_android.cc
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.cc
@@ -9,11 +9,13 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
+#include "base/feature_list.h"
#include "components/autofill/android/provider/form_data_android.h"
#include "components/autofill/android/provider/jni_headers/AutofillProvider_jni.h"
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_handler_proxy.h"
#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/window_android.h"
@@ -34,6 +36,12 @@ namespace autofill {
using mojom::SubmissionSource;
+static jboolean JNI_AutofillProvider_IsQueryServerFieldTypesEnabled(
+ JNIEnv* env) {
+ return base::FeatureList::IsEnabled(
+ features::kAndroidAutofillQueryServerFieldTypes);
+}
+
AutofillProviderAndroid::AutofillProviderAndroid(
const JavaRef<jobject>& jcaller,
content::WebContents* web_contents)
@@ -151,7 +159,7 @@ void AutofillProviderAndroid::MaybeStartNewSession(
Java_AutofillProvider_startAutofillSession(
env, obj, form_obj, index, transformed_bounding.x(),
transformed_bounding.y(), transformed_bounding.width(),
- transformed_bounding.height());
+ transformed_bounding.height(), handler->has_server_prediction());
}
void AutofillProviderAndroid::OnAutofillAvailable(JNIEnv* env,
@@ -341,8 +349,7 @@ void AutofillProviderAndroid::OnDidFillAutofillFormData(
}
void AutofillProviderAndroid::OnFormsSeen(AutofillHandlerProxy* handler,
- const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) {}
+ const std::vector<FormData>& forms) {}
void AutofillProviderAndroid::OnHidePopup(AutofillHandlerProxy* handler) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -356,6 +363,45 @@ void AutofillProviderAndroid::OnHidePopup(AutofillHandlerProxy* handler) {
}
}
+void AutofillProviderAndroid::OnServerPredictionsAvailable(
+ AutofillHandlerProxy* handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (handler != handler_.get() || !form_.get())
+ return;
+
+ if (auto* form_structure = handler_->FindCachedFormByRendererId(
+ form_->form().unique_renderer_id)) {
+ form_->UpdateFieldTypes(*form_structure);
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_AutofillProvider_onQueryDone(env, obj, /*success=*/true);
+ }
+}
+
+void AutofillProviderAndroid::OnServerQueryRequestError(
+ AutofillHandlerProxy* handler,
+ FormSignature form_signature) {
+ if (!IsCurrentlyLinkedHandler(handler) || !form_.get())
+ return;
+
+ if (auto* form_structure = handler_->FindCachedFormByRendererId(
+ form_->form().unique_renderer_id)) {
+ if (form_structure->form_signature() != form_signature)
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_AutofillProvider_onQueryDone(env, obj, /*success=*/false);
+ }
+}
+
void AutofillProviderAndroid::Reset(AutofillHandlerProxy* handler) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (handler == handler_.get()) {
diff --git a/chromium/components/autofill/android/provider/autofill_provider_android.h b/chromium/components/autofill/android/provider/autofill_provider_android.h
index 618517ca585..bd21af383a0 100644
--- a/chromium/components/autofill/android/provider/autofill_provider_android.h
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.h
@@ -66,9 +66,11 @@ class AutofillProviderAndroid : public AutofillProvider {
const FormData& form,
base::TimeTicks timestamp) override;
void OnFormsSeen(AutofillHandlerProxy* handler,
- const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) override;
+ const std::vector<FormData>& forms) override;
void OnHidePopup(AutofillHandlerProxy* handler) override;
+ void OnServerPredictionsAvailable(AutofillHandlerProxy* handler) override;
+ void OnServerQueryRequestError(AutofillHandlerProxy* handler,
+ FormSignature form_signature) override;
void Reset(AutofillHandlerProxy* handler) override;
diff --git a/chromium/components/autofill/android/provider/form_data_android.cc b/chromium/components/autofill/android/provider/form_data_android.cc
index 7f24f8967c5..1d74c49fd32 100644
--- a/chromium/components/autofill/android/provider/form_data_android.cc
+++ b/chromium/components/autofill/android/provider/form_data_android.cc
@@ -40,7 +40,7 @@ ScopedJavaLocalRef<jobject> FormDataAndroid::GetJavaPeer(
new FormFieldDataAndroid(&form_.fields[i])));
}
if (form_structure)
- ApplyHeuristicFieldType(*form_structure);
+ UpdateFieldTypes(*form_structure);
ScopedJavaLocalRef<jstring> jname =
ConvertUTF16ToJavaString(env, form_.name);
ScopedJavaLocalRef<jstring> jhost =
@@ -96,14 +96,20 @@ bool FormDataAndroid::SimilarFormAs(const FormData& form) {
return form_.SimilarFormAs(form);
}
-void FormDataAndroid::ApplyHeuristicFieldType(
- const FormStructure& form_structure) {
+void FormDataAndroid::UpdateFieldTypes(const FormStructure& form_structure) {
DCHECK(form_structure.field_count() == fields_.size());
auto form_field_data_android = fields_.begin();
for (const auto& autofill_field : form_structure) {
DCHECK(form_field_data_android->get()->SimilarFieldAs(*autofill_field));
- form_field_data_android->get()->set_heuristic_type(
- AutofillType(autofill_field->heuristic_type()));
+ std::vector<AutofillType> server_predictions;
+ for (const auto& prediction : autofill_field->server_predictions()) {
+ server_predictions.emplace_back(
+ static_cast<ServerFieldType>(prediction.type()));
+ }
+ form_field_data_android->get()->UpdateAutofillTypes(
+ AutofillType(autofill_field->heuristic_type()),
+ AutofillType(autofill_field->server_type()),
+ autofill_field->ComputedType(), server_predictions);
if (++form_field_data_android == fields_.end())
break;
}
diff --git a/chromium/components/autofill/android/provider/form_data_android.h b/chromium/components/autofill/android/provider/form_data_android.h
index 96002f62c94..e7c39495dc3 100644
--- a/chromium/components/autofill/android/provider/form_data_android.h
+++ b/chromium/components/autofill/android/provider/form_data_android.h
@@ -52,7 +52,8 @@ class FormDataAndroid {
// |value|.
void OnFormFieldDidChange(size_t index, const base::string16& value);
- void ApplyHeuristicFieldType(const FormStructure& form);
+ // Updates the field types from the |form|.
+ void UpdateFieldTypes(const FormStructure& form);
const FormData& form() { return form_; }
diff --git a/chromium/components/autofill/android/provider/form_field_data_android.cc b/chromium/components/autofill/android/provider/form_field_data_android.cc
index 943ff3cf116..b40701a8e56 100644
--- a/chromium/components/autofill/android/provider/form_field_data_android.cc
+++ b/chromium/components/autofill/android/provider/form_field_data_android.cc
@@ -21,9 +21,28 @@ using base::android::ToJavaArrayOfStrings;
namespace autofill {
+namespace {
+base::android::ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfPredictionString(
+ JNIEnv* env,
+ const std::vector<AutofillType>& server_predictions) {
+ if (!server_predictions.empty()) {
+ std::vector<std::string> server_prediction_array;
+ server_prediction_array.reserve(server_predictions.size());
+ for (const auto& p : server_predictions) {
+ server_prediction_array.emplace_back(p.ToString());
+ }
+ return ToJavaArrayOfStrings(env, server_prediction_array);
+ }
+ return nullptr;
+}
+
+} // namespace
+
FormFieldDataAndroid::FormFieldDataAndroid(FormFieldData* field)
: heuristic_type_(AutofillType(UNKNOWN_TYPE)), field_ptr_(field) {}
+FormFieldDataAndroid::~FormFieldDataAndroid() = default;
+
ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
@@ -47,9 +66,17 @@ ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
ScopedJavaLocalRef<jobjectArray> joption_contents =
ToJavaArrayOfStrings(env, field_ptr_->option_contents);
ScopedJavaLocalRef<jstring> jheuristic_type;
- if (!heuristic_type_.IsUnknown())
+ if (!heuristic_type_.IsUnknown()) {
jheuristic_type =
ConvertUTF8ToJavaString(env, heuristic_type_.ToString());
+ }
+ ScopedJavaLocalRef<jstring> jserver_type =
+ ConvertUTF8ToJavaString(env, server_type_.ToString());
+ ScopedJavaLocalRef<jstring> jcomputed_type =
+ ConvertUTF8ToJavaString(env, computed_type_.ToString());
+ ScopedJavaLocalRef<jobjectArray> jserver_predictions =
+ ToJavaArrayOfPredictionString(env, server_predictions_);
+
ScopedJavaLocalRef<jobjectArray> jdatalist_values =
ToJavaArrayOfStrings(env, field_ptr_->datalist_values);
ScopedJavaLocalRef<jobjectArray> jdatalist_labels =
@@ -60,7 +87,8 @@ ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
field_ptr_->should_autocomplete, jplaceholder, jtype, jid,
joption_values, joption_contents, IsCheckable(field_ptr_->check_status),
IsChecked(field_ptr_->check_status), field_ptr_->max_length,
- jheuristic_type, field_ptr_->bounds.x(), field_ptr_->bounds.y(),
+ jheuristic_type, jserver_type, jcomputed_type, jserver_predictions,
+ field_ptr_->bounds.x(), field_ptr_->bounds.y(),
field_ptr_->bounds.right(), field_ptr_->bounds.bottom(),
jdatalist_values, jdatalist_labels, field_ptr_->IsVisible());
java_ref_ = JavaObjectWeakGlobalRef(env, obj);
@@ -103,4 +131,32 @@ bool FormFieldDataAndroid::SimilarFieldAs(const FormFieldData& field) const {
return field_ptr_->SimilarFieldAs(field);
}
+void FormFieldDataAndroid::UpdateAutofillTypes(
+ const AutofillType& heuristic_type,
+ const AutofillType& server_type,
+ const AutofillType& computed_type,
+ const std::vector<AutofillType>& server_predictions) {
+ heuristic_type_ = heuristic_type;
+ server_type_ = server_type;
+ computed_type_ = computed_type;
+ server_predictions_ = server_predictions;
+
+ // Java peer isn't available when this object is instantiated, update to
+ // Java peer if the prediction arrives later.
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ ScopedJavaLocalRef<jstring> jserver_type =
+ ConvertUTF8ToJavaString(env, server_type_.ToString());
+ ScopedJavaLocalRef<jstring> jcomputed_type =
+ ConvertUTF8ToJavaString(env, computed_type_.ToString());
+ ScopedJavaLocalRef<jobjectArray> jserver_predictions =
+ ToJavaArrayOfPredictionString(env, server_predictions_);
+
+ Java_FormFieldData_updateFieldTypes(env, obj, jserver_type, jcomputed_type,
+ jserver_predictions);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/android/provider/form_field_data_android.h b/chromium/components/autofill/android/provider/form_field_data_android.h
index a12ad979bfe..ff0879b48b9 100644
--- a/chromium/components/autofill/android/provider/form_field_data_android.h
+++ b/chromium/components/autofill/android/provider/form_field_data_android.h
@@ -16,20 +16,24 @@ namespace autofill {
// autofill::FormFieldData available in Java.
class FormFieldDataAndroid {
public:
- FormFieldDataAndroid(FormFieldData* field);
- virtual ~FormFieldDataAndroid() {}
+ explicit FormFieldDataAndroid(FormFieldData* field);
+ virtual ~FormFieldDataAndroid();
base::android::ScopedJavaLocalRef<jobject> GetJavaPeer();
void GetValue();
void OnFormFieldDidChange(const base::string16& value);
bool SimilarFieldAs(const FormFieldData& field) const;
-
- void set_heuristic_type(const AutofillType& heuristic_type) {
- heuristic_type_ = heuristic_type;
- }
+ void UpdateAutofillTypes(const AutofillType& heuristic_type,
+ const AutofillType& server_type,
+ const AutofillType& computed_type,
+ const std::vector<AutofillType>& server_predictions);
private:
AutofillType heuristic_type_;
+ AutofillType server_type_;
+ AutofillType computed_type_;
+ std::vector<AutofillType> server_predictions_;
+
// Not owned.
FormFieldData* field_ptr_;
JavaObjectWeakGlobalRef java_ref_;
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java
new file mode 100644
index 00000000000..14fd7b0e73e
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.os.IBinder;
+
+import org.chromium.base.Log;
+import org.chromium.components.autofill_public.IAutofillHintsService;
+import org.chromium.components.autofill_public.IViewTypeCallback;
+import org.chromium.components.autofill_public.ViewType;
+
+import java.util.List;
+
+/**
+ * This class is used to talk to autofill service about the view type.
+ */
+public class AutofillHintsService {
+ private static final String TAG = "AutofillHintsService";
+
+ public AutofillHintsService() {
+ mBinder = new IAutofillHintsService.Stub() {
+ @Override
+ public void registerViewTypeCallback(IViewTypeCallback callback) {
+ mCallback = callback;
+ if (mUnsentViewTypes != null) {
+ invokeOnViewTypeAvailable();
+ } else if (mQueryFailed != null) {
+ invokeOnQueryFailed();
+ }
+ }
+ };
+ }
+
+ public IBinder getBinder() {
+ return mBinder;
+ }
+
+ public void onViewTypeAvailable(List<ViewType> viewTypes) {
+ if (mUnsentViewTypes != null) return;
+ mUnsentViewTypes = viewTypes;
+ if (mCallback == null) return;
+ invokeOnViewTypeAvailable();
+ }
+
+ public void onQueryFailed() {
+ if (mQueryFailed != null) return;
+ mQueryFailed = Boolean.TRUE;
+ if (mCallback == null) return;
+ invokeOnQueryFailed();
+ }
+
+ private void invokeOnViewTypeAvailable() {
+ try {
+ mCallback.onViewTypeAvailable(mUnsentViewTypes);
+ } catch (Exception e) {
+ Log.e(TAG, "onViewTypeAvailable ", e);
+ }
+ }
+
+ private void invokeOnQueryFailed() {
+ try {
+ mCallback.onQueryFailed();
+ } catch (Exception e) {
+ Log.e(TAG, "onQueryFailed ", e);
+ }
+ }
+
+ private IAutofillHintsService.Stub mBinder;
+ private IViewTypeCallback mCallback;
+ private List<ViewType> mUnsentViewTypes;
+ private Boolean mQueryFailed;
+}
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
index e92fdb19c61..237cf244e98 100644
--- a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
@@ -5,6 +5,7 @@
package org.chromium.components.autofill;
import android.annotation.TargetApi;
+import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
@@ -29,7 +30,8 @@ public class AutofillManagerWrapper {
// NOTE: As a result of the above, the tag below still references the name of this class from
// when it was originally developed specifically for Android WebView.
public static final String TAG = "AwAutofillManager";
-
+ private static final String AWG_COMPONENT_NAME =
+ "com.google.android.gms/com.google.android.gms.autofill.service.AutofillService";
/**
* The observer of suggestion window.
*/
@@ -58,17 +60,42 @@ public class AutofillManagerWrapper {
private boolean mDestroyed;
private boolean mDisabled;
private ArrayList<WeakReference<InputUIObserver>> mInputUIObservers;
+ // Indicates if AwG is the current Android autofill service.
+ private final boolean mIsAwGCurrentAutofillService;
public AutofillManagerWrapper(Context context) {
updateLogStat();
if (isLoggable()) log("constructor");
mAutofillManager = context.getSystemService(AutofillManager.class);
mDisabled = mAutofillManager == null || !mAutofillManager.isEnabled();
+
if (mDisabled) {
+ mIsAwGCurrentAutofillService = false;
if (isLoggable()) log("disabled");
return;
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ ComponentName componentName = null;
+ try {
+ componentName = mAutofillManager.getAutofillServiceComponentName();
+ } catch (Exception e) {
+ // Can't catch com.android.internal.util.SyncResultReceiver.TimeoutException,
+ // because
+ // - The exception isn't Android API.
+ // - Different version of Android handle it differently.
+ // Uses Exception to catch various cases. (refer to crbug.com/1186406)
+ Log.e(TAG, "getAutofillServiceComponentName", e);
+ }
+ if (componentName != null) {
+ mIsAwGCurrentAutofillService =
+ AWG_COMPONENT_NAME.equals(componentName.flattenToString());
+ } else {
+ mIsAwGCurrentAutofillService = false;
+ }
+ } else {
+ mIsAwGCurrentAutofillService = false;
+ }
mMonitor = new AutofillInputUIMonitor(this);
mAutofillManager.registerCallback(mMonitor);
}
@@ -142,6 +169,14 @@ public class AutofillManagerWrapper {
return mDisabled;
}
+ /**
+ * Only work for Android P and beyond. Always return false for Android O.
+ * @return if the Autofill with Google is the current autofill service.
+ */
+ public boolean isAwGCurrentAutofillService() {
+ return mIsAwGCurrentAutofillService;
+ }
+
private boolean checkAndWarnIfDestroyed() {
if (mDestroyed) {
Log.w(TAG, "Application attempted to call on a destroyed AutofillManagerWrapper",
@@ -165,9 +200,13 @@ public class AutofillManagerWrapper {
}
}
- public void notifyNewSessionStarted() {
+ public void notifyNewSessionStarted(boolean hasServerPrediction) {
updateLogStat();
- if (isLoggable()) log("Session starts");
+ if (isLoggable()) log("Session starts, has server prediction = " + hasServerPrediction);
+ }
+
+ public void onQueryDone(boolean success) {
+ if (isLoggable()) log("Query " + (success ? "succeed" : "failed"));
}
/**
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
index 226f0dc55a7..726a17f0784 100644
--- a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -28,6 +28,7 @@ import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.annotations.VerifiesOnO;
import org.chromium.base.metrics.ScopedSysTraceEvent;
+import org.chromium.components.autofill_public.ViewType;
import org.chromium.components.version_info.VersionConstants;
import org.chromium.content_public.browser.RenderCoordinates;
import org.chromium.content_public.browser.WebContents;
@@ -37,6 +38,8 @@ import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.display.DisplayAndroid;
+import java.util.ArrayList;
+
/**
* This class works with Android autofill service to fill web form, it doesn't use chrome's
* autofill service or suggestion UI. All methods are supposed to be called in UI thread.
@@ -58,6 +61,11 @@ import org.chromium.ui.display.DisplayAndroid;
@JNINamespace("autofill")
public class AutofillProvider {
private static final String TAG = "AutofillProvider";
+
+ // This member is initialize at first use. Not access it directly, always through
+ // isQueryServerFieldTypesEnabled().
+ private static Boolean sIsQueryServerFieldTypesEnabled;
+
private static class FocusField {
public final short fieldIndex;
public final Rect absBound;
@@ -81,11 +89,19 @@ public class AutofillProvider {
public final int sessionId;
private FormData mFormData;
private FocusField mFocusField;
-
- public AutofillRequest(FormData formData, FocusField focus) {
+ private AutofillHintsService mAutofillHintsService;
+
+ /**
+ * @param formData the form of the AutofillRequest.
+ * @param focus the current focused field.
+ * @param hasServerPrediction whether the server type of formData is valid.
+ */
+ public AutofillRequest(FormData formData, FocusField focus, boolean hasServerPrediction) {
sessionId = getNextClientId();
mFormData = formData;
mFocusField = focus;
+ // Don't need to create binder object if server prediction is already available.
+ if (!hasServerPrediction) mAutofillHintsService = new AutofillHintsService();
}
public void fillViewStructure(ViewStructure structure) {
@@ -99,6 +115,7 @@ public class AutofillProvider {
ViewStructure child = structure.newChild(index++);
int virtualId = toVirtualId(sessionId, fieldIndex++);
child.setAutofillId(structure.getAutofillId(), virtualId);
+ field.setAutofillId(child.getAutofillId());
if (field.mAutocompleteAttr != null && !field.mAutocompleteAttr.isEmpty()) {
child.setAutofillHints(field.mAutocompleteAttr.split(" +"));
}
@@ -118,6 +135,16 @@ public class AutofillProvider {
.addAttribute("ua-autofill-hints", field.mHeuristicType)
.addAttribute("id", field.mId);
+ if (isQueryServerFieldTypesEnabled()) {
+ builder.addAttribute("crowdsourcing-autofill-hints", field.getServerType());
+ builder.addAttribute("computed-autofill-hints", field.getComputedType());
+ // Compose multiple predictions to a string separated by ','.
+ String[] predictions = field.getServerPredictions();
+ if (predictions != null && predictions.length > 0) {
+ builder.addAttribute("crowdsourcing-predictions-autofill-hints",
+ String.join(",", predictions));
+ }
+ }
switch (field.getControlType()) {
case FormFieldData.ControlType.LIST:
child.setAutofillType(View.AUTOFILL_TYPE_LIST);
@@ -249,6 +276,24 @@ public class AutofillProvider {
private static int toVirtualId(int clientId, short index) {
return (clientId << 16) | index;
}
+
+ public AutofillHintsService getAutofillHintsService() {
+ return mAutofillHintsService;
+ }
+
+ public void onQueryDone(boolean success) {
+ if (mAutofillHintsService == null) return;
+ if (success) {
+ ArrayList<ViewType> viewTypes = new ArrayList<ViewType>();
+ for (FormFieldData field : mFormData.mFields) {
+ viewTypes.add(new ViewType(field.getAutofillId(), field.getServerType(),
+ field.getComputedType(), field.getServerPredictions()));
+ }
+ mAutofillHintsService.onViewTypeAvailable(viewTypes);
+ } else {
+ mAutofillHintsService.onQueryFailed();
+ }
+ }
}
private final String mProviderName;
@@ -279,7 +324,7 @@ public class AutofillProvider {
assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
mAutofillManager = manager;
mContainerView = containerView;
- mAutofillUMA = new AutofillProviderUMA(context);
+ mAutofillUMA = new AutofillProviderUMA(context, manager.isAwGCurrentAutofillService());
mInputUIObserver = new AutofillManagerWrapper.InputUIObserver() {
@Override
public void onInputUIShown() {
@@ -321,6 +366,13 @@ public class AutofillProvider {
bundle.putCharSequence("VIRTUAL_STRUCTURE_PROVIDER_NAME", mProviderName);
bundle.putCharSequence(
"VIRTUAL_STRUCTURE_PROVIDER_VERSION", VersionConstants.PRODUCT_VERSION);
+
+ if (isQueryServerFieldTypesEnabled()) {
+ AutofillHintsService autofillHintsService = mRequest.getAutofillHintsService();
+ if (autofillHintsService != null) {
+ bundle.putBinder("AUTOFILL_HINTS_SERVICE", autofillHintsService.getBinder());
+ }
+ }
}
mRequest.fillViewStructure(structure);
if (AutofillManagerWrapper.isLoggable()) {
@@ -373,10 +425,11 @@ public class AutofillProvider {
* @param y the boundary of focus field.
* @param width the boundary of focus field.
* @param height the boundary of focus field.
+ * @param hasServerPrediction whether the server prediction arrived.
*/
@CalledByNative
- public void startAutofillSession(
- FormData formData, int focus, float x, float y, float width, float height) {
+ public void startAutofillSession(FormData formData, int focus, float x, float y, float width,
+ float height, boolean hasServerPrediction) {
// Check focusField inside short value?
// Autofill Manager might have session that wasn't started by AutofillProvider,
// we just always cancel existing session here.
@@ -387,13 +440,17 @@ public class AutofillProvider {
Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
if (mRequest != null) notifyViewExitBeforeDestroyRequest();
transformFormFieldToContainViewCoordinates(formData);
- mRequest = new AutofillRequest(formData, new FocusField((short) focus, absBound));
+ mRequest = new AutofillRequest(
+ formData, new FocusField((short) focus, absBound), hasServerPrediction);
int virtualId = mRequest.getVirtualId((short) focus);
notifyVirtualViewEntered(mContainerView, virtualId, absBound);
mAutofillUMA.onSessionStarted(mAutofillManager.isDisabled());
+ if (hasServerPrediction) {
+ mAutofillUMA.onServerTypeAvailable(formData, /*afterSessionStarted=*/false);
+ }
mAutofillTriggeredTimeMillis = System.currentTimeMillis();
- mAutofillManager.notifyNewSessionStarted();
+ mAutofillManager.notifyNewSessionStarted(hasServerPrediction);
}
/**
@@ -704,6 +761,22 @@ public class AutofillProvider {
forceNotifyFormValues();
}
+ @CalledByNative
+ private void onQueryDone(boolean success) {
+ mRequest.onQueryDone(success);
+ mAutofillUMA.onServerTypeAvailable(
+ success ? mRequest.mFormData : null, /*afterSessionStarted*/ true);
+ mAutofillManager.onQueryDone(success);
+ }
+
+ public static boolean isQueryServerFieldTypesEnabled() {
+ if (sIsQueryServerFieldTypesEnabled == null) {
+ sIsQueryServerFieldTypesEnabled =
+ AutofillProviderJni.get().isQueryServerFieldTypesEnabled();
+ }
+ return sIsQueryServerFieldTypesEnabled;
+ }
+
private void forceNotifyFormValues() {
if (mRequest == null) return;
for (int i = 0; i < mRequest.getFieldCount(); ++i) {
@@ -795,5 +868,7 @@ public class AutofillProvider {
void setAnchorViewRect(long nativeAutofillProviderAndroid, AutofillProvider caller,
View anchorView, float x, float y, float width, float height);
+
+ boolean isQueryServerFieldTypesEnabled();
}
}
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
index 394cd849c95..3f4ea071c87 100644
--- a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
@@ -5,6 +5,7 @@
package org.chromium.components.autofill;
import android.content.Context;
+import android.os.Build;
import org.chromium.autofill.mojom.SubmissionSource;
import org.chromium.base.ContextUtils;
@@ -26,6 +27,10 @@ public class AutofillProviderUMA {
public static final String UMA_AUTOFILL_CREATED_BY_ACTIVITY_CONTEXT =
"Autofill.WebView.CreatedByActivityContext";
+ // Records whether the current autofill service is AwG.
+ public static final String UMA_AUTOFILL_AWG_IS_CURRENT_SERVICE =
+ "Autofill.WebView.AwGIsCurrentService";
+
// Records what happened in an autofill session.
public static final String UMA_AUTOFILL_AUTOFILL_SESSION = "Autofill.WebView.AutofillSession";
// The possible value of UMA_AUTOFILL_AUTOFILL_SESSION.
@@ -45,6 +50,25 @@ public class AutofillProviderUMA {
public static final int USER_NOT_SELECT_SUGGESTION_USER_NOT_CHANGE_FORM_NO_FORM_SUBMITTED = 13;
public static final int AUTOFILL_SESSION_HISTOGRAM_COUNT = 14;
+ // The possible values for the server prediction availability.
+ public static final String UMA_AUTOFILL_SERVER_PREDICTION_AVAILABILITY =
+ "Autofill.WebView.ServerPredicton.PredictionAvailability";
+ public static final int SERVER_PREDICTION_NOT_AVAILABLE = 0;
+ public static final int SERVER_PREDICTION_AVAILABLE_ON_SESSION_STARTS = 1;
+ public static final int SERVER_PREDICTION_AVAILABLE_AFTER_SESSION_STARTS = 2;
+ public static final int SERVER_PREDICTION_AVAILABLE_COUNT = 3;
+
+ // The possible values for the AwG suggestion availability.
+ public static final String UMA_AUTOFILL_AWG_SUGGSTION_AVAILABILITY =
+ "Autofill.WebView.ServerPrediction.AwGSuggestionAvailability";
+ public static final int AWG_NO_SUGGESTION = 0;
+ public static final int AWG_HAS_SUGGESTION_NO_AUTOFILL = 1;
+ public static final int AWG_HAS_SUGGESTION_AUTOFILLED = 2;
+ public static final int AWG_SUGGSTION_AVAILABLE_COUNT = 3;
+
+ public static final String UMA_AUTOFILL_VALID_SERVER_PREDICTION =
+ "Autofill.WebView.ServerPredicton.HasValidServerPrediction";
+
// Records whether user changed autofilled field if user ever changed the form. The action isn't
// recorded if user didn't change form at all.
public static final String UMA_AUTOFILL_USER_CHANGED_AUTOFILLED_FIELD =
@@ -120,6 +144,31 @@ public class AutofillProviderUMA {
if (mSuggestionTimeMillis != null) {
recordTimesHistogram(UMA_AUTOFILL_SUGGESTION_TIME, mSuggestionTimeMillis);
}
+ if (!mServerPredictionAvailable && AutofillProvider.isQueryServerFieldTypesEnabled()) {
+ RecordHistogram.recordEnumeratedHistogram(
+ UMA_AUTOFILL_SERVER_PREDICTION_AVAILABILITY,
+ SERVER_PREDICTION_NOT_AVAILABLE, SERVER_PREDICTION_AVAILABLE_COUNT);
+ }
+ }
+
+ public void onServerTypeAvailable(FormData formData, boolean afterSessionStarted) {
+ if (!AutofillProvider.isQueryServerFieldTypesEnabled()) return;
+ mServerPredictionAvailable = true;
+ RecordHistogram.recordEnumeratedHistogram(UMA_AUTOFILL_SERVER_PREDICTION_AVAILABILITY,
+ afterSessionStarted ? SERVER_PREDICTION_AVAILABLE_AFTER_SESSION_STARTS
+ : SERVER_PREDICTION_AVAILABLE_ON_SESSION_STARTS,
+ SERVER_PREDICTION_AVAILABLE_COUNT);
+ if (formData != null) {
+ boolean hasValidServerData = false;
+ for (FormFieldData fieldData : formData.mFields) {
+ if (!fieldData.getServerType().equals("NO_SERVER_DATA")) {
+ hasValidServerData = true;
+ break;
+ }
+ }
+ RecordHistogram.recordBooleanHistogram(
+ UMA_AUTOFILL_VALID_SERVER_PREDICTION, hasValidServerData);
+ }
}
private int toUMAAutofillSessionValue() {
@@ -174,19 +223,62 @@ public class AutofillProviderUMA {
private int mState;
private Boolean mUserChangedAutofilledField;
+
+ // Indicates whether the server prediction arrives.
+ private boolean mServerPredictionAvailable;
+ }
+
+ /**
+ * The class to record Autofill.WebView.ServerPrediction.AwGSuggestion, is only instantiated
+ * when the Android platform AutofillServcie is AwG, This will give us more actual result in
+ * A/B experiment while only AwG supports the server prediction.
+ */
+ private static class ServerPredictionRecorder {
+ private boolean mHasSuggestions;
+ private boolean mAutofilled;
+ private boolean mRecorded;
+
+ public void onSuggestionDisplayed() {
+ mHasSuggestions = true;
+ }
+
+ public void onAutofill() {
+ mAutofilled = true;
+ }
+
+ public void recordHistograms() {
+ if (mRecorded) return;
+ mRecorded = true;
+ int sample = AWG_NO_SUGGESTION;
+ if (mHasSuggestions) {
+ sample = mAutofilled ? AWG_HAS_SUGGESTION_AUTOFILLED
+ : AWG_HAS_SUGGESTION_NO_AUTOFILL;
+ }
+ RecordHistogram.recordEnumeratedHistogram(
+ UMA_AUTOFILL_AWG_SUGGSTION_AVAILABILITY, sample, AWG_SUGGSTION_AVAILABLE_COUNT);
+ }
}
private SessionRecorder mRecorder;
private Boolean mAutofillDisabled;
- public AutofillProviderUMA(Context context) {
+ private final boolean mIsAwGCurrentAutofillService;
+ private ServerPredictionRecorder mServerPredictionRecorder;
+
+ public AutofillProviderUMA(Context context, boolean isAwGCurrentAutofillService) {
RecordHistogram.recordBooleanHistogram(UMA_AUTOFILL_CREATED_BY_ACTIVITY_CONTEXT,
ContextUtils.activityFromContext(context) != null);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ RecordHistogram.recordBooleanHistogram(
+ UMA_AUTOFILL_AWG_IS_CURRENT_SERVICE, isAwGCurrentAutofillService);
+ }
+ mIsAwGCurrentAutofillService = isAwGCurrentAutofillService;
}
public void onFormSubmitted(int submissionSource) {
if (mRecorder != null) mRecorder.record(SessionRecorder.EVENT_FORM_SUBMITTED);
recordSession();
+ if (mServerPredictionRecorder != null) mServerPredictionRecorder.recordHistograms();
// We record this no matter autofill service is disabled or not.
RecordHistogram.recordEnumeratedHistogram(UMA_AUTOFILL_SUBMISSION_SOURCE,
toUMASubmissionSource(submissionSource), SUBMISSION_SOURCE_HISTOGRAM_COUNT);
@@ -201,6 +293,9 @@ public class AutofillProviderUMA {
if (mRecorder != null) recordSession();
mRecorder = new SessionRecorder();
+ if (mIsAwGCurrentAutofillService) {
+ mServerPredictionRecorder = new ServerPredictionRecorder();
+ }
}
public void onVirtualStructureProvided() {
@@ -212,10 +307,12 @@ public class AutofillProviderUMA {
mRecorder.record(SessionRecorder.EVENT_SUGGESTION_DISPLAYED);
mRecorder.setSuggestionTimeMillis(suggestionTimeMillis);
}
+ if (mServerPredictionRecorder != null) mServerPredictionRecorder.onSuggestionDisplayed();
}
public void onAutofill() {
if (mRecorder != null) mRecorder.record(SessionRecorder.EVENT_FORM_AUTOFILLED);
+ if (mServerPredictionRecorder != null) mServerPredictionRecorder.onAutofill();
}
public void onUserChangeFieldValue(boolean isPreviouslyAutofilled) {
@@ -227,6 +324,17 @@ public class AutofillProviderUMA {
}
}
+ /**
+ * Invoked when the server query was done or has arrived when the autofill sension starts.
+ *
+ * @param formData the form of the current session, is null if the query failed.
+ * @param afterSessionStarted true if the server type predication arrive after the session
+ * starts.
+ */
+ public void onServerTypeAvailable(FormData formData, boolean afterSessionStarted) {
+ mRecorder.onServerTypeAvailable(formData, afterSessionStarted);
+ }
+
private void recordSession() {
if (mAutofillDisabled != null && !mAutofillDisabled.booleanValue() && mRecorder != null) {
mRecorder.recordHistogram();
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
index 9175bd42752..77f65ef7324 100644
--- a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
@@ -5,6 +5,7 @@
package org.chromium.components.autofill;
import android.graphics.RectF;
+import android.view.autofill.AutofillId;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
@@ -63,10 +64,18 @@ public class FormFieldData {
// Indicates whether this fields was autofilled, but changed by user.
private boolean mPreviouslyAutofilled;
+ // Provides the field type along with mHeuristicType, but could be changed
+ // after the object instantiated.
+ private String mServerType;
+ private String mComputedType;
+ private String[] mServerPredictions;
+ private AutofillId mAutofillId;
+
private FormFieldData(String name, String label, String value, String autocompleteAttr,
boolean shouldAutocomplete, String placeholder, String type, String id,
String[] optionValues, String[] optionContents, boolean isCheckField, boolean isChecked,
- int maxLength, String heuristicType, float left, float top, float right, float bottom,
+ int maxLength, String heuristicType, String serverType, String computedType,
+ String[] serverPredictions, float left, float top, float right, float bottom,
String[] datalistValues, String[] datalistLabels, boolean visible) {
mName = name;
mLabel = label;
@@ -92,6 +101,9 @@ public class FormFieldData {
}
mMaxLength = maxLength;
mHeuristicType = heuristicType;
+ mServerType = serverType;
+ mServerPredictions = serverPredictions;
+ mComputedType = computedType;
mBounds = new RectF(left, top, right, bottom);
mVisible = visible;
}
@@ -137,6 +149,26 @@ public class FormFieldData {
}
@CalledByNative
+ private void updateFieldTypes(
+ String serverType, String computedType, String[] serverPredictions) {
+ mServerType = serverType;
+ mComputedType = computedType;
+ mServerPredictions = serverPredictions;
+ }
+
+ public String getServerType() {
+ return mServerType;
+ }
+
+ public String getComputedType() {
+ return mComputedType;
+ }
+
+ public String[] getServerPredictions() {
+ return mServerPredictions;
+ }
+
+ @CalledByNative
public boolean isChecked() {
return mIsChecked;
}
@@ -150,17 +182,25 @@ public class FormFieldData {
mAutofilled = autofilled;
}
+ public void setAutofillId(AutofillId id) {
+ mAutofillId = id;
+ }
+
+ public AutofillId getAutofillId() {
+ return mAutofillId;
+ }
+
@CalledByNative
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public static FormFieldData createFormFieldData(String name, String label, String value,
String autocompleteAttr, boolean shouldAutocomplete, String placeholder, String type,
String id, String[] optionValues, String[] optionContents, boolean isCheckField,
- boolean isChecked, int maxLength, String heuristicType, float left, float top,
- float right, float bottom, String[] datalistValues, String[] datalistLabels,
- boolean visible) {
+ boolean isChecked, int maxLength, String heuristicType, String serverType,
+ String computedType, String[] serverPredictions, float left, float top, float right,
+ float bottom, String[] datalistValues, String[] datalistLabels, boolean visible) {
return new FormFieldData(name, label, value, autocompleteAttr, shouldAutocomplete,
placeholder, type, id, optionValues, optionContents, isCheckField, isChecked,
- maxLength, heuristicType, left, top, right, bottom, datalistValues, datalistLabels,
- visible);
+ maxLength, heuristicType, serverType, computedType, serverPredictions, left, top,
+ right, bottom, datalistValues, datalistLabels, visible);
}
}
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl
new file mode 100644
index 00000000000..dd5dd191b39
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill_public;
+
+import android.os.Bundle;
+
+import org.chromium.components.autofill_public.IViewTypeCallback;
+
+/**
+ * Interface to provide the autofill hints that are unable to be supported
+ * by Android framework.
+ *
+ * The autofill service could get the binder from ViewStructure.
+ * Bundle bundle = viewStructure.getExtras();
+ * IBinder binder = bundle.getBinder("AUTOFILL_HINTS_SERVICE");
+ */
+interface IAutofillHintsService {
+ // Register the IViewTypeCallback to get the server prediction type.
+ void registerViewTypeCallback(IViewTypeCallback callback);
+}
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl
new file mode 100644
index 00000000000..70fa902c55d
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill_public;
+
+import android.os.Bundle;
+
+import org.chromium.components.autofill_public.ViewType;
+
+/**
+ * The interface for AutofillHintsService to provide the type of view.
+ */
+interface IViewTypeCallback {
+ // Invoked when the query succeeds, though the server might not have the
+ // prediction of the views.
+ void onViewTypeAvailable(in List<ViewType> viewTypes);
+
+ // Invoked when the query fails, mostly because of the connection or server
+ // error.
+ void onQueryFailed();
+}
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/OWNERS b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/OWNERS
new file mode 100644
index 00000000000..8f094e0099e
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/OWNERS
@@ -0,0 +1,2 @@
+per-file *.aidl=set noparent
+per-file *.aidl=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/README.md b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/README.md
new file mode 100644
index 00000000000..7e77e096932
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/README.md
@@ -0,0 +1,53 @@
+# How to integrate the AutofillHintsService
+
+1. Add all files of this directory to your project.
+2. Get the binder in your autofill service as below
+
+ ```java
+ public void processNode(AssistStructure.ViewNode node) {
+ Bundle bundle = node.getExtras();
+ if (bundle != null) {
+ IBinder binder = bundle.getBinder("AUTOFILL_HINTS_SERVICE");
+ if (binder != null) {
+ callViewTypeService(binder);
+ } else {
+ Log.e("MyAutofillService", "binder is null.");
+ }
+ } else {
+ Log.e("MyAutofillService", "bundle is null.");
+ }
+ }
+ ```
+
+3. Register the ViewTypeCallback
+
+ ```java
+ private void callViewTypeService(IBinder binder) {
+ IViewTypeService viewTypeService = IViewTypeService.Stub.asInterface(binder);
+ if (viewTypeService != null) {
+ try {
+ if (mViewTypeCallback == null) mViewTypeCallback = new ViewTypeCallback();
+ viewTypeService.registerViewTypeCallback(mViewTypeCallback.getBinder());
+ Log.d("MyAutofillService", " registerViewTypeCallback ");
+ } catch (Exception e) {
+ Log.e("MyAutofillService", " registerViewTypeCallback exception", e);
+ }
+ } else {
+ Log.e("MyAutofillService", "viewTypeService is null.");
+ }
+ }
+ ```
+
+4. A list of ViewType will be returned from ViewTypeCallback when they are available.
+
+ ```java
+ public void onViewTypeAvailable(List<ViewType> viewTypeList) {
+ for(ViewType viewType : viewTypeList) {
+ if (viewType.getServerPredictions() ! = null) {
+ // Uses server predictions if they are available.
+ } else {
+ // otherwise, uses viewType.mServerType.
+ }
+ }
+ }
+ ```
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.aidl b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.aidl
new file mode 100644
index 00000000000..6a7398d38a4
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.aidl
@@ -0,0 +1,7 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill_public;
+
+parcelable ViewType;
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.java
new file mode 100644
index 00000000000..fe0d9e18e28
--- /dev/null
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill_public/ViewType.java
@@ -0,0 +1,88 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill_public;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.autofill.AutofillId;
+
+import org.chromium.base.annotations.VerifiesOnO;
+
+/**
+ * This class is used to send the server and computed view type to the autofill service.
+ * The valid types are listed in the two FieldTypeToStringPiece() functions in
+ * components/autofill/core/browser/field_types.cc. Note that the list of possibly returned strings
+ * can and will change in the future.
+ */
+@TargetApi(Build.VERSION_CODES.O)
+@VerifiesOnO
+public class ViewType implements Parcelable {
+ /**
+ * The AutofillId of the view that types are for.
+ */
+ public final AutofillId mAutofillId;
+
+ /**
+ * The type from Chrome autofill server.
+ */
+ public final String mServerType;
+
+ /**
+ * The type computed overall type. The valid types are the same as for mServerType.
+ */
+ public final String mComputedType;
+
+ private String[] mServerPredictions;
+
+ public static final Parcelable.Creator<ViewType> CREATOR = new Parcelable.Creator<ViewType>() {
+ @Override
+ public ViewType createFromParcel(Parcel in) {
+ return new ViewType(in);
+ }
+
+ @Override
+ public ViewType[] newArray(int size) {
+ return new ViewType[size];
+ }
+ };
+
+ public ViewType(
+ AutofillId id, String serverType, String computedType, String[] serverPredictions) {
+ mAutofillId = id;
+ mServerType = serverType;
+ mComputedType = computedType;
+ mServerPredictions = serverPredictions;
+ }
+
+ private ViewType(Parcel in) {
+ mAutofillId = AutofillId.CREATOR.createFromParcel(in);
+ mServerType = in.readString();
+ mComputedType = in.readString();
+ in.readStringArray(mServerPredictions);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ mAutofillId.writeToParcel(parcel, flags);
+ parcel.writeString(mServerType);
+ parcel.writeString(mComputedType);
+ parcel.writeStringArray(mServerPredictions);
+ }
+
+ /**
+ * @return the server predictions, they are in the order of the confidence. The mServerType
+ * shall be used if the server predictions aren't available.
+ */
+ public String[] getServerPredictions() {
+ return mServerPredictions;
+ }
+}
diff --git a/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java b/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
index 5d63ae0630b..87c73025e49 100644
--- a/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
+++ b/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
@@ -83,11 +83,11 @@ public class AutofillProviderTest {
public void testTransformFormFieldToContainViewCoordinates() {
ArrayList<FormFieldData> fields = new ArrayList<FormFieldData>(1);
fields.add(FormFieldData.createFormFieldData(null, null, null, null, false, null, null,
- null, null, null, false, false, 0, null, 10 /* left */, 20 /* top */,
- 300 /* right */, 60 /*bottom*/, null, null, true));
+ null, null, null, false, false, 0, null, null, null, null, 10 /* left */,
+ 20 /* top */, 300 /* right */, 60 /*bottom*/, null, null, true));
fields.add(FormFieldData.createFormFieldData(null, null, null, null, false, null, null,
- null, null, null, false, false, 0, null, 20 /* left */, 100 /* top */,
- 400 /* right */, 200 /*bottom*/, null, null, true));
+ null, null, null, false, false, 0, null, null, null, null, 20 /* left */,
+ 100 /* top */, 400 /* right */, 200 /*bottom*/, null, null, true));
FormData formData = new FormData(null, null, fields);
mAutofillProvider.transformFormFieldToContainViewCoordinates(formData);
RectF result = formData.mFields.get(0).getBoundsInContainerViewCoordinates();
diff --git a/chromium/components/autofill/android/provider/test_support/BUILD.gn b/chromium/components/autofill/android/provider/test_support/BUILD.gn
new file mode 100644
index 00000000000..6ed8af92b68
--- /dev/null
+++ b/chromium/components/autofill/android/provider/test_support/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+testonly = true
+
+android_library("component_autofill_provider_java_test_support") {
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+ sources = [
+ "java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java",
+ "java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java",
+ ]
+ deps = [
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//base:jni_java",
+ "//components/autofill/android/provider:autofill_aidl",
+ "//components/autofill/android/provider:java",
+ "//content/public/android:content_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ ]
+}
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java",
+ ]
+}
+
+source_set("component_autofill_provider_native_test_support") {
+ sources = [ "autofill_provider_test_helper.cc" ]
+ deps = [
+ ":jni_headers",
+ "//base",
+ "//components/autofill/content/browser",
+ "//components/autofill/core/browser:test_support",
+ "//content/public/browser",
+ ]
+}
diff --git a/chromium/components/autofill/android/provider/test_support/autofill_provider_test_helper.cc b/chromium/components/autofill/android/provider/test_support/autofill_provider_test_helper.cc
new file mode 100644
index 00000000000..1d244099f3e
--- /dev/null
+++ b/chromium/components/autofill/android/provider/test_support/autofill_provider_test_helper.cc
@@ -0,0 +1,173 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/android/provider/test_support/jni_headers/AutofillProviderTestHelper_jni.h"
+
+#include "base/android/jni_array.h"
+#include "base/base64.h"
+#include "base/strings/string16.h"
+#include "components/autofill/content/browser/content_autofill_driver.h"
+#include "components/autofill/content/browser/content_autofill_driver_factory.h"
+#include "components/autofill/core/browser/autofill_provider.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "content/public/browser/web_contents.h"
+
+namespace autofill {
+
+namespace {
+AutofillHandler* GetAutofillHandler(content::WebContents* web_contents,
+ content::RenderFrameHost* rfh) {
+ // Avoid using ContentAutofillDriver::GetForRenderFrameHost(), it will create
+ // a new ContentAutofillDriver.
+ if (ContentAutofillDriverFactory* factory =
+ ContentAutofillDriverFactory::FromWebContents(web_contents)) {
+ if (ContentAutofillDriver* driver =
+ static_cast<ContentAutofillDriver*>(factory->DriverForKey(rfh))) {
+ return driver->autofill_handler();
+ }
+ }
+ return nullptr;
+}
+
+AutofillHandler* ToMainFrameAutofillHandler(
+ const base::android::JavaParamRef<jobject>& jweb_contents) {
+ content::WebContents* web_contents =
+ content::WebContents::FromJavaWebContents(jweb_contents);
+ CHECK(web_contents);
+ AutofillHandler* autofill_handler =
+ GetAutofillHandler(web_contents, web_contents->GetMainFrame());
+ CHECK(autofill_handler);
+ return autofill_handler;
+}
+
+} // namespace
+
+static void JNI_AutofillProviderTestHelper_DisableDownloadServerForTesting(
+ JNIEnv* env_md_ctx_st) {
+ AutofillProvider::set_is_download_manager_disabled_for_testing();
+}
+
+static jboolean
+JNI_AutofillProviderTestHelper_SimulateMainFrameAutofillServerResponseForTesting(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jweb_contents,
+ const base::android::JavaParamRef<jobjectArray>& jfield_ids,
+ const base::android::JavaParamRef<jintArray>& jfield_types) {
+ std::vector<base::string16> field_ids;
+ base::android::AppendJavaStringArrayToStringVector(env, jfield_ids,
+ &field_ids);
+ std::vector<int> field_types;
+ base::android::JavaIntArrayToIntVector(env, jfield_types, &field_types);
+
+ AutofillHandler* autofill_handler = ToMainFrameAutofillHandler(jweb_contents);
+ const std::map<FormRendererId, std::unique_ptr<FormStructure>>&
+ form_structures = autofill_handler->form_structures();
+ CHECK(!form_structures.empty());
+
+ // Make API response with suggestions.
+ AutofillQueryResponse response;
+ AutofillQueryResponse::FormSuggestion* form_suggestion;
+
+ form_suggestion = response.add_form_suggestions();
+ size_t found_fields_count = 0;
+ std::vector<FormSignature> signatures;
+ for (auto& j : form_structures) {
+ FormData formData = j.second->ToFormData();
+ for (size_t i = 0; i < field_ids.size(); ++i) {
+ for (auto form_field_data : formData.fields) {
+ if (form_field_data.id_attribute == field_ids[i]) {
+ autofill::test::AddFieldSuggestionToForm(
+ form_field_data,
+ static_cast<autofill::ServerFieldType>(field_types[i]),
+ form_suggestion);
+ found_fields_count++;
+ break;
+ }
+ }
+ }
+ if (found_fields_count > 0) {
+ signatures = autofill::test::GetEncodedSignatures(*(j.second));
+ break;
+ }
+ }
+ CHECK(found_fields_count == field_ids.size());
+
+ std::string response_string;
+ CHECK(response.SerializeToString(&response_string));
+ std::string encoded_response_string;
+ base::Base64Encode(response_string, &encoded_response_string);
+ autofill_handler->OnLoadedServerPredictionsForTest(encoded_response_string,
+ signatures);
+ return true;
+}
+
+static jboolean
+JNI_AutofillProviderTestHelper_SimulateMainFramePredictionsAutofillServerResponseForTesting(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jweb_contents,
+ const base::android::JavaParamRef<jobjectArray>& jfield_ids,
+ const base::android::JavaParamRef<jobjectArray>& jfield_types) {
+ std::vector<base::string16> field_ids;
+ base::android::AppendJavaStringArrayToStringVector(env, jfield_ids,
+ &field_ids);
+ std::vector<std::vector<int>> field_types;
+ base::android::JavaArrayOfIntArrayToIntVector(env, jfield_types,
+ &field_types);
+
+ AutofillHandler* autofill_handler = ToMainFrameAutofillHandler(jweb_contents);
+ const std::map<FormRendererId, std::unique_ptr<FormStructure>>&
+ form_structures = autofill_handler->form_structures();
+ CHECK(!form_structures.empty());
+
+ // Make API response with suggestions.
+ AutofillQueryResponse response;
+ AutofillQueryResponse::FormSuggestion* form_suggestion;
+
+ form_suggestion = response.add_form_suggestions();
+ size_t found_fields_count = 0;
+ std::vector<FormSignature> signatures;
+ for (auto& j : form_structures) {
+ FormData formData = j.second->ToFormData();
+ for (size_t i = 0; i < field_ids.size(); ++i) {
+ for (auto form_field_data : formData.fields) {
+ if (form_field_data.id_attribute == field_ids[i]) {
+ autofill::test::AddFieldPredictionsToForm(
+ form_field_data, field_types[i], form_suggestion);
+ found_fields_count++;
+ break;
+ }
+ }
+ }
+ if (found_fields_count > 0) {
+ signatures = autofill::test::GetEncodedSignatures(*(j.second));
+ CHECK(found_fields_count == field_ids.size());
+ }
+ }
+
+ std::string response_string;
+ CHECK(response.SerializeToString(&response_string));
+ std::string encoded_response_string;
+ base::Base64Encode(response_string, &encoded_response_string);
+ autofill_handler->OnLoadedServerPredictionsForTest(encoded_response_string,
+ signatures);
+ return true;
+}
+
+static void
+JNI_AutofillProviderTestHelper_SimulateMainFrameAutofillQueryFailedForTesting(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jweb_contents) {
+ AutofillHandler* autofill_handler = ToMainFrameAutofillHandler(jweb_contents);
+ const std::map<FormRendererId, std::unique_ptr<FormStructure>>&
+ form_structures = autofill_handler->form_structures();
+ // Always use first form.
+ CHECK(form_structures.size());
+ autofill_handler->OnServerRequestErrorForTest(
+ *(autofill::test::GetEncodedSignatures(*(form_structures.begin()->second))
+ .begin()),
+ AutofillDownloadManager::RequestType::REQUEST_QUERY, 400);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java b/chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java
new file mode 100644
index 00000000000..742e98d7471
--- /dev/null
+++ b/chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.os.IBinder;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.components.autofill_public.IAutofillHintsService;
+import org.chromium.components.autofill_public.IViewTypeCallback;
+import org.chromium.components.autofill_public.ViewType;
+
+import java.util.List;
+
+/**
+ * This class implements and registers IViewTypeCallback for testing.
+ */
+public class AutofillHintsServiceTestHelper {
+ public void registerViewTypeService(IBinder binder) throws Exception {
+ IAutofillHintsService.Stub.asInterface(binder).registerViewTypeCallback(getBinder());
+ }
+
+ private IViewTypeCallback.Stub mBinder = new IViewTypeCallback.Stub() {
+ @Override
+ public void onViewTypeAvailable(List<ViewType> viewTypeList) {
+ mViewTypeList = viewTypeList;
+ mCallbackHelper.notifyCalled();
+ }
+
+ @Override
+ public void onQueryFailed() {
+ mQueryFailed = true;
+ mCallbackHelper.notifyCalled();
+ }
+ };
+
+ private List<ViewType> mViewTypeList;
+ private boolean mQueryFailed;
+ private CallbackHelper mCallbackHelper = new CallbackHelper();
+
+ public IViewTypeCallback getBinder() {
+ return mBinder;
+ }
+
+ public List<ViewType> getViewTypes() {
+ return mViewTypeList;
+ }
+
+ public boolean isQueryFailed() {
+ return mQueryFailed;
+ }
+
+ public void waitForCallbackInvoked() throws Exception {
+ mCallbackHelper.waitForCallback(0);
+ }
+}
diff --git a/chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java b/chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java
new file mode 100644
index 00000000000..5db6332bce7
--- /dev/null
+++ b/chromium/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java
@@ -0,0 +1,64 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.annotations.VerifiesOnO;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * The help class for Autofill Provider test to access the native code.
+ */
+@VerifiesOnO
+@TargetApi(Build.VERSION_CODES.O)
+@JNINamespace("autofill")
+public class AutofillProviderTestHelper {
+ /**
+ * Disable the download server for testing to avoid the server response affect the integration
+ * tests. Must be called before WebContents is created.
+ */
+ public static void disableDownloadServerForTesting() {
+ AutofillProviderTestHelperJni.get().disableDownloadServerForTesting();
+ }
+
+ /**
+ * Simulate the primary server type only.
+ */
+ public static boolean simulateMainFrameAutofillServerResponseForTesting(
+ WebContents webContents, String[] fieldIds, int[] fieldTypes) {
+ return AutofillProviderTestHelperJni.get()
+ .simulateMainFrameAutofillServerResponseForTesting(
+ webContents, fieldIds, fieldTypes);
+ }
+
+ /**
+ * Simulate the server predictions, the first prediction will be set as primary server type.
+ */
+ public static boolean simulateMainFramePredictionsAutofillServerResponseForTesting(
+ WebContents webContents, String[] fieldIds, int[][] fieldTypes) {
+ return AutofillProviderTestHelperJni.get()
+ .simulateMainFramePredictionsAutofillServerResponseForTesting(
+ webContents, fieldIds, fieldTypes);
+ }
+
+ public static void simulateMainFrameAutofillQueryFailedForTesting(WebContents webContents) {
+ AutofillProviderTestHelperJni.get().simulateMainFrameAutofillQueryFailedForTesting(
+ webContents);
+ }
+
+ @NativeMethods
+ interface Natives {
+ void disableDownloadServerForTesting();
+ boolean simulateMainFrameAutofillServerResponseForTesting(
+ WebContents webContents, String[] fieldIds, int[] fieldTypes);
+ boolean simulateMainFramePredictionsAutofillServerResponseForTesting(
+ WebContents webContents, String[] fieldIds, int[][] fieldTypes);
+ void simulateMainFrameAutofillQueryFailedForTesting(WebContents webContents);
+ }
+}
diff --git a/chromium/components/autofill/content/browser/BUILD.gn b/chromium/components/autofill/content/browser/BUILD.gn
index d54493f4c21..2cb8cb1f316 100644
--- a/chromium/components/autofill/content/browser/BUILD.gn
+++ b/chromium/components/autofill/content/browser/BUILD.gn
@@ -31,9 +31,11 @@ static_library("browser") {
"//base:i18n",
"//components/os_crypt",
"//components/prefs",
+ "//components/profile_metrics",
"//components/resources",
"//components/strings",
"//components/user_prefs",
+ "//components/version_info",
"//content/public/browser",
"//content/public/common",
"//gpu/config",
@@ -77,6 +79,7 @@ source_set("unit_tests") {
"//components/autofill/core/browser",
"//components/autofill/core/browser:test_support",
"//components/autofill/core/common",
+ "//components/version_info",
"//content/public/browser",
"//content/public/common",
"//content/test:test_support",
diff --git a/chromium/components/autofill/content/browser/DEPS b/chromium/components/autofill/content/browser/DEPS
index c98729d3c65..9f9c1a2c0e0 100644
--- a/chromium/components/autofill/content/browser/DEPS
+++ b/chromium/components/autofill/content/browser/DEPS
@@ -1,12 +1,13 @@
include_rules = [
"+content/public/browser",
"+components/keyed_service/content",
+ "+components/version_info",
+ "+components/profile_metrics",
"+crypto/random.h",
"+gpu/config/gpu_info.h",
"+services/device/public",
"+services/service_manager/public/mojom",
"+third_party/blink/public/common",
- "+third_party/blink/public/platform/web_rect.h",
]
specific_include_rules = {
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 3c37af33dac..0bf21286ba2 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -4,6 +4,7 @@
#include "components/autofill/content/browser/content_autofill_driver.h"
+#include <tuple>
#include <utility>
#include <vector>
@@ -12,12 +13,14 @@
#include "build/build_config.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_handler_proxy.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/payments/payments_service_url.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/profile_metrics/browser_profile_type.h"
+#include "components/version_info/channel.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_controller.h"
@@ -36,13 +39,31 @@
#include "ui/gfx/geometry/size_f.h"
#include "url/origin.h"
+namespace {
+
+bool ShouldEnableHeavyFormDataScraping(const version_info::Channel channel) {
+ switch (channel) {
+ case version_info::Channel::CANARY:
+ case version_info::Channel::DEV:
+ return true;
+ case version_info::Channel::STABLE:
+ case version_info::Channel::BETA:
+ case version_info::Channel::UNKNOWN:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace
+
namespace autofill {
ContentAutofillDriver::ContentAutofillDriver(
content::RenderFrameHost* render_frame_host,
AutofillClient* client,
const std::string& app_locale,
- AutofillManager::AutofillDownloadManagerState enable_download_manager,
+ AutofillHandler::AutofillDownloadManagerState enable_download_manager,
AutofillProvider* provider)
: render_frame_host_(render_frame_host),
autofill_manager_(nullptr),
@@ -51,11 +72,14 @@ ContentAutofillDriver::ContentAutofillDriver(
// AutofillManager isn't used if provider is valid, Autofill provider is
// currently used by Android WebView only.
if (provider) {
- SetAutofillProvider(provider);
+ SetAutofillProvider(provider, client, enable_download_manager);
} else {
SetAutofillManager(std::make_unique<AutofillManager>(
this, client, app_locale, enable_download_manager));
}
+ if (client && ShouldEnableHeavyFormDataScraping(client->GetChannel())) {
+ GetAutofillAgent()->EnableHeavyFormDataScraping();
+ }
}
ContentAutofillDriver::~ContentAutofillDriver() = default;
@@ -75,6 +99,17 @@ void ContentAutofillDriver::BindPendingReceiver(
}
bool ContentAutofillDriver::IsIncognito() const {
+ // TODO(https://crbug.com/1125474): Enable Autofill for Ephemeral Guest
+ // profiles.
+ // TODO(https://crbug.com/1125474): Consider renaming this function to
+ // |IsOffTheRecord| after deprecation of off-the-record or ephemeral Guest
+ // profiles.
+ if (autofill_manager_ &&
+ autofill_manager_->client()->GetProfileType() ==
+ profile_metrics::BrowserProfileType::kEphemeralGuest) {
+ return true;
+ }
+
return render_frame_host_->GetSiteInstance()
->GetBrowserContext()
->IsOffTheRecord();
@@ -136,8 +171,10 @@ void ContentAutofillDriver::SendFormDataToRenderer(
void ContentAutofillDriver::PropagateAutofillPredictions(
const std::vector<FormStructure*>& forms) {
- autofill_manager_->client()->PropagateAutofillPredictions(render_frame_host_,
- forms);
+ AutofillHandler* handler =
+ autofill_manager_ ? autofill_manager_ : autofill_handler_.get();
+ DCHECK(handler);
+ handler->PropagateAutofillPredictions(render_frame_host_, forms);
}
void ContentAutofillDriver::HandleParsedForms(
@@ -216,12 +253,11 @@ gfx::RectF ContentAutofillDriver::TransformBoundingBoxToViewportCoordinates(
}
net::IsolationInfo ContentAutofillDriver::IsolationInfo() {
- return render_frame_host_->GetIsolationInfoForSubresources();
+ return render_frame_host_->GetPendingIsolationInfoForSubresources();
}
-void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms,
- base::TimeTicks timestamp) {
- autofill_handler_->OnFormsSeen(forms, timestamp);
+void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms) {
+ autofill_handler_->OnFormsSeen(forms);
}
void ContentAutofillDriver::SetFormToBeProbablySubmitted(
@@ -326,6 +362,14 @@ void ContentAutofillDriver::DidNavigateFrame(
return;
}
+ ShowOfferNotificationIfApplicable(navigation_handle);
+
+ // When IsServedFromBackForwardCache, the form data is not parsed
+ // again. So, we should keep and use the autofill handler's
+ // form_structures from BFCache for form submit.
+ if (navigation_handle->IsServedFromBackForwardCache())
+ return;
+
submitted_forms_.clear();
autofill_handler_->Reset();
}
@@ -334,9 +378,6 @@ void ContentAutofillDriver::SetAutofillManager(
std::unique_ptr<AutofillManager> manager) {
autofill_handler_ = std::move(manager);
autofill_manager_ = static_cast<AutofillManager*>(autofill_handler_.get());
- autofill_external_delegate_ =
- std::make_unique<AutofillExternalDelegate>(autofill_manager_, this);
- autofill_manager_->SetExternalDelegate(autofill_external_delegate_.get());
}
ContentAutofillDriver::ContentAutofillDriver()
@@ -381,9 +422,12 @@ void ContentAutofillDriver::RemoveHandler(
view->GetRenderWidgetHost()->RemoveKeyPressEventCallback(handler);
}
-void ContentAutofillDriver::SetAutofillProvider(AutofillProvider* provider) {
- autofill_handler_ =
- std::make_unique<AutofillHandlerProxy>(this, log_manager_, provider);
+void ContentAutofillDriver::SetAutofillProvider(
+ AutofillProvider* provider,
+ AutofillClient* client,
+ AutofillHandler::AutofillDownloadManagerState enable_download_manager) {
+ autofill_handler_ = std::make_unique<AutofillHandlerProxy>(
+ this, client, provider, enable_download_manager);
GetAutofillAgent()->SetUserGestureRequired(false);
GetAutofillAgent()->SetSecureContextRequired(true);
GetAutofillAgent()->SetFocusRequiresScroll(false);
@@ -428,10 +472,51 @@ void ContentAutofillDriver::ReportAutofillWebOTPMetrics(
}
void ContentAutofillDriver::SetAutofillProviderForTesting(
- AutofillProvider* provider) {
- SetAutofillProvider(provider);
+ AutofillProvider* provider,
+ AutofillClient* client) {
+ SetAutofillProvider(provider, client,
+ AutofillHandler::AutofillDownloadManagerState::
+ DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
// AutofillManager isn't used if provider is valid.
autofill_manager_ = nullptr;
}
+void ContentAutofillDriver::ShowOfferNotificationIfApplicable(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->IsInMainFrame())
+ return;
+
+ // TODO(crbug.com/1093057): Android webview does not have |autofill_manager_|,
+ // so flow is not enabled in Android Webview.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableOfferNotification) ||
+ !autofill_manager_) {
+ return;
+ }
+
+ AutofillOfferManager* offer_manager = autofill_manager_->offer_manager();
+ // This happens in the Incognito mode.
+ if (!offer_manager)
+ return;
+
+ GURL url = autofill_manager_->client()->GetLastCommittedURL();
+ if (!offer_manager->IsUrlEligible(url))
+ return;
+
+ // Try to show offer notification when the last committed URL has the domain
+ // that an offer is applicable for.
+ std::tuple<std::vector<GURL>, GURL, CreditCard*> result =
+ offer_manager->GetEligibleDomainsAndCardForOfferForUrl(url);
+ std::vector<GURL>& domains = std::get<0>(result);
+ GURL offer_details_url = std::get<1>(result);
+ CreditCard* card = std::get<2>(result);
+ // TODO(crbug.com/1093057): Update return condition once we introduce the
+ // promo offers.
+ if (domains.empty() || !card)
+ return;
+
+ autofill_manager_->client()->ShowOfferNotificationIfApplicable(
+ domains, offer_details_url, card);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index efa287202f4..f659b5d0013 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -16,7 +16,6 @@
#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
#include "components/autofill/core/browser/autofill_driver.h"
-#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
@@ -63,7 +62,7 @@ class ContentAutofillDriver : public AutofillDriver,
content::RenderFrameHost* render_frame_host,
AutofillClient* client,
const std::string& app_locale,
- AutofillManager::AutofillDownloadManagerState enable_download_manager,
+ AutofillHandler::AutofillDownloadManagerState enable_download_manager,
AutofillProvider* provider);
~ContentAutofillDriver() override;
@@ -107,8 +106,7 @@ class ContentAutofillDriver : public AutofillDriver,
// mojom::AutofillDriver:
void SetFormToBeProbablySubmitted(
const base::Optional<FormData>& form) override;
- void FormsSeen(const std::vector<FormData>& forms,
- base::TimeTicks timestamp) override;
+ void FormsSeen(const std::vector<FormData>& forms) override;
void FormSubmitted(const FormData& form,
bool known_success,
mojom::SubmissionSource source) override;
@@ -155,10 +153,10 @@ class ContentAutofillDriver : public AutofillDriver,
const content::RenderWidgetHost::KeyPressEventCallback& handler);
void RemoveKeyPressHandler();
- void SetAutofillProviderForTesting(AutofillProvider* provider);
+ void SetAutofillProviderForTesting(AutofillProvider* provider,
+ AutofillClient* client);
- // Sets the manager to |manager| and sets |manager|'s external delegate
- // to |autofill_external_delegate_|. Takes ownership of |manager|.
+ // Sets the manager to |manager|. Takes ownership of |manager|.
void SetAutofillManager(std::unique_ptr<AutofillManager> manager);
// Reports whether a document collects phone numbers, uses one time code, uses
@@ -182,12 +180,20 @@ class ContentAutofillDriver : public AutofillDriver,
void RemoveHandler(
const content::RenderWidgetHost::KeyPressEventCallback& handler) override;
- void SetAutofillProvider(AutofillProvider* provider);
+ void SetAutofillProvider(
+ AutofillProvider* provider,
+ AutofillClient* client,
+ AutofillHandler::AutofillDownloadManagerState enable_download_manager);
// Returns whether navigator.credentials.get({otp: {transport:"sms"}}) has
// been used.
bool DocumentUsedWebOTP() const;
+ // Show a bubble or infobar indicating that the current page has an eligible
+ // offer or reward, if the bubble/infobar is not currently being visible.
+ void ShowOfferNotificationIfApplicable(
+ content::NavigationHandle* navigation_handle);
+
// Weak ref to the RenderFrameHost the driver is associated with. Should
// always be non-NULL and valid for lifetime of |this|.
content::RenderFrameHost* const render_frame_host_;
@@ -213,10 +219,6 @@ class ContentAutofillDriver : public AutofillDriver,
// Pointer to an implementation of InternalAuthenticator.
std::unique_ptr<InternalAuthenticator> authenticator_impl_;
- // AutofillExternalDelegate instance that this object instantiates in the
- // case where the Autofill native UI is enabled.
- std::unique_ptr<AutofillExternalDelegate> autofill_external_delegate_;
-
KeyPressHandlerManager key_press_handler_manager_;
LogManager* const log_manager_;
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 3862c76d670..508edb416b1 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -21,6 +21,7 @@
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data_predictions.h"
+#include "components/version_info/version_info.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/storage_partition.h"
@@ -141,6 +142,7 @@ class FakeAutofillAgent : public mojom::AutofillAgent {
// Mocked mojom::AutofillAgent methods:
MOCK_METHOD0(FirstUserGestureObservedInTab, void());
+ MOCK_METHOD0(EnableHeavyFormDataScraping, void());
private:
void CallDone() {
@@ -311,10 +313,11 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
content::RenderViewHostTestHarness::TearDown();
}
- void Navigate(bool same_document) {
+ void Navigate(bool same_document, bool from_bfcache = false) {
content::MockNavigationHandle navigation_handle(GURL(), main_rfh());
navigation_handle.set_has_committed(true);
navigation_handle.set_is_same_document(same_document);
+ navigation_handle.set_is_served_from_bfcache(from_bfcache);
driver_->DidNavigateFrame(&navigation_handle);
}
@@ -335,6 +338,11 @@ TEST_F(ContentAutofillDriverTest, NavigatedMainFrameSameDocument) {
Navigate(/*same_document=*/true);
}
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameFromBackForwardCache) {
+ EXPECT_CALL(*driver_->mock_autofill_manager(), Reset()).Times(0);
+ Navigate(/*same_document=*/false, /*from_bfcache=*/true);
+}
+
TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
int input_page_id = 42;
FormData input_form_data;
@@ -456,4 +464,30 @@ TEST_F(ContentAutofillDriverTest, PreviewFieldWithValue) {
EXPECT_EQ(input_value, output_value);
}
+TEST_F(ContentAutofillDriverTest, EnableHeavyFormDataScraping) {
+ struct TestCase {
+ version_info::Channel channel;
+ bool heavy_scraping_enabled;
+ } kTestCases[] = {{version_info::Channel::CANARY, true},
+ {version_info::Channel::DEV, true},
+ {version_info::Channel::UNKNOWN, false},
+ {version_info::Channel::BETA, false},
+ {version_info::Channel::STABLE, false}};
+
+ for (auto test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "channel: "
+ << version_info::GetChannelString(test_case.channel));
+ test_autofill_client_->set_channel_for_testing(test_case.channel);
+ EXPECT_CALL(fake_agent_, EnableHeavyFormDataScraping())
+ .Times(test_case.heavy_scraping_enabled ? 1 : 0);
+
+ std::unique_ptr<ContentAutofillDriver> driver(new TestContentAutofillDriver(
+ web_contents()->GetMainFrame(), test_autofill_client_.get()));
+
+ base::RunLoop().RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(&fake_agent_);
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index 994561d81ae..2607d63a434 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -45,7 +45,6 @@
#include "services/device/public/mojom/geolocation.mojom.h"
#include "services/device/public/mojom/geolocation_context.mojom.h"
#include "services/device/public/mojom/geoposition.mojom.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
@@ -328,7 +327,7 @@ void FingerprintDataLoader::OnGpuInfoUpdate() {
return;
DCHECK(gpu_observation_.IsObservingSource(gpu_data_manager_));
- gpu_observation_.RemoveObservation();
+ gpu_observation_.Reset();
MaybeFillFingerprint();
}
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index 885c1d4206d..6ef24aa48ff 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -21,7 +21,6 @@
#include "services/device/public/mojom/geoposition.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "ui/gfx/geometry/rect.h"
using testing::ElementsAre;
diff --git a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
index 28e6bd73674..28177255d0b 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
@@ -78,6 +78,10 @@ interface AutofillAgent {
// Set whether or not an assistant action is currently running an action.
SetAssistantActionState(bool running);
+
+ // Allows heavy scraping of form data (e.g., button titles for
+ // unowned forms).
+ EnableHeavyFormDataScraping();
};
// There is one instance of this interface per render frame in the render
diff --git a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
index 106f0d69d37..a87410e220b 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
@@ -22,7 +22,7 @@ interface AutofillDriver {
// Notification that forms have been seen that are candidates for
// filling/submitting by the AutofillManager.
- FormsSeen(array<FormData> forms, mojo_base.mojom.TimeTicks timestamp);
+ FormsSeen(array<FormData> forms);
// Notification that a form has been submitted. The |known_success| indicates
// whether the submission succeeded or not. Currently, we assume submission
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 95ff56c0a45..52e5547d61e 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -437,13 +437,12 @@ void AutofillAgent::TriggerRefillIfNeeded(const FormData& form) {
if (FindFormAndFieldForFormControlElement(element_, field_data_manager_.get(),
&updated_form, &field) &&
(!element_.IsAutofilled() || !form.DynamicallySameFormAs(updated_form))) {
- base::TimeTicks forms_seen_timestamp = AutofillTickClock::NowTicks();
WebLocalFrame* frame = render_frame()->GetWebFrame();
std::vector<FormData> forms;
forms.push_back(updated_form);
// Always communicate to browser process for topmost frame.
if (!forms.empty() || !frame->Parent()) {
- GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp);
+ GetAutofillDriver()->FormsSeen(forms);
}
}
}
@@ -481,8 +480,10 @@ void AutofillAgent::PreviewForm(int32_t id, const FormData& form) {
if (id != autofill_query_id_)
return;
+ ClearPreviewedForm();
+
query_node_autofill_state_ = element_.GetAutofillState();
- form_util::PreviewForm(form, element_);
+ previewed_elements_ = form_util::PreviewForm(form, element_);
GetAutofillDriver()->DidPreviewAutofillFormData();
}
@@ -513,8 +514,9 @@ void AutofillAgent::ClearPreviewedForm() {
if (password_autofill_agent_->DidClearAutofillSelection(element_))
return;
- form_util::ClearPreviewedFormWithElement(element_,
- query_node_autofill_state_);
+ form_util::ClearPreviewedElements(previewed_elements_, element_,
+ query_node_autofill_state_);
+ previewed_elements_ = {};
}
void AutofillAgent::FillFieldWithValue(const base::string16& value) {
@@ -759,6 +761,10 @@ void AutofillAgent::SetAssistantActionState(bool running) {
}
}
+void AutofillAgent::EnableHeavyFormDataScraping() {
+ is_heavy_form_data_scraping_enabled_ = true;
+}
+
void AutofillAgent::QueryAutofillSuggestions(
const WebFormControlElement& element,
bool autoselect_first_suggestion) {
@@ -818,25 +824,23 @@ void AutofillAgent::DoFillFieldWithValue(const base::string16& value,
void AutofillAgent::DoPreviewFieldWithValue(const base::string16& value,
WebInputElement* node) {
+ ClearPreviewedForm();
query_node_autofill_state_ = element_.GetAutofillState();
node->SetSuggestedValue(blink::WebString::FromUTF16(value));
node->SetAutofillState(WebAutofillState::kPreviewed);
form_util::PreviewSuggestion(node->SuggestedValue().Utf16(),
node->Value().Utf16(), node);
+ previewed_elements_.push_back(*node);
}
void AutofillAgent::ProcessForms() {
- // Record timestamp of when the forms are first seen. This is used to
- // measure the overhead of the Autofill feature.
- base::TimeTicks forms_seen_timestamp = AutofillTickClock::NowTicks();
-
WebLocalFrame* frame = render_frame()->GetWebFrame();
std::vector<FormData> forms =
form_cache_.ExtractNewForms(field_data_manager_.get());
// Always communicate to browser process for topmost frame.
if (!forms.empty() || !frame->Parent()) {
- GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp);
+ GetAutofillDriver()->FormsSeen(forms);
}
}
@@ -1019,15 +1023,17 @@ void AutofillAgent::OnProvisionallySaveForm(
UpdateLastInteractedForm(element.Form());
} else {
// Remove invisible elements
+ WebLocalFrame* frame = render_frame()->GetWebFrame();
for (auto it = formless_elements_user_edited_.begin();
it != formless_elements_user_edited_.end();) {
- if (form_util::IsWebElementVisible(*it)) {
+ if (form_util::IsFormControlVisible(frame, *it)) {
it = formless_elements_user_edited_.erase(it);
} else {
++it;
}
}
- formless_elements_user_edited_.insert(element);
+ formless_elements_user_edited_.insert(
+ FieldRendererId(element.UniqueRendererFormControlId()));
provisionally_saved_form_ = base::make_optional<FormData>();
if (!CollectFormlessElements(&provisionally_saved_form_.value())) {
provisionally_saved_form_.reset();
@@ -1127,6 +1133,7 @@ base::Optional<FormData> AutofillAgent::GetSubmittedForm() const {
}
} else if (formless_elements_user_edited_.size() != 0 &&
!form_util::IsSomeControlElementVisible(
+ render_frame()->GetWebFrame(),
formless_elements_user_edited_)) {
// we check if all the elements the user has interacted with are gone,
// to decide if submission has occurred, and use the
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index a6d4cbeb9ec..dae44e9b0dd 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -100,6 +100,7 @@ class AutofillAgent : public content::RenderFrameObserver,
const std::vector<std::string>& selectors,
GetElementFormAndFieldDataCallback callback) override;
void SetAssistantActionState(bool running) override;
+ void EnableHeavyFormDataScraping() override;
void FormControlElementClicked(const blink::WebFormControlElement& element,
bool was_focused);
@@ -124,6 +125,10 @@ class AutofillAgent : public content::RenderFrameObserver,
FormTracker* form_tracker_for_testing() { return &form_tracker_; }
+ bool is_heavy_form_data_scraping_enabled() {
+ return is_heavy_form_data_scraping_enabled_;
+ }
+
void SelectWasUpdated(const blink::WebFormControlElement& element);
protected:
@@ -297,6 +302,9 @@ class AutofillAgent : public content::RenderFrameObserver,
// The element corresponding to the last request sent for form field Autofill.
blink::WebFormControlElement element_;
+ // The elements that currently are being previewed.
+ std::vector<blink::WebFormControlElement> previewed_elements_;
+
// The form element currently requesting an interactive autocomplete.
blink::WebFormElement in_flight_request_form_;
@@ -305,7 +313,7 @@ class AutofillAgent : public content::RenderFrameObserver,
// When dealing with forms that don't use a <form> tag, we keep track of the
// elements the user has modified so we can determine when submission occurs.
- std::set<blink::WebFormControlElement> formless_elements_user_edited_;
+ std::set<FieldRendererId> formless_elements_user_edited_;
// The form user interacted, it is used if last_interacted_form_ or formless
// form can't be converted to FormData at the time of form submission.
@@ -367,6 +375,10 @@ class AutofillAgent : public content::RenderFrameObserver,
// is.
bool is_screen_reader_enabled_ = false;
+ // Whether agents should enable heavy scraping of form data (e.g., button
+ // titles for unowned forms).
+ bool is_heavy_form_data_scraping_enabled_ = false;
+
const scoped_refptr<FieldDataManager> field_data_manager_;
base::WeakPtrFactory<AutofillAgent> weak_ptr_factory_{this};
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index f42cf808f28..d6da084c1bc 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -15,12 +15,12 @@
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/i18n/case_conversion.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -99,15 +99,6 @@ enum FieldFilterMask {
FILTER_NON_FOCUSABLE_ELEMENTS,
};
-// Returns whether sending autofill field metadata to the server is enabled.
-// TODO(crbug.com/938804): Remove this when button titles are crowdsourced in
-// all channels.
-bool IsAutofillFieldMetadataEnabled() {
- static base::NoDestructor<std::string> kGroupName(
- base::FieldTrialList::FindFullName("AutofillFieldMetadata"));
- return base::StartsWith(*kGroupName, "Enabled", base::CompareCase::SENSITIVE);
-}
-
void TruncateString(base::string16* str, size_t max_length) {
if (str->length() > max_length)
str->resize(max_length);
@@ -999,7 +990,7 @@ typedef void (*Callback)(const FormFieldData&,
bool, /* is_initiating_element */
blink::WebFormControlElement*);
-void ForEachMatchingFormFieldCommon(
+std::vector<WebFormControlElement> ForEachMatchingFormFieldCommon(
std::vector<WebFormControlElement>* control_elements,
const WebElement& initiating_element,
const FormData& data,
@@ -1009,6 +1000,9 @@ void ForEachMatchingFormFieldCommon(
const Callback& callback) {
DCHECK(control_elements);
+ std::vector<WebFormControlElement> matching_fields;
+ matching_fields.reserve(control_elements->size());
+
const bool num_elements_matches_num_fields =
control_elements->size() == data.fields.size();
UMA_HISTOGRAM_BOOLEAN("Autofill.NumElementsMatchesNumFields",
@@ -1023,7 +1017,7 @@ void ForEachMatchingFormFieldCommon(
// restrictions are applied.
//
// TODO(crbug/847221): Add a UKM to capture these events.
- return;
+ return matching_fields;
}
// The intended behaviour is:
@@ -1072,6 +1066,7 @@ void ForEachMatchingFormFieldCommon(
if (!is_preview && element->Focused())
initially_focused_element = element;
+ matching_fields.push_back(*element);
callback(data.fields[i], is_initiating_element, element);
continue;
}
@@ -1115,7 +1110,7 @@ void ForEachMatchingFormFieldCommon(
// If there is no other field to be autofilled, sending the blur event and
// then the focus event for the initiating element does not make sense.
if (autofillable_elements_index.empty())
- return;
+ return matching_fields;
// A blur event is emitted for the focused element if it is the initiating
// element before all other elements are autofilled.
@@ -1123,50 +1118,58 @@ void ForEachMatchingFormFieldCommon(
initially_focused_element->DispatchBlurEvent();
// Autofill the non-initiating elements.
- for (const auto& index : autofillable_elements_index)
+ for (const auto& index : autofillable_elements_index) {
+ matching_fields.push_back((*control_elements)[index]);
callback(data.fields[index], false, &(*control_elements)[index]);
+ }
// A focus event is emitted for the initiating element after autofilling is
// completed. It is not intended to work for the preview filling.
if (initially_focused_element)
initially_focused_element->DispatchFocusEvent();
+
+ return matching_fields;
}
// For each autofillable field in |data| that matches a field in the |form|,
// the |callback| is invoked with the corresponding |form| field data.
-void ForEachMatchingFormField(const WebFormElement& form_element,
- const WebElement& initiating_element,
- const FormData& data,
- FieldFilterMask filters,
- bool force_override,
- bool is_preview,
- const Callback& callback) {
+std::vector<WebFormControlElement> ForEachMatchingFormField(
+ const WebFormElement& form_element,
+ const WebElement& initiating_element,
+ const FormData& data,
+ FieldFilterMask filters,
+ bool force_override,
+ bool is_preview,
+ const Callback& callback) {
std::vector<WebFormControlElement> control_elements =
ExtractAutofillableElementsInForm(form_element);
- ForEachMatchingFormFieldCommon(&control_elements, initiating_element, data,
- filters, force_override, is_preview, callback);
+ return ForEachMatchingFormFieldCommon(&control_elements, initiating_element,
+ data, filters, force_override,
+ is_preview, callback);
}
// For each autofillable field in |data| that matches a field in the set of
// unowned autofillable form fields, the |callback| is invoked with the
// corresponding |data| field.
-void ForEachMatchingUnownedFormField(const WebElement& initiating_element,
- const FormData& data,
- FieldFilterMask filters,
- bool force_override,
- bool is_preview,
- const Callback& callback) {
+std::vector<WebFormControlElement> ForEachMatchingUnownedFormField(
+ const WebElement& initiating_element,
+ const FormData& data,
+ FieldFilterMask filters,
+ bool force_override,
+ bool is_preview,
+ const Callback& callback) {
if (initiating_element.IsNull())
- return;
+ return {};
std::vector<WebFormControlElement> control_elements =
GetUnownedAutofillableFormFieldElements(
initiating_element.GetDocument().All(), nullptr);
if (!IsElementInControlElementSet(initiating_element, control_elements))
- return;
+ return {};
- ForEachMatchingFormFieldCommon(&control_elements, initiating_element, data,
- filters, force_override, is_preview, callback);
+ return ForEachMatchingFormFieldCommon(&control_elements, initiating_element,
+ data, filters, force_override,
+ is_preview, callback);
}
// Sets the |field|'s value to the value in |data|, and specifies the section
@@ -1589,6 +1592,32 @@ bool IsSomeControlElementVisible(
return false;
}
+bool IsSomeControlElementVisible(
+ blink::WebLocalFrame* frame,
+ const std::set<FieldRendererId>& control_elements) {
+ // This is basically a set intersection of |control_elements| and the form
+ // controls on the website. We don't call IsFormControlVisible() on each
+ // element in |control_elements| as that would be O(N * M). Iterating over
+ // all form controls on the website and checking their existence in
+ // control_lements makes this O(N log M), where N is the number of form
+ // controls on the website and M the number of elements in |control_elements|.
+ WebDocument doc = frame->GetDocument();
+ if (doc.IsNull())
+ return false;
+ WebElementCollection elements = doc.All();
+
+ for (WebElement element = elements.FirstItem(); !element.IsNull();
+ element = elements.NextItem()) {
+ if (!element.IsFormControlElement() || !IsWebElementVisible(element))
+ continue;
+ WebFormControlElement control = element.To<WebFormControlElement>();
+ FieldRendererId field_renderer_id(control.UniqueRendererFormControlId());
+ if (control_elements.find(field_renderer_id) != control_elements.end())
+ return true;
+ }
+ return false;
+}
+
bool AreFormContentsVisible(const WebFormElement& form) {
return IsSomeControlElementVisible(form.GetFormControlElements());
}
@@ -1663,10 +1692,8 @@ bool IsWebElementVisible(const blink::WebElement& element) {
base::string16 GetFormIdentifier(const WebFormElement& form) {
base::string16 identifier = form.GetName().Utf16();
- static base::NoDestructor<WebString> kId("id");
if (identifier.empty())
- identifier = form.GetAttribute(*kId).Utf16();
-
+ identifier = form.GetIdAttribute().Utf16();
return identifier;
}
@@ -1716,7 +1743,6 @@ void WebFormControlElementToFormField(
DCHECK(field);
DCHECK(!element.IsNull());
static base::NoDestructor<WebString> kAutocomplete("autocomplete");
- static base::NoDestructor<WebString> kId("id");
static base::NoDestructor<WebString> kName("name");
static base::NoDestructor<WebString> kRole("role");
static base::NoDestructor<WebString> kPlaceholder("placeholder");
@@ -1725,7 +1751,7 @@ void WebFormControlElementToFormField(
// Save both id and name attributes, if present. If there is only one of them,
// it will be saved to |name|. See HTMLFormControlElement::nameForAutofill.
field->name = element.NameForAutofill().Utf16();
- field->id_attribute = element.GetAttribute(*kId).Utf16();
+ field->id_attribute = element.GetIdAttribute().Utf16();
field->name_attribute = element.GetAttribute(*kName).Utf16();
field->unique_renderer_id =
FieldRendererId(element.UniqueRendererFormControlId());
@@ -1837,15 +1863,15 @@ void WebFormControlElementToFormField(
if (field_data_manager &&
field->properties_mask & (FieldPropertiesFlags::kUserTyped |
FieldPropertiesFlags::kAutofilled)) {
- const base::string16 typed_value = field_data_manager->GetUserTypedValue(
+ const base::string16 user_input = field_data_manager->GetUserInput(
FieldRendererId(element.UniqueRendererFormControlId()));
// The typed value is preserved for all passwords. It is also preserved for
// potential usernames, as long as the |value| is not deemed acceptable.
if (field->form_control_type == "password" ||
- !ScriptModifiedUsernameAcceptable(value, typed_value,
+ !ScriptModifiedUsernameAcceptable(value, user_input,
field_data_manager)) {
- field->typed_value = typed_value;
+ field->user_input = user_input;
}
}
}
@@ -2059,85 +2085,66 @@ bool FindFormAndFieldForFormControlElement(
element, field_data_manager, form_util::EXTRACT_NONE, form, field);
}
-void FillForm(const FormData& form, const WebFormControlElement& element) {
+std::vector<WebFormControlElement> FillForm(
+ const FormData& form,
+ const WebFormControlElement& element) {
WebFormElement form_element = element.Form();
if (form_element.IsNull()) {
- ForEachMatchingUnownedFormField(element, form,
+ return ForEachMatchingUnownedFormField(element, form,
+ FILTER_ALL_NON_EDITABLE_ELEMENTS,
+ false, /* dont force override */
+ false, /* not a preview filling */
+ &FillFormField);
+ } else {
+ return ForEachMatchingFormField(form_element, element, form,
FILTER_ALL_NON_EDITABLE_ELEMENTS,
false, /* dont force override */
false, /* not a preview filling */
&FillFormField);
- return;
}
-
- ForEachMatchingFormField(form_element, element, form,
- FILTER_ALL_NON_EDITABLE_ELEMENTS,
- false, /* dont force override */
- false, /* not a preview filling */
- &FillFormField);
}
-void PreviewForm(const FormData& form, const WebFormControlElement& element) {
+std::vector<WebFormControlElement> PreviewForm(
+ const FormData& form,
+ const WebFormControlElement& element) {
WebFormElement form_element = element.Form();
if (form_element.IsNull()) {
- ForEachMatchingUnownedFormField(element, form,
+ return ForEachMatchingUnownedFormField(element, form,
+ FILTER_ALL_NON_EDITABLE_ELEMENTS,
+ false, /* dont force override */
+ true, /* preview filling */
+ &PreviewFormField);
+ } else {
+ return ForEachMatchingFormField(form_element, element, form,
FILTER_ALL_NON_EDITABLE_ELEMENTS,
false, /* dont force override */
true, /* preview filling */
&PreviewFormField);
- return;
}
-
- ForEachMatchingFormField(form_element, element, form,
- FILTER_ALL_NON_EDITABLE_ELEMENTS,
- false, /* dont force override */
- true, /* preview filling */
- &PreviewFormField);
}
-bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
- blink::WebAutofillState old_autofill_state) {
- WebFormElement form_element = element.Form();
- std::vector<WebFormControlElement> control_elements;
- if (form_element.IsNull()) {
- control_elements = GetUnownedAutofillableFormFieldElements(
- element.GetDocument().All(), nullptr);
- if (!IsElementInControlElementSet(element, control_elements))
- return false;
- } else {
- control_elements = ExtractAutofillableElementsInForm(form_element);
- }
-
- for (size_t i = 0; i < control_elements.size(); ++i) {
- // There might be unrelated elements in this form which have already been
- // auto-filled. For example, the user might have already filled the address
- // part of a form and now be dealing with the credit card section. We only
- // want to reset the auto-filled status for fields that were previewed.
- WebFormControlElement control_element = control_elements[i];
-
- // Only text input, textarea and select elements can be previewed.
- WebInputElement* input_element = ToWebInputElement(&control_element);
- if (!IsTextInput(input_element) && !IsMonthInput(input_element) &&
- !IsTextAreaElement(control_element) &&
- !IsSelectElement(control_element))
+void ClearPreviewedElements(
+ std::vector<blink::WebFormControlElement>& previewed_elements,
+ const WebFormControlElement& initiating_element,
+ blink::WebAutofillState old_autofill_state) {
+ for (WebFormControlElement& control_element : previewed_elements) {
+ if (control_element.IsNull())
continue;
// Only clear previewed fields.
if (control_element.GetAutofillState() != WebAutofillState::kPreviewed)
continue;
- if ((IsTextInput(input_element) || IsMonthInput(input_element) ||
- IsTextAreaElement(control_element) ||
- IsSelectElement(control_element)) &&
- control_element.SuggestedValue().IsEmpty())
+ if (control_element.SuggestedValue().IsEmpty())
continue;
// Clear the suggested value. For the initiating node, also restore the
// original value.
+ WebInputElement* input_element = ToWebInputElement(&control_element);
if (IsTextInput(input_element) || IsMonthInput(input_element) ||
IsTextAreaElement(control_element)) {
control_element.SetSuggestedValue(WebString());
- bool is_initiating_node = (element == control_element);
+ bool is_initiating_node = (initiating_element == control_element);
if (is_initiating_node) {
// Clearing the suggested value in the focused node (above) can cause
// selection to be lost. We force selection range to restore the text
@@ -2145,17 +2152,14 @@ bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
int length = control_element.Value().length();
control_element.SetSelectionRange(length, length);
control_element.SetAutofillState(old_autofill_state);
-
} else {
control_element.SetAutofillState(WebAutofillState::kNotFilled);
}
- } else if (IsSelectElement(control_element)) {
+ } else {
control_element.SetSuggestedValue(WebString());
control_element.SetAutofillState(WebAutofillState::kNotFilled);
}
}
-
- return true;
}
bool IsWebpageEmpty(const blink::WebLocalFrame* frame) {
@@ -2211,9 +2215,10 @@ base::string16 FindChildText(const WebNode& node) {
ButtonTitleList GetButtonTitles(const WebFormElement& web_form,
const WebDocument& document,
ButtonTitlesCache* button_titles_cache) {
- DCHECK(button_titles_cache);
- if (!IsAutofillFieldMetadataEnabled() && web_form.IsNull())
+ if (!button_titles_cache) {
+ // Button titles scraping is disabled for this form.
return ButtonTitleList();
+ }
// True if the cache has no entry for |web_form|.
bool cache_miss = true;
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h
index 1a33e640255..a8b0a8b46f3 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.h
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.h
@@ -96,6 +96,11 @@ bool IsFormControlVisible(blink::WebLocalFrame* frame,
bool IsSomeControlElementVisible(
const blink::WebVector<blink::WebFormControlElement>& control_elements);
+// Returns true if at least one element from |control_elements| is visible.
+bool IsSomeControlElementVisible(
+ blink::WebLocalFrame* frame,
+ const std::set<FieldRendererId>& control_elements);
+
// Returns true if some control elements of |form| are visible.
bool AreFormContentsVisible(const blink::WebFormElement& form);
@@ -244,21 +249,24 @@ bool FindFormAndFieldForFormControlElement(
FormFieldData* field);
// Fills the form represented by |form|. |element| is the input element that
-// initiated the auto-fill process.
-void FillForm(const FormData& form,
- const blink::WebFormControlElement& element);
-
-// Previews the form represented by |form|. |element| is the input element that
-// initiated the preview process.
-void PreviewForm(const FormData& form,
- const blink::WebFormControlElement& element);
-
-// Clears the placeholder values and the auto-filled background for any fields
-// in the form containing |node| that have been previewed. Resets the
-// autofilled state of |node| to |was_autofilled|. Returns false if the form is
-// not found.
-bool ClearPreviewedFormWithElement(const blink::WebFormControlElement& element,
- blink::WebAutofillState old_autofill_state);
+// initiated the auto-fill process. Returns the filled fields.
+std::vector<blink::WebFormControlElement> FillForm(
+ const FormData& form,
+ const blink::WebFormControlElement& element);
+
+// Previews the form represented by |form|. |element| is the input element that
+// initiated the preview process. Returns the previewed fields.
+std::vector<blink::WebFormControlElement> PreviewForm(
+ const FormData& form,
+ const blink::WebFormControlElement& element);
+
+// Clears the suggested values in |control_elements|. The state of
+// |initiating_element| is set to |old_autofill_state|; all other fields are set
+// to kNotFilled.
+void ClearPreviewedElements(
+ std::vector<blink::WebFormControlElement>& control_elements,
+ const blink::WebFormControlElement& initiating_element,
+ blink::WebAutofillState old_autofill_state);
// Checks if the webpage is empty.
// This kind of webpage is considered as empty:
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 34575e77b47..17593a6df51 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -360,12 +360,6 @@ TEST_F(FormAutofillUtilsTest, GetButtonTitles_TooLongTitle) {
}
TEST_F(FormAutofillUtilsTest, GetButtonTitles_Formless) {
- // Button titles computation and crowdsourcing for <form>less forms are
- // enabled only if |AutofillFieldMetadata| (Dev and Canary) is enabled.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.Init();
- base::FieldTrialList::CreateFieldTrial("AutofillFieldMetadata", "Enabled");
-
constexpr char kNoFormHtml[] =
"<div class='reg-form'>"
" <input type='button' value='\n Show\t password '>"
@@ -400,13 +394,10 @@ TEST_F(FormAutofillUtilsTest, GetButtonTitles_Formless) {
VerifyButtonTitleCache(form_target, expected, cache);
}
-TEST_F(FormAutofillUtilsTest, GetButtonTitles_Formless_DisabledByDefault) {
- // Button titles computation and crowdsourcing for <form>less forms should be
- // disabled if |AutofillFieldMetadata| is disabled.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.Init();
- base::FieldTrialList::CreateFieldTrial("AutofillFieldMetadata", "Disabled");
-
+TEST_F(FormAutofillUtilsTest, GetButtonTitles_DisabledIfNoCache) {
+ // Button titles scraping for unowned forms can be time-consuming and disabled
+ // in Beta and Stable. To disable button titles computation, |buttons_cache|
+ // should be null.
constexpr char kNoFormHtml[] =
"<div class='reg-form'>"
" <input type='button' value='\n Show\t password '>"
@@ -425,13 +416,11 @@ TEST_F(FormAutofillUtilsTest, GetButtonTitles_Formless_DisabledByDefault) {
ASSERT_NE(nullptr, web_frame);
WebFormElement form_target;
ASSERT_FALSE(web_frame->GetDocument().Body().IsNull());
- ButtonTitlesCache cache;
autofill::ButtonTitleList actual =
- GetButtonTitles(form_target, web_frame->GetDocument(), &cache);
+ GetButtonTitles(form_target, web_frame->GetDocument(), nullptr);
EXPECT_TRUE(actual.empty());
- EXPECT_TRUE(cache.empty());
}
TEST_F(FormAutofillUtilsTest, IsEnabled) {
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index a4aca1d571a..ab2c36aa4a9 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/check_op.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/stl_util.h"
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.cc b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
index df035aa498c..5824571b4b4 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.cc
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
@@ -9,6 +9,7 @@
#include <tuple>
#include <utility>
+#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/i18n/case_conversion.h"
#include "base/macros.h"
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index 83a970ccad2..97731d7f534 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -13,13 +13,13 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -1370,7 +1370,9 @@ PasswordAutofillAgent::GetFormDataFromUnownedInputElements() {
return nullptr;
return CreateFormDataFromUnownedInputElements(
*web_frame, field_data_manager_.get(), &username_detector_cache_,
- &button_titles_cache_);
+ autofill_agent_ && autofill_agent_->is_heavy_form_data_scraping_enabled()
+ ? &button_titles_cache_
+ : nullptr);
}
void PasswordAutofillAgent::InformAboutFormClearing(
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index 040f7aecada..98b5b758bc5 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "build/build_config.h"
#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
@@ -27,7 +27,6 @@
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "content/public/renderer/render_frame_observer.h"
-#include "content/public/renderer/render_view_observer.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -108,9 +107,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
public FormTracker::Observer,
public mojom::PasswordAutofillAgent {
public:
- using UseFallbackData = util::StrongAlias<class UseFallbackDataTag, bool>;
- using ShowAll = util::StrongAlias<class ShowAllTag, bool>;
- using GenerationShowing = util::StrongAlias<class GenerationShowingTag, bool>;
+ using UseFallbackData = base::StrongAlias<class UseFallbackDataTag, bool>;
+ using ShowAll = base::StrongAlias<class ShowAllTag, bool>;
+ using GenerationShowing = base::StrongAlias<class GenerationShowingTag, bool>;
PasswordAutofillAgent(content::RenderFrame* render_frame,
blink::AssociatedInterfaceRegistry* registry);
@@ -253,7 +252,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
}
private:
- using OnPasswordField = util::StrongAlias<class OnPasswordFieldTag, bool>;
+ using OnPasswordField = base::StrongAlias<class OnPasswordFieldTag, bool>;
// Enumeration representing possible Touch To Fill states. This is used to
// make sure that Touch To Fill will only be shown in response to the first
@@ -319,16 +318,17 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
DISALLOW_COPY_AND_ASSIGN(FocusStateNotifier);
};
- // This class keeps track of autofilled password input elements and makes sure
- // the autofilled password value is not accessible to JavaScript code until
- // the user interacts with the page.
+ // This class keeps track of autofilled username and password input elements
+ // and ensures that the autofilled values are not accessible to JavaScript
+ // code until the user interacts with the page. This restriction improves
+ // privacy (crbug.com/798492) and reduces attack surface (crbug.com/777272).
class PasswordValueGatekeeper {
public:
PasswordValueGatekeeper();
~PasswordValueGatekeeper();
- // Call this for every autofilled password field, so that the gatekeeper
- // protects the value accordingly.
+ // Call this for every autofilled username and password field, so that
+ // the gatekeeper protects the value accordingly.
void RegisterElement(blink::WebInputElement* element);
// Call this to notify the gatekeeper that the user interacted with the
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index dea5a37779b..cfc0cb471d0 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -12,7 +12,7 @@
#include "base/bind.h"
#include "base/check_op.h"
#include "base/command_line.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/password_autofill_agent.h"
diff --git a/chromium/components/autofill/content/renderer/prefilled_values_detector.cc b/chromium/components/autofill/content/renderer/prefilled_values_detector.cc
index 8ef1d3abaef..43e427c34f2 100644
--- a/chromium/components/autofill/content/renderer/prefilled_values_detector.cc
+++ b/chromium/components/autofill/content/renderer/prefilled_values_detector.cc
@@ -4,87 +4,88 @@
#include "components/autofill/content/renderer/prefilled_values_detector.h"
-#include "base/no_destructor.h"
+#include "base/containers/fixed_flat_set.h"
#include "base/strings/string_util.h"
namespace autofill {
-const base::flat_set<std::string, std::less<>>& KnownUsernamePlaceholders() {
- // Explicitly create a |StringFlatSet| when constructing
- // kPrefilledUsernameValues to work around GCC bug 84849, which causes the
- // initializer list not to be properly forwarded to base::flat_set's
- // constructor.
- using StringFlatSet = base::flat_set<std::string, std::less<>>;
- static base::NoDestructor<StringFlatSet> kPrefilledUsernameValues(
- StringFlatSet({"___.___.___-__",
- "+1",
- "3~15个字符,中文字符7个以内",
- "benutzername",
- "client id",
- "codice titolare",
- "digite seu cpf ou e-mail",
- "ds logon username",
- "email",
- "email address",
- "email masih kosong",
- "email/手機號碼",
- "e-mail/username",
- "e-mail address",
- "enter username",
- "enter user name",
- "identifiant",
- "kullanıcı adı",
- "kunden-id",
- "login",
- "nick",
- "nom d'usuari",
- "nom utilisateur",
- "rut",
- "siret",
- "this is usually your email address",
- "tu dni",
- "uid/用戶名/email",
- "uporabnik...",
- "user/codice",
- "user id",
- "user name",
- "username",
- "username or email",
- "username or email:",
- "username/email",
- "usuario",
- "your email address",
- "ååååmmddxxxx",
- "아이디 or @이하 모두 입력",
- "Имя",
- "Имя (логин)",
- "Логин",
- "Логин...",
- "Логин (e-mail)",
- "שם משתמש",
- "כתובת דוא''ל",
- "اسم العضو",
- "اسم المستخدم",
- "الاسم",
- "نام کاربری",
- "メールアドレス",
- "อีเมล",
- "用户名",
- "用户名/email",
- "邮箱/手机",
- "帳號",
- "請輸入身份證字號",
- "请用微博帐号登录",
- "请输入手机号或邮箱",
- "请输入邮箱或手机号",
- "邮箱/手机/展位号"}));
- return *kPrefilledUsernameValues;
+namespace {
+
+constexpr auto kKnownUsernamePlaceholders =
+ base::MakeFixedFlatSet<base::StringPiece>({
+ "___.___.___-__",
+ "+1",
+ "3~15个字符,中文字符7个以内",
+ "benutzername",
+ "client id",
+ "codice titolare",
+ "digite seu cpf ou e-mail",
+ "ds logon username",
+ "email",
+ "email address",
+ "email masih kosong",
+ "email/手機號碼",
+ "e-mail/username",
+ "e-mail address",
+ "enter username",
+ "enter user name",
+ "identifiant",
+ "kullanıcı adı",
+ "kunden-id",
+ "login",
+ "nick",
+ "nom d'usuari",
+ "nom utilisateur",
+ "rut",
+ "siret",
+ "this is usually your email address",
+ "tu dni",
+ "uid/用戶名/email",
+ "uporabnik...",
+ "user/codice",
+ "user id",
+ "user name",
+ "username",
+ "username or email",
+ "username or email:",
+ "username/email",
+ "usuario",
+ "your email address",
+ "ååååmmddxxxx",
+ "아이디 or @이하 모두 입력",
+ "Имя",
+ "Имя (логин)",
+ "Логин",
+ "Логин...",
+ "Логин (e-mail)",
+ "שם משתמש",
+ "כתובת דוא''ל",
+ "اسم العضو",
+ "اسم المستخدم",
+ "الاسم",
+ "نام کاربری",
+ "メールアドレス",
+ "อีเมล",
+ "用户名",
+ "用户名/email",
+ "邮箱/手机",
+ "帳號",
+ "請輸入身份證字號",
+ "请用微博帐号登录",
+ "请输入手机号或邮箱",
+ "请输入邮箱或手机号",
+ "邮箱/手机/展位号",
+ });
+
+} // namespace
+
+base::span<const base::StringPiece> KnownUsernamePlaceholders() {
+ return base::make_span(kKnownUsernamePlaceholders.begin(),
+ kKnownUsernamePlaceholders.end());
}
bool PossiblePrefilledUsernameValue(const std::string& username_value,
const std::string& possible_email_domain) {
- const auto& placeholders = KnownUsernamePlaceholders();
-
std::string normalized_username_value = base::ToLowerASCII(
base::TrimWhitespaceASCII(username_value, base::TRIM_ALL));
@@ -101,7 +102,7 @@ bool PossiblePrefilledUsernameValue(const std::string& username_value,
return true;
}
- return placeholders.find(normalized_username_value) != placeholders.end();
+ return kKnownUsernamePlaceholders.contains(normalized_username_value);
}
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/prefilled_values_detector.h b/chromium/components/autofill/content/renderer/prefilled_values_detector.h
index 8c4c732dc26..f8071de7e4d 100644
--- a/chromium/components/autofill/content/renderer/prefilled_values_detector.h
+++ b/chromium/components/autofill/content/renderer/prefilled_values_detector.h
@@ -7,14 +7,15 @@
#include <string>
-#include "base/containers/flat_set.h"
+#include "base/containers/span.h"
+#include "base/strings/string_piece.h"
namespace autofill {
-// Returns a set of known username placeholders, all guaranteed to be lower
+// Returns a list of known username placeholders, all guaranteed to be lower
// case.
// This is only exposed for testing.
-const base::flat_set<std::string, std::less<>>& KnownUsernamePlaceholders();
+base::span<const base::StringPiece> KnownUsernamePlaceholders();
// Checks if the prefilled value of the username element is one of the known
// values possibly used as placeholders. The list of possible placeholder
diff --git a/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc b/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc
index 6c3250665e3..fa87d73d922 100644
--- a/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc
+++ b/chromium/components/autofill/content/renderer/prefilled_values_detector_unittest.cc
@@ -12,7 +12,7 @@ namespace autofill {
// Ensure that all entries in KnownUsernamePlaceholders() are lowercase because
// the lowercase string of the website is tested against this set.
TEST(PossiblePrefilledUsernameValue, AllLowerCase) {
- for (const auto& entry : KnownUsernamePlaceholders())
+ for (auto entry : KnownUsernamePlaceholders())
EXPECT_EQ(entry, base::ToLowerASCII(entry));
}
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index b0dcbce1521..d6ce1fbbc51 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -18,6 +18,17 @@ grit("autofill_address_rewriter_resources") {
output_dir = "$root_gen_dir/components/autofill/core/browser"
}
+action("default_regex_patterns_cc") {
+ visibility = [ ":*" ]
+ sources = [ "pattern_provider/resources/regex_patterns.json" ]
+ script = "pattern_provider/transpile_default_regex_patterns.py"
+ args = [
+ rebase_path("pattern_provider/resources/regex_patterns.json"),
+ rebase_path("$target_gen_dir/pattern_provider/default_regex_patterns.cc"),
+ ]
+ outputs = [ "$target_gen_dir/pattern_provider/default_regex_patterns.cc" ]
+}
+
static_library("browser") {
sources = [
"address_normalization_manager.cc",
@@ -25,8 +36,8 @@ static_library("browser") {
"address_normalizer.h",
"address_normalizer_impl.cc",
"address_normalizer_impl.h",
- "address_profiles/address_profile_save_manager.cc",
- "address_profiles/address_profile_save_manager.h",
+ "address_profile_save_manager.cc",
+ "address_profile_save_manager.h",
"address_rewriter.cc",
"address_rewriter.h",
"autocomplete_history_manager.cc",
@@ -151,6 +162,10 @@ static_library("browser") {
"form_parsing/search_field.h",
"form_parsing/travel_field.cc",
"form_parsing/travel_field.h",
+ "form_processing/label_processing_util.cc",
+ "form_processing/label_processing_util.h",
+ "form_processing/name_processing_util.cc",
+ "form_processing/name_processing_util.h",
"form_structure.cc",
"form_structure.h",
"form_types.cc",
@@ -193,6 +208,7 @@ static_library("browser") {
"metrics/form_event_logger_base.cc",
"metrics/form_event_logger_base.h",
"metrics/form_events.h",
+ "pattern_provider/default_regex_patterns.h",
"pattern_provider/pattern_configuration_parser.cc",
"pattern_provider/pattern_configuration_parser.h",
"pattern_provider/pattern_provider.cc",
@@ -234,6 +250,8 @@ static_library("browser") {
"payments/webauthn_callback_types.h",
"personal_data_manager.cc",
"personal_data_manager.h",
+ "personal_data_manager_cleaner.cc",
+ "personal_data_manager_cleaner.h",
"personal_data_manager_observer.h",
"randomized_encoder.cc",
"randomized_encoder.h",
@@ -314,6 +332,8 @@ static_library("browser") {
"webdata/system_encryptor.h",
]
+ sources += get_target_outputs(":default_regex_patterns_cc")
+
if (is_win) {
sources += [
"autofill_ie_toolbar_import_win.cc",
@@ -332,6 +352,8 @@ static_library("browser") {
sources += [
"payments/autofill_credit_card_filling_infobar_delegate_mobile.cc",
"payments/autofill_credit_card_filling_infobar_delegate_mobile.h",
+ "payments/autofill_offer_notification_infobar_delegate_mobile.cc",
+ "payments/autofill_offer_notification_infobar_delegate_mobile.h",
"payments/autofill_save_card_infobar_delegate_mobile.cc",
"payments/autofill_save_card_infobar_delegate_mobile.h",
"payments/autofill_save_card_infobar_mobile.h",
@@ -376,25 +398,29 @@ static_library("browser") {
]
deps = [
":autofill_address_rewriter_resources",
+ ":default_regex_patterns_cc",
"//base",
"//base:i18n",
"//build:branding_buildflags",
+ "//build:chromeos_buildflags",
"//components/google/core/common",
"//components/history/core/browser",
"//components/infobars/core",
"//components/keyed_service/core",
- "//components/language_usage_metrics",
+ "//components/language/core/browser",
"//components/leveldb_proto",
"//components/os_crypt",
"//components/policy/core/browser",
"//components/policy/core/common",
"//components/pref_registry",
"//components/prefs",
+ "//components/profile_metrics",
"//components/signin/public/base",
"//components/signin/public/identity_manager",
"//components/strings",
"//components/sync",
"//components/translate/core/browser",
+ "//components/translate/core/common",
"//components/variations/net",
"//components/variations/service:service",
"//components/version_info",
@@ -461,8 +487,6 @@ static_library("test_support") {
"logging/stub_log_manager.h",
"mock_autocomplete_history_manager.cc",
"mock_autocomplete_history_manager.h",
- "pattern_provider/test_pattern_provider.cc",
- "pattern_provider/test_pattern_provider.h",
"payments/test_authentication_requester.cc",
"payments/test_authentication_requester.h",
"payments/test_credit_card_save_manager.cc",
@@ -494,7 +518,6 @@ static_library("test_support") {
"test_autofill_profile_validator.h",
"test_autofill_profile_validator_delayed.cc",
"test_autofill_profile_validator_delayed.h",
- "test_autofill_provider.cc",
"test_autofill_provider.h",
"test_autofill_tick_clock.cc",
"test_autofill_tick_clock.h",
@@ -533,6 +556,7 @@ static_library("test_support") {
"//components/translate/core/browser:test_support",
"//components/ukm",
"//components/ukm:test_support",
+ "//components/version_info:version_info",
"//google_apis:test_support",
"//services/network:test_support",
"//services/network/public/cpp",
@@ -593,7 +617,7 @@ source_set("unit_tests") {
sources = [
"address_normalization_manager_unittest.cc",
"address_normalizer_impl_unittest.cc",
- "address_profiles/address_profile_save_manager_unittest.cc",
+ "address_profile_save_manager_unittest.cc",
"address_rewriter_unittest.cc",
"autocomplete_history_manager_unittest.cc",
"autofill_address_policy_handler_unittest.cc",
@@ -609,6 +633,7 @@ source_set("unit_tests") {
"autofill_profile_sync_util_unittest.cc",
"autofill_profile_validation_util_unittest.cc",
"autofill_profile_validator_unittest.cc",
+ "autofill_provider_unittest.cc",
"autofill_regexes_unittest.cc",
"autofill_subject_unittest.cc",
"autofill_type_unittest.cc",
@@ -634,9 +659,13 @@ source_set("unit_tests") {
"form_parsing/field_candidates_unittest.cc",
"form_parsing/form_field_unittest.cc",
"form_parsing/name_field_unittest.cc",
+ "form_parsing/parsing_test_utils.cc",
+ "form_parsing/parsing_test_utils.h",
"form_parsing/phone_field_unittest.cc",
"form_parsing/price_field_unittest.cc",
"form_parsing/search_field_unittest.cc",
+ "form_processing/label_processing_util_unittest.cc",
+ "form_processing/name_processing_util_unittest.cc",
"form_structure_unittest.cc",
"geo/address_i18n_unittest.cc",
"geo/alternative_state_name_map_unittest.cc",
@@ -723,8 +752,8 @@ source_set("unit_tests") {
":unit_tests_bundle_data",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//components/autofill/core/common",
- "//components/infobars/core:feature_flags",
"//components/leveldb_proto",
"//components/os_crypt",
"//components/os_crypt:test_support",
@@ -738,6 +767,7 @@ source_set("unit_tests") {
"//components/sync:test_support_model",
"//components/sync/driver:test_support",
"//components/translate/core/browser",
+ "//components/translate/core/common",
"//components/ukm",
"//components/ukm:test_support",
"//components/unified_consent",
diff --git a/chromium/components/autofill/core/browser/DEPS b/chromium/components/autofill/core/browser/DEPS
index 99a308e09b9..69082786805 100644
--- a/chromium/components/autofill/core/browser/DEPS
+++ b/chromium/components/autofill/core/browser/DEPS
@@ -4,15 +4,17 @@ include_rules = [
"+components/history/core/browser",
"+components/infobars/core",
"+components/keyed_service/core",
- "+components/language_usage_metrics",
+ "+components/language/core/browser",
"+components/leveldb_proto",
"+components/metrics",
+ "+components/profile_metrics",
"+components/policy",
"+components/security_state",
"+components/security_interstitials/core/pref_names.h",
"+components/signin/public",
"+components/sync",
"+components/translate/core/browser",
+ "+components/translate/core/common",
"+components/variations",
"+components/version_info",
"+components/webdata/common",
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager.cc b/chromium/components/autofill/core/browser/address_profile_save_manager.cc
new file mode 100644
index 00000000000..4272c8e7eb1
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager.cc
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/address_profile_save_manager.h"
+
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/autofill_features.h"
+
+namespace autofill {
+
+AddressProfileSaveManager::AddressProfileSaveManager(
+ AutofillClient* client,
+ PersonalDataManager* personal_data_manager)
+ : client_(client), personal_data_manager_(personal_data_manager) {}
+
+AddressProfileSaveManager::~AddressProfileSaveManager() = default;
+
+void AddressProfileSaveManager::SaveProfile(const AutofillProfile& profile) {
+ if (!personal_data_manager_)
+ return;
+
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillAddressProfileSavePrompt)) {
+ client_->ConfirmSaveAddressProfile(
+ profile,
+ base::BindOnce(&AddressProfileSaveManager::SaveProfilePromptCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+ return;
+ }
+ SaveProfileInternal(profile);
+}
+
+void AddressProfileSaveManager::SaveProfileInternal(
+ const AutofillProfile& profile) {
+ personal_data_manager_->SaveImportedProfile(profile);
+}
+
+void AddressProfileSaveManager::SaveProfilePromptCallback(
+ AutofillClient::SaveAddressProfileOfferUserDecision user_decision,
+ AutofillProfile profile) {
+ switch (user_decision) {
+ case AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted:
+ case AutofillClient::SaveAddressProfileOfferUserDecision::kEdited:
+ personal_data_manager_->SaveImportedProfile(profile);
+ break;
+ case AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined:
+ case AutofillClient::SaveAddressProfileOfferUserDecision::kIgnored:
+ break;
+ }
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager.h b/chromium/components/autofill/core/browser/address_profile_save_manager.h
new file mode 100644
index 00000000000..0eec8bf5ae5
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILE_SAVE_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILE_SAVE_MANAGER_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/autofill_client.h"
+
+namespace autofill {
+
+class AutofillProfile;
+class PersonalDataManager;
+
+// Manages logic for saving address profiles to the database. Owned by
+// FormDataImporter.
+class AddressProfileSaveManager {
+ public:
+ // The parameters should outlive the AddressProfileSaveManager.
+ AddressProfileSaveManager(AutofillClient* client,
+ PersonalDataManager* personal_data_manager);
+ AddressProfileSaveManager(const AddressProfileSaveManager&) = delete;
+ AddressProfileSaveManager& operator=(const AddressProfileSaveManager&) =
+ delete;
+ virtual ~AddressProfileSaveManager();
+
+ // Saves `profile` using the `personal_data_manager_`.
+ void SaveProfile(const AutofillProfile& profile);
+
+ private:
+ void SaveProfilePromptCallback(
+ AutofillClient::SaveAddressProfileOfferUserDecision user_decision,
+ AutofillProfile profile);
+ void SaveProfileInternal(const AutofillProfile& profile);
+
+ AutofillClient* const client_;
+
+ // The personal data manager, used to save and load personal data to/from the
+ // web database.
+ PersonalDataManager* const personal_data_manager_;
+
+ base::WeakPtrFactory<AddressProfileSaveManager> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILE_SAVE_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc b/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
new file mode 100644
index 00000000000..19b9037b57e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/address_profile_save_manager.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace {
+class MockPersonalDataManager : public TestPersonalDataManager {
+ public:
+ MockPersonalDataManager() = default;
+ ~MockPersonalDataManager() override = default;
+ MOCK_METHOD(std::string,
+ SaveImportedProfile,
+ (const AutofillProfile&),
+ (override));
+};
+
+class AddressProfileSaveManagerTest : public testing::Test {
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ TestAutofillClient autofill_client_;
+ MockPersonalDataManager mock_personal_data_manager_;
+};
+
+} // namespace
+
+TEST_F(AddressProfileSaveManagerTest, SaveProfileWhenNoSavePrompt) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(
+ features::kAutofillAddressProfileSavePrompt);
+
+ AddressProfileSaveManager save_manager(&autofill_client_,
+ &mock_personal_data_manager_);
+ AutofillProfile test_profile = test::GetFullProfile();
+ EXPECT_CALL(mock_personal_data_manager_, SaveImportedProfile(test_profile));
+ save_manager.SaveProfile(test_profile);
+}
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc
deleted file mode 100644
index 4081c68239a..00000000000
--- a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/address_profiles/address_profile_save_manager.h"
-
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-
-namespace autofill {
-
-AddressProfileSaveManager::AddressProfileSaveManager(
- PersonalDataManager* personal_data_manager)
- : personal_data_manager_(personal_data_manager) {}
-
-AddressProfileSaveManager::~AddressProfileSaveManager() = default;
-
-std::string AddressProfileSaveManager::SaveProfile(
- const AutofillProfile& profile) {
- return personal_data_manager_
- ? personal_data_manager_->SaveImportedProfile(profile)
- : std::string();
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h
deleted file mode 100644
index 69ac2d01511..00000000000
--- a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILES_ADDRESS_PROFILE_SAVE_MANAGER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILES_ADDRESS_PROFILE_SAVE_MANAGER_H_
-
-#include <string>
-
-namespace autofill {
-
-class AutofillProfile;
-class PersonalDataManager;
-
-// Manages logic for saving address profiles to the database. Owned by
-// FormDataImporter.
-class AddressProfileSaveManager {
- public:
- explicit AddressProfileSaveManager(
- PersonalDataManager* personal_data_manager);
- AddressProfileSaveManager(const AddressProfileSaveManager&) = delete;
- AddressProfileSaveManager& operator=(const AddressProfileSaveManager&) =
- delete;
- virtual ~AddressProfileSaveManager();
-
- // Saves `imported_profile` using the `personal_data_manager_`. Returns the
- // guid of the new or updated profile, or the empty string if no profile was
- // saved.
- std::string SaveProfile(const AutofillProfile& imported_profile);
-
- private:
- // The personal data manager, used to save and load personal data to/from the
- // web database.
- PersonalDataManager* const personal_data_manager_;
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILES_ADDRESS_PROFILE_SAVE_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc
deleted file mode 100644
index b73b0dc35e5..00000000000
--- a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/address_profiles/address_profile_save_manager.h"
-
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace autofill {
-
-namespace {
-class MockPersonalDataManager : public TestPersonalDataManager {
- public:
- MockPersonalDataManager() = default;
- ~MockPersonalDataManager() override = default;
- MOCK_METHOD(std::string,
- SaveImportedProfile,
- (const AutofillProfile&),
- (override));
-};
-
-} // namespace
-
-TEST(AddressProfileSaveManager, SaveProfile) {
- MockPersonalDataManager pdm;
- AddressProfileSaveManager save_manager(&pdm);
- AutofillProfile test_profile = test::GetFullProfile();
- EXPECT_CALL(pdm, SaveImportedProfile(test_profile));
- save_manager.SaveProfile(test_profile);
-}
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_rewriter.cc b/chromium/components/autofill/core/browser/address_rewriter.cc
index 030a5aba146..c2d8533e376 100644
--- a/chromium/components/autofill/core/browser/address_rewriter.cc
+++ b/chromium/components/autofill/core/browser/address_rewriter.cc
@@ -35,8 +35,8 @@ static bool ExtractRegionRulesData(const std::string& region,
int resource_id = 0;
std::string resource_key = GetMapKey(region);
for (size_t i = 0; i < kAutofillAddressRewriterResourcesSize; ++i) {
- if (kAutofillAddressRewriterResources[i].name == resource_key) {
- resource_id = kAutofillAddressRewriterResources[i].value;
+ if (kAutofillAddressRewriterResources[i].path == resource_key) {
+ resource_id = kAutofillAddressRewriterResources[i].id;
break;
}
}
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
index 364ee098871..6ffe717feb3 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -15,10 +15,12 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/form_data.h"
#include "components/prefs/pref_service.h"
@@ -42,6 +44,22 @@ bool IsTextField(const FormFieldData& field) {
field.form_control_type == "email";
}
+// Returns true if the field has a meaningful name.
+// An input field name 'field_2' bears no semantic meaning and there is a chance
+// that a different website or different form uses the same field name for a
+// totally different purpose.
+bool IsMeaningfulFieldName(const base::string16& name) {
+ // If the corresponding feature is not enabled, every field name is considered
+ // as meaningful.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutocompleteFilterForMeaningfulNames)) {
+ return true;
+ }
+ return !MatchesPattern(
+ name,
+ base::UTF8ToUTF16("^(((field|input)(_|-)?\\d+)|tan|otp|title|captcha)$"));
+}
+
} // namespace
void AutocompleteHistoryManager::UMARecorder::OnGetAutocompleteSuggestions(
@@ -153,7 +171,8 @@ void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
base::WeakPtr<SuggestionsHandler> handler) {
CancelPendingQueries(handler.get());
- if (!is_autocomplete_enabled || form_control_type == "textarea" ||
+ if (!IsMeaningfulFieldName(name) || !is_autocomplete_enabled ||
+ form_control_type == "textarea" ||
IsInAutofillSuggestionsDisabledExperiment()) {
SendSuggestions({}, QueryHandler(query_id, autoselect_first_suggestion,
prefix, handler));
@@ -372,7 +391,8 @@ bool AutocompleteHistoryManager::IsFieldValueSaveable(
}
}
- return is_value_valid && !field.name.empty() && IsTextField(field) &&
+ return IsMeaningfulFieldName(field.name) && is_value_valid &&
+ !field.name.empty() && IsTextField(field) &&
field.should_autocomplete && !IsValidCreditCardNumber(field.value) &&
!IsSSN(field.value) &&
(field.properties_mask & kUserTyped || field.is_focusable) &&
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
index 29f9a67bee4..853dc159546 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -8,10 +8,12 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -47,8 +49,11 @@ namespace {
class MockAutofillClient : public TestAutofillClient {
public:
MockAutofillClient() : prefs_(test::PrefServiceForTesting()) {}
- ~MockAutofillClient() override {}
- PrefService* GetPrefs() override { return prefs_.get(); }
+ ~MockAutofillClient() override = default;
+ PrefService* GetPrefs() override {
+ return const_cast<PrefService*>(base::as_const(*this).GetPrefs());
+ }
+ const PrefService* GetPrefs() const override { return prefs_.get(); }
private:
std::unique_ptr<PrefService> prefs_;
@@ -475,6 +480,79 @@ TEST_F(AutocompleteHistoryManagerTest,
std::move(mocked_results));
}
+// Tests that no suggestions are queried if the field name is filtered because
+// it has a meaningless name.
+TEST_F(AutocompleteHistoryManagerTest,
+ DoQuerySuggestionsForMeaninglessFieldNames_FilterName) {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndEnableFeature(
+ features::kAutocompleteFilterForMeaningfulNames);
+
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ int test_query_id = 2;
+ auto test_name = ASCIIToUTF16("input_123");
+ auto test_prefix = ASCIIToUTF16("");
+
+ // Only expect a call when the name is not filtered out.
+ EXPECT_CALL(*web_data_service_,
+ GetFormValuesForElementName(test_name, test_prefix, _,
+ autocomplete_manager_.get()))
+ .Times(0);
+
+ // Simulate request for suggestions.
+ autocomplete_manager_->OnGetAutocompleteSuggestions(
+ test_query_id, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_name, test_prefix,
+ "Some Type", suggestions_handler->GetWeakPtr());
+
+ // Setting up mock to verify that DB response does not trigger a call to the
+ // handler's OnSuggestionsReturned.
+ EXPECT_CALL(*suggestions_handler.get(),
+ OnSuggestionsReturned(test_query_id,
+ /*autoselect_first_suggestion=*/false, _))
+ .Times(0);
+}
+
+// Tests that the suggestions are queried if the field name is not filtered
+// because the field's name is meaningful.
+TEST_F(AutocompleteHistoryManagerTest,
+ DoQuerySuggestionsForMeaninglessFieldNames_PassName) {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndEnableFeature(
+ features::kAutocompleteFilterForMeaningfulNames);
+
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ int test_query_id = 2;
+ auto test_name = ASCIIToUTF16("addressline_1");
+ auto test_prefix = ASCIIToUTF16("");
+ int mocked_db_query_id = 100;
+
+ std::vector<AutofillEntry> expected_values;
+
+ std::unique_ptr<WDTypedResult> mocked_results =
+ GetMockedDbResults(expected_values);
+
+ // Expect a call because the name is not filtered.
+ EXPECT_CALL(*web_data_service_,
+ GetFormValuesForElementName(test_name, test_prefix, _,
+ autocomplete_manager_.get()))
+ .WillOnce(Return(mocked_db_query_id));
+
+ // Simulate request for suggestions.
+ autocomplete_manager_->OnGetAutocompleteSuggestions(
+ test_query_id, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_name, test_prefix,
+ "Some Type", suggestions_handler->GetWeakPtr());
+
+ // Setting up mock to verify that DB response triggers a call to the handler's
+ EXPECT_CALL(*suggestions_handler.get(),
+ OnSuggestionsReturned(test_query_id,
+ /*autoselect_first_suggestion=*/false, _));
+
+ autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id,
+ std::move(mocked_results));
+}
+
TEST_F(AutocompleteHistoryManagerTest,
SuggestionsReturned_InvokeHandler_SingleValue) {
int mocked_db_query_id = 100;
diff --git a/chromium/components/autofill/core/browser/autofill_browser_util.cc b/chromium/components/autofill/core/browser/autofill_browser_util.cc
index 7d5ab372f01..eafd2ccab31 100644
--- a/chromium/components/autofill/core/browser/autofill_browser_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_browser_util.cc
@@ -14,12 +14,9 @@ bool IsInsecureFormAction(const GURL& action_url) {
// to same-origin contexts, so they are not blocked. Some forms use
// javascript URLs to handle submissions in JS, those don't count as mixed
// content either.
- // The data scheme is explicitly allowed in order to match blink's equivalent
- // check, since IsUrlPotentiallyTrustworthy excludes it.
if (action_url.SchemeIs(url::kJavaScriptScheme) ||
action_url.SchemeIs(url::kBlobScheme) ||
- action_url.SchemeIs(url::kFileSystemScheme) ||
- action_url.SchemeIs(url::kDataScheme)) {
+ action_url.SchemeIs(url::kFileSystemScheme)) {
return false;
}
return !network::IsUrlPotentiallyTrustworthy(action_url);
@@ -28,17 +25,18 @@ bool IsInsecureFormAction(const GURL& action_url) {
namespace autofill {
-bool IsFormOrClientNonSecure(AutofillClient* client, const FormData& form) {
+bool IsFormOrClientNonSecure(const AutofillClient* client,
+ const FormData& form) {
return !client->IsContextSecure() ||
(form.action.is_valid() && form.action.SchemeIs("http"));
}
-bool IsFormMixedContent(AutofillClient* client, const FormData& form) {
+bool IsFormMixedContent(const AutofillClient* client, const FormData& form) {
return client->IsContextSecure() &&
(form.action.is_valid() && IsInsecureFormAction(form.action));
}
-bool ShouldAllowCreditCardFallbacks(AutofillClient* client,
+bool ShouldAllowCreditCardFallbacks(const AutofillClient* client,
const FormData& form) {
// Skip the form check if there wasn't a form yet:
if (form.unique_renderer_id.is_null())
diff --git a/chromium/components/autofill/core/browser/autofill_browser_util.h b/chromium/components/autofill/core/browser/autofill_browser_util.h
index c03cbe8f5a1..e03b14408a3 100644
--- a/chromium/components/autofill/core/browser/autofill_browser_util.h
+++ b/chromium/components/autofill/core/browser/autofill_browser_util.h
@@ -14,15 +14,16 @@ namespace autofill {
class AutofillClient;
// Checks whether a given form is considered insecure (by origin or action).
-bool IsFormOrClientNonSecure(AutofillClient* client, const FormData& form);
+bool IsFormOrClientNonSecure(const AutofillClient* client,
+ const FormData& form);
// Checks whether a given form is considered mixed content. A form is mixed
// content if is displayed on a secure context, but submits to an insecure one.
-bool IsFormMixedContent(AutofillClient* client, const FormData& form);
+bool IsFormMixedContent(const AutofillClient* client, const FormData& form);
// Returns true if context provided by the client and the given form are
// considered "secure enough" to manually fill credit card data.
-bool ShouldAllowCreditCardFallbacks(AutofillClient* client,
+bool ShouldAllowCreditCardFallbacks(const AutofillClient* client,
const FormData& form);
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_client.cc b/chromium/components/autofill/core/browser/autofill_client.cc
index 54d977b408b..05229af8b02 100644
--- a/chromium/components/autofill/core/browser/autofill_client.cc
+++ b/chromium/components/autofill/core/browser/autofill_client.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/autofill_client.h"
+#include "base/stl_util.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/version_info/channel.h"
@@ -43,6 +44,12 @@ std::string AutofillClient::GetVariationConfigCountryCode() const {
return std::string();
}
+profile_metrics::BrowserProfileType AutofillClient::GetProfileType() const {
+ // This is an abstract interface and thus never instantiated directly,
+ // therefore it is safe to always return |kRegular| here.
+ return profile_metrics::BrowserProfileType::kRegular;
+}
+
#if !defined(OS_IOS)
std::unique_ptr<InternalAuthenticator>
AutofillClient::CreateCreditCardInternalAuthenticator(
@@ -51,6 +58,14 @@ AutofillClient::CreateCreditCardInternalAuthenticator(
}
#endif
+void AutofillClient::ShowOfferNotificationIfApplicable(
+ const std::vector<GURL>& domains_to_display_bubble,
+ const GURL& offer_details_url,
+ const CreditCard* card) {
+ // This is overridden by platform subclasses. Currently only
+ // ChromeAutofillClient (Chrome Desktop and Clank) implement this.
+}
+
LogManager* AutofillClient::GetLogManager() const {
return nullptr;
}
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index d8bb5ce5779..1a8c8b2f652 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -15,13 +15,14 @@
#include "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/payments/legal_message_line.h"
#include "components/autofill/core/browser/payments/risk_data_loader.h"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/browser/ui/popup_types.h"
+#include "components/profile_metrics/browser_profile_type.h"
#include "components/security_state/core/security_state.h"
#include "components/translate/core/browser/language_state.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
@@ -58,6 +59,7 @@ enum class Channel;
namespace autofill {
class AddressNormalizer;
+class AutofillProfile;
class AutocompleteHistoryManager;
class AutofillOfferManager;
class AutofillPopupDelegate;
@@ -134,6 +136,13 @@ class AutofillClient : public RiskDataLoader {
FIDO = 2,
};
+ enum class SaveAddressProfileOfferUserDecision {
+ kAccepted,
+ kEdited,
+ kDeclined,
+ kIgnored,
+ };
+
// Used for explicitly requesting the user to enter/confirm cardholder name,
// expiration date month and year.
struct UserProvidedCardDetails {
@@ -180,7 +189,7 @@ class AutofillClient : public RiskDataLoader {
// Required arguments to create a dropdown showing autofill suggestions.
struct PopupOpenArgs {
using AutoselectFirstSuggestion =
- ::util::StrongAlias<class AutoSelectFirstSuggestionTag, bool>;
+ ::base::StrongAlias<class AutoSelectFirstSuggestionTag, bool>;
PopupOpenArgs();
PopupOpenArgs(const gfx::RectF& element_bounds,
@@ -235,6 +244,10 @@ class AutofillClient : public RiskDataLoader {
typedef base::RepeatingCallback<void(WebauthnDialogCallbackType)>
WebauthnDialogCallback;
+ using AddressProfileSavePromptCallback =
+ base::OnceCallback<void(SaveAddressProfileOfferUserDecision,
+ autofill::AutofillProfile profile)>;
+
~AutofillClient() override = default;
// Returns the channel for the installation. In branded builds, this will be
@@ -251,6 +264,7 @@ class AutofillClient : public RiskDataLoader {
// Gets the preferences associated with the client.
virtual PrefService* GetPrefs() = 0;
+ virtual const PrefService* GetPrefs() const = 0;
// Gets the sync service associated with the client.
virtual syncer::SyncService* GetSyncService() = 0;
@@ -282,7 +296,7 @@ class AutofillClient : public RiskDataLoader {
// Gets the virtual URL of the last committed page of this client's
// associated WebContents.
- virtual const GURL& GetLastCommittedURL() = 0;
+ virtual const GURL& GetLastCommittedURL() const = 0;
// Gets the security level used for recording histograms for the current
// context if possible, SECURITY_LEVEL_COUNT otherwise.
@@ -291,10 +305,19 @@ class AutofillClient : public RiskDataLoader {
// Returns the language state, if available.
virtual const translate::LanguageState* GetLanguageState() = 0;
+ // Returns the translate driver, if available, which is used to observe the
+ // page language for language-dependent heuristics.
+ virtual translate::TranslateDriver* GetTranslateDriver() = 0;
+
// Retrieves the country code of the user from Chrome variation service.
// If the variation service is not available, return an empty string.
virtual std::string GetVariationConfigCountryCode() const;
+ // Returns the profile type of the session.
+ // TODO(https://crbug.com/1169142): Replace by getting profile type directly
+ // from BrowserContext.
+ virtual profile_metrics::BrowserProfileType GetProfileType() const;
+
#if !defined(OS_IOS)
// Creates the appropriate implementation of InternalAuthenticator. May be
// null for platforms that don't support this, in which case standard CVC
@@ -434,6 +457,12 @@ class AutofillClient : public RiskDataLoader {
virtual void ConfirmCreditCardFillAssist(const CreditCard& card,
base::OnceClosure callback) = 0;
+ // Shows the offer-to-save address profile bubble. Runs |callback| once the
+ // user makes a decision with respect to the offer-to-save prompt.
+ virtual void ConfirmSaveAddressProfile(
+ const AutofillProfile& profile,
+ AddressProfileSavePromptCallback callback) = 0;
+
// Returns true if both the platform and the device support scanning credit
// cards. Should be called before ScanCreditCard().
virtual bool HasCreditCardScanFeature() = 0;
@@ -475,6 +504,21 @@ class AutofillClient : public RiskDataLoader {
// Hide the Autofill popup if one is currently showing.
virtual void HideAutofillPopup(PopupHidingReason reason) = 0;
+ // TODO(crbug.com/1093057): Rename all the "domain" in this flow to origin.
+ // The server is passing down full origin of the
+ // urls. "Domain" is no longer accurate.
+ // Will show a bubble or infobar indicating that the current web domain has an
+ // eligible offer or reward if no other notification bubble is currently
+ // visible. See bubble controller for details. The bubble is sticky over a set
+ // of domains given in |domains_to_display_bubble|. The bubble displays the
+ // information of the |card| if the offer is card-related. On mobile, the
+ // bubble also shows the |offer_details_url| as a link which has more
+ // information about the offer.
+ virtual void ShowOfferNotificationIfApplicable(
+ const std::vector<GURL>& domains_to_display_bubble,
+ const GURL& offer_details_url,
+ const CreditCard* card);
+
// Whether the Autocomplete feature of Autofill should be enabled.
virtual bool IsAutocompleteEnabled() = 0;
@@ -490,14 +534,14 @@ class AutofillClient : public RiskDataLoader {
const base::string16& profile_full_name) = 0;
// If the context is secure.
- virtual bool IsContextSecure() = 0;
+ virtual bool IsContextSecure() const = 0;
// Whether it is appropriate to show a signin promo for this user.
virtual bool ShouldShowSigninPromo() = 0;
// Whether server side cards are supported by the client. If false, only
// local cards will be shown.
- virtual bool AreServerCardsSupported() = 0;
+ virtual bool AreServerCardsSupported() const = 0;
// Handles simple actions for the autofill popups.
virtual void ExecuteCommand(int id) = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc
index d8b5520cfc4..ab3195e97b5 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util.cc
@@ -81,24 +81,23 @@ const char* const family_name_prefixes[] = {"d'", "de", "del", "den", "der",
// The common and non-ambiguous CJK surnames (last names) that have more than
// one character.
const char* common_cjk_multi_char_surnames[] = {
- // Korean, taken from the list of surnames:
- // https://ko.wikipedia.org/wiki/%ED%95%9C%EA%B5%AD%EC%9D%98_%EC%84%B1%EC%94%A8_%EB%AA%A9%EB%A1%9D
- "남궁", "사공", "서문", "선우", "제갈", "황보", "독고", "망절",
-
- // Chinese, taken from the top 10 Chinese 2-character surnames:
- // https://zh.wikipedia.org/wiki/%E8%A4%87%E5%A7%93#.E5.B8.B8.E8.A6.8B.E7.9A.84.E8.A4.87.E5.A7.93
- // Simplified Chinese (mostly mainland China)
- "欧阳", "令狐", "皇甫", "上官", "司徒", "诸葛", "司马", "宇文", "呼延", "端木",
- // Traditional Chinese (mostly Taiwan)
- "張簡", "歐陽", "諸葛", "申屠", "尉遲", "司馬", "軒轅", "夏侯"
-};
+ // Korean, taken from the list of surnames:
+ // https://ko.wikipedia.org/wiki/%ED%95%9C%EA%B5%AD%EC%9D%98_%EC%84%B1%EC%94%A8_%EB%AA%A9%EB%A1%9D
+ "남궁", "사공", "서문", "선우", "제갈", "황보", "독고", "망절",
+
+ // Chinese, taken from the top 10 Chinese 2-character surnames:
+ // https://zh.wikipedia.org/wiki/%E8%A4%87%E5%A7%93#.E5.B8.B8.E8.A6.8B.E7.9A.84.E8.A4.87.E5.A7.93
+ // Simplified Chinese (mostly mainland China)
+ "欧阳", "令狐", "皇甫", "上官", "司徒", "诸葛", "司马", "宇文", "呼延",
+ "端木",
+ // Traditional Chinese (mostly Taiwan)
+ "張簡", "歐陽", "諸葛", "申屠", "尉遲", "司馬", "軒轅", "夏侯"};
// All Korean surnames that have more than one character, even the
// rare/ambiguous ones.
const char* korean_multi_char_surnames[] = {
- "강전", "남궁", "독고", "동방", "망절", "사공", "서문", "선우",
- "소봉", "어금", "장곡", "제갈", "황목", "황보"
-};
+ "강전", "남궁", "독고", "동방", "망절", "사공", "서문",
+ "선우", "소봉", "어금", "장곡", "제갈", "황목", "황보"};
// Returns true if |set| contains |element|, modulo a final period.
bool ContainsString(const char* const set[],
@@ -146,7 +145,8 @@ void StripSuffixes(std::vector<base::StringPiece16>* name_tokens) {
// Find whether |name| starts with any of the strings from the array
// |prefixes|. The returned value is the length of the prefix found, or 0 if
// none is found.
-size_t StartsWithAny(base::StringPiece16 name, const char** prefixes,
+size_t StartsWithAny(base::StringPiece16 name,
+ const char** prefixes,
size_t prefix_count) {
base::string16 buffer;
for (size_t i = 0; i < prefix_count; i++) {
@@ -250,16 +250,16 @@ void AddGroupToBitmask(uint32_t* group_bitmask, ServerFieldType type) {
const FieldTypeGroup group =
AutofillType(AutofillType(type).GetStorableType()).group();
switch (group) {
- case autofill::NAME:
+ case autofill::FieldTypeGroup::kName:
*group_bitmask |= kName;
break;
- case autofill::ADDRESS_HOME:
+ case autofill::FieldTypeGroup::kAddressHome:
*group_bitmask |= kAddress;
break;
- case autofill::EMAIL:
+ case autofill::FieldTypeGroup::kEmail:
*group_bitmask |= kEmail;
break;
- case autofill::PHONE_HOME:
+ case autofill::FieldTypeGroup::kPhoneHome:
*group_bitmask |= kPhone;
break;
default:
@@ -383,12 +383,12 @@ bool IsCJKName(base::StringPiece16 name) {
NameParts SplitName(base::StringPiece16 name) {
static const base::char16 kWordSeparators[] = {
- u' ', // ASCII space.
- u',', // ASCII comma.
- u'\u3000', // 'IDEOGRAPHIC SPACE' (U+3000).
- u'\u30FB', // 'KATAKANA MIDDLE DOT' (U+30FB).
- u'\u00B7', // 'MIDDLE DOT' (U+00B7).
- u'\0' // End of string.
+ u' ', // ASCII space.
+ u',', // ASCII comma.
+ u'\u3000', // 'IDEOGRAPHIC SPACE' (U+3000).
+ u'\u30FB', // 'KATAKANA MIDDLE DOT' (U+30FB).
+ u'\u00B7', // 'MIDDLE DOT' (U+00B7).
+ u'\0' // End of string.
};
std::vector<base::StringPiece16> name_tokens = base::SplitStringPiece(
name, kWordSeparators, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
diff --git a/chromium/components/autofill/core/browser/autofill_data_util.h b/chromium/components/autofill/core/browser/autofill_data_util.h
index cef371d6983..144a1acd942 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util.h
+++ b/chromium/components/autofill/core/browser/autofill_data_util.h
@@ -28,15 +28,15 @@ struct NameParts {
namespace bit_field_type_groups {
// Bits for FieldTypeGroup options.
-// The form has a field associated with the NAME_HOME or NAME_BILLING
+// The form has a field associated with the kName or kNameBilling
// FieldTypeGroups.
constexpr uint32_t kName = 1 << 0;
-// The form has a field associated with the ADDRESS_HOME or ADDRESS_BILLING
+// The form has a field associated with the :kAddressHome or kAddressBilling
// FieldTypeGroups.
constexpr uint32_t kAddress = 1 << 1;
-// The form has a field associated with the EMAIL FieldTypeGroup.
+// The form has a field associated with the kEmail FieldTypeGroup.
constexpr uint32_t kEmail = 1 << 2;
-// The form has a field associated with the PHONE_HOME or PHONE_BILLING
+// The form has a field associated with the kPhoneHome or kPhoneBilling
// FieldTypeGroups.
constexpr uint32_t kPhone = 1 << 3;
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index e356433a2f8..097f5b9db03 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -590,10 +590,12 @@ ScopedActiveAutofillExperiments::~ScopedActiveAutofillExperiments() {
std::vector<variations::VariationID>*
AutofillDownloadManager::active_experiments_ = nullptr;
-AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver,
- Observer* observer,
- const std::string& api_key,
- LogManager* log_manager)
+AutofillDownloadManager::AutofillDownloadManager(
+ AutofillDriver* driver,
+ Observer* observer,
+ const std::string& api_key,
+ IsRawMetadataUploadingEnabled is_raw_metadata_uploading_enabled,
+ LogManager* log_manager)
: driver_(driver),
observer_(observer),
api_key_(api_key),
@@ -601,7 +603,8 @@ AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver,
autofill_server_url_(GetAutofillServerURL()),
throttle_reset_period_(GetThrottleResetPeriod()),
max_form_cache_size_(kAutofillDownloadManagerMaxFormCacheSize),
- loader_backoff_(&kAutofillBackoffPolicy) {
+ loader_backoff_(&kAutofillBackoffPolicy),
+ is_raw_metadata_uploading_enabled_(is_raw_metadata_uploading_enabled) {
DCHECK(observer_);
}
@@ -610,6 +613,7 @@ AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver,
: AutofillDownloadManager(driver,
observer,
kDefaultAPIKey,
+ IsRawMetadataUploadingEnabled(false),
/*log_manager=*/nullptr) {}
AutofillDownloadManager::~AutofillDownloadManager() = default;
@@ -706,7 +710,8 @@ bool AutofillDownloadManager::StartUploadRequest(
std::vector<FormSignature> form_signatures;
if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled,
login_form_signature, observed_submission,
- &upload, &form_signatures)) {
+ is_raw_metadata_uploading_enabled_, &upload,
+ &form_signatures)) {
return false;
}
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.h b/chromium/components/autofill/core/browser/autofill_download_manager.h
index 8aaececf094..afd5e4dca0a 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.h
@@ -19,6 +19,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
+#include "base/types/strong_alias.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/signatures.h"
@@ -50,6 +51,8 @@ class AutofillDownloadManager {
REQUEST_QUERY,
REQUEST_UPLOAD,
};
+ using IsRawMetadataUploadingEnabled =
+ base::StrongAlias<class IsRawMetadataUploadingEnabledTag, bool>;
// An interface used to notify clients of AutofillDownloadManager.
class Observer {
@@ -79,16 +82,18 @@ class AutofillDownloadManager {
// |driver| must outlive this instance.
// |observer| - observer to notify on successful completion or error.
- // Uses an API callback function that gives an empty string.
- AutofillDownloadManager(AutofillDriver* driver, Observer* observer);
- // |driver| must outlive this instance.
- // |observer| - observer to notify on successful completion or error.
// |api_key| - API key to add to API request query parameters. Will only take
// effect if using API.
- AutofillDownloadManager(AutofillDriver* driver,
- Observer* observer,
- const std::string& api_key,
- LogManager* log_manager);
+ AutofillDownloadManager(
+ AutofillDriver* driver,
+ Observer* observer,
+ const std::string& api_key,
+ IsRawMetadataUploadingEnabled is_raw_metadata_uploading_enabled,
+ LogManager* log_manager);
+ // |driver| must outlive this instance.
+ // |observer| - observer to notify on successful completion or error.
+ // Uses an API callback function that gives an empty string.
+ AutofillDownloadManager(AutofillDriver* driver, Observer* observer);
virtual ~AutofillDownloadManager();
// Starts a query request to Autofill servers. The observer is called with the
@@ -225,6 +230,10 @@ class AutofillDownloadManager {
// Used for exponential backoff of requests.
net::BackoffEntry loader_backoff_;
+ // Whether form data (e.g. form and field names) can be uploaded in clear
+ // text.
+ bool is_raw_metadata_uploading_enabled_ = false;
+
base::WeakPtrFactory<AutofillDownloadManager> weak_factory_{this};
};
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 923f8c9071c..bf06e7d2e2f 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -14,6 +14,7 @@
#include "base/base64url.h"
#include "base/bind.h"
#include "base/format_macros.h"
+#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -84,23 +85,15 @@ std::vector<FormStructure*> ToRawPointerVector(
// the response body data is utilized.
std::string GetStringFromDataElements(
const std::vector<network::DataElement>* data_elements) {
- network::DataElement unified_data_element;
- auto data_elements_it = data_elements->begin();
- if (data_elements_it != data_elements->end()) {
- unified_data_element.SetToBytes(data_elements_it->bytes(),
- data_elements_it->length());
+ std::string result;
+ for (const network::DataElement& e : *data_elements) {
+ DCHECK_EQ(e.type(), network::DataElement::Tag::kBytes);
+ // Provide the length of the bytes explicitly, not to rely on the null
+ // termination.
+ const auto piece = e.As<network::DataElementBytes>().AsStringPiece();
+ result.append(piece.data(), piece.size());
}
- ++data_elements_it;
- while (data_elements_it != data_elements->end()) {
- unified_data_element.AppendBytes(data_elements_it->bytes(),
- data_elements_it->length());
- ++data_elements_it;
- }
- // Using the std::string constructor with length ensures that we don't rely
- // on having a termination character to delimit the string. This is the
- // safest approach.
- return std::string(unified_data_element.bytes(),
- unified_data_element.length());
+ return result;
}
// Gets the AutofillUploadRequest proto from the HTTP loader request payload.
@@ -165,10 +158,12 @@ class AutofillDownloadManagerWithCustomPayloadSize
Observer* observer,
const std::string& api_key,
size_t length)
- : AutofillDownloadManager(driver,
- observer,
- api_key,
- /*log_manager=*/nullptr),
+ : AutofillDownloadManager(
+ driver,
+ observer,
+ api_key,
+ AutofillDownloadManager::IsRawMetadataUploadingEnabled(false),
+ /*log_manager=*/nullptr),
length_(length) {}
protected:
@@ -350,8 +345,10 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
form_structures.push_back(std::make_unique<FormStructure>(form));
// Make download manager.
- AutofillDownloadManager download_manager(&driver_, this, "dummykey",
- /*log_manager=*/nullptr);
+ AutofillDownloadManager download_manager(
+ &driver_, this, "dummykey",
+ AutofillDownloadManager::IsRawMetadataUploadingEnabled(false),
+ /*log_manager=*/nullptr);
// Request with id 0.
base::HistogramTester histogram;
@@ -540,8 +537,10 @@ TEST_F(AutofillDownloadManagerTest, QueryAPITest) {
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::make_unique<FormStructure>(form));
- AutofillDownloadManager download_manager(&driver_, this, "dummykey",
- /*log_manager=*/nullptr);
+ AutofillDownloadManager download_manager(
+ &driver_, this, "dummykey",
+ AutofillDownloadManager::IsRawMetadataUploadingEnabled(false),
+ /*log_manager=*/nullptr);
// Start the query request and look if it is successful. No response was
// received yet.
@@ -729,7 +728,7 @@ TEST_F(AutofillDownloadManagerTest, UploadToAPITest) {
// We don't want upload throttling for testing purpose.
{features::kAutofillUploadThrottling});
- // Build the form structures that we want to query.
+ // Build the form structures that we want to upload.
FormData form;
FormFieldData field;
@@ -746,8 +745,10 @@ TEST_F(AutofillDownloadManagerTest, UploadToAPITest) {
form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION);
std::unique_ptr<PrefService> pref_service = test::PrefServiceForTesting();
- AutofillDownloadManager download_manager(&driver_, this, "dummykey",
- /*log_manager=*/nullptr);
+ AutofillDownloadManager download_manager(
+ &driver_, this, "dummykey",
+ AutofillDownloadManager::IsRawMetadataUploadingEnabled(false),
+ /*log_manager=*/nullptr);
EXPECT_TRUE(download_manager.StartUploadRequest(form_structure, true,
ServerFieldTypeSet(), "",
true, pref_service.get()));
@@ -793,6 +794,80 @@ TEST_F(AutofillDownloadManagerTest, UploadToAPITest) {
net::HTTP_OK, 1);
}
+TEST_F(AutofillDownloadManagerTest, UploadWithRawMetadata) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ // Enabled
+ {},
+ // Disabled
+ // We don't want upload throttling for testing purpose.
+ {features::kAutofillUploadThrottling});
+
+ for (bool is_raw_metadata_uploading_enabled : {false, true}) {
+ SCOPED_TRACE(testing::Message() << "is_raw_metadata_uploading_enabled = "
+ << is_raw_metadata_uploading_enabled);
+ // Build the form structures that we want to upload.
+ FormData form;
+ form.name = UTF8ToUTF16("form1");
+ FormFieldData field;
+
+ field.name = UTF8ToUTF16("firstname");
+ field.form_control_type = "text";
+ form.fields.push_back(field);
+
+ field.name = UTF8ToUTF16("lastname");
+ field.form_control_type = "text";
+ form.fields.push_back(field);
+ FormStructure form_structure(form);
+ form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION);
+
+ std::unique_ptr<PrefService> pref_service = test::PrefServiceForTesting();
+ AutofillDownloadManager download_manager(
+ &driver_, this, "dummykey",
+ AutofillDownloadManager::IsRawMetadataUploadingEnabled(
+ is_raw_metadata_uploading_enabled),
+ /*log_manager=*/nullptr);
+ EXPECT_TRUE(download_manager.StartUploadRequest(form_structure, true,
+ ServerFieldTypeSet(), "",
+ true, pref_service.get()));
+
+ // Inspect the request that the test URL loader sent.
+ ASSERT_EQ(1, test_url_loader_factory_.NumPending());
+ network::TestURLLoaderFactory::PendingRequest* request =
+ test_url_loader_factory_.GetPendingRequest(0);
+
+ // Assert some of the fields within the uploaded proto to make sure it was
+ // filled with something else than default data.
+ AutofillUploadRequest autofill_upload_request;
+ EXPECT_TRUE(
+ GetUploadRequestProtoFromRequest(request, &autofill_upload_request));
+ AutofillUploadContents upload = autofill_upload_request.upload();
+ EXPECT_GT(upload.client_version().size(), 0U);
+ EXPECT_EQ(FormSignature(upload.form_signature()),
+ form_structure.form_signature());
+ // Only a few strings are tested, full testing happens in FormStructure's
+ // tests.
+ ASSERT_EQ(is_raw_metadata_uploading_enabled, upload.has_form_name());
+ ASSERT_EQ(is_raw_metadata_uploading_enabled, upload.field()[0].has_name());
+ ASSERT_EQ(is_raw_metadata_uploading_enabled, upload.field()[1].has_type());
+ if (is_raw_metadata_uploading_enabled) {
+ EXPECT_EQ(form.name, UTF8ToUTF16(upload.form_name()));
+ EXPECT_EQ(form.fields[0].name, UTF8ToUTF16(upload.field()[0].name()));
+ EXPECT_EQ(form.fields[1].form_control_type, upload.field()[1].type());
+ }
+
+ test_url_loader_factory_.SimulateResponseForPendingRequest(
+ request->request.url.spec(), "");
+ EXPECT_EQ(1U, responses_.size());
+ EXPECT_EQ(AutofillDownloadManagerTest::UPLOAD_SUCCESSFULL,
+ responses_.front().type_of_response);
+
+ ASSERT_EQ(0, test_url_loader_factory_.NumPending());
+ test_url_loader_factory_.ClearResponses();
+ responses_.clear();
+ }
+}
+
TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) {
FormData form;
FormFieldData field;
@@ -1946,7 +2021,7 @@ TEST_P(AutofillUploadTest, RichMetadata) {
AutofillDownloadManager download_manager(driver_.get(), this);
FormStructure form_structure(form);
- form_structure.set_page_language("fr-ca");
+ form_structure.set_current_page_language(LanguageCode("fr"));
pref_service_->SetBoolean(
RandomizedEncoder::kUrlKeyedAnonymizedDataCollectionEnabled, true);
@@ -1983,7 +2058,8 @@ TEST_P(AutofillUploadTest, RichMetadata) {
ASSERT_TRUE(request.ParseFromString(payloads_.front()));
ASSERT_TRUE(request.has_upload());
const AutofillUploadContents& upload = request.upload();
- EXPECT_EQ(upload.language(), form_structure.page_language());
+ EXPECT_EQ(upload.language(),
+ form_structure.current_page_language().value());
ASSERT_TRUE(upload.has_randomized_form_metadata());
EXPECT_TRUE(upload.randomized_form_metadata().has_id());
EXPECT_TRUE(upload.randomized_form_metadata().has_name());
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index 3b1c49daf94..0217bbc8696 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/check.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/notreached.h"
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index 41610aa4482..f563c4a4c90 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -20,11 +20,20 @@ AutofillField::AutofillField() = default;
AutofillField::AutofillField(FieldSignature field_signature)
: field_signature_(field_signature) {}
+AutofillField::AutofillField(const FormFieldData& field)
+ : FormFieldData(field),
+ parseable_name_(field.name),
+ parseable_label_(field.label) {
+ field_signature_ =
+ CalculateFieldSignatureByNameAndType(name, form_control_type);
+}
+
AutofillField::AutofillField(const FormFieldData& field,
const base::string16& unique_name)
: FormFieldData(field),
unique_name_(unique_name),
- parseable_name_(field.name) {
+ parseable_name_(field.name),
+ parseable_label_(field.label) {
field_signature_ =
CalculateFieldSignatureByNameAndType(name, form_control_type);
}
@@ -96,10 +105,14 @@ void AutofillField::SetTypeTo(const AutofillType& type) {
AutofillType AutofillField::ComputedType() const {
// If autocomplete=tel/tel-* and server confirms it really is a phone field,
// we always user the server prediction as html types are not very reliable.
- if ((GroupTypeOfHtmlFieldType(html_type_, html_mode_) == PHONE_BILLING ||
- GroupTypeOfHtmlFieldType(html_type_, html_mode_) == PHONE_HOME) &&
- (GroupTypeOfServerFieldType(server_type_) == PHONE_BILLING ||
- GroupTypeOfServerFieldType(server_type_) == PHONE_HOME)) {
+ if ((GroupTypeOfHtmlFieldType(html_type_, html_mode_) ==
+ FieldTypeGroup::kPhoneBilling ||
+ GroupTypeOfHtmlFieldType(html_type_, html_mode_) ==
+ FieldTypeGroup::kPhoneHome) &&
+ (GroupTypeOfServerFieldType(server_type_) ==
+ FieldTypeGroup::kPhoneBilling ||
+ GroupTypeOfServerFieldType(server_type_) ==
+ FieldTypeGroup::kPhoneHome)) {
return AutofillType(server_type_);
}
@@ -140,9 +153,10 @@ AutofillType AutofillField::ComputedType() const {
// Either way, retain a preference for the the CVC heuristic over the
// server's password predictions (http://crbug.com/469007)
- believe_server = believe_server &&
- !(AutofillType(server_type_).group() == PASSWORD_FIELD &&
- heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
+ believe_server =
+ believe_server && !(AutofillType(server_type_).group() ==
+ FieldTypeGroup::kPasswordField &&
+ heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
// For new name tokens the heuristic predictions get precedence over the
// server predictions.
@@ -172,6 +186,14 @@ AutofillType AutofillField::ComputedType() const {
}
AutofillType AutofillField::Type() const {
+ // If the corresponding feature is enabled, server predictions that are an
+ // override are granted precedence unconditionally.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillServerTypeTakesPrecedence) &&
+ server_type_prediction_is_override_ && server_type_ != NO_SERVER_DATA) {
+ return AutofillType(server_type_);
+ }
+
if (overall_type_.GetStorableType() != NO_SERVER_DATA) {
return overall_type_;
}
@@ -214,8 +236,8 @@ void AutofillField::NormalizePossibleTypesValidities() {
}
bool AutofillField::IsCreditCardPrediction() const {
- return AutofillType(server_type_).group() == CREDIT_CARD ||
- AutofillType(heuristic_type_).group() == CREDIT_CARD;
+ return AutofillType(server_type_).group() == FieldTypeGroup::kCreditCard ||
+ AutofillType(heuristic_type_).group() == FieldTypeGroup::kCreditCard;
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h
index 4f72790ea37..f3971ad3788 100644
--- a/chromium/components/autofill/core/browser/autofill_field.h
+++ b/chromium/components/autofill/core/browser/autofill_field.h
@@ -40,6 +40,7 @@ class AutofillField : public FormFieldData {
};
AutofillField();
+ explicit AutofillField(const FormFieldData& field);
AutofillField(const FormFieldData& field, const base::string16& unique_name);
virtual ~AutofillField();
@@ -49,10 +50,16 @@ class AutofillField : public FormFieldData {
static std::unique_ptr<AutofillField> CreateForPasswordManagerUpload(
FieldSignature field_signature);
+ // Unique names are not stable across dynamic change. Use renderer IDs instead
+ // if possible.
+ // TODO(crbug/896689): Remove unique_name.
const base::string16& unique_name() const { return unique_name_; }
ServerFieldType heuristic_type() const { return heuristic_type_; }
ServerFieldType server_type() const { return server_type_; }
+ bool server_type_prediction_is_override() const {
+ return server_type_prediction_is_override_;
+ }
const std::vector<
AutofillQueryResponse::FormSuggestion::FieldSuggestion::FieldPrediction>&
server_predictions() const {
@@ -70,11 +77,16 @@ class AutofillField : public FormFieldData {
PhonePart phone_part() const { return phone_part_; }
bool previously_autofilled() const { return previously_autofilled_; }
const base::string16& parseable_name() const { return parseable_name_; }
+ const base::string16& parseable_label() const { return parseable_label_; }
bool only_fill_when_focused() const { return only_fill_when_focused_; }
// Setters for the detected types.
void set_heuristic_type(ServerFieldType type);
void set_server_type(ServerFieldType type);
+ // Setter for the indicator that the server prediction is an override.
+ void set_server_type_prediction_is_override(bool is_override) {
+ server_type_prediction_is_override_ = is_override;
+ }
void add_possible_types_validities(
const ServerFieldTypeValidityStateMap& possible_types_validities);
void set_server_predictions(
@@ -103,6 +115,9 @@ class AutofillField : public FormFieldData {
void set_parseable_name(const base::string16& parseable_name) {
parseable_name_ = parseable_name;
}
+ void set_parseable_label(const base::string16& parseable_label) {
+ parseable_label_ = parseable_label;
+ }
void set_only_fill_when_focused(bool fill_when_focused) {
only_fill_when_focused_ = fill_when_focused;
@@ -182,6 +197,14 @@ class AutofillField : public FormFieldData {
return password_requirements_;
}
+ // Getter and Setter methods for |state_is_a_matching_type_|.
+ void set_state_is_a_matching_type(bool value = true) {
+ state_is_a_matching_type_ = value;
+ }
+ const bool& state_is_a_matching_type() const {
+ return state_is_a_matching_type_;
+ }
+
// For each type in |possible_types_| that's missing from
// |possible_types_validities_|, will add it to the
// |possible_types_validities_| and will set its validity to UNVALIDATED. This
@@ -204,6 +227,9 @@ class AutofillField : public FormFieldData {
// The type of the field, as determined by the Autofill server.
ServerFieldType server_type_ = NO_SERVER_DATA;
+ // Indicates if the server type prediction is an override.
+ bool server_type_prediction_is_override_ = false;
+
// The possible types of the field, as determined by the Autofill server,
// including |server_type_| as the first item.
std::vector<
@@ -262,6 +288,10 @@ class AutofillField : public FormFieldData {
// parsing.
base::string16 parseable_name_;
+ // The parseable label attribute is potentially only a part of the original
+ // label when the label is divided between subsequent fields.
+ base::string16 parseable_label_;
+
// The type of password generation event, if it happened.
AutofillUploadContents::Field::PasswordGenerationType generation_type_ =
AutofillUploadContents::Field::NO_GENERATION;
@@ -275,6 +305,9 @@ class AutofillField : public FormFieldData {
AutofillUploadContents::Field::VoteType vote_type_ =
AutofillUploadContents::Field::NO_INFORMATION;
+ // Denotes if |ADDRESS_HOME_STATE| should be added to |possible_types_|.
+ bool state_is_a_matching_type_ = false;
+
DISALLOW_COPY_AND_ASSIGN(AutofillField);
};
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
index f8889cfce9f..97d4e4c9b00 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -135,7 +135,7 @@ void FormStructureTest::CheckFormStructureTestData(
auto form_structure = std::make_unique<FormStructure>(form);
if (test_case.form_flags.determine_heuristic_type)
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
if (test_case.form_flags.is_autofillable)
EXPECT_TRUE(form_structure->IsAutofillable());
diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc
index b8f647955ae..99752491c36 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler.cc
@@ -4,8 +4,11 @@
#include "components/autofill/core/browser/autofill_handler.h"
+#include "base/bind.h"
#include "base/containers/adapters.h"
#include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/autofill_data_validation.h"
@@ -13,9 +16,10 @@
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
-#include "components/autofill/core/common/renderer_id.h"
-#include "components/autofill/core/common/signatures.h"
+#include "components/translate/core/common/language_detection_details.h"
+#include "google_apis/google_api_keys.h"
#include "ui/gfx/geometry/rect_f.h"
namespace autofill {
@@ -42,7 +46,8 @@ AutofillField* FindAutofillFillField(const FormStructure& form,
return nullptr;
}
-// Returns true if |live_form| does not match |cached_form|.
+// Returns true if |live_form| does not match |cached_form|, assuming that
+// |live_form|'s language is |live_form_language|.
bool CachedFormNeedsUpdate(const FormData& live_form,
const FormStructure& cached_form) {
if (live_form.fields.size() != cached_form.field_count())
@@ -56,15 +61,128 @@ bool CachedFormNeedsUpdate(const FormData& live_form,
return false;
}
+std::string GetAPIKeyForUrl(version_info::Channel channel) {
+ // First look if we can get API key from command line flag.
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kAutofillAPIKey))
+ return command_line.GetSwitchValueASCII(switches::kAutofillAPIKey);
+
+ // Get the API key from Chrome baked keys.
+ if (channel == version_info::Channel::STABLE)
+ return google_apis::GetAPIKey();
+ return google_apis::GetNonStableAPIKey();
+}
+
} // namespace
using base::TimeTicks;
-AutofillHandler::AutofillHandler(AutofillDriver* driver,
- LogManager* log_manager)
- : driver_(driver), log_manager_(log_manager) {}
+// static
+void AutofillHandler::LogAutofillTypePredictionsAvailable(
+ LogManager* log_manager,
+ const std::vector<FormStructure*>& forms) {
+ if (VLOG_IS_ON(1)) {
+ VLOG(1) << "Parsed forms:";
+ for (FormStructure* form : forms)
+ VLOG(1) << *form;
+ }
+
+ if (!log_manager || !log_manager->IsLoggingActive())
+ return;
+
+ LogBuffer buffer;
+ for (FormStructure* form : forms)
+ buffer << *form;
+
+ log_manager->Log() << LoggingScope::kParsing << LogMessage::kParsedForms
+ << std::move(buffer);
+}
+
+// static
+bool AutofillHandler::IsRichQueryEnabled(version_info::Channel channel) {
+ return base::FeatureList::IsEnabled(features::kAutofillRichMetadataQueries) &&
+ channel != version_info::Channel::STABLE &&
+ channel != version_info::Channel::BETA;
+}
-AutofillHandler::~AutofillHandler() = default;
+// static
+bool AutofillHandler::IsRawMetadataUploadingEnabled(
+ version_info::Channel channel) {
+ return channel == version_info::Channel::CANARY ||
+ channel == version_info::Channel::DEV;
+}
+
+AutofillHandler::AutofillHandler(
+ AutofillDriver* driver,
+ AutofillClient* client,
+ AutofillDownloadManagerState enable_download_manager)
+ : AutofillHandler(driver,
+ client,
+ enable_download_manager,
+ client->GetChannel()) {
+ DCHECK(driver);
+ DCHECK(client);
+}
+
+AutofillHandler::AutofillHandler(
+ AutofillDriver* driver,
+ AutofillClient* client,
+ AutofillDownloadManagerState enable_download_manager,
+ version_info::Channel channel)
+ : driver_(driver),
+ client_(client),
+ log_manager_(client ? client->GetLogManager() : nullptr),
+ form_interactions_ukm_logger_(CreateFormInteractionsUkmLogger()),
+ is_rich_query_enabled_(IsRichQueryEnabled(channel)) {
+ if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {
+ download_manager_ = std::make_unique<AutofillDownloadManager>(
+ driver, this, GetAPIKeyForUrl(channel),
+ AutofillDownloadManager::IsRawMetadataUploadingEnabled(
+ IsRawMetadataUploadingEnabled(channel)),
+ log_manager_);
+ }
+ if (client) {
+ translate::TranslateDriver* translate_driver = client->GetTranslateDriver();
+ if (translate_driver) {
+ translate_observation_.Observe(translate_driver);
+ }
+ }
+}
+
+AutofillHandler::~AutofillHandler() {
+ translate_observation_.Reset();
+ if (!query_result_delay_task_.IsCancelled())
+ query_result_delay_task_.Cancel();
+}
+
+void AutofillHandler::OnLanguageDetermined(
+ const translate::LanguageDetectionDetails& details) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillParsingPatternsLanguageDetection)) {
+ return;
+ }
+ for (auto& p : form_structures_) {
+ std::unique_ptr<FormStructure>& form_structure = p.second;
+ form_structure->set_current_page_language(
+ LanguageCode(details.adopted_language));
+ form_structure->DetermineHeuristicTypes(form_interactions_ukm_logger(),
+ log_manager_);
+ }
+}
+
+void AutofillHandler::OnTranslateDriverDestroyed(
+ translate::TranslateDriver* translate_driver) {
+ translate_observation_.Reset();
+}
+
+LanguageCode AutofillHandler::GetCurrentPageLanguage() const {
+ DCHECK(client_);
+ const translate::LanguageState* language_state = client_->GetLanguageState();
+ if (!language_state)
+ return LanguageCode();
+ return LanguageCode(language_state->current_language());
+}
void AutofillHandler::OnFormSubmitted(const FormData& form,
bool known_success,
@@ -73,14 +191,13 @@ void AutofillHandler::OnFormSubmitted(const FormData& form,
OnFormSubmittedImpl(form, known_success, source);
}
-void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) {
+void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms) {
if (!IsValidFormDataVector(forms) || !driver_->RendererIsAvailable())
return;
// This should be called even forms is empty, AutofillProviderAndroid uses
// this event to detect form submission.
- if (!ShouldParseForms(forms, timestamp))
+ if (!ShouldParseForms(forms))
return;
if (forms.empty())
@@ -91,26 +208,15 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
const auto parse_form_start_time = AutofillTickClock::NowTicks();
FormStructure* cached_form_structure =
FindCachedFormByRendererId(form.unique_renderer_id);
- // Autofill used to ignore cache hits for non-credit-card forms. The
- // motivation behind this is probably to have credit-card forms preserve
- // their original signature, whereas non-credit-card forms would use the
- // most recent form signature. Ignoring cache hits however appears to be
- // part of breaking profile imports and voting for dynamic forms. See
- // crbug/1091401#c15 for details.
- //
- // Therefore, if the kAutofillKeepInitialFormValuesInCache experiment is
- // enabled, we do not ignore cache hits, but in those cases where the old
- // code would have ignored the cache hit we update the FormStructure's
- // FormSignature.
- // Otherwise, if the experiment disabled, we just ignore the cache hit.
+
+ // Not updating signatures of credit card forms is legacy behaviour. We
+ // believe that the signatures are kept stable for voting purposes.
bool update_form_signature = false;
if (cached_form_structure) {
- for (const FormType& form_type : cached_form_structure->GetFormTypes()) {
- if (form_type != CREDIT_CARD_FORM) {
- update_form_signature = true;
- break;
- }
- }
+ const DenseSet<FormType>& form_types =
+ cached_form_structure->GetFormTypes();
+ update_form_signature =
+ form_types.size() > form_types.count(FormType::kCreditCardForm);
}
FormStructure* form_structure = ParseForm(form, cached_form_structure);
@@ -128,7 +234,55 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
if (new_forms.empty())
return;
- OnFormsParsed(new_forms, timestamp);
+ OnFormsParsed(new_forms);
+}
+
+void AutofillHandler::OnFormsParsed(const std::vector<const FormData*>& forms) {
+ DCHECK(!forms.empty());
+ OnBeforeProcessParsedForms();
+
+ driver()->HandleParsedForms(forms);
+
+ std::vector<FormStructure*> non_queryable_forms;
+ std::vector<FormStructure*> queryable_forms;
+ DenseSet<FormType> form_types;
+ for (const FormData* form : forms) {
+ FormStructure* form_structure =
+ FindCachedFormByRendererId(form->unique_renderer_id);
+ if (!form_structure) {
+ NOTREACHED();
+ continue;
+ }
+
+ form_types.insert_all(form_structure->GetFormTypes());
+
+ // Configure the query encoding for this form and add it to the appropriate
+ // collection of forms: queryable vs non-queryable.
+ form_structure->set_is_rich_query_enabled(is_rich_query_enabled_);
+ if (form_structure->ShouldBeQueried())
+ queryable_forms.push_back(form_structure);
+ else
+ non_queryable_forms.push_back(form_structure);
+
+ OnFormProcessed(*form, *form_structure);
+ }
+
+ if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
+ OnAfterProcessParsedForms(form_types);
+ }
+
+ // Send the current type predictions to the renderer. For non-queryable forms
+ // this is all the information about them that will ever be available. The
+ // queryable forms will be updated once the field type query is complete.
+ driver()->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
+ driver()->SendAutofillTypePredictionsToRenderer(queryable_forms);
+ LogAutofillTypePredictionsAvailable(log_manager_, non_queryable_forms);
+ LogAutofillTypePredictionsAvailable(log_manager_, queryable_forms);
+
+ // Query the server if at least one of the forms was parsed.
+ if (!queryable_forms.empty() && download_manager()) {
+ download_manager()->StartQueryRequest(queryable_forms);
+ }
}
void AutofillHandler::OnTextFieldDidChange(const FormData& form,
@@ -203,6 +357,7 @@ void AutofillHandler::SendFormDataToRenderer(
driver_->SendFormDataToRenderer(query_id, action, data);
}
+// Returns true if |live_form| does not match |cached_form|.
bool AutofillHandler::GetCachedFormAndField(const FormData& form,
const FormFieldData& field,
FormStructure** form_structure,
@@ -242,6 +397,15 @@ bool AutofillHandler::GetCachedFormAndField(const FormData& form,
return *autofill_field != nullptr;
}
+std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
+AutofillHandler::CreateFormInteractionsUkmLogger() {
+ if (!client())
+ return nullptr;
+
+ return std::make_unique<AutofillMetrics::FormInteractionsUkmLogger>(
+ client()->GetUkmRecorder(), client()->GetUkmSourceId());
+}
+
size_t AutofillHandler::FindCachedFormsBySignature(
FormSignature form_signature,
std::vector<FormStructure*>* form_structures) const {
@@ -290,9 +454,10 @@ FormStructure* AutofillHandler::ParseForm(const FormData& form,
value_from_dynamic_change_form_ = true;
}
- form_structure->set_page_language(GetPageLanguage());
+ form_structure->set_current_page_language(GetCurrentPageLanguage());
- form_structure->DetermineHeuristicTypes(log_manager_);
+ form_structure->DetermineHeuristicTypes(form_interactions_ukm_logger(),
+ log_manager_);
// Hold the parsed_form_structure we intend to return. We can use this to
// reference the form_signature when transferring ownership below.
@@ -309,12 +474,90 @@ FormStructure* AutofillHandler::ParseForm(const FormData& form,
return parsed_form_structure;
}
-std::string AutofillHandler::GetPageLanguage() const {
- return std::string();
-}
-
void AutofillHandler::Reset() {
form_structures_.clear();
+ form_interactions_ukm_logger_ = CreateFormInteractionsUkmLogger();
}
+void AutofillHandler::OnLoadedServerPredictions(
+ std::string response,
+ const std::vector<FormSignature>& queried_form_signatures) {
+ // Get the current valid FormStructures represented by
+ // |queried_form_signatures|.
+ std::vector<FormStructure*> queried_forms;
+ queried_forms.reserve(queried_form_signatures.size());
+ for (const auto& form_signature : queried_form_signatures) {
+ FindCachedFormsBySignature(form_signature, &queried_forms);
+ }
+
+ // Each form signature in |queried_form_signatures| is supposed to be unique,
+ // and therefore appear only once. This ensures that
+ // FindCachedFormsBySignature() produces an output without duplicates in the
+ // forms.
+ // TODO(crbug/1064709): |queried_forms| could be a set data structure; their
+ // order should be irrelevant.
+ DCHECK_EQ(queried_forms.size(),
+ std::set<FormStructure*>(queried_forms.begin(), queried_forms.end())
+ .size());
+
+ // If there are no current forms corresponding to the queried signatures, drop
+ // the query response.
+ if (queried_forms.empty())
+ return;
+
+ // Parse and store the server predictions.
+ FormStructure::ParseApiQueryResponse(std::move(response), queried_forms,
+ queried_form_signatures,
+ form_interactions_ukm_logger());
+
+ // Will log quality metrics for each FormStructure based on the presence of
+ // autocomplete attributes, if available.
+ if (auto* logger = form_interactions_ukm_logger()) {
+ for (FormStructure* cur_form : queried_forms) {
+ cur_form->LogQualityMetricsBasedOnAutocomplete(logger);
+ }
+ }
+
+ // Send field type predictions to the renderer so that it can possibly
+ // annotate forms with the predicted types or add console warnings.
+ driver()->SendAutofillTypePredictionsToRenderer(queried_forms);
+
+ LogAutofillTypePredictionsAvailable(log_manager_, queried_forms);
+
+ // TODO(crbug.com/1176816): Remove the test code after initial integration.
+ int delay = 0;
+ if (auto* cmd = base::CommandLine::ForCurrentProcess()) {
+ // This command line helps to simulate query result arriving after autofill
+ // is triggered and shall be used for manual test only.
+ std::string value = cmd->GetSwitchValueASCII(
+ "autofill-server-query-result-delay-in-seconds");
+ if (!base::StringToInt(value, &delay))
+ delay = 0;
+ }
+
+ if (delay > 0) {
+ query_result_delay_task_.Reset(
+ base::BindOnce(&AutofillHandler::PropagateAutofillPredictionsToDriver,
+ base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(query_result_delay_task_.callback(), queried_forms),
+ base::TimeDelta::FromSeconds(delay));
+ } else {
+ PropagateAutofillPredictionsToDriver(queried_forms);
+ }
+}
+
+void AutofillHandler::PropagateAutofillPredictionsToDriver(
+ const std::vector<FormStructure*>& queried_forms) {
+ // Forward form structures to the password generation manager to detect
+ // account creation forms.
+ driver()->PropagateAutofillPredictions(queried_forms);
+}
+
+void AutofillHandler::OnServerRequestError(
+ FormSignature form_signature,
+ AutofillDownloadManager::RequestType request_type,
+ int http_error) {}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h
index 18b7d0b42c3..3f1dc3c1259 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.h
+++ b/chromium/components/autofill/core/browser/autofill_handler.h
@@ -10,14 +10,22 @@
#include <string>
#include <vector>
+#include "base/cancelable_callback.h"
#include "base/compiler_specific.h"
+#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_download_manager.h"
#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/language_code.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
+#include "components/translate/core/browser/translate_driver.h"
+#include "components/version_info/channel.h"
namespace gfx {
class RectF;
@@ -33,7 +41,9 @@ class LogManager;
// This class defines the interface should be implemented by autofill
// implementation in browser side to interact with AutofillDriver.
-class AutofillHandler {
+class AutofillHandler
+ : public AutofillDownloadManager::Observer,
+ public translate::TranslateDriver::LanguageDetectionObserver {
public:
enum AutofillDownloadManagerState {
ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
@@ -47,7 +57,24 @@ class AutofillHandler {
virtual void OnFormParsed() = 0;
};
- virtual ~AutofillHandler();
+ // Rich queries are enabled by feature flag iff this chrome instance is
+ // neither on the STABLE nor BETA release channel.
+ static bool IsRichQueryEnabled(version_info::Channel channel);
+
+ // Raw metadata uploading enabled iff this Chrome instance is on Canary or Dev
+ // channel.
+ static bool IsRawMetadataUploadingEnabled(version_info::Channel channel);
+
+ // TODO(crbug.com/1151542): Move to anonymous namespace once
+ // AutofillManager::OnLoadedServerPredictions() moves to AutofillHandler.
+ static void LogAutofillTypePredictionsAvailable(
+ LogManager* log_manager,
+ const std::vector<FormStructure*>& forms);
+
+ ~AutofillHandler() override;
+
+ AutofillClient* client() { return client_; }
+ const AutofillClient* client() const { return client_; }
// Invoked when the value of textfield is changed.
void OnTextFieldDidChange(const FormData& form,
@@ -86,8 +113,7 @@ class AutofillHandler {
mojom::SubmissionSource source);
// Invoked when |forms| has been detected.
- void OnFormsSeen(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp);
+ void OnFormsSeen(const std::vector<FormData>& forms);
// Invoked when focus is no longer on form. |had_interacted_form| indicates
// whether focus was previously on a form with which the user had interacted.
@@ -110,9 +136,25 @@ class AutofillHandler {
// Invoked when the options of a select element in the |form| changed.
virtual void SelectFieldOptionsDidChange(const FormData& form) = 0;
+ // Invoked when the field type predictions are downloaded from the autofill
+ // server.
+ virtual void PropagateAutofillPredictions(
+ content::RenderFrameHost* rfh,
+ const std::vector<FormStructure*>& forms) = 0;
+
// Resets cache.
virtual void Reset();
+ // translate::TranslateDriver::LanguageDetectionObserver:
+ void OnTranslateDriverDestroyed(
+ translate::TranslateDriver* translate_driver) override;
+ // Invoked when the language has been detected by the Translate component.
+ // As this usually happens after Autofill has parsed the forms for the first
+ // time, the heuristics need to be re-run by this function in order to run
+ // use language-specific patterns.
+ void OnLanguageDetermined(
+ const translate::LanguageDetectionDetails& details) override;
+
// Send the form |data| to renderer for the specified |action|.
void SendFormDataToRenderer(int query_id,
AutofillDriver::RendererFormDataAction action,
@@ -127,6 +169,10 @@ class AutofillHandler {
FormStructure** form_structure,
AutofillField** autofill_field) WARN_UNUSED_RESULT;
+ // Returns nullptr if no cached form structure is found with a matching
+ // |renderer_id|. Runs in logarithmic time.
+ FormStructure* FindCachedFormByRendererId(FormRendererId renderer_id) const;
+
// Returns the number of forms this Autofill handler is aware of.
size_t NumFormsDetected() const { return form_structures_.size(); }
@@ -142,6 +188,29 @@ class AutofillHandler {
AutofillDriver* driver() { return driver_; }
+ AutofillDownloadManager* download_manager() {
+ return download_manager_.get();
+ }
+
+ // The return value shouldn't be cached, retrieve it as needed.
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger() {
+ return form_interactions_ukm_logger_.get();
+ }
+
+ // A public wrapper that calls |OnLoadedServerPredictions| for testing
+ // purposes only, it is used by WebView integration test and unit test, so it
+ // can't be in #ifdef UNIT_TEST.
+ void OnLoadedServerPredictionsForTest(
+ std::string response,
+ const std::vector<FormSignature>& queried_form_signatures) {
+ OnLoadedServerPredictions(response, queried_form_signatures);
+ }
+ void OnServerRequestErrorForTest(
+ FormSignature form_signature,
+ AutofillDownloadManager::RequestType request_type,
+ int http_error) {
+ OnServerRequestError(form_signature, request_type, http_error);
+ }
#ifdef UNIT_TEST
// A public wrapper that calls |mutable_form_structures| for testing purposes
// only.
@@ -154,10 +223,22 @@ class AutofillHandler {
FormStructure* ParseFormForTest(const FormData& form) {
return ParseForm(form, nullptr);
}
-#endif
+
+#endif // UNIT_TEST
protected:
- AutofillHandler(AutofillDriver* driver, LogManager* log_manager);
+ AutofillHandler(AutofillDriver* driver,
+ AutofillClient* client,
+ AutofillDownloadManagerState enable_download_manager);
+ AutofillHandler(AutofillDriver* driver,
+ AutofillClient* client,
+ AutofillDownloadManagerState enable_download_manager,
+ version_info::Channel channel);
+
+ LogManager* log_manager() { return log_manager_; }
+
+ // Retrieves the page language from |client_|
+ LanguageCode GetCurrentPageLanguage() const;
virtual void OnFormSubmittedImpl(const FormData& form,
bool known_success,
@@ -189,12 +270,19 @@ class AutofillHandler {
// Return whether the |forms| from OnFormSeen() should be parsed to
// form_structures.
- virtual bool ShouldParseForms(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) = 0;
+ virtual bool ShouldParseForms(const std::vector<FormData>& forms) = 0;
- // Invoked when forms from OnFormsSeen() has been parsed to |form_structures|.
- virtual void OnFormsParsed(const std::vector<const FormData*>& forms,
- const base::TimeTicks timestamp) = 0;
+ // Invoked before parsing the forms.
+ virtual void OnBeforeProcessParsedForms() = 0;
+
+ // Invoked when the given |form| has been processed to the given
+ // |form_structure|.
+ virtual void OnFormProcessed(const FormData& form,
+ const FormStructure& form_structure) = 0;
+ // Invoked after all forms have been processed, |form_types| is a set of
+ // FormType found.
+ virtual void OnAfterProcessParsedForms(
+ const DenseSet<FormType>& form_types) = 0;
// Returns the number of FormStructures with the given |form_signature| and
// appends them to |form_structures|. Runs in linear time.
@@ -202,19 +290,12 @@ class AutofillHandler {
FormSignature form_signature,
std::vector<FormStructure*>* form_structures) const;
- // Returns nullptr if no cached form structure is found with a matching
- // |renderer_id|. Runs in logarithmic time.
- FormStructure* FindCachedFormByRendererId(FormRendererId renderer_id) const;
-
// Parses the |form| with the server data retrieved from the |cached_form|
// (if any). Returns nullptr if the form should not be parsed. Otherwise, adds
// the returned form structure to the |form_structures_|.
FormStructure* ParseForm(const FormData& form,
const FormStructure* cached_form);
- // Returns the page language, if available.
- virtual std::string GetPageLanguage() const;
-
bool value_from_dynamic_change_form_ = false;
std::map<FormRendererId, std::unique_ptr<FormStructure>>*
@@ -222,16 +303,70 @@ class AutofillHandler {
return &form_structures_;
}
+#ifdef UNIT_TEST
+ // Exposed for testing.
+ void set_download_manager_for_test(
+ std::unique_ptr<AutofillDownloadManager> manager) {
+ download_manager_ = std::move(manager);
+ }
+
+ // Exposed for testing.
+ bool is_rich_query_enabled() const { return is_rich_query_enabled_; }
+#endif // UNIT_TEST
+
private:
+ // AutofillDownloadManager::Observer:
+ void OnLoadedServerPredictions(
+ std::string response,
+ const std::vector<FormSignature>& queried_form_signatures) override;
+ void OnServerRequestError(FormSignature form_signature,
+ AutofillDownloadManager::RequestType request_type,
+ int http_error) override;
+
+ // Invoked when forms from OnFormsSeen() have been parsed to
+ // |form_structures|.
+ void OnFormsParsed(const std::vector<const FormData*>& forms);
+
+ void PropagateAutofillPredictionsToDriver(
+ const std::vector<FormStructure*>& forms);
+
+ std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
+ CreateFormInteractionsUkmLogger();
+
// Provides driver-level context to the shared code of the component. Must
// outlive this object.
AutofillDriver* const driver_;
+ AutofillClient* const client_;
+
LogManager* const log_manager_;
+ // Observer needed to re-run heuristics when the language has been detected.
+ base::ScopedObservation<
+ translate::TranslateDriver,
+ translate::TranslateDriver::LanguageDetectionObserver,
+ &translate::TranslateDriver::AddLanguageDetectionObserver,
+ &translate::TranslateDriver::RemoveLanguageDetectionObserver>
+ translate_observation_{this};
+
// Our copy of the form data.
std::map<FormRendererId, std::unique_ptr<FormStructure>> form_structures_;
+ // Handles queries and uploads to Autofill servers. Will be nullptr if
+ // the download manager functionality is disabled.
+ std::unique_ptr<AutofillDownloadManager> download_manager_;
+
+ // Utility for logging URL keyed metrics.
+ std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
+ form_interactions_ukm_logger_;
+
+ // Tracks whether or not rich query encoding is enabled for this client.
+ const bool is_rich_query_enabled_ = false;
+
+ // Task to delay propagate the query result to driver for testing.
+ base::CancelableOnceCallback<void(const std::vector<FormStructure*>&)>
+ query_result_delay_task_;
+
// Will be not null only for |SaveCardBubbleViewsFullFormBrowserTest|.
ObserverForTest* observer_for_testing_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
index 41fd6d405e2..8698501e79c 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -10,10 +10,16 @@ namespace autofill {
using base::TimeTicks;
-AutofillHandlerProxy::AutofillHandlerProxy(AutofillDriver* driver,
- LogManager* log_manager,
- AutofillProvider* provider)
- : AutofillHandler(driver, log_manager), provider_(provider) {}
+AutofillHandlerProxy::AutofillHandlerProxy(
+ AutofillDriver* driver,
+ AutofillClient* client,
+ AutofillProvider* provider,
+ AutofillHandler::AutofillDownloadManagerState enable_download_manager)
+ : AutofillHandler(driver,
+ client,
+ enable_download_manager,
+ version_info::Channel::UNKNOWN),
+ provider_(provider) {}
AutofillHandlerProxy::~AutofillHandlerProxy() {}
@@ -62,18 +68,14 @@ void AutofillHandlerProxy::OnSelectControlDidChangeImpl(
provider_->OnSelectControlDidChange(this, form, field, bounding_box);
}
-bool AutofillHandlerProxy::ShouldParseForms(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) {
- provider_->OnFormsSeen(this, forms, timestamp);
+bool AutofillHandlerProxy::ShouldParseForms(
+ const std::vector<FormData>& forms) {
+ provider_->OnFormsSeen(this, forms);
// Need to parse the |forms| to FormStructure, so heuristic_type can be
// retrieved later.
return true;
}
-void AutofillHandlerProxy::OnFormsParsed(
- const std::vector<const FormData*>& form_structures,
- const base::TimeTicks timestamp) {}
-
void AutofillHandlerProxy::OnFocusNoLongerOnForm(bool had_interacted_form) {
provider_->OnFocusNoLongerOnForm(this, had_interacted_form);
}
@@ -84,17 +86,29 @@ void AutofillHandlerProxy::OnDidFillAutofillFormData(
provider_->OnDidFillAutofillFormData(this, form, timestamp);
}
-void AutofillHandlerProxy::OnDidPreviewAutofillFormData() {}
-
-void AutofillHandlerProxy::OnDidEndTextFieldEditing() {}
-
void AutofillHandlerProxy::OnHidePopup() {
provider_->OnHidePopup(this);
}
void AutofillHandlerProxy::SelectFieldOptionsDidChange(const FormData& form) {}
+void AutofillHandlerProxy::PropagateAutofillPredictions(
+ content::RenderFrameHost* rfh,
+ const std::vector<FormStructure*>& forms) {
+ has_server_prediction_ = true;
+ provider_->OnServerPredictionsAvailable(this);
+}
+
+void AutofillHandlerProxy::OnServerRequestError(
+ FormSignature form_signature,
+ AutofillDownloadManager::RequestType request_type,
+ int http_error) {
+ provider_->OnServerQueryRequestError(this, form_signature);
+}
+
void AutofillHandlerProxy::Reset() {
+ AutofillHandler::Reset();
+ has_server_prediction_ = false;
provider_->Reset(this);
}
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.h b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
index 8d2f0287888..9a41754e3d6 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.h
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
@@ -7,6 +7,7 @@
#include "base/memory/weak_ptr.h"
#include "components/autofill/core/browser/autofill_handler.h"
+#include "components/autofill/core/common/dense_set.h"
namespace autofill {
@@ -15,9 +16,11 @@ class AutofillProvider;
// This class forwards AutofillHandler calls to AutofillProvider.
class AutofillHandlerProxy : public AutofillHandler {
public:
- AutofillHandlerProxy(AutofillDriver* driver,
- LogManager* log_manager,
- AutofillProvider* provider);
+ AutofillHandlerProxy(
+ AutofillDriver* driver,
+ AutofillClient* client,
+ AutofillProvider* provider,
+ AutofillHandler::AutofillDownloadManagerState enable_download_manager);
~AutofillHandlerProxy() override;
void OnFocusNoLongerOnForm(bool had_interacted_form) override;
@@ -25,8 +28,8 @@ class AutofillHandlerProxy : public AutofillHandler {
void OnDidFillAutofillFormData(const FormData& form,
const base::TimeTicks timestamp) override;
- void OnDidPreviewAutofillFormData() override;
- void OnDidEndTextFieldEditing() override;
+ void OnDidPreviewAutofillFormData() override {}
+ void OnDidEndTextFieldEditing() override {}
void OnHidePopup() override;
void SelectFieldOptionsDidChange(const FormData& form) override;
@@ -36,6 +39,8 @@ class AutofillHandlerProxy : public AutofillHandler {
return weak_ptr_factory_.GetWeakPtr();
}
+ bool has_server_prediction() const { return has_server_prediction_; }
+
protected:
void OnFormSubmittedImpl(const FormData& form,
bool known_success,
@@ -64,13 +69,26 @@ class AutofillHandlerProxy : public AutofillHandler {
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
- bool ShouldParseForms(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) override;
+ bool ShouldParseForms(const std::vector<FormData>& forms) override;
+
+ void OnBeforeProcessParsedForms() override {}
+
+ void OnFormProcessed(const FormData& form,
+ const FormStructure& form_structure) override {}
+
+ void OnAfterProcessParsedForms(
+ const DenseSet<FormType>& form_types) override {}
+
+ void PropagateAutofillPredictions(
+ content::RenderFrameHost* rfh,
+ const std::vector<FormStructure*>& forms) override;
- void OnFormsParsed(const std::vector<const FormData*>& form_structures,
- const base::TimeTicks timestamp) override;
+ void OnServerRequestError(FormSignature form_signature,
+ AutofillDownloadManager::RequestType request_type,
+ int http_error) override;
private:
+ bool has_server_prediction_ = false;
AutofillProvider* provider_;
base::WeakPtrFactory<AutofillHandlerProxy> weak_ptr_factory_{this};
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
index 9a951322bc7..f365bd94f19 100644
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
+++ b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
@@ -75,13 +75,12 @@ bool IsEmptySalt(std::wstring const& salt) {
return true;
}
-base::string16 ReadAndDecryptValue(const RegKey& key,
- const wchar_t* value_name) {
+std::wstring ReadAndDecryptValue(const RegKey& key, const wchar_t* value_name) {
DWORD data_type = REG_BINARY;
DWORD data_size = 0;
LONG result = key.ReadValue(value_name, nullptr, &data_size, &data_type);
if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY)
- return base::string16();
+ return std::wstring();
std::string data;
data.resize(data_size);
result = key.ReadValue(value_name, &(data[0]), &data_size, &data_type);
@@ -91,12 +90,11 @@ base::string16 ReadAndDecryptValue(const RegKey& key,
// The actual data is in UTF16 already.
if (!(out_data.size() & 1) && (out_data.size() > 2) &&
!out_data[out_data.size() - 1] && !out_data[out_data.size() - 2]) {
- return base::string16(
- reinterpret_cast<const wchar_t *>(out_data.c_str()));
+ return reinterpret_cast<const wchar_t*>(out_data.c_str());
}
}
}
- return base::string16();
+ return std::wstring();
}
struct {
@@ -157,16 +155,18 @@ bool ImportSingleFormGroup(const RegKey& key,
if (it == reg_to_field.end())
continue; // This field is not imported.
- base::string16 field_value = ReadAndDecryptValue(key, value_name.c_str());
+ std::wstring field_value = ReadAndDecryptValue(key, value_name.c_str());
if (!field_value.empty()) {
if (it->second == CREDIT_CARD_NUMBER)
field_value = DecryptCCNumber(field_value);
// Phone numbers are stored piece-by-piece, and then reconstructed from
// the pieces. The rest of the fields are set "as is".
- if (!phone || !phone->SetInfo(AutofillType(it->second), field_value)) {
+ if (!phone || !phone->SetInfo(AutofillType(it->second),
+ base::WideToUTF16(field_value))) {
has_non_empty_fields = true;
- form_group->SetInfo(AutofillType(it->second), field_value, app_locale);
+ form_group->SetInfo(AutofillType(it->second),
+ base::WideToUTF16(field_value), app_locale);
}
}
}
@@ -265,8 +265,8 @@ bool ImportCurrentUserProfiles(const std::string& app_locale,
profiles->push_back(profile);
}
}
- base::string16 password_hash;
- base::string16 salt;
+ std::wstring password_hash;
+ std::wstring salt;
RegKey cc_key(HKEY_CURRENT_USER, kCreditCardKey, KEY_READ);
if (cc_key.Valid()) {
password_hash = ReadAndDecryptValue(cc_key, kPasswordHashValue);
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
index 089f2cc97ba..f1b065de45a 100644
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
@@ -8,6 +8,7 @@
#include "base/stl_util.h"
#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
@@ -173,32 +174,42 @@ TEST_F(AutofillIeToolbarImportTest, TestAutofillImport) {
EXPECT_TRUE(ImportCurrentUserProfiles("en-US", &profiles, &credit_cards));
ASSERT_EQ(2U, profiles.size());
// The profiles are read in reverse order.
- EXPECT_EQ(profile1[0].value, profiles[1].GetRawInfo(NAME_FIRST));
- EXPECT_EQ(profile1[1].value, profiles[1].GetRawInfo(NAME_MIDDLE));
- EXPECT_EQ(profile1[2].value, profiles[1].GetRawInfo(NAME_LAST));
- EXPECT_EQ(profile1[3].value, profiles[1].GetRawInfo(EMAIL_ADDRESS));
- EXPECT_EQ(profile1[4].value, profiles[1].GetRawInfo(COMPANY_NAME));
- EXPECT_EQ(profile1[7].value,
+ EXPECT_EQ(base::WideToUTF16(profile1[0].value),
+ profiles[1].GetRawInfo(NAME_FIRST));
+ EXPECT_EQ(base::WideToUTF16(profile1[1].value),
+ profiles[1].GetRawInfo(NAME_MIDDLE));
+ EXPECT_EQ(base::WideToUTF16(profile1[2].value),
+ profiles[1].GetRawInfo(NAME_LAST));
+ EXPECT_EQ(base::WideToUTF16(profile1[3].value),
+ profiles[1].GetRawInfo(EMAIL_ADDRESS));
+ EXPECT_EQ(base::WideToUTF16(profile1[4].value),
+ profiles[1].GetRawInfo(COMPANY_NAME));
+ EXPECT_EQ(base::WideToUTF16(profile1[7].value),
profiles[1].GetInfo(AutofillType(PHONE_HOME_COUNTRY_CODE), "US"));
- EXPECT_EQ(profile1[6].value,
+ EXPECT_EQ(base::WideToUTF16(profile1[6].value),
profiles[1].GetInfo(AutofillType(PHONE_HOME_CITY_CODE), "US"));
- EXPECT_EQ(L"5555555",
+ EXPECT_EQ(STRING16_LITERAL("5555555"),
profiles[1].GetInfo(AutofillType(PHONE_HOME_NUMBER), "US"));
- EXPECT_EQ(L"1 650-555-5555", profiles[1].GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
-
- EXPECT_EQ(profile2[0].value, profiles[0].GetRawInfo(NAME_FIRST));
- EXPECT_EQ(profile2[1].value, profiles[0].GetRawInfo(NAME_LAST));
- EXPECT_EQ(profile2[2].value, profiles[0].GetRawInfo(EMAIL_ADDRESS));
- EXPECT_EQ(profile2[3].value, profiles[0].GetRawInfo(COMPANY_NAME));
+ EXPECT_EQ(STRING16_LITERAL("1 650-555-5555"),
+ profiles[1].GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+
+ EXPECT_EQ(base::WideToUTF16(profile2[0].value),
+ profiles[0].GetRawInfo(NAME_FIRST));
+ EXPECT_EQ(base::WideToUTF16(profile2[1].value),
+ profiles[0].GetRawInfo(NAME_LAST));
+ EXPECT_EQ(base::WideToUTF16(profile2[2].value),
+ profiles[0].GetRawInfo(EMAIL_ADDRESS));
+ EXPECT_EQ(base::WideToUTF16(profile2[3].value),
+ profiles[0].GetRawInfo(COMPANY_NAME));
ASSERT_EQ(1U, credit_cards.size());
- EXPECT_EQ(credit_card[0].value,
+ EXPECT_EQ(base::WideToUTF16(credit_card[0].value),
credit_cards[0].GetRawInfo(CREDIT_CARD_NAME_FULL));
- EXPECT_EQ(L"4111111111111111",
+ EXPECT_EQ(STRING16_LITERAL("4111111111111111"),
credit_cards[0].GetRawInfo(CREDIT_CARD_NUMBER));
- EXPECT_EQ(credit_card[2].value,
+ EXPECT_EQ(base::WideToUTF16(credit_card[2].value),
credit_cards[0].GetRawInfo(CREDIT_CARD_EXP_MONTH));
- EXPECT_EQ(credit_card[3].value,
+ EXPECT_EQ(base::WideToUTF16(credit_card[3].value),
credit_cards[0].GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
// Mock password encrypted cc.
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 9f4f5f3688e..5f901aba729 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -20,6 +20,7 @@
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
+#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/guid.h"
@@ -40,6 +41,7 @@
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_browser_util.h"
#include "components/autofill/core/browser/autofill_client.h"
@@ -76,7 +78,6 @@
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
-#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
@@ -89,8 +90,6 @@
#include "components/security_interstitials/core/pref_names.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
-#include "components/version_info/channel.h"
-#include "google_apis/google_api_keys.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect.h"
@@ -137,7 +136,8 @@ base::string16 SanitizeCreditCardFieldValue(const base::string16& value) {
// Returns whether the |field| is predicted as being any kind of name.
bool IsNameType(const AutofillField& field) {
- return field.Type().group() == NAME || field.Type().group() == NAME_BILLING ||
+ return field.Type().group() == FieldTypeGroup::kName ||
+ field.Type().group() == FieldTypeGroup::kNameBilling ||
field.Type().GetStorableType() == CREDIT_CARD_NAME_FULL ||
field.Type().GetStorableType() == CREDIT_CARD_NAME_FIRST ||
field.Type().GetStorableType() == CREDIT_CARD_NAME_LAST;
@@ -157,8 +157,8 @@ void SelectRightNameType(AutofillField* field, bool is_credit_card) {
for (auto type : old_types) {
FieldTypeGroup group = AutofillType(type).group();
- if ((is_credit_card && group == CREDIT_CARD) ||
- (!is_credit_card && group == NAME)) {
+ if ((is_credit_card && group == FieldTypeGroup::kCreditCard) ||
+ (!is_credit_card && group == FieldTypeGroup::kName)) {
types_to_keep.insert(type);
}
}
@@ -176,30 +176,17 @@ void SelectRightNameType(AutofillField* field, bool is_credit_card) {
void LogDeveloperEngagementUkm(ukm::UkmRecorder* ukm_recorder,
ukm::SourceId source_id,
- FormStructure* form_structure) {
- if (form_structure->developer_engagement_metrics()) {
+ const FormStructure& form_structure) {
+ if (form_structure.developer_engagement_metrics()) {
AutofillMetrics::LogDeveloperEngagementUkm(
- ukm_recorder, source_id, form_structure->main_frame_origin().GetURL(),
- form_structure->IsCompleteCreditCardForm(),
- form_structure->GetFormTypes(),
- form_structure->developer_engagement_metrics(),
- form_structure->form_signature());
+ ukm_recorder, source_id, form_structure.main_frame_origin().GetURL(),
+ form_structure.IsCompleteCreditCardForm(),
+ form_structure.GetFormTypes(),
+ form_structure.developer_engagement_metrics(),
+ form_structure.form_signature());
}
}
-std::string GetAPIKeyForUrl(version_info::Channel channel) {
- // First look if we can get API key from command line flag.
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kAutofillAPIKey))
- return command_line.GetSwitchValueASCII(switches::kAutofillAPIKey);
-
- // Get the API key from Chrome baked keys.
- if (channel == version_info::Channel::STABLE)
- return google_apis::GetAPIKey();
- return google_apis::GetNonStableAPIKey();
-}
-
ValuePatternsMetric GetValuePattern(const base::string16& value) {
if (IsUPIVirtualPaymentAddress(value))
return ValuePatternsMetric::kUpiVpa;
@@ -234,47 +221,27 @@ void LogLanguageMetrics(const translate::LanguageState* language_state) {
bool IsAddressForm(FieldTypeGroup field_type_group) {
switch (field_type_group) {
- case NAME:
- case NAME_BILLING:
- case EMAIL:
- case COMPANY:
- case ADDRESS_HOME:
- case ADDRESS_BILLING:
- case PHONE_HOME:
- case PHONE_BILLING:
+ case FieldTypeGroup::kName:
+ case FieldTypeGroup::kNameBilling:
+ case FieldTypeGroup::kEmail:
+ case FieldTypeGroup::kCompany:
+ case FieldTypeGroup::kAddressHome:
+ case FieldTypeGroup::kAddressBilling:
+ case FieldTypeGroup::kPhoneHome:
+ case FieldTypeGroup::kPhoneBilling:
return true;
- case CREDIT_CARD:
- case TRANSACTION:
- case PASSWORD_FIELD:
- case USERNAME_FIELD:
- case NO_GROUP:
- case UNFILLABLE:
+ case FieldTypeGroup::kCreditCard:
+ case FieldTypeGroup::kTransaction:
+ case FieldTypeGroup::kPasswordField:
+ case FieldTypeGroup::kUsernameField:
+ case FieldTypeGroup::kNoGroup:
+ case FieldTypeGroup::kUnfillable:
return false;
}
NOTREACHED();
return false;
}
-void LogAutofillTypePredictionsAvailable(
- LogManager* log_manager,
- const std::vector<FormStructure*>& forms) {
- if (VLOG_IS_ON(1)) {
- VLOG(1) << "Parsed forms:";
- for (FormStructure* form : forms)
- VLOG(1) << *form;
- }
-
- if (!log_manager || !log_manager->IsLoggingActive())
- return;
-
- LogBuffer buffer;
- for (FormStructure* form : forms)
- buffer << *form;
-
- log_manager->Log() << LoggingScope::kParsing << LogMessage::kParsedForms
- << std::move(buffer);
-}
-
// Finds the first field in |form_structure| with |field.value|=|value|.
AutofillField* FindFirstFieldWithValue(const FormStructure& form_structure,
const base::string16& value) {
@@ -432,32 +399,40 @@ const char* SubmissionSourceToString(SubmissionSource source) {
// Returns how many fields with type |field_type| may be filled in a form at
// maximum.
-int TypeValueFormFillingLimit(ServerFieldType field_type) {
- return field_type == CREDIT_CARD_NUMBER ? kCreditCardTypeValueFormFillingLimit
- : kTypeValueFormFillingLimit;
+size_t TypeValueFormFillingLimit(ServerFieldType field_type) {
+ switch (field_type) {
+ case CREDIT_CARD_NUMBER:
+ return kCreditCardTypeValueFormFillingLimit;
+ case ADDRESS_HOME_STATE:
+ return kStateTypeValueFormFillingLimit;
+ default:
+ return kTypeValueFormFillingLimit;
+ }
}
} // namespace
AutofillManager::FillingContext::FillingContext(
const AutofillField& field,
- const AutofillProfile* optional_profile,
- const CreditCard* optional_credit_card,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
const base::string16* optional_cvc)
- : profile(optional_profile ? base::make_optional(*optional_profile)
- : base::nullopt),
- credit_card(optional_credit_card
- ? base::make_optional(std::make_pair(
- *optional_credit_card,
- optional_cvc ? *optional_cvc : base::string16()))
- : base::nullopt),
- filled_field_renderer_id(field.unique_renderer_id),
+ : filled_field_renderer_id(field.unique_renderer_id),
filled_field_signature(field.GetFieldSignature()),
filled_field_unique_name(field.unique_name()),
original_fill_time(AutofillTickClock::NowTicks()) {
- DCHECK(optional_profile || optional_credit_card);
- DCHECK(optional_credit_card || !optional_cvc);
- DCHECK(profile || credit_card);
+ DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card) ||
+ !optional_cvc);
+
+ if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+ profile_or_credit_card_with_cvc =
+ *absl::get<const AutofillProfile*>(profile_or_credit_card);
+ } else if (absl::holds_alternative<const CreditCard*>(
+ profile_or_credit_card)) {
+ profile_or_credit_card_with_cvc =
+ std::make_pair(*absl::get<const CreditCard*>(profile_or_credit_card),
+ optional_cvc ? *optional_cvc : base::string16());
+ }
}
AutofillManager::FillingContext::~FillingContext() = default;
@@ -474,6 +449,37 @@ AutofillManager::AutofillManager(
app_locale,
enable_download_manager) {}
+AutofillManager::AutofillManager(
+ AutofillDriver* driver,
+ AutofillClient* client,
+ PersonalDataManager* personal_data,
+ AutocompleteHistoryManager* autocomplete_history_manager,
+ const std::string app_locale,
+ AutofillDownloadManagerState enable_download_manager,
+ std::unique_ptr<CreditCardAccessManager> cc_access_manager)
+ : AutofillHandler(driver, client, enable_download_manager),
+ external_delegate_(
+ std::make_unique<AutofillExternalDelegate>(this, driver)),
+ app_locale_(app_locale),
+ personal_data_(personal_data),
+ field_filler_(app_locale, client->GetAddressNormalizer()),
+ autocomplete_history_manager_(
+ autocomplete_history_manager->GetWeakPtr()) {
+ address_form_event_logger_ = std::make_unique<AddressFormEventLogger>(
+ driver->IsInMainFrame(), form_interactions_ukm_logger(), client);
+ credit_card_form_event_logger_ = std::make_unique<CreditCardFormEventLogger>(
+ driver->IsInMainFrame(), form_interactions_ukm_logger(), personal_data_,
+ client);
+
+ credit_card_access_manager_ = cc_access_manager
+ ? std::move(cc_access_manager)
+ : std::make_unique<CreditCardAccessManager>(
+ driver, client, personal_data_,
+ credit_card_form_event_logger_.get());
+ CountryNames::SetLocaleString(app_locale_);
+ offer_manager_ = client->GetAutofillOfferManager();
+}
+
AutofillManager::~AutofillManager() {
if (has_parsed_forms_) {
base::UmaHistogramBoolean(
@@ -488,20 +494,13 @@ AutofillManager::~AutofillManager() {
}
}
-void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) {
- // TODO(jrg): consider passing delegate into the ctor. That won't
- // work if the delegate has a pointer to the AutofillManager, but
- // future directions may not need such a pointer.
- external_delegate_ = delegate;
-}
-
void AutofillManager::ShowAutofillSettings(bool show_credit_card_settings) {
- client_->ShowAutofillSettings(show_credit_card_settings);
+ client()->ShowAutofillSettings(show_credit_card_settings);
}
bool AutofillManager::ShouldShowScanCreditCard(const FormData& form,
const FormFieldData& field) {
- if (!client_->HasCreditCardScanFeature())
+ if (!client()->HasCreditCardScanFeature())
return false;
AutofillField* autofill_field = GetAutofillField(form, field);
@@ -530,26 +529,26 @@ PopupType AutofillManager::GetPopupType(const FormData& form,
return PopupType::kUnspecified;
switch (autofill_field->Type().group()) {
- case NO_GROUP:
- case PASSWORD_FIELD:
- case TRANSACTION:
- case USERNAME_FIELD:
- case UNFILLABLE:
+ case FieldTypeGroup::kNoGroup:
+ case FieldTypeGroup::kPasswordField:
+ case FieldTypeGroup::kTransaction:
+ case FieldTypeGroup::kUsernameField:
+ case FieldTypeGroup::kUnfillable:
return PopupType::kUnspecified;
- case CREDIT_CARD:
+ case FieldTypeGroup::kCreditCard:
return PopupType::kCreditCards;
- case ADDRESS_HOME:
- case ADDRESS_BILLING:
+ case FieldTypeGroup::kAddressHome:
+ case FieldTypeGroup::kAddressBilling:
return PopupType::kAddresses;
- case NAME:
- case NAME_BILLING:
- case EMAIL:
- case COMPANY:
- case PHONE_HOME:
- case PHONE_BILLING:
+ case FieldTypeGroup::kName:
+ case FieldTypeGroup::kNameBilling:
+ case FieldTypeGroup::kEmail:
+ case FieldTypeGroup::kCompany:
+ case FieldTypeGroup::kPhoneHome:
+ case FieldTypeGroup::kPhoneBilling:
return FormHasAddressField(form) ? PopupType::kAddresses
: PopupType::kPersonalInformation;
@@ -564,19 +563,20 @@ bool AutofillManager::ShouldShowCreditCardSigninPromo(
// Check whether we are dealing with a credit card field and whether it's
// appropriate to show the promo (e.g. the platform is supported).
AutofillField* autofill_field = GetAutofillField(form, field);
- if (!autofill_field || autofill_field->Type().group() != CREDIT_CARD ||
- !client_->ShouldShowSigninPromo())
+ if (!autofill_field ||
+ autofill_field->Type().group() != FieldTypeGroup::kCreditCard ||
+ !client()->ShouldShowSigninPromo())
return false;
if (IsFormNonSecure(form))
return false;
// The last step is checking if we are under the limit of impressions.
- int impression_count = client_->GetPrefs()->GetInteger(
+ int impression_count = client()->GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount);
if (impression_count < kCreditCardSigninPromoImpressionLimit) {
// The promo will be shown. Increment the impression count.
- client_->GetPrefs()->SetInteger(
+ client()->GetPrefs()->SetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount,
impression_count + 1);
return true;
@@ -590,7 +590,8 @@ bool AutofillManager::ShouldShowCardsFromAccountOption(
const FormFieldData& field) {
// Check whether we are dealing with a credit card field.
AutofillField* autofill_field = GetAutofillField(form, field);
- if (!autofill_field || autofill_field->Type().group() != CREDIT_CARD ||
+ if (!autofill_field ||
+ autofill_field->Type().group() != FieldTypeGroup::kCreditCard ||
// Exclude CVC and card type fields, because these will not have
// suggestions available after the user opts in.
autofill_field->Type().GetStorableType() ==
@@ -617,7 +618,7 @@ void AutofillManager::RefetchCardsAndUpdatePopup(
AutofillType type = autofill_field ? autofill_field->Type()
: AutofillType(CREDIT_CARD_NUMBER);
- DCHECK_EQ(CREDIT_CARD, type.group());
+ DCHECK_EQ(FieldTypeGroup::kCreditCard, type.group());
bool should_display_gpay_logo;
auto cards =
@@ -638,7 +639,7 @@ void AutofillManager::FetchVirtualCardCandidates() {
// ShouldShowVirtualCardOption() should fail.
DCHECK(!candidates.empty());
- client_->OfferVirtualCardOptions(
+ client()->OfferVirtualCardOptions(
candidates,
base::BindOnce(&AutofillManager::OnVirtualCardCandidateSelected,
weak_ptr_factory_.GetWeakPtr()));
@@ -653,8 +654,7 @@ void AutofillManager::OnVirtualCardCandidateSelected(
}
#endif
-bool AutofillManager::ShouldParseForms(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) {
+bool AutofillManager::ShouldParseForms(const std::vector<FormData>& forms) {
bool autofill_enabled = IsAutofillEnabled();
sync_state_ = personal_data_ ? personal_data_->GetSyncSigninState()
: AutofillSyncSigninState::kNumSyncStates;
@@ -674,16 +674,16 @@ bool AutofillManager::ShouldParseForms(const std::vector<FormData>& forms,
void AutofillManager::OnFormSubmittedImpl(const FormData& form,
bool known_success,
SubmissionSource source) {
- if (log_manager_) {
- log_manager_->Log() << LoggingScope::kSubmission
- << LogMessage::kFormSubmissionDetected << Br{}
- << "known_success: " << known_success << Br{}
- << "source: " << SubmissionSourceToString(source)
- << Br{} << form;
+ if (log_manager()) {
+ log_manager()->Log() << LoggingScope::kSubmission
+ << LogMessage::kFormSubmissionDetected << Br{}
+ << "known_success: " << known_success << Br{}
+ << "source: " << SubmissionSourceToString(source)
+ << Br{} << form;
}
// Always upload page language metrics.
- LogLanguageMetrics(client_->GetLanguageState());
+ LogLanguageMetrics(client()->GetLanguageState());
// Always let the value patterns metric upload data.
LogValuePatternsMetric(form);
@@ -692,7 +692,7 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form,
std::unique_ptr<FormStructure> submitted_form = ValidateSubmittedForm(form);
if (!submitted_form) {
autocomplete_history_manager_->OnWillSubmitForm(
- form, client_->IsAutocompleteEnabled());
+ form, client()->IsAutocompleteEnabled());
return;
}
@@ -706,7 +706,11 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form,
}
}
autocomplete_history_manager_->OnWillSubmitForm(
- form_for_autocomplete, client_->IsAutocompleteEnabled());
+ form_for_autocomplete, client()->IsAutocompleteEnabled());
+
+ // TODO(https://crbug.com/1167475): Add Test for this metric.
+ base::UmaHistogramEnumeration("Autofill.FormSubmission.PerProfileType",
+ client()->GetProfileType());
if (IsAutofillProfileEnabled()) {
address_form_event_logger_->OnWillSubmitForm(sync_state_, *submitted_form);
@@ -745,9 +749,9 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form,
// Update Personal Data with the form's submitted data.
// Also triggers offering local/upload credit card save, if applicable.
- client_->GetFormDataImporter()->ImportFormData(*submitted_form,
- IsAutofillProfileEnabled(),
- IsAutofillCreditCardEnabled());
+ client()->GetFormDataImporter()->ImportFormData(
+ *submitted_form, IsAutofillProfileEnabled(),
+ IsAutofillCreditCardEnabled());
}
bool AutofillManager::MaybeStartVoteUploadProcess(
@@ -790,13 +794,16 @@ bool AutofillManager::MaybeStartVoteUploadProcess(
copied_credit_cards.push_back(*card);
// Annotate the form with the source language of the page.
- base::Optional<std::string> page_language = GetPageLanguage();
- if (page_language)
- form_structure->set_page_language(page_language.value());
+ form_structure->set_current_page_language(GetCurrentPageLanguage());
// Attach the Randomized Encoder.
form_structure->set_randomized_encoder(
- RandomizedEncoder::Create(client_->GetPrefs()));
+ RandomizedEncoder::Create(client()->GetPrefs()));
+
+ // Determine |ADDRESS_HOME_STATE| as a possible types for the fields in the
+ // |form_structure| with the help of |AlternativeStateNameMap|.
+ // |AlternativeStateNameMap| can only be accessed on the main UI thread.
+ PreProcessStateMatchingTypes(copied_profiles, form_structure.get());
// Note that ownership of |form_structure| is passed to the second task,
// using |base::Owned|. We MUST temporarily hang on to the raw form pointer
@@ -878,8 +885,8 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
uint32_t profile_form_bitmask = 0;
if (!user_did_type_ || autofill_field->is_autofilled) {
- form_interactions_ukm_logger_->LogTextFieldDidChange(*form_structure,
- *autofill_field);
+ form_interactions_ukm_logger()->LogTextFieldDidChange(*form_structure,
+ *autofill_field);
profile_form_bitmask = data_util::DetermineGroups(*form_structure);
}
@@ -893,7 +900,7 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
user_did_type_ = true;
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::USER_DID_TYPE, autofill_field->Type().group(),
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
}
if (autofill_field->is_autofilled) {
@@ -902,7 +909,7 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD,
autofill_field->Type().group(),
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
auto* logger = GetEventFormLogger(autofill_field->Type().group());
if (logger)
@@ -913,7 +920,7 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE,
autofill_field->Type().group(),
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
}
}
@@ -921,7 +928,7 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
}
bool AutofillManager::IsFormNonSecure(const FormData& form) const {
- return IsFormOrClientNonSecure(client_, form);
+ return IsFormOrClientNonSecure(client(), form);
}
void AutofillManager::OnQueryFormFieldAutofillImpl(
@@ -930,6 +937,10 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
const FormFieldData& field,
const gfx::RectF& transformed_box,
bool autoselect_first_suggestion) {
+ if (base::FeatureList::IsEnabled(features::kAutofillDisableFilling)) {
+ return;
+ }
+
SetDataList(field.datalist_values, field.datalist_labels);
external_delegate_->OnQuery(query_id, form, field, transformed_box);
@@ -991,9 +1002,9 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
// Suggestions come back asynchronously, so the Autocomplete manager will
// handle sending the results back to the renderer.
autocomplete_history_manager_->OnGetAutocompleteSuggestions(
- query_id, client_->IsAutocompleteEnabled(), autoselect_first_suggestion,
- field.name, field.value, field.form_control_type,
- weak_ptr_factory_.GetWeakPtr());
+ query_id, client()->IsAutocompleteEnabled(),
+ autoselect_first_suggestion, field.name, field.value,
+ field.form_control_type, weak_ptr_factory_.GetWeakPtr());
return;
}
@@ -1064,9 +1075,8 @@ void AutofillManager::FillOrPreviewCreditCardForm(
credit_card_, *form_structure, *autofill_field, sync_state_);
}
- FillOrPreviewDataModelForm(action, query_id, form, field, /*profile=*/nullptr,
- &credit_card_, /*cvc=*/nullptr, form_structure,
- autofill_field);
+ FillOrPreviewDataModelForm(action, query_id, form, field, &credit_card_,
+ /*cvc=*/nullptr, form_structure, autofill_field);
}
void AutofillManager::FillOrPreviewProfileForm(
@@ -1085,7 +1095,6 @@ void AutofillManager::FillOrPreviewProfileForm(
}
FillOrPreviewDataModelForm(action, query_id, form, field, &profile,
- /*credit_card=*/nullptr,
/*cvc=*/nullptr, form_structure, autofill_field);
}
@@ -1128,8 +1137,8 @@ void AutofillManager::FillCreditCardForm(int query_id,
return;
FillOrPreviewDataModelForm(AutofillDriver::FORM_DATA_ACTION_FILL, query_id,
- form, field, /*profile=*/nullptr, &credit_card,
- &cvc, form_structure, autofill_field);
+ form, field, &credit_card, &cvc, form_structure,
+ autofill_field);
}
void AutofillManager::FillProfileForm(const autofill::AutofillProfile& profile,
@@ -1148,7 +1157,7 @@ void AutofillManager::OnFocusNoLongerOnForm(bool had_interacted_form) {
ProcessPendingFormForUpload();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// There is no way of determining whether ChromeVox is in use, so assume it's
// being used.
external_delegate_->OnAutofillAvailabilityEvent(
@@ -1168,7 +1177,7 @@ void AutofillManager::OnFocusOnFormFieldImpl(const FormData& form,
// are suggestions to present. Ignore if a screen reader is not present. If
// the platform is ChromeOS, then assume ChromeVox is in use as there is no
// way of determining whether it's being used from this point in the code.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
if (!external_delegate_->HasActiveScreenReader())
return;
#endif
@@ -1204,12 +1213,12 @@ void AutofillManager::OnDidFillAutofillFormData(const FormData& form,
UpdatePendingForm(form);
- std::set<FormType> form_types;
// Find the FormStructure that corresponds to |form|. Use default form type if
// form is not present in our cache, which will happen rarely.
FormStructure* form_structure =
FindCachedFormByRendererId(form.unique_renderer_id);
+ DenseSet<FormType> form_types;
if (form_structure) {
form_types = form_structure->GetFormTypes();
}
@@ -1219,12 +1228,12 @@ void AutofillManager::OnDidFillAutofillFormData(const FormData& form,
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::USER_DID_AUTOFILL, form_types,
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
if (!user_did_autofill_) {
user_did_autofill_ = true;
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::USER_DID_AUTOFILL_ONCE, form_types,
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
}
UpdateInitialInteractionTimestamp(timestamp);
@@ -1251,13 +1260,13 @@ void AutofillManager::DidShowSuggestions(bool has_autofill_suggestions,
uint32_t profile_form_bitmask = data_util::DetermineGroups(*form_structure);
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::SUGGESTIONS_SHOWN, autofill_field->Type().group(),
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
if (!did_show_suggestions_) {
did_show_suggestions_ = true;
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, autofill_field->Type().group(),
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
}
auto* logger = GetEventFormLogger(autofill_field->Type().group());
@@ -1267,7 +1276,7 @@ void AutofillManager::DidShowSuggestions(bool has_autofill_suggestions,
sync_state_, driver()->IsIncognito());
}
- if (autofill_field->Type().group() == CREDIT_CARD &&
+ if (autofill_field->Type().group() == FieldTypeGroup::kCreditCard &&
base::FeatureList::IsEnabled(
features::kAutofillCreditCardAuthentication)) {
credit_card_access_manager_->PrepareToFetchCreditCard();
@@ -1279,7 +1288,7 @@ void AutofillManager::OnHidePopup() {
return;
autocomplete_history_manager_->CancelPendingQueries(this);
- client_->HideAutofillPopup(PopupHidingReason::kRendererEvent);
+ client()->HideAutofillPopup(PopupHidingReason::kRendererEvent);
}
bool AutofillManager::GetDeletionConfirmationText(const base::string16& value,
@@ -1399,6 +1408,7 @@ void AutofillManager::SetDataList(const std::vector<base::string16>& values,
external_delegate_->SetCurrentDataListValues(values, labels);
}
+
void AutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
// Look for a cached version of the form. It will be a null pointer if none is
// found, which is fine.
@@ -1413,53 +1423,10 @@ void AutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
TriggerRefill(form);
}
-void AutofillManager::OnLoadedServerPredictions(
- std::string response,
- const std::vector<FormSignature>& queried_form_signatures) {
- // Get the current valid FormStructures represented by
- // |queried_form_signatures|.
- std::vector<FormStructure*> queried_forms;
- queried_forms.reserve(queried_form_signatures.size());
- for (const auto& form_signature : queried_form_signatures) {
- FindCachedFormsBySignature(form_signature, &queried_forms);
- }
-
- // Each form signature in |queried_form_signatures| is supposed to be unique,
- // and therefore appear only once. This ensures that
- // FindCachedFormsBySignature() produces an output without duplicates in the
- // forms.
- // TODO(crbug/1064709): |queried_forms| could be a set data structure; their
- // order should be irrelevant.
- DCHECK_EQ(queried_forms.size(),
- std::set<FormStructure*>(queried_forms.begin(), queried_forms.end())
- .size());
-
- // If there are no current forms corresponding to the queried signatures, drop
- // the query response.
- if (queried_forms.empty())
- return;
-
- // Parse and store the server predictions.
- FormStructure::ParseApiQueryResponse(std::move(response), queried_forms,
- queried_form_signatures,
- form_interactions_ukm_logger_.get());
-
- // Will log quality metrics for each FormStructure based on the presence of
- // autocomplete attributes, if available.
- for (FormStructure* cur_form : queried_forms) {
- cur_form->LogQualityMetricsBasedOnAutocomplete(
- form_interactions_ukm_logger_.get());
- }
-
- // Send field type predictions to the renderer so that it can possibly
- // annotate forms with the predicted types or add console warnings.
- driver()->SendAutofillTypePredictionsToRenderer(queried_forms);
-
- LogAutofillTypePredictionsAvailable(log_manager_, queried_forms);
-
- // Forward form structures to the password generation manager to detect
- // account creation forms.
- driver()->PropagateAutofillPredictions(queried_forms);
+void AutofillManager::PropagateAutofillPredictions(
+ content::RenderFrameHost* rfh,
+ const std::vector<FormStructure*>& forms) {
+ client()->PropagateAutofillPredictions(rfh, forms);
}
void AutofillManager::OnCreditCardFetched(bool did_succeed,
@@ -1487,8 +1454,7 @@ void AutofillManager::OnCreditCardFetched(bool did_succeed,
DCHECK(credit_card);
FillCreditCardForm(credit_card_query_id_, credit_card_form_,
credit_card_field_, *credit_card, cvc);
- if (base::FeatureList::IsEnabled(features::kAutofillCacheServerCardInfo) &&
- credit_card->record_type() == CreditCard::FULL_SERVER_CARD) {
+ if (credit_card->record_type() == CreditCard::FULL_SERVER_CARD) {
credit_card_access_manager_->CacheUnmaskedCardInfo(*credit_card, cvc);
}
}
@@ -1502,18 +1468,11 @@ bool AutofillManager::IsAutofillEnabled() const {
}
bool AutofillManager::IsAutofillProfileEnabled() const {
- return ::autofill::prefs::IsAutofillProfileEnabled(client_->GetPrefs());
+ return ::autofill::prefs::IsAutofillProfileEnabled(client()->GetPrefs());
}
bool AutofillManager::IsAutofillCreditCardEnabled() const {
- return ::autofill::prefs::IsAutofillCreditCardEnabled(client_->GetPrefs());
-}
-
-// static
-bool AutofillManager::IsRichQueryEnabled(version_info::Channel channel) {
- return base::FeatureList::IsEnabled(features::kAutofillRichMetadataQueries) &&
- channel != version_info::Channel::STABLE &&
- channel != version_info::Channel::BETA;
+ return ::autofill::prefs::IsAutofillCreditCardEnabled(client()->GetPrefs());
}
const FormData& AutofillManager::last_query_form() const {
@@ -1547,8 +1506,8 @@ void AutofillManager::UploadFormDataAsyncCallback(
submitted_form->ShouldBeQueried()) {
submitted_form->LogQualityMetrics(
submitted_form->form_parsed_timestamp(), interaction_time,
- submission_time, form_interactions_ukm_logger_.get(),
- did_show_suggestions_, observed_submission);
+ submission_time, form_interactions_ukm_logger(), did_show_suggestions_,
+ observed_submission);
}
if (submitted_form->ShouldBeUploaded())
UploadFormData(*submitted_form, observed_submission);
@@ -1556,7 +1515,7 @@ void AutofillManager::UploadFormDataAsyncCallback(
void AutofillManager::UploadFormData(const FormStructure& submitted_form,
bool observed_submission) {
- if (!download_manager_)
+ if (!download_manager())
return;
// Check if the form is among the forms that were recently auto-filled.
@@ -1577,10 +1536,10 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form,
non_empty_types.insert(CREDIT_CARD_VERIFICATION_CODE);
}
- download_manager_->StartUploadRequest(
+ download_manager()->StartUploadRequest(
submitted_form, was_autofilled, non_empty_types,
/*login_form_signature=*/std::string(), observed_submission,
- client_->GetPrefs());
+ client()->GetPrefs());
}
void AutofillManager::Reset() {
@@ -1589,16 +1548,13 @@ void AutofillManager::Reset() {
ProcessPendingFormForUpload();
DCHECK(!pending_form_data_);
AutofillHandler::Reset();
- form_interactions_ukm_logger_.reset(
- new AutofillMetrics::FormInteractionsUkmLogger(
- client_->GetUkmRecorder(), client_->GetUkmSourceId()));
- address_form_event_logger_.reset(new AddressFormEventLogger(
- driver()->IsInMainFrame(), form_interactions_ukm_logger_.get(), client_));
- credit_card_form_event_logger_.reset(new CreditCardFormEventLogger(
- driver()->IsInMainFrame(), form_interactions_ukm_logger_.get(),
- personal_data_, client_));
- credit_card_access_manager_.reset(new CreditCardAccessManager(
- driver(), client_, personal_data_, credit_card_form_event_logger_.get()));
+ address_form_event_logger_ = std::make_unique<AddressFormEventLogger>(
+ driver()->IsInMainFrame(), form_interactions_ukm_logger(), client());
+ credit_card_form_event_logger_ = std::make_unique<CreditCardFormEventLogger>(
+ driver()->IsInMainFrame(), form_interactions_ukm_logger(), personal_data_,
+ client());
+ credit_card_access_manager_ = std::make_unique<CreditCardAccessManager>(
+ driver(), client(), personal_data_, credit_card_form_event_logger_.get());
has_logged_autofill_enabled_ = false;
has_logged_address_suggestions_count_ = false;
@@ -1619,52 +1575,6 @@ void AutofillManager::Reset() {
filling_context_by_unique_name_.clear();
}
-AutofillManager::AutofillManager(
- AutofillDriver* driver,
- AutofillClient* client,
- PersonalDataManager* personal_data,
- AutocompleteHistoryManager* autocomplete_history_manager,
- const std::string app_locale,
- AutofillDownloadManagerState enable_download_manager,
- std::unique_ptr<CreditCardAccessManager> cc_access_manager)
- : AutofillHandler(driver, client->GetLogManager()),
- client_(client),
- log_manager_(client_->GetLogManager()),
- app_locale_(app_locale),
- personal_data_(personal_data),
- field_filler_(app_locale, client->GetAddressNormalizer()),
- autocomplete_history_manager_(autocomplete_history_manager->GetWeakPtr()),
- form_interactions_ukm_logger_(
- std::make_unique<AutofillMetrics::FormInteractionsUkmLogger>(
- client->GetUkmRecorder(),
- client->GetUkmSourceId())),
- address_form_event_logger_(std::make_unique<AddressFormEventLogger>(
- driver->IsInMainFrame(),
- form_interactions_ukm_logger_.get(),
- client_)),
- credit_card_form_event_logger_(
- std::make_unique<CreditCardFormEventLogger>(
- driver->IsInMainFrame(),
- form_interactions_ukm_logger_.get(),
- personal_data_,
- client_)),
- is_rich_query_enabled_(IsRichQueryEnabled(client->GetChannel())) {
- DCHECK(driver);
- DCHECK(client_);
- credit_card_access_manager_ = cc_access_manager
- ? std::move(cc_access_manager)
- : std::make_unique<CreditCardAccessManager>(
- driver, client_, personal_data_,
- credit_card_form_event_logger_.get());
- if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {
- version_info::Channel channel = client_->GetChannel();
- download_manager_.reset(new AutofillDownloadManager(
- driver, this, GetAPIKeyForUrl(channel), client_->GetLogManager()));
- }
- CountryNames::SetLocaleString(app_locale_);
- offer_manager_ = client_->GetAutofillOfferManager();
-}
-
bool AutofillManager::RefreshDataModels() {
if (!IsAutofillEnabled())
return false;
@@ -1717,25 +1627,19 @@ void AutofillManager::FillOrPreviewDataModelForm(
int query_id,
const FormData& form,
const FormFieldData& field,
- const AutofillProfile* optional_profile,
- const CreditCard* optional_credit_card,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
const base::string16* optional_cvc,
FormStructure* form_structure,
AutofillField* autofill_field,
bool is_refill) {
- DCHECK(optional_profile || optional_credit_card);
- DCHECK(optional_credit_card || !optional_cvc);
+ bool is_credit_card =
+ absl::holds_alternative<const CreditCard*>(profile_or_credit_card);
+
+ DCHECK(is_credit_card || !optional_cvc);
DCHECK(form_structure);
DCHECK(autofill_field);
- const AutofillDataModel& data_model = [&]() -> const AutofillDataModel& {
- if (optional_profile)
- return *optional_profile;
- else
- return *optional_credit_card;
- }();
- bool is_credit_card = !!optional_credit_card;
-
LogBuffer buffer;
buffer << "is credit card section: " << is_credit_card << Br{};
buffer << "is refill: " << is_refill << Br{};
@@ -1745,12 +1649,17 @@ void AutofillManager::FillOrPreviewDataModelForm(
form_structure->RationalizePhoneNumbersInSection(autofill_field->section);
FormData result = form;
- DCHECK_EQ(form_structure->field_count(), form.fields.size());
+
+ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime, which
+ // may happen with refills.
+ if (form_structure->field_count() != form.fields.size())
+ return;
if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) {
- SetFillingContext(*form_structure, std::make_unique<FillingContext>(
- *autofill_field, optional_profile,
- optional_credit_card, optional_cvc));
+ SetFillingContext(
+ *form_structure,
+ std::make_unique<FillingContext>(*autofill_field,
+ profile_or_credit_card, optional_cvc));
}
// Only record the types that are filled for an eventual refill if all the
@@ -1765,7 +1674,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
// Count the number of times the value of a specific type was filled into the
// form.
- std::map<ServerFieldType, int> type_filling_count;
+ base::flat_map<ServerFieldType, size_t> type_filling_count;
+ type_filling_count.reserve(form_structure->field_count());
for (size_t i = 0; i < form_structure->field_count(); ++i) {
std::string field_number = base::StringPrintf("Field %zu", i);
@@ -1784,8 +1694,10 @@ void AutofillManager::FillOrPreviewDataModelForm(
continue;
}
- // The field order should be the same in |form_structure| and |result|.
- DCHECK(form_structure->field(i)->SameFieldAs(result.fields[i]));
+ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime,
+ // which may happen with refills.
+ if (!form_structure->field(i)->SameFieldAs(result.fields[i]))
+ continue;
AutofillField* cached_field = form_structure->field(i);
FieldTypeGroup field_group_type = cached_field->Type().group();
@@ -1794,8 +1706,9 @@ void AutofillManager::FillOrPreviewDataModelForm(
// the sake of filling the synthetic fields.
if (!cached_field->IsVisible()) {
bool skip = result.fields[i].form_control_type != "select-one";
- form_interactions_ukm_logger_->LogHiddenRepresentationalFieldSkipDecision(
- *form_structure, *cached_field, skip);
+ form_interactions_ukm_logger()
+ ->LogHiddenRepresentationalFieldSkipDecision(*form_structure,
+ *cached_field, skip);
if (skip) {
buffer << Tr{} << field_number << "Skipped: invisible field";
continue;
@@ -1806,9 +1719,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
// is empty and its initial value (= cached value) was empty as well. A
// similar check is done in ForEachMatchingFormFieldCommon(), which
// frequently has false negatives.
- if (base::FeatureList::IsEnabled(
- features::kAutofillSkipFillingFieldsWithChangedValues) &&
- ((form.fields[i].properties_mask & kUserTyped)) &&
+ if ((form.fields[i].properties_mask & kUserTyped) &&
(!form.fields[i].value.empty() ||
!form_structure->field(i)->value.empty()) &&
!cached_field->SameFieldAs(field)) {
@@ -1827,7 +1738,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
continue;
}
- if (field_group_type == NO_GROUP) {
+ if (field_group_type == FieldTypeGroup::kNoGroup) {
buffer << Tr{} << field_number
<< "Skipped: field type has no fillable group";
continue;
@@ -1848,8 +1759,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
// Don't fill expired cards expiration date.
if (data_util::IsCreditCardExpirationType(field_type) &&
- (!optional_credit_card ||
- optional_credit_card->IsExpired(AutofillClock::Now()))) {
+ (is_credit_card && absl::get<const CreditCard*>(profile_or_credit_card)
+ ->IsExpired(AutofillClock::Now()))) {
buffer << Tr{} << field_number
<< "Skipped: don't fill expiration date of expired cards";
continue;
@@ -1857,7 +1768,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
// A field with a specific type is only allowed to be filled a limited
// number of times given by |TypeValueFormFillingLimit(field_type)|.
- if (type_filling_count[field_type] >=
+ if (++type_filling_count[field_type] >
TypeValueFormFillingLimit(field_type)) {
buffer << Tr{} << field_number
<< "Skipped: field-type filling-limit reached";
@@ -1882,9 +1793,9 @@ void AutofillManager::FillOrPreviewDataModelForm(
const base::string16 kEmptyCvc{};
std::string failure_to_fill; // Reason for failing to fill.
- // Fill the non-empty value from |data_model| into the result vector, which
- // will be sent to the renderer.
- FillFieldWithValue(cached_field, data_model, &result.fields[i],
+ // Fill the non-empty value from |profile_or_credit_card| into the result
+ // vector, which will be sent to the renderer.
+ FillFieldWithValue(cached_field, profile_or_credit_card, &result.fields[i],
should_notify, optional_cvc ? *optional_cvc : kEmptyCvc,
data_util::DetermineGroups(*form_structure),
&failure_to_fill);
@@ -1892,10 +1803,6 @@ void AutofillManager::FillOrPreviewDataModelForm(
bool has_value_after = !result.fields[i].value.empty();
bool is_autofilled_after = result.fields[i].is_autofilled;
- // If the field was actually filled, increment the filling counter.
- if (is_autofilled_after)
- type_filling_count[field_type]++;
-
buffer << Tr{} << field_number
<< base::StringPrintf(
"Fillable - has value: %d->%d; autofilled: %d->%d. %s",
@@ -1913,14 +1820,14 @@ void AutofillManager::FillOrPreviewDataModelForm(
if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember)
autofilled_form_signatures_.pop_back();
- // Note that this may invalidate |data_model|.
+ // Note that this may invalidate |profile_or_credit_card|.
if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill)
- personal_data_->RecordUseOf(data_model);
+ personal_data_->RecordUseOf(profile_or_credit_card);
- if (log_manager_) {
- log_manager_->Log() << LoggingScope::kFilling
- << LogMessage::kSendFillingData << Br{}
- << std::move(buffer);
+ if (log_manager()) {
+ log_manager()->Log() << LoggingScope::kFilling
+ << LogMessage::kSendFillingData << Br{}
+ << std::move(buffer);
}
driver()->SendFormDataToRenderer(query_id, action, result);
}
@@ -1965,8 +1872,9 @@ AutofillField* AutofillManager::GetAutofillField(const FormData& form,
bool AutofillManager::FormHasAddressField(const FormData& form) {
for (const FormFieldData& field : form.fields) {
const AutofillField* autofill_field = GetAutofillField(form, field);
- if (autofill_field && (autofill_field->Type().group() == ADDRESS_HOME ||
- autofill_field->Type().group() == ADDRESS_BILLING)) {
+ if (autofill_field &&
+ (autofill_field->Type().group() == FieldTypeGroup::kAddressHome ||
+ autofill_field->Type().group() == FieldTypeGroup::kAddressBilling)) {
return true;
}
}
@@ -2014,11 +1922,11 @@ std::vector<Suggestion> AutofillManager::GetCreditCardSuggestions(
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
type, SanitizeCreditCardFieldValue(field.value),
- client_->AreServerCardsSupported());
+ client()->AreServerCardsSupported());
if (base::FeatureList::IsEnabled(
features::kAutofillEnableOffersInDownstream) &&
offer_manager_) {
- offer_manager_->UpdateSuggestionsWithOffers(client_->GetLastCommittedURL(),
+ offer_manager_->UpdateSuggestionsWithOffers(client()->GetLastCommittedURL(),
suggestions);
}
*should_display_gpay_logo =
@@ -2033,117 +1941,82 @@ std::vector<Suggestion> AutofillManager::GetCreditCardSuggestions(
return suggestions;
}
-void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms,
- const base::TimeTicks timestamp) {
- DCHECK(!forms.empty());
+void AutofillManager::OnBeforeProcessParsedForms() {
has_parsed_forms_ = true;
// Record the current sync state to be used for metrics on this page.
sync_state_ = personal_data_->GetSyncSigninState();
// Setup the url for metrics that we will collect for this form.
- form_interactions_ukm_logger_->OnFormsParsed(client_->GetUkmSourceId());
-
- driver()->HandleParsedForms(forms);
-
- std::vector<FormStructure*> non_queryable_forms;
- std::vector<FormStructure*> queryable_forms;
- std::set<FormType> form_types;
- for (const FormData* form : forms) {
- FormStructure* form_structure =
- FindCachedFormByRendererId(form->unique_renderer_id);
- if (!form_structure) {
- NOTREACHED();
- continue;
- }
+ form_interactions_ukm_logger()->OnFormsParsed(client()->GetUkmSourceId());
+}
- if (data_util::ContainsPhone(data_util::DetermineGroups(*form_structure))) {
- has_observed_phone_number_field_ = true;
- }
+void AutofillManager::OnFormProcessed(const FormData& form,
+ const FormStructure& form_structure) {
+ if (data_util::ContainsPhone(data_util::DetermineGroups(form_structure))) {
+ has_observed_phone_number_field_ = true;
+ }
- // TODO(crbug.com/869482): avoid logging developer engagement multiple
- // times for a given form if it or other forms on the page are dynamic.
- LogDeveloperEngagementUkm(client_->GetUkmRecorder(),
- client_->GetUkmSourceId(), form_structure);
- std::set<FormType> current_form_types = form_structure->GetFormTypes();
- form_types.insert(current_form_types.begin(), current_form_types.end());
-
- // Configure the query encoding for this form and add it to the appropriate
- // collection of forms: queryable vs non-queryable.
- form_structure->set_is_rich_query_enabled(is_rich_query_enabled_);
- if (form_structure->ShouldBeQueried())
- queryable_forms.push_back(form_structure);
- else
- non_queryable_forms.push_back(form_structure);
-
- // Log the type of form that was parsed.
- bool card_form = false;
- bool address_form = false;
- for (const auto& field : *form_structure) {
- if (field->Type().group() == CREDIT_CARD) {
- card_form = true;
- } else if (IsAddressForm(field->Type().group())) {
- address_form = true;
- } else if (field->Type().html_type() == HTML_TYPE_ONE_TIME_CODE) {
- has_observed_one_time_code_field_ = true;
- }
- }
- if (card_form) {
- credit_card_form_event_logger_->OnDidParseForm(*form_structure);
- }
- if (address_form) {
- address_form_event_logger_->OnDidParseForm(*form_structure);
- }
+ // TODO(crbug.com/869482): avoid logging developer engagement multiple
+ // times for a given form if it or other forms on the page are dynamic.
+ LogDeveloperEngagementUkm(client()->GetUkmRecorder(),
+ client()->GetUkmSourceId(), form_structure);
- // If a form with the same name was previously filled, and there has not
- // been a refill attempt on that form yet, start the process of triggering a
- // refill.
- if (ShouldTriggerRefill(*form_structure)) {
- FillingContext* filling_context = GetFillingContext(*form_structure);
- DCHECK(filling_context != nullptr);
-
- // If a timer for the refill was already running, it means the form
- // changed again. Stop the timer and start it again.
- if (filling_context->on_refill_timer.IsRunning())
- filling_context->on_refill_timer.AbandonAndStop();
-
- // Start a new timer to trigger refill.
- filling_context->on_refill_timer.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kWaitTimeForDynamicFormsMs),
- base::BindRepeating(&AutofillManager::TriggerRefill,
- weak_ptr_factory_.GetWeakPtr(), *form));
+ // Log the type of form that was parsed.
+ bool card_form = false;
+ bool address_form = false;
+ for (const auto& field : form_structure) {
+ if (field->Type().group() == FieldTypeGroup::kCreditCard) {
+ card_form = true;
+ } else if (IsAddressForm(field->Type().group())) {
+ address_form = true;
+ } else if (field->Type().html_type() == HTML_TYPE_ONE_TIME_CODE) {
+ has_observed_one_time_code_field_ = true;
}
}
- if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
- AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::FORMS_LOADED, form_types,
- client_->GetSecurityLevelForUmaHistograms(),
- /*profile_form_bitmask=*/0);
-
-#if defined(OS_IOS)
- // Log this from same location as AutofillMetrics::FORMS_LOADED to ensure
- // that KeyboardAccessoryButtonsIOS and UserHappiness UMA metrics will be
- // directly comparable.
- KeyboardAccessoryMetricsLogger::OnFormsLoaded();
-#endif
+ if (card_form) {
+ credit_card_form_event_logger_->OnDidParseForm(form_structure);
+ }
+ if (address_form) {
+ address_form_event_logger_->OnDidParseForm(form_structure);
}
- // Send the current type predictions to the renderer. For non-queryable forms
- // this is all the information about them that will ever be available. The
- // queryable forms will be updated once the field type query is complete.
- driver()->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
- driver()->SendAutofillTypePredictionsToRenderer(queryable_forms);
- LogAutofillTypePredictionsAvailable(log_manager_, non_queryable_forms);
- LogAutofillTypePredictionsAvailable(log_manager_, queryable_forms);
+ // If a form with the same name was previously filled, and there has not
+ // been a refill attempt on that form yet, start the process of triggering a
+ // refill.
+ if (ShouldTriggerRefill(form_structure)) {
+ FillingContext* filling_context = GetFillingContext(form_structure);
+ DCHECK(filling_context != nullptr);
- // Query the server if at least one of the forms was parsed.
- if (!queryable_forms.empty() && download_manager_) {
- download_manager_->StartQueryRequest(queryable_forms);
+ // If a timer for the refill was already running, it means the form
+ // changed again. Stop the timer and start it again.
+ if (filling_context->on_refill_timer.IsRunning())
+ filling_context->on_refill_timer.AbandonAndStop();
+
+ // Start a new timer to trigger refill.
+ filling_context->on_refill_timer.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kWaitTimeForDynamicFormsMs),
+ base::BindRepeating(&AutofillManager::TriggerRefill,
+ weak_ptr_factory_.GetWeakPtr(), form));
}
}
+void AutofillManager::OnAfterProcessParsedForms(
+ const DenseSet<FormType>& form_types) {
+ AutofillMetrics::LogUserHappinessMetric(
+ AutofillMetrics::FORMS_LOADED, form_types,
+ client()->GetSecurityLevelForUmaHistograms(),
+ /*profile_form_bitmask=*/0);
+#if defined(OS_IOS)
+ // Log this from same location as AutofillMetrics::FORMS_LOADED to ensure
+ // that KeyboardAccessoryButtonsIOS and UserHappiness UMA metrics will be
+ // directly comparable.
+ KeyboardAccessoryMetricsLogger::OnFormsLoaded();
+#endif
+}
+
int AutofillManager::BackendIDToInt(const std::string& backend_id) const {
if (!base::IsValidGUID(backend_id))
return 0;
@@ -2250,6 +2123,9 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
if (IsUPIVirtualPaymentAddress(value))
matching_types.insert(UPI_VPA);
+ if (field->state_is_a_matching_type())
+ matching_types.insert(ADDRESS_HOME_STATE);
+
if (matching_types.empty()) {
matching_types.insert(UNKNOWN_TYPE);
ServerFieldTypeValidityStateMap matching_types_validities;
@@ -2298,10 +2174,10 @@ void AutofillManager::DisambiguateUploadTypes(FormStructure* form) {
bool undisambiuatable_types = false;
for (const auto& type : upload_types) {
switch (AutofillType(type).group()) {
- case CREDIT_CARD:
+ case FieldTypeGroup::kCreditCard:
++credit_card_type_count;
break;
- case NAME:
+ case FieldTypeGroup::kName:
++name_type_count;
break;
// If there is any other type left, do not disambiguate.
@@ -2399,7 +2275,8 @@ void AutofillManager::DisambiguateNameUploadTypes(
AutofillField* prev_field = form->field(index);
if (!IsNameType(*prev_field)) {
has_found_previous_type = true;
- is_previous_credit_card = prev_field->Type().group() == CREDIT_CARD;
+ is_previous_credit_card =
+ prev_field->Type().group() == FieldTypeGroup::kCreditCard;
}
}
@@ -2411,7 +2288,8 @@ void AutofillManager::DisambiguateNameUploadTypes(
AutofillField* next_field = form->field(index);
if (!IsNameType(*next_field)) {
has_found_next_type = true;
- is_next_credit_card = next_field->Type().group() == CREDIT_CARD;
+ is_next_credit_card =
+ next_field->Type().group() == FieldTypeGroup::kCreditCard;
}
}
@@ -2435,15 +2313,17 @@ void AutofillManager::DisambiguateNameUploadTypes(
}
}
-void AutofillManager::FillFieldWithValue(AutofillField* autofill_field,
- const AutofillDataModel& data_model,
- FormFieldData* field_data,
- bool should_notify,
- const base::string16& cvc,
- uint32_t profile_form_bitmask,
- std::string* failure_to_fill) {
- if (field_filler_.FillFormField(*autofill_field, data_model, field_data, cvc,
- failure_to_fill)) {
+void AutofillManager::FillFieldWithValue(
+ AutofillField* autofill_field,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
+ FormFieldData* field_data,
+ bool should_notify,
+ const base::string16& cvc,
+ uint32_t profile_form_bitmask,
+ std::string* failure_to_fill) {
+ if (field_filler_.FillFormField(*autofill_field, profile_or_credit_card,
+ field_data, cvc, failure_to_fill)) {
if (failure_to_fill)
*failure_to_fill = "Decided to fill";
// Mark the cached field as autofilled, so that we can detect when a
@@ -2456,13 +2336,17 @@ void AutofillManager::FillFieldWithValue(AutofillField* autofill_field,
field_data->is_autofilled = true;
AutofillMetrics::LogUserHappinessMetric(
AutofillMetrics::FIELD_WAS_AUTOFILLED, autofill_field->Type().group(),
- client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
+ client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
if (should_notify) {
- client_->DidFillOrPreviewField(
- /*value=*/data_model.GetInfo(autofill_field->Type(), app_locale_),
- /*profile_full_name=*/data_model.GetInfo(AutofillType(NAME_FULL),
- app_locale_));
+ DCHECK(absl::holds_alternative<const AutofillProfile*>(
+ profile_or_credit_card));
+ const AutofillProfile* profile =
+ absl::get<const AutofillProfile*>(profile_or_credit_card);
+ client()->DidFillOrPreviewField(
+ /*value=*/profile->GetInfo(autofill_field->Type(), app_locale_),
+ /*profile_full_name=*/profile->GetInfo(AutofillType(NAME_FULL),
+ app_locale_));
}
}
}
@@ -2589,22 +2473,28 @@ void AutofillManager::TriggerRefill(const FormData& form) {
return;
FormFieldData field = *autofill_field;
- if (filling_context->credit_card) {
+ if (absl::holds_alternative<std::pair<CreditCard, base::string16>>(
+ filling_context->profile_or_credit_card_with_cvc)) {
FillOrPreviewDataModelForm(
AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
/*query_id=*/-1, form, field,
- /*profile=*/nullptr, &filling_context->credit_card.value().first,
- &filling_context->credit_card.value().second, form_structure,
- autofill_field,
+ &absl::get<std::pair<CreditCard, base::string16>>(
+ filling_context->profile_or_credit_card_with_cvc)
+ .first,
+ &absl::get<std::pair<CreditCard, base::string16>>(
+ filling_context->profile_or_credit_card_with_cvc)
+ .second,
+ form_structure, autofill_field,
/*is_refill=*/true);
}
- if (filling_context->profile) {
+ if (absl::holds_alternative<AutofillProfile>(
+ filling_context->profile_or_credit_card_with_cvc)) {
FillOrPreviewDataModelForm(
AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
- /*query_id=*/-1, form, field, &filling_context->profile.value(),
- /*credic_card=*/nullptr, /*cvc=*/nullptr, form_structure,
- autofill_field,
- /*is_refill=*/true);
+ /*query_id=*/-1, form, field,
+ &absl::get<AutofillProfile>(
+ filling_context->profile_or_credit_card_with_cvc),
+ /*cvc=*/nullptr, form_structure, autofill_field, /*is_refill=*/true);
}
}
@@ -2627,7 +2517,7 @@ void AutofillManager::GetAvailableSuggestions(
// Log interactions of forms that are autofillable.
if (got_autofillable_form) {
- if (context->focused_field->Type().group() == CREDIT_CARD) {
+ if (context->focused_field->Type().group() == FieldTypeGroup::kCreditCard) {
context->is_filling_credit_card = true;
}
auto* logger = GetEventFormLogger(context->focused_field->Type().group());
@@ -2640,10 +2530,10 @@ void AutofillManager::GetAvailableSuggestions(
// If the feature is enabled and this is a mixed content form, we show a
// warning message and don't offer autofill. The warning is shown even if
// there are no autofill suggestions available.
- if (IsFormMixedContent(client_, form) &&
+ if (IsFormMixedContent(client(), form) &&
base::FeatureList::IsEnabled(
features::kAutofillPreventMixedFormsFilling) &&
- client_->GetPrefs()->GetBoolean(::prefs::kMixedFormsWarningsEnabled)) {
+ client()->GetPrefs()->GetBoolean(::prefs::kMixedFormsWarningsEnabled)) {
suggestions->clear();
// If the user begins typing, we interpret that as dismissing the warning.
// No suggestions are allowed, but the warning is no longer shown.
@@ -2684,15 +2574,6 @@ void AutofillManager::GetAvailableSuggestions(
return;
}
} else {
- // On desktop, don't return non credit card related suggestions for forms
- // or fields that have the "autocomplete" attribute set to off, only if
- // the feature to always fill addresses is off.
- if (!base::FeatureList::IsEnabled(features::kAutofillAlwaysFillAddresses) &&
- IsDesktopPlatform() && !field.should_autocomplete) {
- context->suppress_reason = SuppressReason::kAutocompleteOff;
- return;
- }
-
*suggestions = GetProfileSuggestions(*context->form_structure, field,
*context->focused_field);
}
@@ -2741,7 +2622,7 @@ bool AutofillManager::ShouldShowVirtualCardOption(
// If merchant is not allowed, return false.
std::vector<std::string> allowed_merchants =
- client_->GetAllowedMerchantsForVirtualCards();
+ client()->GetAllowedMerchantsForVirtualCards();
if (std::find(allowed_merchants.begin(), allowed_merchants.end(),
form_structure->source_url().spec()) ==
allowed_merchants.end()) {
@@ -2771,34 +2652,64 @@ bool AutofillManager::ShouldShowVirtualCardOption(
FormEventLoggerBase* AutofillManager::GetEventFormLogger(
FieldTypeGroup field_type_group) const {
switch (field_type_group) {
- case NAME:
- case NAME_BILLING:
- case EMAIL:
- case COMPANY:
- case ADDRESS_HOME:
- case ADDRESS_BILLING:
- case PHONE_HOME:
- case PHONE_BILLING:
+ case FieldTypeGroup::kName:
+ case FieldTypeGroup::kNameBilling:
+ case FieldTypeGroup::kEmail:
+ case FieldTypeGroup::kCompany:
+ case FieldTypeGroup::kAddressHome:
+ case FieldTypeGroup::kAddressBilling:
+ case FieldTypeGroup::kPhoneHome:
+ case FieldTypeGroup::kPhoneBilling:
return address_form_event_logger_.get();
- case CREDIT_CARD:
+ case FieldTypeGroup::kCreditCard:
return credit_card_form_event_logger_.get();
- case TRANSACTION:
- case PASSWORD_FIELD:
- case USERNAME_FIELD:
- case NO_GROUP:
- case UNFILLABLE:
+ case FieldTypeGroup::kTransaction:
+ case FieldTypeGroup::kPasswordField:
+ case FieldTypeGroup::kUsernameField:
+ case FieldTypeGroup::kNoGroup:
+ case FieldTypeGroup::kUnfillable:
return nullptr;
}
NOTREACHED();
return nullptr;
}
-std::string AutofillManager::GetPageLanguage() const {
- DCHECK(client_);
- const translate::LanguageState* language_state = client_->GetLanguageState();
- if (language_state)
- return language_state->original_language();
- return std::string();
+void AutofillManager::PreProcessStateMatchingTypes(
+ const std::vector<AutofillProfile>& profiles,
+ FormStructure* form_structure) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ return;
+ }
+
+ for (const auto& profile : profiles) {
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ canonical_state_name_from_profile =
+ profile.GetAddress().GetCanonicalizedStateName();
+
+ if (!canonical_state_name_from_profile)
+ continue;
+
+ const AutofillType kCountryCode(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE);
+ const base::string16& country_code =
+ profile.GetInfo(kCountryCode, app_locale_);
+
+ for (auto& field : *form_structure) {
+ if (field->state_is_a_matching_type())
+ continue;
+
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ canonical_state_name_from_text =
+ AlternativeStateNameMap::GetCanonicalStateName(
+ base::UTF16ToUTF8(country_code), field->value);
+
+ if (canonical_state_name_from_text &&
+ canonical_state_name_from_text.value() ==
+ canonical_state_name_from_profile.value()) {
+ field->set_state_is_a_matching_type();
+ }
+ }
+ }
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index d2cecaf5e00..ab3482f1eb9 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -24,10 +24,9 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/autofill_download_manager.h"
#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_handler.h"
-#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/field_filler.h"
#include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/browser/metrics/address_form_event_logger.h"
@@ -39,8 +38,10 @@
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/browser/ui/popup_types.h"
+#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/signatures.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
namespace gfx {
class RectF;
@@ -48,9 +49,6 @@ class RectF;
namespace autofill {
-class AutofillDataModel;
-class AutofillDownloadManager;
-class AutofillExternalDelegate;
class AutofillField;
class AutofillClient;
class AutofillManagerTestDelegate;
@@ -58,7 +56,6 @@ class AutofillProfile;
class AutofillType;
class CreditCard;
class FormStructureBrowserTest;
-class LogManager;
struct FormData;
struct FormFieldData;
@@ -78,7 +75,6 @@ enum class ValuePatternsMetric {
// Manages saving and restoring the user's personal information entered into web
// forms. One per frame; owned by the AutofillDriver.
class AutofillManager : public AutofillHandler,
- public AutofillDownloadManager::Observer,
public AutocompleteHistoryManager::SuggestionsHandler,
public CreditCardAccessManager::Accessor {
public:
@@ -88,9 +84,6 @@ class AutofillManager : public AutofillHandler,
AutofillDownloadManagerState enable_download_manager);
~AutofillManager() override;
- // Sets an external delegate.
- void SetExternalDelegate(AutofillExternalDelegate* delegate);
-
void ShowAutofillSettings(bool show_credit_card_settings);
// Whether the |field| should show an entry to scan a credit card.
@@ -177,11 +170,7 @@ class AutofillManager : public AutofillHandler,
// Returns true only if the previewed form should be cleared.
bool ShouldClearPreviewedForm();
- AutofillClient* client() { return client_; }
-
- AutofillDownloadManager* download_manager() {
- return download_manager_.get();
- }
+ AutofillOfferManager* offer_manager() { return offer_manager_; }
CreditCardAccessManager* credit_card_access_manager() {
return credit_card_access_manager_.get();
@@ -227,6 +216,9 @@ class AutofillManager : public AutofillHandler,
void OnDidEndTextFieldEditing() override;
void OnHidePopup() override;
void SelectFieldOptionsDidChange(const FormData& form) override;
+ void PropagateAutofillPredictions(
+ content::RenderFrameHost* rfh,
+ const std::vector<FormStructure*>& forms) override;
void Reset() override;
// AutocompleteHistoryManager::SuggestionsHandler:
@@ -251,10 +243,6 @@ class AutofillManager : public AutofillHandler,
// to be uploadable. Exposed for testing.
bool ShouldUploadForm(const FormStructure& form);
- // Rich queries are enabled by feature flag iff this chrome instance is
- // neither on the STABLE nor BETA release channel.
- static bool IsRichQueryEnabled(version_info::Channel channel);
-
// Returns the last form the autofill manager considered in this frame.
virtual const FormData& last_query_form() const;
@@ -268,6 +256,11 @@ class AutofillManager : public AutofillHandler,
}
#if defined(UNIT_TEST)
+ void SetExternalDelegateForTest(
+ std::unique_ptr<AutofillExternalDelegate> external_delegate) {
+ external_delegate_ = std::move(external_delegate);
+ }
+
// A public wrapper that calls |DeterminePossibleFieldTypesForUpload| for
// testing purposes only.
static void DeterminePossibleFieldTypesForUploadForTest(
@@ -281,27 +274,12 @@ class AutofillManager : public AutofillHandler,
app_locale, submitted_form);
}
- // A public wrapper that calls |OnLoadedServerPredictions| for testing
- // purposes only.
- void OnLoadedServerPredictionsForTest(
- std::string response,
- const std::vector<FormSignature>& queried_form_signatures) {
- OnLoadedServerPredictions(response, queried_form_signatures);
- }
-
// A public wrapper that calls |MakeFrontendID| for testing purposes only.
int MakeFrontendIDForTest(const std::string& cc_backend_id,
const std::string& profile_backend_id) const {
return MakeFrontendID(cc_backend_id, profile_backend_id);
}
- // A public wrapper that calls |form_interactions_ukm_logger| for testing
- // purposes only.
- AutofillMetrics::FormInteractionsUkmLogger*
- form_interactions_ukm_logger_for_test() {
- return form_interactions_ukm_logger();
- }
-
// A public wrapper that calls |ShouldTriggerRefill| for testing purposes
// only.
bool ShouldTriggerRefillForTest(const FormStructure& form_structure) {
@@ -310,6 +288,14 @@ class AutofillManager : public AutofillHandler,
// A public wrapper that calls |TriggerRefill| for testing purposes only.
void TriggerRefillForTest(const FormData& form) { TriggerRefill(form); }
+
+ // A public wrapper that calls |PreProcessStateMatchingTypes| for testing
+ // purposes.
+ void PreProcessStateMatchingTypesForTest(
+ const std::vector<AutofillProfile>& profiles,
+ FormStructure* form_structure) {
+ PreProcessStateMatchingTypes(profiles, form_structure);
+ }
#endif
protected:
@@ -371,34 +357,31 @@ class AutofillManager : public AutofillHandler,
void OnSelectControlDidChangeImpl(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
- bool ShouldParseForms(const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) override;
- void OnFormsParsed(const std::vector<const FormData*>& forms,
- const base::TimeTicks timestamp) override;
-
- AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger() {
- return form_interactions_ukm_logger_.get();
- }
-
- // Exposed for testing.
- void set_download_manager(AutofillDownloadManager* manager) {
- download_manager_.reset(manager);
- }
-
- // Exposed for testing.
- bool is_rich_query_enabled() const { return is_rich_query_enabled_; }
+ bool ShouldParseForms(const std::vector<FormData>& forms) override;
+ void OnBeforeProcessParsedForms() override;
+ void OnFormProcessed(const FormData& form,
+ const FormStructure& form_structure) override;
+ void OnAfterProcessParsedForms(const DenseSet<FormType>& form_types) override;
// Exposed for testing.
FormData* pending_form_data() { return pending_form_data_.get(); }
private:
+ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, PageLanguageGetsCorrectlySet);
+ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
+ PageLanguageGetsCorrectlyDetected);
+ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DoNotFillIfFormFieldChanged);
+ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DoNotFillIfFormFieldRemoved);
+
// Keeps track of the filling context for a form, used to make refill attemps.
struct FillingContext {
- // |optional_profile| or |optional_credit_card| must be non-null.
- // If |optional_credit_card| is non-null, |optional_cvc| may be non-null.
+ // |profile_or_credit_card| contains either AutofillProfile or CreditCard
+ // and must be non-null.
+ // If |profile_or_credit_card| contains a CreditCard, |optional_cvc| may be
+ // non-null.
FillingContext(const AutofillField& field,
- const AutofillProfile* optional_profile,
- const CreditCard* optional_credit_card,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
const base::string16* optional_cvc);
~FillingContext();
@@ -407,8 +390,8 @@ class AutofillManager : public AutofillHandler,
// The profile or credit card that was used for the initial fill.
// The std::string associated with the credit card is the CVC, which may be
// empty.
- const base::Optional<AutofillProfile> profile;
- const base::Optional<std::pair<CreditCard, base::string16>> credit_card;
+ absl::variant<AutofillProfile, std::pair<CreditCard, base::string16>>
+ profile_or_credit_card_with_cvc;
// Possible identifiers of the field that was focused when the form was
// initially filled. A refill shall be triggered from the same field.
// TODO(crbug/896689): Remove |filled_field_unique_name|.
@@ -451,11 +434,6 @@ class AutofillManager : public AutofillHandler,
SuppressReason suppress_reason = SuppressReason::kNotSuppressed;
};
- // AutofillDownloadManager::Observer:
- void OnLoadedServerPredictions(
- std::string response,
- const std::vector<FormSignature>& queried_form_signatures) override;
-
// CreditCardAccessManager::Accessor
void OnCreditCardFetched(
bool did_succeed,
@@ -497,16 +475,17 @@ class AutofillManager : public AutofillHandler,
const AutofillProfile& profile);
// Fills or previews |data_model| in the |form|.
- void FillOrPreviewDataModelForm(AutofillDriver::RendererFormDataAction action,
- int query_id,
- const FormData& form,
- const FormFieldData& field,
- const AutofillProfile* optional_profile,
- const CreditCard* optional_credit_card,
- const base::string16* optional_cvc,
- FormStructure* form_structure,
- AutofillField* autofill_field,
- bool is_refill = false);
+ void FillOrPreviewDataModelForm(
+ AutofillDriver::RendererFormDataAction action,
+ int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
+ const base::string16* optional_cvc,
+ FormStructure* form_structure,
+ AutofillField* autofill_field,
+ bool is_refill = false);
// Creates a FormStructure using the FormData received from the renderer. Will
// return an empty scoped_ptr if the data should not be processed for upload
@@ -581,13 +560,15 @@ class AutofillManager : public AutofillHandler,
size_t current_index,
const ServerFieldTypeSet& upload_types);
- void FillFieldWithValue(AutofillField* autofill_field,
- const AutofillDataModel& data_model,
- FormFieldData* field_data,
- bool should_notify,
- const base::string16& cvc,
- uint32_t profile_form_bitmask,
- std::string* failure_to_fill);
+ void FillFieldWithValue(
+ AutofillField* autofill_field,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
+ FormFieldData* field_data,
+ bool should_notify,
+ const base::string16& cvc,
+ uint32_t profile_form_bitmask,
+ std::string* failure_to_fill);
// TODO(crbug/896689): Remove code duplication once experiment is finished.
void SetFillingContext(const FormStructure& form,
@@ -617,8 +598,13 @@ class AutofillManager : public AutofillHandler,
std::vector<Suggestion>* suggestions,
SuggestionsContext* context);
- // Retrieves the page language from |client_|
- std::string GetPageLanguage() const override;
+ // For each submitted field in the |form_structure|, it determines whether
+ // |ADDRESS_HOME_STATE| is a possible matching type.
+ // This method is intended to run matching type detection on the browser UI
+ // thread.
+ void PreProcessStateMatchingTypes(
+ const std::vector<AutofillProfile>& profiles,
+ FormStructure* form_structure);
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Whether to show the option to use virtual card in the autofill popup.
@@ -633,9 +619,9 @@ class AutofillManager : public AutofillHandler,
void SetDataList(const std::vector<base::string16>& values,
const std::vector<base::string16>& labels);
- AutofillClient* const client_;
-
- LogManager* log_manager_;
+ // Delegate to perform external processing (display, selection) on
+ // our behalf.
+ std::unique_ptr<AutofillExternalDelegate> external_delegate_;
std::string app_locale_;
@@ -650,18 +636,10 @@ class AutofillManager : public AutofillHandler,
base::circular_deque<std::string> autofilled_form_signatures_;
- // Handles queries and uploads to Autofill servers. Will be NULL if
- // the download manager functionality is disabled.
- std::unique_ptr<AutofillDownloadManager> download_manager_;
-
// Handles single-field autocomplete form data.
// May be NULL. NULL indicates OTR.
base::WeakPtr<AutocompleteHistoryManager> autocomplete_history_manager_;
- // Utility for logging URL keyed metrics.
- std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
- form_interactions_ukm_logger_;
-
// Utilities for logging form events.
std::unique_ptr<AddressFormEventLogger> address_form_event_logger_;
std::unique_ptr<CreditCardFormEventLogger> credit_card_form_event_logger_;
@@ -698,7 +676,8 @@ class AutofillManager : public AutofillHandler,
std::unique_ptr<CreditCardAccessManager> credit_card_access_manager_;
// The autofill offer manager, used to to retrieve offers for card
- // suggestions.
+ // suggestions. Initialized when AutofillManager is created. |offer_manager_|
+ // is never null.
AutofillOfferManager* offer_manager_;
// Collected information about the autofill form where a credit card will be
@@ -720,10 +699,6 @@ class AutofillManager : public AutofillHandler,
mutable std::map<std::string, int> backend_to_int_map_;
mutable std::map<int, std::string> int_to_backend_map_;
- // Delegate to perform external processing (display, selection) on
- // our behalf. Weak.
- AutofillExternalDelegate* external_delegate_ = nullptr;
-
// Delegate used in test to get notifications on certain events.
AutofillManagerTestDelegate* test_delegate_ = nullptr;
@@ -735,9 +710,6 @@ class AutofillManager : public AutofillHandler,
std::map<base::string16, std::unique_ptr<FillingContext>>
filling_context_by_unique_name_;
- // Tracks whether or not rich query encoding is enabled for this client.
- const bool is_rich_query_enabled_ = false;
-
// Used to record metrics. This should be set at the beginning of the
// interaction and re-used throughout the context of this manager.
AutofillSyncSigninState sync_state_ = AutofillSyncSigninState::kNumSyncStates;
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index d801bda0abb..d00a45b5848 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -30,14 +30,15 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_download_manager.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
@@ -69,6 +70,7 @@
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/driver/test_sync_service.h"
+#include "components/translate/core/common/language_detection_details.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/channel.h"
#include "net/base/url_util.h"
@@ -79,6 +81,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
+#include "url/url_canon.h"
using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
@@ -86,6 +89,8 @@ using testing::_;
using testing::AnyOf;
using testing::AtLeast;
using testing::Contains;
+using testing::DoAll;
+using testing::Each;
using testing::ElementsAre;
using testing::HasSubstr;
using testing::Not;
@@ -182,13 +187,8 @@ void ExpectFilledForm(int page_id,
EXPECT_EQ(expected_page_id, page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), filled_form.name);
- if (has_credit_card_fields) {
- EXPECT_EQ(GURL("https://myform.com/form.html"), filled_form.url);
- EXPECT_EQ(GURL("https://myform.com/submit.html"), filled_form.action);
- } else {
- EXPECT_EQ(GURL("http://myform.com/form.html"), filled_form.url);
- EXPECT_EQ(GURL("http://myform.com/submit.html"), filled_form.action);
- }
+ EXPECT_EQ(GURL("https://myform.com/form.html"), filled_form.url);
+ EXPECT_EQ(GURL("https://myform.com/submit.html"), filled_form.action);
size_t form_size = 0;
if (has_address_fields)
@@ -326,6 +326,7 @@ class AutofillManagerTest : public testing::Test {
personal_data_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -360,17 +361,20 @@ class AutofillManagerTest : public testing::Test {
autofill_manager_ = std::make_unique<TestAutofillManager>(
autofill_driver_.get(), &autofill_client_, &personal_data_,
autocomplete_history_manager_.get());
- download_manager_ = new MockAutofillDownloadManager(
+
+ auto download_manager = std::make_unique<MockAutofillDownloadManager>(
autofill_driver_.get(), autofill_manager_.get());
- // AutofillManager takes ownership of |download_manager_|.
- autofill_manager_->set_download_manager(download_manager_);
- external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ download_manager_ = download_manager.get();
+ autofill_manager_->set_download_manager_for_test(
+ std::move(download_manager));
+
+ auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
- std::unique_ptr<TestStrikeDatabase> test_strike_database =
- std::make_unique<TestStrikeDatabase>();
+ auto test_strike_database = std::make_unique<TestStrikeDatabase>();
strike_database_ = test_strike_database.get();
autofill_client_.set_test_strike_database(std::move(test_strike_database));
@@ -431,7 +435,6 @@ class AutofillManagerTest : public testing::Test {
// Order of destruction is important as AutofillManager relies on
// PersonalDataManager to be around when it gets destroyed.
autofill_manager_.reset();
- autofill_driver_.reset();
personal_data_.SetPrefService(nullptr);
personal_data_.ClearCreditCards();
@@ -463,7 +466,7 @@ class AutofillManagerTest : public testing::Test {
}
void FormsSeen(const std::vector<FormData>& forms) {
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
}
void FormSubmitted(const FormData& form) {
@@ -517,6 +520,14 @@ class AutofillManagerTest : public testing::Test {
form->url = GURL("https://myform.com/form.html");
form->action = GURL("https://myform.com/submit.html");
} else {
+ // If we are testing a form that submits over HTTP, we also need to set
+ // the main frame to HTTP, otherwise mixed form warnings will trigger and
+ // autofill will be disabled.
+ GURL::Replacements replacements;
+ replacements.SetScheme(url::kHttpScheme,
+ url::Component(0, strlen(url::kHttpScheme)));
+ autofill_client_.set_form_origin(
+ autofill_client_.form_origin().ReplaceComponents(replacements));
form->url = GURL("http://myform.com/form.html");
form->action = GURL("http://myform.com/submit.html");
}
@@ -628,14 +639,13 @@ class AutofillManagerTest : public testing::Test {
MockAutofillClient autofill_client_;
std::unique_ptr<MockAutofillDriver> autofill_driver_;
std::unique_ptr<TestAutofillManager> autofill_manager_;
- std::unique_ptr<TestAutofillExternalDelegate> external_delegate_;
+ TestAutofillExternalDelegate* external_delegate_;
scoped_refptr<AutofillWebDataService> database_;
MockAutofillDownloadManager* download_manager_;
TestPersonalDataManager personal_data_;
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
base::test::ScopedFeatureList scoped_feature_list_;
TestStrikeDatabase* strike_database_;
- TestPatternProvider test_pattern_provider_;
private:
int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) {
@@ -715,21 +725,25 @@ class AutofillManagerStructuredProfileTest
void InitializeFeatures();
- bool StructuredNames() const { return structured_names_enabled_; }
+ bool StructuredNamesAndAddresses() const {
+ return structured_names_and_addresses_;
+ }
private:
- bool structured_names_enabled_;
+ bool structured_names_and_addresses_;
base::test::ScopedFeatureList scoped_features_;
};
void AutofillManagerStructuredProfileTest::InitializeFeatures() {
- structured_names_enabled_ = GetParam();
- if (structured_names_enabled_) {
- scoped_features_.InitAndEnableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ structured_names_and_addresses_ = GetParam();
+
+ std::vector<base::Feature> features = {
+ features::kAutofillEnableSupportForMoreStructureInAddresses,
+ features::kAutofillEnableSupportForMoreStructureInNames};
+ if (structured_names_and_addresses_) {
+ scoped_features_.InitWithFeatures(features, {});
} else {
- scoped_features_.InitAndDisableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ scoped_features_.InitWithFeatures({}, features);
}
}
@@ -1226,8 +1240,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Username", "username", "", "text", &field);
@@ -1653,7 +1667,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
FormsSeen(forms);
// Set the field being edited to CC field.
const FormFieldData& credit_card_number_field = form.fields[1];
- const std::string google_issued_card_value = "Google";
+ const std::string google_issued_card_value = base::JoinString(
+ {"Plex Mastercard ", test::ObfuscatedCardDigitsAsUTF8("4444")}, "");
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string google_issued_card_label = std::string("10/98");
#else
@@ -1692,13 +1707,16 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set the field being edited to the cardholder name field.
const FormFieldData& cardholder_name_field = form.fields[0];
#if defined(OS_ANDROID)
- const std::string google_issued_card_label = std::string("Google");
+ const std::string google_issued_card_label = base::JoinString(
+ {"Plex Mastercard ", test::ObfuscatedCardDigitsAsUTF8("4444")}, "");
#elif defined(OS_IOS)
const std::string google_issued_card_label =
test::ObfuscatedCardDigitsAsUTF8("4444");
#else
- const std::string google_issued_card_label =
- std::string("Google, expires on 10/98");
+ const std::string google_issued_card_label = base::JoinString(
+ {"Plex Mastercard ", test::ObfuscatedCardDigitsAsUTF8("4444"),
+ ", expires on 10/98"},
+ "");
#endif
GetAutofillSuggestions(form, cardholder_name_field);
@@ -1790,16 +1808,19 @@ TEST_P(AutofillManagerStructuredProfileTest,
GetAutofillSuggestions(form, field);
// Test that we sent the right values to the external delegate.
- CheckSuggestions(kDefaultPageID,
- Suggestion(l10n_util::GetStringUTF8(
- IDS_AUTOFILL_WARNING_INSECURE_CONNECTION),
- "", "", -1));
+ CheckSuggestions(
+ kDefaultPageID,
+ Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
+ "", -26));
- // Clear the test credit cards and try again -- we shouldn't return a warning.
+ // Clear the test credit cards and try again -- we should still show the
+ // mixed form warning.
personal_data_.ClearCreditCards();
GetAutofillSuggestions(form, field);
- // Autocomplete suggestions are queried, but not Autofill.
- EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+ CheckSuggestions(
+ kDefaultPageID,
+ Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
+ "", -26));
}
// Test that we return credit card suggestions for secure pages that have an
@@ -2095,6 +2116,71 @@ TEST_F(AutofillManagerTest, FillTriggeredSection) {
false);
}
+MATCHER(HasEmptyValue, "") {
+ return arg.value.empty();
+}
+
+// Test that if the form cache is outdated because a field has changed, filling
+// is aborted after that field.
+TEST_F(AutofillManagerTest, DoNotFillIfFormFieldChanged) {
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ FormsSeen({form});
+
+ FormStructure* form_structure = nullptr;
+ AutofillField* autofill_field = nullptr;
+ ASSERT_TRUE(autofill_manager_->GetCachedFormAndField(
+ form, form.fields.front(), &form_structure, &autofill_field));
+
+ // Modify |form| so that it doesn't match |form_structure| anymore.
+ ASSERT_GE(form.fields.size(), 3u);
+ for (auto it = form.fields.begin() + 2; it != form.fields.end(); ++it)
+ *it = FormFieldData();
+
+ const char guid[] = "00000000-0000-0000-0000-000000000001";
+ AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
+ ASSERT_TRUE(profile);
+
+ int response_query_id = 0;
+ FormData response_data;
+ EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _))
+ .WillOnce((DoAll(testing::SaveArg<0>(&response_query_id),
+ testing::SaveArg<2>(&response_data))));
+ autofill_manager_->FillOrPreviewDataModelForm(
+ AutofillDriver::FORM_DATA_ACTION_FILL, kDefaultPageID, form,
+ form.fields.front(), profile, nullptr, form_structure, autofill_field);
+ std::vector<FormFieldData> filled_fields(response_data.fields.begin(),
+ response_data.fields.begin() + 2);
+ std::vector<FormFieldData> skipped_fields(response_data.fields.begin() + 2,
+ response_data.fields.end());
+
+ EXPECT_THAT(filled_fields, Each(Not(HasEmptyValue())));
+ EXPECT_THAT(skipped_fields, Each(HasEmptyValue()));
+}
+
+// Test that if the form cache is outdated because a field was removed, filling
+// is aborted.
+TEST_F(AutofillManagerTest, DoNotFillIfFormFieldRemoved) {
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ FormsSeen({form});
+
+ FormStructure* form_structure = nullptr;
+ AutofillField* autofill_field = nullptr;
+ ASSERT_TRUE(autofill_manager_->GetCachedFormAndField(
+ form, form.fields.front(), &form_structure, &autofill_field));
+
+ // Modify |form| so that it doesn't match |form_structure| anymore.
+ ASSERT_GE(form.fields.size(), 2u);
+ form.fields.pop_back();
+
+ const char guid[] = "00000000-0000-0000-0000-000000000001";
+ AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
+ ASSERT_TRUE(profile);
+
+ EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _)).Times(0);
+}
+
// Tests that AutofillManager ignores loss of focus events sent from the
// renderer if the renderer did not have a previously-interacted form.
// TODO(crbug.com/1140473): Remove this test when workaround is no longer
@@ -2151,6 +2237,86 @@ TEST_F(AutofillManagerTest,
1);
}
+// Test that we properly match typed values to stored state data.
+TEST_F(AutofillManagerTest, DetermineStateFieldTypeForUpload) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+
+ AutofillProfile profile;
+ test::SetProfileInfo(&profile, "", "", "", "", "", "", "", "", "Bavaria", "",
+ "DE", "");
+
+ const char* const kValidMatches[] = {"by", "Bavaria", "Bayern",
+ "BY", "B.Y", "B-Y"};
+ for (const char* valid_match : kValidMatches) {
+ SCOPED_TRACE(valid_match);
+ FormData form;
+ FormFieldData field;
+
+ test::CreateTestFormField("Name", "Name", "Test", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("State", "state", valid_match, "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ EXPECT_EQ(form_structure.field_count(), 2U);
+
+ autofill_manager_->PreProcessStateMatchingTypesForTest({profile},
+ &form_structure);
+ EXPECT_TRUE(form_structure.field(1)->state_is_a_matching_type());
+ }
+
+ const char* const kInvalidMatches[] = {"Garbage", "BYA", "BYA is a state",
+ "Bava", "Empty", ""};
+ for (const char* invalid_match : kInvalidMatches) {
+ SCOPED_TRACE(invalid_match);
+ FormData form;
+ FormFieldData field;
+
+ test::CreateTestFormField("Name", "Name", "Test", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("State", "state", invalid_match, "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ EXPECT_EQ(form_structure.field_count(), 2U);
+
+ autofill_manager_->PreProcessStateMatchingTypesForTest({profile},
+ &form_structure);
+ EXPECT_FALSE(form_structure.field(1)->state_is_a_matching_type());
+ }
+
+ test::PopulateAlternativeStateNameMapForTesting(
+ "US", "California",
+ {{.canonical_name = "California",
+ .abbreviations = {"CA"},
+ .alternative_names = {}}});
+
+ test::SetProfileInfo(&profile, "", "", "", "", "", "", "", "", "California",
+ "", "US", "");
+
+ FormData form;
+ FormFieldData field;
+
+ test::CreateTestFormField("Name", "Name", "Test", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("State", "state", "CA", "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ EXPECT_EQ(form_structure.field_count(), 2U);
+
+ autofill_manager_->PreProcessStateMatchingTypesForTest({profile},
+ &form_structure);
+ EXPECT_TRUE(form_structure.field(1)->state_is_a_matching_type());
+}
+
// Test that we return normal Autofill suggestions when trying to autofill
// already filled forms.
TEST_P(SuggestionMatchingTest, GetFieldSuggestionsWhenFormIsAutofilled) {
@@ -2332,8 +2498,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
struct {
const char* const label;
@@ -2384,8 +2550,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
struct {
const char* const label;
@@ -2900,6 +3066,11 @@ TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_SplitName) {
// Test that only filled selection boxes are counted for the type filling limit.
TEST_P(AutofillManagerStructuredProfileTest,
OnlyCountFilledSelectionBoxesForTypeFillingLimit) {
+ test::PopulateAlternativeStateNameMapForTesting(
+ "US", "Tennessee",
+ {{.canonical_name = "Tennessee",
+ .abbreviations = {"TN"},
+ .alternative_names = {}}});
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -2938,6 +3109,14 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.fields.push_back(field);
}
+ // Create a selection box for the state that hat the correct entry to be
+ // filled with user data. Note, TN is the official abbreviation for Tennessee.
+ for (int i = 0; i < 20; ++i) {
+ test::CreateTestSelectField("Country", "country", "", {"DE", "FR", "US"},
+ {"DE", "FR", "US"}, 3, &field);
+ form.fields.push_back(field);
+ }
+
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -2974,17 +3153,18 @@ TEST_P(AutofillManagerStructuredProfileTest,
response_data.fields[4 + i]);
}
- // Verify that the next 8 selection boxes are correctly filled again.
- for (int i = 0; i < 8; i++) {
+ // Verify that the remaining selection boxes are correctly filled again
+ // because there's no limit on filling ADDRESS_HOME_STATE fields.
+ for (int i = 0; i < 20; i++) {
ExpectFilledField("State", "state", "TN", "select-one",
response_data.fields[24 + i]);
}
- // Verify that the last 12 boxes are not filled because the filling limit for
- // the state type is already reached.
- for (int i = 0; i < 12; i++) {
- ExpectFilledField("State", "state", "", "select-one",
- response_data.fields[32 + i]);
+ // Verify that only the first 9 of the remaining selection boxes are
+ // correctly filled due to the limit on filling ADDRESS_HOME_COUNTRY fields.
+ for (int i = 0; i < 20; i++) {
+ ExpectFilledField("Country", "country", i < 9 ? "US" : "", "select-one",
+ response_data.fields[44 + i]);
}
}
@@ -3067,68 +3247,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
}
// Test that non credit card related fields with the autocomplete attribute set
-// to off are not filled on desktop when the feature to autofill all addresses
-// is disabled.
-TEST_P(AutofillManagerStructuredProfileTest,
- FillAddressForm_AutocompleteOffRespected) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(features::kAutofillAlwaysFillAddresses);
-
- FormData address_form;
- address_form.name = ASCIIToUTF16("MyForm");
- address_form.url = GURL("https://myform.com/form.html");
- address_form.action = GURL("https://myform.com/submit.html");
- FormFieldData field;
- test::CreateTestFormField("First name", "firstname", "", "text", &field);
- address_form.fields.push_back(field);
- test::CreateTestFormField("Middle name", "middle", "", "text", &field);
- field.should_autocomplete = false;
- address_form.fields.push_back(field);
- test::CreateTestFormField("Last name", "lastname", "", "text", &field);
- field.should_autocomplete = true;
- address_form.fields.push_back(field);
- test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
- field.should_autocomplete = false;
- address_form.fields.push_back(field);
- std::vector<FormData> address_forms(1, address_form);
- FormsSeen(address_forms);
-
- // Fill the address form.
- const char guid[] = "00000000-0000-0000-0000-000000000001";
- int response_page_id = 0;
- FormData response_data;
- FillAutofillFormDataAndSaveResults(
- kDefaultPageID, address_form, address_form.fields[0],
- MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
-
- // The fist name should be filled.
- ExpectFilledField("First name", "firstname", "Elvis", "text",
- response_data.fields[0]);
-
- // The middle name should not be filled on desktop.
- if (IsDesktopPlatform()) {
- ExpectFilledField("Middle name", "middle", "", "text",
- response_data.fields[1]);
- } else {
- ExpectFilledField("Middle name", "middle", "Aaron", "text",
- response_data.fields[1]);
- }
-
- // The last name should be filled.
- ExpectFilledField("Last name", "lastname", "Presley", "text",
- response_data.fields[2]);
-
- // The address line 1 should not be filled on desktop.
- if (IsDesktopPlatform()) {
- ExpectFilledField("Address Line 1", "addr1", "", "text",
- response_data.fields[3]);
- } else {
- ExpectFilledField("Address Line 1", "addr1", "3734 Elvis Presley Blvd.",
- "text", response_data.fields[3]);
- }
-}
-
-// Test that non credit card related fields with the autocomplete attribute set
// to off are filled on all platforms when the feature to autofill all addresses
// is enabled (default).
TEST_P(AutofillManagerStructuredProfileTest,
@@ -3808,14 +3926,6 @@ TEST_P(AutofillManagerStructuredProfileTest, FillPartlyAutofilledForm) {
// Test that we correctly fill a previously partly auto-filled form.
TEST_P(AutofillManagerStructuredProfileTest, FillPartlyManuallyFilledForm) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled
- {features::kAutofillSkipFillingFieldsWithChangedValues},
- // Disabled
- // We want to query the legacy server rather than the API server.
- {});
-
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -3872,9 +3982,9 @@ TEST_P(AutofillManagerStructuredProfileTest, FillPhoneNumber) {
FormData form_with_us_number_max_length;
form_with_us_number_max_length.name = ASCIIToUTF16("MyMaxlengthPhoneForm");
form_with_us_number_max_length.url =
- GURL("http://myform.com/phone_form.html");
+ GURL("https://myform.com/phone_form.html");
form_with_us_number_max_length.action =
- GURL("http://myform.com/phone_submit.html");
+ GURL("https://myform.com/phone_submit.html");
FormData form_with_autocompletetype = form_with_us_number_max_length;
form_with_autocompletetype.name = ASCIIToUTF16("MyAutocompletetypePhoneForm");
@@ -4002,7 +4112,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
// componentized number fields.
FormData form_with_multiple_componentized_phone_fields;
form_with_multiple_componentized_phone_fields.url =
- GURL("http://www.foo.com/");
+ GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4069,7 +4179,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
- form_with_multiple_whole_number_fields.url = GURL("http://www.foo.com/");
+ form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4125,7 +4235,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
// componentized number fields.
FormData form_with_multiple_componentized_phone_fields;
form_with_multiple_componentized_phone_fields.url =
- GURL("http://www.foo.com/");
+ GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4197,7 +4307,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_misclassified_extension;
- form_with_misclassified_extension.url = GURL("http://www.foo.com/");
+ form_with_misclassified_extension.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4259,7 +4369,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_no_complete_number;
- form_with_no_complete_number.url = GURL("http://www.foo.com/");
+ form_with_no_complete_number.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4319,7 +4429,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
- form_with_multiple_whole_number_fields.url = GURL("http://www.foo.com/");
+ form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4375,7 +4485,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
- form_with_multiple_whole_number_fields.url = GURL("http://www.foo.com/");
+ form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4426,8 +4536,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
FormWithHiddenOrPresentationalSelects) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
@@ -4502,7 +4612,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_sections;
- form_with_multiple_sections.url = GURL("http://www.foo.com/");
+ form_with_multiple_sections.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
@@ -4647,7 +4757,7 @@ TEST_P(AutofillManagerStructuredProfileTest, FormChangesAddField) {
TEST_P(AutofillManagerStructuredProfileTest, FormChangesVisibilityOfFields) {
// Set up our form data.
FormData form;
- form.url = GURL("http://www.foo.com/");
+ form.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -4799,7 +4909,7 @@ TEST_P(AutofillManagerStructuredProfileTest, ValuePatternsMetric) {
&field);
field.is_focusable = true; // The metric skips hidden fields.
form.name = ASCIIToUTF16("my-form");
- form.url = GURL("http://myform.com/form.html");
+ form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
@@ -4822,10 +4932,11 @@ TEST_P(AutofillManagerStructuredProfileTest,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
- external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
@@ -4851,10 +4962,11 @@ TEST_P(AutofillManagerStructuredProfileTest,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
- external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
@@ -4921,15 +5033,23 @@ TEST_P(AutofillManagerStructuredProfileTest,
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_CreditCardNameFieldShouldAutocomplete) {
TestAutofillClient client;
+ // Since we are testing a form that submits over HTTP, we also need to set
+ // the main frame to HTTP in the client, otherwise mixed form warnings will
+ // trigger and autofill will be disabled.
+ GURL::Replacements replacements;
+ replacements.SetScheme(url::kHttpScheme,
+ url::Component(0, strlen(url::kHttpScheme)));
+ client.set_form_origin(client.form_origin().ReplaceComponents(replacements));
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
- external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
@@ -4952,15 +5072,23 @@ TEST_P(AutofillManagerStructuredProfileTest,
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_CreditCardNumberShouldNotAutocomplete) {
TestAutofillClient client;
+ // Since we are testing a form that submits over HTTP, we also need to set
+ // the main frame to HTTP in the client, otherwise mixed form warnings will
+ // trigger and autofill will be disabled.
+ GURL::Replacements replacements;
+ replacements.SetScheme(url::kHttpScheme,
+ url::Component(0, strlen(url::kHttpScheme)));
+ client.set_form_origin(client.form_origin().ReplaceComponents(replacements));
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
- external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
@@ -5011,10 +5139,11 @@ TEST_P(AutofillManagerStructuredProfileTest,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
- external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
@@ -5046,18 +5175,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
autofill_manager_.reset();
}
-namespace {
-void AddFieldSuggestionToForm(
- ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion,
- autofill::FormFieldData field_data,
- ServerFieldType field_type) {
- auto* field_suggestion = form_suggestion->add_field_suggestions();
- field_suggestion->set_field_signature(
- CalculateFieldSignatureForField(field_data).value());
- field_suggestion->set_primary_type_prediction(field_type);
-}
-} // namespace
-
// Test that OnLoadedServerPredictions can obtain the FormStructure with the
// signature of the queried form from the API and apply type predictions.
// What we test here:
@@ -5068,8 +5185,8 @@ TEST_P(AutofillManagerStructuredProfileTest, OnLoadedServerPredictionsFromApi) {
FormData form;
form.unique_renderer_id.value() = 1;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField(/*label=*/"City", /*name=*/"city",
/*value=*/"", /*type=*/"text", /*field=*/&field);
@@ -5085,15 +5202,15 @@ TEST_P(AutofillManagerStructuredProfileTest, OnLoadedServerPredictionsFromApi) {
auto form_structure_instance = std::make_unique<TestFormStructure>(form);
// This pointer is valid as long as autofill manager lives.
TestFormStructure* form_structure = form_structure_instance.get();
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
autofill_manager_->AddSeenFormStructure(std::move(form_structure_instance));
// Second form on the page.
FormData form2;
form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("MyForm2");
- form2.url = GURL("http://myform.com/form.html");
- form2.action = GURL("http://myform.com/submit.html");
+ form2.url = GURL("https://myform.com/form.html");
+ form2.action = GURL("https://myform.com/submit.html");
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form2.fields.push_back(field);
test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
@@ -5103,7 +5220,7 @@ TEST_P(AutofillManagerStructuredProfileTest, OnLoadedServerPredictionsFromApi) {
auto form_structure_instance2 = std::make_unique<TestFormStructure>(form2);
// This pointer is valid as long as autofill manager lives.
TestFormStructure* form_structure2 = form_structure_instance2.get();
- form_structure2->DetermineHeuristicTypes();
+ form_structure2->DetermineHeuristicTypes(nullptr, nullptr);
autofill_manager_->AddSeenFormStructure(std::move(form_structure_instance2));
// Make API response with suggestions.
@@ -5111,14 +5228,20 @@ TEST_P(AutofillManagerStructuredProfileTest, OnLoadedServerPredictionsFromApi) {
AutofillQueryResponse::FormSuggestion* form_suggestion;
// Set suggestions for form 1.
form_suggestion = response.add_form_suggestions();
- AddFieldSuggestionToForm(form_suggestion, form.fields[0], ADDRESS_HOME_CITY);
- AddFieldSuggestionToForm(form_suggestion, form.fields[1], ADDRESS_HOME_STATE);
- AddFieldSuggestionToForm(form_suggestion, form.fields[2], ADDRESS_HOME_ZIP);
+ autofill::test::AddFieldSuggestionToForm(form.fields[0], ADDRESS_HOME_CITY,
+ form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(form.fields[1], ADDRESS_HOME_STATE,
+ form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(form.fields[2], ADDRESS_HOME_ZIP,
+ form_suggestion);
// Set suggestions for form 2.
form_suggestion = response.add_form_suggestions();
- AddFieldSuggestionToForm(form_suggestion, form2.fields[0], NAME_LAST);
- AddFieldSuggestionToForm(form_suggestion, form2.fields[1], NAME_MIDDLE);
- AddFieldSuggestionToForm(form_suggestion, form2.fields[2], ADDRESS_HOME_ZIP);
+ autofill::test::AddFieldSuggestionToForm(form2.fields[0], NAME_LAST,
+ form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(form2.fields[1], NAME_MIDDLE,
+ form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(form2.fields[2], ADDRESS_HOME_ZIP,
+ form_suggestion);
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
@@ -5168,7 +5291,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormSignature> signatures =
test::GetEncodedSignatures(*form_structure);
autofill_manager_->AddSeenFormStructure(
@@ -5228,21 +5351,22 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
autofill_manager_->AddSeenFormStructure(
std::unique_ptr<TestFormStructure>(form_structure));
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
- AddFieldSuggestionToForm(form_suggestion, form.fields[0],
- CREDIT_CARD_NAME_FIRST);
- AddFieldSuggestionToForm(form_suggestion, form.fields[1],
- CREDIT_CARD_NAME_LAST);
- AddFieldSuggestionToForm(form_suggestion, form.fields[2], CREDIT_CARD_NUMBER);
- AddFieldSuggestionToForm(form_suggestion, form.fields[3],
- CREDIT_CARD_EXP_MONTH);
- AddFieldSuggestionToForm(form_suggestion, form.fields[4],
- CREDIT_CARD_EXP_4_DIGIT_YEAR);
+ autofill::test::AddFieldSuggestionToForm(
+ form.fields[0], CREDIT_CARD_NAME_FIRST, form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(
+ form.fields[1], CREDIT_CARD_NAME_LAST, form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(form.fields[2], CREDIT_CARD_NUMBER,
+ form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(
+ form.fields[3], CREDIT_CARD_EXP_MONTH, form_suggestion);
+ autofill::test::AddFieldSuggestionToForm(
+ form.fields[4], CREDIT_CARD_EXP_4_DIGIT_YEAR, form_suggestion);
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
@@ -5301,7 +5425,7 @@ TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedServerTypes) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
// Clear the heuristic types, and instead set the appropriate server types.
std::vector<ServerFieldType> heuristic_types, server_types;
@@ -5445,9 +5569,8 @@ TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedWithDefaultValues) {
struct ProfileMatchingTypesTestCase {
const char* input_value; // The value to input in the field.
- std::set<ServerFieldType>
- field_types; // The expected field types to be determined.
- std::set<ServerFieldType>
+ ServerFieldTypeSet field_types; // The expected field types to be determined.
+ ServerFieldTypeSet
structured_field_types; // The expected field types to be determined.
};
@@ -5464,24 +5587,27 @@ class ProfileMatchingTypesTest
InitializeFeatures();
}
- bool StructuredNames() const { return structured_names_enabled_; }
+ bool StructuredNamesAndAddresses() const {
+ return structured_names_and_addresses_;
+ }
void InitializeFeatures();
private:
- bool structured_names_enabled_;
+ bool structured_names_and_addresses_;
base::test::ScopedFeatureList scoped_features_;
};
void ProfileMatchingTypesTest::InitializeFeatures() {
- structured_names_enabled_ = std::get<2>(GetParam());
+ structured_names_and_addresses_ = std::get<2>(GetParam());
- if (structured_names_enabled_) {
- scoped_features_.InitAndEnableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ std::vector<base::Feature> features = {
+ features::kAutofillEnableSupportForMoreStructureInAddresses,
+ features::kAutofillEnableSupportForMoreStructureInNames};
+ if (structured_names_and_addresses_) {
+ scoped_features_.InitWithFeatures(features, {});
} else {
- scoped_features_.InitAndDisableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ scoped_features_.InitWithFeatures({}, features);
}
}
@@ -5495,7 +5621,11 @@ const ProfileMatchingTypesTestCase kProfileMatchingTypesTestCases[] = {
{"theking@gmail.com", {EMAIL_ADDRESS}, {EMAIL_ADDRESS}},
{"RCA", {COMPANY_NAME}, {COMPANY_NAME}},
{"3734 Elvis Presley Blvd.", {ADDRESS_HOME_LINE1}, {ADDRESS_HOME_LINE1}},
- {"Apt. 10", {ADDRESS_HOME_LINE2}, {ADDRESS_HOME_LINE2}},
+ {"3734", {UNKNOWN_TYPE}, {ADDRESS_HOME_HOUSE_NUMBER}},
+ {"Elvis Presley Blvd.", {UNKNOWN_TYPE}, {ADDRESS_HOME_STREET_NAME}},
+ {"Apt. 10",
+ {ADDRESS_HOME_LINE2},
+ {ADDRESS_HOME_LINE2, ADDRESS_HOME_SUBPREMISE}},
{"Memphis", {ADDRESS_HOME_CITY}, {ADDRESS_HOME_CITY}},
{"Tennessee", {ADDRESS_HOME_STATE}, {ADDRESS_HOME_STATE}},
{"38116", {ADDRESS_HOME_ZIP}, {ADDRESS_HOME_ZIP}},
@@ -5607,13 +5737,14 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
"structured_names=%s ",
test_case.input_value,
AutofillType(*test_case.field_types.begin()).ToString().c_str(),
- validity_state, validation_source, StructuredNames() ? "true" : "false"));
+ validity_state, validation_source,
+ StructuredNamesAndAddresses() ? "true" : "false"));
// Take the field types depending on the state of the structured names
// feature.
- const std::set<ServerFieldType>& expected_possible_types =
- StructuredNames() ? test_case.structured_field_types
- : test_case.field_types;
+ const ServerFieldTypeSet& expected_possible_types =
+ StructuredNamesAndAddresses() ? test_case.structured_field_types
+ : test_case.field_types;
ASSERT_LE(AutofillDataModel::UNVALIDATED, validity_state);
ASSERT_LE(validity_state, AutofillDataModel::UNSUPPORTED);
@@ -5640,7 +5771,7 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
// Set the validity state for the matching field type.
for (auto type : expected_possible_types) {
- if (GroupTypeOfServerFieldType(type) != CREDIT_CARD) {
+ if (GroupTypeOfServerFieldType(type) != FieldTypeGroup::kCreditCard) {
for (auto& profile : profiles) {
ASSERT_GT(test_case.field_types.size(), 0U);
if (type == UNKNOWN_TYPE) {
@@ -5666,8 +5797,8 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("", "1", "", "text", &field);
@@ -5687,7 +5818,7 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
for (auto type : expected_possible_types) {
// We don't add validity states for credit card fields.
- if (GroupTypeOfServerFieldType(type) != CREDIT_CARD) {
+ if (GroupTypeOfServerFieldType(type) != FieldTypeGroup::kCreditCard) {
ServerFieldTypeValidityStatesMap possible_types_validities =
form_structure.field(0)->possible_types_validities();
ASSERT_EQ(expected_possible_types.size(),
@@ -5708,8 +5839,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
DeterminePossibleFieldTypesForUpload_IsTriggered) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
std::vector<base::string16> expected_values;
@@ -5811,8 +5942,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
for (const std::vector<TestFieldData>& test_fields : test_cases) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
// Create the form fields specified in the test case.
FormFieldData field;
@@ -6000,8 +6131,8 @@ TEST_P(AutofillManagerStructuredProfileTest, DisambiguateUploadTypes) {
for (const std::vector<TestFieldData>& test_fields : test_cases) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
// Create the form fields specified in the test case.
FormFieldData field;
@@ -6028,12 +6159,13 @@ TEST_P(AutofillManagerStructuredProfileTest, DisambiguateUploadTypes) {
// For structured names it is possible that a field as two out of three
// possible classifications: NAME_FULL, NAME_LAST,
// NAME_LAST_FIRST/SECOND. Note, all cases contain NAME_LAST.
- if (StructuredNames() && possible_types.size() == 2) {
+ if (StructuredNamesAndAddresses() && possible_types.size() == 2) {
EXPECT_TRUE(possible_types.count(NAME_LAST) &&
(possible_types.count(NAME_LAST_SECOND) ||
possible_types.count(NAME_LAST_FIRST) ||
possible_types.count(NAME_FULL)));
- } else if (StructuredNames() && possible_types.size() == 3) {
+ } else if (StructuredNamesAndAddresses() &&
+ possible_types.size() == 3) {
// Or even all three.
EXPECT_TRUE(possible_types.count(NAME_FULL) &&
possible_types.count(NAME_LAST) &&
@@ -6429,8 +6561,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set up our form data (it's already filled out with user data).
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
ServerFieldTypeSet types;
@@ -6485,8 +6617,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set up our form data (it's already filled out with user data).
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
ServerFieldTypeSet types;
@@ -6500,7 +6632,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
types.clear();
- if (StructuredNames())
+ if (StructuredNamesAndAddresses())
types.insert(NAME_LAST_SECOND);
types.insert(NAME_LAST);
expected_types.push_back(types);
@@ -6538,8 +6670,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Set up our form data (empty).
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
@@ -6554,7 +6686,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
types.clear();
- if (StructuredNames())
+ if (StructuredNamesAndAddresses())
types.insert(NAME_LAST_SECOND);
types.insert(NAME_LAST);
expected_types.push_back(types);
@@ -6696,8 +6828,8 @@ TEST_P(AutofillManagerStructuredProfileTest, DontSaveCvcInAutocompleteHistory) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
struct {
const char* label;
@@ -7271,8 +7403,8 @@ TEST_P(AutofillManagerStructuredProfileTest, ShouldUploadForm) {
// scenarios.
FormData form;
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
// Empty Form.
EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
@@ -7362,47 +7494,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
}
}
-// Verify that no suggestions are shown on desktop for non credit card related
-// fields if the initiating field has the "autocomplete" attribute set to off
-// and the feature to autofill all addresses is also off.
-TEST_P(AutofillManagerStructuredProfileTest,
- DisplaySuggestions_AutocompleteOffRespected_AddressField) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(features::kAutofillAlwaysFillAddresses);
-
- // Set up an address form.
- FormData mixed_form;
- mixed_form.name = ASCIIToUTF16("MyForm");
- mixed_form.url = GURL("https://myform.com/form.html");
- mixed_form.action = GURL("https://myform.com/submit.html");
- FormFieldData field;
- test::CreateTestFormField("First name", "firstname", "", "text", &field);
- field.should_autocomplete = false;
- mixed_form.fields.push_back(field);
- test::CreateTestFormField("Last name", "lastname", "", "text", &field);
- field.should_autocomplete = true;
- mixed_form.fields.push_back(field);
- test::CreateTestFormField("Address", "address", "", "text", &field);
- field.should_autocomplete = true;
- mixed_form.fields.push_back(field);
- std::vector<FormData> mixed_forms(1, mixed_form);
- FormsSeen(mixed_forms);
-
- // Suggestions should not be displayed on desktop for this field.
- GetAutofillSuggestions(mixed_form, mixed_form.fields[0]);
- if (IsDesktopPlatform()) {
- EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
- } else {
- EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
- }
-
- // Suggestions should always be displayed for all the other fields.
- for (size_t i = 1U; i < mixed_form.fields.size(); ++i) {
- GetAutofillSuggestions(mixed_form, mixed_form.fields[i]);
- EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
- }
-}
-
// Verify that suggestions are shown on desktop for credit card related fields
// even if the initiating field field has the "autocomplete" attribute set to
// off.
@@ -7442,8 +7533,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
// Create a form with unknown heuristic fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Field 1", "field1", "", "text", &field);
@@ -7454,7 +7545,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.fields.push_back(field);
auto form_structure = std::make_unique<TestFormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
// Make sure the form can not be autofilled now.
ASSERT_EQ(0u, form_structure->autofill_count());
for (size_t idx = 0; idx < form_structure->field_count(); ++idx) {
@@ -7502,8 +7593,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
FormWithLongOptionValuesIsAcceptable) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First name", "firstname", "", "text", &field);
@@ -7583,7 +7674,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
version_info::Channel::UNKNOWN}) {
SCOPED_TRACE(::testing::Message()
<< "Channel " << static_cast<int>(channel));
- EXPECT_CALL(autofill_client_, GetChannel()).WillOnce(Return(channel));
+ // One more call is from TestAutofillManager constructor.
+ EXPECT_CALL(autofill_client_, GetChannel()).WillRepeatedly(Return(channel));
TestAutofillManager test_instance(autofill_driver_.get(), &autofill_client_,
&personal_data_,
autocomplete_history_manager_.get());
@@ -7618,7 +7710,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
SCOPED_TRACE(::testing::Message()
<< "Channel " << static_cast<int>(channel));
EXPECT_FALSE(AutofillManager::IsRichQueryEnabled(channel));
- EXPECT_CALL(autofill_client_, GetChannel()).WillOnce(Return(channel));
+ // One more call is from TestAutofillManager constructor.
+ EXPECT_CALL(autofill_client_, GetChannel()).WillRepeatedly(Return(channel));
TestAutofillManager test_instance(autofill_driver_.get(), &autofill_client_,
&personal_data_,
autocomplete_history_manager_.get());
@@ -7687,8 +7780,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -7732,8 +7825,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -7777,8 +7870,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -7821,8 +7914,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -7865,8 +7958,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -7909,8 +8002,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -7953,8 +8046,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -8006,8 +8099,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -8057,8 +8150,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -8110,8 +8203,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -8161,8 +8254,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -8215,8 +8308,8 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
@@ -8392,8 +8485,9 @@ TEST_F(AutofillManagerTest, DontImportUpiIdWhenIncognito) {
// Tests the vote generation for the address enhancement types.
TEST_F(AutofillManagerTest, PossibleFieldTypesForEnhancementVotes) {
base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillAddressEnhancementVotes);
+ scoped_feature_list.InitWithFeatures(
+ {features::kAutofillAddressEnhancementVotes},
+ {features::kAutofillEnableSupportForMoreStructureInAddresses});
std::vector<AutofillProfile> profiles = {AutofillProfile()};
profiles[0].SetRawInfo(ADDRESS_HOME_STREET_NAME,
@@ -8459,13 +8553,47 @@ TEST_F(AutofillManagerTest, PageLanguageGetsCorrectlySet) {
FormData form;
test::CreateTestAddressFormData(&form);
- // Set up language state mock.
- autofill_client_.GetLanguageState()->SetOriginalLanguage("test_lang");
+ autofill_manager_->OnFormsSeen({form});
+ FormStructure* parsed_form =
+ autofill_manager_->FindCachedFormByRendererId(form.unique_renderer_id);
+
+ ASSERT_TRUE(parsed_form);
+ ASSERT_EQ(LanguageCode(), parsed_form->current_page_language());
- FormStructure* parsed_form = autofill_manager_->ParseFormForTest(form);
+ autofill_client_.GetLanguageState()->SetCurrentLanguage("zh");
+
+ autofill_manager_->OnFormsSeen({form});
+ parsed_form =
+ autofill_manager_->FindCachedFormByRendererId(form.unique_renderer_id);
+
+ ASSERT_EQ(LanguageCode("zh"), parsed_form->current_page_language());
+}
+
+TEST_F(AutofillManagerTest, PageLanguageGetsCorrectlyDetected) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillParsingPatternsLanguageDetection);
+
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+
+ autofill_manager_->OnFormsSeen({form});
+ FormStructure* parsed_form =
+ autofill_manager_->FindCachedFormByRendererId(form.unique_renderer_id);
ASSERT_TRUE(parsed_form);
- ASSERT_EQ("test_lang", parsed_form->page_language());
+ ASSERT_EQ(LanguageCode(), parsed_form->current_page_language());
+
+ translate::LanguageDetectionDetails language_detection_details;
+ language_detection_details.adopted_language = "zh";
+ autofill_manager_->OnLanguageDetermined(language_detection_details);
+
+ autofill_client_.GetLanguageState()->SetCurrentLanguage("zh");
+
+ parsed_form =
+ autofill_manager_->FindCachedFormByRendererId(form.unique_renderer_id);
+
+ ASSERT_EQ(LanguageCode("zh"), parsed_form->current_page_language());
}
// AutofillManagerTest with kAutofillDisabledMixedForms feature enabled.
@@ -8886,7 +9014,7 @@ class OnFocusOnFormFieldTest : public AutofillManagerTest,
}
void CheckSuggestionsAvailableIfScreenReaderRunning() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// The only existing functions for determining whether ChromeVox is in use
// are in the src/chrome directory, which cannot be included in components.
// Thus, if the platform is ChromeOS, we assume that ChromeVox is in use at
@@ -8896,7 +9024,7 @@ class OnFocusOnFormFieldTest : public AutofillManagerTest,
#else
EXPECT_EQ(has_active_screen_reader_,
external_delegate_->has_suggestions_available_on_field_focus());
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void CheckNoSuggestionsAvailableOnFieldFocus() {
@@ -8936,10 +9064,6 @@ TEST_P(OnFocusOnFormFieldTest, AddressSuggestions) {
}
TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffNotRespected) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillAlwaysFillAddresses);
-
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
@@ -8960,34 +9084,6 @@ TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffNotRespected) {
CheckSuggestionsAvailableIfScreenReaderRunning();
}
-TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffRespected) {
- if (!IsDesktopPlatform())
- return;
-
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kAutofillAlwaysFillAddresses);
-
- FormData form;
- form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("https://myform.com/form.html");
- form.action = GURL("https://myform.com/submit.html");
- FormFieldData field;
- // Set a valid autocomplete attribute for the first name.
- test::CreateTestFormField("First name", "firstname", "", "text", &field);
- field.autocomplete_attribute = "given-name";
- form.fields.push_back(field);
- // Set an autocomplete=off attribute for the last name.
- test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
- field.should_autocomplete = false;
- form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[1], gfx::RectF());
- CheckNoSuggestionsAvailableOnFieldFocus();
-}
-
TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_SecureContext) {
// Set up our form data.
FormData form;
diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
index 53593fd85bd..1602cab0588 100644
--- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -76,10 +76,9 @@ const std::vector<base::FilePath> GetTestFiles() {
base::FilePath dir = GetTestDataDir();
bool structured_names = base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames);
- dir =
- dir.AppendASCII("autofill")
- .AppendASCII(structured_names ? "merge_structured_names" : "merge")
- .AppendASCII("input");
+ dir = dir.AppendASCII("autofill")
+ .AppendASCII(structured_names ? "merge_structured_names" : "merge")
+ .AppendASCII("input");
base::FileEnumerator input_files(dir, false, base::FileEnumerator::FILES,
kFileNamePattern);
std::vector<base::FilePath> files;
@@ -104,7 +103,7 @@ std::string SerializeProfiles(const std::vector<AutofillProfile*>& profiles) {
result += "\n";
for (const ServerFieldType& type : kProfileFieldTypes) {
base::string16 value = profiles[i]->GetRawInfo(type);
- result += AutofillType(type).ToString();
+ result += AutofillType::ServerFieldTypeToString(type);
result += kFieldSeparator;
if (!value.empty()) {
base::ReplaceFirstSubstringAfterOffset(
@@ -208,12 +207,19 @@ class AutofillMergeTest : public DataDrivenTest,
AutofillMergeTest::AutofillMergeTest() : DataDrivenTest(GetTestDataDir()) {
CountryNames::SetLocaleString("en-US");
for (size_t i = NO_SERVER_DATA; i < MAX_VALID_FIELD_TYPE; ++i) {
+ // Some ServerFieldTypes are deprecated and removed from the enum
+ // definition.
+ if ((i >= 15 && i <= 19) || (i >= 25 && i <= 29) || (i >= 44 && i <= 50) ||
+ (i == 94)) {
+ continue;
+ }
ServerFieldType field_type = static_cast<ServerFieldType>(i);
- string_to_field_type_map_[AutofillType(field_type).ToString()] = field_type;
+ string_to_field_type_map_[AutofillType::ServerFieldTypeToString(
+ field_type)] = field_type;
}
}
-AutofillMergeTest::~AutofillMergeTest() {}
+AutofillMergeTest::~AutofillMergeTest() = default;
void AutofillMergeTest::SetUp() {
test::DisableSystemServices(nullptr);
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index 1f74c2b7180..0aa01bd33cb 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -26,7 +26,7 @@
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/language_usage_metrics/language_usage_metrics.h"
+#include "components/language/core/browser/language_usage_metrics.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
@@ -37,10 +37,11 @@ using mojom::SubmissionSource;
namespace {
// Exponential bucket spacing for UKM event data.
-const double kAutofillEventDataBucketSpacing = 2.0;
+constexpr double kAutofillEventDataBucketSpacing = 2.0;
// Note: if adding an enum value here, update the corresponding description for
-// AutofillTypeQualityByFieldType in histograms.xml.
+// AutofillFieldPredictionQualityByFieldType in
+// tools/metrics/histograms/enums.xml.
enum FieldTypeGroupForMetrics {
GROUP_AMBIGUOUS = 0,
GROUP_NAME,
@@ -69,6 +70,16 @@ enum FieldTypeGroupForMetrics {
GROUP_STREET_ADDRESS,
GROUP_CREDIT_CARD_VERIFICATION,
GROUP_UNFILLABLE,
+ GROUP_ADDRESS_HOME_APT_NUM,
+ GROUP_ADDRESS_HOME_SORTING_CODE,
+ GROUP_ADDRESS_HOME_DEPENDENT_LOCALITY,
+ GROUP_ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
+ GROUP_ADDRESS_HOME_OTHER_SUBUNIT,
+ GROUP_ADDRESS_HOME_ADDRESS,
+ GROUP_ADDRESS_HOME_ADDRESS_WITH_NAME,
+ GROUP_ADDRESS_HOME_FLOOR,
+ GROUP_UNKNOWN_TYPE,
+ // Add new entries here and update enums.xml.
NUM_FIELD_TYPE_GROUPS_FOR_METRICS
};
@@ -99,9 +110,9 @@ std::string PreviousSaveCreditCardPromptUserDecisionToString(
// Returns the interpolated index.
//
// The interpolation maps the pair (|group|, |metric|) to a single index, so
-// that all the indicies for a given group are adjacent. In particular, with
-// the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH,
-// MISMATCH}, we create this set of mapped indices:
+// that all the indices for a given group are adjacent. In particular, with
+// the groups {AMBIGUOUS, NAME, ...} combining with the metrics
+// {UNKNOWN, MATCH, MISMATCH}, we create this set of mapped indices:
// {
// AMBIGUOUS+UNKNOWN,
// AMBIGUOUS+MATCH,
@@ -125,21 +136,21 @@ int GetFieldTypeGroupPredictionQualityMetric(
FieldTypeGroupForMetrics group = GROUP_AMBIGUOUS;
switch (AutofillType(field_type).group()) {
- case NO_GROUP:
+ case FieldTypeGroup::kNoGroup:
group = GROUP_AMBIGUOUS;
break;
- case NAME:
- case NAME_BILLING:
+ case FieldTypeGroup::kName:
+ case FieldTypeGroup::kNameBilling:
group = GROUP_NAME;
break;
- case COMPANY:
+ case FieldTypeGroup::kCompany:
group = GROUP_COMPANY;
break;
- case ADDRESS_HOME:
- case ADDRESS_BILLING:
+ case FieldTypeGroup::kAddressHome:
+ case FieldTypeGroup::kAddressBilling:
switch (AutofillType(field_type).GetStorableType()) {
case ADDRESS_HOME_LINE1:
group = GROUP_ADDRESS_LINE_1;
@@ -150,6 +161,9 @@ int GetFieldTypeGroupPredictionQualityMetric(
case ADDRESS_HOME_LINE3:
group = GROUP_ADDRESS_LINE_3;
break;
+ case ADDRESS_HOME_APT_NUM:
+ group = GROUP_ADDRESS_HOME_APT_NUM;
+ break;
case ADDRESS_HOME_STREET_ADDRESS:
group = GROUP_STREET_ADDRESS;
break;
@@ -168,6 +182,12 @@ int GetFieldTypeGroupPredictionQualityMetric(
case ADDRESS_HOME_STREET_NAME:
group = GROUP_ADDRESS_HOME_STREET_NAME;
break;
+ case ADDRESS_HOME_SORTING_CODE:
+ group = GROUP_ADDRESS_HOME_SORTING_CODE;
+ break;
+ case ADDRESS_HOME_DEPENDENT_LOCALITY:
+ group = GROUP_ADDRESS_HOME_DEPENDENT_LOCALITY;
+ break;
case ADDRESS_HOME_DEPENDENT_STREET_NAME:
group = GROUP_ADDRESS_HOME_DEPENDENT_STREET_NAME;
break;
@@ -177,26 +197,122 @@ int GetFieldTypeGroupPredictionQualityMetric(
case ADDRESS_HOME_PREMISE_NAME:
group = GROUP_ADDRESS_HOME_PREMISE_NAME;
break;
+ case ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME:
+ group = GROUP_ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME;
+ break;
case ADDRESS_HOME_SUBPREMISE:
group = GROUP_ADDRESS_HOME_SUBPREMISE;
break;
- default:
- NOTREACHED() << field_type << " has no group assigned (ambiguous)";
+ case ADDRESS_HOME_OTHER_SUBUNIT:
+ group = GROUP_ADDRESS_HOME_OTHER_SUBUNIT;
+ break;
+ case ADDRESS_HOME_ADDRESS:
+ group = GROUP_ADDRESS_HOME_ADDRESS;
+ break;
+ case ADDRESS_HOME_ADDRESS_WITH_NAME:
+ group = GROUP_ADDRESS_HOME_ADDRESS_WITH_NAME;
+ break;
+ case ADDRESS_HOME_FLOOR:
+ group = GROUP_ADDRESS_HOME_FLOOR;
+ break;
+ case UNKNOWN_TYPE:
+ group = GROUP_UNKNOWN_TYPE;
+ break;
+ case NO_SERVER_DATA:
+ case EMPTY_TYPE:
+ case NAME_FIRST:
+ case NAME_MIDDLE:
+ case NAME_LAST:
+ case NAME_MIDDLE_INITIAL:
+ case NAME_FULL:
+ case NAME_SUFFIX:
+ case EMAIL_ADDRESS:
+ case PHONE_HOME_NUMBER:
+ case PHONE_HOME_CITY_CODE:
+ case PHONE_HOME_COUNTRY_CODE:
+ case PHONE_HOME_CITY_AND_NUMBER:
+ case PHONE_HOME_WHOLE_NUMBER:
+ case PHONE_FAX_NUMBER:
+ case PHONE_FAX_CITY_CODE:
+ case PHONE_FAX_COUNTRY_CODE:
+ case PHONE_FAX_CITY_AND_NUMBER:
+ case PHONE_FAX_WHOLE_NUMBER:
+ case ADDRESS_BILLING_LINE1:
+ case ADDRESS_BILLING_LINE2:
+ case ADDRESS_BILLING_APT_NUM:
+ case ADDRESS_BILLING_CITY:
+ case ADDRESS_BILLING_STATE:
+ case ADDRESS_BILLING_ZIP:
+ case ADDRESS_BILLING_COUNTRY:
+ case CREDIT_CARD_NAME_FULL:
+ case CREDIT_CARD_NUMBER:
+ case CREDIT_CARD_EXP_MONTH:
+ case CREDIT_CARD_EXP_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_4_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+ case CREDIT_CARD_TYPE:
+ case CREDIT_CARD_VERIFICATION_CODE:
+ case COMPANY_NAME:
+ case FIELD_WITH_DEFAULT_VALUE:
+ case PHONE_BILLING_NUMBER:
+ case PHONE_BILLING_CITY_CODE:
+ case PHONE_BILLING_COUNTRY_CODE:
+ case PHONE_BILLING_CITY_AND_NUMBER:
+ case PHONE_BILLING_WHOLE_NUMBER:
+ case NAME_BILLING_FIRST:
+ case NAME_BILLING_MIDDLE:
+ case NAME_BILLING_LAST:
+ case NAME_BILLING_MIDDLE_INITIAL:
+ case NAME_BILLING_FULL:
+ case NAME_BILLING_SUFFIX:
+ case MERCHANT_EMAIL_SIGNUP:
+ case MERCHANT_PROMO_CODE:
+ case PASSWORD:
+ case ACCOUNT_CREATION_PASSWORD:
+ case ADDRESS_BILLING_STREET_ADDRESS:
+ case ADDRESS_BILLING_SORTING_CODE:
+ case ADDRESS_BILLING_DEPENDENT_LOCALITY:
+ case ADDRESS_BILLING_LINE3:
+ case NOT_ACCOUNT_CREATION_PASSWORD:
+ case USERNAME:
+ case USERNAME_AND_EMAIL_ADDRESS:
+ case NEW_PASSWORD:
+ case PROBABLY_NEW_PASSWORD:
+ case NOT_NEW_PASSWORD:
+ case CREDIT_CARD_NAME_FIRST:
+ case CREDIT_CARD_NAME_LAST:
+ case PHONE_HOME_EXTENSION:
+ case CONFIRMATION_PASSWORD:
+ case AMBIGUOUS_TYPE:
+ case SEARCH_TERM:
+ case PRICE:
+ case NOT_PASSWORD:
+ case SINGLE_USERNAME:
+ case NOT_USERNAME:
+ case UPI_VPA:
+ case NAME_LAST_FIRST:
+ case NAME_LAST_CONJUNCTION:
+ case NAME_LAST_SECOND:
+ case NAME_HONORIFIC_PREFIX:
+ case NAME_FULL_WITH_HONORIFIC_PREFIX:
+ case MAX_VALID_FIELD_TYPE:
+ NOTREACHED() << field_type << " type is not in that group.";
group = GROUP_AMBIGUOUS;
break;
}
break;
- case EMAIL:
+ case FieldTypeGroup::kEmail:
group = GROUP_EMAIL;
break;
- case PHONE_HOME:
- case PHONE_BILLING:
+ case FieldTypeGroup::kPhoneHome:
+ case FieldTypeGroup::kPhoneBilling:
group = GROUP_PHONE;
break;
- case CREDIT_CARD:
+ case FieldTypeGroup::kCreditCard:
switch (field_type) {
case CREDIT_CARD_NAME_FULL:
case CREDIT_CARD_NAME_FIRST:
@@ -226,19 +342,19 @@ int GetFieldTypeGroupPredictionQualityMetric(
}
break;
- case PASSWORD_FIELD:
+ case FieldTypeGroup::kPasswordField:
group = GROUP_PASSWORD;
break;
- case USERNAME_FIELD:
+ case FieldTypeGroup::kUsernameField:
group = GROUP_USERNAME;
break;
- case UNFILLABLE:
+ case FieldTypeGroup::kUnfillable:
group = GROUP_UNFILLABLE;
break;
- case TRANSACTION:
+ case FieldTypeGroup::kTransaction:
NOTREACHED();
break;
}
@@ -346,7 +462,8 @@ ServerFieldType GetActualFieldType(const ServerFieldTypeSet& possible_types,
if (collapsed_field_types.size() == 1)
actual_type = *collapsed_field_types.begin();
- DVLOG(2) << "Inferred Type: " << AutofillType(actual_type).ToString();
+ DVLOG(2) << "Inferred Type: "
+ << AutofillType::ServerFieldTypeToString(actual_type);
return actual_type;
}
@@ -553,8 +670,9 @@ void LogPredictionQualityMetrics(
ServerFieldType actual_type =
GetActualFieldType(possible_types, predicted_type);
- DVLOG(2) << "Predicted: " << AutofillType(predicted_type).ToString() << "; "
- << "Actual: " << AutofillType(actual_type).ToString();
+ DVLOG(2) << "Predicted: "
+ << AutofillType::ServerFieldTypeToString(predicted_type) << "; "
+ << "Actual: " << AutofillType::ServerFieldTypeToString(actual_type);
DCHECK_LE(predicted_type, UINT16_MAX);
DCHECK_LE(actual_type, UINT16_MAX);
@@ -850,77 +968,6 @@ void AutofillMetrics::LogSaveCardPromptResultMetric(
}
// static
-void AutofillMetrics::LogSaveCardPromptMetric(
- SaveCardPromptMetric metric,
- bool is_uploading,
- bool is_reshow,
- AutofillClient::SaveCreditCardOptions options,
- int previous_save_credit_card_prompt_user_decision,
- security_state::SecurityLevel security_level,
- AutofillSyncSigninState sync_state) {
- DCHECK_LT(metric, NUM_SAVE_CARD_PROMPT_METRICS);
- std::string destination = is_uploading ? ".Upload" : ".Local";
- std::string show = is_reshow ? ".Reshows" : ".FirstShow";
- std::string metric_with_destination_and_show =
- "Autofill.SaveCreditCardPrompt" + destination + show;
- base::UmaHistogramEnumeration(metric_with_destination_and_show, metric,
- NUM_SAVE_CARD_PROMPT_METRICS);
- base::UmaHistogramEnumeration(
- metric_with_destination_and_show + GetMetricsSyncStateSuffix(sync_state),
- metric, NUM_SAVE_CARD_PROMPT_METRICS);
- if (options.should_request_name_from_user) {
- base::UmaHistogramEnumeration(
- metric_with_destination_and_show + ".RequestingCardholderName", metric,
- NUM_SAVE_CARD_PROMPT_METRICS);
- }
- if (options.should_request_expiration_date_from_user) {
- base::UmaHistogramEnumeration(
- metric_with_destination_and_show + ".RequestingExpirationDate", metric,
- NUM_SAVE_CARD_PROMPT_METRICS);
- }
- if (options.has_non_focusable_field) {
- base::UmaHistogramEnumeration(
- metric_with_destination_and_show + ".FromNonFocusableForm", metric,
- NUM_SAVE_CARD_PROMPT_METRICS);
- }
- if (options.from_dynamic_change_form) {
- base::UmaHistogramEnumeration(
- metric_with_destination_and_show + ".FromDynamicChangeForm", metric,
- NUM_SAVE_CARD_PROMPT_METRICS);
- }
- base::UmaHistogramEnumeration(
- metric_with_destination_and_show +
- PreviousSaveCreditCardPromptUserDecisionToString(
- previous_save_credit_card_prompt_user_decision),
- metric, NUM_SAVE_CARD_PROMPT_METRICS);
-
- LogSaveCardPromptMetricBySecurityLevel(metric, is_uploading, security_level);
-}
-
-// static
-void AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- SaveCardPromptMetric metric,
- bool is_uploading,
- security_state::SecurityLevel security_level) {
- // Getting a SECURITY_LEVEL_COUNT security level means that it was not
- // possible to get the real security level. Don't log.
- if (security_level == security_state::SecurityLevel::SECURITY_LEVEL_COUNT) {
- return;
- }
-
- std::string histogram_name = "Autofill.SaveCreditCardPrompt.";
- if (is_uploading) {
- histogram_name += "Upload";
- } else {
- histogram_name += "Local";
- }
-
- base::UmaHistogramEnumeration(security_state::GetSecurityLevelHistogramName(
- histogram_name, security_level),
- metric, NUM_SAVE_CARD_PROMPT_METRICS);
-}
-
-// static
void AutofillMetrics::LogCreditCardUploadLegalMessageLinkClicked() {
base::RecordAction(base::UserMetricsAction(
"Autofill_CreditCardUpload_LegalMessageLinkClicked"));
@@ -981,19 +1028,6 @@ void AutofillMetrics::LogLocalCardMigrationBubbleOfferMetric(
}
// static
-void AutofillMetrics::LogLocalCardMigrationBubbleUserInteractionMetric(
- LocalCardMigrationBubbleUserInteractionMetric metric,
- bool is_reshow) {
- DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_BUBBLE_USER_INTERACTION_METRICS);
- std::string histogram_name =
- "Autofill.LocalCardMigrationBubbleUserInteraction.";
- histogram_name += is_reshow ? "Reshows" : "FirstShow";
- base::UmaHistogramEnumeration(
- histogram_name, metric,
- NUM_LOCAL_CARD_MIGRATION_BUBBLE_USER_INTERACTION_METRICS);
-}
-
-// static
void AutofillMetrics::LogLocalCardMigrationBubbleResultMetric(
LocalCardMigrationBubbleResultMetric metric,
bool is_reshow) {
@@ -1080,6 +1114,43 @@ void AutofillMetrics::LogLocalCardMigrationPromptMetric(
}
// static
+void AutofillMetrics::LogOfferNotificationBubbleOfferMetric(bool is_reshow) {
+ base::UmaHistogramBoolean(
+ "Autofill.OfferNotificationBubbleOffer.CardLinkedOffer", is_reshow);
+}
+
+// static
+void AutofillMetrics::LogOfferNotificationBubbleResultMetric(
+ OfferNotificationBubbleResultMetric metric,
+ bool is_reshow) {
+ DCHECK_LE(metric, OfferNotificationBubbleResultMetric::kMaxValue);
+ static const char first_show[] =
+ "Autofill.OfferNotificationBubbleResult.CardLinkedOffer.FirstShow";
+ static const char reshows[] =
+ "Autofill.OfferNotificationBubbleResult.CardLinkedOffer.Reshows";
+ base::UmaHistogramEnumeration(is_reshow ? reshows : first_show, metric);
+}
+
+// static
+void AutofillMetrics::LogOfferNotificationInfoBarDeepLinkClicked() {
+ base::RecordAction(base::UserMetricsAction(
+ "Autofill_OfferNotificationInfoBar_DeepLinkClicked"));
+}
+
+// static
+void AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
+ OfferNotificationInfoBarResultMetric metric) {
+ DCHECK_LE(metric, OfferNotificationInfoBarResultMetric::kMaxValue);
+ base::UmaHistogramEnumeration(
+ "Autofill.OfferNotificationInfoBarResult.CardLinkedOffer", metric);
+}
+
+void AutofillMetrics::LogOfferNotificationInfoBarShown() {
+ base::UmaHistogramBoolean(
+ "Autofill.OfferNotificationInfoBarOffer.CardLinkedOffer", true);
+}
+
+// static
void AutofillMetrics::LogSaveCardWithFirstAndLastNameOffered(bool is_local) {
std::string histogram_name = "Autofill.SaveCardWithFirstAndLastNameOffered.";
histogram_name += is_local ? "Local" : "Server";
@@ -1452,14 +1523,14 @@ void AutofillMetrics::LogEditedAutofilledFieldAtSubmission(
field.Type().GetStorableType(), editing_metric));
// Record the UMA statistics spliced by the autocomplete attribute value.
- FormType form_type =
- FormTypes::FieldTypeGroupToFormType(field.Type().group());
- if (form_type == ADDRESS_FORM || form_type == CREDIT_CARD_FORM) {
+ FormType form_type = FieldTypeGroupToFormType(field.Type().group());
+ if (form_type == FormType::kAddressForm ||
+ form_type == FormType::kCreditCardForm) {
bool autocomplete_off = field.autocomplete_attribute == "off";
const std::string autocomplete_histogram = base::StrCat(
{"Autofill.Autocomplete.", autocomplete_off ? "Off" : "NotOff",
".EditedAutofilledFieldAtSubmission.",
- form_type == ADDRESS_FORM ? "Address" : "CreditCard"});
+ form_type == FormType::kAddressForm ? "Address" : "CreditCard"});
base::UmaHistogramEnumeration(autocomplete_histogram, editing_metric);
}
@@ -1484,42 +1555,45 @@ void AutofillMetrics::LogUserHappinessMetric(
FieldTypeGroup field_type_group,
security_state::SecurityLevel security_level,
uint32_t profile_form_bitmask) {
- LogUserHappinessMetric(
- metric, {FormTypes::FieldTypeGroupToFormType(field_type_group)},
- security_level, profile_form_bitmask);
+ LogUserHappinessMetric(metric, {FieldTypeGroupToFormType(field_type_group)},
+ security_level, profile_form_bitmask);
}
// static
void AutofillMetrics::LogUserHappinessMetric(
UserHappinessMetric metric,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
security_state::SecurityLevel security_level,
uint32_t profile_form_bitmask) {
DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS);
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
NUM_USER_HAPPINESS_METRICS);
- if (base::Contains(form_types, CREDIT_CARD_FORM)) {
+ if (base::Contains(form_types, FormType::kCreditCardForm)) {
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.CreditCard", metric,
NUM_USER_HAPPINESS_METRICS);
- LogUserHappinessBySecurityLevel(metric, CREDIT_CARD_FORM, security_level);
+ LogUserHappinessBySecurityLevel(metric, FormType::kCreditCardForm,
+ security_level);
}
- if (base::Contains(form_types, ADDRESS_FORM)) {
+ if (base::Contains(form_types, FormType::kAddressForm)) {
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.Address", metric,
NUM_USER_HAPPINESS_METRICS);
if (metric != AutofillMetrics::FORMS_LOADED) {
LogUserHappinessByProfileFormType(metric, profile_form_bitmask);
}
- LogUserHappinessBySecurityLevel(metric, ADDRESS_FORM, security_level);
+ LogUserHappinessBySecurityLevel(metric, FormType::kAddressForm,
+ security_level);
}
- if (base::Contains(form_types, PASSWORD_FORM)) {
+ if (base::Contains(form_types, FormType::kPasswordForm)) {
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.Password", metric,
NUM_USER_HAPPINESS_METRICS);
- LogUserHappinessBySecurityLevel(metric, PASSWORD_FORM, security_level);
+ LogUserHappinessBySecurityLevel(metric, FormType::kPasswordForm,
+ security_level);
}
- if (base::Contains(form_types, UNKNOWN_FORM_TYPE)) {
+ if (base::Contains(form_types, FormType::kUnknownFormType)) {
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.Unknown", metric,
NUM_USER_HAPPINESS_METRICS);
- LogUserHappinessBySecurityLevel(metric, UNKNOWN_FORM_TYPE, security_level);
+ LogUserHappinessBySecurityLevel(metric, FormType::kUnknownFormType,
+ security_level);
}
}
@@ -1534,19 +1608,19 @@ void AutofillMetrics::LogUserHappinessBySecurityLevel(
std::string histogram_name = "Autofill.UserHappiness.";
switch (form_type) {
- case CREDIT_CARD_FORM:
+ case FormType::kCreditCardForm:
histogram_name += "CreditCard";
break;
- case ADDRESS_FORM:
+ case FormType::kAddressForm:
histogram_name += "Address";
break;
- case PASSWORD_FORM:
+ case FormType::kPasswordForm:
histogram_name += "Password";
break;
- case UNKNOWN_FORM_TYPE:
+ case FormType::kUnknownFormType:
histogram_name += "Unknown";
break;
@@ -1592,7 +1666,7 @@ void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
// static
void AutofillMetrics::LogFormFillDurationFromInteraction(
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
bool used_autofill,
const base::TimeDelta& duration) {
std::string parent_metric;
@@ -1602,16 +1676,16 @@ void AutofillMetrics::LogFormFillDurationFromInteraction(
parent_metric = "Autofill.FillDuration.FromInteraction.WithoutAutofill";
}
LogFormFillDuration(parent_metric, duration);
- if (base::Contains(form_types, CREDIT_CARD_FORM)) {
+ if (base::Contains(form_types, FormType::kCreditCardForm)) {
LogFormFillDuration(parent_metric + ".CreditCard", duration);
}
- if (base::Contains(form_types, ADDRESS_FORM)) {
+ if (base::Contains(form_types, FormType::kAddressForm)) {
LogFormFillDuration(parent_metric + ".Address", duration);
}
- if (base::Contains(form_types, PASSWORD_FORM)) {
+ if (base::Contains(form_types, FormType::kPasswordForm)) {
LogFormFillDuration(parent_metric + ".Password", duration);
}
- if (base::Contains(form_types, UNKNOWN_FORM_TYPE)) {
+ if (base::Contains(form_types, FormType::kUnknownFormType)) {
LogFormFillDuration(parent_metric + ".Unknown", duration);
}
}
@@ -1926,7 +2000,7 @@ void AutofillMetrics::LogAutofillFormSubmittedState(
AutofillFormSubmittedState state,
bool is_for_credit_card,
bool has_upi_vpa_field,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
@@ -2107,7 +2181,7 @@ void AutofillMetrics::LogDeveloperEngagementUkm(
ukm::SourceId source_id,
const GURL& url,
bool is_for_credit_card,
- std::set<FormType> form_types,
+ DenseSet<FormType> form_types,
int developer_engagement_metrics,
FormSignature form_signature) {
DCHECK(developer_engagement_metrics);
@@ -2313,7 +2387,7 @@ void AutofillMetrics::FormInteractionsUkmLogger::
}
int64_t AutofillMetrics::FormTypesToBitVector(
- const std::set<FormType>& form_types) {
+ const DenseSet<FormType>& form_types) {
int64_t form_type_bv = 0;
for (const FormType& form_type : form_types) {
DCHECK_LT(static_cast<int64_t>(form_type), 63);
@@ -2366,7 +2440,7 @@ const char* AutofillMetrics::GetMetricsSyncStateSuffix(
void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
bool is_for_credit_card,
bool has_upi_vpa_field,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
AutofillFormSubmittedState state,
const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature) {
@@ -2392,7 +2466,7 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
void AutofillMetrics::FormInteractionsUkmLogger::LogFormEvent(
FormEvent form_event,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
return;
@@ -2481,7 +2555,7 @@ void AutofillMetrics::LogFieldParsingTranslatedFormLanguageMetric(
base::StringPiece locale) {
base::UmaHistogramSparse(
"Autofill.ParsedFieldTypesUsingTranslatedPageLanguage",
- language_usage_metrics::LanguageUsageMetrics::ToLanguageCode(locale));
+ language::LanguageUsageMetrics::ToLanguageCode(locale));
}
// static
@@ -2498,4 +2572,18 @@ void AutofillMetrics::LogWebOTPPhoneCollectionMetricStateUkm(
builder.Record(recorder);
}
+// static
+void AutofillMetrics::LogNumberOfAutofilledFieldsAtSubmission(
+ size_t number_of_accepted_fields,
+ size_t number_of_corrected_fields) {
+ base::UmaHistogramExactLinear(
+ "Autofill.NumberOfAutofilledFieldsAtSubmission.Total",
+ number_of_accepted_fields + number_of_corrected_fields, 50);
+ base::UmaHistogramExactLinear(
+ "Autofill.NumberOfAutofilledFieldsAtSubmission.Accepted",
+ number_of_accepted_fields, 50);
+ base::UmaHistogramExactLinear(
+ "Autofill.NumberOfAutofilledFieldsAtSubmission.Corrected",
+ number_of_corrected_fields, 50);
+}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index b7213dc6318..b2c0772525a 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -22,6 +22,7 @@
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/browser/ui/popup_types.h"
+#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/signatures.h"
@@ -261,67 +262,34 @@ class AutofillMetrics {
NUM_SAVE_CARD_PROMPT_RESULT_METRICS,
};
- // Metrics to measure user interaction with the save credit card prompt.
- //
- // SAVE_CARD_PROMPT_DISMISS_FOCUS is not stored explicitly, but can be
- // inferred from the other metrics:
- // SAVE_CARD_PROMPT_DISMISS_FOCUS = SHOW_REQUESTED - END_* - DISMISS_*
- enum SaveCardPromptMetric {
- // Prompt was requested to be shown due to:
- // CC info being submitted (first show), or
- // location bar icon being clicked while bubble is hidden (reshows).
- SAVE_CARD_PROMPT_SHOW_REQUESTED,
- // The prompt was shown successfully.
- SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
- // The prompt was not shown because the legal message was invalid.
- SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE,
- // The user explicitly accepted the prompt.
- SAVE_CARD_PROMPT_END_ACCEPTED,
- // The user explicitly denied the prompt.
- SAVE_CARD_PROMPT_END_DENIED,
- // The prompt and icon were removed because of navigation away from the
- // page that caused the prompt to be shown. The navigation occurred while
- // the prompt was showing.
- SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING,
- // The prompt and icon were removed because of navigation away from the
- // page that caused the prompt to be shown. The navigation occurred while
- // the prompt was hidden.
- SAVE_CARD_PROMPT_END_NAVIGATION_HIDDEN,
- // The prompt was dismissed because the user clicked the "Learn more" link.
- // Deprecated.
- DEPRECATED_SAVE_CARD_PROMPT_DISMISS_CLICK_LEARN_MORE,
- // The prompt was dismissed because the user clicked a legal message link.
- SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE,
-
- // The following _CVC_FIX_FLOW_ metrics are independent of the ones above,
- // and were relevant when the CVC fix flow was active M62-M64. During that
- // time, for instance, accepting the CVC fix flow would trigger both
- // SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_ACCEPTED as well as
- // SAVE_CARD_PROMPT_END_ACCEPTED. They were split apart in order to track
- // acceptance/abandonment rates of the multi-stage dialog user experience.
- // (SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_DENIED was an impossible state because
- // the CVC fix flow uses a close button instead of a cancel button.)
-
- // The prompt moved to a second stage that requested CVC from the user.
- SAVE_CARD_PROMPT_CVC_FIX_FLOW_SHOWN,
- // The user explicitly entered CVC and accepted the prompt.
- SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_ACCEPTED,
- // The prompt and icon were removed because of navigation away from the page
- // that caused the prompt to be shown. The navigation occurred while the
- // prompt was showing, at the CVC request stage.
- SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_NAVIGATION_SHOWING,
- // The prompt and icon were removed because of navigation away from the page
- // that caused the prompt to be shown. The navigation occurred while the
- // prompt was hidden, at the CVC request stage.
- SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_NAVIGATION_HIDDEN,
- // The prompt was dismissed because the user clicked a legal message link.
- SAVE_CARD_PROMPT_CVC_FIX_FLOW_DISMISS_CLICK_LEGAL_MESSAGE,
-
- // The save card bubble was not shown due to the card having too many
- // offer-to-save strikes, but the omnibox icon was still displayed.
- SAVE_CARD_ICON_SHOWN_WITHOUT_PROMPT,
-
- NUM_SAVE_CARD_PROMPT_METRICS,
+ // Metrics to track event when the offer notification bubble is closed.
+ enum class OfferNotificationBubbleResultMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The user explicitly acknowledged the bubble by clicking the ok button.
+ OFFER_NOTIFICATION_BUBBLE_ACKNOWLEDGED = 0,
+ // The user explicitly closed the prompt with the close button or ESC.
+ OFFER_NOTIFICATION_BUBBLE_CLOSED = 1,
+ // The user did not interact with the prompt.
+ OFFER_NOTIFICATION_BUBBLE_NOT_INTERACTED = 2,
+ // The prompt lost focus and was deactivated.
+ OFFER_NOTIFICATION_BUBBLE_LOST_FOCUS = 3,
+ kMaxValue = OFFER_NOTIFICATION_BUBBLE_LOST_FOCUS,
+ };
+
+ // Metrics to track event when the offer notification infobar is closed.
+ enum class OfferNotificationInfoBarResultMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // User acknowledged the infobar by clicking the ok button.
+ OFFER_NOTIFICATION_INFOBAR_ACKNOWLEDGED = 0,
+ // User explicitly closed the infobar with the close button.
+ OFFER_NOTIFICATION_INFOBAR_CLOSED = 1,
+ // InfoBar was shown but user did not interact with the it.
+ OFFER_NOTIFICATION_INFOBAR_IGNORED = 2,
+ kMaxValue = OFFER_NOTIFICATION_INFOBAR_IGNORED,
};
enum CreditCardUploadFeedbackMetric {
@@ -543,23 +511,6 @@ class AutofillMetrics {
NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS,
};
- // Metrics to track user interactions with the bubble.
- // TODO(crbug.com/1070799): Remove this enum once the old logging is cleaned
- // up.
- enum LocalCardMigrationBubbleUserInteractionMetric {
- // The user explicitly accepts the offer.
- LOCAL_CARD_MIGRATION_BUBBLE_CLOSED_ACCEPTED = 0,
- // The user explicitly denies the offer (clicks the cancel button).
- LOCAL_CARD_MIGRATION_BUBBLE_CLOSED_DENIED = 1,
- // The bubble is closed due to user navigating away from the page
- // while the bubble was showing.
- LOCAL_CARD_MIGRATION_BUBBLE_CLOSED_NAVIGATED_WHILE_SHOWING = 2,
- // The bubble is closed due to user navigating away from the page
- // while the bubble was hidden.
- LOCAL_CARD_MIGRATION_BUBBLE_CLOSED_NAVIGATED_WHILE_HIDDEN = 3,
- NUM_LOCAL_CARD_MIGRATION_BUBBLE_USER_INTERACTION_METRICS,
- };
-
// Metrics to track user action result of the bubble when the bubble is
// closed.
enum LocalCardMigrationBubbleResultMetric {
@@ -1059,12 +1010,12 @@ class AutofillMetrics {
ServerFieldType actual_type);
void LogFormSubmitted(bool is_for_credit_card,
bool has_upi_vpa_field,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
AutofillFormSubmittedState state,
const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature);
void LogFormEvent(FormEvent form_event,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp);
// Log whether the autofill decided to skip or to fill each
@@ -1171,18 +1122,6 @@ class AutofillMetrics {
int previous_save_credit_card_prompt_user_decision,
security_state::SecurityLevel security_level,
AutofillSyncSigninState sync_state);
- static void LogSaveCardPromptMetric(
- SaveCardPromptMetric metric,
- bool is_uploading,
- bool is_reshow,
- AutofillClient::SaveCreditCardOptions options,
- int previous_save_credit_card_prompt_user_decision,
- security_state::SecurityLevel security_level,
- AutofillSyncSigninState sync_state);
- static void LogSaveCardPromptMetricBySecurityLevel(
- SaveCardPromptMetric metric,
- bool is_uploading,
- security_state::SecurityLevel security_level);
static void LogCreditCardUploadLegalMessageLinkClicked();
static void LogCreditCardUploadFeedbackMetric(
CreditCardUploadFeedbackMetric metric);
@@ -1194,11 +1133,6 @@ class AutofillMetrics {
static void LogLocalCardMigrationBubbleOfferMetric(
LocalCardMigrationBubbleOfferMetric metric,
bool is_reshow);
- // TODO(crbug.com/1070799): Delete the user interaction metrics when the
- // experiment is fully launched.
- static void LogLocalCardMigrationBubbleUserInteractionMetric(
- LocalCardMigrationBubbleUserInteractionMetric metric,
- bool is_reshow);
static void LogLocalCardMigrationBubbleResultMetric(
LocalCardMigrationBubbleResultMetric metric,
bool is_reshow);
@@ -1213,6 +1147,14 @@ class AutofillMetrics {
static void LogLocalCardMigrationPromptMetric(
LocalCardMigrationOrigin local_card_migration_origin,
LocalCardMigrationPromptMetric metric);
+ static void LogOfferNotificationBubbleOfferMetric(bool is_reshow);
+ static void LogOfferNotificationBubbleResultMetric(
+ OfferNotificationBubbleResultMetric metric,
+ bool is_reshow);
+ static void LogOfferNotificationInfoBarDeepLinkClicked();
+ static void LogOfferNotificationInfoBarResultMetric(
+ OfferNotificationInfoBarResultMetric metric);
+ static void LogOfferNotificationInfoBarShown();
// Should be called when credit card scan is finished. |duration| should be
// the time elapsed between launching the credit card scanner and getting back
@@ -1252,7 +1194,7 @@ class AutofillMetrics {
static void LogUserHappinessMetric(
UserHappinessMetric metric,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
security_state::SecurityLevel security_level,
uint32_t profile_form_bitmask);
@@ -1374,7 +1316,7 @@ class AutofillMetrics {
// time elapsed between the initial form interaction and submission. This
// metric is sliced by |form_type| and |used_autofill|.
static void LogFormFillDurationFromInteraction(
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
bool used_autofill,
const base::TimeDelta& duration);
@@ -1507,7 +1449,7 @@ class AutofillMetrics {
AutofillFormSubmittedState state,
bool is_for_credit_card,
bool has_upi_vpa_field,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature,
FormInteractionsUkmLogger* form_interactions_ukm_logger);
@@ -1570,7 +1512,7 @@ class AutofillMetrics {
ukm::SourceId source_id,
const GURL& url,
bool is_for_credit_card,
- std::set<FormType> form_types,
+ DenseSet<FormType> form_types,
int developer_engagement_metrics,
FormSignature form_signature);
@@ -1579,7 +1521,7 @@ class AutofillMetrics {
static void LogHiddenOrPresentationalSelectFieldsFilled();
// Converts form type to bit vector to store in UKM.
- static int64_t FormTypesToBitVector(const std::set<FormType>& form_types);
+ static int64_t FormTypesToBitVector(const DenseSet<FormType>& form_types);
// Records the fact that the server card link was clicked with information
// about the current sync state.
@@ -1632,6 +1574,11 @@ class AutofillMetrics {
ukm::SourceId source_id,
uint32_t phone_collection_metric_state);
+ // Logs the number of autofilled fields at submission time.
+ static void LogNumberOfAutofilledFieldsAtSubmission(
+ size_t number_of_accepted_fields,
+ size_t number_of_corrected_fields);
+
private:
static void Log(AutocompleteEvent event);
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index b9da1edcafb..7a43731c706 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -32,7 +32,6 @@
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
@@ -52,12 +51,14 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
+#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/test_sync_service.h"
+#include "components/translate/core/common/language_detection_details.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/webdata/common/web_data_results.h"
#include "services/metrics/public/cpp/ukm_builders.h"
@@ -67,6 +68,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
+#include "url/url_canon.h"
#if !defined(OS_IOS)
#include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
@@ -136,7 +138,7 @@ void VerifyDeveloperEngagementUkm(
const ukm::TestUkmRecorder* ukm_recorder,
const FormData& form,
const bool is_for_credit_card,
- const std::set<FormType>& form_types,
+ const DenseSet<FormType>& form_types,
const std::vector<int64_t>& expected_metric_values) {
int expected_metric_value = 0;
for (const auto it : expected_metric_values)
@@ -196,7 +198,7 @@ void VerifySubmitFormUkm(const ukm::TestUkmRecorder* ukm_recorder,
AutofillMetrics::AutofillFormSubmittedState state,
bool is_for_credit_card,
bool has_upi_vpa_field,
- const std::set<FormType>& form_types) {
+ const DenseSet<FormType>& form_types) {
VerifyUkm(ukm_recorder, form, UkmFormSubmittedType::kEntryName,
{{{UkmFormSubmittedType::kAutofillFormSubmittedStateName, state},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
@@ -381,9 +383,8 @@ class AutofillMetricsTest : public testing::Test {
std::unique_ptr<TestAutofillManager> autofill_manager_;
std::unique_ptr<TestPersonalDataManager> personal_data_;
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
- std::unique_ptr<AutofillExternalDelegate> external_delegate_;
+ AutofillExternalDelegate* external_delegate_;
base::test::ScopedFeatureList scoped_feature_list_;
- TestPatternProvider test_pattern_provider_;
private:
void CreateTestAutofillProfiles();
@@ -432,9 +433,10 @@ void AutofillMetricsTest::SetUp() {
autofill_manager_ = std::make_unique<TestAutofillManager>(
autofill_driver_.get(), &autofill_client_, personal_data_.get(),
autocomplete_history_manager_.get());
- external_delegate_ = std::make_unique<AutofillExternalDelegate>(
+ auto external_delegate = std::make_unique<AutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get());
- autofill_manager_->SetExternalDelegate(external_delegate_.get());
+ external_delegate_ = external_delegate.get();
+ autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
#if !defined(OS_IOS)
autofill_manager_->credit_card_access_manager()
@@ -626,6 +628,80 @@ INSTANTIATE_TEST_SUITE_P(AutofillMetricsTest,
AutofillMetricsIFrameTest,
testing::Bool());
+// Test that we log the right number of autofilled fields at submission time.
+TEST_F(AutofillMetricsTest, NumberOfAutofilledFieldsAtSubmission) {
+ // Set up our form data with two autofilled fields.
+ FormData form =
+ test::GetFormData({.description_for_logging = "NumberOfAutofilledFields",
+ .fields = {{.label = "Autofilled",
+ .name = "autofilled",
+ .value = "Elvis Aaron Presley",
+ .is_autofilled = true},
+ {.label = "Autofilled but corrected",
+ .name = "autofillfailed",
+ .value = "buddy@gmail.com",
+ .is_autofilled = true},
+ {.label = "Empty",
+ .name = "empty",
+ .value = "",
+ .is_autofilled = false},
+ {.label = "Unknown",
+ .name = "unknown",
+ .value = "garbage",
+ .is_autofilled = false},
+ {.label = "Select",
+ .name = "select",
+ .value = "USA",
+ .form_control_type = "select-one",
+ .is_autofilled = false},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER,
+ .value = "2345678901",
+ .form_control_type = "tel",
+ .is_autofilled = true}},
+ .unique_renderer_id = MakeFormRendererId(),
+ .main_frame_origin = url::Origin::Create(
+ autofill_client_.form_origin())});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, PHONE_HOME_NUMBER, NAME_FULL,
+ PHONE_HOME_NUMBER, UNKNOWN_TYPE, PHONE_HOME_CITY_AND_NUMBER};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FIRST, EMAIL_ADDRESS, NAME_FIRST,
+ EMAIL_ADDRESS, NO_SERVER_DATA, PHONE_HOME_CITY_AND_NUMBER};
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ // Simulate user changing the second field of the form.
+ autofill_manager_->OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
+ TimeTicks());
+ form.fields.at(1).is_autofilled = false;
+
+ // Simulate form submission.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION);
+
+ // Test that the correct bucket for the number of filled fields received a
+ // count while the others remain at zero counts.
+ const size_t expected_number_of_accepted_fillings = 2;
+ const size_t expected_number_of_corrected_fillings = 1;
+ const size_t expected_number_of_total_fillings =
+ expected_number_of_accepted_fillings +
+ expected_number_of_corrected_fillings;
+ for (int i = 0; i < 50; i++) {
+ histogram_tester.ExpectBucketCount(
+ "Autofill.NumberOfAutofilledFieldsAtSubmission.Total", i,
+ i == expected_number_of_total_fillings ? 1 : 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.NumberOfAutofilledFieldsAtSubmission.Accepted", i,
+ i == expected_number_of_accepted_fillings ? 1 : 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.NumberOfAutofilledFieldsAtSubmission.Corrected", i,
+ i == expected_number_of_corrected_fillings ? 1 : 0);
+ }
+}
+
// Test that we log quality metrics appropriately.
TEST_F(AutofillMetricsTest, QualityMetrics) {
// Set up our form data.
@@ -1698,7 +1774,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[0].value()},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_LINE1},
@@ -1717,7 +1793,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[1].value()},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_CITY},
@@ -1736,7 +1812,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[2].value()},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_STATE},
@@ -1755,7 +1831,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldSignatureName,
field_signature[3].value()},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogHiddenRepresentationalFieldSkipDecisionType::
kFieldOverallTypeName,
ADDRESS_HOME_COUNTRY},
@@ -1837,7 +1913,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
std::string response_string = SerializeAndEncode(response);
FormStructure::ParseApiQueryResponse(
response_string, forms, test::GetEncodedSignatures(forms),
- autofill_manager_->form_interactions_ukm_logger_for_test());
+ autofill_manager_->form_interactions_ukm_logger());
ASSERT_EQ(test_ukm_recorder_
->GetEntriesByName(
@@ -1853,7 +1929,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[0].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogRepeatedServerTypePredictionRationalized::
kFieldOldOverallTypeName,
ADDRESS_HOME_STREET_ADDRESS},
@@ -1873,7 +1949,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[1].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogRepeatedServerTypePredictionRationalized::
kFieldOldOverallTypeName,
ADDRESS_HOME_STREET_ADDRESS},
@@ -1955,7 +2031,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
std::string response_string = SerializeAndEncode(response);
FormStructure::ParseApiQueryResponse(
response_string, forms, test::GetEncodedSignatures(forms),
- autofill_manager_->form_interactions_ukm_logger_for_test());
+ autofill_manager_->form_interactions_ukm_logger());
ASSERT_EQ(test_ukm_recorder_
->GetEntriesByName(
@@ -1971,7 +2047,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[0].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogRepeatedServerTypePredictionRationalized::
kFieldOldOverallTypeName,
ADDRESS_HOME_COUNTRY},
@@ -1991,7 +2067,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[1].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogRepeatedServerTypePredictionRationalized::
kFieldOldOverallTypeName,
ADDRESS_HOME_COUNTRY},
@@ -2011,7 +2087,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[2].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
- ADDRESS_HOME},
+ static_cast<int64_t>(FieldTypeGroup::kAddressHome)},
{UkmLogRepeatedServerTypePredictionRationalized::
kFieldOldOverallTypeName,
ADDRESS_HOME_COUNTRY},
@@ -2403,8 +2479,9 @@ TEST_P(QualityMetricsTest, Classification) {
ServerFieldType predicted_type = GetParam().predicted_field_type;
DVLOG(2) << "Test Case = Predicted: "
- << AutofillType(predicted_type).ToString() << "; "
- << "Actual: " << AutofillType(actual_field_type).ToString();
+ << AutofillType::ServerFieldTypeToString(predicted_type) << "; "
+ << "Actual: "
+ << AutofillType::ServerFieldTypeToString(actual_field_type);
// Set up our form data.
FormData form;
@@ -2609,7 +2686,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
// Simulate a OnFormsSeen() call that should trigger the recording.
std::vector<FormData> forms;
forms.push_back(form);
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
// Because these metrics are related to timing, it is not possible to know in
// advance which bucket the sample will fall into, so we just need to make
@@ -2847,7 +2924,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
std::unique_ptr<TestFormStructure> form_structure =
std::make_unique<TestFormStructure>(form);
TestFormStructure* form_structure_ptr = form_structure.get();
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
ASSERT_TRUE(autofill_manager_->mutable_form_structures_for_test()
->emplace(form_structure_ptr->unique_renderer_id(),
std::move(form_structure))
@@ -3106,7 +3183,7 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
@@ -3139,7 +3216,7 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
@@ -3415,7 +3492,7 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// number of fields enforced).
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
histogram_tester.ExpectTotalCount("Autofill.DeveloperEngagement", 0);
}
@@ -3427,7 +3504,7 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// Expect the "form parsed without hints" metric to be logged.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
histogram_tester.ExpectUniqueSample(
"Autofill.DeveloperEngagement",
@@ -3452,7 +3529,7 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// Expect the "form parsed with field type hints" metric to be logged.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
histogram_tester.ExpectBucketCount(
"Autofill.DeveloperEngagement",
@@ -3472,7 +3549,7 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// "author-specified upi-vpa type" metric to be logged.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
histogram_tester.ExpectBucketCount(
"Autofill.DeveloperEngagement",
@@ -3505,7 +3582,7 @@ TEST_F(AutofillMetricsTest,
// Ensure no entries are logged when loading a non-fillable form.
{
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
EXPECT_EQ(0ul, test_ukm_recorder_->entries_count());
@@ -3518,12 +3595,12 @@ TEST_F(AutofillMetricsTest,
// Expect the "form parsed without field type hints" metric and the
// "form loaded" form interaction event to be logged.
{
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
VerifyDeveloperEngagementUkm(
test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
- {FormType::ADDRESS_FORM},
+ {FormType::kAddressForm},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
}
}
@@ -3569,12 +3646,12 @@ TEST_F(AutofillMetricsTest,
// Expect the "form parsed without field type hints" metric and the
// "form loaded" form interaction event to be logged.
{
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
VerifyDeveloperEngagementUkm(
test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
- {FormType::ADDRESS_FORM},
+ {FormType::kAddressForm},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS});
}
}
@@ -3605,12 +3682,12 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
{
SCOPED_TRACE("VPA and other autocomplete hint present");
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
VerifyDeveloperEngagementUkm(
test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
/* UPI VPA has Unknown form type.*/
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE},
+ {FormType::kAddressForm, FormType::kUnknownFormType},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
PurgeUKM();
@@ -3829,7 +3906,8 @@ TEST_F(AutofillMetricsTest, AutofillProfileIsEnabledAtStartup) {
personal_data_->SetAutofillProfileEnabled(true);
personal_data_->Init(scoped_refptr<AutofillWebDataService>(nullptr),
/*account_database=*/nullptr,
- autofill_client_.GetPrefs(),
+ /*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -3844,7 +3922,8 @@ TEST_F(AutofillMetricsTest, AutofillProfileIsDisabledAtStartup) {
personal_data_->SetAutofillProfileEnabled(false);
personal_data_->Init(scoped_refptr<AutofillWebDataService>(nullptr),
/*account_database=*/nullptr,
- autofill_client_.GetPrefs(),
+ /*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -3859,7 +3938,8 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsEnabledAtStartup) {
personal_data_->SetAutofillCreditCardEnabled(true);
personal_data_->Init(scoped_refptr<AutofillWebDataService>(nullptr),
/*account_database=*/nullptr,
- autofill_client_.GetPrefs(),
+ /*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -3874,7 +3954,8 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsDisabledAtStartup) {
personal_data_->SetAutofillCreditCardEnabled(false);
personal_data_->Init(scoped_refptr<AutofillWebDataService>(nullptr),
/*account_database=*/nullptr,
- autofill_client_.GetPrefs(),
+ /*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -3889,8 +3970,8 @@ TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
FormFieldData field;
@@ -3962,8 +4043,8 @@ TEST_F(AutofillMetricsTest, CompanyNameSuggestions) {
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
FormFieldData field;
@@ -4003,8 +4084,8 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
FormFieldData field;
@@ -4181,7 +4262,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true, /* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Test that the UPI Checkout flow form submit is correctly logged
@@ -4200,14 +4281,14 @@ TEST_F(AutofillMetricsTest, UpiVpaUkmTest) {
std::vector<FormData> forms(1, form);
{
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
VerifySubmitFormUkm(test_ukm_recorder_, forms.back(),
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/false,
/* has_upi_vpa_field */ true,
/* UPI VPA has Unknown form type.*/
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE});
+ {FormType::kAddressForm, FormType::kUnknownFormType});
PurgeUKM();
}
}
@@ -4221,8 +4302,8 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
FormFieldData field;
@@ -4349,7 +4430,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/false,
- /* has_upi_vpa_field=*/false, {FormType::ADDRESS_FORM});
+ /* has_upi_vpa_field=*/false, {FormType::kAddressForm});
}
// Tests that the Autofill_PolledCreditCardSuggestions user action is only
@@ -4445,6 +4526,15 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
form.unique_renderer_id = MakeFormRendererId();
form.url = GURL("http://example.com/form.html");
form.action = GURL("http://example.com/submit.html");
+ // In order to test that the QueriedCreditCardFormIsSecure is logged as
+ // false, we need to set the main frame origin, otherwise this fill is
+ // skipped due to the form being detected as mixed content.
+ GURL client_form_origin = autofill_client_.form_origin();
+ GURL::Replacements replacements;
+ replacements.SetScheme(url::kHttpScheme,
+ url::Component(0, strlen(url::kHttpScheme)));
+ autofill_client_.set_form_origin(
+ client_form_origin.ReplaceComponents(replacements));
form.main_frame_origin =
url::Origin::Create(autofill_client_.form_origin());
autofill_manager_->AddSeenForm(form, field_types, field_types);
@@ -4457,6 +4547,8 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
/*autoselect_first_suggestion=*/false);
histogram_tester.ExpectUniqueSample(
"Autofill.QueriedCreditCardFormIsSecure", false, 1);
+ // Reset the main frame origin to secure for other tests
+ autofill_client_.set_form_origin(client_form_origin);
}
{
@@ -4488,8 +4580,8 @@ TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) {
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
FormFieldData field;
@@ -4567,7 +4659,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) {
forms.push_back(form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectUniqueSample(
"Autofill.FormEvents.CreditCard.WithNoData", FORM_EVENT_DID_PARSE_FORM,
1);
@@ -5558,7 +5650,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -5602,7 +5694,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -5650,7 +5742,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -5696,7 +5788,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -5743,7 +5835,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -5789,7 +5881,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -5817,7 +5909,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
@@ -5830,7 +5922,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
{UkmFormSubmittedType::kIsForCreditCardName, true},
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kCreditCardForm})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}},
{{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
@@ -5839,7 +5931,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
{UkmFormSubmittedType::kIsForCreditCardName, true},
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kCreditCardForm})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}}});
@@ -5993,7 +6085,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
/* has_upi_vpa_field=*/false,
- {FormType::CREDIT_CARD_FORM});
+ {FormType::kCreditCardForm});
}
}
@@ -6324,8 +6416,8 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ form.url = GURL("https://example.com/form.html");
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
FormFieldData field;
@@ -6606,7 +6698,7 @@ TEST_F(AutofillMetricsTest, MixedParsedFormEvents) {
forms.push_back(form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.FormEvents.Address.WithNoData",
FORM_EVENT_DID_PARSE_FORM, 1);
histogram_tester.ExpectUniqueSample(
@@ -6641,7 +6733,7 @@ TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
forms.push_back(form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.FormEvents.Address.WithNoData",
FORM_EVENT_DID_PARSE_FORM, 1);
@@ -6653,7 +6745,7 @@ TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
test_ukm_recorder_, form, UkmFormEventType::kEntryName,
{{{UkmFormEventType::kAutofillFormEventName, FORM_EVENT_DID_PARSE_FORM},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
@@ -6700,7 +6792,7 @@ TEST_F(AutofillMetricsTest, AddressInteractedFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_INTERACTED_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
@@ -6727,7 +6819,7 @@ TEST_F(AutofillMetricsTest, AddressInteractedFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_INTERACTED_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
}
@@ -6778,12 +6870,12 @@ TEST_F(AutofillMetricsTest, AddressSuppressedFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_POPUP_SUPPRESSED},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_POPUP_SUPPRESSED_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
@@ -6811,17 +6903,17 @@ TEST_F(AutofillMetricsTest, AddressSuppressedFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_POPUP_SUPPRESSED},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_POPUP_SUPPRESSED_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_POPUP_SUPPRESSED},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
}
@@ -6871,12 +6963,12 @@ TEST_F(AutofillMetricsTest, AddressShownFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_SUGGESTIONS_SHOWN},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
@@ -6903,17 +6995,17 @@ TEST_F(AutofillMetricsTest, AddressShownFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_SUGGESTIONS_SHOWN},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_SUGGESTIONS_SHOWN},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
@@ -6987,12 +7079,12 @@ TEST_F(AutofillMetricsTest, AddressFilledFormEvents) {
{{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_LOCAL_SUGGESTION_FILLED},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
{{UkmFormEventType::kAutofillFormEventName,
FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE},
{UkmFormEventType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
@@ -7103,7 +7195,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/false,
- /* has_upi_vpa_field=*/false, {FormType::ADDRESS_FORM});
+ /* has_upi_vpa_field=*/false, {FormType::kAddressForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -7132,7 +7224,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/false,
- /* has_upi_vpa_field=*/false, {FormType::ADDRESS_FORM});
+ /* has_upi_vpa_field=*/false, {FormType::kAddressForm});
}
// Reset the autofill manager state and purge UKM logs.
@@ -7651,7 +7743,7 @@ TEST_F(AutofillMetricsTest, AddressFormEventsAreSegmented) {
TEST_F(AutofillMetricsTest, AutofillProfileIsEnabledAtPageLoad) {
base::HistogramTester histogram_tester;
autofill_manager_->SetAutofillProfileEnabled(true);
- autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks());
+ autofill_manager_->OnFormsSeen(std::vector<FormData>());
histogram_tester.ExpectUniqueSample("Autofill.Address.IsEnabled.PageLoad",
true, 1);
}
@@ -7660,7 +7752,7 @@ TEST_F(AutofillMetricsTest, AutofillProfileIsEnabledAtPageLoad) {
TEST_F(AutofillMetricsTest, AutofillProfileIsDisabledAtPageLoad) {
base::HistogramTester histogram_tester;
autofill_manager_->SetAutofillProfileEnabled(false);
- autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks());
+ autofill_manager_->OnFormsSeen(std::vector<FormData>());
histogram_tester.ExpectUniqueSample("Autofill.Address.IsEnabled.PageLoad",
false, 1);
}
@@ -7669,7 +7761,7 @@ TEST_F(AutofillMetricsTest, AutofillProfileIsDisabledAtPageLoad) {
TEST_F(AutofillMetricsTest, AutofillCreditCardIsEnabledAtPageLoad) {
base::HistogramTester histogram_tester;
autofill_manager_->SetAutofillCreditCardEnabled(true);
- autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks());
+ autofill_manager_->OnFormsSeen(std::vector<FormData>());
histogram_tester.ExpectUniqueSample("Autofill.CreditCard.IsEnabled.PageLoad",
true, 1);
}
@@ -7678,7 +7770,7 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsEnabledAtPageLoad) {
TEST_F(AutofillMetricsTest, AutofillCreditCardIsDisabledAtPageLoad) {
base::HistogramTester histogram_tester;
autofill_manager_->SetAutofillCreditCardEnabled(false);
- autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks());
+ autofill_manager_->OnFormsSeen(std::vector<FormData>());
histogram_tester.ExpectUniqueSample("Autofill.CreditCard.IsEnabled.PageLoad",
false, 1);
}
@@ -7728,12 +7820,12 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Expect no notifications when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectTotalCount("Autofill.FormSubmittedState", 0);
VerifyDeveloperEngagementUkm(
test_ukm_recorder_, form, /*is_for_credit_card=*/false,
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE},
+ {FormType::kAddressForm, FormType::kUnknownFormType},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
}
@@ -7760,7 +7852,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {FormType::kAddressForm, FormType::kUnknownFormType})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -7795,7 +7887,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {FormType::kAddressForm, FormType::kUnknownFormType})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -7834,7 +7926,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {FormType::kAddressForm, FormType::kUnknownFormType})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
@@ -7880,7 +7972,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {FormType::kAddressForm, FormType::kUnknownFormType})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -7915,7 +8007,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {FormType::kAddressForm, FormType::kUnknownFormType})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -7951,7 +8043,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {FormType::kAddressForm, FormType::kUnknownFormType})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -7997,10 +8089,10 @@ TEST_F(
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
VerifyDeveloperEngagementUkm(
test_ukm_recorder_, form, /*is_for_credit_card=*/false,
- {FormType::ADDRESS_FORM},
+ {FormType::kAddressForm},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
histogram_tester.ExpectTotalCount("Autofill.FormSubmittedState", 0);
@@ -8029,7 +8121,7 @@ TEST_F(
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kHasUpiVpaFieldName, false},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ AutofillMetrics::FormTypesToBitVector({FormType::kAddressForm})},
{UkmFormSubmittedType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}});
VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -8045,7 +8137,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessMetric_PasswordForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_AUTOFILL, PASSWORD_FIELD,
+ AutofillMetrics::USER_DID_AUTOFILL, FieldTypeGroup::kPasswordField,
security_state::SecurityLevel::SECURITY_LEVEL_COUNT,
/*profile_form_bitmask=*/0);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
@@ -8060,7 +8152,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessMetric_PasswordForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_AUTOFILL, USERNAME_FIELD,
+ AutofillMetrics::USER_DID_AUTOFILL, FieldTypeGroup::kUsernameField,
security_state::SecurityLevel::SECURITY_LEVEL_COUNT,
/*profile_form_bitmask=*/0);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
@@ -8077,7 +8169,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessMetric_UnknownForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_AUTOFILL, NO_GROUP,
+ AutofillMetrics::USER_DID_AUTOFILL, FieldTypeGroup::kNoGroup,
security_state::SecurityLevel::SECURITY_LEVEL_COUNT,
/*profile_form_bitmask=*/0);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
@@ -8092,7 +8184,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessMetric_UnknownForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_AUTOFILL, TRANSACTION,
+ AutofillMetrics::USER_DID_AUTOFILL, FieldTypeGroup::kTransaction,
security_state::SecurityLevel::SECURITY_LEVEL_COUNT,
/*profile_form_bitmask=*/0);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
@@ -8120,7 +8212,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_EmptyForm) {
// Expect a notification when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness", 0);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0);
@@ -8161,7 +8253,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
{
SCOPED_TRACE("First seen");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::FORMS_LOADED, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard",
@@ -8325,7 +8417,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Expect a notification when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::FORMS_LOADED, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address",
@@ -8360,7 +8452,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
}
autofill_manager_->Reset();
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
// Simulate suggestions shown twice for a single edit (i.e. multiple
// keystrokes in a single field).
{
@@ -8514,7 +8606,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
Collapse(CalculateFormSignature(form)).value()}}});
VerifyUkm(
test_ukm_recorder_, form, UkmTextFieldDidChangeType::kEntryName,
- {{{UkmTextFieldDidChangeType::kFieldTypeGroupName, NAME},
+ {{{UkmTextFieldDidChangeType::kFieldTypeGroupName,
+ static_cast<int64_t>(FieldTypeGroup::kName)},
{UkmTextFieldDidChangeType::kHeuristicTypeName, NAME_FULL},
{UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
@@ -8526,7 +8619,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
Collapse(CalculateFieldSignatureForField(form.fields[0])).value()},
{UkmTextFieldDidChangeType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}},
- {{UkmTextFieldDidChangeType::kFieldTypeGroupName, NAME},
+ {{UkmTextFieldDidChangeType::kFieldTypeGroupName,
+ static_cast<int64_t>(FieldTypeGroup::kName)},
{UkmTextFieldDidChangeType::kHeuristicTypeName, NAME_FULL},
{UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
@@ -8538,7 +8632,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
Collapse(CalculateFieldSignatureForField(form.fields[0])).value()},
{UkmTextFieldDidChangeType::kFormSignatureName,
Collapse(CalculateFormSignature(form)).value()}},
- {{UkmTextFieldDidChangeType::kFieldTypeGroupName, EMAIL},
+ {{UkmTextFieldDidChangeType::kFieldTypeGroupName,
+ static_cast<int64_t>(FieldTypeGroup::kEmail)},
{UkmTextFieldDidChangeType::kHeuristicTypeName, EMAIL_ADDRESS},
{UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
@@ -8601,7 +8696,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 1");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
base::TimeTicks parse_time = autofill_manager_->form_structures()
.begin()
->second->form_parsed_timestamp();
@@ -8625,7 +8720,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 2");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
base::TimeTicks parse_time = autofill_manager_->form_structures()
.begin()
->second->form_parsed_timestamp();
@@ -8654,7 +8749,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 3");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
base::TimeTicks parse_time = autofill_manager_->form_structures()
.begin()
->second->form_parsed_timestamp();
@@ -8684,7 +8779,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
SCOPED_TRACE("Test 4");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
base::TimeTicks parse_time = autofill_manager_->form_structures()
.begin()
->second->form_parsed_timestamp();
@@ -8716,11 +8811,11 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 5");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
base::TimeTicks parse_time = autofill_manager_->form_structures()
.begin()
->second->form_parsed_timestamp();
- autofill_manager_->OnFormsSeen(second_forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(second_forms);
autofill_manager_->OnDidFillAutofillFormData(
form, parse_time + base::TimeDelta::FromMicroseconds(5));
autofill_manager_->OnTextFieldDidChange(
@@ -8748,8 +8843,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 6");
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
- autofill_manager_->OnFormsSeen(second_forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
+ autofill_manager_->OnFormsSeen(second_forms);
base::TimeTicks parse_time{};
for (const auto& kv : autofill_manager_->form_structures()) {
if (kv.second->form_parsed_timestamp() > parse_time)
@@ -8777,7 +8872,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_CreditCardForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {CREDIT_CARD_FORM}, true /* used_autofill */,
+ {FormType::kCreditCardForm}, true /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard",
@@ -8790,7 +8885,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_CreditCardForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {CREDIT_CARD_FORM}, false /* used_autofill */,
+ {FormType::kCreditCardForm}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithoutAutofill.CreditCard",
@@ -8804,7 +8899,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_CreditCardForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {UNKNOWN_FORM_TYPE}, false /* used_autofill */,
+ {FormType::kUnknownFormType}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard", 0);
@@ -8818,7 +8913,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_AddressForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {ADDRESS_FORM}, true /* used_autofill */,
+ {FormType::kAddressForm}, true /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.Address",
@@ -8831,7 +8926,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_AddressForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {ADDRESS_FORM}, false /* used_autofill */,
+ {FormType::kAddressForm}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithoutAutofill.Address",
@@ -8845,7 +8940,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_AddressForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {UNKNOWN_FORM_TYPE}, false /* used_autofill */,
+ {FormType::kUnknownFormType}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.Address", 0);
@@ -8859,7 +8954,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_PasswordForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {PASSWORD_FORM}, true /* used_autofill */,
+ {FormType::kPasswordForm}, true /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.Password",
@@ -8872,7 +8967,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_PasswordForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {PASSWORD_FORM}, false /* used_autofill */,
+ {FormType::kPasswordForm}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithoutAutofill.Password",
@@ -8886,7 +8981,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_PasswordForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {UNKNOWN_FORM_TYPE}, false /* used_autofill */,
+ {FormType::kUnknownFormType}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.Password", 0);
@@ -8900,7 +8995,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_UnknownForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {UNKNOWN_FORM_TYPE}, true /* used_autofill */,
+ {FormType::kUnknownFormType}, true /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.Unknown",
@@ -8913,7 +9008,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_UnknownForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {UNKNOWN_FORM_TYPE}, false /* used_autofill */,
+ {FormType::kUnknownFormType}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithoutAutofill.Unknown",
@@ -8927,7 +9022,7 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_UnknownForm) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {ADDRESS_FORM}, false /* used_autofill */,
+ {FormType::kAddressForm}, false /* used_autofill */,
base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.Unknown", 0);
@@ -8941,7 +9036,8 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_MultipleForms) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {CREDIT_CARD_FORM, ADDRESS_FORM, PASSWORD_FORM, UNKNOWN_FORM_TYPE},
+ {FormType::kCreditCardForm, FormType::kAddressForm,
+ FormType::kPasswordForm, FormType::kUnknownFormType},
true /* used_autofill */, base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard",
@@ -8961,7 +9057,8 @@ TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_MultipleForms) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogFormFillDurationFromInteraction(
- {CREDIT_CARD_FORM, ADDRESS_FORM, PASSWORD_FORM, UNKNOWN_FORM_TYPE},
+ {FormType::kCreditCardForm, FormType::kAddressForm,
+ FormType::kPasswordForm, FormType::kUnknownFormType},
false /* used_autofill */, base::TimeDelta::FromMilliseconds(2000));
histogram_tester.ExpectTimeBucketCount(
"Autofill.FillDuration.FromInteraction.WithoutAutofill.CreditCard",
@@ -9055,7 +9152,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
// submitted.
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -9068,7 +9165,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log EXISTING_PROFILE_USED for the metric since the same profile
// is submitted.
- autofill_manager_->OnFormsSeen(second_forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(second_forms);
autofill_manager_->OnFormSubmitted(second_form, false,
SubmissionSource::FORM_SUBMISSION);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -9081,7 +9178,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
// submitted.
- autofill_manager_->OnFormsSeen(third_forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(third_forms);
autofill_manager_->OnFormSubmitted(third_form, false,
SubmissionSource::FORM_SUBMISSION);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -9094,7 +9191,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log EXISTING_PROFILE_UPDATED for the metric since the profile was
// updated.
- autofill_manager_->OnFormsSeen(fourth_forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(fourth_forms);
autofill_manager_->OnFormSubmitted(fourth_form, false,
SubmissionSource::FORM_SUBMISSION);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -9327,7 +9424,9 @@ TEST_F(AutofillMetricsTest,
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
form.url = GURL("https://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
+ // Form action needs to be secure on secure page, otherwise this triggers
+ // mixed form warnings and no suggestions are offered.
+ form.action = GURL("https://example.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("http://example_root.com/form.html"));
@@ -9402,7 +9501,7 @@ TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
AutofillMetrics::LogDeveloperEngagementUkm(
test_ukm_recorder_, autofill_client_.GetUkmSourceId(), url, true,
- {FormType::CREDIT_CARD_FORM}, form_structure_metric, form_signature);
+ {FormType::kCreditCardForm}, form_structure_metric, form_signature);
auto entries = test_ukm_recorder_->GetEntriesByName(
UkmDeveloperEngagementType::kEntryName);
EXPECT_EQ(1u, entries.size());
@@ -9416,7 +9515,7 @@ TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
entry, UkmDeveloperEngagementType::kIsForCreditCardName, true);
test_ukm_recorder_->ExpectEntryMetric(
entry, UkmDeveloperEngagementType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM}));
+ AutofillMetrics::FormTypesToBitVector({FormType::kCreditCardForm}));
test_ukm_recorder_->ExpectEntryMetric(
entry, UkmDeveloperEngagementType::kFormSignatureName,
form_signature.value());
@@ -9558,7 +9657,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessBySecurityLevel(
- AutofillMetrics::USER_DID_AUTOFILL, CREDIT_CARD_FORM,
+ AutofillMetrics::USER_DID_AUTOFILL, FormType::kCreditCardForm,
security_state::SecurityLevel::SECURE);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness.CreditCard.SECURE",
@@ -9568,7 +9667,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessBySecurityLevel(
- AutofillMetrics::SUGGESTIONS_SHOWN, ADDRESS_FORM,
+ AutofillMetrics::SUGGESTIONS_SHOWN, FormType::kAddressForm,
security_state::SecurityLevel::DANGEROUS);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness.Address.DANGEROUS",
@@ -9578,7 +9677,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessBySecurityLevel(
- AutofillMetrics::FIELD_WAS_AUTOFILLED, PASSWORD_FORM,
+ AutofillMetrics::FIELD_WAS_AUTOFILLED, FormType::kPasswordForm,
security_state::SecurityLevel::WARNING);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness.Password.WARNING",
@@ -9588,7 +9687,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessBySecurityLevel(
- AutofillMetrics::USER_DID_AUTOFILL_ONCE, UNKNOWN_FORM_TYPE,
+ AutofillMetrics::USER_DID_AUTOFILL_ONCE, FormType::kUnknownFormType,
security_state::SecurityLevel::SECURE);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Unknown.SECURE",
AutofillMetrics::USER_DID_AUTOFILL_ONCE,
@@ -9601,7 +9700,8 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessBySecurityLevel(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME,
- CREDIT_CARD_FORM, security_state::SecurityLevel::SECURITY_LEVEL_COUNT);
+ FormType::kCreditCardForm,
+ security_state::SecurityLevel::SECURITY_LEVEL_COUNT);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard.OTHER",
0);
}
@@ -9633,7 +9733,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) {
base::HistogramTester histogram_tester;
autofill_client_.set_security_level(
security_state::SecurityLevel::DANGEROUS);
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness.Address.DANGEROUS",
AutofillMetrics::FORMS_LOADED, 1);
@@ -9656,7 +9756,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) {
TEST_F(AutofillMetricsTest, LogUserHappinessByProfileFormType_AddressOnly) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
ADDRESS_HOME_DEPENDENT_LOCALITY}));
@@ -9685,7 +9785,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessByProfileFormType_AddressOnly) {
TEST_F(AutofillMetricsTest, LogUserHappinessByProfileFormType_ContactOnly) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({NAME_FIRST, NAME_LAST, EMAIL_ADDRESS}));
@@ -9714,7 +9814,7 @@ TEST_F(AutofillMetricsTest,
LogUserHappinessByProfileFormType_AddressPlusPhone) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups(
{NAME_FULL, ADDRESS_HOME_ZIP, PHONE_HOME_CITY_AND_NUMBER}));
@@ -9747,7 +9847,7 @@ TEST_F(AutofillMetricsTest,
LogUserHappinessByProfileFormType_AddressPlusEmail) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({NAME_FULL, ADDRESS_HOME_ZIP, EMAIL_ADDRESS}));
@@ -9779,7 +9879,7 @@ TEST_F(AutofillMetricsTest,
LogUserHappinessByProfileFormType_AddressPlusEmailPlusPhone) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({NAME_FULL, ADDRESS_HOME_ZIP, EMAIL_ADDRESS,
PHONE_HOME_WHOLE_NUMBER}));
@@ -9810,7 +9910,7 @@ TEST_F(AutofillMetricsTest,
TEST_F(AutofillMetricsTest, LogUserHappinessByProfileFormType_Other) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({NAME_FIRST, NAME_MIDDLE, NAME_LAST}));
@@ -9838,7 +9938,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessByProfileFormType_Other) {
TEST_F(AutofillMetricsTest, LogUserHappinessByProfileFormType_PhoneOnly) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::USER_DID_TYPE, {FormType::ADDRESS_FORM},
+ AutofillMetrics::USER_DID_TYPE, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({PHONE_HOME_NUMBER}));
@@ -9866,7 +9966,7 @@ TEST_F(AutofillMetricsTest,
LogUserHappinessByProfileFormType_FormsLoadedNotLogged) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(
- AutofillMetrics::FORMS_LOADED, {FormType::ADDRESS_FORM},
+ AutofillMetrics::FORMS_LOADED, {FormType::kAddressForm},
security_state::SecurityLevel::NONE,
data_util::DetermineGroups({NAME_FIRST, NAME_MIDDLE, NAME_LAST}));
@@ -9893,7 +9993,7 @@ TEST_F(AutofillMetricsTest,
LogUserHappinessByProfileFormType_NoAddressFormType) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED,
- {FormType::CREDIT_CARD_FORM},
+ {FormType::kCreditCardForm},
security_state::SecurityLevel::NONE,
/*profile_form_bitmask=*/0);
@@ -9903,98 +10003,13 @@ TEST_F(AutofillMetricsTest,
Not(AnyOf(HasSubstr("Autofill.UserHappiness.Address"))));
}
-// Tests that the LogSaveCardPromptMetricBySecurityLevel are recorded correctly.
-TEST_F(AutofillMetricsTest, LogSaveCardPromptMetricBySecurityLevel) {
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
- /*is_uploading=*/true, security_state::SecurityLevel::SECURE);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Upload.SECURE",
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED, 1);
- }
-
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, /*is_uploading=*/false,
- security_state::SecurityLevel::DANGEROUS);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Local.DANGEROUS",
- AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, 1);
- }
-
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, /*is_uploading=*/true,
- security_state::SecurityLevel::WARNING);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Upload.WARNING",
- AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, 1);
- }
-
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING,
- /*is_uploading=*/false, security_state::SecurityLevel::SECURE);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Local.SECURE",
- AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, 1);
- }
-
- {
- // No metric should be recorded if the security level is
- // SECURITY_LEVEL_COUNT.
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- AutofillMetrics::SAVE_CARD_PROMPT_CVC_FIX_FLOW_SHOWN,
- /*is_uploading=*/true,
- security_state::SecurityLevel::SECURITY_LEVEL_COUNT);
- histogram_tester.ExpectTotalCount(
- "Autofill.SaveCreditCardPrompt.Upload.OTHER", 0);
- }
-}
-
-// Verify that we correctly log LogSaveCardPromptMetricBySecurityLevel from the
-// save card prompt metrics.
-TEST_F(AutofillMetricsTest,
- LogSaveCardPromptMetricBySecurityLevel_FromSaveCardPromptMetric) {
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetric(
- AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING,
- /*is_uploading=*/true, /*is_reshow=*/false,
- AutofillClient::SaveCreditCardOptions(),
- /*previous_save_credit_card_prompt_user_decision=*/1,
- security_state::SecurityLevel::SECURE, SyncSigninState::kSignedOut);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Upload.SECURE",
- AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, 1);
- }
-
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetric(
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
- /*is_uploading=*/false,
- /*is_reshow=*/true, AutofillClient::SaveCreditCardOptions(),
- /*previous_save_credit_card_prompt_user_decision=*/0,
- security_state::SecurityLevel::SECURE, SyncSigninState::kSignedOut);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Local.SECURE",
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED, 1);
- }
-}
-
// Verify that we don't log Autofill.WebOTP.OneTimeCode.FromAutocomplete if the
// frame has no form.
TEST_F(AutofillMetricsTest, FrameHasNoForm) {
base::HistogramTester histogram_tester;
autofill_manager_.reset();
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.OneTimeCode.FromAutocomplete", 0);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.WebOTP.OneTimeCode.FromAutocomplete", 0);
}
// Verify that we correctly log metrics if a frame has
@@ -10018,7 +10033,7 @@ TEST_F(AutofillMetricsTest, FrameHasAutocompleteOneTimeCode) {
forms_with_one_time_code.back().fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms_with_one_time_code, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms_with_one_time_code);
autofill_manager_.reset();
// Verifies that autocomplete="one-time-code" in a form is correctly recorded.
histogram_tester.ExpectBucketCount(
@@ -10046,7 +10061,7 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHaveAutocompleteOneTimeCode) {
forms_without_one_time_code.back().fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms_without_one_time_code, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms_without_one_time_code);
autofill_manager_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.OneTimeCode.FromAutocomplete",
@@ -10080,7 +10095,7 @@ TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithoutAutocomplete) {
forms_with_phone_number.back().fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms_with_phone_number, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms_with_phone_number);
autofill_manager_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -10109,8 +10124,7 @@ TEST_F(AutofillMetricsTest, FrameHasSinglePhoneNumberFieldWithoutAutocomplete) {
forms_with_single_phone_number_field.back().fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms_with_single_phone_number_field,
- TimeTicks());
+ autofill_manager_->OnFormsSeen(forms_with_single_phone_number_field);
autofill_manager_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -10129,7 +10143,7 @@ TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithAutocomplete) {
std::vector<FormData> forms_with_phone_number(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms_with_phone_number, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms_with_phone_number);
autofill_manager_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -10156,7 +10170,7 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHavePhoneNumberField) {
forms_without_phone_number.back().fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms_without_phone_number, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms_without_phone_number);
autofill_manager_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -10177,7 +10191,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateNone) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(false);
@@ -10195,7 +10209,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateOTC) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(false);
@@ -10227,7 +10241,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateWebOTPPlusOTC) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(true);
@@ -10246,7 +10260,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStatePhone) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(false);
@@ -10265,7 +10279,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStatePhonePlusOTC) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(false);
@@ -10284,7 +10298,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStatePhonePlusWebOTP) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(true);
@@ -10306,7 +10320,7 @@ TEST_F(AutofillMetricsTest,
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(true);
@@ -10332,7 +10346,7 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateLoggedToUKM) {
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_driver_->SetAutofillManager(std::move(autofill_manager_));
static_cast<ContentAutofillDriver*>(autofill_driver_.get())
->ReportAutofillWebOTPMetrics(/* Document uses WebOTP */ true);
@@ -10453,7 +10467,7 @@ TEST_F(AutofillMetricsTest, FormEventMetrics_BySyncState) {
FormData form;
FormStructure form_structure(form);
std::vector<FormData> forms(1, form);
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
+ autofill_manager_->OnFormsSeen(forms);
autofill_manager_->Reset();
{
@@ -10504,38 +10518,6 @@ TEST_F(AutofillMetricsTest, LogIsAutofillEnabledAtPageLoad_BySyncState) {
}
}
-// Verify that we correctly log FormEvent metrics with the appropriate sync
-// state.
-TEST_F(AutofillMetricsTest, LogSaveCardPromptMetric_BySyncState) {
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetric(
- AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING,
- /*is_uploading=*/true, /*is_reshow=*/false,
- AutofillClient::SaveCreditCardOptions(),
- /*previous_save_credit_card_prompt_user_decision=*/1,
- security_state::SecurityLevel::SECURE, SyncSigninState::kSignedIn);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Upload.FirstShow.SignedIn",
- AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, 1);
- }
-
- {
- base::HistogramTester histogram_tester;
- AutofillMetrics::LogSaveCardPromptMetric(
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
- /*is_uploading=*/false,
- /*is_reshow=*/true, AutofillClient::SaveCreditCardOptions(),
- /*previous_save_credit_card_prompt_user_decision=*/0,
- security_state::SecurityLevel::SECURE,
- SyncSigninState::kSignedInAndSyncFeatureEnabled);
- histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Local.Reshows."
- "SignedInAndSyncFeatureEnabled",
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED, 1);
- }
-}
-
TEST_F(AutofillMetricsTest, LogServerCardLinkClicked) {
{
base::HistogramTester histogram_tester;
@@ -10606,7 +10588,7 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
const bool user_submitted_form = GetParam() >= 4;
// Simulate that the autofill manager has seen this form on page load.
- autofill_manager_->OnFormsSeen({form}, TimeTicks());
+ autofill_manager_->OnFormsSeen({form});
if (!user_saw_suggestion) {
// Remove the profile to prevent suggestion from being shown.
@@ -10763,7 +10745,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogEmptyForm) {
base::HistogramTester histogram_tester;
// Simulate page load.
- autofill_manager_->OnFormsSeen({form_}, TimeTicks());
+ autofill_manager_->OnFormsSeen({form_});
autofill_manager_->OnQueryFormFieldAutofill(
0, form_, form_.fields[0], gfx::RectF(),
/*autoselect_first_suggestion=*/false);
@@ -10794,7 +10776,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogNoProfile) {
// Simulate that no data is available.
personal_data_->ClearProfiles();
- autofill_manager_->OnFormsSeen({form_}, TimeTicks());
+ autofill_manager_->OnFormsSeen({form_});
autofill_manager_->OnQueryFormFieldAutofill(
0, form_, form_.fields[0], gfx::RectF(),
/*autoselect_first_suggestion=*/false);
@@ -10829,7 +10811,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserDoesNotAcceptSuggestion) {
base::HistogramTester histogram_tester;
// Simulate that suggestion is shown but user does not accept it.
- autofill_manager_->OnFormsSeen({form_}, TimeTicks());
+ autofill_manager_->OnFormsSeen({form_});
autofill_manager_->OnQueryFormFieldAutofill(
0, form_, form_.fields[0], gfx::RectF(),
/*autoselect_first_suggestion=*/false);
@@ -10866,7 +10848,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledData) {
base::HistogramTester histogram_tester;
// Simulate that suggestion is shown and user accepts it.
- autofill_manager_->OnFormsSeen({form_}, TimeTicks());
+ autofill_manager_->OnFormsSeen({form_});
autofill_manager_->OnQueryFormFieldAutofill(
0, form_, form_.fields[0], gfx::RectF(),
/*autoselect_first_suggestion=*/false);
@@ -10905,7 +10887,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledDataButDoesNotSubmit) {
base::HistogramTester histogram_tester;
// Simulate that suggestion is shown and user accepts it.
- autofill_manager_->OnFormsSeen({form_}, TimeTicks());
+ autofill_manager_->OnFormsSeen({form_});
autofill_manager_->OnQueryFormFieldAutofill(
0, form_, form_.fields[0], gfx::RectF(),
/*autoselect_first_suggestion=*/false);
@@ -10957,6 +10939,9 @@ TEST_F(AutofillMetricsTest, PageLanguageMetricsExpectedCase) {
CreateSimpleForm(autofill_client_.form_origin(), form);
// Set up language state.
+ translate::LanguageDetectionDetails language_detection_details;
+ language_detection_details.adopted_language = "ub";
+ autofill_manager_->OnLanguageDetermined(language_detection_details);
autofill_client_.GetLanguageState()->SetOriginalLanguage("ub");
autofill_client_.GetLanguageState()->SetCurrentLanguage("ub");
int language_code = 'u' * 256 + 'b';
@@ -10979,7 +10964,10 @@ TEST_F(AutofillMetricsTest, PageLanguageMetricsInvalidLanguage) {
CreateSimpleForm(autofill_client_.form_origin(), form);
// Set up language state.
- autofill_client_.GetLanguageState()->SetOriginalLanguage("!ab");
+ translate::LanguageDetectionDetails language_detection_details;
+ language_detection_details.adopted_language = "en";
+ autofill_manager_->OnLanguageDetermined(language_detection_details);
+ autofill_client_.GetLanguageState()->SetOriginalLanguage("en");
autofill_client_.GetLanguageState()->SetCurrentLanguage("other");
// Simulate form submission.
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
index f82bcdf9778..313cd9d1670 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -18,7 +18,7 @@
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/browser/proto/autofill_sync.pb.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
using autofill::data_util::TruncateUTF8;
using base::UTF16ToUTF8;
@@ -120,6 +120,8 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_LAST_CONJUNCTION))));
specifics->add_name_full(
TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_FULL))));
+ specifics->add_name_full_with_honorific(TruncateUTF8(
+ UTF16ToUTF8(entry.GetRawInfo(NAME_FULL_WITH_HONORIFIC_PREFIX))));
// Set address-related statuses.
specifics->add_name_honorific_status(
@@ -142,6 +144,9 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
entry.GetVerificationStatus(NAME_LAST_SECOND)));
specifics->add_name_full_status(ConvertProfileToSpecificsVerificationStatus(
entry.GetVerificationStatus(NAME_FULL)));
+ specifics->add_name_full_with_honorific_status(
+ ConvertProfileToSpecificsVerificationStatus(
+ entry.GetVerificationStatus(NAME_FULL_WITH_HONORIFIC_PREFIX)));
// Set email, phone and company values.
specifics->add_email_address(
@@ -176,6 +181,10 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME)));
specifics->set_address_home_subpremise_name(
UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_SUBPREMISE)));
+ specifics->set_address_home_apt_num(
+ UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_APT_NUM)));
+ specifics->set_address_home_floor(
+ UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_FLOOR)));
specifics->set_address_home_premise_name(
UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_PREMISE_NAME)));
specifics->set_address_home_thoroughfare_number(
@@ -212,6 +221,12 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
specifics->set_address_home_subpremise_name_status(
ConvertProfileToSpecificsVerificationStatus(
entry.GetVerificationStatus(ADDRESS_HOME_SUBPREMISE)));
+ specifics->set_address_home_apt_num_status(
+ ConvertProfileToSpecificsVerificationStatus(
+ entry.GetVerificationStatus(ADDRESS_HOME_APT_NUM)));
+ specifics->set_address_home_floor_status(
+ ConvertProfileToSpecificsVerificationStatus(
+ entry.GetVerificationStatus(ADDRESS_HOME_FLOOR)));
specifics->set_address_home_premise_name_status(
ConvertProfileToSpecificsVerificationStatus(
entry.GetVerificationStatus(ADDRESS_HOME_PREMISE_NAME)));
@@ -250,6 +265,17 @@ std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
profile->SetRawInfoWithVerificationStatus(
+ NAME_FULL_WITH_HONORIFIC_PREFIX,
+ UTF8ToUTF16(specifics.name_full_with_honorific_size()
+ ? specifics.name_full_with_honorific(0)
+ : std::string()),
+ ConvertSpecificsToProfileVerificationStatus(
+ specifics.name_full_with_honorific_status_size()
+ ? specifics.name_full_with_honorific_status(0)
+ : AutofillProfileSpecifics::VerificationStatus::
+ AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+ profile->SetRawInfoWithVerificationStatus(
NAME_FIRST,
UTF8ToUTF16(specifics.name_first_size() ? specifics.name_first(0)
: std::string()),
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
index f6468b412a1..1388ab1f0c7 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
@@ -13,7 +13,7 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
@@ -43,8 +43,14 @@ AutofillProfile ConstructCompleteProfile() {
profile.set_use_date(base::Time::FromTimeT(1423182152));
// Set testing values and statuses for the name.
- profile.SetRawInfoWithVerificationStatus(
- NAME_HONORIFIC_PREFIX, ASCIIToUTF16(""), VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(NAME_HONORIFIC_PREFIX,
+ ASCIIToUTF16("Dr."),
+ VerificationStatus::kObserved);
+
+ profile.SetRawInfoWithVerificationStatus(NAME_FULL_WITH_HONORIFIC_PREFIX,
+ ASCIIToUTF16("Dr. John K. Doe"),
+ VerificationStatus::kFormatted);
+
profile.SetRawInfoWithVerificationStatus(NAME_FULL,
ASCIIToUTF16("John K. Doe"),
VerificationStatus::kUserVerified);
@@ -65,15 +71,17 @@ AutofillProfile ConstructCompleteProfile() {
profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("user@example.com"));
profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1.800.555.1234"));
profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google, Inc."));
- profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("123 Fake St.\n"
- "Apt. 42"),
- VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS,
+ ASCIIToUTF16("123 Fake St. Dep Premise\n"
+ "Apt. 10 Floor 2"),
+ VerificationStatus::kObserved);
// Set testing values and statuses for the address.
- EXPECT_EQ(ASCIIToUTF16("123 Fake St."),
+ EXPECT_EQ(ASCIIToUTF16("123 Fake St. Dep Premise"),
profile.GetRawInfo(ADDRESS_HOME_LINE1));
- EXPECT_EQ(ASCIIToUTF16("Apt. 42"), profile.GetRawInfo(ADDRESS_HOME_LINE2));
+ EXPECT_EQ(ASCIIToUTF16("Apt. 10 Floor 2"),
+ profile.GetRawInfo(ADDRESS_HOME_LINE2));
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_CITY,
ASCIIToUTF16("Mountain View"),
@@ -98,19 +106,23 @@ AutofillProfile ConstructCompleteProfile() {
VerificationStatus::kObserved);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_NAME,
- ASCIIToUTF16("Street Name"),
+ ASCIIToUTF16("Fake St."),
+ VerificationStatus::kFormatted);
+ profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_DEPENDENT_STREET_NAME,
+ ASCIIToUTF16("Dep"),
VerificationStatus::kFormatted);
- profile.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_DEPENDENT_STREET_NAME, ASCIIToUTF16("Dependent Street Name"),
- VerificationStatus::kFormatted);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER,
- ASCIIToUTF16("House Number"),
+ ASCIIToUTF16("123"),
VerificationStatus::kFormatted);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_SUBPREMISE,
- ASCIIToUTF16("Subpremise"),
- VerificationStatus::kFormatted);
+ ASCIIToUTF16("Apt. 10 Floor 2"),
+ VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_APT_NUM, ASCIIToUTF16("10"), VerificationStatus::kParsed);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_FLOOR, ASCIIToUTF16("2"), VerificationStatus::kParsed);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_PREMISE_NAME,
ASCIIToUTF16("Premise"),
@@ -133,10 +145,15 @@ AutofillProfileSpecifics ConstructCompleteSpecifics() {
specifics.set_use_date(1423182152);
// Set values and statuses for the names.
- specifics.add_name_honorific("");
+ specifics.add_name_honorific("Dr.");
specifics.add_name_honorific_status(
AutofillProfileSpecifics::VerificationStatus::
- AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED);
+ AutofillProfileSpecifics_VerificationStatus_OBSERVED);
+
+ specifics.add_name_full_with_honorific("Dr. John K. Doe");
+ specifics.add_name_full_with_honorific_status(
+ AutofillProfileSpecifics::VerificationStatus::
+ AutofillProfileSpecifics_VerificationStatus_FORMATTED);
specifics.add_name_first("John");
specifics.add_name_first_status(
@@ -181,31 +198,38 @@ AutofillProfileSpecifics ConstructCompleteSpecifics() {
// Set values and statuses for the address.
// Address lines are derived from the home street address and do not have an
// independent status.
- specifics.set_address_home_line1("123 Fake St.");
- specifics.set_address_home_line2("Apt. 42");
+ specifics.set_address_home_line1("123 Fake St. Dep Premise");
+ specifics.set_address_home_line2("Apt. 10 Floor 2");
specifics.set_address_home_street_address(
- "123 Fake St.\n"
- "Apt. 42");
+ "123 Fake St. Dep Premise\n"
+ "Apt. 10 Floor 2");
specifics.set_address_home_street_address_status(
sync_pb::AutofillProfileSpecifics_VerificationStatus::
AutofillProfileSpecifics_VerificationStatus_OBSERVED);
- specifics.set_address_home_thoroughfare_name("Street Name");
+ specifics.set_address_home_thoroughfare_name("Fake St.");
specifics.set_address_home_thoroughfare_name_status(
sync_pb::AutofillProfileSpecifics_VerificationStatus_FORMATTED);
- specifics.set_address_home_dependent_thoroughfare_name(
- "Dependent Street Name");
+ specifics.set_address_home_dependent_thoroughfare_name("Dep");
specifics.set_address_home_dependent_thoroughfare_name_status(
sync_pb::AutofillProfileSpecifics_VerificationStatus_FORMATTED);
- specifics.set_address_home_thoroughfare_number("House Number");
+ specifics.set_address_home_thoroughfare_number("123");
specifics.set_address_home_thoroughfare_number_status(
sync_pb::AutofillProfileSpecifics_VerificationStatus_FORMATTED);
- specifics.set_address_home_subpremise_name("Subpremise");
+ specifics.set_address_home_subpremise_name("Apt. 10 Floor 2");
specifics.set_address_home_subpremise_name_status(
- sync_pb::AutofillProfileSpecifics_VerificationStatus_FORMATTED);
+ sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED);
+
+ specifics.set_address_home_apt_num("10");
+ specifics.set_address_home_apt_num_status(
+ sync_pb::AutofillProfileSpecifics_VerificationStatus_PARSED);
+
+ specifics.set_address_home_floor("2");
+ specifics.set_address_home_floor_status(
+ sync_pb::AutofillProfileSpecifics_VerificationStatus_PARSED);
specifics.set_address_home_premise_name("Premise");
specifics.set_address_home_premise_name_status(
@@ -258,14 +282,15 @@ class AutofillProfileSyncUtilTest : public testing::Test {
// the server.
TEST_F(AutofillProfileSyncUtilTest, CreateEntityDataFromAutofillProfile) {
base::test::ScopedFeatureList structured_names_feature;
- // With those two features enabled, the AutofillProfile supports all tokens
+ // With those three features enabled, the AutofillProfile supports all tokens
// and statuses assignable in the specifics. If one of those features is
// disabled, for some tokens
// AutofillProfile::GetRawInfo(AutofillProfile::SetRawInfo()) is not the
// identify function. The same is true for the verification status.
structured_names_feature.InitWithFeatures(
{features::kAutofillEnableSupportForMoreStructureInAddresses,
- features::kAutofillEnableSupportForMoreStructureInNames},
+ features::kAutofillEnableSupportForMoreStructureInNames,
+ features::kAutofillEnableSupportForHonorificPrefixes},
{});
AutofillProfile profile = ConstructCompleteProfile();
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc b/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc
index 14f084dc981..aabb458d126 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/i18n/case_conversion.h"
-#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
#include "components/autofill/core/browser/geo/country_data.h"
diff --git a/chromium/components/autofill/core/browser/autofill_provider.cc b/chromium/components/autofill/core/browser/autofill_provider.cc
index 8cea5630a05..0c6c3c5f60e 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.cc
+++ b/chromium/components/autofill/core/browser/autofill_provider.cc
@@ -7,6 +7,18 @@
#include "components/autofill/core/browser/autofill_handler_proxy.h"
namespace autofill {
+namespace {
+bool g_is_download_manager_disabled_for_testing = false;
+}
+
+// static
+bool AutofillProvider::is_download_manager_disabled_for_testing() {
+ return g_is_download_manager_disabled_for_testing;
+}
+
+void AutofillProvider::set_is_download_manager_disabled_for_testing() {
+ g_is_download_manager_disabled_for_testing = true;
+}
AutofillProvider::AutofillProvider() {}
diff --git a/chromium/components/autofill/core/browser/autofill_provider.h b/chromium/components/autofill/core/browser/autofill_provider.h
index 1d9b93d8535..4ea027b0d67 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.h
+++ b/chromium/components/autofill/core/browser/autofill_provider.h
@@ -8,6 +8,7 @@
#include "base/time/time.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
+#include "components/autofill/core/common/signatures.h"
namespace gfx {
class RectF;
@@ -24,6 +25,9 @@ class AutofillProvider {
AutofillProvider();
virtual ~AutofillProvider();
+ static bool is_download_manager_disabled_for_testing();
+ static void set_is_download_manager_disabled_for_testing();
+
virtual void OnQueryFormFieldAutofill(AutofillHandlerProxy* handler,
int32_t id,
const FormData& form,
@@ -65,11 +69,15 @@ class AutofillProvider {
base::TimeTicks timestamp) = 0;
virtual void OnFormsSeen(AutofillHandlerProxy* handler,
- const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) = 0;
+ const std::vector<FormData>& forms) = 0;
virtual void OnHidePopup(AutofillHandlerProxy* handler) = 0;
+ virtual void OnServerPredictionsAvailable(AutofillHandlerProxy* handler) = 0;
+
+ virtual void OnServerQueryRequestError(AutofillHandlerProxy* handler,
+ FormSignature form_signature) = 0;
+
virtual void Reset(AutofillHandlerProxy* handler) = 0;
void SendFormDataToRenderer(AutofillHandlerProxy* handler,
diff --git a/chromium/components/autofill/core/browser/autofill_provider_unittest.cc b/chromium/components/autofill/core/browser/autofill_provider_unittest.cc
new file mode 100644
index 00000000000..567d391e3fb
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_provider_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_handler_proxy.h"
+#include "components/autofill/core/browser/test_autofill_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+class AutofillHandlerProxyTestHelper : public AutofillHandlerProxy {
+ public:
+ explicit AutofillHandlerProxyTestHelper(AutofillProvider* autofill_provider)
+ : AutofillHandlerProxy(nullptr,
+ nullptr,
+ autofill_provider,
+ DISABLE_AUTOFILL_DOWNLOAD_MANAGER) {}
+
+ void SimulatePropagateAutofillPredictions() {
+ PropagateAutofillPredictions(nullptr, std::vector<FormStructure*>());
+ }
+
+ void SimulateOnQueryFormFieldAutofillImpl() {
+ OnQueryFormFieldAutofillImpl(0, FormData(), FormFieldData(), gfx::RectF(),
+ /*autoselect_first_suggestion=*/false);
+ }
+};
+
+class AutofillProviderTestHelper : public TestAutofillProvider {
+ public:
+ bool HasServerPrediction() const { return handler_->has_server_prediction(); }
+
+ private:
+ // AutofillProvider
+ void OnQueryFormFieldAutofill(AutofillHandlerProxy* handler,
+ int32_t id,
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ bool autoselect_first_suggestion) override {
+ handler_ = handler;
+ }
+ void OnServerQueryRequestError(AutofillHandlerProxy* handler,
+ FormSignature form_signature) override {}
+
+ AutofillHandlerProxy* handler_;
+};
+
+class AutofillProviderTest : public testing::Test {
+ public:
+ void SetUp() override {
+ autofill_provider_test_helper_ =
+ std::make_unique<AutofillProviderTestHelper>();
+ autofill_handler_proxy_test_helper_ =
+ std::make_unique<AutofillHandlerProxyTestHelper>(
+ autofill_provider_test_helper_.get());
+ }
+
+ AutofillProviderTestHelper* autofill_provider_test_helper() {
+ return autofill_provider_test_helper_.get();
+ }
+
+ AutofillHandlerProxyTestHelper* autofill_handler_proxy_test_helper() {
+ return autofill_handler_proxy_test_helper_.get();
+ }
+
+ private:
+ std::unique_ptr<AutofillProviderTestHelper> autofill_provider_test_helper_;
+ std::unique_ptr<AutofillHandlerProxyTestHelper>
+ autofill_handler_proxy_test_helper_;
+};
+
+TEST_F(AutofillProviderTest, HasServerPredictionAfterQuery) {
+ // Simulate the result arrives after starting autofill.
+ autofill_handler_proxy_test_helper()->SimulateOnQueryFormFieldAutofillImpl();
+ EXPECT_FALSE(autofill_provider_test_helper()->HasServerPrediction());
+ autofill_handler_proxy_test_helper()->SimulatePropagateAutofillPredictions();
+ EXPECT_TRUE(autofill_provider_test_helper()->HasServerPrediction());
+ autofill_handler_proxy_test_helper()->Reset();
+ EXPECT_FALSE(autofill_provider_test_helper()->HasServerPrediction());
+}
+
+TEST_F(AutofillProviderTest, HasServerPredictionBeforeQuery) {
+ // Simulate the result arrives before starting autofill.
+ autofill_handler_proxy_test_helper()->SimulatePropagateAutofillPredictions();
+ autofill_handler_proxy_test_helper()->SimulateOnQueryFormFieldAutofillImpl();
+ EXPECT_TRUE(autofill_provider_test_helper()->HasServerPrediction());
+ autofill_handler_proxy_test_helper()->Reset();
+ EXPECT_FALSE(autofill_provider_test_helper()->HasServerPrediction());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index 60997b8bb58..ae58f14698e 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -18,7 +18,11 @@ const char kRegionIgnoredRe[] =
"province|region|other"
"|provincia" // es
"|bairro|suburb"; // pt-BR, pt-PT
-const char kAddressNameIgnoredRe[] = "address.*nickname|address.*label";
+const char kAddressNameIgnoredRe[] =
+ "address.*nickname|address.*label"
+ "|adres ([İi]sim|başlığı|adı)" // tr
+ "|identificação do endereço" // pt-BR, pt-PT
+ "|(label|judul|nama) alamat"; // id
const char kCompanyRe[] =
"company|business|organization|organisation"
"|(?<!con)firma|firmenname" // de-DE
@@ -29,44 +33,61 @@ const char kCompanyRe[] =
"|название.?компании" // ru
"|单位|公司" // zh-CN
"|شرکت" // fa
- "|회사|직장"; // ko-KR
+ "|회사|직장" // ko-KR
+ "|(nama.?)?perusahaan"; // id
const char kStreetNameRe[] =
- "stra(ss|ß)e" // de
- "|street" // en
- "|улица|название.?улицы" // ru
- "|rua|avenida" // pt-PT, pt-BR
- "|((?<!do |de )endereço)"; // pt-BR
+ "stra(ss|ß)e" // de
+ "|street" // en
+ "|улица|название.?улицы" // ru
+ "|rua|avenida" // pt-PT, pt-BR
+ "|((?<!do |de )endereço)" // pt-BR
+ "|calle"; // es-MX
const char kHouseNumberRe[] =
"(house.?|street.?|^)number" // en
"|(haus|^)nummer" // de
"|^\\*?.?número(.?\\*?$| da residência)" // pt-BR, pt-PT
- "|дом|номер.?дома"; // ru
+ "|дом|номер.?дома" // ru
+ "|exterior"; // es-MX
+const char kApartmentNumberRe[] =
+ "apartment" // en
+ "|interior" // es-MX
+ "|n(u|ú)mero.*app?art(a|e)ment" // es,fr,it
+ "|Wohnung" // de
+ "|квартир"; // ru
const char kAddressLine1Re[] =
"^address$|address[_-]?line(one)?|address1|addr1|street"
"|(?:shipping|billing)address$"
- "|strasse|straße|hausnummer|housenumber" // de-DE
- "|house.?name" // en-GB
- "|direccion|dirección" // es
- "|adresse" // fr-FR
- "|indirizzo" // it-IT
- "|^住所$|住所1" // ja-JP
- "|morada|((?<!do |de )endereço)" // pt-BR, pt-PT
- "|Адрес" // ru
- "|地址" // zh-CN
- "|(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)" // tr
- "|^주소.?$|주소.?1"; // ko-KR
+ "|strasse|straße|hausnummer|housenumber" // de-DE
+ "|house.?name" // en-GB
+ "|direccion|dirección" // es
+ "|adresse" // fr-FR
+ "|indirizzo" // it-IT
+ "|^住所$|住所1" // ja-JP
+ "|morada|((?<!do |de )endereço)" // pt-BR, pt-PT
+ "|Адрес" // ru
+ "|地址" // zh-CN
+ "|(\\b|_)adres(?! tarifi)(\\b|_)" // tr
+ "|^주소.?$|주소.?1" // ko-KR
+ "|^alamat"; // id
const char kAddressLine1LabelRe[] =
"(^\\W*address)"
"|(address\\W*$)"
"|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|"
"recipient|home|work|office|school|business|mail)[\\s\\-]+address"
"|address\\s+(of|for|to|from)"
- "|adresse" // fr-FR
- "|indirizzo" // it-IT
- "|住所" // ja-JP
- "|地址" // zh-CN
- "|(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)" // tr
- "|주소"; // ko-KR
+ "|adresse" // fr-FR
+ "|indirizzo" // it-IT
+ "|住所" // ja-JP
+ "|地址" // zh-CN
+ "|(\\b|_)adres(?! tarifi)(\\b|_)" // tr
+ "|주소" // ko-KR
+ "|^alamat" // id
+ // Should contain street and any other address component, in any order
+ "|street.*(house|building|apartment|floor)" // en
+ "|(house|building|apartment|floor).*street"
+ "|(sokak|cadde).*(apartman|bina|daire|mahalle)" // tr
+ "|(apartman|bina|daire|mahalle).*(sokak|cadde)"
+ "|улиц.*(дом|корпус|квартир|этаж)|(дом|корпус|квартир|этаж).*улиц"; // ru
const char kAddressLine2Re[] =
"address[_-]?line(2|two)|address2|addr2|street|suite|unit"
"|adresszusatz|ergänzende.?angaben" // de-DE
@@ -98,7 +119,8 @@ const char kCountryRe[] =
"|国家" // zh-CN
"|국가|나라" // ko-KR
"|(\\b|_)(ülke|ulce|ulke)(\\b|_)" // tr
- "|کشور"; // fa
+ "|کشور" // fa
+ "|negara"; // id
const char kCountryLocationRe[] = "location";
const char kZipCodeRe[] =
"zip|postal|post.*code|pcode"
@@ -115,10 +137,16 @@ const char kZipCodeRe[] =
"|邮政编码|邮编" // zh-CN
"|郵遞區號" // zh-TW
"|(\\b|_)posta kodu(\\b|_)" // tr
- "|우편.?번호"; // ko-KR
+ "|우편.?번호" // ko-KR
+ "|kode.?pos"; // id
const char kZip4Re[] =
"zip|^-$|post2"
"|codpos2"; // pt-BR, pt-PT
+const char kDependentLocalityRe[] =
+ "neighbo(u)?rhood" // en
+ "|bairro" // pt-BR, pt-PT
+ "|mahalle|köy" // tr
+ "|kecamatan"; // id
const char kCityRe[] =
"city|town"
"|\\bort\\b|stadt" // de-DE
@@ -128,7 +156,7 @@ const char kCityRe[] =
"|localita" // it-IT
"|市区町村" // ja-JP
"|cidade|município" // pt-BR, pt-PT
- "|Город|Населённый.?пункт" // ru
+ "|Город|Насел(е|ё)нный.?пункт" // ru
"|市" // zh-CN
"|分區" // zh-TW
"|شهر" // fa
@@ -136,7 +164,8 @@ const char kCityRe[] =
"|ग्राम|गाँव" // hi for village
"|നഗരം|ഗ്രാമം" // ml for town|village
"|((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))" // tr
- "|^시[^도·・]|시[·・]?군[·・]?구"; // ko-KR
+ "|^시[^도·・]|시[·・]?군[·・]?구" // ko-KR
+ "|kota|kabupaten"; // id
const char kStateRe[] =
"(?<!(united|hist|history).?)state|county|region|province"
"|county|principality" // en-UK
@@ -149,7 +178,8 @@ const char kStateRe[] =
"|استان" // fa
"|राज्य" // hi
"|((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))" // tr
- "|^시[·・]?도"; // ko-KR
+ "|^시[·・]?도" // ko-KR
+ "|provinci"; // id
/////////////////////////////////////////////////////////////////////////////
// search_field.cc
@@ -188,6 +218,7 @@ const char kNameOnCardRe[] =
"|nome.*cart" // it-IT
"|名前" // ja-JP
"|Имя.*карты" // ru
+ "|nama.*kartu" // id
"|信用卡开户名|开户名|持卡人姓名" // zh-CN
"|持卡人姓名"; // zh-TW
const char kNameOnCardContextualRe[] = "name";
@@ -196,6 +227,7 @@ const char kCardNumberRe[] =
"|(?<!telefon|haus|person|fødsels)nummer" // de-DE, sv-SE, no
"|カード番号" // ja-JP
"|Номер.*карты" // ru
+ "|no.*kartu" // id
"|信用卡号|信用卡号码" // zh-CN
"|信用卡卡號" // zh-TW
"|카드" // ko-KR
@@ -223,14 +255,15 @@ const char kCardCvcRe[] =
// Instead, we match only words beginning with "month".
const char kExpirationMonthRe[] =
"expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth"
- "|gueltig|gültig|monat" // de-DE
- "|fecha" // es
- "|date.*exp" // fr-FR
- "|scadenza" // it-IT
- "|有効期限" // ja-JP
- "|validade" // pt-BR, pt-PT
- "|Срок действия карты" // ru
- "|月"; // zh-CN
+ "|gueltig|gültig|monat" // de-DE
+ "|fecha" // es
+ "|date.*exp" // fr-FR
+ "|scadenza" // it-IT
+ "|有効期限" // ja-JP
+ "|validade" // pt-BR, pt-PT
+ "|Срок действия карты" // ru
+ "|masa berlaku|berlaku hingga" // id
+ "|月"; // zh-CN
const char kExpirationYearRe[] =
"exp|^/|(add)?year"
"|ablaufdatum|gueltig|gültig|jahr" // de-DE
@@ -239,6 +272,7 @@ const char kExpirationYearRe[] =
"|有効期限" // ja-JP
"|validade" // pt-BR, pt-PT
"|Срок действия карты" // ru
+ "|masa berlaku|berlaku hingga" // id
"|年|有效期"; // zh-CN
// Used to match a expiration date field with a two digit year.
@@ -277,12 +311,12 @@ const char kDayRe[] = "day";
/////////////////////////////////////////////////////////////////////////////
const char kEmailRe[] =
"e.?mail"
- "|courriel" // fr
- "|correo.*electr(o|ó)nico" // es-ES
- "|メールアドレス" // ja-JP
- "|Электронной.?Почты" // ru
- "|邮件|邮箱" // zh-CN
- "|電郵地址" // zh-TW
+ "|courriel" // fr
+ "|correo.*electr(o|ó)nico" // es-ES
+ "|メールアドレス" // ja-JP
+ "|Электронн(ая|ой).?Почт(а|ы)" // ru
+ "|邮件|邮箱" // zh-CN
+ "|電郵地址" // zh-TW
"|ഇ-മെയില്‍|ഇലക്ട്രോണിക്.?"
"മെയിൽ" // ml
"|ایمیل|پست.*الکترونیک" // fa
@@ -295,21 +329,22 @@ const char kEmailRe[] =
/////////////////////////////////////////////////////////////////////////////
const char kNameIgnoredRe[] =
"user.?name|user.?id|nickname|maiden name|title|prefix|suffix"
- "|adres başlığınız" // tr
"|vollständiger.?name" // de-DE
"|用户名" // zh-CN
"|(?:사용자.?)?아이디|사용자.?ID"; // ko-KR
const char kNameRe[] =
"^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name"
- "|name.*first.*last|firstandlastname"
+ "|name.*first.*last|firstandlastname|contact.?(name|person)"
"|nombre.*y.*apellidos" // es
- "|^nom(?!bre)" // fr-FR
+ "|^nom(?![a-zA-Z])" // fr-FR
"|お名前|氏名" // ja-JP
"|^nome" // pt-BR, pt-PT
"|نام.*نام.*خانوادگی" // fa
"|姓名" // zh-CN
+ "|контактное.?лицо" // ru
"|(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)" // tr
- "|성명"; // ko-KR
+ "|성명" // ko-KR
+ "|nama.?(lengkap|penerima|kamu)"; // id
const char kNameSpecificRe[] =
"^name"
"|^nom" // fr-FR
@@ -326,14 +361,15 @@ const char kFirstNameRe[] =
"|이름" // ko-KR
"|പേര്" // ml
"|(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)" // tr
- "|नाम"; // hi
+ "|नाम" // hi
+ "|nama depan"; // id
const char kMiddleInitialRe[] = "middle.*initial|m\\.i\\.|mi$|\\bmi\\b";
const char kMiddleNameRe[] = "middle.*name|mname|middle$";
const char kLastNameRe[] =
"last.*name|lname|surname(?!\\d)|last$|secondname|family.*name"
"|nachname" // de-DE
"|apellidos?" // es
- "|famille|^nom(?!bre)" // fr-FR
+ "|famille|^nom(?![a-zA-Z])" // fr-FR
"|cognome" // it-IT
"|姓" // ja-JP
"|apelidos|surename|sobrenome" // pt-BR, pt-PT
@@ -342,7 +378,8 @@ const char kLastNameRe[] =
"|उपनाम" // hi
"|മറുപേര്" // ml
"|(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)" // tr
- "|\\b성(?:[^명]|\\b)"; // ko-KR
+ "|\\b성(?:[^명]|\\b)" // ko-KR
+ "|nama belakang"; // id
const char kNameLastFirstRe[] =
"(primer.*apellido)" // es
"|(apellido1)" // es
@@ -360,7 +397,7 @@ const char kHonorificPrefixRe[] =
"|(salutation(?! and given name))" // en
"|titolo" // it-IT
"|titre" // fr-FR
- "|обраще́ние|зва́ние" // ru
+ "|обращение|звание" // ru
"|προσφώνηση" // el
"|hitap"; // tr
/////////////////////////////////////////////////////////////////////////////
@@ -368,17 +405,18 @@ const char kHonorificPrefixRe[] =
/////////////////////////////////////////////////////////////////////////////
const char kPhoneRe[] =
"phone|mobile|contact.?number"
- "|telefonnummer" // de-DE
- "|telefono|teléfono" // es
- "|telfixe" // fr-FR
- "|電話" // ja-JP
- "|telefone|telemovel" // pt-BR, pt-PT
- "|телефон" // ru
- "|मोबाइल" // hi for mobile
- "|(\\b|_|\\*)telefon(\\b|_|\\*)" // tr
- "|电话" // zh-CN
- "|മൊബൈല്‍" // ml for mobile
- "|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?"; // ko-KR
+ "|telefonnummer" // de-DE
+ "|telefono|teléfono" // es
+ "|telfixe" // fr-FR
+ "|電話" // ja-JP
+ "|telefone|telemovel" // pt-BR, pt-PT
+ "|телефон" // ru
+ "|मोबाइल" // hi for mobile
+ "|(\\b|_|\\*)telefon(\\b|_|\\*)" // tr
+ "|电话" // zh-CN
+ "|മൊബൈല്‍" // ml for mobile
+ "|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?" // ko-KR
+ "|telepon|ponsel|(nomor|no\\.?).?(hp|handphone)"; // id
const char kAugmentedPhoneCountryCodeRe[] =
"^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$";
const char kCountryCodeRe[] =
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.h b/chromium/components/autofill/core/browser/autofill_regex_constants.h
index de9ef0ecba2..d755da5d990 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.h
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.h
@@ -12,6 +12,7 @@ extern const char kRegionIgnoredRe[];
extern const char kAddressNameIgnoredRe[];
extern const char kCompanyRe[];
extern const char kHouseNumberRe[];
+extern const char kApartmentNumberRe[];
extern const char kStreetNameRe[];
extern const char kAddressLine1Re[];
extern const char kAddressLine1LabelRe[];
@@ -20,9 +21,11 @@ extern const char kAddressLine2LabelRe[];
extern const char kAddressLinesExtraRe[];
extern const char kAddressLookupRe[];
extern const char kCountryRe[];
+extern const char kDependentLocality[];
extern const char kCountryLocationRe[];
extern const char kZipCodeRe[];
extern const char kZip4Re[];
+extern const char kDependentLocalityRe[];
extern const char kCityRe[];
extern const char kStateRe[];
extern const char kNameOnCardRe[];
diff --git a/chromium/components/autofill/core/browser/autofill_regexes.cc b/chromium/components/autofill/core/browser/autofill_regexes.cc
index 4875a113f8b..fc387879ecf 100644
--- a/chromium/components/autofill/core/browser/autofill_regexes.cc
+++ b/chromium/components/autofill/core/browser/autofill_regexes.cc
@@ -4,8 +4,8 @@
#include "components/autofill/core/browser/autofill_regexes.h"
+#include <map>
#include <memory>
-#include <unordered_map>
#include <utility>
#include "base/check.h"
@@ -28,19 +28,20 @@ class AutofillRegexes {
AutofillRegexes() = default;
// Returns the compiled regex matcher corresponding to |pattern|.
- icu::RegexMatcher* GetMatcher(const base::string16& pattern);
+ icu::RegexMatcher* GetMatcher(const base::StringPiece16& pattern);
private:
~AutofillRegexes() = default;
// Maps patterns to their corresponding regex matchers.
- std::unordered_map<base::string16, std::unique_ptr<icu::RegexMatcher>>
+ std::map<base::string16, std::unique_ptr<icu::RegexMatcher>, std::less<>>
matchers_;
DISALLOW_COPY_AND_ASSIGN(AutofillRegexes);
};
-icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) {
+icu::RegexMatcher* AutofillRegexes::GetMatcher(
+ const base::StringPiece16& pattern) {
auto it = matchers_.find(pattern);
if (it == matchers_.end()) {
const icu::UnicodeString icu_pattern(false, pattern.data(),
@@ -62,8 +63,8 @@ icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) {
namespace autofill {
-bool MatchesPattern(const base::string16& input,
- const base::string16& pattern,
+bool MatchesPattern(const base::StringPiece16& input,
+ const base::StringPiece16& pattern,
base::string16* match,
int32_t group_to_be_captured) {
static base::NoDestructor<AutofillRegexes> g_autofill_regexes;
diff --git a/chromium/components/autofill/core/browser/autofill_regexes.h b/chromium/components/autofill/core/browser/autofill_regexes.h
index 585e88e20b6..4ec3fce0f78 100644
--- a/chromium/components/autofill/core/browser/autofill_regexes.h
+++ b/chromium/components/autofill/core/browser/autofill_regexes.h
@@ -6,6 +6,7 @@
#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
// Parsing utilities.
namespace autofill {
@@ -13,8 +14,8 @@ namespace autofill {
// Case-insensitive regular expression matching.
// Returns true if |pattern| is found in |input|.
// The |group_to_be_captured| numbered group is captured into |match|.
-bool MatchesPattern(const base::string16& input,
- const base::string16& pattern,
+bool MatchesPattern(const base::StringPiece16& input,
+ const base::StringPiece16& pattern,
base::string16* match = nullptr,
int32_t group_to_be_captured = 0);
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index 0b711b69c67..4853951bac6 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -83,6 +83,37 @@ FieldRendererId MakeFieldRendererId() {
} // namespace
+void SetFormGroupValues(FormGroup& form_group,
+ const std::vector<FormGroupValue>& values) {
+ for (const auto& value : values) {
+ form_group.SetRawInfoWithVerificationStatus(
+ value.type, base::UTF8ToUTF16(value.value), value.verification_status);
+ }
+}
+
+void VerifyFormGroupValues(const FormGroup& form_group,
+ const std::vector<FormGroupValue>& values,
+ bool ignore_status) {
+ for (const auto& value : values) {
+ SCOPED_TRACE(testing::Message()
+ << "Expected for type "
+ << AutofillType::ServerFieldTypeToString(value.type) << "\n\t"
+ << value.value << " with status "
+ << (ignore_status ? "(ignored)" : "")
+ << value.verification_status << "\nFound:"
+ << "\n\t" << form_group.GetRawInfo(value.type)
+ << " with status "
+ << form_group.GetVerificationStatus(value.type));
+
+ EXPECT_EQ(form_group.GetRawInfo(value.type),
+ base::UTF8ToUTF16(value.value));
+ if (!ignore_status) {
+ EXPECT_EQ(form_group.GetVerificationStatus(value.type),
+ value.verification_status);
+ }
+ }
+}
+
std::unique_ptr<PrefService> PrefServiceForTesting() {
scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
new user_prefs::PrefRegistrySyncable());
@@ -176,9 +207,9 @@ void CreateTestAddressFormData(FormData* form,
form->button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
- form->url = GURL("http://myform.com/form.html");
- form->full_url = GURL("http://myform.com/form.html?foo=bar");
- form->action = GURL("http://myform.com/submit.html");
+ form->url = GURL("https://myform.com/form.html");
+ form->full_url = GURL("https://myform.com/form.html?foo=bar");
+ form->action = GURL("https://myform.com/submit.html");
form->is_action_empty = true;
form->main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
@@ -216,6 +247,10 @@ void CreateTestAddressFormData(FormData* form,
form->fields.push_back(field);
type_set.clear();
type_set.insert(ADDRESS_HOME_LINE2);
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInAddresses)) {
+ type_set.insert(ADDRESS_HOME_SUBPREMISE);
+ }
types->push_back(type_set);
test::CreateTestFormField("City", "city", "", "text", &field);
form->fields.push_back(field);
@@ -254,9 +289,9 @@ void CreateTestPersonalInformationFormData(FormData* form,
form->unique_renderer_id = MakeFormRendererId();
form->name =
ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : "");
- form->url = GURL("http://myform.com/form.html");
- form->full_url = GURL("http://myform.com/form.html?foo=bar");
- form->action = GURL("http://myform.com/submit.html");
+ form->url = GURL("https://myform.com/form.html");
+ form->full_url = GURL("https://myform.com/form.html?foo=bar");
+ form->action = GURL("https://myform.com/submit.html");
form->main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
@@ -281,7 +316,7 @@ void CreateTestCreditCardFormData(FormData* form,
ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : "");
if (is_https) {
form->url = GURL("https://myform.com/form.html");
- form->full_url = GURL("http://myform.com/form.html?foo=bar");
+ form->full_url = GURL("https://myform.com/form.html?foo=bar");
form->action = GURL("https://myform.com/submit.html");
form->main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
@@ -324,13 +359,15 @@ void CreateTestCreditCardFormData(FormData* form,
form->fields.push_back(field);
}
-inline void check_and_set(FormGroup* profile,
- ServerFieldType type,
- const char* value) {
+inline void check_and_set(
+ FormGroup* profile,
+ ServerFieldType type,
+ const char* value,
+ structured_address::VerificationStatus status =
+ structured_address::VerificationStatus::kObserved) {
if (value) {
- profile->SetRawInfoWithVerificationStatus(
- type, base::UTF8ToUTF16(value),
- structured_address::VerificationStatus::kObserved);
+ profile->SetRawInfoWithVerificationStatus(type, base::UTF8ToUTF16(value),
+ status);
}
}
@@ -619,20 +656,22 @@ void SetProfileInfo(AutofillProfile* profile,
const char* zipcode,
const char* country,
const char* phone,
- bool finalize) {
- check_and_set(profile, NAME_FIRST, first_name);
- check_and_set(profile, NAME_MIDDLE, middle_name);
- check_and_set(profile, NAME_LAST, last_name);
- check_and_set(profile, EMAIL_ADDRESS, email);
- check_and_set(profile, COMPANY_NAME, company);
- check_and_set(profile, ADDRESS_HOME_LINE1, address1);
- check_and_set(profile, ADDRESS_HOME_LINE2, address2);
- check_and_set(profile, ADDRESS_HOME_DEPENDENT_LOCALITY, dependent_locality);
- check_and_set(profile, ADDRESS_HOME_CITY, city);
- check_and_set(profile, ADDRESS_HOME_STATE, state);
- check_and_set(profile, ADDRESS_HOME_ZIP, zipcode);
- check_and_set(profile, ADDRESS_HOME_COUNTRY, country);
- check_and_set(profile, PHONE_HOME_WHOLE_NUMBER, phone);
+ bool finalize,
+ structured_address::VerificationStatus status) {
+ check_and_set(profile, NAME_FIRST, first_name, status);
+ check_and_set(profile, NAME_MIDDLE, middle_name, status);
+ check_and_set(profile, NAME_LAST, last_name, status);
+ check_and_set(profile, EMAIL_ADDRESS, email, status);
+ check_and_set(profile, COMPANY_NAME, company, status);
+ check_and_set(profile, ADDRESS_HOME_LINE1, address1, status);
+ check_and_set(profile, ADDRESS_HOME_LINE2, address2, status);
+ check_and_set(profile, ADDRESS_HOME_DEPENDENT_LOCALITY, dependent_locality,
+ status);
+ check_and_set(profile, ADDRESS_HOME_CITY, city, status);
+ check_and_set(profile, ADDRESS_HOME_STATE, state, status);
+ check_and_set(profile, ADDRESS_HOME_ZIP, zipcode, status);
+ check_and_set(profile, ADDRESS_HOME_COUNTRY, country, status);
+ check_and_set(profile, PHONE_HOME_WHOLE_NUMBER, phone, status);
if (finalize)
profile->FinalizeAfterImport();
}
@@ -650,19 +689,20 @@ void SetProfileInfo(AutofillProfile* profile,
const char* zipcode,
const char* country,
const char* phone,
- bool finalize) {
- check_and_set(profile, NAME_FIRST, first_name);
- check_and_set(profile, NAME_MIDDLE, middle_name);
- check_and_set(profile, NAME_LAST, last_name);
- check_and_set(profile, EMAIL_ADDRESS, email);
- check_and_set(profile, COMPANY_NAME, company);
- check_and_set(profile, ADDRESS_HOME_LINE1, address1);
- check_and_set(profile, ADDRESS_HOME_LINE2, address2);
- check_and_set(profile, ADDRESS_HOME_CITY, city);
- check_and_set(profile, ADDRESS_HOME_STATE, state);
- check_and_set(profile, ADDRESS_HOME_ZIP, zipcode);
- check_and_set(profile, ADDRESS_HOME_COUNTRY, country);
- check_and_set(profile, PHONE_HOME_WHOLE_NUMBER, phone);
+ bool finalize,
+ structured_address::VerificationStatus status) {
+ check_and_set(profile, NAME_FIRST, first_name, status);
+ check_and_set(profile, NAME_MIDDLE, middle_name, status);
+ check_and_set(profile, NAME_LAST, last_name, status);
+ check_and_set(profile, EMAIL_ADDRESS, email, status);
+ check_and_set(profile, COMPANY_NAME, company, status);
+ check_and_set(profile, ADDRESS_HOME_LINE1, address1, status);
+ check_and_set(profile, ADDRESS_HOME_LINE2, address2, status);
+ check_and_set(profile, ADDRESS_HOME_CITY, city, status);
+ check_and_set(profile, ADDRESS_HOME_STATE, state, status);
+ check_and_set(profile, ADDRESS_HOME_ZIP, zipcode, status);
+ check_and_set(profile, ADDRESS_HOME_COUNTRY, country, status);
+ check_and_set(profile, PHONE_HOME_WHOLE_NUMBER, phone, status);
if (finalize)
profile->FinalizeAfterImport();
}
@@ -681,12 +721,13 @@ void SetProfileInfoWithGuid(AutofillProfile* profile,
const char* zipcode,
const char* country,
const char* phone,
- bool finalize) {
+ bool finalize,
+ structured_address::VerificationStatus status) {
if (guid)
profile->set_guid(guid);
SetProfileInfo(profile, first_name, middle_name, last_name, email, company,
address1, address2, city, state, zipcode, country, phone,
- finalize);
+ finalize, status);
}
void SetCreditCardInfo(CreditCard* credit_card,
@@ -830,28 +871,6 @@ void FillUploadField(AutofillUploadContents::Field* field,
type_validities->add_validity(validity_states[i]);
}
-void FillQueryField(AutofillQueryContents::Form::Field* field,
- unsigned signature,
- const char* name,
- const char* control_type) {
- field->set_signature(signature);
- if (name)
- field->set_name(name);
- if (control_type)
- field->set_type(control_type);
-}
-
-void FillQueryField(AutofillPageQueryRequest_Form_Field* field,
- unsigned signature,
- const char* name,
- const char* control_type) {
- field->set_signature(signature);
- if (name)
- field->set_name(name);
- if (control_type)
- field->set_control_type(control_type);
-}
-
void GenerateTestAutofillPopup(
AutofillExternalDelegate* autofill_external_delegate) {
int query_id = 1;
@@ -875,26 +894,22 @@ std::string ObfuscatedCardDigitsAsUTF8(const std::string& str) {
std::string NextMonth() {
base::Time::Exploded now;
- // Using AutofillClock here might cause test flakiness. See crbug/1108232.
- base::Time::Now().LocalExplode(&now);
+ AutofillClock::Now().LocalExplode(&now);
return base::StringPrintf("%02d", now.month % 12 + 1);
}
std::string LastYear() {
base::Time::Exploded now;
- // Using AutofillClock here might cause test flakiness. See crbug/1108232.
- base::Time::Now().LocalExplode(&now);
+ AutofillClock::Now().LocalExplode(&now);
return base::NumberToString(now.year - 1);
}
std::string NextYear() {
base::Time::Exploded now;
- // Using AutofillClock here might cause test flakiness. See crbug/1108232.
- base::Time::Now().LocalExplode(&now);
+ AutofillClock::Now().LocalExplode(&now);
return base::NumberToString(now.year + 1);
}
std::string TenYearsFromNow() {
base::Time::Exploded now;
- // Using AutofillClock here might cause test flakiness. See crbug/1108232.
- base::Time::Now().LocalExplode(&now);
+ AutofillClock::Now().LocalExplode(&now);
return base::NumberToString(now.year + 10);
}
@@ -912,5 +927,42 @@ std::vector<FormSignature> GetEncodedSignatures(
return all_signatures;
}
+void AddFieldSuggestionToForm(
+ const autofill::FormFieldData& field_data,
+ ServerFieldType field_type,
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion) {
+ auto* field_suggestion = form_suggestion->add_field_suggestions();
+ field_suggestion->set_field_signature(
+ CalculateFieldSignatureForField(field_data).value());
+ field_suggestion->set_primary_type_prediction(field_type);
+}
+
+void AddFieldPredictionsToForm(
+ const autofill::FormFieldData& field_data,
+ const std::vector<int>& field_types,
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion) {
+ std::vector<ServerFieldType> types;
+ for (auto type : field_types) {
+ types.emplace_back(static_cast<ServerFieldType>(type));
+ }
+ AddFieldPredictionsToForm(field_data, types, form_suggestion);
+}
+
+void AddFieldPredictionsToForm(
+ const autofill::FormFieldData& field_data,
+ const std::vector<ServerFieldType>& field_types,
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion) {
+ // According to api_v1.proto, the first element is always set to primary type.
+ auto* field_suggestion = form_suggestion->add_field_suggestions();
+ field_suggestion->set_field_signature(
+ CalculateFieldSignatureForField(field_data).value());
+ field_suggestion->set_primary_type_prediction(*field_types.begin());
+ for (auto field_type : field_types) {
+ AutofillQueryResponse_FormSuggestion_FieldSuggestion_FieldPrediction*
+ prediction = field_suggestion->add_predictions();
+ prediction->set_type(field_type);
+ }
+}
+
} // namespace test
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index fc1d97d580a..3944ae1c830 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -56,6 +56,29 @@ inline bool operator!=(const FormDataPredictions& a,
// Common utilities shared amongst Autofill tests.
namespace test {
+// A compound data type that contains the type, the value and the verification
+// status for a form group entry (an AutofillProfile).
+struct FormGroupValue {
+ ServerFieldType type;
+ std::string value;
+ structured_address::VerificationStatus verification_status =
+ structured_address::VerificationStatus::kNoStatus;
+};
+
+// Convenience declaration for multiple FormGroup values.
+using FormGroupValues = std::vector<FormGroupValue>;
+
+// Helper function to set values and verification statuses to a form group.
+void SetFormGroupValues(FormGroup& form_group,
+ const std::vector<FormGroupValue>& values);
+
+// Helper function to verify the expectation of values and verification
+// statuses in a form group. If |ignore_status| is set, status checking is
+// omitted.
+void VerifyFormGroupValues(const FormGroup& form_group,
+ const std::vector<FormGroupValue>& values,
+ bool ignore_status = false);
+
const char kEmptyOrigin[] = "";
// The following methods return a PrefService that can be used for
@@ -207,7 +230,9 @@ void SetProfileInfo(AutofillProfile* profile,
const char* zipcode,
const char* country,
const char* phone,
- bool finalize = true);
+ bool finalize = true,
+ structured_address::VerificationStatus =
+ structured_address::VerificationStatus::kObserved);
// This one doesn't require the |dependent_locality|.
void SetProfileInfo(AutofillProfile* profile,
@@ -223,23 +248,28 @@ void SetProfileInfo(AutofillProfile* profile,
const char* zipcode,
const char* country,
const char* phone,
- bool finalize = true);
-
-void SetProfileInfoWithGuid(AutofillProfile* profile,
- const char* guid,
- const char* first_name,
- const char* middle_name,
- const char* last_name,
- const char* email,
- const char* company,
- const char* address1,
- const char* address2,
- const char* city,
- const char* state,
- const char* zipcode,
- const char* country,
- const char* phone,
- bool finalize = true);
+ bool finalize = true,
+ structured_address::VerificationStatus =
+ structured_address::VerificationStatus::kObserved);
+
+void SetProfileInfoWithGuid(
+ AutofillProfile* profile,
+ const char* guid,
+ const char* first_name,
+ const char* middle_name,
+ const char* last_name,
+ const char* email,
+ const char* company,
+ const char* address1,
+ const char* address2,
+ const char* city,
+ const char* state,
+ const char* zipcode,
+ const char* country,
+ const char* phone,
+ bool finalize = true,
+ structured_address::VerificationStatus =
+ structured_address::VerificationStatus::kObserved);
// A unit testing utility that is common to a number of the Autofill unit
// tests. |SetCreditCardInfo| provides a quick way to populate a credit card
@@ -302,18 +332,6 @@ void FillUploadField(AutofillUploadContents::Field* field,
unsigned autofill_type,
const std::vector<unsigned>& validity_states);
-// Fills the query form |field| with the information passed by parameter. If the
-// value of a const char* parameter is NULL, the corresponding attribute won't
-// be set at all, as opposed to being set to empty string.
-void FillQueryField(AutofillQueryContents::Form::Field* field,
- unsigned signature,
- const char* name,
- const char* control_type);
-void FillQueryField(AutofillPageQueryRequest_Form_Field* field,
- unsigned signature,
- const char* name,
- const char* control_type);
-
// Creates the structure of signatures that would be encoded by
// FormStructure::EncodeUploadRequest() and FormStructure::EncodeQueryRequest()
// and consumed by FormStructure::ParseQueryResponse() and
@@ -337,6 +355,23 @@ std::string LastYear();
std::string NextYear();
std::string TenYearsFromNow();
+void AddFieldSuggestionToForm(
+ const autofill::FormFieldData& field_data,
+ ServerFieldType field_type,
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion);
+
+// Adds |field_types| predictions of |field_data| to |form_suggestion| query
+// response. Assumes int type can be cast to ServerFieldType.
+void AddFieldPredictionsToForm(
+ const autofill::FormFieldData& field_data,
+ const std::vector<int>& field_types,
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion);
+
+void AddFieldPredictionsToForm(
+ const autofill::FormFieldData& field_data,
+ const std::vector<ServerFieldType>& field_types,
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion);
+
} // namespace test
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc
index 2d0f844fef1..83ceb74943e 100644
--- a/chromium/components/autofill/core/browser/autofill_type.cc
+++ b/chromium/components/autofill/core/browser/autofill_type.cc
@@ -21,7 +21,8 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case NAME_MIDDLE_INITIAL:
case NAME_FULL:
case NAME_SUFFIX:
- return NAME;
+ case NAME_FULL_WITH_HONORIFIC_PREFIX:
+ return FieldTypeGroup::kName;
case NAME_BILLING_FIRST:
case NAME_BILLING_MIDDLE:
@@ -29,11 +30,11 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case NAME_BILLING_MIDDLE_INITIAL:
case NAME_BILLING_FULL:
case NAME_BILLING_SUFFIX:
- return NAME_BILLING;
+ return FieldTypeGroup::kNameBilling;
case EMAIL_ADDRESS:
case USERNAME_AND_EMAIL_ADDRESS:
- return EMAIL;
+ return FieldTypeGroup::kEmail;
case PHONE_HOME_NUMBER:
case PHONE_HOME_CITY_CODE:
@@ -41,14 +42,14 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_HOME_WHOLE_NUMBER:
case PHONE_HOME_EXTENSION:
- return PHONE_HOME;
+ return FieldTypeGroup::kPhoneHome;
case PHONE_BILLING_NUMBER:
case PHONE_BILLING_CITY_CODE:
case PHONE_BILLING_COUNTRY_CODE:
case PHONE_BILLING_CITY_AND_NUMBER:
case PHONE_BILLING_WHOLE_NUMBER:
- return PHONE_BILLING;
+ return FieldTypeGroup::kPhoneBilling;
case ADDRESS_HOME_LINE1:
case ADDRESS_HOME_LINE2:
@@ -71,7 +72,7 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case ADDRESS_HOME_ADDRESS:
case ADDRESS_HOME_ADDRESS_WITH_NAME:
case ADDRESS_HOME_FLOOR:
- return ADDRESS_HOME;
+ return FieldTypeGroup::kAddressHome;
case ADDRESS_BILLING_LINE1:
case ADDRESS_BILLING_LINE2:
@@ -84,7 +85,7 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case ADDRESS_BILLING_STREET_ADDRESS:
case ADDRESS_BILLING_SORTING_CODE:
case ADDRESS_BILLING_DEPENDENT_LOCALITY:
- return ADDRESS_BILLING;
+ return FieldTypeGroup::kAddressBilling;
case CREDIT_CARD_NAME_FULL:
case CREDIT_CARD_NAME_FIRST:
@@ -97,10 +98,10 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
case CREDIT_CARD_TYPE:
case CREDIT_CARD_VERIFICATION_CODE:
- return CREDIT_CARD;
+ return FieldTypeGroup::kCreditCard;
case COMPANY_NAME:
- return COMPANY;
+ return FieldTypeGroup::kCompany;
case PASSWORD:
case ACCOUNT_CREATION_PASSWORD:
@@ -112,7 +113,7 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case NOT_PASSWORD:
case SINGLE_USERNAME:
case NOT_USERNAME:
- return PASSWORD_FIELD;
+ return FieldTypeGroup::kPasswordField;
case NO_SERVER_DATA:
case EMPTY_TYPE:
@@ -126,24 +127,24 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case MERCHANT_EMAIL_SIGNUP:
case MERCHANT_PROMO_CODE:
case UPI_VPA:
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
case MAX_VALID_FIELD_TYPE:
NOTREACHED();
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
case USERNAME:
- return USERNAME_FIELD;
+ return FieldTypeGroup::kUsernameField;
case PRICE:
case SEARCH_TERM:
- return UNFILLABLE;
+ return FieldTypeGroup::kUnfillable;
case UNKNOWN_TYPE:
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
}
NOTREACHED();
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
}
FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
@@ -155,10 +156,11 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
case HTML_TYPE_ADDITIONAL_NAME:
case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
case HTML_TYPE_FAMILY_NAME:
- return field_mode == HTML_MODE_BILLING ? NAME_BILLING : NAME;
+ return field_mode == HTML_MODE_BILLING ? FieldTypeGroup::kNameBilling
+ : FieldTypeGroup::kName;
case HTML_TYPE_ORGANIZATION:
- return COMPANY;
+ return FieldTypeGroup::kCompany;
case HTML_TYPE_STREET_ADDRESS:
case HTML_TYPE_ADDRESS_LINE1:
@@ -171,7 +173,8 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
case HTML_TYPE_COUNTRY_NAME:
case HTML_TYPE_POSTAL_CODE:
case HTML_TYPE_FULL_ADDRESS:
- return field_mode == HTML_MODE_BILLING ? ADDRESS_BILLING : ADDRESS_HOME;
+ return field_mode == HTML_MODE_BILLING ? FieldTypeGroup::kAddressBilling
+ : FieldTypeGroup::kAddressHome;
case HTML_TYPE_CREDIT_CARD_NAME_FULL:
case HTML_TYPE_CREDIT_CARD_NAME_FIRST:
@@ -186,11 +189,11 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
case HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR:
case HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE:
case HTML_TYPE_CREDIT_CARD_TYPE:
- return CREDIT_CARD;
+ return FieldTypeGroup::kCreditCard;
case HTML_TYPE_TRANSACTION_AMOUNT:
case HTML_TYPE_TRANSACTION_CURRENCY:
- return TRANSACTION;
+ return FieldTypeGroup::kTransaction;
case HTML_TYPE_TEL:
case HTML_TYPE_TEL_COUNTRY_CODE:
@@ -200,24 +203,25 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
case HTML_TYPE_TEL_LOCAL_PREFIX:
case HTML_TYPE_TEL_LOCAL_SUFFIX:
case HTML_TYPE_TEL_EXTENSION:
- return field_mode == HTML_MODE_BILLING ? PHONE_BILLING : PHONE_HOME;
+ return field_mode == HTML_MODE_BILLING ? FieldTypeGroup::kPhoneBilling
+ : FieldTypeGroup::kPhoneHome;
case HTML_TYPE_EMAIL:
- return EMAIL;
+ return FieldTypeGroup::kEmail;
case HTML_TYPE_UPI_VPA:
// TODO(crbug/702223): Add support for UPI-VPA.
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
case HTML_TYPE_ONE_TIME_CODE:
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
case HTML_TYPE_UNSPECIFIED:
case HTML_TYPE_UNRECOGNIZED:
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
}
NOTREACHED();
- return NO_GROUP;
+ return FieldTypeGroup::kNoGroup;
}
AutofillType::AutofillType(ServerFieldType field_type)
@@ -236,7 +240,7 @@ AutofillType::AutofillType(HtmlFieldType field_type, HtmlFieldMode mode)
: server_type_(UNKNOWN_TYPE), html_type_(field_type), html_mode_(mode) {}
FieldTypeGroup AutofillType::group() const {
- FieldTypeGroup result = NO_GROUP;
+ FieldTypeGroup result = FieldTypeGroup::kNoGroup;
if (server_type_ != UNKNOWN_TYPE) {
result = GroupTypeOfServerFieldType(server_type_);
} else {
diff --git a/chromium/components/autofill/core/browser/autofill_type_unittest.cc b/chromium/components/autofill/core/browser/autofill_type_unittest.cc
index 3fc28cc091b..9c4a5bb3a9d 100644
--- a/chromium/components/autofill/core/browser/autofill_type_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_type_unittest.cc
@@ -12,79 +12,79 @@ TEST(AutofillTypeTest, ServerFieldTypes) {
// No server data.
AutofillType none(NO_SERVER_DATA);
EXPECT_EQ(NO_SERVER_DATA, none.GetStorableType());
- EXPECT_EQ(NO_GROUP, none.group());
+ EXPECT_EQ(FieldTypeGroup::kNoGroup, none.group());
// Unknown type.
AutofillType unknown(UNKNOWN_TYPE);
EXPECT_EQ(UNKNOWN_TYPE, unknown.GetStorableType());
- EXPECT_EQ(NO_GROUP, unknown.group());
+ EXPECT_EQ(FieldTypeGroup::kNoGroup, unknown.group());
// Type with group but no subgroup.
AutofillType first(NAME_FIRST);
EXPECT_EQ(NAME_FIRST, first.GetStorableType());
- EXPECT_EQ(NAME, first.group());
+ EXPECT_EQ(FieldTypeGroup::kName, first.group());
// Type with group and subgroup.
AutofillType phone(PHONE_HOME_NUMBER);
EXPECT_EQ(PHONE_HOME_NUMBER, phone.GetStorableType());
- EXPECT_EQ(PHONE_HOME, phone.group());
+ EXPECT_EQ(FieldTypeGroup::kPhoneHome, phone.group());
// Billing type.
AutofillType billing_address(ADDRESS_BILLING_LINE1);
EXPECT_EQ(ADDRESS_HOME_LINE1, billing_address.GetStorableType());
- EXPECT_EQ(ADDRESS_BILLING, billing_address.group());
+ EXPECT_EQ(FieldTypeGroup::kAddressBilling, billing_address.group());
// Last value, to check any offset errors.
AutofillType last(NAME_BILLING_SUFFIX);
EXPECT_EQ(NAME_SUFFIX, last.GetStorableType());
- EXPECT_EQ(NAME_BILLING, last.group());
+ EXPECT_EQ(FieldTypeGroup::kNameBilling, last.group());
// Boundary (error) condition.
AutofillType boundary(MAX_VALID_FIELD_TYPE);
EXPECT_EQ(UNKNOWN_TYPE, boundary.GetStorableType());
- EXPECT_EQ(NO_GROUP, boundary.group());
+ EXPECT_EQ(FieldTypeGroup::kNoGroup, boundary.group());
// Beyond the boundary (error) condition.
AutofillType beyond(static_cast<ServerFieldType>(MAX_VALID_FIELD_TYPE + 10));
EXPECT_EQ(UNKNOWN_TYPE, beyond.GetStorableType());
- EXPECT_EQ(NO_GROUP, beyond.group());
+ EXPECT_EQ(FieldTypeGroup::kNoGroup, beyond.group());
// In-between value. Missing from enum but within range. Error condition.
AutofillType between(static_cast<ServerFieldType>(16));
EXPECT_EQ(UNKNOWN_TYPE, between.GetStorableType());
- EXPECT_EQ(NO_GROUP, between.group());
+ EXPECT_EQ(FieldTypeGroup::kNoGroup, between.group());
}
TEST(AutofillTypeTest, HtmlFieldTypes) {
// Unknown type.
AutofillType unknown(HTML_TYPE_UNSPECIFIED, HTML_MODE_NONE);
EXPECT_EQ(UNKNOWN_TYPE, unknown.GetStorableType());
- EXPECT_EQ(NO_GROUP, unknown.group());
+ EXPECT_EQ(FieldTypeGroup::kNoGroup, unknown.group());
// Type with group but no subgroup.
AutofillType first(HTML_TYPE_GIVEN_NAME, HTML_MODE_NONE);
EXPECT_EQ(NAME_FIRST, first.GetStorableType());
- EXPECT_EQ(NAME, first.group());
+ EXPECT_EQ(FieldTypeGroup::kName, first.group());
// Type with group and subgroup.
AutofillType phone(HTML_TYPE_TEL, HTML_MODE_NONE);
EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, phone.GetStorableType());
- EXPECT_EQ(PHONE_HOME, phone.group());
+ EXPECT_EQ(FieldTypeGroup::kPhoneHome, phone.group());
// Last value, to check any offset errors.
AutofillType last(HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, HTML_MODE_NONE);
EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR, last.GetStorableType());
- EXPECT_EQ(CREDIT_CARD, last.group());
+ EXPECT_EQ(FieldTypeGroup::kCreditCard, last.group());
// Shipping mode.
AutofillType shipping_first(HTML_TYPE_GIVEN_NAME, HTML_MODE_SHIPPING);
EXPECT_EQ(NAME_FIRST, shipping_first.GetStorableType());
- EXPECT_EQ(NAME, shipping_first.group());
+ EXPECT_EQ(FieldTypeGroup::kName, shipping_first.group());
// Billing mode.
AutofillType billing_first(HTML_TYPE_GIVEN_NAME, HTML_MODE_BILLING);
EXPECT_EQ(NAME_FIRST, billing_first.GetStorableType());
- EXPECT_EQ(NAME_BILLING, billing_first.group());
+ EXPECT_EQ(FieldTypeGroup::kNameBilling, billing_first.group());
}
} // namespace
diff --git a/chromium/components/autofill/core/browser/data_model/address.cc b/chromium/components/autofill/core/browser/data_model/address.cc
index 284283981ee..9fe03c9a1c1 100644
--- a/chromium/components/autofill/core/browser/data_model/address.cc
+++ b/chromium/components/autofill/core/browser/data_model/address.cc
@@ -8,10 +8,10 @@
#include <algorithm>
#include "base/check_op.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -45,14 +45,30 @@ bool Address::operator==(const Address& other) const {
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled()) {
- return structured_address_ == other.structured_address_;
+ return structured_address_.SameAs(other.structured_address_);
+ }
+
+ bool are_states_equal = (state_ == other.state_);
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap) &&
+ !are_states_equal) {
+ // If the canonical state name exists for |state_| and |other.state_|, they
+ // are compared otherwise.
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ canonical_state_name_cur = GetCanonicalizedStateName();
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ canonical_state_name_other = other.GetCanonicalizedStateName();
+ if (canonical_state_name_cur && canonical_state_name_other) {
+ are_states_equal =
+ (canonical_state_name_cur == canonical_state_name_other);
+ }
}
return street_address_ == other.street_address_ &&
dependent_locality_ == other.dependent_locality_ &&
- city_ == other.city_ && state_ == other.state_ &&
- zip_code_ == other.zip_code_ && sorting_code_ == other.sorting_code_ &&
- country_code_ == other.country_code_ &&
+ city_ == other.city_ && zip_code_ == other.zip_code_ &&
+ sorting_code_ == other.sorting_code_ &&
+ country_code_ == other.country_code_ && are_states_equal &&
street_name_ == other.street_name_ &&
dependent_street_name_ == other.dependent_street_name_ &&
house_number_ == other.house_number_ &&
@@ -86,6 +102,13 @@ bool Address::MergeStructuredAddress(const Address& newer,
newer_was_more_recently_used);
}
+base::Optional<AlternativeStateNameMap::CanonicalStateName>
+Address::GetCanonicalizedStateName() const {
+ return AlternativeStateNameMap::GetCanonicalStateName(
+ base::UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY)),
+ GetRawInfo(ADDRESS_HOME_STATE));
+}
+
bool Address::IsStructuredAddressMergeable(const Address& newer) const {
return structured_address_.IsMergeableWithComponent(
newer.GetStructuredAddress());
@@ -96,7 +119,7 @@ const structured_address::Address& Address::GetStructuredAddress() const {
}
base::string16 Address::GetRawInfo(ServerFieldType type) const {
- DCHECK_EQ(ADDRESS_HOME, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kAddressHome, AutofillType(type).group());
// For structured addresses, the value can be directly retrieved.
if (structured_address::StructuredAddressesEnabled())
@@ -136,6 +159,9 @@ base::string16 Address::GetRawInfo(ServerFieldType type) const {
case ADDRESS_HOME_APT_NUM:
return base::string16();
+ case ADDRESS_HOME_FLOOR:
+ return base::string16();
+
// The following tokens are used for creating new type votes but should not
// be filled into fields.
case ADDRESS_HOME_STREET_NAME:
@@ -153,6 +179,10 @@ base::string16 Address::GetRawInfo(ServerFieldType type) const {
case ADDRESS_HOME_SUBPREMISE:
return subpremise_;
+ case ADDRESS_HOME_ADDRESS:
+ case ADDRESS_HOME_ADDRESS_WITH_NAME:
+ return base::string16();
+
default:
NOTREACHED() << "Unrecognized type: " << type;
return base::string16();
@@ -162,7 +192,7 @@ base::string16 Address::GetRawInfo(ServerFieldType type) const {
void Address::SetRawInfoWithVerificationStatus(ServerFieldType type,
const base::string16& value,
VerificationStatus status) {
- DCHECK_EQ(ADDRESS_HOME, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kAddressHome, AutofillType(type).group());
// For structured addresses, the value can directly be set.
// TODO(crbug.com/1130194): Clean legacy implementation once structured
@@ -278,6 +308,17 @@ void Address::SetRawInfoWithVerificationStatus(ServerFieldType type,
subpremise_ = value;
break;
+ // Not implemented for unstructured addresses.
+ case ADDRESS_HOME_APT_NUM:
+ break;
+
+ // Not implemented for unstructured addresses.
+ case ADDRESS_HOME_FLOOR:
+ break;
+
+ case ADDRESS_HOME_ADDRESS:
+ break;
+
default:
NOTREACHED();
}
@@ -313,6 +354,7 @@ void Address::GetMatchingTypes(const base::string16& text,
if (!entered_country_code.empty() && country_code == entered_country_code)
matching_types->insert(ADDRESS_HOME_COUNTRY);
+ l10n::CaseInsensitiveCompare compare;
AutofillProfileComparator comparator(app_locale);
// Check to see if the |text| could be the full name or abbreviation of a
// state.
@@ -321,8 +363,8 @@ void Address::GetMatchingTypes(const base::string16& text,
base::string16 state_abbreviation;
state_names::GetNameAndAbbreviation(canon_text, &state_name,
&state_abbreviation);
+
if (!state_name.empty() || !state_abbreviation.empty()) {
- l10n::CaseInsensitiveCompare compare;
base::string16 canon_profile_state = comparator.NormalizeForComparison(
GetInfo(AutofillType(ADDRESS_HOME_STATE), app_locale));
if ((!state_name.empty() &&
@@ -434,7 +476,7 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
} else {
country_code_ = country_code;
}
- return !country_code_.empty();
+ return !GetRawInfo(ADDRESS_HOME_COUNTRY).empty();
}
SetRawInfoWithVerificationStatus(storable_type, value, status);
diff --git a/chromium/components/autofill/core/browser/data_model/address.h b/chromium/components/autofill/core/browser/data_model/address.h
index 348ef2af02a..beb2f9d1600 100644
--- a/chromium/components/autofill/core/browser/data_model/address.h
+++ b/chromium/components/autofill/core/browser/data_model/address.h
@@ -12,6 +12,7 @@
#include "base/strings/string16.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address.h"
#include "components/autofill/core/browser/data_model/form_group.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
namespace autofill {
@@ -53,6 +54,11 @@ class Address : public FormGroup {
bool MergeStructuredAddress(const Address& newer,
bool newer_was_more_recently_used);
+ // Fetches the canonical state name for the current address object if
+ // possible.
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ GetCanonicalizedStateName() const;
+
// For structured addresses, returns true if |this| is mergeable with |newer|.
bool IsStructuredAddressMergeable(const Address& newer) const;
diff --git a/chromium/components/autofill/core/browser/data_model/address_unittest.cc b/chromium/components/autofill/core/browser/data_model/address_unittest.cc
index ee3aed0d76c..248ccdbe097 100644
--- a/chromium/components/autofill/core/browser/data_model/address_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/address_unittest.cc
@@ -12,8 +12,10 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/address.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
@@ -390,6 +392,55 @@ TEST_P(AddressTest, IsCountry) {
EXPECT_EQ(0U, matching_types.size());
}
+// Test the equality of two |Address()| objects w.r.t. the state.
+TEST_P(AddressTest, TestAreStatesEqual) {
+ base::test::ScopedFeatureList feature;
+ // The feature
+ // |features::kAutofillEnableSupportForMoreStructureInAddresses| is disabled
+ // since it is incompatible with the feature
+ // |features::kAutofillUseStateMappingCache|.
+ feature.InitWithFeatures(
+ {features::kAutofillUseAlternativeStateNameMap},
+ {features::kAutofillEnableSupportForMoreStructureInAddresses});
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+
+ struct {
+ const char* const country_code;
+ const char* const first;
+ const char* const second;
+ const bool result;
+ } test_cases[] = {
+ {"DE", "Bavaria", "BY", true}, {"DE", "", "", true},
+ {"DE", "", "BY", false}, {"DE", "Bavaria", "Bayern", true},
+ {"DE", "BY", "Bayern", true}, {"DE", "b.y.", "Bayern", true}};
+
+ for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(testing::Message() << "first: " << test_case.first
+ << " | second: " << test_case.second);
+
+ Address address1;
+ Address address2;
+
+ // Set the address tokens.
+ address1.SetRawInfo(ADDRESS_HOME_COUNTRY,
+ base::ASCIIToUTF16(test_case.country_code));
+ address2.SetRawInfo(ADDRESS_HOME_COUNTRY,
+ base::ASCIIToUTF16(test_case.country_code));
+
+ address1.SetRawInfo(ADDRESS_HOME_STATE,
+ base::ASCIIToUTF16(test_case.first));
+ address2.SetRawInfo(ADDRESS_HOME_STATE,
+ base::ASCIIToUTF16(test_case.second));
+
+ if (test_case.result) {
+ EXPECT_TRUE(address1 == address2);
+ } else {
+ EXPECT_FALSE(address1 == address2);
+ }
+ }
+}
+
// Verifies that Address::GetInfo() correctly combines address lines.
TEST_P(AddressTest, GetStreetAddress) {
const AutofillType type = AutofillType(ADDRESS_HOME_STREET_ADDRESS);
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
index 7da13d15f85..b0ea8bd395f 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
@@ -87,9 +87,4 @@ AutofillDataModel::ValidityState AutofillDataModel::GetValidityState(
return AutofillDataModel::UNSUPPORTED;
}
-bool AutofillDataModel::ShouldSkipFillingOrSuggesting(
- ServerFieldType type) const {
- return false;
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.h b/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
index e8738773f25..e67afcda8dc 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
@@ -94,10 +94,6 @@ class AutofillDataModel : public FormGroup {
virtual ValidityState GetValidityState(ServerFieldType type,
ValidationSource source) const;
- // Check for the validity of the data. Leave the field empty if the data is
- // invalid and the relevant feature is enabled.
- virtual bool ShouldSkipFillingOrSuggesting(ServerFieldType type) const;
-
protected:
// Called to update |use_count_| and |use_date_| when this data model is
// the subject of user interaction (usually, when it's used to fill a form).
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
index e9668df416b..10eee8a3ffe 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -17,6 +17,7 @@
#include "base/i18n/char_iterator.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -67,10 +68,10 @@ namespace {
// similarly.
ServerFieldType GetStorableTypeCollapsingGroups(ServerFieldType type) {
ServerFieldType storable_type = AutofillType(type).GetStorableType();
- if (AutofillType(storable_type).group() == NAME)
+ if (AutofillType(storable_type).group() == FieldTypeGroup::kName)
return NAME_FULL;
- if (AutofillType(storable_type).group() == PHONE_HOME)
+ if (AutofillType(storable_type).group() == FieldTypeGroup::kPhoneHome)
return PHONE_HOME_WHOLE_NUMBER;
return storable_type;
@@ -167,7 +168,7 @@ void GetFieldsForDistinguishingProfiles(
// Keep track of which fields we've seen so that we avoid duplicate entries.
// Always ignore fields of unknown type and the excluded field.
- std::set<ServerFieldType> seen_fields;
+ ServerFieldTypeSet seen_fields;
seen_fields.insert(UNKNOWN_TYPE);
seen_fields.insert(GetStorableTypeCollapsingGroups(excluded_field));
@@ -222,7 +223,8 @@ static_assert(kNumSupportedTypesForValidation * kValidityBitsPerType <= 64,
// main stored type for used to mark field validity .
ServerFieldType NormalizeTypeForValidityCheck(ServerFieldType type) {
auto field_type_group = AutofillType(type).group();
- if (field_type_group == PHONE_HOME || field_type_group == PHONE_BILLING)
+ if (field_type_group == FieldTypeGroup::kPhoneHome ||
+ field_type_group == FieldTypeGroup::kPhoneBilling)
return PHONE_HOME_WHOLE_NUMBER;
return type;
}
@@ -259,9 +261,6 @@ AutofillProfile::AutofillProfile(const AutofillProfile& profile)
company_(this),
phone_number_(this) {
operator=(profile);
- // In case the profile is converted from a legacy profile or a wallet profile
- // with structured names, try to finalize it.
- FinalizeAfterImport();
}
AutofillProfile::~AutofillProfile() = default;
@@ -328,8 +327,7 @@ void AutofillProfile::GetMatchingTypes(
const std::string& app_locale,
ServerFieldTypeSet* matching_types) const {
ServerFieldTypeSet matching_types_in_this_profile;
- FormGroupList info = FormGroups();
- for (const auto* form_group : info) {
+ for (const auto* form_group : FormGroups()) {
form_group->GetMatchingTypes(text, app_locale,
&matching_types_in_this_profile);
}
@@ -348,8 +346,7 @@ void AutofillProfile::GetMatchingTypesAndValidities(
return;
ServerFieldTypeSet matching_types_in_this_profile;
- FormGroupList info = FormGroups();
- for (const auto* form_group : info) {
+ for (const auto* form_group : FormGroups()) {
form_group->GetMatchingTypes(text, app_locale,
&matching_types_in_this_profile);
}
@@ -387,8 +384,7 @@ void AutofillProfile::SetRawInfoWithVerificationStatus(
void AutofillProfile::GetSupportedTypes(
ServerFieldTypeSet* supported_types) const {
- FormGroupList info = FormGroups();
- for (const auto* form_group : info) {
+ for (const auto* form_group : FormGroups()) {
form_group->GetSupportedTypes(supported_types);
}
}
@@ -579,7 +575,7 @@ bool AutofillProfile::IsSubsetOfForFieldSet(
// conditions that follow.
return false;
}
- } else if (AutofillType(type).group() == PHONE_HOME) {
+ } else if (AutofillType(type).group() == FieldTypeGroup::kPhoneHome) {
// Phone numbers should be canonicalized before comparing.
if (type != PHONE_HOME_WHOLE_NUMBER &&
type != PHONE_HOME_CITY_AND_NUMBER) {
@@ -1015,14 +1011,15 @@ bool AutofillProfile::IsAnInvalidPhoneNumber(ServerFieldType type) const {
return true;
ServerFieldTypeSet types;
- if (GroupTypeOfServerFieldType(type) == PHONE_HOME) {
+ if (GroupTypeOfServerFieldType(type) == FieldTypeGroup::kPhoneHome) {
types = {PHONE_HOME_NUMBER, PHONE_HOME_CITY_CODE,
PHONE_HOME_CITY_AND_NUMBER};
if (type == PHONE_HOME_WHOLE_NUMBER) {
types.insert(PHONE_HOME_WHOLE_NUMBER);
types.insert(PHONE_HOME_COUNTRY_CODE);
}
- } else if (GroupTypeOfServerFieldType(type) == PHONE_BILLING) {
+ } else if (GroupTypeOfServerFieldType(type) ==
+ FieldTypeGroup::kPhoneBilling) {
types = {PHONE_BILLING_NUMBER, PHONE_BILLING_CITY_CODE,
PHONE_BILLING_CITY_AND_NUMBER};
if (type == PHONE_BILLING_WHOLE_NUMBER) {
@@ -1144,7 +1141,7 @@ bool AutofillProfile::ShouldSkipFillingOrSuggesting(
autofill::features::kAutofillProfileClientValidation) &&
GetValidityState(type, AutofillProfile::CLIENT) ==
AutofillProfile::INVALID &&
- (GroupTypeOfServerFieldType(type) != ADDRESS_HOME ||
+ (GroupTypeOfServerFieldType(type) != FieldTypeGroup::kAddressHome ||
!GetRawInfo(ADDRESS_HOME_COUNTRY).empty())) {
return true;
}
@@ -1277,16 +1274,6 @@ void AutofillProfile::CreateInferredLabelsHelper(
}
}
-AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
- FormGroupList v(5);
- v[0] = &name_;
- v[1] = &email_;
- v[2] = &company_;
- v[3] = &phone_number_;
- v[4] = &address_;
- return v;
-}
-
const FormGroup* AutofillProfile::FormGroupForType(
const AutofillType& type) const {
return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
@@ -1294,30 +1281,30 @@ const FormGroup* AutofillProfile::FormGroupForType(
FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
switch (type.group()) {
- case NAME:
- case NAME_BILLING:
+ case FieldTypeGroup::kName:
+ case FieldTypeGroup::kNameBilling:
return &name_;
- case EMAIL:
+ case FieldTypeGroup::kEmail:
return &email_;
- case COMPANY:
+ case FieldTypeGroup::kCompany:
return &company_;
- case PHONE_HOME:
- case PHONE_BILLING:
+ case FieldTypeGroup::kPhoneHome:
+ case FieldTypeGroup::kPhoneBilling:
return &phone_number_;
- case ADDRESS_HOME:
- case ADDRESS_BILLING:
+ case FieldTypeGroup::kAddressHome:
+ case FieldTypeGroup::kAddressBilling:
return &address_;
- case NO_GROUP:
- case CREDIT_CARD:
- case PASSWORD_FIELD:
- case USERNAME_FIELD:
- case TRANSACTION:
- case UNFILLABLE:
+ case FieldTypeGroup::kNoGroup:
+ case FieldTypeGroup::kCreditCard:
+ case FieldTypeGroup::kPasswordField:
+ case FieldTypeGroup::kUsernameField:
+ case FieldTypeGroup::kTransaction:
+ case FieldTypeGroup::kUnfillable:
return nullptr;
}
@@ -1331,68 +1318,57 @@ bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const {
}
std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
- return os
- << (profile.record_type() == AutofillProfile::LOCAL_PROFILE
- ? profile.guid()
- : base::HexEncode(profile.server_id().data(),
- profile.server_id().size()))
- << " " << profile.origin() << " "
- << UTF16ToUTF8(profile.GetRawInfo(NAME_FULL)) << " "
- << "("
- << base::NumberToString(profile.GetVerificationStatusInt(NAME_FULL))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_FIRST)) << " "
- << "("
- << base::NumberToString(profile.GetVerificationStatusInt(NAME_FIRST))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_MIDDLE)) << " "
- << "("
- << base::NumberToString(profile.GetVerificationStatusInt(NAME_MIDDLE))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST)) << " "
- << "("
- << base::NumberToString(profile.GetVerificationStatusInt(NAME_LAST))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST_FIRST)) << " "
- << "("
- << base::NumberToString(
- profile.GetVerificationStatusInt(NAME_LAST_FIRST))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST_CONJUNCTION))
- << " "
- << "("
- << base::NumberToString(
- profile.GetVerificationStatusInt(NAME_LAST_CONJUNCTION))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST_SECOND)) << " "
- << "("
- << base::NumberToString(
- profile.GetVerificationStatusInt(NAME_LAST_SECOND))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(EMAIL_ADDRESS)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE3)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)) << " "
- << "("
- << base::NumberToString(
- profile.GetVerificationStatusInt(ADDRESS_HOME_STREET_ADDRESS))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_NAME))
- << " "
- << "("
- << base::NumberToString(
- profile.GetVerificationStatusInt(ADDRESS_HOME_STREET_NAME))
- << ") " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER))
- << " "
- << "("
- << base::NumberToString(
- profile.GetVerificationStatusInt(ADDRESS_HOME_HOUSE_NUMBER))
- << ") "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
- << " " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) << " "
- << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) << " "
- << profile.language_code() << " "
- << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)) << " "
- << profile.GetClientValidityBitfieldValue() << " "
- << profile.has_converted() << " " << profile.use_count() << " "
- << profile.use_date();
+ os << (profile.record_type() == AutofillProfile::LOCAL_PROFILE
+ ? profile.guid()
+ : base::HexEncode(profile.server_id().data(),
+ profile.server_id().size()))
+ << " " << profile.origin() << " "
+ << profile.GetClientValidityBitfieldValue() << " "
+ << profile.has_converted() << " " << profile.use_count() << " "
+ << profile.use_date() << " " << profile.language_code() << std::endl;
+
+ // Lambda to print the value and verification status for |type|.
+ auto print_values_lambda = [&os, &profile](ServerFieldType type) {
+ os << AutofillType::ServerFieldTypeToString(type) << ": "
+ << profile.GetRawInfo(type) << "(" << profile.GetVerificationStatus(type)
+ << ")" << std::endl;
+ };
+
+ // Use a helper function to print the values of the stored types.
+ const ServerFieldType field_types_to_print[] = {
+ NAME_FULL,
+ NAME_HONORIFIC_PREFIX,
+ NAME_FIRST,
+ NAME_MIDDLE,
+ NAME_LAST,
+ NAME_LAST_FIRST,
+ NAME_LAST_CONJUNCTION,
+ NAME_LAST_SECOND,
+ EMAIL_ADDRESS,
+ COMPANY_NAME,
+ ADDRESS_HOME_ADDRESS,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_LINE2,
+ ADDRESS_HOME_LINE3,
+ ADDRESS_HOME_STREET_ADDRESS,
+ ADDRESS_HOME_STREET_NAME,
+ ADDRESS_HOME_DEPENDENT_STREET_NAME,
+ ADDRESS_HOME_HOUSE_NUMBER,
+ ADDRESS_HOME_APT_NUM,
+ ADDRESS_HOME_FLOOR,
+ ADDRESS_HOME_DEPENDENT_LOCALITY,
+ ADDRESS_HOME_PREMISE_NAME,
+ ADDRESS_HOME_SUBPREMISE,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_SORTING_CODE,
+ ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_WHOLE_NUMBER};
+
+ base::ranges::for_each(field_types_to_print, print_values_lambda);
+
+ return os;
}
bool AutofillProfile::FinalizeAfterImport() {
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.h b/chromium/components/autofill/core/browser/data_model/autofill_profile.h
index 9bdb9ea800a..d11ce432c8c 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <array>
#include <iosfwd>
#include <list>
#include <map>
@@ -279,7 +280,7 @@ class AutofillProfile : public AutofillDataModel {
// Check for the validity of the data. Leave the field empty if the data is
// invalid and the relevant feature is enabled.
- bool ShouldSkipFillingOrSuggesting(ServerFieldType type) const override;
+ bool ShouldSkipFillingOrSuggesting(ServerFieldType type) const;
base::WeakPtr<const AutofillProfile> GetWeakPtr() const {
return weak_ptr_factory_.GetWeakPtr();
@@ -300,8 +301,6 @@ class AutofillProfile : public AutofillDataModel {
const Address& GetAddress() const { return address_; }
private:
- typedef std::vector<const FormGroup*> FormGroupList;
-
// FormGroup:
base::string16 GetInfoImpl(const AutofillType& type,
const std::string& app_locale) const override;
@@ -330,7 +329,11 @@ class AutofillProfile : public AutofillDataModel {
// Utilities for listing and lookup of the data members that constitute
// user-visible profile information.
- FormGroupList FormGroups() const;
+ std::array<const FormGroup*, 5> FormGroups() const {
+ // Adjust the return type size as necessary.
+ return {&name_, &email_, &company_, &phone_number_, &address_};
+ }
+
const FormGroup* FormGroupForType(const AutofillType& type) const;
FormGroup* MutableFormGroupForType(const AutofillType& type);
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
index e24375a36eb..978ba958b27 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
@@ -10,6 +10,7 @@
#include "base/i18n/case_conversion.h"
#include "base/i18n/char_iterator.h"
#include "base/i18n/unicodestring.h"
+#include "base/optional.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversion_utils.h"
@@ -701,13 +702,48 @@ bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1,
const AutofillType kState(ADDRESS_HOME_STATE);
const base::string16& state1 = p1.GetInfo(kState, app_locale_);
const base::string16& state2 = p2.GetInfo(kState, app_locale_);
- if (state1.empty()) {
- address->SetInfo(kState, state2, app_locale_);
- } else if (state2.empty()) {
- address->SetInfo(kState, state1, app_locale_);
+
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ // Holds information about the state string that is going to be used as the
+ // state value in the merged profile.
+ base::string16 candidate_state = state1;
+
+ // Cases where the |state2| is used as the state value in the merged
+ // profile:
+ // 1. |state1| is empty.
+ // 2. |state2| has the canonical state name present in
+ // AlternativeStateNameMap and |state1| does not.
+ // 3. |state2.size()| < |state1.size()| and either both or none of them
+ // have canonical state name present in the AlternativeStateNameMap.
+ if (state1.empty()) {
+ candidate_state = state2;
+ } else if (!state2.empty()) {
+ bool state1_has_canonical_name_present =
+ p1.GetAddress().GetCanonicalizedStateName().has_value();
+ bool state2_has_canonical_name_present =
+ p2.GetAddress().GetCanonicalizedStateName().has_value();
+
+ if ((state2_has_canonical_name_present &&
+ !state1_has_canonical_name_present) ||
+ (state2_has_canonical_name_present ==
+ state1_has_canonical_name_present &&
+ state2.size() < state1.size())) {
+ candidate_state = state2;
+ }
+ }
+
+ address->SetInfo(kState, candidate_state, app_locale_);
} else {
- address->SetInfo(kState, (state2.size() < state1.size() ? state2 : state1),
- app_locale_);
+ if (state1.empty()) {
+ address->SetInfo(kState, state2, app_locale_);
+ } else if (state2.empty()) {
+ address->SetInfo(kState, state1, app_locale_);
+ } else {
+ address->SetInfo(kState,
+ (state2.size() < state1.size() ? state2 : state1),
+ app_locale_);
+ }
}
AddressRewriter rewriter = AddressRewriter::ForCountryCode(country_code);
@@ -1149,7 +1185,14 @@ bool AutofillProfileComparator::HaveMergeableAddresses(
// State
// ------
- // Heuristic: States are mergeable if one is a (possibly empty) bag of words
+ // When |kAutofillUseAlternativeStateNameMap| is disabled: States are
+ // mergeable if one is a (possibly empty) bag of words subset of the other.
+ //
+ // When |kAutofillUseAlternativeStateNameMap| is enabled: The profiles
+ // w.r.t the state are mergeable if their canonical state names in
+ // AlternativeStateNameMap matches.
+ // In case one of the profile does not have a canonical state name present in
+ // the AlternativeStateNameMap, states are mergeable if one is a bag of words
// subset of the other.
//
// TODO(rogerm): If the match is between non-empty zip codes then we can infer
@@ -1157,12 +1200,30 @@ bool AutofillProfileComparator::HaveMergeableAddresses(
// handles the cases where we have invalid or poorly formed data in one of the
// state values (like "Select one", or "CA - California").
const AutofillType kState(ADDRESS_HOME_STATE);
- const base::string16& state1 =
- rewriter.Rewrite(NormalizeForComparison(p1.GetInfo(kState, app_locale_)));
- const base::string16& state2 =
- rewriter.Rewrite(NormalizeForComparison(p2.GetInfo(kState, app_locale_)));
- if (CompareTokens(state1, state2) == DIFFERENT_TOKENS) {
- return false;
+ bool canonical_state_names_match = false;
+ bool use_alternative_state_name_map_enabled = base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap);
+ if (use_alternative_state_name_map_enabled) {
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ canonical_name_state1 = p1.GetAddress().GetCanonicalizedStateName();
+ base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ canonical_name_state2 = p2.GetAddress().GetCanonicalizedStateName();
+ if (canonical_name_state1 && canonical_name_state2) {
+ if (canonical_name_state1.value() == canonical_name_state2.value())
+ canonical_state_names_match = true;
+ else
+ return false;
+ }
+ }
+
+ if (!use_alternative_state_name_map_enabled || !canonical_state_names_match) {
+ base::string16 state1 = rewriter.Rewrite(
+ NormalizeForComparison(p1.GetInfo(kState, app_locale_)));
+ base::string16 state2 = rewriter.Rewrite(
+ NormalizeForComparison(p2.GetInfo(kState, app_locale_)));
+ if (CompareTokens(state1, state2) == DIFFERENT_TOKENS) {
+ return false;
+ }
}
// City
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
index a3cdf6c2e63..6935d2073eb 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
@@ -15,6 +15,7 @@
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/data_model/contact_info.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -1428,6 +1429,75 @@ TEST_P(AutofillProfileComparatorTest,
MergeAddressesAndExpect(p2, p1, expected);
}
+// Checks for various scenarios for determining mergeability of profiles w.r.t.
+// the state.
+TEST_P(AutofillProfileComparatorTest, CheckStatesMergeability) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(
+ autofill::features::kAutofillUseAlternativeStateNameMap);
+
+ autofill::test::ClearAlternativeStateNameMapForTesting();
+ autofill::test::PopulateAlternativeStateNameMapForTesting();
+
+ AutofillProfile empty = CreateProfileWithAddress("", "", "", "", "", "DE");
+ AutofillProfile p1 = CreateProfileWithAddress("", "", "", "Bayern", "", "DE");
+ AutofillProfile p2 = CreateProfileWithAddress("", "", "", "Random", "", "DE");
+ AutofillProfile p3 =
+ CreateProfileWithAddress("", "", "", "Bayern - BY - Bavaria", "", "DE");
+ AutofillProfile p4 =
+ CreateProfileWithAddress("", "", "", "Bavaria", "", "DE");
+
+ EXPECT_TRUE(comparator_.HaveMergeableAddresses(empty, empty));
+ EXPECT_TRUE(comparator_.HaveMergeableAddresses(p1, empty));
+ EXPECT_TRUE(comparator_.HaveMergeableAddresses(p1, p1));
+ EXPECT_FALSE(comparator_.HaveMergeableAddresses(p1, p2));
+ EXPECT_TRUE(comparator_.HaveMergeableAddresses(p3, p1));
+ EXPECT_TRUE(comparator_.HaveMergeableAddresses(p1, p4));
+ EXPECT_FALSE(comparator_.HaveMergeableAddresses(p2, p4));
+}
+
+// Tests that the profiles are merged when they have common states.
+TEST_P(AutofillProfileComparatorTest, MergeProfilesBasedOnState) {
+ base::test::ScopedFeatureList feature;
+ // The feature
+ // |autofill::features::kAutofillEnableSupportForMoreStructureInAddresses| is
+ // disabled since it is incompatible with the feature
+ // |autofill::features::kAutofillUseStateMappingCache|.
+ feature.InitWithFeatures(
+ {autofill::features::kAutofillUseAlternativeStateNameMap},
+ {autofill::features::kAutofillEnableSupportForMoreStructureInAddresses});
+
+ autofill::test::ClearAlternativeStateNameMapForTesting();
+ autofill::test::PopulateAlternativeStateNameMapForTesting();
+ autofill::test::PopulateAlternativeStateNameMapForTesting(
+ "IN", "UP",
+ {{.canonical_name = "Uttar Pradesh",
+ .abbreviations = {"UP"},
+ .alternative_names = {}}});
+
+ AutofillProfile empty = CreateProfileWithAddress("", "", "", "", "", "DE");
+ AutofillProfile p1 = CreateProfileWithAddress("", "", "", "Bayern", "", "DE");
+ AutofillProfile p2 =
+ CreateProfileWithAddress("", "", "", "Bayern - BY - Bavaria", "", "DE");
+
+ Address expected;
+ expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("DE"));
+ expected.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16("Bayern"));
+ MergeAddressesAndExpect(empty, p1, expected);
+ MergeAddressesAndExpect(p1, empty, expected);
+ MergeAddressesAndExpect(p1, p2, expected);
+ MergeAddressesAndExpect(p2, p1, expected);
+
+ AutofillProfile p3 =
+ CreateProfileWithAddress("", "", "", "Pradesh", "", "IN");
+ AutofillProfile p4 =
+ CreateProfileWithAddress("", "", "", "Uttar Pradesh", "", "IN");
+ expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("IN"));
+ expected.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16("Uttar Pradesh"));
+ MergeAddressesAndExpect(p3, p4, expected);
+ MergeAddressesAndExpect(p4, p3, expected);
+}
+
INSTANTIATE_TEST_SUITE_P(
All,
AutofillProfileComparatorTest,
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
index 5029ad6d3ad..2e47d29e0b9 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
@@ -1123,18 +1123,25 @@ TEST_P(AutofillProfileTest, MergeDataFrom_DifferentProfile) {
AutofillProfile b = a;
b.set_guid(base::GenerateGUID());
b.set_origin(kSettingsOrigin);
- b.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Unit 5, area 51"));
- b.SetRawInfo(COMPANY_NAME, base::string16());
+ b.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_LINE2, ASCIIToUTF16("Unit 5, area 51"),
+ structured_address::VerificationStatus::kObserved);
+ b.SetRawInfoWithVerificationStatus(
+ COMPANY_NAME, base::string16(),
+ structured_address::VerificationStatus::kObserved);
b.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("M."));
b.SetRawInfo(NAME_FULL, ASCIIToUTF16("Marion M. Morrison"));
b.set_language_code("en");
+ b.FinalizeAfterImport();
+ a.FinalizeAfterImport();
EXPECT_TRUE(a.MergeDataFrom(b, "en-US"));
// Merge has modified profile a, the validation is not updated.
EXPECT_FALSE(a.is_client_validity_states_updated());
EXPECT_EQ(kSettingsOrigin, a.origin());
- EXPECT_EQ(ASCIIToUTF16("Unit 5, area 51"), a.GetRawInfo(ADDRESS_HOME_LINE2));
+ EXPECT_EQ("Unit 5, area 51",
+ base::UTF16ToUTF8(a.GetRawInfo(ADDRESS_HOME_LINE2)));
EXPECT_EQ(ASCIIToUTF16("Fox"), a.GetRawInfo(COMPANY_NAME));
base::string16 name = a.GetInfo(NAME_FULL, "en-US");
EXPECT_EQ(ASCIIToUTF16("Marion Mitchell Morrison"), name);
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
index b5fa1ea03e3..80aabc5ac36 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
@@ -38,7 +38,6 @@ base::string16 AddressComponentWithRewriter::ValueForComparison() const {
StreetName::StreetName(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_STREET_NAME,
parent,
- {},
MergeMode::kDefault) {}
StreetName::~StreetName() = default;
@@ -46,7 +45,6 @@ StreetName::~StreetName() = default;
DependentStreetName::DependentStreetName(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_DEPENDENT_STREET_NAME,
parent,
- {},
MergeMode::kDefault) {}
DependentStreetName::~DependentStreetName() = default;
@@ -55,7 +53,6 @@ StreetAndDependentStreetName::StreetAndDependentStreetName(
AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
parent,
- {&thoroughfare_name_, &dependent_thoroughfare_name_},
MergeMode::kDefault) {}
StreetAndDependentStreetName::~StreetAndDependentStreetName() = default;
@@ -63,7 +60,6 @@ StreetAndDependentStreetName::~StreetAndDependentStreetName() = default;
HouseNumber::HouseNumber(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_HOUSE_NUMBER,
parent,
- {},
MergeMode::kDefault) {}
HouseNumber::~HouseNumber() = default;
@@ -71,25 +67,23 @@ HouseNumber::~HouseNumber() = default;
Premise::Premise(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_PREMISE_NAME,
parent,
- {},
MergeMode::kDefault) {}
Premise::~Premise() = default;
Floor::Floor(AddressComponent* parent)
- : AddressComponent(ADDRESS_HOME_FLOOR, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(ADDRESS_HOME_FLOOR, parent, MergeMode::kDefault) {}
Floor::~Floor() = default;
Apartment::Apartment(AddressComponent* parent)
- : AddressComponent(ADDRESS_HOME_APT_NUM, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(ADDRESS_HOME_APT_NUM, parent, MergeMode::kDefault) {}
Apartment::~Apartment() = default;
SubPremise::SubPremise(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_SUBPREMISE,
parent,
- {&floor_, &apartment_},
MergeMode::kDefault) {}
SubPremise::~SubPremise() = default;
@@ -101,7 +95,6 @@ StreetAddress::StreetAddress(AddressComponent* parent)
: AddressComponentWithRewriter(
ADDRESS_HOME_STREET_ADDRESS,
parent,
- {&streets_, &number_, &premise_, &sub_premise_},
MergeMode::kReplaceEmpty | MergeMode::kReplaceSubset |
MergeMode::kDefault) {}
@@ -114,7 +107,9 @@ StreetAddress::GetParseRegularExpressionsByRelevance() const {
return {pattern_provider->GetRegEx(RegEx::kParseHouseNumberStreetName),
pattern_provider->GetRegEx(RegEx::kParseStreetNameHouseNumber),
pattern_provider->GetRegEx(
- RegEx::kParseStreetNameHouseNumberSuffixedFloor)};
+ RegEx::kParseStreetNameHouseNumberSuffixedFloor),
+ pattern_provider->GetRegEx(
+ RegEx::kParseStreetNameHouseNumberSuffixedFloorAndAppartmentRe)};
}
void StreetAddress::ParseValueAndAssignSubcomponentsByFallbackMethod() {
@@ -167,6 +162,16 @@ base::string16 StreetAddress::GetBestFormatString() const {
"${ADDRESS_HOME_FLOOR;, ;. Stock}${ADDRESS_HOME_APT_NUM;, ;. Wohnung}");
}
+ if (country_code == "MX") {
+ return base::ASCIIToUTF16(
+ "${ADDRESS_HOME_STREET_NAME} ${ADDRESS_HOME_HOUSE_NUMBER}"
+ "${ADDRESS_HOME_FLOOR; - Piso ;}${ADDRESS_HOME_APT_NUM; - ;}");
+ }
+ if (country_code == "ES") {
+ return base::UTF8ToUTF16(
+ "${ADDRESS_HOME_STREET_NAME} ${ADDRESS_HOME_HOUSE_NUMBER}"
+ "${ADDRESS_HOME_FLOOR;, ;º}${ADDRESS_HOME_APT_NUM;, ;ª}");
+ }
// Use the format for US/UK as the default.
return base::ASCIIToUTF16(
"${ADDRESS_HOME_HOUSE_NUMBER} ${ADDRESS_HOME_STREET_NAME} "
@@ -209,21 +214,21 @@ bool StreetAddress::IsValueValid() const {
bool StreetAddress::ConvertAndGetTheValueForAdditionalFieldTypeName(
const std::string& type_name,
base::string16* value) const {
- if (type_name == AutofillType(ADDRESS_HOME_LINE1).ToString()) {
+ if (type_name == AutofillType::ServerFieldTypeToString(ADDRESS_HOME_LINE1)) {
if (value) {
*value =
address_lines_.size() > 0 ? address_lines_.at(0) : base::string16();
}
return true;
}
- if (type_name == AutofillType(ADDRESS_HOME_LINE2).ToString()) {
+ if (type_name == AutofillType::ServerFieldTypeToString(ADDRESS_HOME_LINE2)) {
if (value) {
*value =
address_lines_.size() > 1 ? address_lines_.at(1) : base::string16();
}
return true;
}
- if (type_name == AutofillType(ADDRESS_HOME_LINE3).ToString()) {
+ if (type_name == AutofillType::ServerFieldTypeToString(ADDRESS_HOME_LINE3)) {
if (value) {
*value =
address_lines_.size() > 2 ? address_lines_.at(2) : base::string16();
@@ -240,11 +245,13 @@ bool StreetAddress::ConvertAndSetValueForAdditionalFieldTypeName(
const base::string16& value,
const VerificationStatus& status) {
size_t index = 0;
- if (type_name == AutofillType(ADDRESS_HOME_LINE1).ToString()) {
+ if (type_name == AutofillType::ServerFieldTypeToString(ADDRESS_HOME_LINE1)) {
index = 0;
- } else if (type_name == AutofillType(ADDRESS_HOME_LINE2).ToString()) {
+ } else if (type_name ==
+ AutofillType::ServerFieldTypeToString(ADDRESS_HOME_LINE2)) {
index = 1;
- } else if (type_name == AutofillType(ADDRESS_HOME_LINE3).ToString()) {
+ } else if (type_name ==
+ AutofillType::ServerFieldTypeToString(ADDRESS_HOME_LINE3)) {
index = 2;
} else {
return false;
@@ -287,7 +294,6 @@ void StreetAddress::GetAdditionalSupportedFieldTypes(
CountryCode::CountryCode(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_COUNTRY,
parent,
- {},
MergeMode::kReplaceEmpty |
MergeMode::kUseBetterOrNewerForSameValue) {}
@@ -298,7 +304,6 @@ CountryCode::~CountryCode() = default;
DependentLocality::DependentLocality(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_DEPENDENT_LOCALITY,
parent,
- {},
MergeMode::kReplaceSubset | MergeMode::kReplaceEmpty) {}
DependentLocality::~DependentLocality() = default;
@@ -308,7 +313,6 @@ DependentLocality::~DependentLocality() = default;
City::City(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_CITY,
parent,
- {},
MergeMode::kReplaceSubset | MergeMode::kReplaceEmpty) {}
City::~City() = default;
@@ -319,7 +323,6 @@ State::State(AddressComponent* parent)
: AddressComponentWithRewriter(
ADDRESS_HOME_STATE,
parent,
- {},
MergeMode::kPickShorterIfOneContainsTheOther | kReplaceEmpty) {}
State::~State() = default;
@@ -330,7 +333,6 @@ PostalCode::PostalCode(AddressComponent* parent)
: AddressComponentWithRewriter(
ADDRESS_HOME_ZIP,
parent,
- {},
MergeMode::kUseMostRecentSubstring | kReplaceEmpty) {}
PostalCode::~PostalCode() = default;
@@ -342,35 +344,37 @@ base::string16 PostalCode::NormalizedValue() const {
SortingCode::SortingCode(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_SORTING_CODE,
parent,
- {},
MergeMode::kReplaceEmpty | kUseMostRecentSubstring) {}
SortingCode::~SortingCode() = default;
-Address::Address() : Address{nullptr} {}
+Address::Address() : Address(nullptr) {}
Address::Address(const Address& other) : Address() {
- *this = other;
+ CopyFrom(other);
}
-bool Address::WipeInvalidStructure() {
- // For structured addresses, currently it is sufficient to wipe the structure
- // of the street address, because this is the only directly assignable value
- // that has a substructure.
- return street_address_.WipeInvalidStructure();
+Address& Address::operator=(const Address& other) {
+ CopyFrom(other);
+ return *this;
}
// Addresses are mergeable when all of their children are mergeable.
-// Reformat the address from their children after merge.
+// Reformat the address from the children after merge if it changed.
Address::Address(AddressComponent* parent)
: AddressComponent(ADDRESS_HOME_ADDRESS,
parent,
- {&street_address_, &postal_code_, &sorting_code_,
- &dependent_locality_, &city_, &state_, &country_code_},
- MergeMode::kMergeChildrenAndReformat) {}
+ MergeMode::kMergeChildrenAndReformatIfNeeded) {}
Address::~Address() = default;
+bool Address::WipeInvalidStructure() {
+ // For structured addresses, currently it is sufficient to wipe the structure
+ // of the street address, because this is the only directly assignable value
+ // that has a substructure.
+ return street_address_.WipeInvalidStructure();
+}
+
void Address::MigrateLegacyStructure(bool is_verified_profile) {
// If this component already has a verification status, no profile is regarded
// as already verified.
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
index 7e872bfc114..87ac1fdc8e8 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
@@ -221,10 +221,9 @@ class Address : public AddressComponent {
Address(const Address& other);
explicit Address(AddressComponent* parent);
~Address() override;
+ Address& operator=(const Address& other);
- // Migrates from a legacy structure in which name tokens are imported without
- // a status.
- void MigrateLegacyStructure(bool is_verified_profile);
+ void MigrateLegacyStructure(bool is_verified_profile) override;
// Checks if the street address contains an invalid structure and wipes it if
// necessary.
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
index 50e6e86f2d2..a2a1c831c31 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
@@ -49,15 +49,50 @@ bool IsLessSignificantVerificationStatus(VerificationStatus left,
static_cast<std::underlying_type_t<VerificationStatus>>(right);
}
+VerificationStatus GetMoreSignificantVerificationStatus(
+ VerificationStatus left,
+ VerificationStatus right) {
+ if (IsLessSignificantVerificationStatus(left, right))
+ return right;
+
+ return left;
+}
+
+std::ostream& operator<<(std::ostream& os, VerificationStatus status) {
+ switch (status) {
+ case VerificationStatus::kNoStatus:
+ os << "NoStatus";
+ break;
+ case VerificationStatus::kParsed:
+ os << "Parsed";
+ break;
+ case VerificationStatus::kFormatted:
+ os << "Formatted";
+ break;
+ case VerificationStatus::kObserved:
+ os << "Observed";
+ break;
+ case VerificationStatus::kServerParsed:
+ os << "ServerParsed";
+ break;
+ case VerificationStatus::kUserVerified:
+ os << "UserVerified";
+ break;
+ }
+ return os;
+}
+
AddressComponent::AddressComponent(ServerFieldType storage_type,
AddressComponent* parent,
- std::vector<AddressComponent*> subcomponents,
unsigned int merge_mode)
: value_verification_status_(VerificationStatus::kNoStatus),
storage_type_(storage_type),
- subcomponents_(subcomponents),
parent_(parent),
- merge_mode_(merge_mode) {}
+ merge_mode_(merge_mode) {
+ if (parent) {
+ parent->RegisterChildNode(this);
+ }
+}
AddressComponent::~AddressComponent() = default;
@@ -66,55 +101,51 @@ ServerFieldType AddressComponent::GetStorageType() const {
}
std::string AddressComponent::GetStorageTypeName() const {
- return AutofillType(storage_type_).ToString();
+ return AutofillType::ServerFieldTypeToString(storage_type_);
}
-AddressComponent& AddressComponent::operator=(const AddressComponent& right) {
- DCHECK(GetStorageType() == right.GetStorageType());
- if (this == &right)
- return *this;
+void AddressComponent::CopyFrom(const AddressComponent& other) {
+ DCHECK(GetStorageType() == other.GetStorageType());
+ if (this == &other)
+ return;
- if (right.IsValueAssigned()) {
- value_ = right.value_;
- value_verification_status_ = right.value_verification_status_;
- sorted_normalized_tokens_ = right.sorted_normalized_tokens_;
+ if (other.IsValueAssigned()) {
+ value_ = other.value_;
+ value_verification_status_ = other.value_verification_status_;
+ sorted_normalized_tokens_ = other.sorted_normalized_tokens_;
} else {
UnsetValue();
}
- DCHECK(right.subcomponents_.size() == subcomponents_.size());
+ CHECK(other.subcomponents_.size() == subcomponents_.size());
- for (size_t i = 0; i < right.subcomponents_.size(); i++)
- *subcomponents_[i] = *right.subcomponents_[i];
+ for (size_t i = 0; i < other.subcomponents_.size(); i++)
+ subcomponents_[i]->CopyFrom(*other.subcomponents_[i]);
PostAssignSanitization();
-
- return *this;
}
-bool AddressComponent::operator==(const AddressComponent& right) const {
- if (this == &right)
+bool AddressComponent::SameAs(const AddressComponent& other) const {
+ if (this == &other)
return true;
- if (GetStorageType() != right.GetStorageType())
+ if (GetStorageType() != other.GetStorageType())
return false;
- if (GetValue() != right.GetValue() ||
- value_verification_status_ != right.value_verification_status_) {
+ if (GetValue() != other.GetValue() ||
+ value_verification_status_ != other.value_verification_status_) {
return false;
}
- DCHECK(right.subcomponents_.size() == subcomponents_.size());
- for (size_t i = 0; i < right.subcomponents_.size(); i++)
- if (!(*subcomponents_[i] == *right.subcomponents_[i]))
+ DCHECK(other.subcomponents_.size() == subcomponents_.size());
+ for (size_t i = 0; i < other.subcomponents_.size(); i++) {
+ if (!(subcomponents_[i]->SameAs(*other.subcomponents_[i]))) {
return false;
+ }
+ }
return true;
}
-bool AddressComponent::operator!=(const AddressComponent& right) const {
- return !(*this == right);
-}
-
bool AddressComponent::IsAtomic() const {
return subcomponents_.empty();
}
@@ -134,7 +165,12 @@ bool AddressComponent::IsValueForTypeValid(const std::string& field_type_name,
bool AddressComponent::IsValueForTypeValid(ServerFieldType field_type,
bool wipe_if_not) {
- return IsValueForTypeValid(AutofillType(field_type).ToString(), wipe_if_not);
+ return IsValueForTypeValid(AutofillType::ServerFieldTypeToString(field_type),
+ wipe_if_not);
+}
+
+void AddressComponent::RegisterChildNode(AddressComponent* child) {
+ subcomponents_.push_back(child);
}
bool AddressComponent::GetIsValueForTypeValidIfPossible(
@@ -191,8 +227,9 @@ void AddressComponent::GetSupportedTypes(
<< storage_type_;
supported_types->insert(storage_type_);
GetAdditionalSupportedFieldTypes(supported_types);
- for (auto* subcomponent : subcomponents_)
+ for (auto* subcomponent : subcomponents_) {
subcomponent->GetSupportedTypes(supported_types);
+ }
}
bool AddressComponent::ConvertAndSetValueForAdditionalFieldTypeName(
@@ -239,9 +276,9 @@ bool AddressComponent::SetValueForTypeIfPossible(
const VerificationStatus& verification_status,
bool invalidate_child_nodes,
bool invalidate_parent_nodes) {
- return SetValueForTypeIfPossible(AutofillType(type).ToString(), value,
- verification_status, invalidate_child_nodes,
- invalidate_parent_nodes);
+ return SetValueForTypeIfPossible(
+ AutofillType::ServerFieldTypeToString(type), value, verification_status,
+ invalidate_child_nodes, invalidate_parent_nodes);
}
bool AddressComponent::SetValueForTypeIfPossible(
@@ -318,8 +355,8 @@ bool AddressComponent::GetValueAndStatusForTypeIfPossible(
const ServerFieldType& type,
base::string16* value,
VerificationStatus* status) const {
- return GetValueAndStatusForTypeIfPossible(AutofillType(type).ToString(),
- value, status);
+ return GetValueAndStatusForTypeIfPossible(
+ AutofillType::ServerFieldTypeToString(type), value, status);
}
bool AddressComponent::GetValueAndStatusForTypeIfPossible(
@@ -353,22 +390,21 @@ bool AddressComponent::GetValueAndStatusForTypeIfPossible(
base::string16 AddressComponent::GetValueForType(
const ServerFieldType& type) const {
- return GetValueForType(AutofillType(type).ToString());
+ return GetValueForType(AutofillType::ServerFieldTypeToString(type));
}
base::string16 AddressComponent::GetValueForType(
const std::string& type_name) const {
base::string16 value;
bool success = GetValueAndStatusForTypeIfPossible(type_name, &value, nullptr);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- DCHECK(success || type_name == AutofillType(NAME_HONORIFIC_PREFIX).ToString())
- << type_name;
+ DCHECK(success) << type_name;
return value;
}
VerificationStatus AddressComponent::GetVerificationStatusForType(
const ServerFieldType& type) const {
- return GetVerificationStatusForType(AutofillType(type).ToString());
+ return GetVerificationStatusForType(
+ AutofillType::ServerFieldTypeToString(type));
}
VerificationStatus AddressComponent::GetVerificationStatusForType(
@@ -376,9 +412,7 @@ VerificationStatus AddressComponent::GetVerificationStatusForType(
VerificationStatus status = VerificationStatus::kNoStatus;
bool success =
GetValueAndStatusForTypeIfPossible(type_name, nullptr, &status);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- DCHECK(success ||
- type_name == AutofillType(NAME_HONORIFIC_PREFIX).ToString());
+ DCHECK(success) << type_name;
return status;
}
@@ -447,11 +481,9 @@ bool AddressComponent::ParseValueAndAssignSubcomponentsByRegularExpression(
const std::string& field_type = result_entry.first;
base::string16 field_value = base::UTF8ToUTF16(result_entry.second);
// Do not reassign the value of this node.
- if (field_type == GetStorageTypeName())
- continue;
- // crbug.com(1113617): Honorifics are temporarily disabled.
- if (field_type == AutofillType(NAME_HONORIFIC_PREFIX).ToString())
+ if (field_type == GetStorageTypeName()) {
continue;
+ }
bool success = SetValueForTypeIfPossible(field_type, field_value,
VerificationStatus::kParsed);
// Setting the value should always work unless the regular expression is
@@ -504,28 +536,35 @@ void AddressComponent::ParseValueAndAssignSubcomponentsByFallbackMethod() {
DCHECK(success);
}
-bool AddressComponent::WipeInvalidStructure() {
+bool AddressComponent::AllDescendantsAreEmpty() const {
+ return base::ranges::all_of(Subcomponents(), [](const auto* c) {
+ return c->GetValue().empty() && c->AllDescendantsAreEmpty();
+ });
+}
+
+bool AddressComponent::IsStructureValid() const {
if (IsAtomic()) {
- return false;
+ return true;
}
-
// Test that each structured token is part of the subcomponent.
// This is not perfect, because different components can match with an
// overlapping portion of the unstructured string, but it guarantees that all
// information in the components is contained in the unstructured
// representation.
- for (const auto* component : Subcomponents()) {
- if (GetValue().find(component->GetValue()) == base::string16::npos) {
- // If the value of one component could not have been found, wipe the full
- // structure.
- RecursivelyUnsetSubcomponents();
- return true;
- }
+ return base::ranges::all_of(Subcomponents(), [this](const auto* c) {
+ return GetValue().find(c->GetValue()) != base::string16::npos;
+ });
+}
+
+bool AddressComponent::WipeInvalidStructure() {
+ if (!IsStructureValid()) {
+ RecursivelyUnsetSubcomponents();
+ return true;
}
return false;
}
-void AddressComponent::FormatValueFromSubcomponents() {
+base::string16 AddressComponent::GetFormattedValueFromSubcomponents() {
// Get the most suited format string.
base::string16 format_string = GetBestFormatString();
@@ -536,8 +575,13 @@ void AddressComponent::FormatValueFromSubcomponents() {
// with an empty value.
base::string16 result = ReplacePlaceholderTypesWithValues(format_string);
- result = base::CollapseWhitespace(result, /*trim_line_breaks=*/false);
- SetValue(result, VerificationStatus::kFormatted);
+ return base::CollapseWhitespace(result,
+ /*trim_sequences_with_line_breaks=*/false);
+}
+
+void AddressComponent::FormatValueFromSubcomponents() {
+ SetValue(GetFormattedValueFromSubcomponents(),
+ VerificationStatus::kFormatted);
}
base::string16 AddressComponent::ReplacePlaceholderTypesWithValues(
@@ -761,9 +805,14 @@ bool AddressComponent::IsMergeableWithComponent(
const base::string16 value_newer = newer_component.ValueForComparison();
// If both components are the same, there is nothing to do.
- if (*this == newer_component)
+ if (SameAs(newer_component))
return true;
+ if (merge_mode_ & kUseNewerIfDifferent ||
+ merge_mode_ & kUseBetterOrMostRecentIfDifferent) {
+ return true;
+ }
+
if ((merge_mode_ & kReplaceEmpty) && (value.empty() || value_newer.empty())) {
return true;
}
@@ -791,12 +840,15 @@ bool AddressComponent::IsMergeableWithComponent(
if ((merge_mode_ & kRecursivelyMergeSingleTokenSubset) &&
token_comparison_result.IsSingleTokenSuperset()) {
- return true;
+ // This strategy is only applicable if also the unnormalized values have a
+ // single-token-superset relation.
+ SortedTokenComparisonResult unnormalized_token_comparison_result =
+ CompareSortedTokens(GetValue(), newer_component.GetValue());
+ if (unnormalized_token_comparison_result.IsSingleTokenSuperset()) {
+ return true;
+ }
}
- if (merge_mode_ == kUseNewerIfDifferent)
- return true;
-
// If the one value is a substring of the other, use the substring of the
// corresponding mode is active.
if ((merge_mode_ & kUseMostRecentSubstring) &&
@@ -810,7 +862,8 @@ bool AddressComponent::IsMergeableWithComponent(
return true;
}
- if (merge_mode_ == kMergeChildrenAndReformat) {
+ // Checks if all child nodes are mergeable.
+ if (merge_mode_ & kMergeChildrenAndReformatIfNeeded) {
bool is_mergeable = true;
DCHECK(newer_component.subcomponents_.size() == subcomponents_.size());
for (size_t i = 0; i < newer_component.subcomponents_.size(); i++) {
@@ -833,25 +886,28 @@ bool AddressComponent::MergeWithComponent(
const base::string16 value = ValueForComparison();
const base::string16 value_newer = newer_component.ValueForComparison();
-
- if (*this == newer_component)
+ if (SameAs(newer_component))
return true;
// Now, it is guaranteed that both values are not identical.
// Use the non empty one if the corresponding mode is active.
if (merge_mode_ & kReplaceEmpty) {
if (value.empty()) {
- *this = newer_component;
+ // Only replace the value if the verification status is not kUserVerified.
+ if (GetVerificationStatus() != VerificationStatus::kUserVerified) {
+ CopyFrom(newer_component);
+ }
return true;
}
- if (value_newer.empty())
+ if (value_newer.empty()) {
return true;
+ }
}
// If the normalized values are the same, optimize the verification status.
if ((merge_mode_ & kUseBetterOrNewerForSameValue) && (value == value_newer)) {
if (HasNewerValuePrecendenceInMerging(newer_component)) {
- *this = newer_component;
+ CopyFrom(newer_component);
}
return true;
}
@@ -869,8 +925,11 @@ bool AddressComponent::MergeWithComponent(
// Replace the subset with the superset if the corresponding mode is active.
if ((merge_mode_ & kReplaceSubset) && token_comparison_result.OneIsSubset()) {
- if (token_comparison_result.status == SUBSET)
- *this = newer_component;
+ if (token_comparison_result.status == SUBSET &&
+ !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus())) {
+ CopyFrom(newer_component);
+ }
return true;
}
@@ -878,15 +937,18 @@ bool AddressComponent::MergeWithComponent(
if ((merge_mode_ & kReplaceSuperset) &&
token_comparison_result.OneIsSubset()) {
if (token_comparison_result.status == SUPERSET)
- *this = newer_component;
+ CopyFrom(newer_component);
return true;
}
// If the tokens are already equivalent, use the more recently used one.
if ((merge_mode_ & (kReplaceSuperset | kReplaceSubset)) &&
token_comparison_result.status == MATCH) {
- if (newer_was_more_recently_used)
- *this = newer_component;
+ if (newer_was_more_recently_used &&
+ !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus())) {
+ CopyFrom(newer_component);
+ }
return true;
}
@@ -896,15 +958,20 @@ bool AddressComponent::MergeWithComponent(
token_comparison_result.IsSingleTokenSuperset()) {
// For the merging of subset token, the tokenization must be done without
// prior normalization of the values.
- SortedTokenComparisonResult token_comparison_result =
+ SortedTokenComparisonResult unnormalized_token_comparison_result =
CompareSortedTokens(GetValue(), newer_component.GetValue());
- return MergeSubsetComponent(newer_component, token_comparison_result);
+ // The merging strategy can only be applied when the comparison of the
+ // unnormalized tokens still yields a single token superset.
+ if (unnormalized_token_comparison_result.IsSingleTokenSuperset()) {
+ return MergeSubsetComponent(newer_component,
+ unnormalized_token_comparison_result);
+ }
}
// Replace the older value with the newer one if the corresponding mode is
// active.
if (merge_mode_ & kUseNewerIfDifferent) {
- *this = newer_component;
+ CopyFrom(newer_component);
return true;
}
@@ -913,21 +980,34 @@ bool AddressComponent::MergeWithComponent(
if ((merge_mode_ & kUseMostRecentSubstring) &&
(value.find(value_newer) != base::string16::npos ||
value_newer.find(value) != base::string16::npos)) {
- if (newer_was_more_recently_used)
- *this = newer_component;
+ if (newer_was_more_recently_used &&
+ !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus()))
+ CopyFrom(newer_component);
return true;
}
if ((merge_mode_ & kPickShorterIfOneContainsTheOther) &&
token_comparison_result.ContainEachOther()) {
- if (newer_component.GetValue().size() <= GetValue().size())
- *this = newer_component;
+ if (newer_component.GetValue().size() <= GetValue().size() &&
+ !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus())) {
+ CopyFrom(newer_component);
+ }
+ return true;
+ }
+
+ if (merge_mode_ & kUseBetterOrMostRecentIfDifferent) {
+ if (HasNewerValuePrecendenceInMerging(newer_component)) {
+ SetValue(newer_component.GetValue(),
+ newer_component.GetVerificationStatus());
+ }
return true;
}
// If the corresponding mode is active, ignore this mode and pair-wise merge
// the child tokens. Reformat this nodes from its children after the merge.
- if (merge_mode_ & kMergeChildrenAndReformat) {
+ if (merge_mode_ & kMergeChildrenAndReformatIfNeeded) {
DCHECK(newer_component.subcomponents_.size() == subcomponents_.size());
for (size_t i = 0; i < newer_component.subcomponents_.size(); i++) {
bool success = subcomponents_[i]->MergeWithComponent(
@@ -935,9 +1015,37 @@ bool AddressComponent::MergeWithComponent(
if (!success)
return false;
}
- FormatValueFromSubcomponents();
+ // If the two values are already token equivalent, use the value of the
+ // component with the better verification status, or if both are the same,
+ // use the newer one.
+ if (token_comparison_result.TokensMatch()) {
+ if (HasNewerValuePrecendenceInMerging(newer_component)) {
+ SetValue(newer_component.GetValue(),
+ newer_component.GetVerificationStatus());
+ }
+ } else {
+ // Otherwise do a reformat from the subcomponents.
+ base::string16 formatted_value = GetFormattedValueFromSubcomponents();
+ // If the current value is maintained, keep the more significant
+ // verification status.
+ if (formatted_value == GetValue()) {
+ SetValue(formatted_value,
+ GetMoreSignificantVerificationStatus(
+ VerificationStatus::kFormatted, GetVerificationStatus()));
+ } else if (formatted_value == newer_component.GetValue()) {
+ // Otherwise test if the value is the same as the one of
+ // |newer_component|. If yes, maintain the better verification status.
+ SetValue(formatted_value, GetMoreSignificantVerificationStatus(
+ VerificationStatus::kFormatted,
+ newer_component.GetVerificationStatus()));
+ } else {
+ // In all other cases, set the formatted_value.
+ SetValue(formatted_value, VerificationStatus::kFormatted);
+ }
+ }
return true;
}
+
return false;
}
@@ -972,11 +1080,30 @@ bool AddressComponent::MergeTokenEquivalentComponent(
// this component or the other depending on which substructure is better in
// terms of the number of validated tokens.
+ const std::vector<AddressComponent*> other_subcomponents =
+ newer_component.Subcomponents();
+ DCHECK(subcomponents_.size() == other_subcomponents.size());
+
if (HasNewerValuePrecendenceInMerging(newer_component)) {
SetValue(newer_component.GetValue(),
newer_component.GetVerificationStatus());
}
+ if (IsAtomic())
+ return true;
+
+ // If the other component has subtree, just keep this one.
+ if (newer_component.AllDescendantsAreEmpty()) {
+ return true;
+ } else if (AllDescendantsAreEmpty()) {
+ // Otherwise, replace this subtree with the other one if this subtree is
+ // empty.
+ for (size_t i = 0; i < subcomponents_.size(); ++i) {
+ subcomponents_[i]->CopyFrom(*other_subcomponents[i]);
+ }
+ return true;
+ }
+
// Now, the substructure of the node must be merged. There are three cases:
//
// * All nodes of the substructure are pairwise mergeable. In this case it
@@ -1001,11 +1128,6 @@ bool AddressComponent::MergeTokenEquivalentComponent(
// components. By favoring the other component in a tie, the most recently
// used structure wins.
- const std::vector<AddressComponent*> other_subcomponents =
- newer_component.Subcomponents();
-
- DCHECK(subcomponents_.size() == other_subcomponents.size());
-
int this_component_verification_score = 0;
int newer_component_verification_score = 0;
@@ -1033,10 +1155,10 @@ bool AddressComponent::MergeTokenEquivalentComponent(
// component is equal or larger than the score of this component, use its
// subcomponents including their substructure for all unmerged components.
if (newer_component_verification_score >= this_component_verification_score) {
- for (size_t i : unmerged_indices)
- *subcomponents_[i] = *other_subcomponents[i];
+ for (size_t i : unmerged_indices) {
+ subcomponents_[i]->CopyFrom(*other_subcomponents[i]);
+ }
}
-
return true;
}
@@ -1136,7 +1258,7 @@ bool AddressComponent::MergeSubsetComponent(
// subcomponents including their substructure for all unmerged components.
if (newer_component_verification_score >= this_component_verification_score) {
for (size_t i : unmerged_indices)
- *subcomponents_[i] = *subset_subcomponents[i];
+ subcomponents_[i]->CopyFrom(*subset_subcomponents[i]);
if (!found_subset_component)
this->ConsumeAdditionalToken(token_to_consume);
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
index 7adba19a86e..8b7f5345471 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -41,12 +41,26 @@ enum class VerificationStatus {
kServerParsed = 5,
};
+// Prints the string representation of |status| to |os|.
+std::ostream& operator<<(std::ostream& os, VerificationStatus status);
+
// Returns true if |left| has a less significant verification status compared to
// |right|.
bool IsLessSignificantVerificationStatus(VerificationStatus left,
VerificationStatus right);
+// Returns the more significant verification status according to
+// |IsLessSignificantVerificationStatus|.
+VerificationStatus GetMoreSignificantVerificationStatus(
+ VerificationStatus left,
+ VerificationStatus right);
+
// The merge mode defines if and how two components are merged.
+// The merge operations are applied in the order defined here.
+// If one merge operation succeeds, the subsequent ones are not tested.
+// Therefore, if |KUseBetterOrMoreRecentIfDifferent| is active,
+// |kMergeChildrenAndReformatIfNeeded| will not be applied because
+// |kUseBetterOrMostRecentIfDifferent| is always applicable.
enum MergeMode {
// If one component has an empty value, use the non-empty one.
kReplaceEmpty = 1,
@@ -65,13 +79,17 @@ enum MergeMode {
// If the newer component contains one token more, apply a recursive strategy
// to merge the tokens.
kRecursivelyMergeSingleTokenSubset = 1 << 6,
- // If one is a substring use the most recent one.
+ // If one is a substring of the other use the most recent one.
kUseMostRecentSubstring = 1 << 7,
- // Merge the child nodes and reformat the node from its children after merge.
- kMergeChildrenAndReformat = 1 << 8,
- // If the tokens match or one is a subset of the other, pick the shorter one.
- kPickShorterIfOneContainsTheOther = 1 << 9,
+ // Merge the child nodes and reformat the node from its children after merge
+ // if the value has changed.
+ kPickShorterIfOneContainsTheOther = 1 << 8,
+ // If the normalized values are different, use the better one in terms
+ // of verification score or the most recent one if both scores are the same.
+ kUseBetterOrMostRecentIfDifferent = 1 << 9,
// Defines the default merging behavior.
+ kMergeChildrenAndReformatIfNeeded = 1 << 10,
+ // If the tokens match or one is a subset of the other, pick the shorter one.
kDefault = kRecursivelyMergeTokenEquivalentValues
};
@@ -119,25 +137,31 @@ class AddressComponent {
// Constructor for a compound child node.
AddressComponent(ServerFieldType storage_type,
AddressComponent* parent,
- std::vector<AddressComponent*> subcomponents,
unsigned int merge_mode);
- // Disallows copies since they are not needed in the current Autofill design.
+ // Disallows copies and direct assignments since they are not needed in the
+ // current Autofill design.
AddressComponent(const AddressComponent& other) = delete;
+ AddressComponent& operator=(const AddressComponent& right) = delete;
virtual ~AddressComponent();
- // Assignment operator that works recursively down the tree and assigns the
- // |value_| and |verification_status_| of every node in right to the
- // corresponding nodes in |this|. For an assignment it is required that both
- // nodes have the same |storage_type_|.
- AddressComponent& operator=(const AddressComponent& right);
+ // Migrates from a legacy structure in which tokens are imported without
+ // a status.
+ virtual void MigrateLegacyStructure(bool is_verified_profile) {}
+
+ // Comparison operators are deleted in favor of and |SameAs()|.
+ bool operator==(const AddressComponent& right) const = delete;
+ bool operator!=(const AddressComponent& right) const = delete;
- // Comparison operator that works recursively down the tree.
- bool operator==(const AddressComponent& right) const;
+ // Compares the values and verification statuses with |other| recursively down
+ // the tree. Returns true iff all values and verification statuses of this
+ // node and its subtree and |other| with its subtree are the same.
+ bool SameAs(const AddressComponent& other) const;
- // Inequality operator that works recursively down the tree.
- bool operator!=(const AddressComponent& right) const;
+ // Copies the values and verification statuses from |other| recursively down
+ // the tree.
+ void CopyFrom(const AddressComponent& other);
// Returns the autofill storage type stored in |storage_type_|.
ServerFieldType GetStorageType() const;
@@ -341,11 +365,18 @@ class AddressComponent {
bool* validity_status,
bool wipe_if_not = false);
- // Deletes the stored structure if it contains strings that are not a
- // substring of the unstructured representation.
- // Return true if a wipe operation was performed.
+ // Deletes the stored structure and returns true if |IsStructureValid()|
+ // returns false.
virtual bool WipeInvalidStructure();
+ // Returns if the structure in the tree below this node is valid. A structure
+ // becomes invalid when it contains information that is not contained in the
+ // value of this node.
+ bool IsStructureValid() const;
+
+ // Returns true if all values of all descendent nodes are empty.
+ bool AllDescendantsAreEmpty() const;
+
#ifdef UNIT_TEST
// Initiates the formatting of the values from the subcomponents.
void FormatValueFromSubcomponentsForTesting() {
@@ -381,6 +412,10 @@ class AddressComponent {
// Sets the merge mode for testing purposes.
void SetMergeModeForTesting(int merge_mode) { merge_mode_ = merge_mode; }
+ // Returns the value used for comparison for testing purposes.
+ base::string16 ValueForComparisonForTesting() const {
+ return ValueForComparison();
+ }
#endif
protected:
@@ -480,16 +515,28 @@ class AddressComponent {
const base::string16& value,
const re2::RE2* parse_expression);
+ // Determines and sets a formatted value using
+ // |GetFormattedValueFromSubcomponents|.
+ void FormatValueFromSubcomponents();
+
+ // Returns the maximum number of components with assigned values on the path
+ // from the component to a leaf node.
+ int MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() const;
+
private:
+ // Function to be called by child nodes on construction to register
+ // themselves as child nodes.
+ void RegisterChildNode(AddressComponent* child);
+
// Unsets the node and all of its children.
void UnsetAddressComponentAndItsSubcomponents();
// Unsets the children of a node.
void UnsetSubcomponents();
- // Determines the |value_| from the values of the subcomponents by using the
+ // Determines a value from the subcomponents by using the
// most suitable format string determined by |GetBestFormatString()|.
- void FormatValueFromSubcomponents();
+ base::string16 GetFormattedValueFromSubcomponents();
// Replaces placeholder values with the corresponding values.
base::string16 ReplacePlaceholderTypesWithValues(
@@ -504,10 +551,6 @@ class AddressComponent {
// of the subcomponents. Returns true on success and is allowed to fail.
bool ParseValueAndAssignSubcomponentsByRegularExpressions();
- // Returns the maximum number of components with assigned values on the path
- // from the component to a leaf node.
- int MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() const;
-
// The unstructured value of this component.
base::Optional<base::string16> value_;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
index a9356b83cd8..029c510ea41 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
@@ -30,7 +30,7 @@ class TestAtomicFirstNameAddressComponent : public AddressComponent {
TestAtomicFirstNameAddressComponent()
: TestAtomicFirstNameAddressComponent(nullptr) {}
explicit TestAtomicFirstNameAddressComponent(AddressComponent* parent)
- : AddressComponent(NAME_FIRST, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_FIRST, parent, MergeMode::kDefault) {}
};
class TestAtomicMiddleNameAddressComponent : public AddressComponent {
@@ -38,7 +38,7 @@ class TestAtomicMiddleNameAddressComponent : public AddressComponent {
TestAtomicMiddleNameAddressComponent()
: TestAtomicMiddleNameAddressComponent(nullptr) {}
explicit TestAtomicMiddleNameAddressComponent(AddressComponent* parent)
- : AddressComponent(NAME_MIDDLE, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_MIDDLE, parent, MergeMode::kDefault) {}
void GetAdditionalSupportedFieldTypes(
ServerFieldTypeSet* supported_types) const override {
@@ -51,7 +51,8 @@ class TestAtomicMiddleNameAddressComponent : public AddressComponent {
const std::string& field_type_name,
const base::string16& value,
const VerificationStatus& status) override {
- if (field_type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
+ if (field_type_name ==
+ AutofillType::ServerFieldTypeToString(NAME_MIDDLE_INITIAL)) {
SetValue(value, status);
return true;
}
@@ -61,7 +62,8 @@ class TestAtomicMiddleNameAddressComponent : public AddressComponent {
bool ConvertAndGetTheValueForAdditionalFieldTypeName(
const std::string& field_type_name,
base::string16* value) const override {
- if (field_type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
+ if (field_type_name ==
+ AutofillType::ServerFieldTypeToString(NAME_MIDDLE_INITIAL)) {
if (value) {
*value = GetValue().substr(0, 1);
}
@@ -76,7 +78,7 @@ class TestAtomicLastNameAddressComponent : public AddressComponent {
TestAtomicLastNameAddressComponent()
: TestAtomicLastNameAddressComponent(nullptr) {}
explicit TestAtomicLastNameAddressComponent(AddressComponent* parent)
- : AddressComponent(NAME_LAST, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_LAST, parent, MergeMode::kDefault) {}
};
// Creates a compound name for testing purposes.
@@ -87,7 +89,6 @@ class TestCompoundNameAddressComponent : public AddressComponent {
explicit TestCompoundNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
- {&first_name_, &middle_name_, &last_name_},
MergeMode::kDefault) {}
AddressComponent* GetFirstNameSubComponentForTesting() {
@@ -109,7 +110,6 @@ class TestCompoundNameMethodParsedAddressComponent : public AddressComponent {
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
- {&first_name_, &middle_name_, &last_name_},
MergeMode::kDefault) {}
bool ParseValueAndAssignSubcomponentsByMethod() override {
@@ -137,7 +137,6 @@ class TestCompoundNameRegExParsedAddressComponent : public AddressComponent {
explicit TestCompoundNameRegExParsedAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
- {&first_name_, &middle_name_, &last_name_},
MergeMode::kDefault) {}
std::vector<const RE2*> GetParseRegularExpressionsByRelevance()
@@ -164,7 +163,6 @@ class TestCompoundNameCustomFormatAddressComponent : public AddressComponent {
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
- {&first_name, &middle_name, &last_name},
MergeMode::kDefault) {}
// Introduces a custom format with a leading last name.
@@ -188,7 +186,6 @@ class TestCompoundNameCustomAffixedFormatAddressComponent
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
- {&first_name, &middle_name, &last_name},
MergeMode::kDefault) {}
// Introduces a custom format with a leading last name.
@@ -213,7 +210,6 @@ class TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
- {&first_name, &middle_name, &last_name},
MergeMode::kDefault) {}
// Introduce a custom format with a leading last name.
@@ -234,7 +230,6 @@ class TestAtomicTitleAddressComponent : public AddressComponent {
explicit TestAtomicTitleAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_HONORIFIC_PREFIX,
parent,
- {},
MergeMode::kDefault) {}
};
@@ -246,7 +241,6 @@ class TestCompoundNameWithTitleAddressComponent : public AddressComponent {
explicit TestCompoundNameWithTitleAddressComponent(AddressComponent* parent)
: AddressComponent(CREDIT_CARD_NAME_FULL,
parent,
- {&title, &full_name},
MergeMode::kDefault) {}
private:
@@ -263,13 +257,34 @@ class TestNonProperFirstNameAddressComponent : public AddressComponent {
explicit TestNonProperFirstNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_FIRST,
parent,
- {&second_name_first_node_},
MergeMode::kDefault) {}
private:
- TestAtomicFirstNameAddressComponent second_name_first_node_;
+ TestAtomicFirstNameAddressComponent second_name_first_node_{this};
};
+// Tests the merging of two atomic component with |type|, and vales
+// |older_values| and |newer_values| respectively, and |merge_modes|.
+// If |is_mergeable| it is expected that the two components are mergeable.
+// If |newer_was_more_recently_used| the newer component was also more recently
+// used which is true by default.
+void TestAtomMerging(ServerFieldType type,
+ AddressComponentTestValues older_values,
+ AddressComponentTestValues newer_values,
+ AddressComponentTestValues merge_expectation,
+ bool is_mergeable,
+ int merge_modes,
+ bool newer_was_more_recently_used = true) {
+ AddressComponent older(type, nullptr, merge_modes);
+ AddressComponent newer(type, nullptr, merge_modes);
+
+ SetTestValues(&older, older_values);
+ SetTestValues(&newer, newer_values);
+
+ TestMerging(&older, &newer, merge_expectation, is_mergeable, merge_modes,
+ newer_was_more_recently_used);
+}
+
void TestCompoundNameMerging(AddressComponentTestValues older_values,
AddressComponentTestValues newer_values,
AddressComponentTestValues merge_expectation,
@@ -289,7 +304,7 @@ void TestCompoundNameMerging(AddressComponentTestValues older_values,
// Tests that the destructor does not crash
TEST(AutofillStructuredAddressAddressComponent, ConstructAndDestruct) {
AddressComponent* component =
- new AddressComponent(NAME_FULL, nullptr, {}, MergeMode::kDefault);
+ new AddressComponent(NAME_FULL, nullptr, MergeMode::kDefault);
delete component;
EXPECT_TRUE(true);
}
@@ -383,9 +398,9 @@ TEST(AutofillStructuredAddressAddressComponent, TestGetSupportedTypes) {
}
// Tests the comparison of thw atoms of the same type.
-TEST(AutofillStructuredAddressAddressComponent, TestComparisonOperator_Atom) {
- AddressComponent left(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
- AddressComponent right(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
+TEST(AutofillStructuredAddressAddressComponent, TestComparison_Atom) {
+ AddressComponent left(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
+ AddressComponent right(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
left.SetValue(UTF8ToUTF16("some value"), VerificationStatus::kParsed);
right.SetValue(UTF8ToUTF16("some other value"),
@@ -393,37 +408,34 @@ TEST(AutofillStructuredAddressAddressComponent, TestComparisonOperator_Atom) {
EXPECT_NE(left.GetValue(), right.GetValue());
EXPECT_NE(left.GetVerificationStatus(), right.GetVerificationStatus());
- EXPECT_FALSE(left == right);
- EXPECT_TRUE(left != right);
+ EXPECT_FALSE(left.SameAs(right));
right.SetValue(UTF8ToUTF16("some value"), VerificationStatus::kParsed);
- EXPECT_TRUE(left == right);
- EXPECT_FALSE(left != right);
+ EXPECT_TRUE(left.SameAs(right));
}
// Tests comparison of two different types.
TEST(AutofillStructuredAddressAddressComponent,
TestComparisonOperator_DifferentTypes) {
- AddressComponent type_a1(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
- AddressComponent type_a2(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
- AddressComponent type_b(NAME_LAST, nullptr, {}, MergeMode::kReplaceEmpty);
+ AddressComponent type_a1(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
+ AddressComponent type_a2(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
+ AddressComponent type_b(NAME_LAST, nullptr, MergeMode::kReplaceEmpty);
- EXPECT_TRUE(type_a1 == type_a2);
- EXPECT_FALSE(type_a1 == type_b);
+ EXPECT_TRUE(type_a1.SameAs(type_a2));
+ EXPECT_FALSE(type_a1.SameAs(type_b));
}
// Tests the comparison with itself.
TEST(AutofillStructuredAddressAddressComponent,
TestComparisonOperator_SelfComparison) {
- AddressComponent type_a(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
+ AddressComponent type_a(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
- EXPECT_TRUE(type_a == type_a);
+ EXPECT_TRUE(type_a.SameAs(type_a));
}
// Tests the comparison operator.
-TEST(AutofillStructuredAddressAddressComponent,
- TestComparisonOperator_Compound) {
+TEST(AutofillStructuredAddressAddressComponent, TestComparison_Compound) {
TestCompoundNameAddressComponent left;
TestCompoundNameAddressComponent right;
@@ -461,8 +473,7 @@ TEST(AutofillStructuredAddressAddressComponent,
EXPECT_EQ(right.GetVerificationStatusForType(NAME_MIDDLE),
VerificationStatus::kParsed);
- EXPECT_FALSE(left == right);
- EXPECT_TRUE(left != right);
+ EXPECT_FALSE(left.SameAs(right));
// Set left to the same values as right and verify that it is now equal.
TestCompoundNameAddressComponent same_right;
@@ -471,29 +482,51 @@ TEST(AutofillStructuredAddressAddressComponent,
VerificationStatus::kUserVerified);
EXPECT_TRUE(same_right.CompleteFullTree());
- EXPECT_TRUE(right == same_right);
- EXPECT_FALSE(right != same_right);
+ EXPECT_TRUE(right.SameAs(same_right));
// Change one subcomponent and verify that it is not equal anymore.
same_right.SetValueForTypeIfPossible(NAME_LAST, UTF8ToUTF16("Joker"),
VerificationStatus::kParsed);
- EXPECT_TRUE(right != same_right);
- EXPECT_FALSE(right == same_right);
+ EXPECT_FALSE(right.SameAs(same_right));
}
// Tests the assignment operator.
TEST(AutofillStructuredAddressAddressComponent, TestAssignmentOperator_Atom) {
- AddressComponent left(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
- AddressComponent right(NAME_FIRST, nullptr, {}, MergeMode::kReplaceEmpty);
+ AddressComponent left(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
+ AddressComponent right(NAME_FIRST, nullptr, MergeMode::kReplaceEmpty);
left.SetValue(UTF8ToUTF16("some value"), VerificationStatus::kParsed);
right.SetValue(UTF8ToUTF16("some other value"),
VerificationStatus::kFormatted);
- EXPECT_FALSE(left == right);
+ EXPECT_FALSE(left.SameAs(right));
left.SetValue(UTF8ToUTF16("some other value"),
VerificationStatus::kFormatted);
- EXPECT_TRUE(left == right);
+ EXPECT_TRUE(left.SameAs(right));
+}
+
+// Tests the assignment operator when using the base class type.
+TEST(AutofillStructuredAddressAddressComponent,
+ TestAssignmentOperator_Compound_FromBase) {
+ TestCompoundNameAddressComponent left;
+ TestCompoundNameAddressComponent right;
+
+ left.SetValueForTypeIfPossible(NAME_FULL, UTF8ToUTF16("First Middle Last"),
+ VerificationStatus::kObserved);
+ left.RecursivelyCompleteTree();
+
+ right.SetValueForTypeIfPossible(NAME_FULL, UTF8ToUTF16("The Dark Knight"),
+ VerificationStatus::kParsed);
+ right.RecursivelyCompleteTree();
+
+ AddressComponent* left_base = &left;
+ AddressComponent* right_base = &right;
+ EXPECT_FALSE(left_base->SameAs(*right_base));
+
+ // Use the assignment operators defined in the base.
+ left_base->CopyFrom(*right_base);
+ // But verify that the higher level classes are assigned correctly.
+ EXPECT_TRUE(left.SameAs(right));
}
// Tests the assignment operator on a compound node.
@@ -510,10 +543,10 @@ TEST(AutofillStructuredAddressAddressComponent,
VerificationStatus::kParsed);
right.RecursivelyCompleteTree();
- EXPECT_FALSE(left == right);
+ EXPECT_FALSE(left.SameAs(right));
- left = right;
- EXPECT_TRUE(left == right);
+ left.CopyFrom(right);
+ EXPECT_TRUE(left.SameAs(right));
}
// Tests that self-assignment does not break things.
@@ -522,7 +555,7 @@ TEST(AutofillStructuredAddressAddressComponent, SelfAssignment) {
left.SetValueForTypeIfPossible(NAME_FULL, UTF8ToUTF16("First Middle Last"),
VerificationStatus::kObserved);
- left = *(&left);
+ left.CopyFrom(*(&left));
EXPECT_EQ(left.GetValueForType(NAME_FULL), UTF8ToUTF16("First Middle Last"));
}
@@ -1398,7 +1431,7 @@ TEST(AutofillStructuredAddressAddressComponent, MergePermutatedComponent) {
VerificationStatus::kObserved));
TestCompoundNameAddressComponent copy_of_one;
- copy_of_one = one;
+ copy_of_one.CopyFrom(one);
EXPECT_TRUE(one.MergeWithComponent(two));
// As a result of the merging, the unstructured representation should be
@@ -1577,7 +1610,7 @@ TEST(AutofillStructuredAddressAddressComponent, MergeChildsAndReformatRoot) {
// Set the root node to merging mode which only merges the children and gets
// reformatted afterwards.
- older.SetMergeModeForTesting(MergeMode::kMergeChildrenAndReformat);
+ older.SetMergeModeForTesting(MergeMode::kMergeChildrenAndReformatIfNeeded);
// Set the merge modes of the children to replace empty values and use
// supersets.
for (auto* subcomponent : older.Subcomponents()) {
@@ -1661,7 +1694,7 @@ TEST(AutofillStructuredAddressAddressComponent, MergeChildsAndReformatRoot) {
VerifyTestValues(&older, older_values);
}
-// Test the comparison of different Verification statuses.
+// Tests the comparison of different Verification statuses.
TEST(AutofillStructuredAddressAddressComponent,
TestIsLessSignificantVerificationStatus) {
EXPECT_TRUE(IsLessSignificantVerificationStatus(
@@ -1682,5 +1715,64 @@ TEST(AutofillStructuredAddressAddressComponent,
VerificationStatus::kUserVerified, VerificationStatus::kServerParsed));
}
+// Tests gettings the more significant VerificationStatus.
+TEST(AutofillStructuredAddressAddressComponent,
+ GetMoreSignificantVerificationStatus) {
+ EXPECT_EQ(VerificationStatus::kFormatted,
+ GetMoreSignificantVerificationStatus(VerificationStatus::kFormatted,
+ VerificationStatus::kParsed));
+ EXPECT_EQ(VerificationStatus::kObserved,
+ GetMoreSignificantVerificationStatus(
+ VerificationStatus::kFormatted, VerificationStatus::kObserved));
+ EXPECT_EQ(
+ VerificationStatus::kUserVerified,
+ GetMoreSignificantVerificationStatus(VerificationStatus::kUserVerified,
+ VerificationStatus::kUserVerified));
+}
+
+// Tests merging using the Mermode::KUseBetterOrMoreRecentIfDifferent|
+TEST(AutofillStructuredAddressAddressComponent,
+ TestUseBetterOfMoreRecentIfDifferentMergeStrategy) {
+ AddressComponentTestValues old_values = {
+ {.type = NAME_FIRST,
+ .value = "first value",
+ .status = VerificationStatus::kObserved}};
+ AddressComponentTestValues newer_values = {
+ {.type = NAME_FIRST,
+ .value = "second value",
+ .status = VerificationStatus::kObserved}};
+ AddressComponentTestValues better_values = {
+ {.type = NAME_FIRST,
+ .value = "second value",
+ .status = VerificationStatus::kUserVerified}};
+ AddressComponentTestValues not_better_values = {
+ {.type = NAME_FIRST,
+ .value = "second value",
+ .status = VerificationStatus::kParsed}};
+
+ // Test that the newer values are used.
+ TestAtomMerging(NAME_FIRST, old_values, newer_values, newer_values,
+ /*is_mergable=*/true,
+ MergeMode::kUseBetterOrMostRecentIfDifferent);
+
+ // Test that the better values are used.
+ TestAtomMerging(NAME_FIRST, old_values, better_values, better_values,
+ /*is_mergable=*/true,
+ MergeMode::kUseBetterOrMostRecentIfDifferent);
+ // Should work equally in both directions.
+ TestAtomMerging(NAME_FIRST, better_values, old_values, better_values,
+ /*is_mergable=*/true,
+ MergeMode::kUseBetterOrMostRecentIfDifferent);
+
+ // Test that the not better values are not used.
+ TestAtomMerging(NAME_FIRST, old_values, not_better_values, old_values,
+ /*is_mergable=*/true,
+ MergeMode::kUseBetterOrMostRecentIfDifferent);
+ // Should work equally in both directions.
+ TestAtomMerging(NAME_FIRST, not_better_values, old_values, old_values,
+ /*is_mergable=*/true,
+ MergeMode::kUseBetterOrMostRecentIfDifferent);
+}
+
} // namespace structured_address
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.cc
index e544cc54c78..dfc86617acc 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.cc
@@ -40,18 +40,17 @@ base::string16 ReduceToInitials(const base::string16& value) {
}
NameHonorific::NameHonorific(AddressComponent* parent)
- : AddressComponent(NAME_HONORIFIC_PREFIX, parent, {}, MergeMode::kDefault) {
-}
+ : AddressComponent(NAME_HONORIFIC_PREFIX, parent, MergeMode::kDefault) {}
NameHonorific::~NameHonorific() = default;
NameFirst::NameFirst(AddressComponent* parent)
- : AddressComponent(NAME_FIRST, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_FIRST, parent, MergeMode::kDefault) {}
NameFirst::~NameFirst() = default;
NameMiddle::NameMiddle(AddressComponent* parent)
- : AddressComponent(NAME_MIDDLE, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_MIDDLE, parent, MergeMode::kDefault) {}
NameMiddle::~NameMiddle() = default;
@@ -63,7 +62,7 @@ void NameMiddle::GetAdditionalSupportedFieldTypes(
bool NameMiddle::ConvertAndGetTheValueForAdditionalFieldTypeName(
const std::string& type_name,
base::string16* value) const {
- if (type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
+ if (type_name == AutofillType::ServerFieldTypeToString(NAME_MIDDLE_INITIAL)) {
if (value) {
// If the stored value has the characteristics of containing only
// initials, use the value as it is. Otherwise, convert it to a
@@ -84,7 +83,7 @@ bool NameMiddle::ConvertAndSetValueForAdditionalFieldTypeName(
const std::string& type_name,
const base::string16& value,
const VerificationStatus& status) {
- if (type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
+ if (type_name == AutofillType::ServerFieldTypeToString(NAME_MIDDLE_INITIAL)) {
SetValue(value, status);
return true;
}
@@ -92,13 +91,12 @@ bool NameMiddle::ConvertAndSetValueForAdditionalFieldTypeName(
}
NameLastFirst::NameLastFirst(AddressComponent* parent)
- : AddressComponent(NAME_LAST_FIRST, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_LAST_FIRST, parent, MergeMode::kDefault) {}
NameLastFirst::~NameLastFirst() = default;
NameLastConjunction::NameLastConjunction(AddressComponent* parent)
- : AddressComponent(NAME_LAST_CONJUNCTION, parent, {}, MergeMode::kDefault) {
-}
+ : AddressComponent(NAME_LAST_CONJUNCTION, parent, MergeMode::kDefault) {}
NameLastConjunction::~NameLastConjunction() = default;
@@ -113,14 +111,13 @@ std::vector<const re2::RE2*> NameLast::GetParseRegularExpressionsByRelevance()
}
NameLastSecond::NameLastSecond(AddressComponent* parent)
- : AddressComponent(NAME_LAST_SECOND, parent, {}, MergeMode::kDefault) {}
+ : AddressComponent(NAME_LAST_SECOND, parent, MergeMode::kDefault) {}
NameLastSecond::~NameLastSecond() = default;
NameLast::NameLast(AddressComponent* parent)
: AddressComponent(NAME_LAST,
parent,
- {&first_, &conjunction_, &second_},
MergeMode::kDefault) {}
NameLast::~NameLast() = default;
@@ -137,16 +134,24 @@ NameFull::NameFull(AddressComponent* parent)
: AddressComponent(
NAME_FULL,
parent,
- {/*&name_honorific_,*/ &name_first_, &name_middle_, &name_last_},
MergeMode::kDefault) {}
NameFull::NameFull(const NameFull& other) : NameFull() {
// The purpose of the copy operator is to copy the values and verification
// statuses of all nodes in |other| to |this|. This exact functionality is
- // already implemented in the assignment operator.
- *this = other;
+ // already implemented as a recursive operation in the base class.
+ this->CopyFrom(other);
}
+NameHonorificPrefix::NameHonorificPrefix(AddressComponent* parent)
+ : AddressComponent(NAME_HONORIFIC_PREFIX,
+ parent,
+ MergeMode::kUseBetterOrNewerForSameValue |
+ MergeMode::kReplaceEmpty |
+ MergeMode::kUseBetterOrMostRecentIfDifferent) {}
+
+NameHonorificPrefix::~NameHonorificPrefix() = default;
+
void NameFull::MigrateLegacyStructure(bool is_verified_profile) {
// Only if the name was imported from a legacy structure, the component has no
if (GetVerificationStatus() != VerificationStatus::kNoStatus)
@@ -235,14 +240,52 @@ base::string16 NameFull::GetBestFormatString() const {
HasCjkNameCharacteristics(base::UTF16ToUTF8(name_last_.GetValue()))) {
return base::ASCIIToUTF16("${NAME_LAST}${NAME_FIRST}");
}
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
return
- // base::ASCIIToUTF16( "${NAME_HONORIFIC_PREFIX} ${NAME_FIRST}
- // ${NAME_MIDDLE} ${NAME_LAST}");
base::ASCIIToUTF16("${NAME_FIRST} ${NAME_MIDDLE} ${NAME_LAST}");
}
NameFull::~NameFull() = default;
+NameFullWithPrefix::NameFullWithPrefix() : NameFullWithPrefix(nullptr) {}
+
+NameFullWithPrefix::NameFullWithPrefix(AddressComponent* parent)
+ : AddressComponent(NAME_FULL_WITH_HONORIFIC_PREFIX,
+ parent,
+ MergeMode::kMergeChildrenAndReformatIfNeeded) {}
+
+NameFullWithPrefix::NameFullWithPrefix(const NameFullWithPrefix& other)
+ : NameFullWithPrefix() {
+ // The purpose of the copy operator is to copy the values and verification
+ // statuses of all nodes in |other| to |this|. This exact functionality is
+ // already implemented as a recursive operation in the base class.
+ this->CopyFrom(other);
+}
+
+NameFullWithPrefix::~NameFullWithPrefix() = default;
+
+std::vector<const re2::RE2*>
+NameFullWithPrefix::GetParseRegularExpressionsByRelevance() const {
+ auto* pattern_provider = StructuredAddressesRegExProvider::Instance();
+ return {pattern_provider->GetRegEx(RegEx::kParsePrefixedName)};
+}
+
+void NameFullWithPrefix::MigrateLegacyStructure(bool is_verified_profile) {
+ // If a verification status is set, the structure is already migrated.
+ if (GetVerificationStatus() != VerificationStatus::kNoStatus) {
+ return;
+ }
+
+ // If it is not migrated, continue with migrating the full name.
+ name_full_.MigrateLegacyStructure(is_verified_profile);
+
+ // Check if the tree is already in a completed state.
+ // If yes, build the root node from the subcomponents.
+ // Otherwise, this step is not necessary and will be taken care of in a later
+ // stage of the import process.
+ if (MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() > 1) {
+ FormatValueFromSubcomponents();
+ }
+}
+
} // namespace structured_address
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.h
index 67dd210ada0..db4e70137d6 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name.h
@@ -114,23 +114,22 @@ class NameLast : public AddressComponent {
// Compound that represents a full name. It contains a honorific, a first
// name, a middle name and a last name. The last name is a compound itself.
//
-// +----------+
-// | NAME_FULL|
-// +----------+
-// / | | \
-// / | | \
-// / | | \
-// / | | \
-// +------------+ +--------+ +---------+ +-------+
-// | _HONORIFIC | | _FIRST | | _MIDDLE | | _LAST |
-// +------------+ +--------+ +---------+ +-------+
-// / | \
-// / | \
+// +------------+
+// | NAME_FULL |
+// +------------+
+// / | \
+// / | \
+// / | \
+// +------------+ +-------------+ +-----------+
+// | NAME_FIRST | | NAME_MIDDLE | | NAME_LAST |
+// +------------+ +-------------+ +-----------+
+// / | \
// / | \
+// / | \
// / | \
-// +--------+ +-----------+ +---------+
-// | _FIRST | | _CONJUNC. | | _SECOND |
-// +--------+ +-----------+ +---------+
+// +--------+ +--------------+ +---------+
+// | _FIRST | | _CONJUNCTION | | _SECOND |
+// +--------+ +--------------+ +---------+
//
class NameFull : public AddressComponent {
public:
@@ -139,9 +138,7 @@ class NameFull : public AddressComponent {
NameFull(const NameFull& other);
~NameFull() override;
- // Migrates from a legacy structure in which name tokens are imported without
- // a status.
- void MigrateLegacyStructure(bool is_verified_profile);
+ void MigrateLegacyStructure(bool is_verified_profile) override;
protected:
std::vector<const re2::RE2*> GetParseRegularExpressionsByRelevance()
@@ -151,13 +148,61 @@ class NameFull : public AddressComponent {
base::string16 GetBestFormatString() const override;
private:
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // NameHonorific name_honorific_;
NameFirst name_first_{this};
NameMiddle name_middle_{this};
NameLast name_last_{this};
};
+// Atomic component that represents a honorific prefix.
+class NameHonorificPrefix : public AddressComponent {
+ public:
+ explicit NameHonorificPrefix(AddressComponent* parent);
+ ~NameHonorificPrefix() override;
+};
+
+// Compound that represent a full name and a honorific prefix.
+//
+// +-----------------------+
+// | NAME_FULL_WITH_PREFIX |
+// +-----------------------+
+// / \
+// / \
+// / \
+// / \
+// +-------------------+ +------------+
+// | HONORIFIC_PREFIX | | NAME_FULL |
+// +-------------------+ +------------+
+// / | \
+// / | \
+// / | \
+// +------------+ +-------------+ +-----------+
+// | NAME_FIRST | | NAME_MIDDLE | | NAME_LAST |
+// +------------+ +-------------+ +-----------+
+// / | \
+// / | \
+// / | \
+// / | \
+// +--------+ +--------------+ +---------+
+// | _FIRST | | _CONJUNCTION | | _SECOND |
+// +--------+ +--------------+ +---------+
+//
+class NameFullWithPrefix : public AddressComponent {
+ public:
+ NameFullWithPrefix();
+ explicit NameFullWithPrefix(AddressComponent* parent);
+ NameFullWithPrefix(const NameFullWithPrefix& other);
+ ~NameFullWithPrefix() override;
+
+ void MigrateLegacyStructure(bool is_verified_profile) override;
+
+ protected:
+ std::vector<const re2::RE2*> GetParseRegularExpressionsByRelevance()
+ const override;
+
+ NameHonorificPrefix honorific_prefix_{this};
+ NameFull name_full_{this};
+};
+
} // namespace structured_address
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
index ea5ba89c845..7be3e48495e 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
@@ -48,7 +48,7 @@ struct LastNameParserTestRecord {
// Function to test the parsing of a name from the full (unstructured)
// representation into its subcomponents.
-void TestNameParsing(const base::string16& full,
+void TestNameParsing(const base::string16& full_with_prefix,
const base::string16& honorific,
const base::string16& first,
const base::string16& middle,
@@ -56,15 +56,25 @@ void TestNameParsing(const base::string16& full,
const base::string16& last_first,
const base::string16& last_conjunction,
const base::string16& last_second) {
- SCOPED_TRACE(full);
- NameFull name;
- name.SetValueForTypeIfPossible(NAME_FULL, full,
+ SCOPED_TRACE(full_with_prefix);
+ NameFullWithPrefix name;
+ name.SetValueForTypeIfPossible(NAME_FULL_WITH_HONORIFIC_PREFIX,
+ full_with_prefix,
VerificationStatus::kObserved);
name.CompleteFullTree();
- EXPECT_EQ(name.GetValueForType(NAME_FULL), full);
+ EXPECT_EQ(name.GetValueForType(NAME_FULL_WITH_HONORIFIC_PREFIX),
+ full_with_prefix);
// TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(name.GetValueForType(NAME_HONORIFIC_PREFIX), honorific);
+ if (structured_address::HonorificPrefixEnabled()) {
+ EXPECT_EQ(name.GetValueForType(NAME_HONORIFIC_PREFIX), honorific);
+ }
+
+ SCOPED_TRACE(testing::Message()
+ << "first name: " << name.GetValueForType(NAME_FIRST) << "\n"
+ << "middle name: " << name.GetValueForType(NAME_MIDDLE) << "\n"
+ << "last name: " << name.GetValueForType(NAME_LAST));
+
EXPECT_EQ(name.GetValueForType(NAME_FIRST), first);
EXPECT_EQ(name.GetValueForType(NAME_MIDDLE), middle);
EXPECT_EQ(name.GetValueForType(NAME_LAST), last);
@@ -346,28 +356,39 @@ TEST(AutofillStructuredName, GetNameMiddleInitial) {
base::ASCIIToUTF16("G.-W."));
}
-TEST(AutofillStructuredName, TestGetSupportedTypes) {
+TEST(AutofillStructuredName, TestGetSupportedTypes_FullNameWithPrefix) {
+ NameFullWithPrefix full_name_with_prefix;
+ ServerFieldTypeSet supported_types;
+ full_name_with_prefix.GetSupportedTypes(&supported_types);
+ EXPECT_EQ(ServerFieldTypeSet({NAME_FULL_WITH_HONORIFIC_PREFIX, NAME_FULL,
+ NAME_HONORIFIC_PREFIX, NAME_FIRST, NAME_MIDDLE,
+ NAME_MIDDLE_INITIAL, NAME_LAST, NAME_LAST_FIRST,
+ NAME_LAST_CONJUNCTION, NAME_LAST_SECOND}),
+ supported_types);
+}
+
+TEST(AutofillStructuredName, TestGetSupportedTypes_FullName) {
NameFull full_name;
ServerFieldTypeSet supported_types;
full_name.GetSupportedTypes(&supported_types);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- EXPECT_EQ(ServerFieldTypeSet({NAME_FULL, /*NAME_HONORIFIC_PREFIX*/ NAME_FIRST,
- NAME_MIDDLE, NAME_MIDDLE_INITIAL, NAME_LAST,
- NAME_LAST_FIRST, NAME_LAST_CONJUNCTION,
- NAME_LAST_SECOND}),
+ EXPECT_EQ(ServerFieldTypeSet({NAME_FULL, NAME_FIRST, NAME_MIDDLE,
+ NAME_MIDDLE_INITIAL, NAME_LAST, NAME_LAST_FIRST,
+ NAME_LAST_CONJUNCTION, NAME_LAST_SECOND}),
supported_types);
}
TEST(AutofillStructuredName, TestSettingMiddleNameInitial) {
- NameFull full_name;
- EXPECT_EQ(full_name.GetValueForType(NAME_MIDDLE), base::string16());
+ NameFullWithPrefix full_name_with_prefix;
+ EXPECT_EQ(full_name_with_prefix.GetValueForType(NAME_MIDDLE),
+ base::string16());
- EXPECT_TRUE(full_name.SetValueForTypeIfPossible(
+ EXPECT_TRUE(full_name_with_prefix.SetValueForTypeIfPossible(
NAME_MIDDLE_INITIAL, base::UTF8ToUTF16("M"),
VerificationStatus::kObserved));
- EXPECT_EQ(full_name.GetValueForType(NAME_MIDDLE_INITIAL),
+ EXPECT_EQ(full_name_with_prefix.GetValueForType(NAME_MIDDLE_INITIAL),
+ base::UTF8ToUTF16("M"));
+ EXPECT_EQ(full_name_with_prefix.GetValueForType(NAME_MIDDLE),
base::UTF8ToUTF16("M"));
- EXPECT_EQ(full_name.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("M"));
}
TEST(AutofillStructuredName, MergePermutatedNames) {
@@ -415,126 +436,376 @@ TEST(AutofillStructuredName, MergePermutatedNames) {
VerificationStatus::kObserved);
}
-TEST(AutofillStructuredName, MergeNamesByCombiningSubstructureObservations) {
+TEST(AutofillStructuredName,
+ MergeNamesByCombiningSubstructureObservations_WithAdditionalPrefix) {
+ NameFullWithPrefix one;
+ NameFullWithPrefix two;
+
+ // The first name has an incorrect componentization of the last name, but a
+ // correctly observed structure of first, middle, last and a verified full
+ // name.
+ AddressComponentTestValues name_one_values = {
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kFormatted},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed}};
+
+ // The second name has a correct componentization of the last name, but an
+ // correctly parsed structure of first, middle, last and an additional
+ // title.
+ AddressComponentTestValues name_two_values = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "Mr",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_FIRST,
+ .value = "Pablo",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_MIDDLE,
+ .value = "Diego",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .status = VerificationStatus::kObserved},
+ };
+
+ AddressComponentTestValues merge_expectation = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "Mr",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .status = VerificationStatus::kObserved},
+ };
+
+ SetTestValues(&one, name_one_values);
+ SetTestValues(&two, name_two_values);
+
+ NameFullWithPrefix copy_of_one(one);
+ ASSERT_TRUE(one.IsMergeableWithComponent(two));
+ EXPECT_TRUE(one.MergeWithComponent(two));
+
+ VerifyTestValues(&one, merge_expectation);
+
+ // The merging should work in both directions equally.
+ EXPECT_TRUE(two.MergeWithComponent(copy_of_one));
+
+ VerifyTestValues(&two, merge_expectation);
+}
+
+// Tests that the root node of NameFullWithPrefix is correctly populated after a
+// migration from a NameFull structure.
+TEST(AutofillStructuredName, TestPopulationOfNameFullWithPrefix) {
+ NameFullWithPrefix name_full_with_prefix;
+
+ // The first name has an incorrect componentization of the last name, but a
+ // correctly observed structure of title, first, middle, last.
+ AddressComponentTestValues name_full_with_prefix_values = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed}};
+
+ SetTestValues(&name_full_with_prefix, name_full_with_prefix_values);
+
+ AddressComponentTestValues expectation = {
+ // Expect the honorific prefix to be derived from the full name.
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kFormatted},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed}};
+
+ name_full_with_prefix.MigrateLegacyStructure(true);
+ name_full_with_prefix.CompleteFullTree();
+
+ VerifyTestValues(&name_full_with_prefix, expectation);
+}
+
+TEST(AutofillStructuredName,
+ MergeNamesByCombiningSubstructureObservations_FullName) {
NameFull one;
NameFull two;
// The first name has an incorrect componentization of the last name, but a
+ // correctly observed structure of first, middle, last.
+ AddressComponentTestValues name_one_values = {
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed}};
+
+ // The second name has a correct componentization of the last name, but an
+ // incorrectly parsed structure of first, middle, last.
+ AddressComponentTestValues name_two_values = {
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_FIRST,
+ .value = "Pablo",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_MIDDLE,
+ .value = "Diego",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .status = VerificationStatus::kObserved},
+ };
+
+ AddressComponentTestValues merge_expectation = {
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .status = VerificationStatus::kObserved},
+ };
+
+ SetTestValues(&one, name_one_values);
+ SetTestValues(&two, name_two_values);
+
+ // By merging both, it is expected that the first, middle, last
+ // structure of |one| is maintained, while the substructure of the last name
+ // is taken from two.
+ NameFull copy_of_one(one);
+ EXPECT_TRUE(one.MergeWithComponent(two));
+
+ VerifyTestValues(&one, merge_expectation);
+
+ // The merging should work in both directions equally.
+ EXPECT_TRUE(two.MergeWithComponent(copy_of_one));
+
+ VerifyTestValues(&two, merge_expectation);
+}
+
+TEST(AutofillStructuredName,
+ MergeNamesByCombiningSubstructureObservations_FullNameWithPrefix) {
+ NameFullWithPrefix one;
+ NameFullWithPrefix two;
+
+ // The first name has an incorrect componentization of the last name, but a
// correctly observed structure of title, first, middle, last.
- one.SetValueForTypeIfPossible(
- NAME_FULL, base::ASCIIToUTF16("Mr Pablo Diego Ruiz y Picasso"),
- VerificationStatus::kUserVerified);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // one.SetValueForTypeIfPossible(NAME_HONORIFIC_PREFIX,
- // base::ASCIIToUTF16("Mr"),
- // VerificationStatus::kObserved);
- one.SetValueForTypeIfPossible(NAME_FIRST, base::ASCIIToUTF16("Pablo Diego"),
- VerificationStatus::kObserved);
- one.SetValueForTypeIfPossible(NAME_MIDDLE, base::ASCIIToUTF16(""),
- VerificationStatus::kObserved);
- one.SetValueForTypeIfPossible(NAME_LAST, base::ASCIIToUTF16("Ruiz y Picasso"),
- VerificationStatus::kObserved);
- one.SetValueForTypeIfPossible(NAME_LAST_SECOND,
- base::ASCIIToUTF16("Ruiz y Picasso"),
- VerificationStatus::kParsed);
+ AddressComponentTestValues name_one_values = {
+
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "Mr",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed}};
// The second name has a correct componentization of the last name, but an
- // incorrectly parsed structure of title,first,middle,last.
- two.SetValueForTypeIfPossible(
- NAME_FULL, base::ASCIIToUTF16("Mr Pablo Diego Ruiz y Picasso"),
- VerificationStatus::kUserVerified);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // two.SetValueForTypeIfPossible(NAME_HONORIFIC_PREFIX,
- // base::ASCIIToUTF16(""),
- // VerificationStatus::kParsed);
- two.SetValueForTypeIfPossible(NAME_FIRST, base::ASCIIToUTF16("Pablo"),
- VerificationStatus::kParsed);
- two.SetValueForTypeIfPossible(NAME_MIDDLE, base::ASCIIToUTF16("Diego"),
- VerificationStatus::kParsed);
- two.SetValueForTypeIfPossible(NAME_LAST, base::ASCIIToUTF16("Ruiz y Picasso"),
- VerificationStatus::kParsed);
- two.SetValueForTypeIfPossible(NAME_LAST_FIRST, base::ASCIIToUTF16("Ruiz"),
- VerificationStatus::kObserved);
- two.SetValueForTypeIfPossible(NAME_LAST_CONJUNCTION, base::ASCIIToUTF16("y"),
- VerificationStatus::kObserved);
- two.SetValueForTypeIfPossible(NAME_LAST_SECOND, base::ASCIIToUTF16("Picasso"),
- VerificationStatus::kObserved);
+ // incorrectly parsed structure of first, middle, last.
+ AddressComponentTestValues name_two_values = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "Mr",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_FIRST,
+ .value = "Pablo",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_MIDDLE,
+ .value = "Diego",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .status = VerificationStatus::kObserved},
+ };
+
+ AddressComponentTestValues merge_expectation = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FULL,
+ .value = "Pablo Diego Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "Mr",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .status = VerificationStatus::kObserved},
+ };
+
+ SetTestValues(&one, name_one_values);
+ SetTestValues(&two, name_two_values);
// By merging both, it is expected that the title, first, middle, last
// structure of |one| is maintained, while the substructure of the last name
// is taken from two.
- NameFull copy_of_one;
- copy_of_one = one;
+ NameFullWithPrefix copy_of_one(one);
EXPECT_TRUE(one.MergeWithComponent(two));
- EXPECT_EQ(one.GetValueForType(NAME_FULL),
- base::ASCIIToUTF16("Mr Pablo Diego Ruiz y Picasso"));
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(one.GetValueForType(NAME_HONORIFIC_PREFIX),
- // base::ASCIIToUTF16("Mr"));
- EXPECT_EQ(one.GetValueForType(NAME_FIRST), base::ASCIIToUTF16("Pablo Diego"));
- EXPECT_EQ(one.GetValueForType(NAME_MIDDLE), base::ASCIIToUTF16(""));
- EXPECT_EQ(one.GetValueForType(NAME_LAST),
- base::ASCIIToUTF16("Ruiz y Picasso"));
- EXPECT_EQ(one.GetValueForType(NAME_LAST_FIRST), base::ASCIIToUTF16("Ruiz"));
- EXPECT_EQ(one.GetValueForType(NAME_LAST_CONJUNCTION),
- base::ASCIIToUTF16("y"));
- EXPECT_EQ(one.GetValueForType(NAME_LAST_SECOND),
- base::ASCIIToUTF16("Picasso"));
-
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_FULL),
- VerificationStatus::kUserVerified);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(one.GetVerificationStatusForType(NAME_HONORIFIC_PREFIX),
- // VerificationStatus::kObserved);
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_FIRST),
- VerificationStatus::kObserved);
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_MIDDLE),
- VerificationStatus::kObserved);
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_LAST),
- VerificationStatus::kObserved);
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_LAST_FIRST),
- VerificationStatus::kObserved);
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_LAST_CONJUNCTION),
- VerificationStatus::kObserved);
- EXPECT_EQ(one.GetVerificationStatusForType(NAME_LAST_SECOND),
- VerificationStatus::kObserved);
+ VerifyTestValues(&one, merge_expectation);
// The merging should work in both directions equally.
EXPECT_TRUE(two.MergeWithComponent(copy_of_one));
- EXPECT_EQ(two.GetValueForType(NAME_FULL),
- base::ASCIIToUTF16("Mr Pablo Diego Ruiz y Picasso"));
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(two.GetValueForType(NAME_HONORIFIC_PREFIX),
- // base::ASCIIToUTF16("Mr"));
- EXPECT_EQ(two.GetValueForType(NAME_FIRST), base::ASCIIToUTF16("Pablo Diego"));
- EXPECT_EQ(two.GetValueForType(NAME_MIDDLE), base::ASCIIToUTF16(""));
- EXPECT_EQ(two.GetValueForType(NAME_LAST),
- base::ASCIIToUTF16("Ruiz y Picasso"));
- EXPECT_EQ(two.GetValueForType(NAME_LAST_FIRST), base::ASCIIToUTF16("Ruiz"));
- EXPECT_EQ(two.GetValueForType(NAME_LAST_CONJUNCTION),
- base::ASCIIToUTF16("y"));
- EXPECT_EQ(two.GetValueForType(NAME_LAST_SECOND),
- base::ASCIIToUTF16("Picasso"));
-
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_FULL),
- VerificationStatus::kUserVerified);
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(two.GetVerificationStatusForType(NAME_HONORIFIC_PREFIX),
- // VerificationStatus::kObserved);
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_FIRST),
- VerificationStatus::kObserved);
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_MIDDLE),
- VerificationStatus::kObserved);
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_LAST),
- VerificationStatus::kObserved);
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_LAST_FIRST),
- VerificationStatus::kObserved);
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_LAST_CONJUNCTION),
- VerificationStatus::kObserved);
- EXPECT_EQ(two.GetVerificationStatusForType(NAME_LAST_SECOND),
- VerificationStatus::kObserved);
+ VerifyTestValues(&two, merge_expectation);
}
TEST(AutofillStructuredName, TestCopyConstructuror) {
@@ -560,7 +831,7 @@ TEST(AutofillStructuredName, TestCopyConstructuror) {
VerificationStatus::kParsed);
NameFull copy = orginal;
- EXPECT_EQ(orginal, copy);
+ EXPECT_TRUE(orginal.SameAs(copy));
}
TEST(AutofillStructuredName,
@@ -731,13 +1002,83 @@ TEST(AutofillStructuredName, MergeSubsetLastname) {
VerifyTestValues(&name, name_values);
}
-TEST(AutofillStructuredName, MergeSubsetLastname2) {
+TEST(AutofillStructuredName, MergeSubsetLastname_WithNonSpaceSeparators) {
NameFull name;
NameFull subset_name;
name.SetMergeModeForTesting(kRecursivelyMergeSingleTokenSubset |
kRecursivelyMergeTokenEquivalentValues);
AddressComponentTestValues name_values = {
+ {.type = NAME_FULL,
+ .value = "Thomas-Neo-Anderson",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FIRST,
+ .value = "Thomas",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "Thomas",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Anderson",
+ .status = VerificationStatus::kObserved},
+ };
+
+ AddressComponentTestValues subset_name_values = {
+ {.type = NAME_FULL,
+ .value = "Thomas-Anderson",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_FIRST,
+ .value = "Thomas",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Anderson",
+ .status = VerificationStatus::kObserved},
+ };
+
+ AddressComponentTestValues expectation = {
+ {.type = NAME_FULL,
+ .value = "Thomas-Neo-Anderson",
+ .status = VerificationStatus::kUserVerified},
+ {.type = NAME_FIRST,
+ .value = "Thomas",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_MIDDLE,
+ .value = "Thomas",
+ .status = VerificationStatus::kObserved},
+ {.type = NAME_LAST,
+ .value = "Anderson",
+ .status = VerificationStatus::kObserved},
+ };
+
+ SetTestValues(&name, name_values);
+ SetTestValues(&subset_name, subset_name_values);
+
+ // After normalization, the two names should have a single-token-superset
+ // relation.
+ SortedTokenComparisonResult token_comparison_result =
+ CompareSortedTokens(name.ValueForComparisonForTesting(),
+ subset_name.ValueForComparisonForTesting());
+ EXPECT_TRUE(token_comparison_result.IsSingleTokenSuperset());
+
+ // Without normalization, the two names should be considered distinct.
+ token_comparison_result =
+ CompareSortedTokens(name.GetValue(), subset_name.GetValue());
+ EXPECT_TRUE(token_comparison_result.status == DISTINCT);
+
+ // Verify that those two names are not considered mergeable.
+ EXPECT_FALSE(name.IsMergeableWithComponent(subset_name));
+ EXPECT_FALSE(name.MergeWithComponent(subset_name));
+
+ VerifyTestValues(&name, expectation);
+}
+
+TEST(AutofillStructuredName, MergeSubsetLastname2) {
+ NameFullWithPrefix name;
+ NameFullWithPrefix subset_name;
+ name.SetMergeModeForTesting(kRecursivelyMergeSingleTokenSubset |
+ kRecursivelyMergeTokenEquivalentValues);
+
+ AddressComponentTestValues name_values = {
{.type = NAME_FIRST,
.value = "Thomas",
.status = VerificationStatus::kObserved},
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
index ba400f32f08..82aab62d170 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
@@ -160,12 +160,16 @@ const char kOptionalLastNamePrefixRe[] =
// Regular expression to match the affixes that indicate the floor an
// apartment is located in.
const char kFloorAffixRe[] =
- "((°|º|\\.|\\s)*"
- "(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar)"
+ "((°|º|\\.|\\s|-)*"
+ "(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)"
"(\\.|\\s|-)*)";
+// Prefix that indicates an apartment number.
const char kApartmentNumberPrefix[] =
- "((apt|apartment|wohnung|apto)(\\.|\\s|-)*)";
+ "((apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)";
+
+// Suffix that inficates an apartment number.
+const char kApartmentNumberSuffix[] = "(\\.|\\s|-)*(ª)";
// Regular expression to match the prefixes that indicate a house number.
const char kHouseNumberOptionalPrefixRe[] = "(((no|°|º|number)(\\.|-|\\s)*)?)";
@@ -257,8 +261,8 @@ std::string ParseOnlyLastNameExpression() {
// Returns an expression to parse a name that consists of a first, middle and
// last name with an optional honorific prefix. The full name is parsed into
-// |NAME_FULL|. The name can start with an honorific prefix that is parsed
-// into |NAME_HONORIFIC_PREFIX|. The last token is parsed into |NAME_LAST|.
+// |NAME_FULL|. The name can start with an honorific prefix that is ignored.
+// The last token is parsed into |NAME_LAST|.
// This token may be preceded by a last name prefix like "Mac" or
// "von" that is included in |NAME_LAST|. If the strings contains any
// remaining tokens, the first token is parsed into
@@ -266,8 +270,8 @@ std::string ParseOnlyLastNameExpression() {
std::string ParseFirstMiddleLastNameExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
- {CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ {NoCapturePattern(kHonorificPrefixRe,
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_FIRST, kSingleWordRe,
CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(
@@ -281,15 +285,15 @@ std::string ParseFirstMiddleLastNameExpression() {
// Returns an expression to parse a name that starts with the last name,
// followed by a comma, and than the first and middle names.
// The full name is parsed into |NAME_FULL|. The name can start with an optional
-// honorific prefix that is parsed into |HONORIFIC_PREFIX|, follow by a single
+// honorific prefix that is ignored, followed by a single
// token that is parsed into |LAST_NAME|. The |LAST_NAME| must be preceded by a
// comma with optional spaces. The next token is parsed into |NAME_FIRST| and
// all remaining tokens are parsed into |NAME_MIDDLE|.
std::string ParseLastCommaFirstMiddleExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
- {CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ {NoCapturePattern(kHonorificPrefixRe,
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST,
{kOptionalLastNamePrefixRe, kSingleWordRe},
{.separator = "\\s*,\\s*"}),
@@ -321,13 +325,13 @@ std::string ParseHispanicLastNameExpression() {
}
// Returns an expression to parse a full Hispanic/Latinx name that
-// contains an optional honorific prefix, a first name, and a last name as
-// specified by |ParseHispanicLastNameExpression()|.
+// contains an optional honorific prefix which is ignored, a first name, and a
+// last name as specified by |ParseHispanicLastNameExpression()|.
std::string ParseHispanicFullNameExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
- {CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ {NoCapturePattern(kHonorificPrefixRe,
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(
NAME_FIRST, kMultipleLazyWordsRe,
CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL}),
@@ -354,19 +358,50 @@ std::string ParseStreetNameHouseNumberExpression() {
{CaptureTypeWithPattern(ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
CaptureTypeWithPattern(ADDRESS_HOME_STREET_NAME,
kMultipleLazyWordsRe),
- {.separator = ""}),
- CaptureTypeWithPrefixedPattern(ADDRESS_HOME_HOUSE_NUMBER,
- kHouseNumberOptionalPrefixRe,
- "(?:\\d+\\w?)"),
+ CaptureOptions{.separator = ""}),
+ CaptureTypeWithAffixedPattern(ADDRESS_HOME_HOUSE_NUMBER,
+ kHouseNumberOptionalPrefixRe,
+ "(?:\\d+\\w?)", "(th\\.|\\.)?"),
CaptureTypeWithPattern(
ADDRESS_HOME_SUBPREMISE,
{
CaptureTypeWithPrefixedPattern(
- ADDRESS_HOME_FLOOR, kFloorAffixRe, "(?:(\\d{0,3}\\w?))",
+ ADDRESS_HOME_FLOOR, kFloorAffixRe, "(?:(\\d{1,3}\\w?|\\w))",
CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))",
+ "(?:(\\d{1,3}\\w?|\\w))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ },
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
+}
+
+// Returns an expression to parse a street address into the street name, the
+// house number and the subpremise. The latter is parsed into the floor and
+// apartment number. The expression is applicable, if the street name comes
+// before the house number, followed by the floor and the apartment.
+// Both the floor and the apartment must be indicated by a suffix.
+// Example: Calla 1, 2º, 3ª
+// Where 2 is the floor and 3 the apartment number.
+std::string ParseStreetNameHouseNumberSuffixedFloorAndAppartmentExpression() {
+ return CaptureTypeWithPattern(
+ ADDRESS_HOME_STREET_ADDRESS,
+ {CaptureTypeWithPattern(ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
+ CaptureTypeWithPattern(ADDRESS_HOME_STREET_NAME,
+ kMultipleLazyWordsRe),
+ CaptureOptions{.separator = ""}),
+ CaptureTypeWithAffixedPattern(ADDRESS_HOME_HOUSE_NUMBER,
+ kHouseNumberOptionalPrefixRe,
+ "(?:\\d+\\w?)", "(th\\.|\\.)?"),
+ CaptureTypeWithPattern(
+ ADDRESS_HOME_SUBPREMISE,
+ {
+ CaptureTypeWithSuffixedPattern(
+ ADDRESS_HOME_FLOOR, "(?:(\\d{1,3}\\w?|\\w))", kFloorAffixRe,
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithAffixedPattern(
+ ADDRESS_HOME_APT_NUM, "(-\\s*)?", "(?:(\\d{1,3}\\w?|\\w))",
+ kApartmentNumberSuffix,
CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
CaptureOptions{.quantifier = MATCH_OPTIONAL})});
@@ -388,9 +423,9 @@ std::string ParseStreetNameHouseNumberExpressionSuffixedFloor() {
CaptureTypeWithPattern(ADDRESS_HOME_STREET_NAME,
kMultipleLazyWordsRe),
{.separator = ""}),
- CaptureTypeWithPrefixedPattern(ADDRESS_HOME_HOUSE_NUMBER,
- kHouseNumberOptionalPrefixRe,
- "(?:\\d+\\w?)"),
+ CaptureTypeWithAffixedPattern(ADDRESS_HOME_HOUSE_NUMBER,
+ kHouseNumberOptionalPrefixRe,
+ "(?:\\d+\\w?)", "(th\\.|\\.)?"),
CaptureTypeWithPattern(
ADDRESS_HOME_SUBPREMISE,
{
@@ -414,7 +449,9 @@ std::string ParseStreetNameHouseNumberExpressionSuffixedFloor() {
std::string ParseHouseNumberStreetNameExpression() {
return CaptureTypeWithPattern(
ADDRESS_HOME_STREET_ADDRESS,
- {CaptureTypeWithPattern(ADDRESS_HOME_HOUSE_NUMBER, "(?:\\d+\\w{0,3})"),
+ {CaptureTypeWithAffixedPattern(ADDRESS_HOME_HOUSE_NUMBER,
+ kHouseNumberOptionalPrefixRe,
+ "(?:\\d+\\w?)", "(th\\.|\\.)?"),
CaptureTypeWithPattern(ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
CaptureTypeWithPattern(ADDRESS_HOME_STREET_NAME,
kMultipleLazyWordsRe),
@@ -433,6 +470,17 @@ std::string ParseHouseNumberStreetNameExpression() {
CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
+// Returns a regular expression to parse a name with a honorific into the prefix
+// and the full name.
+std::string ParsePrefixedName() {
+ return CaptureTypeWithPattern(
+ NAME_FULL_WITH_HONORIFIC_PREFIX,
+ {CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(NAME_FULL, ".+",
+ CaptureOptions{.quantifier = MATCH_REQUIRED})});
+}
+
} // namespace
StructuredAddressesRegExProvider::StructuredAddressesRegExProvider() = default;
@@ -481,8 +529,12 @@ std::string StructuredAddressesRegExProvider::GetPattern(
return ParseHouseNumberStreetNameExpression();
case RegEx::kParseStreetNameHouseNumberSuffixedFloor:
return ParseStreetNameHouseNumberExpressionSuffixedFloor();
+ case RegEx::kParseStreetNameHouseNumberSuffixedFloorAndAppartmentRe:
+ return ParseStreetNameHouseNumberSuffixedFloorAndAppartmentExpression();
case RegEx::kParseStreetNameHouseNumber:
return ParseStreetNameHouseNumberExpression();
+ case RegEx::kParsePrefixedName:
+ return ParsePrefixedName();
}
NOTREACHED();
}
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h
index ce94af3c5ff..a983be897af 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h
@@ -36,7 +36,9 @@ enum class RegEx {
kMatchMiddleNameInitialsCharacteristics,
kParseStreetNameHouseNumber,
kParseStreetNameHouseNumberSuffixedFloor,
+ kParseStreetNameHouseNumberSuffixedFloorAndAppartmentRe,
kParseHouseNumberStreetName,
+ kParsePrefixedName,
kLastRegEx = kParseLastNameIntoSecondLastName,
};
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_test_utils.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_test_utils.cc
index a2aa93e787d..3d8f0a1b848 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_test_utils.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_test_utils.cc
@@ -66,8 +66,8 @@ void VerifyTestValues(AddressComponent* component,
AutofillType(test_value.type).ToString().c_str(),
test_value.value.c_str(), static_cast<int>(test_value.status)));
- EXPECT_EQ(component->GetValueForType(test_value.type),
- base::UTF8ToUTF16(test_value.value));
+ EXPECT_EQ(base::UTF16ToUTF8(component->GetValueForType(test_value.type)),
+ test_value.value);
// Omit testing the status if the value is empty.
if (!test_value.value.empty()) {
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
index c00710a40d4..4b1a2f33a66 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
@@ -168,7 +168,40 @@ TEST(AutofillStructuredAddress, ParseStreetAddress) {
.street_name = "Av. Paulista",
.house_number = "1098",
.floor = "1",
- .apartment = "101"}};
+ .apartment = "101"},
+ // Examples for Mexico.
+ {.street_address = "Street Name 12 - Piso 13 - 14",
+ .street_name = "Street Name",
+ .house_number = "12",
+ .floor = "13",
+ .apartment = "14"},
+ {.street_address = "Street Name 12 - 14",
+ .street_name = "Street Name",
+ .house_number = "12",
+ .floor = "",
+ .apartment = "14"},
+ {.street_address = "Street Name 12 - Piso 13",
+ .street_name = "Street Name",
+ .house_number = "12",
+ .floor = "13",
+ .apartment = ""},
+ // Examples for Spain.
+ {.street_address = "Street Name 1, 2º, 3ª",
+ .street_name = "Street Name",
+ .house_number = "1",
+ .floor = "2",
+ .apartment = "3"},
+ {.street_address = "Street Name 1, 2º",
+ .street_name = "Street Name",
+ .house_number = "1",
+ .floor = "2",
+ .apartment = ""},
+ {.street_address = "Street Name 1, 3ª",
+ .street_name = "Street Name",
+ .house_number = "1",
+ .floor = "",
+ .apartment = "3"},
+ };
for (const auto& test_case : test_cases)
TestAddressLineParsing(test_case);
@@ -228,7 +261,46 @@ TEST(AutofillStructuredAddress, TestStreetAddressFormatting) {
.street_name = "Amphitheatre Parkway",
.house_number = "1600",
.floor = "6",
- .apartment = "12"}};
+ .apartment = "12"},
+ // Examples for Mexico.
+ {.country_code = "MX",
+ .street_address = "StreetName 12 - Piso 13 - 14",
+ .street_name = "StreetName",
+ .house_number = "12",
+ .floor = "13",
+ .apartment = "14"},
+ {.country_code = "MX",
+ .street_address = "StreetName 12 - 14",
+ .street_name = "StreetName",
+ .house_number = "12",
+ .floor = "",
+ .apartment = "14"},
+ {.country_code = "MX",
+ .street_address = "StreetName 12 - Piso 13",
+ .street_name = "StreetName",
+ .house_number = "12",
+ .floor = "13",
+ .apartment = ""},
+ // Examples for Spain.
+ {.country_code = "ES",
+ .street_address = "Street Name 1, 3ª",
+ .street_name = "Street Name",
+ .house_number = "1",
+ .floor = "",
+ .apartment = "3"},
+ {.country_code = "ES",
+ .street_address = "Street Name 1, 2º",
+ .street_name = "Street Name",
+ .house_number = "1",
+ .floor = "2",
+ .apartment = ""},
+ {.country_code = "ES",
+ .street_address = "Street Name 1, 2º, 3ª",
+ .street_name = "Street Name",
+ .house_number = "1",
+ .floor = "2",
+ .apartment = "3"},
+ };
for (const auto& test_case : test_cases)
TestAddressLineFormatting(test_case);
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc
index 62bf64b2722..0dc7769247a 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc
@@ -55,6 +55,10 @@ bool SortedTokenComparisonResult::ContainEachOther() const {
return status != DISTINCT;
}
+bool SortedTokenComparisonResult::TokensMatch() const {
+ return status == MATCH;
+}
+
bool StructuredNamesEnabled() {
return base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames);
@@ -65,6 +69,13 @@ bool StructuredAddressesEnabled() {
features::kAutofillEnableSupportForMoreStructureInAddresses);
}
+bool HonorificPrefixEnabled() {
+ return base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForHonorificPrefixes) &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInNames);
+}
+
Re2RegExCache::Re2RegExCache() = default;
// static
@@ -269,6 +280,29 @@ std::string CaptureTypeWithPattern(
options);
}
+std::string NoCapturePattern(const std::string& pattern,
+ const CaptureOptions& options) {
+ std::string quantifier;
+ switch (options.quantifier) {
+ // Makes the match optional.
+ case MATCH_OPTIONAL:
+ quantifier = "?";
+ break;
+ // Makes the match lazy meaning that it is avoided if possible.
+ case MATCH_LAZY_OPTIONAL:
+ quantifier = "??";
+ break;
+ // Makes the match required.
+ case MATCH_REQUIRED:
+ quantifier = "";
+ }
+
+ // By adding an "i" in the first group, the capturing is case insensitive.
+ // Allow multiple separators to support the ", " case.
+ return base::StrCat(
+ {"(?i:", pattern, "(?:", options.separator, ")+)", quantifier});
+}
+
std::string CaptureTypeWithAffixedPattern(const ServerFieldType& type,
const std::string& prefix,
const std::string& pattern,
@@ -291,9 +325,9 @@ std::string CaptureTypeWithAffixedPattern(const ServerFieldType& type,
// By adding an "i" in the first group, the capturing is case insensitive.
// Allow multiple separators to support the ", " case.
- return base::StrCat({"(?i:", prefix, "(?P<", AutofillType(type).ToString(),
- ">", pattern, ")", suffix, "(?:", options.separator,
- ")+)", quantifier});
+ return base::StrCat(
+ {"(?i:", prefix, "(?P<", AutofillType::ServerFieldTypeToString(type), ">",
+ pattern, ")", suffix, "(?:", options.separator, ")+)", quantifier});
}
std::string CaptureTypeWithSuffixedPattern(const ServerFieldType& type,
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.h
index 7098f754ae3..f01c89aa50c 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.h
@@ -77,6 +77,8 @@ struct SortedTokenComparisonResult {
bool OneIsSubset() const;
// Returns true if one contains the other.
bool ContainEachOther() const;
+ // Returns true if both contain the same tokens.
+ bool TokensMatch() const;
};
// Options for capturing a named group using the
@@ -97,6 +99,9 @@ bool StructuredNamesEnabled();
// Returns true if the structured address feature is enabled.
bool StructuredAddressesEnabled();
+// Returns true if honorific prefixes are enabled.
+bool HonorificPrefixEnabled();
+
// A cache for compiled RE2 regular expressions.
class Re2RegExCache {
public:
@@ -240,6 +245,11 @@ std::string CaptureTypeWithPattern(
const ServerFieldType& type,
std::initializer_list<base::StringPiece> pattern_span_initializer_list);
+// A pattern that is used to capture tokens that are not supposed to be
+// associated into a type.
+std::string NoCapturePattern(const std::string& pattern,
+ const CaptureOptions& options = CaptureOptions());
+
// Returns a capture group named by the string representation of |type| that
// matches |pattern| with an additional uncaptured |prefix_pattern| and
// |suffix_pattern|.
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils_unittest.cc
index d93c0bb9c63..01fd13bc3ad 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils_unittest.cc
@@ -217,6 +217,17 @@ TEST(AutofillStructuredAddressUtils, CaptureTypeWithPattern) {
CaptureTypeWithPattern(NAME_FULL, "abs\\w", {.separator = "_"}));
}
+TEST(AutofillStructuredAddressUtils, NoCaptureTypeWithPattern) {
+ EXPECT_EQ("(?i:abs\\w(?:,|\\s+|$)+)?",
+ NoCapturePattern("abs\\w", {.quantifier = MATCH_OPTIONAL}));
+ EXPECT_EQ("(?i:abs\\w(?:,|\\s+|$)+)", NoCapturePattern("abs\\w"));
+ EXPECT_EQ("(?i:abs\\w(?:,|\\s+|$)+)??",
+ NoCapturePattern("abs\\w", {.quantifier = MATCH_LAZY_OPTIONAL}));
+ EXPECT_EQ("(?i:abs\\w(?:,|\\s+|$)+)", NoCapturePattern("abs\\w"));
+ EXPECT_EQ("(?i:abs\\w(?:_)+)",
+ NoCapturePattern("abs\\w", {.separator = "_"}));
+}
+
TEST(AutofillStructuredAddressUtils, TokenizeValue) {
std::vector<AddressToken> expected_tokens = {
{base::ASCIIToUTF16("AnD"), base::ASCIIToUTF16("and"), 1},
diff --git a/chromium/components/autofill/core/browser/data_model/contact_info.cc b/chromium/components/autofill/core/browser/data_model/contact_info.cc
index bd31bdcaa3a..a42f4a78f59 100644
--- a/chromium/components/autofill/core/browser/data_model/contact_info.cc
+++ b/chromium/components/autofill/core/browser/data_model/contact_info.cc
@@ -23,21 +23,23 @@
namespace autofill {
-using structured_address::VerificationStatus;
-
namespace {
-// TODO(crbug.com/1103421): Clean legacy implementation once structured names
-// are fully launched.
-bool StructuredAddressesEnabled() {
- return base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames);
+// Factory for the structured tree to be used in NameInfo.
+std::unique_ptr<AddressComponent> CreateStructuredNameTree() {
+ if (structured_address::HonorificPrefixEnabled()) {
+ return std::make_unique<structured_address::NameFullWithPrefix>();
+ }
+ return std::make_unique<structured_address::NameFull>();
}
+
} // namespace
-NameInfo::NameInfo() = default;
+using structured_address::VerificationStatus;
+
+NameInfo::NameInfo() : name_(CreateStructuredNameTree()) {}
-NameInfo::NameInfo(const NameInfo& info) {
+NameInfo::NameInfo(const NameInfo& info) : NameInfo() {
*this = info;
}
@@ -49,8 +51,8 @@ NameInfo& NameInfo::operator=(const NameInfo& info) {
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (StructuredAddressesEnabled()) {
- name_ = info.name_;
+ if (structured_address::StructuredNamesEnabled()) {
+ name_->CopyFrom(*info.name_);
} else {
given_ = info.given_;
middle_ = info.middle_;
@@ -61,24 +63,24 @@ NameInfo& NameInfo::operator=(const NameInfo& info) {
}
bool NameInfo::MergeStructuredName(const NameInfo& newer) {
- return name_.MergeWithComponent(newer.GetStructuredName());
+ return name_->MergeWithComponent(newer.GetStructuredName());
}
void NameInfo::MergeStructuredNameValidationStatuses(const NameInfo& newer) {
- name_.MergeVerificationStatuses(newer.GetStructuredName());
+ name_->MergeVerificationStatuses(newer.GetStructuredName());
}
bool NameInfo::IsStructuredNameMergeable(const NameInfo& newer) const {
- if (!StructuredAddressesEnabled())
+ if (!structured_address::StructuredNamesEnabled())
NOTREACHED();
- return name_.IsMergeableWithComponent(newer.GetStructuredName());
+ return name_->IsMergeableWithComponent(newer.GetStructuredName());
}
bool NameInfo::FinalizeAfterImport(bool profile_is_verified) {
- if (StructuredAddressesEnabled()) {
- name_.MigrateLegacyStructure(profile_is_verified);
- return name_.CompleteFullTree();
+ if (structured_address::StructuredNamesEnabled()) {
+ name_->MigrateLegacyStructure(profile_is_verified);
+ return name_->CompleteFullTree();
}
return true;
}
@@ -89,23 +91,27 @@ bool NameInfo::operator==(const NameInfo& other) const {
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (StructuredAddressesEnabled())
- return name_ == other.name_;
+ if (structured_address::StructuredNamesEnabled())
+ return name_->SameAs(*other.name_);
return given_ == other.given_ && middle_ == other.middle_ &&
family_ == other.family_ && full_ == other.full_;
}
base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
- DCHECK_EQ(NAME, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kName, AutofillType(type).group());
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (StructuredAddressesEnabled()) {
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- if (type == NAME_HONORIFIC_PREFIX)
+ if (structured_address::StructuredNamesEnabled()) {
+ // Without the second generation of the structured name tree, honorific
+ // prefixes and the name including the prefix are unsupported types.
+ if ((type == NAME_HONORIFIC_PREFIX ||
+ type == NAME_FULL_WITH_HONORIFIC_PREFIX) &&
+ !structured_address::HonorificPrefixEnabled()) {
return base::string16();
- return name_.GetValueForType(type);
+ }
+ return name_->GetValueForType(type);
}
switch (type) {
case NAME_FIRST:
@@ -131,15 +137,19 @@ base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
void NameInfo::SetRawInfoWithVerificationStatus(ServerFieldType type,
const base::string16& value,
VerificationStatus status) {
- DCHECK_EQ(NAME, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kName, AutofillType(type).group());
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (StructuredAddressesEnabled()) {
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- if (type == NAME_HONORIFIC_PREFIX)
+ if (structured_address::StructuredNamesEnabled()) {
+ // Without the second generation of the structured name tree, honorific
+ // prefixes and the name including the prefix are unsupported types.
+ if ((type == NAME_HONORIFIC_PREFIX ||
+ type == NAME_FULL_WITH_HONORIFIC_PREFIX) &&
+ !structured_address::HonorificPrefixEnabled()) {
return;
- bool success = name_.SetValueForTypeIfPossible(type, value, status);
- DCHECK(success);
+ }
+ bool success = name_->SetValueForTypeIfPossible(type, value, status);
+ DCHECK(success) << AutofillType::ServerFieldTypeToString(type);
return;
}
switch (type) {
@@ -164,6 +174,7 @@ void NameInfo::SetRawInfoWithVerificationStatus(ServerFieldType type,
case NAME_LAST_SECOND:
case NAME_LAST_CONJUNCTION:
case NAME_HONORIFIC_PREFIX:
+ case NAME_FULL_WITH_HONORIFIC_PREFIX:
break;
default:
@@ -174,8 +185,8 @@ void NameInfo::SetRawInfoWithVerificationStatus(ServerFieldType type,
void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (StructuredAddressesEnabled()) {
- name_.GetSupportedTypes(supported_types);
+ if (structured_address::StructuredNamesEnabled()) {
+ name_->GetSupportedTypes(supported_types);
} else {
supported_types->insert(NAME_FIRST);
supported_types->insert(NAME_MIDDLE);
@@ -189,7 +200,7 @@ base::string16 NameInfo::GetInfoImpl(const AutofillType& type,
const std::string& app_locale) const {
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (!StructuredAddressesEnabled()) {
+ if (!structured_address::StructuredNamesEnabled()) {
if (type.GetStorableType() == NAME_FULL)
return FullName();
}
@@ -202,14 +213,14 @@ bool NameInfo::SetInfoWithVerificationStatusImpl(const AutofillType& type,
VerificationStatus status) {
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched.
- if (StructuredAddressesEnabled()) {
+ if (structured_address::StructuredNamesEnabled()) {
if (type.GetStorableType() == NAME_FULL) {
// If the set string is token equivalent to the old one, the value can
// just be updated, otherwise create a new name record and complete it in
// the end.
bool token_equivalent = structured_address::AreStringTokenEquivalent(
- value, name_.GetValueForType(NAME_FULL));
- name_.SetValueForTypeIfPossible(
+ value, name_->GetValueForType(NAME_FULL));
+ name_->SetValueForTypeIfPossible(
type.GetStorableType(), value, status,
/*invalidate_child_nodes=*/!token_equivalent);
return true;
@@ -229,19 +240,38 @@ bool NameInfo::SetInfoWithVerificationStatusImpl(const AutofillType& type,
status);
}
+void NameInfo::GetMatchingTypes(const base::string16& text,
+ const std::string& app_locale,
+ ServerFieldTypeSet* matching_types) const {
+ FormGroup::GetMatchingTypes(text, app_locale, matching_types);
+ // Replace type matches for |NAME_FULL_WITH_HONORIFIC_PREFIX| with |NAME_FULL|
+ // to always vote for a full name field even if the user decides to add an
+ // additional honorific prefix to their name.
+ if (matching_types->contains(NAME_FULL_WITH_HONORIFIC_PREFIX)) {
+ matching_types->erase(NAME_FULL_WITH_HONORIFIC_PREFIX);
+ matching_types->insert(NAME_FULL);
+ }
+}
+
VerificationStatus NameInfo::GetVerificationStatusImpl(
ServerFieldType type) const {
// TODO(crbug.com/1103421): Clean legacy implementation once structured
// names are fully launched.
- if (StructuredAddressesEnabled())
- return name_.GetVerificationStatusForType(type);
+ // Without the second generation of the structured name tree, honorific
+ // prefixes and the name including the prefix are unsupported types.
+ if (structured_address::StructuredNamesEnabled() &&
+ !((type == NAME_HONORIFIC_PREFIX ||
+ type == NAME_FULL_WITH_HONORIFIC_PREFIX) &&
+ !structured_address::HonorificPrefixEnabled())) {
+ return name_->GetVerificationStatusForType(type);
+ }
return VerificationStatus::kNoStatus;
}
base::string16 NameInfo::FullName() const {
// TODO(crbug.com/1103421): Clean legacy implementation once structured
// names are fully launched.
- if (StructuredAddressesEnabled())
+ if (structured_address::StructuredNamesEnabled())
NOTREACHED();
if (!full_.empty())
return full_;
@@ -252,7 +282,7 @@ base::string16 NameInfo::FullName() const {
base::string16 NameInfo::MiddleInitial() const {
// TODO(crbug.com/1103421): Clean legacy implementation once structured
// names are fully launched.
- if (StructuredAddressesEnabled())
+ if (structured_address::StructuredNamesEnabled())
NOTREACHED();
return middle_.empty() ? base::string16() : middle_.substr(0U, 1U);
}
@@ -260,7 +290,7 @@ base::string16 NameInfo::MiddleInitial() const {
void NameInfo::SetFullName(const base::string16& full) {
// TODO(crbug.com/1103421): Clean legacy implementation once structured
// names are fully launched.
- if (StructuredAddressesEnabled())
+ if (structured_address::StructuredNamesEnabled())
NOTREACHED();
full_ = full;
data_util::NameParts parts = data_util::SplitName(full);
diff --git a/chromium/components/autofill/core/browser/data_model/contact_info.h b/chromium/components/autofill/core/browser/data_model/contact_info.h
index 868595ac103..818dbed3b7e 100644
--- a/chromium/components/autofill/core/browser/data_model/contact_info.h
+++ b/chromium/components/autofill/core/browser/data_model/contact_info.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CONTACT_INFO_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CONTACT_INFO_H_
+#include <memory>
#include <string>
#include <vector>
@@ -31,6 +32,10 @@ class NameInfo : public FormGroup {
// FormGroup:
base::string16 GetRawInfo(ServerFieldType type) const override;
+ void GetMatchingTypes(const base::string16& text,
+ const std::string& app_locale,
+ ServerFieldTypeSet* matching_types) const override;
+
void SetRawInfoWithVerificationStatus(
ServerFieldType type,
const base::string16& value,
@@ -65,8 +70,8 @@ class NameInfo : public FormGroup {
void MergeStructuredNameValidationStatuses(const NameInfo& newer);
// Returns a constant reference to the structured name tree.
- const structured_address::NameFull& GetStructuredName() const {
- return name_;
+ const structured_address::AddressComponent& GetStructuredName() const {
+ return *name_;
}
private:
@@ -105,7 +110,7 @@ class NameInfo : public FormGroup {
// This data structure stores the more-structured representation of the name
// when |features::kAutofillEnableSupportForMoreStructureInNames| is enabled.
- structured_address::NameFull name_;
+ const std::unique_ptr<structured_address::AddressComponent> name_;
};
class EmailInfo : public FormGroup {
diff --git a/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc b/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc
index b600471f24d..65385838a4f 100644
--- a/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc
@@ -12,6 +12,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
@@ -53,46 +54,110 @@ TEST_P(SetFullNameTest, SetFullName) {
name.GetInfo(AutofillType(NAME_FULL), "en-US"));
}
+TEST(NameInfoTest, GetMatchingTypesForStructuredNameWithPrefix) {
+ base::test::ScopedFeatureList structured_name_feature;
+ structured_name_feature.InitWithFeatures(
+ {features::kAutofillEnableSupportForMoreStructureInNames,
+ features::kAutofillEnableSupportForHonorificPrefixes},
+ {});
+
+ NameInfo name;
+ test::FormGroupValues name_values = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr. Pablo Diego Ruiz y Picasso",
+ .verification_status = VerificationStatus::kObserved}};
+ test::SetFormGroupValues(name, name_values);
+ name.FinalizeAfterImport();
+
+ test::FormGroupValues expectation = {
+ {.type = NAME_FULL_WITH_HONORIFIC_PREFIX,
+ .value = "Mr. Pablo Diego Ruiz y Picasso",
+ .verification_status = VerificationStatus::kObserved},
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "Mr.",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .verification_status = VerificationStatus::kParsed}};
+
+ test::VerifyFormGroupValues(name, expectation);
+
+ ServerFieldTypeSet matching_types;
+ name.GetMatchingTypes(base::ASCIIToUTF16("Ruiz"), "US", &matching_types);
+ EXPECT_EQ(matching_types, ServerFieldTypeSet({NAME_LAST_FIRST}));
+
+ name.GetMatchingTypes(base::ASCIIToUTF16("Mr."), "US", &matching_types);
+ EXPECT_EQ(matching_types,
+ ServerFieldTypeSet({NAME_LAST_FIRST, NAME_HONORIFIC_PREFIX}));
+
+ // Verify that a field filled with |NAME_FULL_WITH_HONORIFIC_PREFIX| creates a
+ // |NAME_FULL| vote.
+ name.GetMatchingTypes(base::ASCIIToUTF16("Mr. Pablo Diego Ruiz y Picasso"),
+ "US", &matching_types);
+ EXPECT_EQ(matching_types, ServerFieldTypeSet({NAME_FULL, NAME_LAST_FIRST,
+ NAME_HONORIFIC_PREFIX}));
+}
+
TEST(NameInfoTest, GetMatchingTypesForStructuredName) {
base::test::ScopedFeatureList structured_name_feature;
- structured_name_feature.InitAndEnableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ structured_name_feature.InitWithFeatures(
+ {features::kAutofillEnableSupportForMoreStructureInNames},
+ {features::kAutofillEnableSupportForHonorificPrefixes});
NameInfo name;
- name.SetRawInfoWithVerificationStatus(
- NAME_FULL, base::ASCIIToUTF16("Mr. Pablo Diego Ruiz y Picasso"),
- VerificationStatus::kObserved);
+
+ test::FormGroupValues name_values = {
+ {.type = NAME_FULL,
+ .value = "Mr. Pablo Diego Ruiz y Picasso",
+ .verification_status = VerificationStatus::kObserved}};
+ test::SetFormGroupValues(name, name_values);
name.FinalizeAfterImport();
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(name.GetRawInfo(NAME_HONORIFIC_PREFIX),
- // base::ASCIIToUTF16("Mr."));
- EXPECT_EQ(name.GetRawInfo(NAME_FIRST), base::ASCIIToUTF16("Pablo Diego"));
- EXPECT_EQ(name.GetRawInfo(NAME_MIDDLE), base::ASCIIToUTF16(""));
- EXPECT_EQ(name.GetRawInfo(NAME_LAST), base::ASCIIToUTF16("Ruiz y Picasso"));
- EXPECT_EQ(name.GetRawInfo(NAME_LAST_FIRST), base::ASCIIToUTF16("Ruiz"));
- EXPECT_EQ(name.GetRawInfo(NAME_LAST_SECOND), base::ASCIIToUTF16("Picasso"));
- EXPECT_EQ(name.GetRawInfo(NAME_LAST_CONJUNCTION), base::ASCIIToUTF16("y"));
-
- // TODO(crbug.com/1113617): Honorifics are temporally disabled.
- // EXPECT_EQ(name.GetVerificationStatus(NAME_HONORIFIC_PREFIX),
- // VerificationStatus::kParsed);
- EXPECT_EQ(name.GetVerificationStatus(NAME_FIRST),
- VerificationStatus::kParsed);
- EXPECT_EQ(name.GetVerificationStatus(NAME_MIDDLE),
- VerificationStatus::kParsed);
- EXPECT_EQ(name.GetVerificationStatus(NAME_LAST), VerificationStatus::kParsed);
- EXPECT_EQ(name.GetVerificationStatus(NAME_LAST_FIRST),
- VerificationStatus::kParsed);
- EXPECT_EQ(name.GetVerificationStatus(NAME_LAST_SECOND),
- VerificationStatus::kParsed);
- EXPECT_EQ(name.GetVerificationStatus(NAME_LAST_CONJUNCTION),
- VerificationStatus::kParsed);
+ test::FormGroupValues expectation = {
+ {.type = NAME_HONORIFIC_PREFIX,
+ .value = "",
+ .verification_status = VerificationStatus::kNoStatus},
+ {.type = NAME_FIRST,
+ .value = "Pablo Diego",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_MIDDLE,
+ .value = "",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST,
+ .value = "Ruiz y Picasso",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_FIRST,
+ .value = "Ruiz",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_SECOND,
+ .value = "Picasso",
+ .verification_status = VerificationStatus::kParsed},
+ {.type = NAME_LAST_CONJUNCTION,
+ .value = "y",
+ .verification_status = VerificationStatus::kParsed}};
+
+ test::VerifyFormGroupValues(name, expectation);
ServerFieldTypeSet matching_types;
name.GetMatchingTypes(base::ASCIIToUTF16("Ruiz"), "US", &matching_types);
EXPECT_EQ(matching_types, ServerFieldTypeSet({NAME_LAST_FIRST}));
+ // The honorific prefix is ignored.
name.GetMatchingTypes(base::ASCIIToUTF16("Mr."), "US", &matching_types);
EXPECT_EQ(matching_types, ServerFieldTypeSet({NAME_LAST_FIRST}));
}
@@ -145,10 +210,6 @@ TEST(NameInfoTest, GetFullName) {
EXPECT_EQ(ASCIIToUTF16("First"), name.GetRawInfo(NAME_FIRST));
EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_MIDDLE));
EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_LAST));
- // For structured names, the full must contain all of its subcomponents.
- EXPECT_EQ(structured_address::StructuredNamesEnabled() ? ASCIIToUTF16("First")
- : base::string16(),
- name.GetRawInfo(NAME_FULL));
EXPECT_EQ(ASCIIToUTF16("First"),
name.GetInfo(AutofillType(NAME_FULL), "en-US"));
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.cc b/chromium/components/autofill/core/browser/data_model/credit_card.cc
index 484b13711c5..c775eb2c686 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc
@@ -356,7 +356,7 @@ bool CreditCard::IsDeletable() const {
}
base::string16 CreditCard::GetRawInfo(ServerFieldType type) const {
- DCHECK_EQ(CREDIT_CARD, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kCreditCard, AutofillType(type).group());
switch (type) {
case CREDIT_CARD_NAME_FULL:
return name_on_card_;
@@ -411,7 +411,7 @@ base::string16 CreditCard::GetRawInfo(ServerFieldType type) const {
void CreditCard::SetRawInfoWithVerificationStatus(ServerFieldType type,
const base::string16& value,
VerificationStatus status) {
- DCHECK_EQ(CREDIT_CARD, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kCreditCard, AutofillType(type).group());
switch (type) {
case CREDIT_CARD_NAME_FULL:
name_on_card_ = value;
@@ -799,11 +799,9 @@ const std::pair<base::string16, base::string16> CreditCard::LabelPieces()
if (number().empty()) {
// No CC number, if valid nickname is present, return nickname only.
// Otherwise, return cardholder name only.
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableCardNicknameManagement) &&
- HasNonEmptyValidNickname()) {
+ if (HasNonEmptyValidNickname())
return std::make_pair(nickname_, base::string16());
- }
+
return std::make_pair(name_on_card_, base::string16());
}
@@ -865,12 +863,15 @@ base::string16 CreditCard::CardIdentifierStringForAutofillDisplay(
if (HasNonEmptyValidNickname() || !customized_nickname.empty()) {
return NicknameAndLastFourDigits(customized_nickname);
}
- // Return a Google-specific string for Google-issued cards.
+ base::string16 networkAndLastFourDigits = NetworkAndLastFourDigits();
+ // Add Plex before the network and last four digits to identify it as a Google
+ // Plex card.
if (base::FeatureList::IsEnabled(features::kAutofillEnableGoogleIssuedCard) &&
IsGoogleIssuedCard()) {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GOOGLE_ISSUED);
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GOOGLE_ISSUED) +
+ ASCIIToUTF16(" ") + networkAndLastFourDigits;
}
- return NetworkAndLastFourDigits();
+ return networkAndLastFourDigits;
}
base::string16 CreditCard::CardIdentifierStringAndDescriptiveExpiration(
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
index 2990a9a4360..21923678ee9 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
@@ -100,11 +100,7 @@ TEST(CreditCardTest, GetObfuscatedStringForCardDigits) {
// of different possible summary strings. Variations occur based on the
// existence of credit card number, month, and year fields.
TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
- base::test::ScopedFeatureList scoped_feature_list;
base::string16 valid_nickname = ASCIIToUTF16("My Visa Card");
- // Enable the flag.
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillEnableCardNicknameManagement);
// Case 0: empty credit card.
CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com/");
@@ -205,20 +201,6 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
UTF8ToUTF16(std::string(" ") +
test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
summary6);
-
- // Case 7: No credit card number, has valid nickname, but flag is off.
- // Reset and disable the nickname feature flags.
- scoped_feature_list.Reset();
- scoped_feature_list.InitAndDisableFeature(
- features::kAutofillEnableCardNicknameManagement);
- CreditCard credit_card7(base::GenerateGUID(), "https://www.example.com/");
- test::SetCreditCardInfo(&credit_card7, "John Dillinger", "", "01", "2010",
- "1");
- credit_card7.SetNickname(valid_nickname);
- base::string16 summary7 = credit_card11.Label();
- EXPECT_EQ(base::string16(ASCIIToUTF16("John Dillinger")), summary7);
- base::string16 obfuscated7 = credit_card7.NetworkAndLastFourDigits();
- EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated7);
}
TEST(CreditCardTest, NicknameAndLastFourDigitsStrings) {
@@ -283,7 +265,9 @@ TEST(CreditCardTest, CardIdentifierStringForIssuedCard) {
test::SetCreditCardInfo(&credit_card1, "John Dillinger",
"5105 1051 0510 5100" /* Mastercard */, "01", "2020",
"1");
- EXPECT_EQ(l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GOOGLE_ISSUED),
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GOOGLE_ISSUED) +
+ UTF8ToUTF16(std::string(" Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
credit_card1.CardIdentifierStringForAutofillDisplay());
// Case 2: Card Issuer set to GOOGLE with nickname.
diff --git a/chromium/components/autofill/core/browser/data_model/phone_number.cc b/chromium/components/autofill/core/browser/data_model/phone_number.cc
index c9923332beb..3eb07f06293 100644
--- a/chromium/components/autofill/core/browser/data_model/phone_number.cc
+++ b/chromium/components/autofill/core/browser/data_model/phone_number.cc
@@ -74,7 +74,7 @@ void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
}
base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
- DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kPhoneHome, AutofillType(type).group());
if (type == PHONE_HOME_WHOLE_NUMBER)
return number_;
@@ -87,7 +87,7 @@ base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
void PhoneNumber::SetRawInfoWithVerificationStatus(ServerFieldType type,
const base::string16& value,
VerificationStatus status) {
- DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
+ DCHECK_EQ(FieldTypeGroup::kPhoneHome, AutofillType(type).group());
if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) {
// Only full phone numbers should be set directly. The remaining field
// field types are read-only.
diff --git a/chromium/components/autofill/core/browser/field_filler.cc b/chromium/components/autofill/core/browser/field_filler.cc
index 16ada9dbb6c..0e574dd27f0 100644
--- a/chromium/components/autofill/core/browser/field_filler.cc
+++ b/chromium/components/autofill/core/browser/field_filler.cc
@@ -19,14 +19,14 @@
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_data_model.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/data_model_utils.h"
#include "components/autofill/core/browser/data_model/phone_number.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/browser/geo/state_names.h"
+#include "components/autofill/core/browser/proto/states.pb.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_l10n_util.h"
#include "components/autofill/core/common/autofill_util.h"
@@ -251,35 +251,71 @@ bool FillStateSelectControl(const base::string16& value,
const std::string& country_code,
AddressNormalizer* address_normalizer,
std::string* failure_to_fill) {
+ std::vector<base::string16> abbreviations;
+ std::vector<base::string16> full_names;
+
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ // Fetch the corresponding entry from AlternativeStateNameMap.
+ base::Optional<StateEntry> state_entry =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode(country_code),
+ AlternativeStateNameMap::StateName(value));
+ if (state_entry) {
+ for (const auto& abbr : state_entry->abbreviations())
+ abbreviations.push_back(base::UTF8ToUTF16(abbr));
+ if (state_entry->has_canonical_name())
+ full_names.push_back(base::UTF8ToUTF16(state_entry->canonical_name()));
+ for (const auto& alternative_name : state_entry->alternative_names())
+ full_names.push_back(base::UTF8ToUTF16(alternative_name));
+ } else {
+ full_names.push_back(value);
+ }
+ }
+
base::string16 full;
base::string16 abbreviation;
// |abbreviation| will be empty for non-US countries.
state_names::GetNameAndAbbreviation(value, &full, &abbreviation);
+ if (!full.empty())
+ full_names.push_back(std::move(full));
+
+ if (!abbreviation.empty())
+ abbreviations.push_back(std::move(abbreviation));
+
// Try an exact match of the abbreviation first.
- if (!abbreviation.empty() &&
- SetSelectControlValue(abbreviation, field, /*best_match_index=*/nullptr,
- failure_to_fill)) {
- return true;
+ for (const auto& abbreviation : abbreviations) {
+ if (!abbreviation.empty() &&
+ SetSelectControlValue(abbreviation, field, /*best_match_index=*/nullptr,
+ failure_to_fill)) {
+ return true;
+ }
}
// Try an exact match of the full name.
- if (!full.empty() &&
- SetSelectControlValue(full, field, /*best_match_index=*/nullptr,
- failure_to_fill)) {
- return true;
+ for (const auto& full : full_names) {
+ if (!full.empty() &&
+ SetSelectControlValue(full, field, /*best_match_index=*/nullptr,
+ failure_to_fill)) {
+ return true;
+ }
}
// Try an inexact match of the full name.
- if (!full.empty() && SetSelectControlValueSubstringMatch(full, false, field,
- failure_to_fill)) {
- return true;
+ for (const auto& full : full_names) {
+ if (!full.empty() && SetSelectControlValueSubstringMatch(full, false, field,
+ failure_to_fill)) {
+ return true;
+ }
}
// Try an inexact match of the abbreviation name.
- if (!abbreviation.empty() &&
- SetSelectControlValueTokenMatch(abbreviation, field, failure_to_fill)) {
- return true;
+ for (const auto& abbreviation : abbreviations) {
+ if (!abbreviation.empty() &&
+ SetSelectControlValueTokenMatch(abbreviation, field, failure_to_fill)) {
+ return true;
+ }
}
// Try to match a normalized |value| of the state and the |field| options.
@@ -503,9 +539,10 @@ void FillCreditCardNumberField(const AutofillField& field,
// found, falls back to alternate filling strategies based on the |type|.
bool FillSelectControl(const AutofillType& type,
const base::string16& value,
- FormFieldData* field,
- const AutofillDataModel& data_model,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
const std::string& app_locale,
+ FormFieldData* field,
AddressNormalizer* address_normalizer,
std::string* failure_to_fill) {
DCHECK_EQ("select-one", field->form_control_type);
@@ -534,9 +571,10 @@ bool FillSelectControl(const AutofillType& type,
// If that fails, try specific fallbacks based on the field type.
if (storable_type == ADDRESS_HOME_STATE) {
- // Safe to cast the data model to AutofillProfile here.
+ DCHECK(absl::holds_alternative<const AutofillProfile*>(
+ profile_or_credit_card));
const std::string country_code = data_util::GetCountryCodeWithFallback(
- static_cast<const AutofillProfile&>(data_model), app_locale);
+ *absl::get<const AutofillProfile*>(profile_or_credit_card), app_locale);
return FillStateSelectControl(value, field, country_code,
address_normalizer, failure_to_fill);
}
@@ -580,10 +618,17 @@ void FillStreetAddress(const base::string16& value,
}
// Returns whether the |field| was filled with the state in |value| or its
-// abbreviation. First looks if |value| fits directly in the field, then looks
-// if the abbreviation of |value| fits. Does not fill if neither |value| or its
-// abbreviation are too long for the field.
+// canonical state name or the abbreviation.
+// First looks if |value| fits directly in the field, then looks if the
+// abbreviation of |value| fits in case the
+// |features::kAutofillUseAlternativeStateNameMap| is disabled.
+// If the |features::kAutofillUseAlternativeStateNameMap| is enabled, the
+// canonical state is checked if it fits in the field and at last the
+// abbreviations are tried.
+// Does not fill if neither |value| nor the canonical state name nor its
+// abbreviation fit into the field.
bool FillStateText(const base::string16& value,
+ const std::string& country_code,
FormFieldData* field,
std::string* failure_to_fill) {
if (field->max_length == 0 || field->max_length >= value.size()) {
@@ -591,6 +636,31 @@ bool FillStateText(const base::string16& value,
field->value = value;
return true;
}
+
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ base::Optional<StateEntry> state =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode(country_code),
+ AlternativeStateNameMap::StateName(value));
+ if (state) {
+ // Fill with the canonical state name if possible.
+ if (state->has_canonical_name() && !state->canonical_name().empty() &&
+ field->max_length >= state->canonical_name().size()) {
+ field->value = base::UTF8ToUTF16(state->canonical_name());
+ return true;
+ }
+
+ // Fill with the abbreviation if possible.
+ for (const auto& abbr : state->abbreviations()) {
+ if (!abbr.empty() && field->max_length >= abbr.size()) {
+ field->value = base::i18n::ToUpper(base::UTF8ToUTF16(abbr));
+ return true;
+ }
+ }
+ }
+ }
+
// Fill with the state abbreviation.
base::string16 abbreviation;
state_names::GetNameAndAbbreviation(value, nullptr, &abbreviation);
@@ -598,6 +668,7 @@ bool FillStateText(const base::string16& value,
field->value = base::i18n::ToUpper(abbreviation);
return true;
}
+
if (failure_to_fill)
*failure_to_fill += "Could not fit raw state nor abbreviation. ";
return false;
@@ -743,32 +814,36 @@ FieldFiller::FieldFiller(const std::string& app_locale,
FieldFiller::~FieldFiller() {}
-bool FieldFiller::FillFormField(const AutofillField& field,
- const AutofillDataModel& data_model,
- FormFieldData* field_data,
- const base::string16& cvc,
- std::string* failure_to_fill) {
+bool FieldFiller::FillFormField(
+ const AutofillField& field,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
+ FormFieldData* field_data,
+ const base::string16& cvc,
+ std::string* failure_to_fill) {
const AutofillType type = field.Type();
- // Don't fill if autocomplete=off is set on |field| on desktop for non credit
- // card related fields.
- if (!base::FeatureList::IsEnabled(features::kAutofillAlwaysFillAddresses) &&
- !field.should_autocomplete && IsDesktopPlatform() &&
- (type.group() != CREDIT_CARD)) {
- if (failure_to_fill)
- *failure_to_fill += "autocomplete=off. ";
- return false;
- }
+ base::string16 value;
+ if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+ const AutofillProfile* profile =
+ absl::get<const AutofillProfile*>(profile_or_credit_card);
+ if (profile->ShouldSkipFillingOrSuggesting(type.GetStorableType())) {
+ if (failure_to_fill)
+ *failure_to_fill += "ShouldSkipFillingOrSuggesting() returned true. ";
+ return false;
+ }
- if (data_model.ShouldSkipFillingOrSuggesting(type.GetStorableType())) {
- if (failure_to_fill)
- *failure_to_fill += "ShouldSkipFillingOrSuggesting() returned true. ";
- return false;
- }
+ value = profile->GetInfo(type, app_locale_);
+ } else {
+ DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card));
- base::string16 value = data_model.GetInfo(type, app_locale_);
- if (type.GetStorableType() == CREDIT_CARD_VERIFICATION_CODE)
- value = cvc;
+ if (type.GetStorableType() == CREDIT_CARD_VERIFICATION_CODE) {
+ value = cvc;
+ } else {
+ value = absl::get<const CreditCard*>(profile_or_credit_card)
+ ->GetInfo(type, app_locale_);
+ }
+ }
// Do not attempt to fill empty values as it would skew the metrics.
if (value.empty()) {
@@ -777,7 +852,7 @@ bool FieldFiller::FillFormField(const AutofillField& field,
return false;
}
- if (type.group() == PHONE_HOME) {
+ if (type.group() == FieldTypeGroup::kPhoneHome) {
// If the |field_data| is a selection box and having the type
// |PHONE_HOME_COUNTRY_CODE|, call |FillPhoneCountryCodeSelectControl|.
if (base::FeatureList::IsEnabled(
@@ -791,19 +866,21 @@ bool FieldFiller::FillFormField(const AutofillField& field,
return true;
}
if (field_data->form_control_type == "select-one") {
- return FillSelectControl(type, value, field_data, data_model, app_locale_,
- address_normalizer_, failure_to_fill);
+ return FillSelectControl(type, value, profile_or_credit_card, app_locale_,
+ field_data, address_normalizer_, failure_to_fill);
}
if (field_data->form_control_type == "month") {
- // Safe to cast to CreditCard here because month control type only applying
- // to credit card expirations.
- FillMonthControl(static_cast<const CreditCard&>(data_model), field_data);
+ DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card));
+ FillMonthControl(*absl::get<const CreditCard*>(profile_or_credit_card),
+ field_data);
return true;
}
if (type.GetStorableType() == ADDRESS_HOME_STREET_ADDRESS) {
- // Safe to cast to AutofillProfile here because of the address |type|.
- const std::string profile_language_code =
- static_cast<const AutofillProfile&>(data_model).language_code();
+ DCHECK(absl::holds_alternative<const AutofillProfile*>(
+ profile_or_credit_card));
+ const std::string& profile_language_code =
+ absl::get<const AutofillProfile*>(profile_or_credit_card)
+ ->language_code();
FillStreetAddress(value, profile_language_code, field_data);
return true;
}
@@ -811,8 +888,14 @@ bool FieldFiller::FillFormField(const AutofillField& field,
FillCreditCardNumberField(field, value, field_data);
return true;
}
- if (type.GetStorableType() == ADDRESS_HOME_STATE)
- return FillStateText(value, field_data, failure_to_fill);
+ if (type.GetStorableType() == ADDRESS_HOME_STATE) {
+ DCHECK(absl::holds_alternative<const AutofillProfile*>(
+ profile_or_credit_card));
+ const std::string& country_code = data_util::GetCountryCodeWithFallback(
+ *absl::get<const AutofillProfile*>(profile_or_credit_card),
+ app_locale_);
+ return FillStateText(value, country_code, field_data, failure_to_fill);
+ }
if (field_data->form_control_type == "text" &&
(type.GetStorableType() == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
type.GetStorableType() == CREDIT_CARD_EXP_4_DIGIT_YEAR)) {
diff --git a/chromium/components/autofill/core/browser/field_filler.h b/chromium/components/autofill/core/browser/field_filler.h
index 85ddb2b56a1..d549587b980 100644
--- a/chromium/components/autofill/core/browser/field_filler.h
+++ b/chromium/components/autofill/core/browser/field_filler.h
@@ -9,12 +9,14 @@
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
namespace autofill {
class AddressNormalizer;
-class AutofillDataModel;
class AutofillField;
// Helper class to put user content in fields, to eventually send to the
@@ -25,14 +27,14 @@ class FieldFiller {
AddressNormalizer* address_normalizer);
~FieldFiller();
- // Set |field_data|'s value to the right value in |data_model|. Uses |field|
- // to determine which field type should be filled, and |app_locale_| as hint
- // when filling exceptional cases like phone number values. Returns |true| if
- // the field has been filled, false otherwise. |cvc| is not stored in the
- // data model and may be needed at fill time. If |failure_to_fill| is not
- // null, errors are reported to that string.
+ // Set |field_data|'s value to the right value in |profile_or_credit_card|.
+ // Uses |field| to determine which field type should be filled, and
+ // |app_locale_| as hint when filling exceptional cases like phone number
+ // values. Returns |true| if the field has been filled, false otherwise. If
+ // |failure_to_fill| is not null, errors are reported to that string.
bool FillFormField(const AutofillField& field,
- const AutofillDataModel& data_model,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
FormFieldData* field_data,
const base::string16& cvc,
std::string* failure_to_fill = nullptr);
diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc
index 02f1c95c11f..1d32da08cfc 100644
--- a/chromium/components/autofill/core/browser/field_filler_unittest.cc
+++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc
@@ -26,6 +26,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_util.h"
@@ -100,13 +101,13 @@ void TestFillingExpirationMonth(const std::vector<const char*>& values,
// Try a single-digit month.
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(3);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
GetIndexOfValue(field.option_values, field.value, &content_index);
EXPECT_EQ(ASCIIToUTF16("Mar"), field.option_contents[content_index]);
// Try a two-digit month.
card.SetExpirationMonth(11);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
GetIndexOfValue(field.option_values, field.value, &content_index);
EXPECT_EQ(ASCIIToUTF16("Nov"), field.option_contents[content_index]);
}
@@ -125,11 +126,11 @@ void TestFillingInvalidFields(const base::string16& state,
field_city.set_heuristic_type(ADDRESS_HOME_CITY);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field_state, profile, &field_state,
+ filler.FillFormField(field_state, &profile, &field_state,
/*cvc=*/base::string16());
EXPECT_EQ(state, field_state.value);
- filler.FillFormField(field_city, profile, &field_city,
+ filler.FillFormField(field_city, &profile, &field_city,
/*cvc=*/base::string16());
EXPECT_EQ(city, field_city.value);
}
@@ -177,37 +178,37 @@ TEST_F(AutofillFieldFillerTest, Type) {
// Set the heuristic type and check it.
field.set_heuristic_type(NAME_FIRST);
EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
- EXPECT_EQ(NAME, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kName, field.Type().group());
// Set the server type and check it.
field.set_server_type(ADDRESS_BILLING_LINE1);
EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
- EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
// Checks that overall_type trumps everything.
field.SetTypeTo(AutofillType(ADDRESS_BILLING_ZIP));
EXPECT_EQ(ADDRESS_HOME_ZIP, field.Type().GetStorableType());
- EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
// Checks that setting server type resets overall type.
field.set_server_type(ADDRESS_BILLING_LINE1);
EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
- EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
// Remove the server type to make sure the heuristic type is preserved.
field.set_server_type(NO_SERVER_DATA);
EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
- EXPECT_EQ(NAME, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kName, field.Type().group());
// Checks that overall_type trumps everything.
field.SetTypeTo(AutofillType(ADDRESS_BILLING_ZIP));
EXPECT_EQ(ADDRESS_HOME_ZIP, field.Type().GetStorableType());
- EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
// Set the heuristic type and check it and reset overall Type.
field.set_heuristic_type(NAME_FIRST);
EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
- EXPECT_EQ(NAME, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kName, field.Type().group());
}
// Tests that a credit card related prediction made by the heuristics overrides
@@ -354,31 +355,6 @@ TEST_F(AutofillFieldFillerTest, IsFieldFillable) {
}
// Verify that non credit card related fields with the autocomplete attribute
-// set to off don't get filled on desktop when the feature to Autofill all
-// addresses is disabled.
-TEST_F(AutofillFieldFillerTest,
- FillFormField_AutocompleteOffRespected_AddressField) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(features::kAutofillAlwaysFillAddresses);
-
- AutofillField field;
- field.should_autocomplete = false;
- field.set_heuristic_type(NAME_FIRST);
-
- // Non credit card related field.
- address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Test"));
- FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
-
- // Verify that the field is filled on mobile but not on desktop.
- if (IsDesktopPlatform()) {
- EXPECT_EQ(base::string16(), field.value);
- } else {
- EXPECT_EQ(ASCIIToUTF16("Test"), field.value);
- }
-}
-
-// Verify that non credit card related fields with the autocomplete attribute
// set to off are filled on desktop when the feature to Autofill all
// addresses is enabled (default).
TEST_F(AutofillFieldFillerTest,
@@ -390,7 +366,7 @@ TEST_F(AutofillFieldFillerTest,
// Non credit card related field.
address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Test"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
// Verify that the field is filled in all circumstances.
EXPECT_EQ(ASCIIToUTF16("Test"), field.value);
@@ -406,7 +382,7 @@ TEST_F(AutofillFieldFillerTest, FillFormField_AutocompleteOff_CreditCardField) {
// Credit card related field.
credit_card()->SetNumber(ASCIIToUTF16("4111111111111111"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
// Verify that the field is filled.
EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
@@ -424,7 +400,7 @@ TEST_F(AutofillFieldFillerTest,
// Credit card related field.
credit_card()->SetNumber(ASCIIToUTF16("0123456789999999"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
// Verify that the field is filled with the fourth digit of the credit card
// number.
@@ -443,7 +419,7 @@ TEST_F(AutofillFieldFillerTest,
// Credit card related field.
credit_card()->SetNumber(ASCIIToUTF16("0123456789999999"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
// Verify that the field is filled with the full credit card number.
EXPECT_EQ(ASCIIToUTF16("0123456789999999"), field.value);
@@ -461,7 +437,7 @@ TEST_F(AutofillFieldFillerTest,
// Credit card related field.
credit_card()->SetNumber(ASCIIToUTF16("0123456789999999"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
// Verify that the field is filled with the third digit of the credit card
// number.
@@ -477,7 +453,7 @@ TEST_F(AutofillFieldFillerTest, FillFormField_MaxLength_CreditCardField) {
// Credit card related field.
credit_card()->SetNumber(ASCIIToUTF16("4111111111111111"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
// Verify that the field is filled with only the first digit of the credit
// card number.
@@ -549,13 +525,13 @@ TEST_F(AutofillFieldFillerTest, FillFormField_Validity_CountryEmpty) {
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
// State is filled, because it's an address field.
- filler.FillFormField(field_state, profile, &field_state,
+ filler.FillFormField(field_state, &profile, &field_state,
/*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("CA"), field_state.value);
// Email is not filled, because it's not an address field, and it doesn't
// depend on the country.
- filler.FillFormField(field_email, profile, &field_email,
+ filler.FillFormField(field_email, &profile, &field_email,
/*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16(""), field_email.value);
}
@@ -581,7 +557,7 @@ TEST_P(PhoneNumberTest, FillPhoneNumber) {
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+15145554578"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
@@ -631,7 +607,7 @@ TEST_P(ExpirationYearTest, FillExpirationYearInput) {
CreditCard card = test::GetCreditCard();
card.SetExpirationDateFromString(ASCIIToUTF16("12/2023"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
@@ -694,7 +670,7 @@ TEST_P(ExpirationDateTest, FillExpirationDateInput) {
card.SetExpirationDateFromString(ASCIIToUTF16("03/2022"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
bool response =
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
EXPECT_EQ(response, test_case.expected_response);
}
@@ -767,7 +743,10 @@ INSTANTIATE_TEST_SUITE_P(
TEST_F(AutofillFieldFillerTest, FillSelectControlByValue) {
std::vector<const char*> kOptions = {
- "Eenie", "Meenie", "Miney", "Mo",
+ "Eenie",
+ "Meenie",
+ "Miney",
+ "Mo",
};
AutofillField field;
@@ -781,13 +760,16 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlByValue) {
address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Meenie"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("Meenie"), field.value);
}
TEST_F(AutofillFieldFillerTest, FillSelectControlByContents) {
std::vector<const char*> kOptions = {
- "Eenie", "Meenie", "Miney", "Mo",
+ "Eenie",
+ "Meenie",
+ "Miney",
+ "Mo",
};
AutofillField field;
test::CreateTestSelectField(kOptions, &field);
@@ -800,7 +782,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlByContents) {
address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Miney"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("2"), field.value); // Corresponds to "Miney".
}
@@ -829,6 +811,17 @@ class AutofillSelectWithStatesTest
std::unique_ptr<Source>(
new TestdataSource(true, file_path.AsUTF8Unsafe())),
std::unique_ptr<Storage>(new NullStorage), "en-US");
+
+ test::PopulateAlternativeStateNameMapForTesting(
+ "US", "California",
+ {{.canonical_name = "California",
+ .abbreviations = {"CA"},
+ .alternative_names = {}}});
+ test::PopulateAlternativeStateNameMapForTesting(
+ "US", "North Carolina",
+ {{.canonical_name = "North Carolina",
+ .abbreviations = {"NC"},
+ .alternative_names = {}}});
// Make sure the normalizer is done initializing its member(s) in
// background task(s).
task_environment_.RunUntilIdle();
@@ -854,7 +847,7 @@ TEST_P(AutofillSelectWithStatesTest, FillSelectWithStates) {
AutofillProfile address = test::GetFullProfile();
address.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16(test_case.input_value));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
// nullptr means we expect them not to match without normalization.
if (test_case.expected_value_without_normalization != nullptr) {
EXPECT_EQ(UTF8ToUTF16(test_case.expected_value_without_normalization),
@@ -867,7 +860,7 @@ TEST_P(AutofillSelectWithStatesTest, FillSelectWithStates) {
UTF8ToUTF16(test_case.input_value));
// Fill a first time without loading the rules for the region.
FieldFiller canadian_filler(/*app_locale=*/"en-US", normalizer());
- canadian_filler.FillFormField(field, canadian_address, &field,
+ canadian_filler.FillFormField(field, &canadian_address, &field,
/*cvc=*/base::string16());
// If the expectation with normalization is nullptr, this means that the same
// result than without a normalizer is expected.
@@ -882,7 +875,7 @@ TEST_P(AutofillSelectWithStatesTest, FillSelectWithStates) {
// Load the rules and try again.
normalizer()->LoadRulesForRegion("CA");
- canadian_filler.FillFormField(field, canadian_address, &field,
+ canadian_filler.FillFormField(field, &canadian_address, &field,
/*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16(test_case.expected_value_with_normalization),
field.value);
@@ -951,7 +944,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectWithCountries) {
AutofillProfile address = test::GetFullProfile();
address.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("CA"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("Canada"), field.value);
}
@@ -1077,7 +1070,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlWithAbbreviatedMonthName) {
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(4);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("Apr"), field.value);
}
@@ -1093,7 +1086,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlWithMonthName) {
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(4);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("April"), field.value);
}
@@ -1110,7 +1103,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlWithMonthNameAndDigits) {
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(4);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("April (04)"), field.value);
}
@@ -1137,10 +1130,10 @@ TEST_F(AutofillFieldFillerTest,
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(8);
FieldFiller filler(/*app_locale=*/"fr-FR", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("08 - AOÛT"), field.value);
card.SetExpirationMonth(12);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("12 - DECEMBRE"), field.value);
}
@@ -1154,15 +1147,15 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlWithMonthName_French) {
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(2);
FieldFiller filler(/*app_locale=*/"fr-FR", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("FÉVR."), field.value);
card.SetExpirationMonth(1);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("JANV"), field.value);
card.SetExpirationMonth(12);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("décembre"), field.value);
}
@@ -1178,7 +1171,7 @@ TEST_F(AutofillFieldFillerTest,
CreditCard card = test::GetCreditCard();
card.SetExpirationMonth(4);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("4"), field.value);
}
@@ -1192,7 +1185,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlWithTwoDigitCreditCardYear) {
CreditCard card = test::GetCreditCard();
card.SetExpirationYear(2017);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("17"), field.value);
}
@@ -1207,22 +1200,22 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlWithCreditCardType) {
// Normal case:
card.SetNumber(ASCIIToUTF16("4111111111111111")); // Visa number.
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("Visa"), field.value);
// Filling should be able to handle intervening whitespace:
card.SetNumber(ASCIIToUTF16("5555555555554444")); // MC number.
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("Mastercard"), field.value);
// American Express is sometimes abbreviated as AmEx:
card.SetNumber(ASCIIToUTF16("378282246310005")); // Amex number.
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value);
// Case insensitivity:
card.SetNumber(ASCIIToUTF16("6011111111111117")); // Discover number.
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("discover"), field.value);
}
@@ -1235,12 +1228,12 @@ TEST_F(AutofillFieldFillerTest, FillMonthControl) {
// Try a month with two digits.
CreditCard card = test::GetCreditCard();
card.SetExpirationDateFromString(ASCIIToUTF16("12/2017"));
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("2017-12"), field.value);
// Try a month with a leading zero.
card.SetExpirationDateFromString(ASCIIToUTF16("03/2019"));
- filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("2019-03"), field.value);
}
@@ -1254,7 +1247,7 @@ TEST_F(AutofillFieldFillerTest, FillStreetAddressTextArea) {
"123 Fake St.\n"
"Apt. 42");
address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), value, "en-US");
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
EXPECT_EQ(value, field.value);
base::string16 ja_value = UTF8ToUTF16(
@@ -1263,7 +1256,7 @@ TEST_F(AutofillFieldFillerTest, FillStreetAddressTextArea) {
address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), ja_value,
"ja-JP");
address()->set_language_code("ja-JP");
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
EXPECT_EQ(ja_value, field.value);
}
@@ -1277,7 +1270,7 @@ TEST_F(AutofillFieldFillerTest, FillStreetAddressTextField) {
"123 Fake St.\n"
"Apt. 42");
address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), value, "en-US");
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("123 Fake St., Apt. 42"), field.value);
base::string16 ja_value = UTF8ToUTF16(
@@ -1286,7 +1279,7 @@ TEST_F(AutofillFieldFillerTest, FillStreetAddressTextField) {
address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), ja_value,
"ja-JP");
address()->set_language_code("ja-JP");
- filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
EXPECT_EQ(UTF8ToUTF16("桜丘町26-1セルリアンタワー6階"), field.value);
}
@@ -1297,7 +1290,7 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithoutSplits) {
credit_card()->SetNumber(ASCIIToUTF16("41111111111111111"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(cc_number_full, *credit_card(), &cc_number_full,
+ filler.FillFormField(cc_number_full, credit_card(), &cc_number_full,
/*cvc=*/base::string16());
// Verify that full card-number shall get filled properly.
@@ -1325,7 +1318,7 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithEqualSizeSplits) {
// Fill with a card-number; should fill just the card_number_part.
credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
- filler.FillFormField(cc_number_part, *credit_card(), &cc_number_part,
+ filler.FillFormField(cc_number_part, credit_card(), &cc_number_part,
/*cvc=*/base::string16());
// Verify for expected results.
@@ -1339,7 +1332,7 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithEqualSizeSplits) {
cc_number_full.set_heuristic_type(CREDIT_CARD_NUMBER);
credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
- filler.FillFormField(cc_number_full, *credit_card(), &cc_number_full,
+ filler.FillFormField(cc_number_full, credit_card(), &cc_number_full,
/*cvc=*/base::string16());
// Verify for expected results.
@@ -1368,7 +1361,7 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithUnequalSizeSplits) {
// Fill with a card-number; should fill just the card_number_part.
credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
- filler.FillFormField(cc_number_part, *credit_card(), &cc_number_part,
+ filler.FillFormField(cc_number_part, credit_card(), &cc_number_part,
/*cvc=*/base::string16());
// Verify for expected results.
@@ -1382,7 +1375,7 @@ TEST_F(AutofillFieldFillerTest, FillCreditCardNumberWithUnequalSizeSplits) {
AutofillField cc_number_full;
cc_number_full.set_heuristic_type(CREDIT_CARD_NUMBER);
credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
- filler.FillFormField(cc_number_full, *credit_card(), &cc_number_full,
+ filler.FillFormField(cc_number_full, credit_card(), &cc_number_full,
/*cvc=*/base::string16());
// Verify for expected results.
@@ -1457,7 +1450,7 @@ TEST_P(AutofillStateTextTest, FillStateText) {
AutofillProfile address = test::GetFullProfile();
address.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16(test_case.value_to_fill));
bool has_filled =
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(test_case.should_fill, has_filled);
EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
@@ -1511,7 +1504,7 @@ TEST_F(AutofillFieldFillerTest,
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+15145554578"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("1"), field.value);
}
@@ -1532,7 +1525,7 @@ TEST_F(AutofillFieldFillerTest,
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+918890888888"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("+91"), field.value);
}
@@ -1553,7 +1546,7 @@ TEST_F(AutofillFieldFillerTest,
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+918890888888"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("0091"), field.value);
}
@@ -1574,7 +1567,7 @@ TEST_F(AutofillFieldFillerTest, FillSelectControlAugmentedPhoneCountryCode) {
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("+49 (Germany)"), field.value);
}
@@ -1596,7 +1589,7 @@ TEST_F(AutofillFieldFillerTest,
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("(00 49) Germany"), field.value);
}
@@ -1619,8 +1612,199 @@ TEST_F(AutofillFieldFillerTest,
AutofillProfile address;
address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
EXPECT_EQ(ASCIIToUTF16("(0049) Germany"), field.value);
}
+// Tests that the abbreviated state names are selected correctly.
+TEST_F(AutofillFieldFillerTest, FillSelectAbbreviatedState) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ std::vector<const char*> kState = {"BA", "BB", "BC", "BY"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("Bavaria"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("BY"), field.value);
+}
+
+// Tests that the localized state names are selected correctly.
+TEST_F(AutofillFieldFillerTest, FillSelectLocalizedState) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ std::vector<const char*> kState = {"Bayern", "Berlin", "Brandenburg",
+ "Bremen"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("Bavaria"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("Bayern"), field.value);
+}
+
+// Tests that the state names are selected correctly when the state name exists
+// as a substring in the selection options.
+TEST_F(AutofillFieldFillerTest, FillSelectLocalizedStateSubstring) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ std::vector<const char*> kState = {"Bavaria Has Munich", "Berlin has Berlin"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("Bavaria"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("Bavaria Has Munich"), field.value);
+}
+
+// Tests that the state abbreviations are filled in the text field when the
+// field length is limited.
+TEST_F(AutofillFieldFillerTest, FillStateAbbreviationInTextField) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+
+ AutofillField field;
+ test::CreateTestFormField("State", "state", "", "text", &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+ field.max_length = 4;
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("Bavaria"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("BY"), field.value);
+}
+
+// Tests that the state names are selected correctly even though the state
+// value saved in the address is not recognized by the AlternativeStateNameMap.
+TEST_F(AutofillFieldFillerTest, FillStateFieldWithSavedValueInProfile) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ std::vector<const char*> kState = {"Bavari", "Berlin", "Lower Saxony"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("Bavari"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("Bavari"), field.value);
+}
+
+// Tests that Autofill does not wrongly fill the state when the appropriate
+// state is not in the list of selection options given that the abbreviation is
+// saved in the profile.
+TEST_F(AutofillFieldFillerTest, FillStateFieldWhenStateIsNotInOptions) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting(
+ "US", "Colorado",
+ {{.canonical_name = "Colorado",
+ .abbreviations = {"CO"},
+ .alternative_names = {}}});
+ std::vector<const char*> kState = {"Connecticut", "California"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CO"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16(""), field.value);
+}
+
+// Tests that Autofill uses the static states data of US as a fallback mechanism
+// for filling when |AlternativeStateNameMap| is not populated.
+TEST_F(AutofillFieldFillerTest,
+ FillStateFieldWhenAlternativeStateNameMapIsNotPopulated) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ std::vector<const char*> kState = {"Colorado", "Connecticut", "California"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CO"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("Colorado"), field.value);
+}
+
+// Tests that Autofill fills upper case abbreviation in the input field when
+// field length is limited.
+TEST_F(AutofillFieldFillerTest, FillUpperCaseAbbreviationInStateTextField) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting("DE", "Bavaria",
+ {{.canonical_name = "Bavaria",
+ .abbreviations = {"by"},
+ .alternative_names = {}}});
+
+ AutofillField field;
+ test::CreateTestFormField("State", "state", "", "text", &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
+ field.max_length = 4;
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("Bavaria"));
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("BY"), field.value);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/field_types.cc b/chromium/components/autofill/core/browser/field_types.cc
index d828d8acc87..78e6b52c81f 100644
--- a/chromium/components/autofill/core/browser/field_types.cc
+++ b/chromium/components/autofill/core/browser/field_types.cc
@@ -21,6 +21,7 @@ bool IsFillableFieldType(ServerFieldType field_type) {
case NAME_LAST_SECOND:
case NAME_MIDDLE_INITIAL:
case NAME_FULL:
+ case NAME_FULL_WITH_HONORIFIC_PREFIX:
case NAME_SUFFIX:
case EMAIL_ADDRESS:
case USERNAME_AND_EMAIL_ADDRESS:
@@ -152,6 +153,8 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "EMPTY_TYPE";
case NAME_HONORIFIC_PREFIX:
return "NAME_HONORIFIC_PREFIX";
+ case NAME_FULL_WITH_HONORIFIC_PREFIX:
+ return "NAME_FULL_WITH_HONORIFIC_PREFIX";
case NAME_FIRST:
return "NAME_FIRST";
case NAME_MIDDLE:
diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h
index 7af166bd7fb..52f3cfab947 100644
--- a/chromium/components/autofill/core/browser/field_types.h
+++ b/chromium/components/autofill/core/browser/field_types.h
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_piece_forward.h"
+#include "components/autofill/core/common/dense_set.h"
namespace autofill {
@@ -233,9 +234,12 @@ enum ServerFieldType {
// The floor number within a building.
ADDRESS_HOME_FLOOR = 116,
+ // The full name including the honorific prefix.
+ NAME_FULL_WITH_HONORIFIC_PREFIX = 117,
+
// No new types can be added without a corresponding change to the Autofill
// server.
- MAX_VALID_FIELD_TYPE = 117,
+ MAX_VALID_FIELD_TYPE = 118,
};
// The list of all HTML autocomplete field type hints supported by Chrome.
@@ -323,24 +327,25 @@ enum HtmlFieldMode {
HTML_MODE_SHIPPING,
};
-enum FieldTypeGroup {
- NO_GROUP,
- NAME,
- NAME_BILLING,
- EMAIL,
- COMPANY,
- ADDRESS_HOME,
- ADDRESS_BILLING,
- PHONE_HOME,
- PHONE_BILLING,
- CREDIT_CARD,
- PASSWORD_FIELD,
- TRANSACTION,
- USERNAME_FIELD,
- UNFILLABLE,
+enum class FieldTypeGroup {
+ kNoGroup,
+ kName,
+ kNameBilling,
+ kEmail,
+ kCompany,
+ kAddressHome,
+ kAddressBilling,
+ kPhoneHome,
+ kPhoneBilling,
+ kCreditCard,
+ kPasswordField,
+ kTransaction,
+ kUsernameField,
+ kUnfillable,
+ kMaxValue = kUnfillable,
};
-typedef std::set<ServerFieldType> ServerFieldTypeSet;
+using ServerFieldTypeSet = DenseSet<ServerFieldType, MAX_VALID_FIELD_TYPE>;
// Returns whether the field can be filled with data.
bool IsFillableFieldType(ServerFieldType field_type);
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index 37c6daaa7a4..a81a2586b53 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -19,7 +19,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "components/autofill/core/browser/address_profiles/address_profile_save_manager.h"
+#include "components/autofill/core/browser/address_profile_save_manager.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_type.h"
@@ -52,22 +52,33 @@ using AddressImportRequirement =
// Return true if the |field_type| and |value| are valid within the context
// of importing a form.
-bool IsValidFieldTypeAndValue(const std::set<ServerFieldType>& types_seen,
+bool IsValidFieldTypeAndValue(const ServerFieldTypeSet types_seen,
ServerFieldType field_type,
const base::string16& value,
LogBuffer* import_log_buffer) {
// Abandon the import if two fields of the same type are encountered.
// This indicates ambiguous data or miscategorization of types.
- // Make an exception for PHONE_HOME_NUMBER however as both prefix and
- // suffix are stored against this type, and for EMAIL_ADDRESS because it is
- // common to see second 'confirm email address' fields on forms.
- if (types_seen.count(field_type) && field_type != PHONE_HOME_NUMBER &&
- field_type != EMAIL_ADDRESS) {
+ // Make an exception for:
+ // - EMAIL_ADDRESS because it is common to see second 'confirm email address'
+ // field;
+ // - PHONE_HOME_NUMBER because it is used to store both prefix and suffix of a
+ // single number;
+ // - phone number components because a form might request several phone
+ // numbers.
+ // TODO(crbug.com/1156315) Remove feature & PHONE_HOME_NUMBER checks when
+ // launched.
+ auto field_type_group = AutofillType(field_type).group();
+ if (types_seen.count(field_type) && field_type != EMAIL_ADDRESS &&
+ (base::FeatureList::IsEnabled(
+ features::kAutofillEnableImportWhenMultiplePhoneNumbers)
+ ? field_type_group != FieldTypeGroup::kPhoneBilling &&
+ field_type_group != FieldTypeGroup::kPhoneHome
+ : field_type != PHONE_HOME_NUMBER)) {
if (import_log_buffer) {
*import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
<< "Multiple fields of type "
- << AutofillType(field_type).ToString() << "."
- << CTag{};
+ << AutofillType::ServerFieldTypeToString(field_type)
+ << "." << CTag{};
}
return false;
}
@@ -77,7 +88,8 @@ bool IsValidFieldTypeAndValue(const std::set<ServerFieldType>& types_seen,
if (import_log_buffer) {
*import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
<< "Email address found in field of different type: "
- << AutofillType(field_type).ToString() << CTag{};
+ << AutofillType::ServerFieldTypeToString(field_type)
+ << CTag{};
}
return false;
}
@@ -229,7 +241,8 @@ FormDataImporter::FormDataImporter(AutofillClient* client,
app_locale,
personal_data_manager)),
address_profile_save_manager_(
- std::make_unique<AddressProfileSaveManager>(personal_data_manager)),
+ std::make_unique<AddressProfileSaveManager>(client,
+ personal_data_manager)),
#if !defined(OS_ANDROID) && !defined(OS_IOS)
local_card_migration_manager_(
std::make_unique<LocalCardMigrationManager>(client,
@@ -421,7 +434,10 @@ bool FormDataImporter::ImportFormData(
// - ImportAddressProfiles may eventually save or update one or more address
// profiles.
bool address_import = false;
- if (profile_autofill_enabled) {
+
+ // Only import addresses if enabled.
+ if (profile_autofill_enabled &&
+ !base::FeatureList::IsEnabled(features::kAutofillDisableAddressImport)) {
address_import = ImportAddressProfiles(submitted_form);
}
@@ -443,7 +459,7 @@ bool FormDataImporter::ImportAddressProfiles(const FormStructure& form) {
// We save a maximum of 2 profiles per submitted form (e.g. for shipping and
// billing).
static const size_t kMaxNumAddressProfilesSaved = 2;
- size_t num_saved_profiles = 0;
+ size_t num_complete_profiles = 0;
if (!form.field_count()) {
import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
@@ -452,12 +468,12 @@ bool FormDataImporter::ImportAddressProfiles(const FormStructure& form) {
// Relevant sections for address fields.
std::set<std::string> sections;
for (const auto& field : form) {
- if (field->Type().group() != CREDIT_CARD)
+ if (field->Type().group() != FieldTypeGroup::kCreditCard)
sections.insert(field->section);
}
for (const std::string& section : sections) {
- if (num_saved_profiles == kMaxNumAddressProfilesSaved)
+ if (num_complete_profiles == kMaxNumAddressProfilesSaved)
break;
// Log the output from a section in a separate div for readability.
import_log_buffer << Tag{"div"}
@@ -466,38 +482,38 @@ bool FormDataImporter::ImportAddressProfiles(const FormStructure& form) {
<< section << CTag{};
// Try to import an address profile from the form fields of this section.
if (ImportAddressProfileForSection(form, section, &import_log_buffer))
- num_saved_profiles++;
+ num_complete_profiles++;
// And close the div of the section import log.
import_log_buffer << CTag{"div"};
}
// Run the import on the union of the section if the import was not
// successful and if there is more than one section.
- if (num_saved_profiles > 0) {
+ if (num_complete_profiles > 0) {
AutofillMetrics::LogAddressFormImportStatustMetric(
AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT);
} else if (sections.size() > 1) {
// Try to import by combining all sections.
if (ImportAddressProfileForSection(form, "", &import_log_buffer)) {
- num_saved_profiles++;
+ num_complete_profiles++;
AutofillMetrics::LogAddressFormImportStatustMetric(
AutofillMetrics::AddressProfileImportStatusMetric::
SECTION_UNION_IMPORT);
}
}
- if (num_saved_profiles == 0) {
+ if (num_complete_profiles == 0) {
AutofillMetrics::LogAddressFormImportStatustMetric(
AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT);
}
}
import_log_buffer << LogMessage::kImportAddressProfileFromFormNumberOfImports
- << num_saved_profiles << CTag{};
+ << num_complete_profiles << CTag{};
// Write log buffer to autofill-internals.
LogManager* log_manager = client_->GetLogManager();
if (log_manager)
log_manager->Log() << std::move(import_log_buffer);
- return num_saved_profiles > 0;
+ return num_complete_profiles > 0;
}
bool FormDataImporter::ImportAddressProfileForSection(
@@ -514,7 +530,7 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Used to detect and discard address forms with multiple fields of the same
// type.
- std::set<ServerFieldType> types_seen;
+ ServerFieldTypeSet types_seen;
// Tracks if the form section contains multiple distinct email addresses.
bool has_multiple_distinct_email_addresses = false;
@@ -528,6 +544,10 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Tracks if the form section contains an invalid country.
bool has_invalid_country = false;
+ // Tracks if subsequent phone number fields should be ignored,
+ // since they do not belong to the first phone number in the form.
+ bool ignore_phone_number_fields = false;
+
// Go through each |form| field and attempt to constitute a valid profile.
for (const auto& field : form) {
// Reject fields that are not within the specified |section|.
@@ -539,14 +559,20 @@ bool FormDataImporter::ImportAddressProfileForSection(
base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
// If we don't know the type of the field, or the user hasn't entered any
- // information into the field, then skip it.
- if (!field->IsFieldFillable() || value.empty())
+ // information into the field, or the field is non-focusable (hidden), then
+ // skip it.
+ // TODO(crbug.com/1101280): Remove |skip_unfocussable_field|
+ bool skip_unfocussable_field =
+ !field->is_focusable &&
+ !base::FeatureList::IsEnabled(
+ features::kAutofillProfileImportFromUnfocusableFields);
+ if (!field->IsFieldFillable() || skip_unfocussable_field || value.empty())
continue;
AutofillType field_type = field->Type();
// Credit card fields are handled by ImportCreditCard().
- if (field_type.group() == CREDIT_CARD)
+ if (field_type.group() == FieldTypeGroup::kCreditCard)
continue;
// There can be multiple email fields (e.g. in the case of 'confirm email'
@@ -569,6 +595,27 @@ bool FormDataImporter::ImportAddressProfileForSection(
if (!IsValidFieldTypeAndValue(types_seen, server_field_type, value,
import_log_buffer))
has_invalid_field_types = true;
+
+ // Found phone number component field.
+ // TODO(crbug.com/1156315) Remove feature check when launched.
+ if ((field_type.group() == FieldTypeGroup::kPhoneBilling ||
+ field_type.group() == FieldTypeGroup::kPhoneHome) &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableImportWhenMultiplePhoneNumbers)) {
+ if (ignore_phone_number_fields)
+ continue;
+ // PHONE_HOME_NUMBER is used for both prefix and suffix, so it might occur
+ // multiple times for a single number. Duplication of any other phone
+ // component means it belongs to a new number. Since Autofill currently
+ // supports storing only one phone number per profile, ignore this and all
+ // subsequent phone number fields.
+ if (server_field_type != PHONE_HOME_NUMBER &&
+ types_seen.count(server_field_type)) {
+ ignore_phone_number_fields = true;
+ continue;
+ }
+ }
+
types_seen.insert(server_field_type);
// We need to store phone data in the variables, before building the whole
@@ -673,10 +720,13 @@ bool FormDataImporter::ImportAddressProfileForSection(
if (!candidate_profile.FinalizeAfterImport())
return false;
- std::string guid =
- address_profile_save_manager_->SaveProfile(candidate_profile);
+ // At this stage, the saving of the profile can only be omitted by the
+ // incognito mode but the import is not triggered if the browser is in the
+ // incognito mode.
+ DCHECK(!personal_data_manager_->IsOffTheRecord());
+ address_profile_save_manager_->SaveProfile(candidate_profile);
- return !guid.empty();
+ return true;
}
bool FormDataImporter::ImportCreditCard(
@@ -803,7 +853,7 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm(
CreditCard candidate_credit_card;
- std::set<ServerFieldType> types_seen;
+ ServerFieldTypeSet types_seen;
for (const auto& field : form) {
base::string16 value;
base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
@@ -815,7 +865,7 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm(
AutofillType field_type = field->Type();
// Field was not identified as a credit card field.
- if (field_type.group() != CREDIT_CARD)
+ if (field_type.group() != FieldTypeGroup::kCreditCard)
continue;
if (form.value_from_dynamic_change_form())
diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h
index 4ef28d575a6..a368708103f 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.h
+++ b/chromium/components/autofill/core/browser/form_data_importer.h
@@ -112,7 +112,8 @@ class FormDataImporter {
// Go through the |form| fields and attempt to extract and import valid
// address profiles. Returns true on extraction success of at least one
// profile. There are many reasons that extraction may fail (see
- // implementation).
+ // implementation). The function returns true if at least one complete address
+ // profile was found.
bool ImportAddressProfiles(const FormStructure& form);
// Helper method for ImportAddressProfiles which only considers the fields for
diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
index b15cee9ccae..8a51f0634dc 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -32,7 +32,6 @@
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/form_structure.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/autofill/core/browser/test_autofill_client.h"
@@ -124,6 +123,7 @@ class FormDataImporterTestBase {
scoped_refptr<AutofillWebDataService>(autofill_database_service_),
/*account_database=*/nullptr,
/*pref_service=*/prefs_.get(),
+ /*local_state=*/prefs_.get(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -195,7 +195,7 @@ class FormDataImporterTestBase {
const char* exp_cc_month,
const char* exp_cc_year) {
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -232,7 +232,6 @@ class FormDataImporterTestBase {
std::unique_ptr<PersonalDataManager> personal_data_manager_;
std::unique_ptr<FormDataImporter> form_data_importer_;
base::test::ScopedFeatureList scoped_feature_list_;
- TestPatternProvider test_pattern_provider_;
};
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
@@ -241,7 +240,7 @@ class FormDataImporterTestBase {
class FormDataImporterTest
: public FormDataImporterTestBase,
public testing::Test,
- public testing::WithParamInterface<std::tuple<bool, bool>> {
+ public testing::WithParamInterface<std::tuple<bool, bool, bool>> {
protected:
bool StructuredNames() const { return structured_names_enabled_; }
bool StructuredAddresses() const { return structured_addresses_enabled_; }
@@ -290,6 +289,7 @@ class FormDataImporterTest
void InitializeFeatures() {
structured_names_enabled_ = std::get<0>(GetParam());
structured_addresses_enabled_ = std::get<1>(GetParam());
+ support_for_apartment_numbers_ = std::get<2>(GetParam());
std::vector<base::Feature> enabled_features;
std::vector<base::Feature> disabled_features;
@@ -309,15 +309,24 @@ class FormDataImporterTest
disabled_features.push_back(
features::kAutofillEnableSupportForMoreStructureInAddresses);
}
+
+ if (support_for_apartment_numbers_) {
+ enabled_features.push_back(
+ features::kAutofillEnableSupportForApartmentNumbers);
+ } else {
+ disabled_features.push_back(
+ features::kAutofillEnableSupportForApartmentNumbers);
+ }
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
bool structured_names_enabled_;
bool structured_addresses_enabled_;
+ bool support_for_apartment_numbers_;
};
// ImportAddressProfiles tests.
-TEST_P(FormDataImporterTest, ImportStructuredAddressProfile) {
+TEST_P(FormDataImporterTest, ImportStructuredNameProfile) {
base::test::ScopedFeatureList structured_addresses_feature;
structured_addresses_feature.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInAddresses);
@@ -342,7 +351,7 @@ TEST_P(FormDataImporterTest, ImportStructuredAddressProfile) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
const std::vector<AutofillProfile*>& results =
@@ -394,7 +403,7 @@ TEST_P(FormDataImporterTest,
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
const std::vector<AutofillProfile*>& results =
@@ -416,6 +425,65 @@ TEST_P(FormDataImporterTest,
structured_address::VerificationStatus::kFormatted);
}
+TEST_P(
+ FormDataImporterTest,
+ ImportStructuredAddressProfile_StreetNameAndHouseNumberAndApartmentNumber) {
+ // This test is only applicable for enabled structured addresses and support
+ // for apartment numbers.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInAddresses) ||
+ !base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForApartmentNumbers)) {
+ return;
+ }
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name:", "name", "Pablo Diego Ruiz y Picasso",
+ "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Street name:", "street_name", "Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("House number:", "house_number", "21", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Apartment", "apartment", "101", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+
+ EXPECT_EQ(results[0]->GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16("21"));
+ EXPECT_EQ(results[0]->GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16("Laussat St"));
+ EXPECT_EQ(results[0]->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
+ base::ASCIIToUTF16("21 Laussat St APT 101"));
+ EXPECT_EQ(results[0]->GetRawInfo(ADDRESS_HOME_APT_NUM),
+ base::ASCIIToUTF16("101"));
+ EXPECT_EQ(results[0]->GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kObserved);
+ EXPECT_EQ(results[0]->GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kObserved);
+ EXPECT_EQ(results[0]->GetVerificationStatus(ADDRESS_HOME_STREET_ADDRESS),
+ structured_address::VerificationStatus::kFormatted);
+}
TEST_P(FormDataImporterTest,
ImportStructuredAddressProfile_GermanStreetNameAndHouseNumber) {
// This test is only applicable if structured addresses are enabled.
@@ -446,7 +514,7 @@ TEST_P(FormDataImporterTest,
test::CreateTestFormField("Zip:", "zip", "80992", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
const std::vector<AutofillProfile*>& results =
@@ -494,7 +562,7 @@ TEST_P(FormDataImporterTest, ImportStructuredNameAddressProfile) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
const std::vector<AutofillProfile*>& results =
@@ -517,6 +585,10 @@ TEST_P(FormDataImporterTest, ImportStructuredNameAddressProfile) {
}
TEST_P(FormDataImporterTest, ImportAddressProfiles) {
+ base::test::ScopedFeatureList dependent_locality_feature;
+ dependent_locality_feature.InitAndEnableFeature(
+ features::kAutofillEnableDependentLocalityParsing);
+
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -533,6 +605,9 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles) {
test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
&field);
form.fields.push_back(field);
+ test::CreateTestFormField("Neighborhood:", "neighborhood", "Nob Hill", "text",
+ &field);
+ form.fields.push_back(field);
test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("State:", "state", "California", "text", &field);
@@ -540,14 +615,14 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
- "San Francisco", "California", "94102", nullptr,
- nullptr);
+ "Nob Hill", "San Francisco", "California", "94102",
+ nullptr, nullptr);
const std::vector<AutofillProfile*>& results =
personal_data_manager_->GetProfiles();
ASSERT_EQ(1U, results.size());
@@ -578,7 +653,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfileFromUnifiedSection) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
// Assign the address field another section than the other fields.
form_structure.field(3)->section = "another_section";
@@ -619,7 +694,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_BadEmail) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
@@ -650,7 +725,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_TwoEmails) {
"example@example.com", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
@@ -681,12 +756,127 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) {
&field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
}
+// Tests that multiple phone numbers do not block profile import and the first
+// one is saved.
+TEST_P(FormDataImporterTest, ImportAddressProfiles_MultiplePhoneNumbers) {
+ base::test::ScopedFeatureList enable_import_when_multiple_phones_feature;
+ enable_import_when_multiple_phones_feature.InitAndEnableFeature(
+ features::kAutofillEnableImportWhenMultiplePhoneNumbers);
+
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 1:", "phone1", "+16505550000", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 2:", "phone2", "+14155551234", "text",
+ &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
+ nullptr, "21 Laussat St", nullptr, "San Francisco",
+ "California", "94102", nullptr, "1 650-555-0000");
+
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, expected.Compare(*results[0]));
+}
+
+// Tests that multiple phone numbers do not block profile import and the first
+// one is saved.
+TEST_P(FormDataImporterTest,
+ ImportAddressProfiles_MultiplePhoneNumbersSplitAcrossMultipleFields) {
+ base::test::ScopedFeatureList enable_import_when_multiple_phones_feature;
+ enable_import_when_multiple_phones_feature.InitAndEnableFeature(
+ features::kAutofillEnableImportWhenMultiplePhoneNumbers);
+
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 1:", "home_phone_area_code1", "650", "text",
+ &field);
+ field.max_length = 3;
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 1:", "home_phone_prefix1", "555", "text",
+ &field);
+ field.max_length = 3;
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 1:", "home_phone_suffix1", "0000", "text",
+ &field);
+ field.max_length = 4;
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 2:", "home_phone_area_code2", "202", "text",
+ &field);
+ field.max_length = 3;
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 2:", "home_phone_prefix2", "555", "text",
+ &field);
+ field.max_length = 3;
+ form.fields.push_back(field);
+ test::CreateTestFormField("Phone 2:", "home_phone_suffix2", "1234", "text",
+ &field);
+ field.max_length = 4;
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
+ nullptr, "21 Laussat St", nullptr, "San Francisco",
+ "California", "94102", nullptr, "(650) 555-0000");
+
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, expected.Compare(*results[0]));
+}
+
// Tests that not enough filled fields will result in not importing an address.
TEST_P(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) {
FormData form;
@@ -703,7 +893,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) {
"4111 1111 1111 1111", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
@@ -731,7 +921,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MinimumAddressUSA) {
test::CreateTestFormField("Country:", "country", "USA", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
@@ -758,7 +948,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGB) {
&field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
@@ -780,7 +970,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGI) {
test::CreateTestFormField("Country:", "country", "Gibraltar", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
@@ -820,7 +1010,7 @@ TEST_P(FormDataImporterTest,
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -833,9 +1023,7 @@ TEST_P(FormDataImporterTest,
EXPECT_EQ(0, expected.Compare(*results[0]));
}
-// Test that a form is imported correctly even if some fields are not
-// focusable.
-TEST_P(FormDataImporterTest, ImportAddressProfiles_WithUnFocussableFields) {
+TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -857,8 +1045,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_WithUnFocussableFields) {
form.fields.push_back(field);
test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
-
- // Set this field to be not focusable.
+ // Set this field to be unfocusable.
field.is_focusable = false;
form.fields.push_back(field);
@@ -869,8 +1056,20 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_WithUnFocussableFields) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
+
+ // Verify the status quo that the form is not imported with the unfocusable
+ // fields.
+ // TODO(crbug.com/1101280): Remove once feature is launched.
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillProfileImportFromUnfocusableFields);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
+ // Activate the feature and test again.
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillProfileImportFromUnfocusableFields);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -909,7 +1108,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -949,7 +1148,7 @@ TEST_P(FormDataImporterTest,
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -985,7 +1184,7 @@ TEST_P(FormDataImporterTest,
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1042,7 +1241,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1116,7 +1315,7 @@ TEST_P(FormDataImporterTest,
// Still able to do the import.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1198,7 +1397,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// Only two are saved.
@@ -1252,7 +1451,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1299,7 +1498,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
const std::vector<AutofillProfile*>& results2 =
@@ -1339,7 +1538,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1377,7 +1576,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
const std::vector<AutofillProfile*>& results2 =
@@ -1424,7 +1623,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1463,7 +1662,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
const std::vector<AutofillProfile*>& results2 =
@@ -1503,7 +1702,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_InsufficientAddress) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure1);
// Since no refresh is expected, reload the data from the database to make
@@ -1559,7 +1758,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// Expect that no new profile is saved.
@@ -1576,7 +1775,7 @@ TEST_P(FormDataImporterTest,
form.fields[0] = field;
FormStructure form_structure2(form);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
@@ -1606,7 +1805,7 @@ TEST_P(FormDataImporterTest,
NAME_FIRST, base::ASCIIToUTF16("Marion"),
structured_address::VerificationStatus::kParsed);
profile.SetRawInfoWithVerificationStatus(
- NAME_FIRST, base::ASCIIToUTF16("Mitchell"),
+ NAME_MIDDLE, base::ASCIIToUTF16("Mitchell"),
structured_address::VerificationStatus::kParsed);
base::RunLoop run_loop;
@@ -1641,7 +1840,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// The form submission should result in a change of name structure.
@@ -1668,7 +1867,7 @@ TEST_P(FormDataImporterTest,
form.fields[0] = field;
FormStructure form_structure2(form);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
@@ -1740,7 +1939,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// The form submission should result in a change of the address structure.
@@ -1791,7 +1990,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
// Since no refresh is expected, reload the data from the database to make
@@ -1838,7 +2037,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_LocalizedCountryName) {
// Verify that the country code is not determined from the country value if
// the page language is not set.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
@@ -1893,7 +2092,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1940,7 +2139,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
// Since no refresh is expected, reload the data from the database to make
@@ -1963,7 +2162,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_Valid) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::HistogramTester histogram_tester;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
@@ -1993,7 +2192,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_InvalidCardNumber) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::HistogramTester histogram_tester;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
@@ -2019,7 +2218,7 @@ TEST_P(FormDataImporterTest,
AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "", "");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::HistogramTester histogram_tester;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
@@ -2039,7 +2238,7 @@ TEST_P(FormDataImporterTest,
"2000");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::HistogramTester histogram_tester;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
@@ -2071,7 +2270,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) {
form.fields[2].option_contents = contents;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::HistogramTester histogram_tester;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
@@ -2102,7 +2301,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_TwoValidCards) {
"2999");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2125,7 +2324,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_TwoValidCards) {
AddFullCreditCardForm(&form2, "", "5500 0000 0000 0004", "02", "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
@@ -2254,7 +2453,7 @@ TEST_P(FormDataImporterTest,
// The card should not be offered to be saved locally because the feature flag
// is disabled.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2285,7 +2484,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_DuplicateServerCards_FullCard) {
// The card should not be offered to be saved locally because it only matches
// the full server card.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2300,7 +2499,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2325,7 +2524,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) {
/* different year */ "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
EXPECT_FALSE(imported_credit_card2);
@@ -2352,7 +2551,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2377,7 +2576,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) {
/* different year */ "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2,
/* should_return_local_card= */ true,
@@ -2407,7 +2606,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
@@ -2432,7 +2631,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) {
"2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_FALSE(
ImportCreditCard(form_structure2, false, &imported_credit_card2));
@@ -2461,7 +2660,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
"2999");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2486,7 +2685,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
"4111-1111-1111-1111", "01", "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
EXPECT_FALSE(imported_credit_card2);
@@ -2513,7 +2712,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
/* no year */ nullptr);
FormStructure form_structure3(form3);
- form_structure3.DetermineHeuristicTypes();
+ form_structure3.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card3;
EXPECT_FALSE(
ImportCreditCard(form_structure3, false, &imported_credit_card3));
@@ -2557,7 +2756,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) {
/* different year */ "2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
@@ -2600,7 +2799,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_SameCardWithSeparators) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
@@ -2642,7 +2841,7 @@ TEST_P(FormDataImporterTest,
/* different year */ "2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2682,7 +2881,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -2706,7 +2905,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(form_data_importer_->ImportFormData(
form_structure2, /*profile_autofill_enabled=*/true,
@@ -2746,7 +2945,7 @@ TEST_P(FormDataImporterTest,
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form3.fields.push_back(field);
FormStructure form_structure3(form3);
- form_structure3.DetermineHeuristicTypes();
+ form_structure3.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card3;
EXPECT_TRUE(form_data_importer_->ImportFormData(
form_structure3, /*profile_autofill_enabled=*/true,
@@ -2770,7 +2969,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -2809,7 +3008,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -2848,7 +3047,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -2886,7 +3085,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -2911,7 +3110,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -2938,7 +3137,7 @@ TEST_P(
"1999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -2981,7 +3180,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -3030,7 +3229,7 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -3112,7 +3311,7 @@ TEST_P(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::RunLoop run_loop;
@@ -3196,7 +3395,7 @@ TEST_P(FormDataImporterTest, ImportFormData_TwoAddressesNameFirst) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// Test that both addresses have been saved.
@@ -3235,7 +3434,7 @@ TEST_P(FormDataImporterTest, ImportFormData_AddressesDisabledOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -3293,7 +3492,7 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -3355,7 +3554,7 @@ TEST_P(FormDataImporterTest, ImportFormData_AddressCreditCardDisabled) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3412,7 +3611,7 @@ TEST_P(FormDataImporterTest, DontDuplicateMaskedServerCard) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3451,7 +3650,7 @@ TEST_P(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
// Still returns true because the credit card import was successful.
@@ -3487,7 +3686,7 @@ TEST_P(FormDataImporterTest,
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -3536,7 +3735,7 @@ TEST_P(FormDataImporterTest, DontDuplicateFullServerCard) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3581,7 +3780,7 @@ TEST_P(FormDataImporterTest,
base::HistogramTester histogram_tester;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3630,7 +3829,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3676,7 +3875,7 @@ TEST_P(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3723,7 +3922,7 @@ TEST_P(
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_TRUE(form_data_importer_->ImportFormData(
@@ -3769,7 +3968,7 @@ TEST_P(FormDataImporterTest,
base::HistogramTester histogram_tester;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3818,7 +4017,7 @@ TEST_P(FormDataImporterTest,
base::HistogramTester histogram_tester;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3868,7 +4067,7 @@ TEST_P(FormDataImporterTest,
base::HistogramTester histogram_tester;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
base::Optional<std::string> imported_upi_id;
EXPECT_FALSE(form_data_importer_->ImportFormData(
@@ -3892,7 +4091,7 @@ TEST_P(FormDataImporterTest, ImportUpiId) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card; // Discarded.
base::Optional<std::string> imported_upi_id;
@@ -3917,7 +4116,7 @@ TEST_P(FormDataImporterTest, ImportUpiIdDisabled) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card; // Discarded.
base::Optional<std::string> imported_upi_id;
@@ -3941,7 +4140,7 @@ TEST_P(FormDataImporterTest, ImportUpiIdIgnoreNonUpiId) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card; // Discarded.
base::Optional<std::string> imported_upi_id;
@@ -3955,10 +4154,13 @@ TEST_P(FormDataImporterTest, ImportUpiIdIgnoreNonUpiId) {
EXPECT_FALSE(imported_upi_id.has_value());
}
-// Runs the suite with the feature |kAutofillSupportForMoreStructuredNames| and
-// |kAutofillSupportForMoreStructuredAddresses| enabled and disabled.
+// Runs the suite with the feature |kAutofillSupportForMoreStructuredNames|,
+// |kAutofillSupportForMoreStructuredAddresses| and
+// |kAutofillEnableSupportForApartmentNumbers| enabled and disabled.
INSTANTIATE_TEST_SUITE_P(,
FormDataImporterTest,
- testing::Combine(testing::Bool(), testing::Bool()));
+ testing::Combine(testing::Bool(),
+ testing::Bool(),
+ testing::Bool()));
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.cc b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
index 6ed67749e2f..e9e494e023a 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
@@ -38,6 +38,9 @@ bool SetFieldAndAdvanceCursor(AutofillScanner* scanner, AutofillField** field) {
const int AddressField::kZipCodeMatchType =
MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER;
+const int AddressField::kDependentLocalityMatchType =
+ MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
+
// Select fields are allowed here. This occurs on top-100 site rediff.com.
const int AddressField::kCityMatchType =
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
@@ -45,9 +48,10 @@ const int AddressField::kCityMatchType =
const int AddressField::kStateMatchType =
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
-std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
- LogManager* log_manager) {
+std::unique_ptr<FormField> AddressField::Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ LogManager* log_manager) {
if (scanner->IsEnd())
return nullptr;
@@ -58,21 +62,25 @@ std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
base::string16 attention_ignored = UTF8ToUTF16(kAttentionIgnoredRe);
base::string16 region_ignored = UTF8ToUTF16(kRegionIgnoredRe);
- // In JSON : EMAIL_ADDRESS
- auto& patterns_email = PatternProvider::GetInstance().GetMatchPatterns(
- "EMAIL_ADDRESS", page_language);
- // In JSON : ADDRESS_LOOKUP
- auto& patterns_al = PatternProvider::GetInstance().GetMatchPatterns(
- "ADDRESS_LOOKUP", page_language);
- // In JSON : ADDRESS_NAME_IGNORED
- auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
- "ADDRESS_NAME_IGNORED", page_language);
- // In JSON : ATTENTION_IGNORED
- auto& patterns_ai = PatternProvider::GetInstance().GetMatchPatterns(
- "ATTENTION_IGNORED", page_language);
- // In JSON : REGION_IGNORED
- auto& patterns_ri = PatternProvider::GetInstance().GetMatchPatterns(
- "REGION_IGNORED", page_language);
+ const std::vector<MatchingPattern>& email_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("EMAIL_ADDRESS",
+ page_language);
+
+ const std::vector<MatchingPattern>& address_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_LOOKUP",
+ page_language);
+
+ const std::vector<MatchingPattern>& address_ignore_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_NAME_IGNORED",
+ page_language);
+
+ const std::vector<MatchingPattern>& attention_ignore_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ATTENTION_IGNORED",
+ page_language);
+
+ const std::vector<MatchingPattern>& region_ignore_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("REGION_IGNORED",
+ page_language);
// Allow address fields to appear in any order.
size_t begin_trailing_non_labeled_fields = 0;
@@ -80,29 +88,30 @@ std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
while (!scanner->IsEnd()) {
const size_t cursor = scanner->SaveCursor();
// Ignore "Address Lookup" field. http://crbug.com/427622
- if (ParseField(scanner, base::UTF8ToUTF16(kAddressLookupRe), patterns_al,
- nullptr, {log_manager, "kAddressLookupRe"}) ||
+ if (ParseField(scanner, base::UTF8ToUTF16(kAddressLookupRe),
+ address_patterns, nullptr,
+ {log_manager, "kAddressLookupRe"}) ||
ParseField(scanner, base::UTF8ToUTF16(kAddressNameIgnoredRe),
- patterns_ni, nullptr,
+ address_ignore_patterns, nullptr,
{log_manager, "kAddressNameIgnoreRe"})) {
continue;
// Ignore email addresses.
} else if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
MATCH_DEFAULT | MATCH_TEXT_AREA,
- patterns_email, nullptr,
+ email_patterns, nullptr,
{log_manager, "kEmailRe"},
{.augment_types = MATCH_TEXT_AREA})) {
continue;
} else if (address_field->ParseAddress(scanner, page_language) ||
- address_field->ParseCityStateCountryZipCode(scanner,
- page_language) ||
+ address_field->ParseDependentLocalityCityStateCountryZipCode(
+ scanner, page_language) ||
address_field->ParseCompany(scanner, page_language)) {
has_trailing_non_labeled_fields = false;
continue;
- } else if (ParseField(scanner, attention_ignored, patterns_ai, nullptr,
- {log_manager, "kAttentionIgnoredRe"}) ||
- ParseField(scanner, region_ignored, patterns_ri, nullptr,
- {log_manager, "kRegionIgnoredRe"})) {
+ } else if (ParseField(scanner, attention_ignored, attention_ignore_patterns,
+ nullptr, {log_manager, "kAttentionIgnoredRe"}) ||
+ ParseField(scanner, region_ignored, region_ignore_patterns,
+ nullptr, {log_manager, "kRegionIgnoredRe"})) {
// We ignore the following:
// * Attention.
// * Province/Region/Other.
@@ -135,7 +144,8 @@ std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
address_field->street_address_ || address_field->city_ ||
address_field->state_ || address_field->zip_ || address_field->zip4_ ||
address_field->street_name_ || address_field->house_number_ ||
- address_field->country_) {
+ address_field->country_ || address_field->apartment_number_ ||
+ address_field->dependent_locality_) {
// Don't slurp non-labeled fields at the end into the address.
if (has_trailing_non_labeled_fields)
scanner->RewindTo(begin_trailing_non_labeled_fields);
@@ -168,6 +178,8 @@ void AddressField::AddClassifications(
field_candidates);
AddClassification(street_address_, ADDRESS_HOME_STREET_ADDRESS,
kBaseAddressParserScore, field_candidates);
+ AddClassification(dependent_locality_, ADDRESS_HOME_DEPENDENT_LOCALITY,
+ kBaseAddressParserScore, field_candidates);
AddClassification(city_, ADDRESS_HOME_CITY, kBaseAddressParserScore,
field_candidates);
AddClassification(state_, ADDRESS_HOME_STATE, kBaseAddressParserScore,
@@ -180,22 +192,26 @@ void AddressField::AddClassifications(
kBaseAddressParserScore, field_candidates);
AddClassification(street_name_, ADDRESS_HOME_STREET_NAME,
kBaseAddressParserScore, field_candidates);
+ AddClassification(apartment_number_, ADDRESS_HOME_APT_NUM,
+ kBaseAddressParserScore, field_candidates);
}
bool AddressField::ParseCompany(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (company_)
return false;
- // In JSON : COMPANY
- auto& patterns_c =
- PatternProvider::GetInstance().GetMatchPatterns("COMPANY", page_language);
- return ParseField(scanner, UTF8ToUTF16(kCompanyRe), patterns_c, &company_,
- {log_manager_, "kCompanyRe"});
+ const std::vector<MatchingPattern>& company_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("COMPANY_NAME",
+ page_language);
+
+ return ParseField(scanner, UTF8ToUTF16(kCompanyRe), company_patterns,
+ &company_, {log_manager_, "kCompanyRe"});
}
-bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner,
- const std::string& page_language) {
+bool AddressField::ParseAddressFieldSequence(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language) {
// Search for a sequence of a street name field followed by a house number
// field. Only if both are found in an abitrary order, the parsing is
// considered successful.
@@ -207,44 +223,62 @@ bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner,
}
const size_t cursor_position = scanner->CursorPosition();
- // In JSON : ---- maybe ADDRESS_LINE1(2,3)
- auto& patterns_s = PatternProvider::GetInstance().GetMatchPatterns(
- ADDRESS_HOME_STREET_NAME, page_language);
- // In JSON : ----
- auto& patterns_h = PatternProvider::GetInstance().GetMatchPatterns(
- ADDRESS_HOME_HOUSE_NUMBER, page_language);
+
+ const std::vector<MatchingPattern>& street_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(ADDRESS_HOME_STREET_NAME,
+ page_language);
+
+ const std::vector<MatchingPattern>& house_number_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(ADDRESS_HOME_HOUSE_NUMBER,
+ page_language);
+ const std::vector<MatchingPattern>& apartment_number_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(ADDRESS_HOME_APT_NUM,
+ page_language);
while (!scanner->IsEnd()) {
if (!street_name_ &&
ParseFieldSpecifics(scanner, UTF8ToUTF16(kStreetNameRe), MATCH_DEFAULT,
- patterns_s, &street_name_,
+ street_name_patterns, &street_name_,
{log_manager_, "kStreetNameRe"})) {
continue;
}
if (!house_number_ &&
- ParseFieldSpecifics(scanner, UTF8ToUTF16(kHouseNumberRe), MATCH_DEFAULT,
- patterns_h, &house_number_,
+ ParseFieldSpecifics(scanner, UTF8ToUTF16(kHouseNumberRe),
+ MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE,
+ house_number_patterns, &house_number_,
{log_manager_, "kHouseNumberRe"})) {
continue;
}
+ // TODO(crbug.com/1153715): Remove finch guard once launched.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForApartmentNumbers) &&
+ !apartment_number_ &&
+ ParseFieldSpecifics(scanner, UTF8ToUTF16(kApartmentNumberRe),
+ MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE,
+ apartment_number_patterns, &apartment_number_,
+ {log_manager_, "kApartmentNumberRe"})) {
+ continue;
+ }
+
break;
}
+ // The street name and house number are non-optional.
if (street_name_ && house_number_)
return true;
- // Reset both fields in case one of them was found.
- if (street_name_ || house_number_) {
- street_name_ = nullptr;
- house_number_ = nullptr;
- }
+ // Reset all fields if the non-optional requirements could not be met.
+ street_name_ = nullptr;
+ house_number_ = nullptr;
+ apartment_number_ = nullptr;
+
scanner->RewindTo(cursor_position);
return false;
}
bool AddressField::ParseAddress(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (street_name_ && house_number_) {
return false;
}
@@ -253,7 +287,7 @@ bool AddressField::ParseAddress(AutofillScanner* scanner,
}
bool AddressField::ParseAddressLines(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
// We only match the string "address" in page text, not in element names,
// because sometimes every element in a group of address fields will have
// a name containing the string "address"; for example, on the page
@@ -267,23 +301,26 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
base::string16 pattern = UTF8ToUTF16(kAddressLine1Re);
base::string16 label_pattern = UTF8ToUTF16(kAddressLine1LabelRe);
- // In JSON : ADDRESS_LINE_1
- auto& patterns_l1 = PatternProvider::GetInstance().GetMatchPatterns(
- "ADDRESS_LINE_1", page_language);
- if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, patterns_l1,
- &address1_, {log_manager_, "kAddressLine1Re"}) &&
+ const std::vector<MatchingPattern>& address_line1_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_LINE_1",
+ page_language);
+
+ if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT,
+ address_line1_patterns, &address1_,
+ {log_manager_, "kAddressLine1Re"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- patterns_l1, &address1_,
+ address_line1_patterns, &address1_,
{log_manager_, "kAddressLine1LabelRe"}) &&
!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_TEXT_AREA,
- patterns_l1, &street_address_,
+ address_line1_patterns, &street_address_,
{log_manager_, "kAddressLine1Re"},
{.augment_types = MATCH_TEXT_AREA}) &&
- !ParseFieldSpecifics(
- scanner, label_pattern, MATCH_LABEL | MATCH_TEXT_AREA, patterns_l1,
- &street_address_, {log_manager_, "kAddressLine1LabelRe"},
- {.augment_types = MATCH_TEXT_AREA}))
+ !ParseFieldSpecifics(scanner, label_pattern,
+ MATCH_LABEL | MATCH_TEXT_AREA,
+ address_line1_patterns, &street_address_,
+ {log_manager_, "kAddressLine1LabelRe"},
+ {.augment_types = MATCH_TEXT_AREA}))
return false;
if (street_address_)
@@ -294,32 +331,29 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
// discussion on https://codereview.chromium.org/741493003/
pattern = UTF8ToUTF16(kAddressLine2Re);
label_pattern = UTF8ToUTF16(kAddressLine2LabelRe);
- // auto& patternsL2 = PatternProvider::GetInstance().GetMatchPatterns(
- // "ADDRESS_HOME_LINE2", page_language);
- // auto& patternsSA = PatternProvider::GetInstance().GetMatchPatterns(
- // "ADDRESS_HOME_STREET_ADDRESS", page_language);
-
- // In JSON : ADDRESS_LINE_2
- auto& patterns_l2 = PatternProvider::GetInstance().GetMatchPatterns(
- "ADDRESS_LINE_2", page_language);
- // In JSON : ADDRESS_LINE_EXTRA
- auto& patterns_le = PatternProvider::GetInstance().GetMatchPatterns(
- "ADDRESS_LINE_EXTRA", page_language);
-
- if (!ParseField(scanner, pattern, patterns_l2, &address2_,
+
+ const std::vector<MatchingPattern>& address_line2_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_LINE_2",
+ page_language);
+
+ if (!ParseField(scanner, pattern, address_line2_patterns, &address2_,
{log_manager_, "kAddressLine2Re"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- patterns_l2, &address2_,
+ address_line2_patterns, &address2_,
{log_manager_, "kAddressLine2LabelRe"}))
return true;
+ const std::vector<MatchingPattern>& address_line_extra_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_LINE_EXTRA",
+ page_language);
+
// Optionally parse address line 3. This uses the same label regexp as
// address 2 above.
pattern = UTF8ToUTF16(kAddressLinesExtraRe);
- if (!ParseField(scanner, pattern, patterns_le, &address3_,
+ if (!ParseField(scanner, pattern, address_line_extra_patterns, &address3_,
{log_manager_, "kAddressLinesExtraRe"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- patterns_l2, &address3_,
+ address_line2_patterns, &address3_,
{log_manager_, "kAddressLine2LabelRe"}))
return true;
@@ -329,7 +363,7 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
// Since these are rare, don't bother considering unlabeled lines as extra
// address lines.
pattern = UTF8ToUTF16(kAddressLinesExtraRe);
- while (ParseField(scanner, pattern, patterns_le, nullptr,
+ while (ParseField(scanner, pattern, address_line_extra_patterns, nullptr,
{log_manager_, "kAddressLinesExtraRe"})) {
// Consumed a surplus line, try for another.
}
@@ -337,20 +371,20 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
}
bool AddressField::ParseCountry(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (country_)
return false;
- // In JSON : COUNTRY
- auto& patterns_c =
+ const std::vector<MatchingPattern>& country_patterns =
PatternProvider::GetInstance().GetMatchPatterns("COUNTRY", page_language);
- auto& patterns_cl = PatternProvider::GetInstance().GetMatchPatterns(
- "COUNTRY_LOCATION", page_language);
+ const std::vector<MatchingPattern>& country_patternsl =
+ PatternProvider::GetInstance().GetMatchPatterns("COUNTRY_LOCATION",
+ page_language);
scanner->SaveCursor();
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kCountryRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- patterns_c, &country_,
+ country_patterns, &country_,
{log_manager_, "kCountryRe"})) {
return true;
}
@@ -360,56 +394,70 @@ bool AddressField::ParseCountry(AutofillScanner* scanner,
scanner->Rewind();
return ParseFieldSpecifics(
scanner, UTF8ToUTF16(kCountryLocationRe),
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, patterns_cl,
+ MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, country_patternsl,
&country_, {log_manager_, "kCountryLocationRe"});
}
bool AddressField::ParseZipCode(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (zip_)
return false;
- // auto& patternsZ = PatternProvider::GetInstance().GetMatchPatterns(
- // "ADDRESS_HOME_ZIP", page_language);
- // In JSON : ZIP_CODE
- auto& patterns_z = PatternProvider::GetInstance().GetMatchPatterns(
- "ZIP_CODE", page_language);
- // In JSON : ZIP_4
- auto& patterns_z4 =
+ const std::vector<MatchingPattern>& zip_code_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ZIP_CODE",
+ page_language);
+
+ const std::vector<MatchingPattern>& four_digit_zip_code_patterns =
PatternProvider::GetInstance().GetMatchPatterns("ZIP_4", page_language);
if (!ParseFieldSpecifics(scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType,
- patterns_z, &zip_, {log_manager_, "kZipCodeRe"})) {
+ zip_code_patterns, &zip_,
+ {log_manager_, "kZipCodeRe"})) {
return false;
}
// Look for a zip+4, whose field name will also often contain
// the substring "zip".
ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType,
- patterns_z4, &zip4_, {log_manager_, "kZip4Re"});
+ four_digit_zip_code_patterns, &zip4_,
+ {log_manager_, "kZip4Re"});
return true;
}
+bool AddressField::ParseDependentLocality(AutofillScanner* scanner,
+ const LanguageCode& page_language) {
+ const bool is_enabled_dependent_locality_parsing =
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableDependentLocalityParsing);
+ // TODO(crbug.com/1157405) Remove feature check when launched.
+ if (dependent_locality_ || !is_enabled_dependent_locality_parsing)
+ return false;
+
+ const std::vector<MatchingPattern>& dependent_locality_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_HOME_DEPENDENT_LOCALITY", page_language);
+ return ParseFieldSpecifics(scanner, UTF8ToUTF16(kDependentLocalityRe),
+ kDependentLocalityMatchType,
+ dependent_locality_patterns, &dependent_locality_,
+ {log_manager_, "kDependentLocalityRe"});
+}
+
bool AddressField::ParseCity(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (city_)
return false;
- // In JSON : CITY
- auto& patterns_city =
+ const std::vector<MatchingPattern>& city_patterns =
PatternProvider::GetInstance().GetMatchPatterns("CITY", page_language);
return ParseFieldSpecifics(scanner, UTF8ToUTF16(kCityRe), kCityMatchType,
- patterns_city, &city_, {log_manager_, "kCityRe"});
+ city_patterns, &city_, {log_manager_, "kCityRe"});
}
bool AddressField::ParseState(AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (state_)
return false;
- // auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
- // "ADDRESS_HOME_STATE", page_language);
- // In JSON : STATE
- auto& patterns_state =
+ const std::vector<MatchingPattern>& patterns_state =
PatternProvider::GetInstance().GetMatchPatterns("STATE", page_language);
return ParseFieldSpecifics(scanner, UTF8ToUTF16(kStateRe), kStateMatchType,
patterns_state, &state_,
@@ -449,28 +497,43 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
return RESULT_MATCH_NONE;
}
-bool AddressField::ParseCityStateCountryZipCode(
+bool AddressField::ParseDependentLocalityCityStateCountryZipCode(
AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
// The |scanner| is not pointing at a field.
if (scanner->IsEnd())
return false;
+ int num_of_missing_types = 0;
+ for (const auto* field :
+ {dependent_locality_, city_, state_, country_, zip_}) {
+ if (!field)
+ ++num_of_missing_types;
+ }
+
// All the field types have already been detected.
- if (city_ && state_ && country_ && zip_)
+ if (num_of_missing_types == 0)
return false;
// Exactly one field type is missing.
- if (state_ && country_ && zip_)
- return ParseCity(scanner, page_language);
- if (city_ && country_ && zip_)
- return ParseState(scanner, page_language);
- if (city_ && state_ && zip_)
- return ParseCountry(scanner, page_language);
- if (city_ && state_ && country_)
- return ParseZipCode(scanner, page_language);
+ if (num_of_missing_types == 1) {
+ if (!dependent_locality_)
+ return ParseDependentLocality(scanner, page_language);
+ if (!city_)
+ return ParseCity(scanner, page_language);
+ if (!state_)
+ return ParseState(scanner, page_language);
+ if (!country_)
+ return ParseCountry(scanner, page_language);
+ if (!zip_)
+ return ParseZipCode(scanner, page_language);
+ }
// Check for matches to both the name and the label.
+ ParseNameLabelResult dependent_locality_result =
+ ParseNameAndLabelForDependentLocality(scanner, page_language);
+ if (dependent_locality_result == RESULT_MATCH_NAME_LABEL)
+ return true;
ParseNameLabelResult city_result =
ParseNameAndLabelForCity(scanner, page_language);
if (city_result == RESULT_MATCH_NAME_LABEL)
@@ -488,63 +551,76 @@ bool AddressField::ParseCityStateCountryZipCode(
if (zip_result == RESULT_MATCH_NAME_LABEL)
return true;
+ int num_of_matches = 0;
+ for (const auto result : {dependent_locality_result, city_result,
+ state_result, country_result, zip_result}) {
+ if (result != RESULT_MATCH_NONE)
+ ++num_of_matches;
+ }
+
// Check if there is only one potential match.
- bool maybe_city = city_result != RESULT_MATCH_NONE;
- bool maybe_state = state_result != RESULT_MATCH_NONE;
- bool maybe_country = country_result != RESULT_MATCH_NONE;
- bool maybe_zip = zip_result != RESULT_MATCH_NONE;
- if (maybe_city && !maybe_state && !maybe_country && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (maybe_state && !maybe_city && !maybe_country && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (maybe_country && !maybe_city && !maybe_state && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &country_);
- if (maybe_zip && !maybe_city && !maybe_state && !maybe_country)
- return ParseZipCode(scanner, page_language);
+ if (num_of_matches == 1) {
+ if (dependent_locality_result != RESULT_MATCH_NONE)
+ return SetFieldAndAdvanceCursor(scanner, &dependent_locality_);
+ if (city_result != RESULT_MATCH_NONE)
+ return SetFieldAndAdvanceCursor(scanner, &city_);
+ if (state_result != RESULT_MATCH_NONE)
+ return SetFieldAndAdvanceCursor(scanner, &state_);
+ if (country_result != RESULT_MATCH_NONE)
+ return SetFieldAndAdvanceCursor(scanner, &country_);
+ if (zip_result != RESULT_MATCH_NONE)
+ return ParseZipCode(scanner, page_language);
+ }
// If there is a clash between the country and the state, set the type of
// the field to the country.
- if (maybe_state && maybe_country && !maybe_city && !maybe_zip)
+ if (num_of_matches == 2 && state_result != RESULT_MATCH_NONE &&
+ country_result != RESULT_MATCH_NONE)
return SetFieldAndAdvanceCursor(scanner, &country_);
- // Otherwise give the name priority over the label.
- if (city_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (state_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (country_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &country_);
- if (zip_result == RESULT_MATCH_NAME)
- return ParseZipCode(scanner, page_language);
-
- if (city_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (state_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (country_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &country_);
- if (zip_result == RESULT_MATCH_LABEL)
- return ParseZipCode(scanner, page_language);
+ // By default give the name priority over the label.
+ ParseNameLabelResult results_to_match[] = {RESULT_MATCH_NAME,
+ RESULT_MATCH_LABEL};
+ if (page_language == LanguageCode("tr") &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableLabelPrecedenceForTurkishAddresses)) {
+ // Give the label priority over the name to avoid misclassifications when
+ // the name has a misleading value (e.g. province field is named "city").
+ std::swap(results_to_match[0], results_to_match[1]);
+ }
+
+ for (const auto result : results_to_match) {
+ if (dependent_locality_result == result)
+ return SetFieldAndAdvanceCursor(scanner, &dependent_locality_);
+ if (city_result == result)
+ return SetFieldAndAdvanceCursor(scanner, &city_);
+ if (state_result == result)
+ return SetFieldAndAdvanceCursor(scanner, &state_);
+ if (country_result == result)
+ return SetFieldAndAdvanceCursor(scanner, &country_);
+ if (zip_result == result)
+ return ParseZipCode(scanner, page_language);
+ }
return false;
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForZipCode(
AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (zip_)
return RESULT_MATCH_NONE;
- // In JSON : ZIP_CODE
- auto& patterns_z = PatternProvider::GetInstance().GetMatchPatterns(
- "ZIP_CODE", page_language);
- // In JSON :
- auto& patterns_z4 =
+ const std::vector<MatchingPattern>& zip_code_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ZIP_CODE",
+ page_language);
+
+ const std::vector<MatchingPattern>& four_digit_zip_code_patterns =
PatternProvider::GetInstance().GetMatchPatterns("ZIP_4", page_language);
ParseNameLabelResult result = ParseNameAndLabelSeparately(
- scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, patterns_z, &zip_,
- {log_manager_, "kZipCodeRe"});
+ scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, zip_code_patterns,
+ &zip_, {log_manager_, "kZipCodeRe"});
if (result != RESULT_MATCH_NAME_LABEL || scanner->IsEnd())
return result;
@@ -565,33 +641,52 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForZipCode(
// Look for a zip+4, whose field name will also often contain
// the substring "zip".
ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType,
- patterns_z4, &zip4_, {log_manager_, "kZip4Re"});
+ four_digit_zip_code_patterns, &zip4_,
+ {log_manager_, "kZip4Re"});
}
return result;
}
+AddressField::ParseNameLabelResult
+AddressField::ParseNameAndLabelForDependentLocality(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language) {
+ const bool is_enabled_dependent_locality_parsing =
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableDependentLocalityParsing);
+ // TODO(crbug.com/1157405) Remove feature check when launched.
+ if (dependent_locality_ || !is_enabled_dependent_locality_parsing)
+ return RESULT_MATCH_NONE;
+
+ const std::vector<MatchingPattern>& dependent_locality_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_HOME_DEPENDENT_LOCALITY", page_language);
+ return ParseNameAndLabelSeparately(
+ scanner, UTF8ToUTF16(kDependentLocalityRe), kDependentLocalityMatchType,
+ dependent_locality_patterns, &dependent_locality_,
+ {log_manager_, "kDependentLocalityRe"});
+}
+
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCity(
AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (city_)
return RESULT_MATCH_NONE;
- // In JSON : CITY
- auto& patterns_city =
+ const std::vector<MatchingPattern>& city_patterns =
PatternProvider::GetInstance().GetMatchPatterns("CITY", page_language);
return ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kCityRe),
- kCityMatchType, patterns_city, &city_,
+ kCityMatchType, city_patterns, &city_,
{log_manager_, "kCityRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForState(
AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (state_)
return RESULT_MATCH_NONE;
- // In JSON : STATE
- auto& patterns_state =
+ const std::vector<MatchingPattern>& patterns_state =
PatternProvider::GetInstance().GetMatchPatterns("STATE", page_language);
return ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kStateRe),
kStateMatchType, patterns_state, &state_,
@@ -600,19 +695,20 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForState(
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
AutofillScanner* scanner,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (country_)
return RESULT_MATCH_NONE;
- // In JSON : COUNTRY
- auto& patterns_c =
+ const std::vector<MatchingPattern>& country_patterns =
PatternProvider::GetInstance().GetMatchPatterns("COUNTRY", page_language);
- auto& patterns_cl = PatternProvider::GetInstance().GetMatchPatterns(
- "COUNTRY_LOCATION", page_language);
+
+ const std::vector<MatchingPattern>& country_location_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("COUNTRY_LOCATION",
+ page_language);
ParseNameLabelResult country_result = ParseNameAndLabelSeparately(
scanner, UTF8ToUTF16(kCountryRe),
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH, patterns_c, &country_,
+ MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH, country_patterns, &country_,
{log_manager_, "kCountryRe"});
if (country_result != RESULT_MATCH_NONE)
return country_result;
@@ -621,8 +717,9 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
// "location". However, this only makes sense for select tags.
return ParseNameAndLabelSeparately(
scanner, UTF8ToUTF16(kCountryLocationRe),
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, patterns_cl,
- &country_, {log_manager_, "kCountryLocationRe"});
+ MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH,
+ country_location_patterns, &country_,
+ {log_manager_, "kCountryLocationRe"});
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.h b/chromium/components/autofill/core/browser/form_parsing/address_field.h
index 0ee62ee3853..820ac0b2f11 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.h
@@ -15,6 +15,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -25,16 +26,9 @@ class LogManager;
class AddressField : public FormField {
public:
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
-#if defined(UNIT_TEST)
- // Assign types to the fields for the testing purposes.
- void AddClassificationsForTesting(
- FieldCandidatesMap* field_candidates_for_testing) const {
- AddClassifications(field_candidates_for_testing);
- }
-#endif
protected:
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
@@ -51,47 +45,47 @@ class AddressField : public FormField {
static const int kZipCodeMatchType;
static const int kCityMatchType;
static const int kStateMatchType;
+ static const int kDependentLocalityMatchType;
explicit AddressField(LogManager* log_manager);
- bool ParseCompany(AutofillScanner* scanner, const std::string& page_language);
+ bool ParseCompany(AutofillScanner* scanner,
+ const LanguageCode& page_language);
- bool ParseAddress(AutofillScanner* scanner, const std::string& page_language);
+ bool ParseAddress(AutofillScanner* scanner,
+ const LanguageCode& page_language);
bool ParseAddressFieldSequence(AutofillScanner* scanner,
- const std::string& page_language);
+ const LanguageCode& page_language);
bool ParseAddressLines(AutofillScanner* scanner,
- const std::string& page_language);
+ const LanguageCode& page_language);
- bool ParseCountry(AutofillScanner* scanner, const std::string& page_language);
+ bool ParseCountry(AutofillScanner* scanner,
+ const LanguageCode& page_language);
- bool ParseZipCode(AutofillScanner* scanner, const std::string& page_language);
+ bool ParseZipCode(AutofillScanner* scanner,
+ const LanguageCode& page_language);
- bool ParseCity(AutofillScanner* scanner, const std::string& page_language);
+ bool ParseDependentLocality(AutofillScanner* scanner,
+ const LanguageCode& page_language);
- bool ParseState(AutofillScanner* scanner, const std::string& page_language);
+ bool ParseCity(AutofillScanner* scanner, const LanguageCode& page_language);
+
+ bool ParseState(AutofillScanner* scanner, const LanguageCode& page_language);
// Parses the current field pointed to by |scanner|, if it exists, and tries
- // to figure out whether the field's type: city, state, country, zip, or
- // none of those.
- bool ParseCityStateCountryZipCode(AutofillScanner* scanner,
- const std::string& page_language);
+ // to determine if the field's type corresponds to one of the following:
+ // dependent locality, city, state, country, zip, or none of those.
+ bool ParseDependentLocalityCityStateCountryZipCode(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language);
// Like ParseFieldSpecifics(), but applies |pattern| against the name and
// label of the current field separately. If the return value is
// RESULT_MATCH_NAME_LABEL, then |scanner| advances and |match| is filled if
// it is non-NULL. Otherwise |scanner| does not advance and |match| does not
// change.
- // ParseNameLabelResult ParseNameAndLabelSeparately(
- // AutofillScanner* scanner,
- // const base::string16& pattern,
- // int match_type,
- // AutofillField** match,
- // const RegExLogging& logging);
-
- // New version of function above using new structure MatchingPattern and
- // PatternProvider.
ParseNameLabelResult ParseNameAndLabelSeparately(
AutofillScanner* scanner,
const base::string16& pattern,
@@ -105,19 +99,23 @@ class AddressField : public FormField {
// Otherwise |scanner| rewinds and the field is cleared.
ParseNameLabelResult ParseNameAndLabelForZipCode(
AutofillScanner* scanner,
- const std::string& page_language);
+ const LanguageCode& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForDependentLocality(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language);
ParseNameLabelResult ParseNameAndLabelForCity(
AutofillScanner* scanner,
- const std::string& page_language);
+ const LanguageCode& page_language);
ParseNameLabelResult ParseNameAndLabelForCountry(
AutofillScanner* scanner,
- const std::string& page_language);
+ const LanguageCode& page_language);
ParseNameLabelResult ParseNameAndLabelForState(
AutofillScanner* scanner,
- const std::string& page_language);
+ const LanguageCode& page_language);
LogManager* log_manager_;
AutofillField* company_ = nullptr;
@@ -127,6 +125,8 @@ class AddressField : public FormField {
AutofillField* address2_ = nullptr;
AutofillField* address3_ = nullptr;
AutofillField* street_address_ = nullptr;
+ AutofillField* apartment_number_ = nullptr;
+ AutofillField* dependent_locality_ = nullptr;
AutofillField* city_ = nullptr;
AutofillField* state_ = nullptr;
AutofillField* zip_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc
index bc6e0908571..63c6258f716 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc
@@ -9,158 +9,57 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
-#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ASCIIToUTF16;
namespace autofill {
-class AddressFieldTest : public testing::Test {
+class AddressFieldTest : public FormFieldTest {
public:
AddressFieldTest() = default;
AddressFieldTest(const AddressFieldTest&) = delete;
AddressFieldTest& operator=(const AddressFieldTest&) = delete;
protected:
- // Downcast for tests.
- static std::unique_ptr<AddressField> Parse(AutofillScanner* scanner) {
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- std::unique_ptr<FormField> field =
- AddressField::Parse(scanner, /*page_language=*/"", nullptr);
- return std::unique_ptr<AddressField>(
- static_cast<AddressField*>(field.release()));
+ std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
+ const LanguageCode& page_language) override {
+ return AddressField::Parse(scanner, page_language, nullptr);
}
-
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<AddressField> field_;
- FieldCandidatesMap field_candidates_map_;
-
- // RAII object to mock the the PatternProvider.
- TestPatternProvider test_pattern_provider_;
};
TEST_F(AddressFieldTest, Empty) {
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
TEST_F(AddressFieldTest, NonParse) {
- list_.push_back(std::make_unique<AutofillField>());
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_EQ(nullptr, field_.get());
+ AddTextFormFieldData("", "", UNKNOWN_TYPE);
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
TEST_F(AddressFieldTest, ParseOneLineAddress) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Address");
- field.name = ASCIIToUTF16("address");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("addr1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map_[ASCIIToUTF16("addr1")].BestHeuristicType());
+ AddTextFormFieldData("address", "Address", ADDRESS_HOME_LINE1);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseTwoLineAddress) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Address");
- field.name = ASCIIToUTF16("address");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("addr1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("address2");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("addr2")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map_[ASCIIToUTF16("addr1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE2,
- field_candidates_map_[ASCIIToUTF16("addr2")].BestHeuristicType());
+ AddTextFormFieldData("address", "Address", ADDRESS_HOME_LINE1);
+ AddTextFormFieldData("address2", "Address", ADDRESS_HOME_LINE2);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseThreeLineAddress) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Address Line1");
- field.name = ASCIIToUTF16("Address1");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("addr1")));
-
- field.label = ASCIIToUTF16("Address Line2");
- field.name = ASCIIToUTF16("Address2");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("addr2")));
-
- field.label = ASCIIToUTF16("Address Line3");
- field.name = ASCIIToUTF16("Address3");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("addr3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map_[ASCIIToUTF16("addr1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE2,
- field_candidates_map_[ASCIIToUTF16("addr2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE3,
- field_candidates_map_[ASCIIToUTF16("addr3")].BestHeuristicType());
+ AddTextFormFieldData("Address1", "Address Line 1", ADDRESS_HOME_LINE1);
+ AddTextFormFieldData("Address1", "Address Line 2", ADDRESS_HOME_LINE2);
+ AddTextFormFieldData("Address1", "Address Line 3", ADDRESS_HOME_LINE3);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseStreetAddressFromTextArea) {
- FormFieldData field;
- field.form_control_type = "textarea";
-
- field.label = ASCIIToUTF16("Address");
- field.name = ASCIIToUTF16("address");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("addr")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS,
- field_candidates_map_[ASCIIToUTF16("addr")].BestHeuristicType());
+ AddFormFieldData("textarea", "address", "Address",
+ ADDRESS_HOME_STREET_ADDRESS);
+ ClassifyAndVerify();
}
// Tests that fields are classified as |ADDRESS_HOME_STREET_NAME| and
@@ -172,63 +71,40 @@ TEST_F(AddressFieldTest, ParseStreetNameAndHouseNumber) {
enabled.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInAddresses);
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Street");
- field.name = ASCIIToUTF16("street");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("street")));
-
- field.label = ASCIIToUTF16("House number");
- field.name = ASCIIToUTF16("house-number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("house")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("street")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_STREET_NAME,
- field_candidates_map_[ASCIIToUTF16("street")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("house")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_HOUSE_NUMBER,
- field_candidates_map_[ASCIIToUTF16("house")].BestHeuristicType());
+ AddTextFormFieldData("street", "Street", ADDRESS_HOME_STREET_NAME);
+ AddTextFormFieldData("house-number", "House number",
+ ADDRESS_HOME_HOUSE_NUMBER);
+ ClassifyAndVerify();
+}
+
+// Tests that fields are classified as |ADDRESS_HOME_STREET_NAME|, and
+// |ADDRESS_HOME_HOUSE_NUMBER| |ADDRESS_HOME_APT_NUM| when they are labeled
+// accordingly and all are present.
+TEST_F(AddressFieldTest, ParseStreetNameAndHouseNumberAndApartmentNumber) {
+ // TODO(crbug.com/1125978): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitWithFeatures(
+ {features::kAutofillEnableSupportForMoreStructureInAddresses,
+ features::kAutofillEnableSupportForApartmentNumbers},
+ {});
+
+ AddTextFormFieldData("street", "Street", ADDRESS_HOME_STREET_NAME);
+ AddTextFormFieldData("house-number", "House number",
+ ADDRESS_HOME_HOUSE_NUMBER);
+ AddTextFormFieldData("apartment", "apartment", ADDRESS_HOME_APT_NUM);
+ ClassifyAndVerify();
}
// Tests that the field is not classified as |ADDRESS_HOME_STREET_NAME| when
-// it is labeled accordingly but adjacent field classified as
+// it is labeled accordingly but an adjacent field classified as
// |ADDRESS_HOME_HOUSE_NUMBER| is absent.
TEST_F(AddressFieldTest, NotParseStreetNameWithoutHouseNumber) {
// TODO(crbug.com/1125978): Remove once launched.
base::test::ScopedFeatureList enabled;
enabled.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInAddresses);
-
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Street");
- field.name = ASCIIToUTF16("street");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("street")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
-
- if (!field_.get())
- return;
- field_->AddClassificationsForTesting(&field_candidates_map_);
- if (field_candidates_map_.empty())
- return;
-
- EXPECT_NE(ADDRESS_HOME_STREET_NAME,
- field_candidates_map_[ASCIIToUTF16("street")].BestHeuristicType());
+ AddTextFormFieldData("street", "Street", ADDRESS_HOME_LINE1);
+ ClassifyAndVerify();
}
// Tests that the field is not classified as |ADDRESS_HOME_HOUSE_NUMBER| when
@@ -240,246 +116,122 @@ TEST_F(AddressFieldTest, NotParseHouseNumberWithoutStreetName) {
enabled.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInAddresses);
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("House number");
- field.name = ASCIIToUTF16("house-number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("house")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
+ AddTextFormFieldData("house-number", "House number", UNKNOWN_TYPE);
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
- if (!field_.get())
- return;
- field_->AddClassificationsForTesting(&field_candidates_map_);
- if (field_candidates_map_.empty())
- return;
+// Tests that the dependent locality is correctly classified with
+// an unambiguous field name and label.
+TEST_F(AddressFieldTest, ParseDependentLocality) {
+ // TODO(crbug.com/1157405): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableDependentLocalityParsing);
- EXPECT_NE(ADDRESS_HOME_HOUSE_NUMBER,
- field_candidates_map_[ASCIIToUTF16("house")].BestHeuristicType());
+ AddTextFormFieldData("neighborhood", "Neighborhood",
+ ADDRESS_HOME_DEPENDENT_LOCALITY);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseCity) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("City");
- field.name = ASCIIToUTF16("city");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("city1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("city1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_CITY,
- field_candidates_map_[ASCIIToUTF16("city1")].BestHeuristicType());
+ AddTextFormFieldData("city", "City", ADDRESS_HOME_CITY);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseState) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("State");
- field.name = ASCIIToUTF16("state");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("state1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("state1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_STATE,
- field_candidates_map_[ASCIIToUTF16("state1")].BestHeuristicType());
+ AddTextFormFieldData("state", "State", ADDRESS_HOME_STATE);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseZip) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Zip");
- field.name = ASCIIToUTF16("zip");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("zip1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("zip1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_ZIP,
- field_candidates_map_[ASCIIToUTF16("zip1")].BestHeuristicType());
+ AddTextFormFieldData("zip", "Zip", ADDRESS_HOME_ZIP);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseStateAndZipOneLabel) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("State/Province, Zip/Postal Code");
- field.name = ASCIIToUTF16("state");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("state")));
-
- field.label = ASCIIToUTF16("State/Province, Zip/Postal Code");
- field.name = ASCIIToUTF16("zip");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("zip")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("state")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_STATE,
- field_candidates_map_[ASCIIToUTF16("state")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("zip")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_ZIP,
- field_candidates_map_[ASCIIToUTF16("zip")].BestHeuristicType());
+ AddTextFormFieldData("state", "State/Province, Zip/Postal Code",
+ ADDRESS_HOME_STATE);
+ AddTextFormFieldData("zip", "State/Province, Zip/Postal Code",
+ ADDRESS_HOME_ZIP);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseCountry) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Country");
- field.name = ASCIIToUTF16("country");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("country1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(
- ADDRESS_HOME_COUNTRY,
- field_candidates_map_[ASCIIToUTF16("country1")].BestHeuristicType());
+ AddTextFormFieldData("country", "Country", ADDRESS_HOME_COUNTRY);
+ ClassifyAndVerify();
}
TEST_F(AddressFieldTest, ParseCompany) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Company");
- field.name = ASCIIToUTF16("company");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("company1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("company1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(
- COMPANY_NAME,
- field_candidates_map_[ASCIIToUTF16("company1")].BestHeuristicType());
+ AddTextFormFieldData("company", "Company", COMPANY_NAME);
+ ClassifyAndVerify();
}
-// Tests that the city, state, country and zip-code fields are correctly
-// classfied with unambiguous field names and labels.
-TEST_F(AddressFieldTest, ParseCityStateCountryZipcodeTogether) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("City");
- field.name = ASCIIToUTF16("city");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("city1")));
-
- field.label = ASCIIToUTF16("State");
- field.name = ASCIIToUTF16("state");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("state1")));
-
- field.label = ASCIIToUTF16("Country");
- field.name = ASCIIToUTF16("country");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
-
- field.label = ASCIIToUTF16("Zip");
- field.name = ASCIIToUTF16("zip");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("zip1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("city1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_CITY,
- field_candidates_map_[ASCIIToUTF16("city1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("state1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_STATE,
- field_candidates_map_[ASCIIToUTF16("state1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("country1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(
- ADDRESS_HOME_COUNTRY,
- field_candidates_map_[ASCIIToUTF16("country1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("zip1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(ADDRESS_HOME_ZIP,
- field_candidates_map_[ASCIIToUTF16("zip1")].BestHeuristicType());
+// Tests that the dependent locality, city, state, country and zip-code
+// fields are correctly classfied with unambiguous field names and labels.
+TEST_F(AddressFieldTest,
+ ParseDependentLocalityCityStateCountryZipcodeTogether) {
+ // TODO(crbug.com/1157405): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableDependentLocalityParsing);
+
+ AddTextFormFieldData("neighborhood", "Neighborhood",
+ ADDRESS_HOME_DEPENDENT_LOCALITY);
+ AddTextFormFieldData("city", "City", ADDRESS_HOME_CITY);
+ AddTextFormFieldData("state", "State", ADDRESS_HOME_STATE);
+ AddTextFormFieldData("country", "Country", ADDRESS_HOME_COUNTRY);
+ AddTextFormFieldData("zip", "Zip", ADDRESS_HOME_ZIP);
+ ClassifyAndVerify();
}
// Tests that the field is classified as |ADDRESS_HOME_COUNTRY| when the field
// label contains 'Region'.
TEST_F(AddressFieldTest, ParseCountryLabelRegion) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Country/Region");
- field.name = ASCIIToUTF16("country");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("country1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(
- ADDRESS_HOME_COUNTRY,
- field_candidates_map_[ASCIIToUTF16("country1")].BestHeuristicType());
+ AddTextFormFieldData("country", "Country/Region", ADDRESS_HOME_COUNTRY);
+ ClassifyAndVerify();
}
// Tests that the field is classified as |ADDRESS_HOME_COUNTRY| when the field
// name contains 'region'.
TEST_F(AddressFieldTest, ParseCountryNameRegion) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Land");
- field.name = ASCIIToUTF16("client_region");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("country1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(
- ADDRESS_HOME_COUNTRY,
- field_candidates_map_[ASCIIToUTF16("country1")].BestHeuristicType());
+ AddTextFormFieldData("client_region", "Land", ADDRESS_HOME_COUNTRY);
+ ClassifyAndVerify();
+}
+
+// Tests that city and state fields are classified correctly when their names
+// contain keywords for different types. This is achieved by giving the priority
+// to the label over the name for pages in Turkish.
+TEST_F(AddressFieldTest, ParseTurkishCityStateWithLabelPrecedence) {
+ // TODO(crbug.com/1156315): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableLabelPrecedenceForTurkishAddresses);
+
+ AddTextFormFieldData("city", "Il", ADDRESS_HOME_STATE);
+ AddTextFormFieldData("county", "Ilce", ADDRESS_HOME_CITY);
+ ClassifyAndVerify(ParseResult::PARSED, LanguageCode("tr"));
+}
+
+// Tests that address name is not misclassified as address.
+TEST_F(AddressFieldTest, NotParseAddressName) {
+ AddTextFormFieldData("address", "Adres Başlığı", UNKNOWN_TYPE);
+ ClassifyAndVerify(ParseResult::NOT_PARSED, LanguageCode("tr"));
+}
+
+// Tests that the address components sequence in a label is classified
+// as |ADDRESS_HOME_LINE1|.
+TEST_F(AddressFieldTest, ParseAddressComponentsSequenceAsAddressLine1) {
+ AddTextFormFieldData("detail", "Улица, дом, квартира", ADDRESS_HOME_LINE1);
+ ClassifyAndVerify(ParseResult::PARSED, LanguageCode("ru"));
+}
+
+// Tests that the address components sequence in a label is classified
+// as |ADDRESS_HOME_STREET_ADDRESS|.
+TEST_F(AddressFieldTest, ParseAddressComponentsSequenceAsStreetAddress) {
+ AddFormFieldData("textarea", "detail",
+ "Mahalle, sokak, cadde ve diğer bilgilerinizi girin",
+ ADDRESS_HOME_STREET_ADDRESS);
+ ClassifyAndVerify(ParseResult::PARSED, LanguageCode("tr"));
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc
index ddd418eca54..33a4e9db8d4 100644
--- a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc
@@ -7,10 +7,10 @@
namespace autofill {
MatchingPattern::MatchingPattern() = default;
-MatchingPattern::MatchingPattern(const MatchingPattern& mp) = default;
-MatchingPattern& MatchingPattern::operator=(const MatchingPattern& mp) =
- default;
-
+MatchingPattern::MatchingPattern(const MatchingPattern&) = default;
+MatchingPattern& MatchingPattern::operator=(const MatchingPattern&) = default;
+MatchingPattern::MatchingPattern(MatchingPattern&&) = default;
+MatchingPattern& MatchingPattern::operator=(MatchingPattern&&) = default;
MatchingPattern::~MatchingPattern() = default;
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
index b24b5b5a5d7..1a4160c01aa 100644
--- a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
+++ b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
@@ -8,6 +8,8 @@
#include <base/optional.h>
#include <string>
+#include "components/autofill/core/common/language_code.h"
+
namespace autofill {
// A bit-field used for matching specific parts of a field in question.
@@ -45,17 +47,18 @@ constexpr int MATCH_DEFAULT = MATCH_ATTRIBUTES_DEFAULT | MATCH_INPUTS_DEFAULT;
// to recognize incorrect matches.
struct MatchingPattern {
MatchingPattern();
- MatchingPattern(const MatchingPattern& mp);
- MatchingPattern& operator=(const MatchingPattern& mp);
+ MatchingPattern(const MatchingPattern&);
+ MatchingPattern& operator=(const MatchingPattern&);
+ MatchingPattern(MatchingPattern&&);
+ MatchingPattern& operator=(MatchingPattern&&);
~MatchingPattern();
- std::string pattern_identifier;
+ LanguageCode language;
std::string positive_pattern;
- float positive_score = 1.1f;
- base::Optional<std::string> negative_pattern;
- int match_field_attributes;
- int match_field_input_types;
- std::string language;
+ std::string negative_pattern;
+ float positive_score = 1.1;
+ uint8_t match_field_attributes;
+ uint16_t match_field_input_types;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
index 27ee112a819..cb1ab38fd8d 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -24,6 +24,7 @@
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -83,7 +84,7 @@ bool FieldCanFitDataForFieldType(int max_length, ServerFieldType type) {
// static
std::unique_ptr<FormField> CreditCardField::Parse(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
if (scanner->IsEnd())
return nullptr;
@@ -91,18 +92,23 @@ std::unique_ptr<FormField> CreditCardField::Parse(
auto credit_card_field = std::make_unique<CreditCardField>(log_manager);
size_t saved_cursor = scanner->SaveCursor();
int nb_unknown_fields = 0;
+ bool cardholder_name_match_has_low_confidence = false;
- auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
- "NAME_ON_CARD", page_language);
- // In JSON : NAME_ON_CARD_CONTEXTUAL
- auto& patterns_cont = PatternProvider::GetInstance().GetMatchPatterns(
- "NAME_ON_CARD_CONTEXTUAL", page_language);
- // In JSON : LAST_NAME
- auto& patterns_nl = PatternProvider::GetInstance().GetMatchPatterns(
- "LAST_NAME", page_language);
- // In JSON : CARD_CVC
- auto& patterns_cvc = PatternProvider::GetInstance().GetMatchPatterns(
- CREDIT_CARD_VERIFICATION_CODE, page_language);
+ const std::vector<MatchingPattern>& name_on_card_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("NAME_ON_CARD",
+ page_language);
+
+ const std::vector<MatchingPattern>& name_on_card_contextual_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("NAME_ON_CARD_CONTEXTUAL",
+ page_language);
+
+ const std::vector<MatchingPattern>& last_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("LAST_NAME",
+ page_language);
+
+ const std::vector<MatchingPattern>& cvc_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_VERIFICATION_CODE, page_language);
// Credit card fields can appear in many different orders.
// We loop until no more credit card related fields are found, see |break| at
@@ -113,8 +119,8 @@ std::unique_ptr<FormField> CreditCardField::Parse(
break;
if (!credit_card_field->cardholder_) {
- if (ParseField(scanner, base::UTF8ToUTF16(kNameOnCardRe), patterns,
- &credit_card_field->cardholder_,
+ if (ParseField(scanner, base::UTF8ToUTF16(kNameOnCardRe),
+ name_on_card_patterns, &credit_card_field->cardholder_,
{log_manager, "kNameOnCardRe"})) {
continue;
}
@@ -128,8 +134,10 @@ std::unique_ptr<FormField> CreditCardField::Parse(
if (fields > 0 && !credit_card_field->expiration_month_ &&
ParseField(scanner, base::UTF8ToUTF16(kNameOnCardContextualRe),
- patterns_cont, &credit_card_field->cardholder_,
+ name_on_card_contextual_patterns,
+ &credit_card_field->cardholder_,
{log_manager, "kNameOnCardContextualRe"})) {
+ cardholder_name_match_has_low_confidence = true;
continue;
}
} else if (!credit_card_field->cardholder_last_) {
@@ -138,8 +146,8 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// and haven't yet parsed the expiration date (which usually appears at
// the end).
if (!credit_card_field->expiration_month_ &&
- ParseField(scanner, base::UTF8ToUTF16(kLastNameRe), patterns_nl,
- &credit_card_field->cardholder_last_,
+ ParseField(scanner, base::UTF8ToUTF16(kLastNameRe),
+ last_name_patterns, &credit_card_field->cardholder_last_,
{log_manager, "kLastNameRe"})) {
continue;
}
@@ -166,7 +174,7 @@ std::unique_ptr<FormField> CreditCardField::Parse(
if (!credit_card_field->verification_ &&
ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardCvcRe),
- kMatchNumTelAndPwd, patterns_cvc,
+ kMatchNumTelAndPwd, cvc_patterns,
&credit_card_field->verification_,
{log_manager, "kCardCvcRe"})) {
// A couple of sites have multiple verification codes right after another.
@@ -182,7 +190,7 @@ std::unique_ptr<FormField> CreditCardField::Parse(
scanner->RewindTo(scanner->SaveCursor() - 2);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardCvcRe),
- kMatchNumTelAndPwd, patterns_cvc,
+ kMatchNumTelAndPwd, cvc_patterns,
&credit_card_field->verification_,
{log_manager, "kCardCvcRe"})) {
// Reset the current cvv (The verification parse overwrote it).
@@ -205,8 +213,9 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// TODO(crbug.com/591816): Make sure parsing cc-numbers of type password
// doesn't have bad side effects.
AutofillField* current_number_field;
- auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
- CREDIT_CARD_NUMBER, page_language);
+ const std::vector<MatchingPattern>& patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(CREDIT_CARD_NUMBER,
+ page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardNumberRe),
kMatchNumTelAndPwd, patterns, &current_number_field,
{log_manager, "kCardNumberRe"})) {
@@ -271,8 +280,18 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// Some pages have a billing address field after the cardholder name field.
// For that case, allow only just the cardholder name field. The remaining
// CC fields will be picked up in a following CreditCardField.
- if (credit_card_field->cardholder_)
- return std::move(credit_card_field);
+ if (credit_card_field->cardholder_) {
+ // If we got the cardholder name with a dangerous check, require at least a
+ // card number and one of expiration or verification fields.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillStrictContextualCardNameConditions) ||
+ !cardholder_name_match_has_low_confidence ||
+ (!credit_card_field->numbers_.empty() &&
+ (credit_card_field->verification_ ||
+ credit_card_field->HasExpiration()))) {
+ return std::move(credit_card_field);
+ }
+ }
// On some pages, the user selects a card type using radio buttons
// (e.g. test page Apple Store Billing.html). We can't handle that yet,
@@ -333,7 +352,7 @@ bool CreditCardField::LikelyCardMonthSelectField(AutofillScanner* scanner) {
bool CreditCardField::LikelyCardYearSelectField(
AutofillScanner* scanner,
LogManager* log_manager,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (scanner->IsEnd())
return false;
@@ -352,11 +371,10 @@ bool CreditCardField::LikelyCardYearSelectField(
}
// Another way to eliminate days - filter out 'day' fields.
- // In JSON : DAY (only in JSON)
- auto& patterns_day =
+ const std::vector<MatchingPattern>& day_patterns =
PatternProvider::GetInstance().GetMatchPatterns("DAY", page_language);
if (FormField::ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDayRe),
- MATCH_DEFAULT | MATCH_SELECT, patterns_day,
+ MATCH_DEFAULT | MATCH_SELECT, day_patterns,
nullptr, {log_manager, "kDayRe"})) {
return false;
}
@@ -414,7 +432,7 @@ bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) {
// static
bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
LogManager* log_manager,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (scanner->IsEnd())
return false;
@@ -422,31 +440,33 @@ bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_SEARCH;
size_t saved_cursor = scanner->SaveCursor();
- // In JSON : DEBIT_CARD (only in JSON)
- auto& patterns_d = PatternProvider::GetInstance().GetMatchPatterns(
- "DEBIT_CARD", page_language);
- // In JSON : DEBIT_GIFT_CARD (only in JSON)
- auto& patterns_dg = PatternProvider::GetInstance().GetMatchPatterns(
- "DEBIT_GIFT_CARD", page_language);
- // In JSON : GIFT_CARD (only in JSON)
- auto& patterns_g = PatternProvider::GetInstance().GetMatchPatterns(
- "GIFT_CARD", page_language);
+ const std::vector<MatchingPattern>& debit_cards_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("DEBIT_CARD",
+ page_language);
+
+ const std::vector<MatchingPattern>& debit_gift_card_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("DEBIT_GIFT_CARD",
+ page_language);
+
+ const std::vector<MatchingPattern>& gift_card_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("GIFT_CARD",
+ page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitCardRe),
- kMatchFieldTypes, patterns_d, nullptr,
+ kMatchFieldTypes, debit_cards_patterns, nullptr,
{log_manager, "kDebitCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitGiftCardRe),
- kMatchFieldTypes, patterns_dg, nullptr,
+ kMatchFieldTypes, debit_gift_card_patterns, nullptr,
{log_manager, "kDebitGiftCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kGiftCardRe),
- kMatchFieldTypes, patterns_g, nullptr,
+ kMatchFieldTypes, gift_card_patterns, nullptr,
{log_manager, "kGiftCardRe"});
}
@@ -504,7 +524,7 @@ void CreditCardField::AddClassifications(
bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
LogManager* log_manager,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
if (!expiration_date_ && base::LowerCaseEqualsASCII(
scanner->Cursor()->form_control_type, "month")) {
expiration_date_ = scanner->Cursor();
@@ -538,22 +558,28 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
const int kMatchCCType = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE |
MATCH_SELECT | MATCH_SEARCH;
- // In JSON : CARD_EXP_MONTH
- auto& patterns_m = PatternProvider::GetInstance().GetMatchPatterns(
- CREDIT_CARD_EXP_MONTH, page_language);
- // In JSON : CARD_EXP_YEAR
- auto& patterns_y = PatternProvider::GetInstance().GetMatchPatterns(
- "CREDIT_CARD_EXP_YEAR", page_language);
- auto& patterns_mm = PatternProvider::GetInstance().GetMatchPatterns(
- "CREDIT_CARD_EXP_MONTH_BEFORE_YEAR", page_language);
- auto& patterns_yy = PatternProvider::GetInstance().GetMatchPatterns(
- "CREDIT_CARD_EXP_YEAR_AFTER_MONTH", page_language);
+ const std::vector<MatchingPattern>& cc_exp_month_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(CREDIT_CARD_EXP_MONTH,
+ page_language);
+
+ const std::vector<MatchingPattern>& cc_exp_year_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("CREDIT_CARD_EXP_YEAR",
+ page_language);
+
+ const std::vector<MatchingPattern>& cc_exp_month_before_year_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ "CREDIT_CARD_EXP_MONTH_BEFORE_YEAR", page_language);
+
+ const std::vector<MatchingPattern>& cc_exp_year_after_month_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ "CREDIT_CARD_EXP_YEAR_AFTER_MONTH", page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationMonthRe),
- kMatchCCType, patterns_m, &expiration_month_,
+ kMatchCCType, cc_exp_month_patterns,
+ &expiration_month_,
{log_manager_, "kExpirationMonthRe"}) &&
ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationYearRe),
- kMatchCCType, patterns_y, &expiration_year_,
+ kMatchCCType, cc_exp_year_patterns, &expiration_year_,
{log_manager_, "kExpirationYearRe"})) {
return true;
}
@@ -561,11 +587,11 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
// If that fails, look for just MM and/or YY(YY).
scanner->RewindTo(month_year_saved_cursor);
if (ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^mm$"), kMatchCCType,
- patterns_mm, &expiration_month_,
+ cc_exp_month_before_year_patterns, &expiration_month_,
{log_manager_, "^mm$"}) &&
ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^(yy|yyyy)$"),
- kMatchCCType, patterns_yy, &expiration_year_,
- {log_manager_, "^(yy|yyyy)$"})) {
+ kMatchCCType, cc_exp_year_after_month_patterns,
+ &expiration_year_, {log_manager_, "^(yy|yyyy)$"})) {
return true;
}
@@ -580,23 +606,24 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
return false;
// Try to look for a 2-digit year expiration date.
- // In JSON : CARD_EXP_DATE_2_DIGIT_YEAR
- auto& patterns_2dy = PatternProvider::GetInstance().GetMatchPatterns(
- CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, page_language);
- if (ParseFieldSpecifics(scanner,
- base::UTF8ToUTF16(kExpirationDate2DigitYearRe),
- kMatchCCType, patterns_2dy, &expiration_date_,
- {log_manager_, "kExpirationDate2DigitYearRe"})) {
+ const std::vector<MatchingPattern>& cc_exp_2digit_year_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, page_language);
+ if (ParseFieldSpecifics(
+ scanner, base::UTF8ToUTF16(kExpirationDate2DigitYearRe), kMatchCCType,
+ cc_exp_2digit_year_patterns, &expiration_date_,
+ {log_manager_, "kExpirationDate2DigitYearRe"})) {
exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
expiration_month_ = nullptr;
return true;
}
// Try to look for a generic expiration date field. (2 or 4 digit year)
- auto& patterns_exp_d = PatternProvider::GetInstance().GetMatchPatterns(
- "CREDIT_CARD_EXP_DATE", page_language);
+ const std::vector<MatchingPattern>& cc_exp_date_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("CREDIT_CARD_EXP_DATE",
+ page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationDateRe),
- kMatchCCType, patterns_exp_d, &expiration_date_,
+ kMatchCCType, cc_exp_date_patterns, &expiration_date_,
{log_manager_, "kExpirationDateRe"})) {
// If such a field exists, but it cannot fit a 4-digit year expiration
// date, then the likely possibility is that it is a 2-digit year expiration
@@ -610,14 +637,15 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
}
// Try to look for a 4-digit year expiration date.
- auto& patterns_4dy = PatternProvider::GetInstance().GetMatchPatterns(
- CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, page_language);
+ const std::vector<MatchingPattern>& cc_exp_date_4_digit_year_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, page_language);
if (FieldCanFitDataForFieldType(current_field_max_length,
CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
- ParseFieldSpecifics(scanner,
- base::UTF8ToUTF16(kExpirationDate4DigitYearRe),
- kMatchCCType, patterns_4dy, &expiration_date_,
- {log_manager_, "kExpirationDate4DigitYearRe"})) {
+ ParseFieldSpecifics(
+ scanner, base::UTF8ToUTF16(kExpirationDate4DigitYearRe), kMatchCCType,
+ cc_exp_date_4_digit_year_patterns, &expiration_date_,
+ {log_manager_, "kExpirationDate4DigitYearRe"})) {
expiration_month_ = nullptr;
return true;
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
index a3aa409c065..8b3c7f69047 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
@@ -13,6 +13,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -25,7 +26,7 @@ class CreditCardField : public FormField {
explicit CreditCardField(LogManager* log_manager);
~CreditCardField() override;
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
protected:
@@ -44,7 +45,7 @@ class CreditCardField : public FormField {
// to chrome://autofill-internals
static bool LikelyCardYearSelectField(AutofillScanner* scanner,
LogManager* log_manager,
- const std::string& page_language);
+ const LanguageCode& page_language);
// Returns true if |scanner| points to a <select> field that contains credit
// card type options.
@@ -56,13 +57,13 @@ class CreditCardField : public FormField {
// a credit card.
static bool IsGiftCardField(AutofillScanner* scanner,
LogManager* log_manager,
- const std::string& page_language);
+ const LanguageCode& page_language);
// Parses the expiration month/year/date fields. Returns true if it finds
// something new.
bool ParseExpirationDate(AutofillScanner* scanner,
LogManager* log_manager,
- const std::string& page_language);
+ const LanguageCode& page_language);
// For the combined expiration field we return |exp_year_type_|; otherwise if
// |expiration_year_| is having year with |max_length| of 2-digits we return
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
index 9d9815c4269..c2b1f7b8d61 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
@@ -11,10 +11,12 @@
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,55 +24,60 @@ using base::ASCIIToUTF16;
namespace autofill {
-class CreditCardFieldTestBase {
+class CreditCardFieldTestBase : public FormFieldTestBase {
public:
CreditCardFieldTestBase() = default;
CreditCardFieldTestBase(const CreditCardFieldTestBase&) = delete;
CreditCardFieldTestBase& operator=(const CreditCardFieldTestBase&) = delete;
protected:
- // Parses the contents of |list_| as a form, and stores the result into
- // |field_|.
- void Parse() {
- AutofillScanner scanner(list_);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- std::unique_ptr<FormField> field =
- CreditCardField::Parse(&scanner, /*page_language=*/"", nullptr);
- field_ = std::unique_ptr<CreditCardField>(
- static_cast<CreditCardField*>(field.release()));
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("us")) override {
+ return CreditCardField::Parse(scanner, page_language, nullptr);
}
- void MultipleParses() {
- std::unique_ptr<FormField> field;
-
+ // Runs multiple parsing attempts until the end of the form is reached.
+ void ClassifyAndVerifyWithMultipleParses(
+ const LanguageCode& page_language = LanguageCode("")) {
AutofillScanner scanner(list_);
while (!scanner.IsEnd()) {
// An empty page_language means the language is unknown and patterns of
// all languages are used.
- field = CreditCardField::Parse(&scanner, /*page_language=*/"", nullptr);
- field_ = std::unique_ptr<CreditCardField>(
- static_cast<CreditCardField*>(field.release()));
+ field_ = Parse(&scanner, page_language);
if (field_ == nullptr) {
scanner.Advance();
} else {
- AddClassifications();
+ field_->AddClassificationsForTesting(&field_candidates_map_);
}
}
+ TestClassificationExpectations();
}
- // Associates fields with their corresponding types, based on the previous
- // call to Parse().
- void AddClassifications() {
- return field_->AddClassifications(&field_candidates_map_);
+ // Returns a vector of numeric months with a leading 0 and an additional "MM"
+ // entry.
+ std::vector<std::string> GetMonths() {
+ return std::vector<std::string>{"MM", "01", "02", "03", "04", "05", "06",
+ "07", "08", "09", "10", "11", "12"};
}
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<const CreditCardField> field_;
- FieldCandidatesMap field_candidates_map_;
+ // Returns a vector of 10 consecutive years starting today in 2 digit format
+ // and an additional "YY" entry.
+ std::vector<std::string> Get2DigitYears() {
+ std::vector<std::string> years = {"YY"};
+
+ const base::Time time_now = AutofillClock::Now();
+ base::Time::Exploded time_exploded;
+ time_now.UTCExplode(&time_exploded);
+ const int kYearsToAdd = 10;
+
+ for (auto year = time_exploded.year;
+ year < time_exploded.year + kYearsToAdd; year++) {
+ years.push_back(base::NumberToString(year).substr(2));
+ }
- // RAII object to mock the the PatternProvider.
- TestPatternProvider test_pattern_provider_;
+ return years;
+ }
};
class CreditCardFieldTest : public CreditCardFieldTestBase,
@@ -82,339 +89,89 @@ class CreditCardFieldTest : public CreditCardFieldTestBase,
};
TEST_F(CreditCardFieldTest, Empty) {
- Parse();
- ASSERT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
TEST_F(CreditCardFieldTest, NonParse) {
- list_.push_back(std::make_unique<AutofillField>());
- Parse();
- ASSERT_EQ(nullptr, field_.get());
+ AddTextFormFieldData("", "", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
TEST_F(CreditCardFieldTest, ParseCreditCardNoNumber) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month1")));
+ AddTextFormFieldData("ccmonth", "Exp Month", UNKNOWN_TYPE);
+ AddTextFormFieldData("ccyear", "Exp Year", UNKNOWN_TYPE);
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year2")));
-
- Parse();
- ASSERT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
TEST_F(CreditCardFieldTest, ParseCreditCardNoDate) {
- FormFieldData field;
- field.form_control_type = "text";
+ AddTextFormFieldData("card_number", "Card Number", UNKNOWN_TYPE);
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number1")));
-
- Parse();
- ASSERT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
TEST_F(CreditCardFieldTest, ParseMiniumCreditCard) {
- FormFieldData field;
- field.form_control_type = "text";
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number1")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month2")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year3")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year3")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseMinimumCreditCardWithExpiryDateOptions) {
- FormFieldData cc_number_field;
- FormFieldData month_field;
- FormFieldData year_field;
-
- cc_number_field.form_control_type = "text";
- cc_number_field.label = ASCIIToUTF16("Card Number");
- cc_number_field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(cc_number_field, ASCIIToUTF16("number")));
-
- // For month field, set the label and name to something which won't match
- // any regex, so we can test matching of the options themselves.
- month_field.form_control_type = "select-one";
- month_field.label = ASCIIToUTF16("Random label");
- month_field.name = ASCIIToUTF16("Random name");
- const std::vector<std::string> kMonths{"MM", "01", "02", "03", "04",
- "05", "06", "07", "08", "09",
- "10", "11", "12"};
- for (auto month : kMonths) {
- month_field.option_contents.push_back(base::UTF8ToUTF16(month));
- month_field.option_values.push_back(base::UTF8ToUTF16(month));
- }
- list_.push_back(
- std::make_unique<AutofillField>(month_field, ASCIIToUTF16("month")));
-
- // For year, keep the label and name to something which doesn't match regex
- // so we can test matching of the options themselves.
- year_field.form_control_type = "select-one";
- year_field.label = ASCIIToUTF16("Random label");
- year_field.name = ASCIIToUTF16("Random name");
- year_field.max_length = 2;
- year_field.option_contents.push_back(base::ASCIIToUTF16("YY"));
- year_field.option_values.push_back(base::ASCIIToUTF16("YY"));
-
- const base::Time time_now = AutofillClock::Now();
- base::Time::Exploded time_exploded;
- time_now.UTCExplode(&time_exploded);
- const int kYearsToAdd = 10;
-
- for (auto year = time_exploded.year; year < time_exploded.year + kYearsToAdd;
- year++) {
- year_field.option_contents.push_back(
- base::NumberToString16(year).substr(2));
- year_field.option_values.push_back(base::NumberToString16(year).substr(2));
- }
- list_.push_back(
- std::make_unique<AutofillField>(year_field, ASCIIToUTF16("year")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddSelectOneFormFieldData("Random Label", "Random Label", GetMonths(),
+ GetMonths(), CREDIT_CARD_EXP_MONTH);
+ AddSelectOneFormFieldDataWithLength("Random Label", "Random Label", 2,
+ Get2DigitYears(), Get2DigitYears(),
+ CREDIT_CARD_EXP_2_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseFullCreditCard) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("name")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("year")));
-
- field.label = ASCIIToUTF16("Verification");
- field.name = ASCIIToUTF16("verification");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("cvc")));
-
- field.form_control_type = "select-one";
- field.label = ASCIIToUTF16("Card Type");
- field.name = ASCIIToUTF16("card_type");
- field.option_contents.push_back(ASCIIToUTF16("visa"));
- field.option_values.push_back(ASCIIToUTF16("visa"));
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("type")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("type")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_TYPE,
- field_candidates_map_[ASCIIToUTF16("type")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("cvc")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_VERIFICATION_CODE,
- field_candidates_map_[ASCIIToUTF16("cvc")].BestHeuristicType());
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+ AddTextFormFieldData("verification", "Verification",
+ CREDIT_CARD_VERIFICATION_CODE);
+ AddSelectOneFormFieldData("Card Type", "card_type", {"visa"}, {"visa"},
+ CREDIT_CARD_TYPE);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseExpMonthYear) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number2")));
-
- field.label = ASCIIToUTF16("ExpDate Month / Year");
- field.name = ASCIIToUTF16("ExpDate");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month3")));
-
- field.label = ASCIIToUTF16("ExpDate Month / Year");
- field.name = ASCIIToUTF16("ExpDate");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year4")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month3")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year4")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year4")].BestHeuristicType());
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ExpDate", "ExpDate Month / Year",
+ CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ExpDate", "ExpDate Month / Year",
+ CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseExpMonthYear2) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number2")));
-
- field.label = ASCIIToUTF16("Expiration date Month / Year");
- field.name = ASCIIToUTF16("ExpDate");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month3")));
-
- field.label = ASCIIToUTF16("Expiration date Month / Year");
- field.name = ASCIIToUTF16("ExpDate");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year4")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month3")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year4")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year4")].BestHeuristicType());
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ExpDate", "Expiration date Month / Year",
+ CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ExpDate", "Expiration date Month / Year",
+ CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseGiftCard) {
- FormFieldData field;
- field.form_control_type = "text";
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("gift.certificate", "Gift certificate", UNKNOWN_TYPE);
+ AddTextFormFieldData("gift-card", "Gift card", UNKNOWN_TYPE);
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("name")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number")));
-
- field.label = ASCIIToUTF16("Gift certificate");
- field.name = ASCIIToUTF16("gift.certificate");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("giftcert")));
-
- field.label = ASCIIToUTF16("Gift card");
- field.name = ASCIIToUTF16("gift-card");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("giftcard")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("giftcert")) ==
- field_candidates_map_.end());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("giftcard")) ==
- field_candidates_map_.end());
+ ClassifyAndVerify(ParseResult::PARSED);
}
typedef struct {
@@ -430,32 +187,13 @@ class ParseExpFieldTest : public CreditCardFieldTestBase,
TEST_P(ParseExpFieldTest, ParseExpField) {
auto test_case = GetParam();
- // Clean up after previous test cases.
- list_.clear();
- field_.reset();
- field_candidates_map_.clear();
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.form_control_type = test_case.cc_fields_form_control_type;
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("num2")));
-
- field.label = ASCIIToUTF16(test_case.label);
- if (test_case.max_length != 0) {
- field.max_length = test_case.max_length;
- }
- field.name = ASCIIToUTF16("cc_exp");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("exp3")));
-
- Parse();
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddFormFieldData(test_case.cc_fields_form_control_type, "card_number",
+ "Card Number", CREDIT_CARD_NUMBER);
+ AddFormFieldDataWithLength(test_case.cc_fields_form_control_type, "cc_exp",
+ test_case.label, test_case.max_length,
+ test_case.expected_prediction);
// Assists in identifing which case has failed.
SCOPED_TRACE(test_case.expected_prediction);
@@ -466,31 +204,15 @@ TEST_P(ParseExpFieldTest, ParseExpField) {
// Expect failure and continue to next test case.
// The expiry date is a required field for credit card forms, and thus the
// parse sets |field_| to nullptr.
- EXPECT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
return;
}
- // Ensure that the form was determined as valid.
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("num2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("num2")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(test_case.expected_prediction,
- field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
INSTANTIATE_TEST_SUITE_P(
- CreditCardFieldTest,
+ ,
ParseExpFieldTest,
testing::Values(
// CC fields input_type="text"
@@ -630,397 +352,155 @@ INSTANTIATE_TEST_SUITE_P(
CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR}));
TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) {
- FormFieldData field;
- field.form_control_type = "text";
+ AddTextFormFieldData("ccfullname", "Name", CREDIT_CARD_NAME_FULL);
- field.label = ASCIIToUTF16("Name");
- field.name = ASCIIToUTF16("ccfullname");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
// Verifies that <input type="month"> controls are able to be parsed correctly.
TEST_F(CreditCardFieldTest, ParseMonthControl) {
- FormFieldData field;
+ AddTextFormFieldData("ccnumber", "Card number:", CREDIT_CARD_NUMBER);
+ AddFormFieldData("month", "ccexp",
+ "Expiration date:", CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
- field.form_control_type = "text";
- field.label = ASCIIToUTF16("Card number:");
- field.name = ASCIIToUTF16("ccnumber");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number1")));
-
- field.form_control_type = "month";
- field.label = ASCIIToUTF16("Expiration date:");
- field.name = ASCIIToUTF16("ccexp");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("date2")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("date2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("date2")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
// Verify that heuristics <input name="ccyear" maxlength="2"/> considers
// *maxlength* attribute while parsing 2 Digit expiration year.
TEST_F(CreditCardFieldTest, ParseCreditCardExpYear_2DigitMaxLength) {
- FormFieldData field;
- field.form_control_type = "text";
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Expiration Date", CREDIT_CARD_EXP_MONTH);
+ AddFormFieldDataWithLength("text", "ccyear", "Expiration Date", 2,
+ CREDIT_CARD_EXP_2_DIGIT_YEAR);
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number")));
-
- field.label = ASCIIToUTF16("Expiration Date");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month")));
-
- field.name = ASCIIToUTF16("ccyear");
- field.max_length = 2;
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("year")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseCreditCardNumberWithSplit) {
FormFieldData field;
field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number_q1");
- field.max_length = 4;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number1")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number_q2");
- field.max_length = 4;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number2")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number_q3");
- field.max_length = 4;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number3")));
-
+ AddFormFieldDataWithLength("text", "card_number_q1", "Card Number", 4,
+ CREDIT_CARD_NUMBER);
+ AddFormFieldDataWithLength("text", "card_number_q2", "Card Number", 4,
+ CREDIT_CARD_NUMBER);
+ AddFormFieldDataWithLength("text", "card_number_q3", "Card Number", 4,
+ CREDIT_CARD_NUMBER);
// For last credit card number input field it simply ignores the |max_length|
// attribute. So even having a very big number, does not conside it an invalid
// split for autofilling.
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number_q4");
- field.max_length = 20;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number4")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month5")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year6")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number1")].BestHeuristicType());
- EXPECT_EQ(0U, list_[0]->credit_card_number_offset());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
- EXPECT_EQ(4U, list_[1]->credit_card_number_offset());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number3")].BestHeuristicType());
- EXPECT_EQ(8U, list_[2]->credit_card_number_offset());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number4")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number4")].BestHeuristicType());
- EXPECT_EQ(12U, list_[3]->credit_card_number_offset());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month5")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month5")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year6")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year6")].BestHeuristicType());
+ AddFormFieldDataWithLength("text", "card_number_q4", "Card Number", 20,
+ CREDIT_CARD_NUMBER);
+
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+
+ // Test the for the right credit card number offsets.
+ ASSERT_TRUE(list_.size() > 4);
+ EXPECT_EQ(list_[0]->credit_card_number_offset(), 0U);
+ EXPECT_EQ(list_[1]->credit_card_number_offset(), 4U);
+ EXPECT_EQ(list_[2]->credit_card_number_offset(), 8U);
+ EXPECT_EQ(list_[3]->credit_card_number_offset(), 12U);
}
TEST_F(CreditCardFieldTest, ParseMultipleCreditCardNumbers) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number2")));
-
- field.label = ASCIIToUTF16("Confirm Card Number");
- field.name = ASCIIToUTF16("confirm_card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number3")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month4")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year5")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number3")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month4")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month4")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year5")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year5")].BestHeuristicType());
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("confirm_card_number", "Confirm Card Number",
+ CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseFirstAndLastNames) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("First Name on Card");
- field.name = ASCIIToUTF16("cc-fname");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Last Name");
- field.name = ASCIIToUTF16("cc-lname");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number3")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month4")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year5")));
-
- Parse();
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number3")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month4")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month4")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year5")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year5")].BestHeuristicType());
+ AddTextFormFieldData("cc-fname", "First Name on Card",
+ CREDIT_CARD_NAME_FIRST);
+ AddTextFormFieldData("cc-lname", "Last Name", CREDIT_CARD_NAME_LAST);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(CreditCardFieldTest, ParseConsecutiveCvc) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("name")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("year")));
-
- field.label = ASCIIToUTF16("Verification");
- field.name = ASCIIToUTF16("verification");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("cvc")));
-
- field.label = ASCIIToUTF16("Verification");
- field.name = ASCIIToUTF16("verification");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("cvc2")));
-
- MultipleParses();
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("cvc")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_VERIFICATION_CODE,
- field_candidates_map_[ASCIIToUTF16("cvc")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("cvc2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_VERIFICATION_CODE,
- field_candidates_map_[ASCIIToUTF16("cvc2")].BestHeuristicType());
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+ AddTextFormFieldData("verification", "Verification",
+ CREDIT_CARD_VERIFICATION_CODE);
+ AddTextFormFieldData("verification", "Verification",
+ CREDIT_CARD_VERIFICATION_CODE);
+
+ ClassifyAndVerifyWithMultipleParses();
}
TEST_F(CreditCardFieldTest, ParseNonConsecutiveCvc) {
- FormFieldData field;
- field.form_control_type = "text";
+ AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("card_number", "Card Number", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+ AddTextFormFieldData("verification", "Verification",
+ CREDIT_CARD_VERIFICATION_CODE);
+ AddTextFormFieldData("unknown", "Unknown", UNKNOWN_TYPE);
+
+ ClassifyAndVerifyWithMultipleParses();
+}
+
+TEST_F(CreditCardFieldTest, ParseCreditCardContextualNameNotCard) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitWithFeatures(
+ {features::kAutofillStrictContextualCardNameConditions}, {});
+
+ AddTextFormFieldData("accNum", "Account ID", UNKNOWN_TYPE);
+ AddTextFormFieldData("name", "Account Name", UNKNOWN_TYPE);
+ AddTextFormFieldData("toAcctNum", "Move to Account ID", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+TEST_F(CreditCardFieldTest, ParseCreditCardContextualNameNotCardAcctMatch) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitWithFeatures(
+ {features::kAutofillStrictContextualCardNameConditions}, {});
+
+ // TODO(crbug.com/1167977): This should be not parseable, but waiting before
+ // changing kNameOnCardRe to use word boundaries.
+ AddTextFormFieldData("acctNum", "Account ID", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("acctName", "Account Name", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("toAcctNum", "Move to Account ID", CREDIT_CARD_NUMBER);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_F(CreditCardFieldTest, ParseCreditCardContextualNameWithExpiration) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitWithFeatures(
+ {features::kAutofillStrictContextualCardNameConditions}, {});
+
+ AddTextFormFieldData("acctNum", "Account ID", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("name", "Account Name", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("ccmonth", "Exp Month", CREDIT_CARD_EXP_MONTH);
+ AddTextFormFieldData("ccyear", "Exp Year", CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_F(CreditCardFieldTest, ParseCreditCardContextualNameWithVerification) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitWithFeatures(
+ {features::kAutofillStrictContextualCardNameConditions}, {});
+
+ AddTextFormFieldData("acctNum", "Account ID", CREDIT_CARD_NUMBER);
+ AddTextFormFieldData("name", "Account Name", CREDIT_CARD_NAME_FULL);
+ AddTextFormFieldData("cvv", "Verification", CREDIT_CARD_VERIFICATION_CODE);
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("name")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("number")));
-
- field.label = ASCIIToUTF16("Exp Month");
- field.name = ASCIIToUTF16("ccmonth");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("month")));
-
- field.label = ASCIIToUTF16("Exp Year");
- field.name = ASCIIToUTF16("ccyear");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("year")));
-
- field.label = ASCIIToUTF16("Verification");
- field.name = ASCIIToUTF16("verification");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("cvc")));
-
- field.label = ASCIIToUTF16("Unknown");
- field.name = ASCIIToUTF16("unknown");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("unknown")));
-
- field.label = ASCIIToUTF16("Verification");
- field.name = ASCIIToUTF16("verification");
- list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("cvc2")));
-
- MultipleParses();
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
- field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("cvc")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_VERIFICATION_CODE,
- field_candidates_map_[ASCIIToUTF16("cvc")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("unknown")) ==
- field_candidates_map_.end());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("cvc2")) ==
- field_candidates_map_.end());
+ ClassifyAndVerify(ParseResult::PARSED);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.cc b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
index 99d87e8fc17..655749affc6 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
@@ -12,13 +12,14 @@ namespace autofill {
// static
std::unique_ptr<FormField> EmailField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
AutofillField* field;
- auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
- "EMAIL_ADDRESS", page_language);
+ const std::vector<MatchingPattern>& email_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("EMAIL_ADDRESS",
+ page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
- MATCH_DEFAULT | MATCH_EMAIL, patterns, &field,
+ MATCH_DEFAULT | MATCH_EMAIL, email_patterns, &field,
{log_manager, "kEmailRe"})) {
return std::make_unique<EmailField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.h b/chromium/components/autofill/core/browser/form_parsing/email_field.h
index 3765457f766..8d7169abd1d 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -19,7 +20,7 @@ class LogManager;
class EmailField : public FormField {
public:
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
explicit EmailField(const AutofillField* field);
diff --git a/chromium/components/autofill/core/browser/form_parsing/field_candidates.h b/chromium/components/autofill/core/browser/form_parsing/field_candidates.h
index f1ef7246213..4cf3c6d7204 100644
--- a/chromium/components/autofill/core/browser/form_parsing/field_candidates.h
+++ b/chromium/components/autofill/core/browser/form_parsing/field_candidates.h
@@ -5,10 +5,11 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_FIELD_CANDIDATES_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_FIELD_CANDIDATES_H_
-#include <unordered_map>
#include <vector>
+#include "base/containers/flat_map.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/common/renderer_id.h"
namespace autofill {
@@ -50,7 +51,7 @@ class FieldCandidates {
};
// A map from the field's unique name to its possible candidates.
-using FieldCandidatesMap = std::unordered_map<base::string16, FieldCandidates>;
+using FieldCandidatesMap = base::flat_map<FieldRendererId, FieldCandidates>;
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.cc b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
index 4b5f80e3ca8..696b422b450 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
@@ -53,7 +53,7 @@ const float FormField::kBaseSearchParserScore = 0.8f;
// static
FieldCandidatesMap FormField::ParseFormFields(
const std::vector<std::unique_ptr<AutofillField>>& fields,
- const std::string& page_language,
+ const LanguageCode& page_language,
bool is_form_tag,
LogManager* log_manager) {
// Set up a working copy of the fields to be processed.
@@ -133,7 +133,7 @@ FieldCandidatesMap FormField::ParseFormFields(
}
for (const auto& candidate : field_candidates) {
LogBuffer name;
- name << "Type candidate for: " << candidate.first;
+ name << "Type candidate for renderer ID: " << candidate.first.value();
LogBuffer description;
ServerFieldType field_type = candidate.second.BestHeuristicType();
description << "BestHeuristicType: "
@@ -174,10 +174,9 @@ bool FormField::ParseField(AutofillScanner* scanner,
AutofillField** match,
const RegExLogging& logging) {
if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ features::kAutofillParsingPatternsLanguageDependent) ||
base::FeatureList::IsEnabled(
- features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ features::kAutofillParsingPatternsNegativeMatching)) {
return ParseField(scanner, patterns, match, logging);
} else {
return ParseField(scanner, pattern, match, logging);
@@ -221,18 +220,17 @@ bool FormField::ParseFieldSpecifics(
// TODO(crbug.com/1132831): Remove feature check once launched.
if (base::FeatureList::IsEnabled(
- features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
- if (pattern.negative_pattern.has_value() &&
- FormField::Match(field,
- base::UTF8ToUTF16(pattern.negative_pattern.value()),
+ features::kAutofillParsingPatternsNegativeMatching)) {
+ if (!pattern.negative_pattern.empty() &&
+ FormField::Match(field, base::UTF8ToUTF16(pattern.negative_pattern),
pattern.match_field_attributes,
pattern.match_field_input_types, logging)) {
continue;
}
}
- if (MatchAndAdvance(scanner, base::UTF8ToUTF16(pattern.positive_pattern),
+ if (!pattern.positive_pattern.empty() &&
+ MatchAndAdvance(scanner, base::UTF8ToUTF16(pattern.positive_pattern),
pattern.match_field_attributes,
pattern.match_field_input_types, match, logging)) {
return true;
@@ -263,22 +261,19 @@ bool FormField::ParseFieldSpecifics(
const RegExLogging& logging,
MatchFieldBitmasks match_field_bitmasks) {
if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ features::kAutofillParsingPatternsLanguageDependent) ||
base::FeatureList::IsEnabled(
- features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ features::kAutofillParsingPatternsNegativeMatching)) {
// TODO(crbug/1142936): This hack is to allow
// AddressField::ParseNameAndLabelSeparately().
if (match_field_bitmasks.restrict_attributes != ~0 ||
match_field_bitmasks.augment_types != 0) {
- std::vector<MatchingPattern> patterns_with_restricted_match_type =
- patterns;
- for (MatchingPattern& mp : patterns_with_restricted_match_type) {
+ std::vector<MatchingPattern> modified_patterns = patterns;
+ for (MatchingPattern& mp : modified_patterns) {
mp.match_field_attributes &= match_field_bitmasks.restrict_attributes;
mp.match_field_input_types |= match_field_bitmasks.augment_types;
}
- return ParseFieldSpecifics(scanner, patterns_with_restricted_match_type,
- match, logging);
+ return ParseFieldSpecifics(scanner, modified_patterns, match, logging);
}
return ParseFieldSpecifics(scanner, patterns, match, logging);
} else {
@@ -302,7 +297,7 @@ void FormField::AddClassification(const AutofillField* field,
if (field == nullptr)
return;
- FieldCandidates& candidates = (*field_candidates)[field->unique_name()];
+ FieldCandidates& candidates = (*field_candidates)[field->unique_renderer_id];
candidates.AddFieldCandidate(type, score);
}
@@ -347,16 +342,25 @@ bool FormField::Match(const AutofillField* field,
base::StringPiece16 value;
base::string16 match;
+ // TODO(crbug/1165780): Remove once shared labels are launched.
+ const base::string16& label =
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForParsingWithSharedLabels)
+ ? field->parseable_label()
+ : field->label;
+
+ const base::string16& name = field->parseable_name();
+
if ((match_field_attributes & MATCH_LABEL) &&
- MatchesPattern(field->label, pattern, &match)) {
+ MatchesPattern(label, pattern, &match)) {
found_match = true;
match_type_string = "Match in label";
- value = field->label;
+ value = label;
} else if ((match_field_attributes & MATCH_NAME) &&
- MatchesPattern(field->parseable_name(), pattern, &match)) {
+ MatchesPattern(name, pattern, &match)) {
found_match = true;
match_type_string = "Match in name";
- value = field->parseable_name();
+ value = name;
}
if (found_match && logging.log_manager) {
@@ -391,7 +395,7 @@ bool FormField::Match(const AutofillField* field,
void FormField::ParseFormFieldsPass(ParseFunction parse,
const std::vector<AutofillField*>& fields,
FieldCandidatesMap* field_candidates,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
AutofillScanner scanner(fields);
while (!scanner.IsEnd()) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.h b/chromium/components/autofill/core/browser/form_parsing/form_field.h
index 7eca61ab200..904c373e517 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.h
@@ -14,6 +14,7 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
#include "components/autofill/core/browser/form_parsing/field_candidates.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -35,17 +36,25 @@ struct RegExLogging {
// name, phone number, or address field.
class FormField {
public:
- virtual ~FormField() {}
+ virtual ~FormField() = default;
// Classifies each field in |fields| with its heuristically detected type.
// Each field has a derived unique name that is used as the key into the
// returned FieldCandidatesMap.
static FieldCandidatesMap ParseFormFields(
const std::vector<std::unique_ptr<AutofillField>>& fields,
- const std::string& page_language,
+ const LanguageCode& page_language,
bool is_form_tag,
LogManager* log_manager = nullptr);
+#if defined(UNIT_TEST)
+ // Assign types to the fields for the testing purposes.
+ void AddClassificationsForTesting(
+ FieldCandidatesMap* field_candidates_for_testing) const {
+ AddClassifications(field_candidates_for_testing);
+ }
+#endif
+
protected:
// Initial values assigned to FieldCandidates by their corresponding parsers.
static const float kBaseEmailParserScore;
@@ -102,6 +111,7 @@ class FormField {
int match_field_input_types,
AutofillField** match,
const RegExLogging& logging = {});
+
struct MatchFieldBitmasks {
int restrict_attributes = ~0;
int augment_types = 0;
@@ -141,12 +151,13 @@ class FormField {
private:
FRIEND_TEST_ALL_PREFIXES(FormFieldTest, Match);
+ FRIEND_TEST_ALL_PREFIXES(FormFieldTest, TestParseableLabels);
// Function pointer type for the parsing function that should be passed to the
// ParseFormFieldsPass() helper function.
typedef std::unique_ptr<FormField> ParseFunction(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
// Matches |pattern| to the contents of the field at the head of the
@@ -192,7 +203,7 @@ class FormField {
static void ParseFormFieldsPass(ParseFunction parse,
const std::vector<AutofillField*>& fields,
FieldCandidatesMap* field_candidates,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager = nullptr);
DISALLOW_COPY_AND_ASSIGN(FormField);
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
index ed5baa21072..1d41fdeea2d 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
@@ -10,7 +10,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
+#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/autofill_features.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,6 +19,20 @@ using base::ASCIIToUTF16;
namespace autofill {
+namespace {
+FieldRendererId MakeFieldRendererId() {
+ static uint64_t id_counter_ = 0;
+ return FieldRendererId(++id_counter_);
+}
+
+// Sets both the field label and parseable label to |label|.
+void SetFieldLabels(AutofillField* field, const std::string& label) {
+ field->label = base::UTF8ToUTF16(label);
+ field->set_parseable_label(base::UTF8ToUTF16(label));
+}
+
+} // namespace
+
TEST(FormFieldTest, Match) {
AutofillField field;
@@ -26,69 +40,69 @@ TEST(FormFieldTest, Match) {
EXPECT_TRUE(FormField::Match(&field, base::string16(), MATCH_LABEL));
// Empty pattern matches non-empty string.
- field.label = ASCIIToUTF16("a");
+ SetFieldLabels(&field, "a");
EXPECT_TRUE(FormField::Match(&field, base::string16(), MATCH_LABEL));
// Strictly empty pattern matches empty string.
- field.label = base::string16();
+ SetFieldLabels(&field, "");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^$"), MATCH_LABEL));
// Strictly empty pattern does not match non-empty string.
- field.label = ASCIIToUTF16("a");
+ SetFieldLabels(&field, "a");
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^$"), MATCH_LABEL));
// Non-empty pattern doesn't match empty string.
- field.label = base::string16();
+ SetFieldLabels(&field, "");
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("a"), MATCH_LABEL));
// Beginning of line.
- field.label = ASCIIToUTF16("head_tail");
+ SetFieldLabels(&field, "head_tail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^head"), MATCH_LABEL));
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^tail"), MATCH_LABEL));
// End of line.
- field.label = ASCIIToUTF16("head_tail");
+ SetFieldLabels(&field, "head_tail");
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("head$"), MATCH_LABEL));
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("tail$"), MATCH_LABEL));
// Exact.
- field.label = ASCIIToUTF16("head_tail");
+ SetFieldLabels(&field, "head_tail");
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^head$"), MATCH_LABEL));
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^tail$"), MATCH_LABEL));
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("^head_tail$"), MATCH_LABEL));
// Escaped dots.
- field.label = ASCIIToUTF16("m.i.");
+ SetFieldLabels(&field, "m.i.");
// Note: This pattern is misleading as the "." characters are wild cards.
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m.i."), MATCH_LABEL));
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."), MATCH_LABEL));
- field.label = ASCIIToUTF16("mXiX");
+ SetFieldLabels(&field, "mXiX");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m.i."), MATCH_LABEL));
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."), MATCH_LABEL));
// Repetition.
- field.label = ASCIIToUTF16("headtail");
+ SetFieldLabels(&field, "headtail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("head.*tail"), MATCH_LABEL));
- field.label = ASCIIToUTF16("headXtail");
+ SetFieldLabels(&field, "headXtail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("head.*tail"), MATCH_LABEL));
- field.label = ASCIIToUTF16("headXXXtail");
+ SetFieldLabels(&field, "headXXXtail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("head.*tail"), MATCH_LABEL));
- field.label = ASCIIToUTF16("headtail");
+ SetFieldLabels(&field, "headtail");
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("head.+tail"), MATCH_LABEL));
- field.label = ASCIIToUTF16("headXtail");
+ SetFieldLabels(&field, "headXtail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("head.+tail"), MATCH_LABEL));
- field.label = ASCIIToUTF16("headXXXtail");
+ SetFieldLabels(&field, "headXXXtail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("head.+tail"), MATCH_LABEL));
// Alternation.
- field.label = ASCIIToUTF16("head_tail");
+ SetFieldLabels(&field, "head_tail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("head|other"), MATCH_LABEL));
EXPECT_TRUE(
@@ -96,11 +110,11 @@ TEST(FormFieldTest, Match) {
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("bad|good"), MATCH_LABEL));
// Case sensitivity.
- field.label = ASCIIToUTF16("xxxHeAd_tAiLxxx");
+ SetFieldLabels(&field, "xxxHeAd_tAiLxxx");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head_tail"), MATCH_LABEL));
// Word boundaries.
- field.label = ASCIIToUTF16("contains word:");
+ SetFieldLabels(&field, "contains word:");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("\\bword\\b"), MATCH_LABEL));
EXPECT_FALSE(
@@ -112,74 +126,66 @@ TEST(FormFieldTest, Match) {
// Test that we ignore checkable elements.
TEST(FormFieldTest, ParseFormFields) {
- TestPatternProvider test_pattern_provider_;
-
std::vector<std::unique_ptr<AutofillField>> fields;
FormFieldData field_data;
field_data.form_control_type = "text";
field_data.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
field_data.label = ASCIIToUTF16("Is PO Box");
- fields.push_back(
- std::make_unique<AutofillField>(field_data, field_data.label));
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ fields.push_back(std::make_unique<AutofillField>(field_data));
// Does not parse since there are only field and it's checkable.
// An empty page_language means the language is unknown and patterns of all
// languages are used.
EXPECT_TRUE(
- FormField::ParseFormFields(fields, /*page_language=*/"", true).empty());
+ FormField::ParseFormFields(fields, LanguageCode(""), true).empty());
// reset |is_checkable| to false.
field_data.check_status = FormFieldData::CheckStatus::kNotCheckable;
-
field_data.label = ASCIIToUTF16("Address line1");
- fields.push_back(
- std::make_unique<AutofillField>(field_data, field_data.label));
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ fields.push_back(std::make_unique<AutofillField>(field_data));
// Parse a single address line 1 field.
- ASSERT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
+ ASSERT_EQ(0u,
+ FormField::ParseFormFields(fields, LanguageCode(""), true).size());
// Parses address line 1 and 2.
field_data.label = ASCIIToUTF16("Address line2");
- fields.push_back(
- std::make_unique<AutofillField>(field_data, field_data.label));
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ fields.push_back(std::make_unique<AutofillField>(field_data));
// An empty page_language means the language is unknown and patterns of
// all languages are used.
- ASSERT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
+ ASSERT_EQ(0u,
+ FormField::ParseFormFields(fields, LanguageCode(""), true).size());
}
// Test that the minimum number of required fields for the heuristics considers
// whether a field is actually fillable.
TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
- TestPatternProvider test_pattern_provider_;
-
std::vector<std::unique_ptr<AutofillField>> fields;
FormFieldData field_data;
field_data.form_control_type = "text";
field_data.label = ASCIIToUTF16("Address line 1");
- fields.push_back(
- std::make_unique<AutofillField>(field_data, field_data.label));
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ fields.push_back(std::make_unique<AutofillField>(field_data));
field_data.label = ASCIIToUTF16("Address line 2");
- fields.push_back(
- std::make_unique<AutofillField>(field_data, field_data.label));
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ fields.push_back(std::make_unique<AutofillField>(field_data));
// Don't parse forms with 2 fields.
// An empty page_language means the language is unknown and patterns of all
// languages are used.
- EXPECT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
+ EXPECT_EQ(0u,
+ FormField::ParseFormFields(fields, LanguageCode(""), true).size());
field_data.label = ASCIIToUTF16("Search");
- fields.push_back(
- std::make_unique<AutofillField>(field_data, field_data.label));
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ fields.push_back(std::make_unique<AutofillField>(field_data));
// Before the fix in kAutofillFixFillableFieldTypes, we would parse the form
// now, although a search field is not fillable.
@@ -189,8 +195,7 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
// An empty page_language means the language is unknown and patterns of all
// languages are used.
EXPECT_EQ(
- 3u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
+ 3u, FormField::ParseFormFields(fields, LanguageCode(""), true).size());
}
// With the fix, we don't parse the form because search fields are not
@@ -201,11 +206,34 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
// An empty page_language means the language is unknown and patterns of all
// languages are used.
const FieldCandidatesMap field_candidates_map =
- FormField::ParseFormFields(fields, /*page_language=*/"", true);
+ FormField::ParseFormFields(fields, LanguageCode(""), true);
EXPECT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
+ 0u, FormField::ParseFormFields(fields, LanguageCode(""), true).size());
}
}
+// Test that the parseable label is used when the feature is enabled.
+TEST(FormFieldTest, TestParseableLabels) {
+ FormFieldData field_data;
+ field_data.form_control_type = "text";
+
+ field_data.label = ASCIIToUTF16("not a parseable label");
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ auto autofill_field = std::make_unique<AutofillField>(field_data);
+ autofill_field->set_parseable_label(ASCIIToUTF16("First Name"));
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kAutofillEnableSupportForParsingWithSharedLabels);
+ EXPECT_TRUE(FormField::Match(autofill_field.get(),
+ ASCIIToUTF16("First Name"), MATCH_LABEL));
+ }
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ features::kAutofillEnableSupportForParsingWithSharedLabels);
+ EXPECT_FALSE(FormField::Match(autofill_field.get(),
+ ASCIIToUTF16("First Name"), MATCH_LABEL));
+ }
+}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.cc b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
index 0fd65aa87c9..1e3bf74d083 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
@@ -24,7 +24,7 @@ namespace {
class FullNameField : public NameField {
public:
static std::unique_ptr<FullNameField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
explicit FullNameField(AutofillField* field);
@@ -43,11 +43,11 @@ class FirstTwoLastNamesField : public NameField {
public:
static std::unique_ptr<FirstTwoLastNamesField> ParseComponentNames(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
static std::unique_ptr<FirstTwoLastNamesField> Parse(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
protected:
@@ -71,15 +71,15 @@ class FirstLastNameField : public NameField {
public:
static std::unique_ptr<FirstLastNameField> ParseSpecificName(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
static std::unique_ptr<FirstLastNameField> ParseComponentNames(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
static std::unique_ptr<FirstLastNameField> Parse(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
protected:
@@ -101,7 +101,7 @@ class FirstLastNameField : public NameField {
// static
std::unique_ptr<FormField> NameField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
if (scanner->IsEnd())
return nullptr;
@@ -126,15 +126,22 @@ void NameField::AddClassifications(FieldCandidatesMap* field_candidates) const {
// static
std::unique_ptr<FullNameField> FullNameField::Parse(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
// Exclude e.g. "username" or "nickname" fields.
scanner->SaveCursor();
- auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
- "NAME_IGNORED", page_language);
+ const std::vector<MatchingPattern>& name_ignored_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("NAME_IGNORED",
+ page_language);
+ const std::vector<MatchingPattern>& address_name_ignored_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_NAME_IGNORED",
+ page_language);
bool should_ignore =
- ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), patterns_ni, nullptr,
- {log_manager, "kNameIgnoredRe"});
+ ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), name_ignored_patterns,
+ nullptr, {log_manager, "kNameIgnoredRe"}) ||
+ ParseField(scanner, UTF8ToUTF16(kAddressNameIgnoredRe),
+ address_name_ignored_patterns, nullptr,
+ {log_manager, "kAddressNameIgnoredRe"});
scanner->Rewind();
if (should_ignore)
return nullptr;
@@ -143,10 +150,11 @@ std::unique_ptr<FullNameField> FullNameField::Parse(
// for example, Travelocity_Edit travel profile.html contains a field
// "Travel Profile Name".
AutofillField* field = nullptr;
- // In JSON : FULL_NAME (closest vatiant)
- auto& patterns_name = PatternProvider::GetInstance().GetMatchPatterns(
- "FULL_NAME", page_language);
- if (ParseField(scanner, UTF8ToUTF16(kNameRe), patterns_name, &field,
+
+ const std::vector<MatchingPattern>& name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("FULL_NAME",
+ page_language);
+ if (ParseField(scanner, UTF8ToUTF16(kNameRe), name_patterns, &field,
{log_manager, "kNameRe"}))
return std::make_unique<FullNameField>(field);
@@ -165,7 +173,7 @@ FirstTwoLastNamesField::FirstTwoLastNamesField() = default;
// static
std::unique_ptr<FirstTwoLastNamesField> FirstTwoLastNamesField::Parse(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
return ParseComponentNames(scanner, page_language, log_manager);
}
@@ -173,34 +181,51 @@ std::unique_ptr<FirstTwoLastNamesField> FirstTwoLastNamesField::Parse(
// static
std::unique_ptr<FirstTwoLastNamesField>
FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstTwoLastNamesField> v(new FirstTwoLastNamesField);
scanner->SaveCursor();
- auto& patterns_hp = PatternProvider::GetInstance().GetMatchPatterns(
- "HONORIFIC_PREFIX", page_language);
- auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
- "NAME_IGNORED", page_language);
- auto& patterns_fn = PatternProvider::GetInstance().GetMatchPatterns(
- "FIRST_NAME", page_language);
- auto& patterns_mn = PatternProvider::GetInstance().GetMatchPatterns(
- "MIDDLE_NAME", page_language);
- auto& patterns_ln1 = PatternProvider::GetInstance().GetMatchPatterns(
- "LAST_NAME_FIRST", page_language);
- auto& patterns_ln2 = PatternProvider::GetInstance().GetMatchPatterns(
- "LAST_NAME_SECOND", page_language);
+ const std::vector<MatchingPattern>& honorific_prefix_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("HONORIFIC_PREFIX",
+ page_language);
+ const std::vector<MatchingPattern>& name_ignored_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("NAME_IGNORED",
+ page_language);
+ const std::vector<MatchingPattern>& address_name_ignored_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_NAME_IGNORED",
+ page_language);
+ const std::vector<MatchingPattern>& first_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("FIRST_NAME",
+ page_language);
+ const std::vector<MatchingPattern>& middle_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("MIDDLE_NAME",
+ page_language);
+ const std::vector<MatchingPattern>& first_last_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("LAST_NAME_FIRST",
+ page_language);
+ const std::vector<MatchingPattern>& second_last_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("LAST_NAME_SECOND",
+ page_language);
// Allow name fields to appear in any order.
while (!scanner->IsEnd()) {
+ // Skip over address label fields, which can have misleading names
+ // e.g. "title" or "name".
+ if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kAddressNameIgnoredRe),
+ MATCH_DEFAULT, address_name_ignored_patterns,
+ nullptr, {log_manager, "kAddressNameIgnoredRe"})) {
+ continue;
+ }
+
// Scan for the honorific prefix before checking for unrelated name fields
// because a honorific prefix field is expected to have very specific labels
// including "Title:". The latter is matched with |kNameIgnoredRe|.
// TODO(crbug.com/1098943): Remove check once feature is launched or
// removed.
if (!v->honorific_prefix_ &&
- ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe), patterns_hp,
- &v->honorific_prefix_,
+ ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe),
+ honorific_prefix_patterns, &v->honorific_prefix_,
{log_manager, "kHonorificPrefixRe"})) {
continue;
}
@@ -208,32 +233,33 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
// Skip over any unrelated fields, e.g. "username" or "nickname".
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kNameIgnoredRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- patterns_ni, nullptr,
+ name_ignored_patterns, nullptr,
{log_manager, "kNameIgnoredRe"})) {
continue;
}
if (!v->first_name_ &&
- ParseField(scanner, UTF8ToUTF16(kFirstNameRe), patterns_fn,
+ ParseField(scanner, UTF8ToUTF16(kFirstNameRe), first_name_patterns,
&v->first_name_, {log_manager, "kFirstNameRe"})) {
continue;
}
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), patterns_mn,
+ ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), middle_name_patterns,
&v->middle_name_, {log_manager, "kMiddleNameRe"})) {
continue;
}
if (!v->first_last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kNameLastFirstRe), patterns_ln1,
- &v->first_last_name_, {log_manager, "kNameLastFirstRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kNameLastFirstRe),
+ first_last_name_patterns, &v->first_last_name_,
+ {log_manager, "kNameLastFirstRe"})) {
continue;
}
if (!v->second_last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kNameLastSecondRe), patterns_ln2,
- &v->second_last_name_,
+ ParseField(scanner, UTF8ToUTF16(kNameLastSecondRe),
+ second_last_name_patterns, &v->second_last_name_,
{log_manager, "kNameLastSecondtRe"})) {
continue;
}
@@ -267,7 +293,7 @@ void FirstTwoLastNamesField::AddClassifications(
std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
// Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html)
// have the label "Name" followed by two or three text fields.
@@ -275,10 +301,11 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
scanner->SaveCursor();
AutofillField* next = nullptr;
- auto& patterns_ns = PatternProvider::GetInstance().GetMatchPatterns(
- "NAME_SPECIFIC", page_language);
+ const std::vector<MatchingPattern>& name_specific_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("NAME_SPECIFIC",
+ page_language);
- if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), patterns_ns,
+ if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), name_specific_patterns,
&v->first_name_, {log_manager, "kNameSpecificRe"}) &&
ParseEmptyLabel(scanner, &next)) {
if (ParseEmptyLabel(scanner, &v->last_name_)) {
@@ -300,7 +327,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
// static
std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstLastNameField> v(new FirstLastNameField);
scanner->SaveCursor();
@@ -317,20 +344,37 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// Allow name fields to appear in any order.
- auto& patterns_hp = PatternProvider::GetInstance().GetMatchPatterns(
- "HONORIFIC_PREFIX", page_language);
- auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
- "NAME_IGNORED", page_language);
- auto& patterns_fn = PatternProvider::GetInstance().GetMatchPatterns(
- "FIRST_NAME", page_language);
- auto& patterns_mi = PatternProvider::GetInstance().GetMatchPatterns(
- "MIDDLE_INITIAL", page_language);
- auto& patterns_mn = PatternProvider::GetInstance().GetMatchPatterns(
- "MIDDLE_NAME", page_language);
- auto& patterns_ln = PatternProvider::GetInstance().GetMatchPatterns(
- "LAST_NAME", page_language);
+ const std::vector<MatchingPattern>& honorific_prefix_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("HONORIFIC_PREFIX",
+ page_language);
+ const std::vector<MatchingPattern>& name_ignored_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("NAME_IGNORED",
+ page_language);
+ const std::vector<MatchingPattern>& address_name_ignored_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_NAME_IGNORED",
+ page_language);
+ const std::vector<MatchingPattern>& first_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("FIRST_NAME",
+ page_language);
+ const std::vector<MatchingPattern>& middle_name_initial_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("MIDDLE_INITIAL",
+ page_language);
+ const std::vector<MatchingPattern>& middle_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("MIDDLE_NAME",
+ page_language);
+ const std::vector<MatchingPattern>& last_name_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("LAST_NAME",
+ page_language);
while (!scanner->IsEnd()) {
+ // Skip over address label fields, which can have misleading names
+ // e.g. "title" or "name".
+ if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kAddressNameIgnoredRe),
+ MATCH_DEFAULT, address_name_ignored_patterns,
+ nullptr, {log_manager, "kAddressNameIgnoredRe"})) {
+ continue;
+ }
+
// Scan for the honorific prefix before checking for unrelated fields
// because a honorific prefix field is expected to have very specific labels
// including "Title:". The latter is matched with |kNameIgnoredRe|.
@@ -339,8 +383,8 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames)) {
if (!v->honorific_prefix_ &&
- ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe), patterns_hp,
- &v->honorific_prefix_,
+ ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe),
+ honorific_prefix_patterns, &v->honorific_prefix_,
{log_manager, "kHonorificPrefixRe"})) {
continue;
}
@@ -349,13 +393,13 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// Skip over any unrelated name fields, e.g. "username" or "nickname".
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kNameIgnoredRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- patterns_ni, nullptr,
+ name_ignored_patterns, nullptr,
{log_manager, "kNameIgnoredRe"})) {
continue;
}
if (!v->first_name_ &&
- ParseField(scanner, UTF8ToUTF16(kFirstNameRe), patterns_fn,
+ ParseField(scanner, UTF8ToUTF16(kFirstNameRe), first_name_patterns,
&v->first_name_, {log_manager, "kFirstNameRe"})) {
continue;
}
@@ -366,20 +410,21 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// "txtmiddlename"); such a field probably actually represents a
// middle initial.
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleInitialRe), patterns_mi,
- &v->middle_name_, {log_manager, "kMiddleInitialRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleInitialRe),
+ middle_name_initial_patterns, &v->middle_name_,
+ {log_manager, "kMiddleInitialRe"})) {
v->middle_initial_ = true;
continue;
}
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), patterns_mn,
+ ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), middle_name_patterns,
&v->middle_name_, {log_manager, "kMiddleNameRe"})) {
continue;
}
if (!v->last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kLastNameRe), patterns_ln,
+ ParseField(scanner, UTF8ToUTF16(kLastNameRe), last_name_patterns,
&v->last_name_, {log_manager, "kLastNameRe"})) {
continue;
}
@@ -399,7 +444,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// static
std::unique_ptr<FirstLastNameField> FirstLastNameField::Parse(
AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstLastNameField> field =
ParseSpecificName(scanner, page_language, log_manager);
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.h b/chromium/components/autofill/core/browser/form_parsing/name_field.h
index 7298fbdb7d5..99c011e70f8 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.h
@@ -14,6 +14,7 @@
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -24,19 +25,11 @@ class LogManager;
class NameField : public FormField {
public:
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
-#ifdef UNIT_TEST
- // Calls the protected method |AddClassification| for testing.
- void AddClassificationsForTesting(
- FieldCandidatesMap* field_candidates) const {
- AddClassifications(field_candidates);
- }
-#endif
-
protected:
- NameField() {}
+ NameField() = default;
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
index e83e8187b8c..af7fdf56732 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
@@ -7,122 +7,49 @@
#include <memory>
#include <vector>
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
-#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/autofill_regexes.h"
-#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
namespace autofill {
-class NameFieldTest : public testing::Test {
+class NameFieldTest : public FormFieldTest {
public:
NameFieldTest() = default;
NameFieldTest(const NameFieldTest&) = delete;
NameFieldTest& operator=(const NameFieldTest&) = delete;
protected:
- // Downcast for tests.
- static std::unique_ptr<NameField> Parse(AutofillScanner* scanner) {
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- std::unique_ptr<FormField> field =
- NameField::Parse(scanner, /*page_language=*/"", nullptr);
- return std::unique_ptr<NameField>(static_cast<NameField*>(field.release()));
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("us")) override {
+ return NameField::Parse(scanner, page_language, nullptr);
}
-
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<NameField> field_;
- FieldCandidatesMap field_candidates_map_;
-
- // RAII object to mock the the PatternProvider.
- TestPatternProvider test_pattern_provider_;
};
TEST_F(NameFieldTest, FirstMiddleLast) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("First Name");
- field.name = ASCIIToUTF16("First");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Middle Name");
- field.name = ASCIIToUTF16("Middle");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = ASCIIToUTF16("Last Name");
- field.name = ASCIIToUTF16("Last");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("First Name", "First", NAME_FIRST);
+ AddTextFormFieldData("Name Middle", "Middle", NAME_MIDDLE);
+ AddTextFormFieldData("Last Name", "Last", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, FirstMiddleLast2) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("firstName");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("middleName");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("lastName");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("firstName", "", NAME_FIRST);
+ AddTextFormFieldData("middleName", "", NAME_MIDDLE);
+ AddTextFormFieldData("lastName", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
-// Test that a field for a honoric title is parsed correctly.
+// Test that a field for a honorific title is parsed correctly.
TEST_F(NameFieldTest, HonorificPrefixFirstLast) {
// With support for two last names, the parsing should find the first name
// field and the two last name fields.
@@ -131,257 +58,63 @@ TEST_F(NameFieldTest, HonorificPrefixFirstLast) {
scoped_feature_list.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("salutation");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name0")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name0")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_HONORIFIC_PREFIX,
- field_candidates_map_[ASCIIToUTF16("name0")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+ AddTextFormFieldData("salutation", "", NAME_HONORIFIC_PREFIX);
+ AddTextFormFieldData("first_name", "", NAME_FIRST);
+ AddTextFormFieldData("last_name", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, FirstLast) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+ AddTextFormFieldData("first_name", "", NAME_FIRST);
+ AddTextFormFieldData("last_name", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, FirstLast2) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name");
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Name");
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+ AddTextFormFieldData("first_name", "Name", NAME_FIRST);
+ AddTextFormFieldData("last_name", "Name", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, FirstLastMiddleWithSpaces) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("First Name");
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Middle Name");
- field.name = ASCIIToUTF16("middle_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = ASCIIToUTF16("Last Name");
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("fist_name", "First Name", NAME_FIRST);
+ AddTextFormFieldData("middle_name", "Middle Name", NAME_MIDDLE);
+ AddTextFormFieldData("last_name", "Last Name", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, FirstLastEmpty) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name");
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+ AddTextFormFieldData("first_name", "Name", NAME_FIRST);
+ AddTextFormFieldData("last_name", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, FirstMiddleLastEmpty) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name");
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("middle_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE_INITIAL,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("first_name", "Name", NAME_FIRST);
+ AddTextFormFieldData("middle_name", "", NAME_MIDDLE_INITIAL);
+ AddTextFormFieldData("last_name", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, MiddleInitial) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("First Name");
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("MI");
- field.name = ASCIIToUTF16("middle_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = ASCIIToUTF16("Last Name");
- field.name = ASCIIToUTF16("last_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE_INITIAL,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("first_name", "Name", NAME_FIRST);
+ AddTextFormFieldData("middle_name", "MI", NAME_MIDDLE_INITIAL);
+ AddTextFormFieldData("last_name", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(NameFieldTest, MiddleInitialNoLastName) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("First Name");
- field.name = ASCIIToUTF16("first_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("MI");
- field.name = ASCIIToUTF16("middle_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_EQ(nullptr, field_.get());
+ AddTextFormFieldData("first_name", "First Name", UNKNOWN_TYPE);
+ AddTextFormFieldData("middle_name", "MI", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
// Tests that a website with a first and second surname field is parsed
@@ -394,53 +127,13 @@ TEST_F(NameFieldTest, HonorificPrefixAndFirstNameAndHispanicLastNames) {
scoped_feature_list.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("tratamiento");
- field.name = ASCIIToUTF16("tratamiento");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- field.label = ASCIIToUTF16("nombre");
- field.name = ASCIIToUTF16("nombre");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name0")));
-
- field.label = ASCIIToUTF16("apellido paterno");
- field.name = ASCIIToUTF16("apellido_paterno");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("segunda apellido");
- field.name = ASCIIToUTF16("segunda_apellido");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- AutofillScanner scanner(list_);
-
- field_ = Parse(&scanner);
- field_->AddClassificationsForTesting(&field_candidates_map_);
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name0")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name0")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST_SECOND,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_HONORIFIC_PREFIX,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("tratamiento", "tratamiento", NAME_HONORIFIC_PREFIX);
+ AddTextFormFieldData("nombre", "nombre", NAME_FIRST);
+ AddTextFormFieldData("apellido paterno", "apellido_paterno", NAME_LAST_FIRST);
+ AddTextFormFieldData("segunda apellido", "segunda_apellido",
+ NAME_LAST_SECOND);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
// Tests that a website with a first and second surname field is parsed
@@ -452,89 +145,23 @@ TEST_F(NameFieldTest, FirstNameAndOptionalMiddleNameAndHispanicLastNames) {
scoped_feature_list.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("nombre");
- field.name = ASCIIToUTF16("nombre");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name0")));
-
- field.label = ASCIIToUTF16("apellido paterno");
- field.name = ASCIIToUTF16("apellido_paterno");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("segunda apellido");
- field.name = ASCIIToUTF16("segunda_apellido");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = ASCIIToUTF16("middle name");
- field.name = ASCIIToUTF16("middle_name");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
-
- field_ = Parse(&scanner);
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name0")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name0")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST_SECOND,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("nombre", "nombre", NAME_FIRST);
+ AddTextFormFieldData("middle name", "middle_name", NAME_MIDDLE);
+ AddTextFormFieldData("apellido paterno", "apellido_paterno", NAME_LAST_FIRST);
+ AddTextFormFieldData("segunda apellido", "segunda_apellido",
+ NAME_LAST_SECOND);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
// This case is from the dell.com checkout page. The middle initial "mi" string
// came at the end following other descriptive text. http://crbug.com/45123.
TEST_F(NameFieldTest, MiddleInitialAtEnd) {
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("XXXnameXXXfirst");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("XXXnameXXXmi");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name2")));
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("XXXnameXXXlast");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("name3")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_FIRST,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_MIDDLE_INITIAL,
- field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(NAME_LAST,
- field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
+ AddTextFormFieldData("XXXnameXXXfirst", "", NAME_FIRST);
+ AddTextFormFieldData("XXXnameXXXmi", "", NAME_MIDDLE_INITIAL);
+ AddTextFormFieldData("XXXnameXXXlast", "", NAME_LAST);
+
+ ClassifyAndVerify(ParseResult::PARSED);
}
// Test the coverage of all found strings for first and second last names.
@@ -574,4 +201,19 @@ TEST_F(NameFieldTest, HispanicLastNameRegexConverage) {
}
}
+// Tests that address name is not misclassified as name or honorific prefix.
+TEST_F(NameFieldTest, NotAddressName) {
+ AddTextFormFieldData("name", "Identificação do Endereço", UNKNOWN_TYPE);
+ AddTextFormFieldData("title", "Adres Adı", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+// Tests that contact name is classified as full name.
+TEST_F(NameFieldTest, ContactNameFull) {
+ AddTextFormFieldData("contact", "Контактное лицо", NAME_FULL);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc b/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
new file mode 100644
index 00000000000..93fc4be0625
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
@@ -0,0 +1,129 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
+
+namespace autofill {
+
+FormFieldTestBase::FormFieldTestBase() = default;
+FormFieldTestBase::~FormFieldTestBase() = default;
+
+void FormFieldTestBase::AddFormFieldData(std::string control_type,
+ std::string name,
+ std::string label,
+ ServerFieldType expected_type) {
+ AddFormFieldDataWithLength(control_type, name, label, /*max_length=*/0,
+ expected_type);
+}
+
+void FormFieldTestBase::AddFormFieldDataWithLength(
+ std::string control_type,
+ std::string name,
+ std::string label,
+ int max_length,
+ ServerFieldType expected_type) {
+ FormFieldData field_data;
+ field_data.form_control_type = control_type;
+ field_data.name = base::UTF8ToUTF16(name);
+ field_data.label = base::UTF8ToUTF16(label);
+ field_data.max_length = max_length;
+ field_data.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field_data));
+ expected_classifications_.insert(
+ std::make_pair(field_data.unique_renderer_id, expected_type));
+}
+
+void FormFieldTestBase::AddSelectOneFormFieldData(
+ std::string name,
+ std::string label,
+ const std::vector<std::string>& options_contents,
+ const std::vector<std::string>& options_values,
+ ServerFieldType expected_type) {
+ AddSelectOneFormFieldDataWithLength(name, label, 0, options_contents,
+ options_values, expected_type);
+}
+
+void FormFieldTestBase::AddSelectOneFormFieldDataWithLength(
+ std::string name,
+ std::string label,
+ int max_length,
+ const std::vector<std::string>& options_contents,
+ const std::vector<std::string>& options_values,
+ ServerFieldType expected_type) {
+ AddFormFieldData("select-one", name, label, expected_type);
+ FormFieldData* field_data = list_.back().get();
+ field_data->max_length = max_length;
+
+ for (auto option_content : options_contents) {
+ field_data->option_contents.push_back(base::UTF8ToUTF16(option_content));
+ }
+
+ for (auto option_value : options_values) {
+ field_data->option_values.push_back(base::UTF8ToUTF16(option_value));
+ }
+}
+
+// Convenience wrapper for text control elements.
+void FormFieldTestBase::AddTextFormFieldData(
+ std::string name,
+ std::string label,
+ ServerFieldType expected_classification) {
+ AddFormFieldData("text", name, label, expected_classification);
+}
+
+// Apply parsing and verify the expected types.
+// |parsed| indicates if at least one field could be parsed successfully.
+// |page_language| the language to be used for parsing, default empty value
+// means the language is unknown and patterns of all languages are used.
+void FormFieldTestBase::ClassifyAndVerify(ParseResult parse_result,
+ const LanguageCode& page_language) {
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner, page_language);
+
+ if (parse_result == ParseResult::NOT_PARSED) {
+ ASSERT_EQ(nullptr, field_.get());
+ return;
+ }
+ ASSERT_NE(nullptr, field_.get());
+ field_->AddClassificationsForTesting(&field_candidates_map_);
+
+ TestClassificationExpectations();
+}
+
+void FormFieldTestBase::TestClassificationExpectations() {
+ for (const std::pair<FieldRendererId, ServerFieldType> it :
+ expected_classifications_) {
+ if (it.second != UNKNOWN_TYPE) {
+ SCOPED_TRACE(testing::Message()
+ << "Found type "
+ << AutofillType::ServerFieldTypeToString(
+ field_candidates_map_[it.first].BestHeuristicType())
+ << ", expected type "
+ << AutofillType::ServerFieldTypeToString(it.second));
+
+ ASSERT_TRUE(field_candidates_map_.find(it.first) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(it.second, field_candidates_map_[it.first].BestHeuristicType());
+ } else {
+ SCOPED_TRACE(
+ testing::Message()
+ << "Expected type UNKNOWN_TYPE but got "
+ << AutofillType::ServerFieldTypeToString(
+ field_candidates_map_.find(it.first) !=
+ field_candidates_map_.end()
+ ? field_candidates_map_[it.first].BestHeuristicType()
+ : UNKNOWN_TYPE));
+ EXPECT_EQ(field_candidates_map_.find(it.first),
+ field_candidates_map_.end());
+ }
+ }
+}
+
+FieldRendererId FormFieldTestBase::MakeFieldRendererId() {
+ return FieldRendererId(++id_counter_);
+}
+
+FormFieldTest::FormFieldTest() = default;
+FormFieldTest::~FormFieldTest() = default;
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.h b/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.h
new file mode 100644
index 00000000000..df5d271565f
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.h
@@ -0,0 +1,112 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_PARSING_TEST_UTILS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_PARSING_TEST_UTILS_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/form_parsing/address_field.h"
+#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/language_code.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+enum class ParseResult {
+ // The form was successfully parsed and at least one type was assigned.
+ PARSED = 0,
+ // Not a single type was assigned.
+ NOT_PARSED,
+ kMaxValue = NOT_PARSED
+};
+
+class FormFieldTestBase {
+ public:
+ FormFieldTestBase(const FormFieldTestBase&) = delete;
+ FormFieldTestBase();
+ ~FormFieldTestBase();
+ FormFieldTestBase& operator=(const FormFieldTestBase&) = delete;
+
+ protected:
+ // Add a field with |control_type|, the |name|, the |label| the expected
+ // parsed type |expected_type|.
+ void AddFormFieldData(std::string control_type,
+ std::string name,
+ std::string label,
+ ServerFieldType expected_type);
+
+ // Convenience wrapper for text control elements with a maximal length.
+ void AddFormFieldDataWithLength(std::string control_type,
+ std::string name,
+ std::string label,
+ int max_length,
+ ServerFieldType expected_type);
+
+ // Convenience wrapper for text control elements.
+ void AddTextFormFieldData(std::string name,
+ std::string label,
+ ServerFieldType expected_classification);
+
+ // Convenience wrapper for 'select-one' elements with a max length.
+ void AddSelectOneFormFieldDataWithLength(
+ std::string name,
+ std::string label,
+ int max_length,
+ const std::vector<std::string>& options_contents,
+ const std::vector<std::string>& options_values,
+ ServerFieldType expected_type);
+
+ // Convenience wrapper for 'select-one' elements.
+ void AddSelectOneFormFieldData(
+ std::string name,
+ std::string label,
+ const std::vector<std::string>& options_contents,
+ const std::vector<std::string>& options_values,
+ ServerFieldType expected_type);
+
+ // Apply parsing and verify the expected types.
+ // |parsed| indicates if at least one field could be parsed successfully.
+ // |page_language| the language to be used for parsing, default empty value
+ // means the language is unknown and patterns of all languages are used.
+ void ClassifyAndVerify(ParseResult parse_result = ParseResult::PARSED,
+ const LanguageCode& page_language = LanguageCode(""));
+
+ // Test the parsed verifications against the expectations.
+ void TestClassificationExpectations();
+
+ // Apply the parsing with a specific parser.
+ virtual std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language) = 0;
+
+ FieldRendererId MakeFieldRendererId();
+
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<FormField> field_;
+ FieldCandidatesMap field_candidates_map_;
+ std::map<FieldRendererId, ServerFieldType> expected_classifications_;
+
+ private:
+ uint64_t id_counter_ = 0;
+};
+
+class FormFieldTest : public FormFieldTestBase, public testing::Test {
+ public:
+ FormFieldTest(const FormFieldTest&) = delete;
+ FormFieldTest();
+ ~FormFieldTest() override;
+ FormFieldTest& operator=(const FormFieldTest&) = delete;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_PARSING_TEST_UTILS_H_
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
index b50388208be..451ca2c75d6 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
@@ -213,7 +213,7 @@ bool PhoneField::LikelyAugmentedPhoneCountryCode(
// static
std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
if (scanner->IsEnd())
return nullptr;
@@ -420,7 +420,8 @@ const char* PhoneField::GetRegExpName(RegexType regex_id) {
return "";
}
-//
+// Returns the string representation of |phonetype_id| as it is used to key to
+// identify coressponding patterns.
std::string PhoneField::GetJSONFieldType(RegexType phonetype_id) {
switch (phonetype_id) {
case REGEX_COUNTRY:
@@ -455,14 +456,15 @@ bool PhoneField::ParsePhoneField(AutofillScanner* scanner,
const RegExLogging& logging,
const bool is_country_code_field,
const std::string& json_field_type,
- const std::string& page_language) {
+ const LanguageCode& page_language) {
int match_type = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER;
// Include the selection boxes too for the matching of the phone country code.
if (is_country_code_field)
match_type |= MATCH_SELECT;
- auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
- json_field_type, page_language);
+ const std::vector<MatchingPattern>& patterns =
+ PatternProvider::GetInstance().GetMatchPatterns(json_field_type,
+ page_language);
return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(regex), match_type,
patterns, field, logging);
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.h b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
index 6ac25f26693..1b3bf5d7fde 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
@@ -18,6 +18,7 @@
#include "components/autofill/core/browser/data_model/phone_number.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -36,7 +37,7 @@ class PhoneField : public FormField {
PhoneField& operator=(const PhoneField&) = delete;
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
#if defined(UNIT_TEST)
@@ -108,7 +109,7 @@ class PhoneField : public FormField {
const RegExLogging& logging,
const bool is_country_code_field,
const std::string& json_field_type,
- const std::string& page_language);
+ const LanguageCode& page_language);
// Returns true if |scanner| points to a <select> field that appears to be the
// phone country code by looking at its option contents.
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
index 71e0cf605c4..1257ba01c13 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
@@ -9,14 +9,13 @@
#include <memory>
#include <vector>
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -47,7 +46,7 @@ class PhoneFieldTest : public testing::Test {
// An empty page_language means the language is unknown and patterns of all
// languages are used.
std::unique_ptr<FormField> field =
- PhoneField::Parse(scanner, /*page_language=*/"", nullptr);
+ PhoneField::Parse(scanner, LanguageCode(""), nullptr);
return std::unique_ptr<PhoneField>(
static_cast<PhoneField*>(field.release()));
}
@@ -58,11 +57,11 @@ class PhoneFieldTest : public testing::Test {
field_candidates_map_.clear();
}
- void CheckField(const std::string& name,
+ void CheckField(const FieldRendererId id,
ServerFieldType expected_type) const {
- auto it = field_candidates_map_.find(ASCIIToUTF16(name));
- ASSERT_TRUE(it != field_candidates_map_.end()) << name;
- EXPECT_EQ(expected_type, it->second.BestHeuristicType()) << name;
+ auto it = field_candidates_map_.find(id);
+ ASSERT_TRUE(it != field_candidates_map_.end());
+ EXPECT_EQ(expected_type, it->second.BestHeuristicType());
}
// Populates a select |field| with the |label|, the |name| and the |contents|.
@@ -85,8 +84,12 @@ class PhoneFieldTest : public testing::Test {
std::unique_ptr<PhoneField> field_;
FieldCandidatesMap field_candidates_map_;
- // RAII object to mock the the PatternProvider.
- TestPatternProvider test_pattern_provider_;
+ FieldRendererId MakeFieldRendererId() {
+ return FieldRendererId(++id_counter_);
+ }
+
+ private:
+ uint64_t id_counter_ = 0;
};
TEST_F(PhoneFieldTest, Empty) {
@@ -111,14 +114,15 @@ TEST_F(PhoneFieldTest, ParseOneLinePhone) {
field.form_control_type = field_type;
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone1")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone1 = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("phone1", PHONE_HOME_WHOLE_NUMBER);
+ CheckField(phone1, PHONE_HOME_WHOLE_NUMBER);
}
}
@@ -131,20 +135,22 @@ TEST_F(PhoneFieldTest, ParseTwoLinePhone) {
field.form_control_type = field_type;
field.label = ASCIIToUTF16("Area Code");
field.name = ASCIIToUTF16("area code");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("areacode1")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId areacode1 = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone2")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone2 = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("areacode1", PHONE_HOME_CITY_CODE);
- CheckField("phone2", PHONE_HOME_NUMBER);
+ CheckField(areacode1, PHONE_HOME_CITY_CODE);
+ CheckField(phone2, PHONE_HOME_NUMBER);
}
}
@@ -163,35 +169,39 @@ TEST_F(PhoneFieldTest, ThreePartPhoneNumber) {
field.label = ASCIIToUTF16("Phone:");
field.name = ASCIIToUTF16("dayphone1");
field.max_length = 0;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("areacode1")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId areacode1 = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("-");
field.name = ASCIIToUTF16("dayphone2");
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("prefix2")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId prefix2 = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("-");
field.name = ASCIIToUTF16("dayphone3");
field.max_length = 4;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("suffix3")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId suffix3 = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("ext.:");
field.name = ASCIIToUTF16("dayphone4");
field.max_length = 0;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("ext4")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId ext4 = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("areacode1", PHONE_HOME_CITY_CODE);
- CheckField("prefix2", PHONE_HOME_NUMBER);
- CheckField("suffix3", PHONE_HOME_NUMBER);
- EXPECT_TRUE(base::Contains(field_candidates_map_, ASCIIToUTF16("ext4")));
+ CheckField(areacode1, PHONE_HOME_CITY_CODE);
+ CheckField(prefix2, PHONE_HOME_NUMBER);
+ CheckField(suffix3, PHONE_HOME_NUMBER);
+ EXPECT_TRUE(base::Contains(field_candidates_map_, ext4));
}
}
@@ -207,26 +217,29 @@ TEST_F(PhoneFieldTest, ThreePartPhoneNumberPrefixSuffix) {
field.form_control_type = field_type;
field.label = ASCIIToUTF16("Phone:");
field.name = ASCIIToUTF16("area");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("areacode1")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId areacode1 = list_.back()->unique_renderer_id;
field.label = base::string16();
field.name = ASCIIToUTF16("prefix");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("prefix2")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId prefix2 = list_.back()->unique_renderer_id;
field.label = base::string16();
field.name = ASCIIToUTF16("suffix");
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("suffix3")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId suffix3 = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("areacode1", PHONE_HOME_CITY_CODE);
- CheckField("prefix2", PHONE_HOME_NUMBER);
- CheckField("suffix3", PHONE_HOME_NUMBER);
+ CheckField(areacode1, PHONE_HOME_CITY_CODE);
+ CheckField(prefix2, PHONE_HOME_NUMBER);
+ CheckField(suffix3, PHONE_HOME_NUMBER);
}
}
@@ -240,28 +253,31 @@ TEST_F(PhoneFieldTest, ThreePartPhoneNumberPrefixSuffix2) {
field.label = ASCIIToUTF16("(");
field.name = ASCIIToUTF16("phone1");
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone1")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone1 = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16(")");
field.name = ASCIIToUTF16("phone2");
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone2")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone2 = list_.back()->unique_renderer_id;
field.label = base::string16();
field.name = ASCIIToUTF16("phone3");
field.max_length = 4;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone3")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone3 = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("phone1", PHONE_HOME_CITY_CODE);
- CheckField("phone2", PHONE_HOME_NUMBER);
- CheckField("phone3", PHONE_HOME_NUMBER);
+ CheckField(phone1, PHONE_HOME_CITY_CODE);
+ CheckField(phone2, PHONE_HOME_NUMBER);
+ CheckField(phone3, PHONE_HOME_NUMBER);
}
}
@@ -277,21 +293,23 @@ TEST_F(PhoneFieldTest, CountryAndCityAndPhoneNumber) {
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("CountryCode");
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("country")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId country = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("PhoneNumber");
field.max_length = 10;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("country", PHONE_HOME_COUNTRY_CODE);
- CheckField("phone", PHONE_HOME_CITY_AND_NUMBER);
+ CheckField(country, PHONE_HOME_COUNTRY_CODE);
+ CheckField(phone, PHONE_HOME_CITY_AND_NUMBER);
}
}
@@ -307,23 +325,25 @@ TEST_F(PhoneFieldTest, CountryAndCityAndPhoneNumberWithLongerMaxLength) {
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("CountryCode");
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("country")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId country = list_.back()->unique_renderer_id;
// Verify if websites expect a longer formatted number like:
// (514)-123-1234, autofill is able to classify correctly.
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("PhoneNumber");
field.max_length = 14;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phone")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phone = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("country", PHONE_HOME_COUNTRY_CODE);
- CheckField("phone", PHONE_HOME_CITY_AND_NUMBER);
+ CheckField(country, PHONE_HOME_COUNTRY_CODE);
+ CheckField(phone, PHONE_HOME_CITY_AND_NUMBER);
}
}
@@ -335,29 +355,32 @@ TEST_F(PhoneFieldTest, CountryCodeIsSelectElement) {
field.label = ASCIIToUTF16("Phone Country Code");
field.name = ASCIIToUTF16("ccode");
field.form_control_type = "select-one";
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("countryCode")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId country_code = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone City Code");
field.name = ASCIIToUTF16("areacode");
field.form_control_type = "text";
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("cityCode")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId cityCode = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 0;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phoneNumber = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("countryCode", PHONE_HOME_COUNTRY_CODE);
- CheckField("cityCode", PHONE_HOME_CITY_CODE);
- CheckField("phoneNumber", PHONE_HOME_NUMBER);
+ CheckField(country_code, PHONE_HOME_COUNTRY_CODE);
+ CheckField(cityCode, PHONE_HOME_CITY_CODE);
+ CheckField(phoneNumber, PHONE_HOME_NUMBER);
}
// Tests if the country code, city code and phone number fields are correctly
@@ -375,29 +398,32 @@ TEST_F(PhoneFieldTest, CountryCodeWithOptions) {
"(+91) India", "(+49) Germany", "(+1) United States", "(+20) Egypt",
"(+1242) Bahamas", "(+593) Ecuador", "(+7) Russia"};
CreateTestSelectField("PC", "PC", augmented_field_options_list, &field);
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("countryCode")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId country_code = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone City Code");
field.name = ASCIIToUTF16("areacode");
field.form_control_type = "text";
field.max_length = 3;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("cityCode")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId cityCode = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 0;
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId phoneNumber = list_.back()->unique_renderer_id;
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("countryCode", PHONE_HOME_COUNTRY_CODE);
- CheckField("cityCode", PHONE_HOME_CITY_CODE);
- CheckField("phoneNumber", PHONE_HOME_NUMBER);
+ CheckField(country_code, PHONE_HOME_COUNTRY_CODE);
+ CheckField(cityCode, PHONE_HOME_CITY_CODE);
+ CheckField(phoneNumber, PHONE_HOME_NUMBER);
}
// Tests if the country code field is correctly classified by the heuristic when
@@ -460,26 +486,32 @@ TEST_F(PhoneFieldTest, IsPhoneCountryCodeField) {
{"0091", "0049", "001", "0020", "001242", "00593", "007"}};
for (size_t i = 0; i < augmented_field_options_list.size(); ++i) {
+ // TODO(crbug/1151473): The below CheckField() call fails in iteration 4.
+ if (i == 4)
+ continue;
+
+ list_.clear();
SCOPED_TRACE(testing::Message() << "i = " << i);
const auto& options_list = augmented_field_options_list[i];
CreateTestSelectField("PC", "PC", options_list, &field);
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("countryCode")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
+ FieldRendererId country_code = list_.back()->unique_renderer_id;
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 14;
field.form_control_type = "text";
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
field_->AddClassificationsForTesting(&field_candidates_map_);
- CheckField("countryCode", PHONE_HOME_COUNTRY_CODE);
+ CheckField(country_code, PHONE_HOME_COUNTRY_CODE);
}
-} // namespace autofill
+}
// Tests that the month field is not classified as |PHONE_HOME_COUNTRY_CODE|.
TEST_F(PhoneFieldTest, IsMonthField) {
@@ -501,15 +533,15 @@ TEST_F(PhoneFieldTest, IsMonthField) {
SCOPED_TRACE(testing::Message() << "i = " << i);
const auto& options_list = augmented_field_options_list[i];
CreateTestSelectField("Month", "Month", options_list, &field);
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("months")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 14;
field.form_control_type = "text";
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
@@ -567,15 +599,15 @@ TEST_F(PhoneFieldTest, IsDayField) {
SCOPED_TRACE(testing::Message() << "i = " << i);
const auto& options_list = augmented_field_options_list[i];
CreateTestSelectField("Field", "Field", options_list, &field);
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("day")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 14;
field.form_control_type = "text";
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
@@ -619,15 +651,15 @@ TEST_F(PhoneFieldTest, IsYearField) {
SCOPED_TRACE(testing::Message() << "i = " << i);
const auto& options_list = augmented_field_options_list[i];
CreateTestSelectField("Field", "Field", options_list, &field);
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("year")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 14;
field.form_control_type = "text";
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
@@ -657,15 +689,15 @@ TEST_F(PhoneFieldTest, IsTimeZoneField) {
SCOPED_TRACE(testing::Message() << "i = " << i);
const auto& options_list = augmented_field_options_list[i];
CreateTestSelectField("Time Zone", "TimeZone", options_list, &field);
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("timeZone")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
field.label = ASCIIToUTF16("Phone Number");
field.name = ASCIIToUTF16("phonenumber");
field.max_length = 14;
field.form_control_type = "text";
- list_.push_back(
- std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+ field.unique_renderer_id = MakeFieldRendererId();
+ list_.push_back(std::make_unique<AutofillField>(field));
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.cc b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
index 595b759ad00..bc1fed93b86 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
@@ -13,16 +13,16 @@ namespace autofill {
// static
std::unique_ptr<FormField> PriceField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
AutofillField* field;
- auto& patterns =
+ const std::vector<MatchingPattern>& price_patterns =
PatternProvider::GetInstance().GetMatchPatterns("PRICE", page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kPriceRe),
MATCH_DEFAULT | MATCH_NUMBER | MATCH_SELECT |
MATCH_TEXT_AREA | MATCH_SEARCH,
- patterns, &field, {log_manager, kPriceRe})) {
+ price_patterns, &field, {log_manager, kPriceRe})) {
return std::make_unique<PriceField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.h b/chromium/components/autofill/core/browser/form_parsing/price_field.h
index 7d05f460dae..99013c2203a 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -23,9 +24,9 @@ class LogManager;
class PriceField : public FormField {
public:
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
- PriceField(const AutofillField* field);
+ explicit PriceField(const AutofillField* field);
protected:
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
index 464830b2852..5243ac9ffb8 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
@@ -4,81 +4,36 @@
#include "components/autofill/core/browser/form_parsing/price_field.h"
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
-#include "components/autofill/core/common/form_field_data.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
using base::ASCIIToUTF16;
namespace autofill {
-class PriceFieldTest : public testing::Test {
+class PriceFieldTest : public FormFieldTest {
public:
PriceFieldTest() = default;
PriceFieldTest(const PriceFieldTest&) = delete;
PriceFieldTest& operator=(const PriceFieldTest&) = delete;
protected:
- // Downcast for tests.
- static std::unique_ptr<PriceField> Parse(AutofillScanner* scanner) {
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- std::unique_ptr<FormField> field =
- PriceField::Parse(scanner, /*page_language=*/"", nullptr);
- return std::unique_ptr<PriceField>(
- static_cast<PriceField*>(field.release()));
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("en")) override {
+ return PriceField::Parse(scanner, page_language, nullptr);
}
-
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<PriceField> field_;
- FieldCandidatesMap field_candidates_map_;
-
- // RAII object to mock the the PatternProvider.
- TestPatternProvider test_pattern_provider_;
};
TEST_F(PriceFieldTest, ParsePrice) {
- FormFieldData price_field;
- price_field.form_control_type = "text";
-
- price_field.label = ASCIIToUTF16("name your price");
- price_field.name = ASCIIToUTF16("userPrice");
+ AddTextFormFieldData("name your price", "userPrice", PRICE);
- list_.push_back(
- std::make_unique<AutofillField>(price_field, ASCIIToUTF16("price1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassifications(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("price1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(PRICE,
- field_candidates_map_[ASCIIToUTF16("price1")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(PriceFieldTest, ParseNonPrice) {
- FormFieldData address_field;
- address_field.form_control_type = "text";
-
- address_field.label = ASCIIToUTF16("Name");
- address_field.name = ASCIIToUTF16("firstName");
-
- list_.push_back(
- std::make_unique<AutofillField>(address_field, ASCIIToUTF16("name1")));
+ AddTextFormFieldData("firstName", "Name", UNKNOWN_TYPE);
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.cc b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
index a7564839f06..7ed0724daa4 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
@@ -13,7 +13,7 @@ namespace autofill {
// static
std::unique_ptr<FormField> SearchField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
AutofillField* field;
auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.h b/chromium/components/autofill/core/browser/form_parsing/search_field.h
index 99e70eb9a2c..c0709a9b773 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -23,7 +24,7 @@ class LogManager;
class SearchField : public FormField {
public:
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
SearchField(const AutofillField* field);
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc
index a6be80cc7e0..7fc31841bb9 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc
@@ -5,80 +5,36 @@
#include "components/autofill/core/browser/form_parsing/search_field.h"
#include <memory>
-#include <vector>
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
-#include "components/autofill/core/common/form_field_data.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ASCIIToUTF16;
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
+#include "components/autofill/core/common/form_data.h"
namespace autofill {
-class SearchFieldTest : public testing::Test {
+class SearchFieldTest : public FormFieldTest {
public:
SearchFieldTest() = default;
SearchFieldTest(const SearchFieldTest&) = delete;
SearchFieldTest& operator=(const SearchFieldTest&) = delete;
protected:
- // Downcast for tests.
- static std::unique_ptr<SearchField> Parse(AutofillScanner* scanner) {
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- std::unique_ptr<FormField> field =
- SearchField::Parse(scanner, /*page_language=*/"", nullptr);
- return std::unique_ptr<SearchField>(
- static_cast<SearchField*>(field.release()));
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("en")) override {
+ return SearchField::Parse(scanner, page_language, nullptr);
}
-
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<SearchField> field_;
- FieldCandidatesMap field_candidates_map_;
-
- // RAII object to mock the the PatternProvider.
- TestPatternProvider test_pattern_provider_;
};
TEST_F(SearchFieldTest, ParseSearchTerm) {
- FormFieldData search_field;
- search_field.form_control_type = "text";
-
- search_field.label = ASCIIToUTF16("Search");
- search_field.name = ASCIIToUTF16("search");
+ AddTextFormFieldData("search", "Search", SEARCH_TERM);
- list_.push_back(
- std::make_unique<AutofillField>(search_field, ASCIIToUTF16("search1")));
-
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_NE(nullptr, field_.get());
- field_->AddClassifications(&field_candidates_map_);
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("search1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(SEARCH_TERM,
- field_candidates_map_[ASCIIToUTF16("search1")].BestHeuristicType());
+ ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(SearchFieldTest, ParseNonSearchTerm) {
- FormFieldData address_field;
- address_field.form_control_type = "text";
-
- address_field.label = ASCIIToUTF16("Address");
- address_field.name = ASCIIToUTF16("address");
-
- list_.push_back(
- std::make_unique<AutofillField>(address_field, ASCIIToUTF16("address")));
+ AddTextFormFieldData("address", "Address", UNKNOWN_TYPE);
- AutofillScanner scanner(list_);
- field_ = Parse(&scanner);
- ASSERT_EQ(nullptr, field_.get());
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
index 2e1dc92a836..0817d6750f4 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
@@ -16,29 +16,33 @@ TravelField::~TravelField() = default;
// static
std::unique_ptr<FormField> TravelField::Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager) {
- if (!scanner || scanner->IsEnd()) {
+ if (!scanner || scanner->IsEnd())
return nullptr;
- }
- auto& patternsP = PatternProvider::GetInstance().GetMatchPatterns(
- "PASSPORT", page_language);
- auto& patternsTO = PatternProvider::GetInstance().GetMatchPatterns(
- "TRAVEL_ORIGIN", page_language);
- auto& patternsTD = PatternProvider::GetInstance().GetMatchPatterns(
- "TRAVEL_DESTINATION", page_language);
- auto& patternsF =
+
+ const std::vector<MatchingPattern>& passport_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("PASSPORT",
+ page_language);
+ const std::vector<MatchingPattern>& travel_origin_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("TRAVEL_ORIGIN",
+ page_language);
+ const std::vector<MatchingPattern>& travel_destination_patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("TRAVEL_DESTINATION",
+ page_language);
+ const std::vector<MatchingPattern>& flight_patterns =
PatternProvider::GetInstance().GetMatchPatterns("FLIGHT", page_language);
auto travel_field = std::make_unique<TravelField>();
- if (ParseField(scanner, base::UTF8ToUTF16(kPassportRe), patternsP,
+ if (ParseField(scanner, base::UTF8ToUTF16(kPassportRe), passport_patterns,
&travel_field->passport_, {log_manager, "kPassportRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kTravelOriginRe), patternsTO,
- &travel_field->origin_, {log_manager, "kTravelOriginRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kTravelDestinationRe), patternsTD,
- &travel_field->destination_,
+ ParseField(scanner, base::UTF8ToUTF16(kTravelOriginRe),
+ travel_origin_patterns, &travel_field->origin_,
+ {log_manager, "kTravelOriginRe"}) ||
+ ParseField(scanner, base::UTF8ToUTF16(kTravelDestinationRe),
+ travel_destination_patterns, &travel_field->destination_,
{log_manager, "kTravelDestinationRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kFlightRe), patternsF,
+ ParseField(scanner, base::UTF8ToUTF16(kFlightRe), flight_patterns,
&travel_field->flight_, {log_manager, "kFlightRe"})) {
// If any regex matches, then we found a travel field.
return std::move(travel_field);
diff --git a/chromium/components/autofill/core/browser/form_parsing/travel_field.h b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
index 9b2d2e5e891..45d05511c10 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
@@ -10,6 +10,7 @@
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -20,7 +21,7 @@ class TravelField : public FormField {
~TravelField() override;
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
- const std::string& page_language,
+ const LanguageCode& page_language,
LogManager* log_manager);
protected:
diff --git a/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc b/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc
new file mode 100644
index 00000000000..50e7e56a1b3
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc
@@ -0,0 +1,108 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/form_processing/label_processing_util.h"
+
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace autofill {
+
+using LabelPieces = std::vector<base::StringPiece16>;
+
+// The maximum number of fields that can share a label.
+const int kMaxNumberOfFieldsToShareALabel = 3;
+// The maximum length of a label that can be shared among fields.
+const int kMaxLengthOfShareableLabel = 40;
+
+base::Optional<std::vector<base::string16>> GetParseableLabels(
+ const LabelPieces& labels) {
+ // Make a copy of the labels.
+ LabelPieces shared_labels = labels;
+
+ // Tracks if at least one shared label was found.
+ bool shared_labels_found = false;
+
+ // The index of the current field that may be eligible to share its label with
+ // the subsequent fields.
+ size_t label_index = 0;
+ while (label_index < labels.size()) {
+ const auto& label = labels.at(label_index);
+ // If the label is empty or has a size that exceeds
+ // |kMaxLengthOfShareableLabel| it can not be shared with subsequent fields.
+ if (label.empty() || label.size() > kMaxLengthOfShareableLabel) {
+ ++label_index;
+ continue;
+ }
+
+ // Otherwise search if the subsequent fields are empty.
+ size_t scan_index = label_index + 1;
+ while (scan_index < labels.size()) {
+ if (!labels.at(scan_index).empty()) {
+ break;
+ }
+ ++scan_index;
+ }
+ // After the loop, the |scan_index| points to the first subsequent field
+ // that does not have an empty label or is the first out-of-bound index.
+
+ // Calculate the number of fields that may share a label.
+ size_t fields_to_share_label = scan_index - label_index;
+
+ // Remember the current index and increment it to continue with the next
+ // non-empty field.
+ size_t shared_label_starting_index = label_index;
+ label_index = scan_index;
+
+ // Determine if there is the correct number of fields that may share a
+ // label.
+ if (fields_to_share_label == 1 ||
+ fields_to_share_label > kMaxNumberOfFieldsToShareALabel) {
+ continue;
+ }
+
+ // Otherwise, try to split the label by single character separators.
+ LabelPieces label_components = base::SplitStringPiece(
+ label, base::ASCIIToUTF16("/,&-"), base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+
+ // If the number of components does not match, try to split by common
+ // separating words.
+ if (label_components.size() != fields_to_share_label) {
+ for (const char* word : {" and ", " und ", " et ", " y "}) {
+ label_components = base::SplitStringPieceUsingSubstr(
+ label, base::ASCIIToUTF16(word), base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ if (label_components.size() == fields_to_share_label)
+ break;
+ }
+ }
+
+ // Continue to the next field if the right number of components has not
+ // been found.
+ if (label_components.size() != fields_to_share_label)
+ continue;
+
+ shared_labels_found = true;
+ // Otherwise assign the label components to the fields.
+ for (size_t i = 0; i < label_components.size(); ++i) {
+ shared_labels[shared_label_starting_index + i] = label_components.at(i);
+ }
+ }
+
+ if (!shared_labels_found) {
+ return base::nullopt;
+ }
+
+ // Otherwise convert the shared label string pieces into strings for memory
+ // safety.
+ std::vector<base::string16> result;
+ result.reserve(shared_labels.size());
+ base::ranges::transform(shared_labels, std::back_inserter(result),
+ [](auto& s) { return base::string16(s); });
+ return base::make_optional(std::move(result));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_processing/label_processing_util.h b/chromium/components/autofill/core/browser/form_processing/label_processing_util.h
new file mode 100644
index 00000000000..31e581a5f32
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_processing/label_processing_util.h
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PROCESSING_LABEL_PROCESSING_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PROCESSING_LABEL_PROCESSING_UTIL_H_
+
+#include <vector>
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+
+namespace autofill {
+
+// If parseable labels can be derived from |labels|, a vector of
+// |base::string16| is return that is aligned with |labels|.
+// Parseable labels can be derived by splitting one label between multiple
+// adjacent fields. If there aren't any changes to the labels, |base::nullopt|
+// is returned.
+base::Optional<std::vector<base::string16>> GetParseableLabels(
+ const std::vector<base::StringPiece16>& labels);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PROCESSING_LABEL_PROCESSING_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc b/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc
new file mode 100644
index 00000000000..f72bdf6d788
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/form_processing/label_processing_util.h"
+
+#include "base/feature_list.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+namespace {
+
+std::vector<base::StringPiece16> StringsToStringPieces(
+ const std::vector<base::string16>& strings) {
+ std::vector<base::StringPiece16> string_pieces;
+ for (const auto& s : strings) {
+ string_pieces.emplace_back(base::StringPiece16(s));
+ }
+ return string_pieces;
+}
+
+} // namespace
+
+namespace autofill {
+
+TEST(LabelProcessingUtil, GetParseableNameStringPieces) {
+ std::vector<base::string16> labels;
+ labels.push_back(ASCIIToUTF16("City"));
+ labels.push_back(ASCIIToUTF16("Street & House Number"));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16("Zip"));
+
+ auto expectation = base::make_optional(std::vector<base::string16>());
+ expectation->push_back(ASCIIToUTF16("City"));
+ expectation->push_back(ASCIIToUTF16("Street"));
+ expectation->push_back(ASCIIToUTF16("House Number"));
+ expectation->push_back(ASCIIToUTF16("Zip"));
+
+ EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+}
+
+TEST(LabelProcessingUtil, GetParseableNameStringPieces_ThreeComponents) {
+ std::vector<base::string16> labels;
+ labels.push_back(ASCIIToUTF16("City"));
+ labels.push_back(ASCIIToUTF16("Street & House Number & Floor"));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16("Zip"));
+
+ auto expectation = base::make_optional(std::vector<base::string16>());
+ expectation->push_back(ASCIIToUTF16("City"));
+ expectation->push_back(ASCIIToUTF16("Street"));
+ expectation->push_back(ASCIIToUTF16("House Number"));
+ expectation->push_back(ASCIIToUTF16("Floor"));
+ expectation->push_back(ASCIIToUTF16("Zip"));
+
+ EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+}
+
+TEST(LabelProcessingUtil, GetParseableNameStringPieces_TooManyComponents) {
+ std::vector<base::string16> labels;
+ labels.push_back(ASCIIToUTF16("City"));
+ labels.push_back(ASCIIToUTF16("Street & House Number & Floor & Stairs"));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16("Zip"));
+
+ base::Optional<std::vector<base::string16>> expectation = base::nullopt;
+ ;
+
+ EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+}
+
+TEST(LabelProcessingUtil, GetParseableNameStringPieces_UnmachtingComponents) {
+ std::vector<base::string16> labels;
+ labels.push_back(ASCIIToUTF16("City"));
+ labels.push_back(ASCIIToUTF16("Street & House Number & Floor"));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16("Zip"));
+
+ base::Optional<std::vector<base::string16>> expectation = base::nullopt;
+
+ EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+}
+
+TEST(LabelProcessingUtil, GetParseableNameStringPieces_SplitableLabelAtEnd) {
+ std::vector<base::string16> labels;
+ labels.push_back(ASCIIToUTF16("City"));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16("Zip"));
+ labels.push_back(ASCIIToUTF16("Street & House Number & Floor"));
+
+ base::Optional<std::vector<base::string16>> expectation = base::nullopt;
+
+ EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+}
+
+TEST(LabelProcessingUtil, GetParseableNameStringPieces_TooLongLabel) {
+ std::vector<base::string16> labels;
+ labels.push_back(ASCIIToUTF16("City"));
+ labels.push_back(
+ ASCIIToUTF16("Street & House Number with a lot of additional text that "
+ "exceeds 40 characters by far"));
+ labels.push_back(ASCIIToUTF16(""));
+ labels.push_back(ASCIIToUTF16("Zip"));
+
+ base::Optional<std::vector<base::string16>> expectation = base::nullopt;
+
+ EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc b/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc
new file mode 100644
index 00000000000..7df75933fd0
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc
@@ -0,0 +1,239 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/form_processing/name_processing_util.h"
+
+#include "base/feature_list.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/common/autofill_features.h"
+
+namespace autofill {
+
+// Only removing common name prefixes if we have a minimum number of fields and
+// a minimum prefix length. These values are chosen to avoid cases such as two
+// fields with "address1" and "address2" and be effective against web frameworks
+// which prepend prefixes such as "ctl01$ctl00$MainContentRegion$" on all
+// fields.
+constexpr int kCommonNamePrefixRemovalFieldThreshold = 3;
+// Minimum required length for prefixes common to a subset of the field names.
+constexpr int kMinCommonNamePrefixLength = 16;
+// Minimum required number of available fields for trying to remove affixes.
+constexpr int kCommonNameAffixRemovalFieldNumberThreshold = 3;
+// Minimum required length for affixes common to all field names.
+constexpr int kMinCommonNameAffixLength = 3;
+// Minimum required length for prefixes common to a subset of the field names.
+constexpr int kMinCommonNameLongPrefixLength = 16;
+// Regular expression for checking if |parseable_name| is valid after stripping
+// affixes.
+constexpr char kParseableNameValidationRe[] = "\\D";
+
+using NamePieces = std::vector<base::StringPiece16>;
+using OptionalNamePieces = base::Optional<NamePieces>;
+
+// Returns the length of the longest common prefix.
+// If |findCommonSuffix| is set, the length of the longest common suffix is
+// returned.
+size_t FindLongestCommonAffixLength(const NamePieces& strings,
+ bool findCommonSuffix) {
+ if (strings.empty())
+ return 0;
+
+ // Go through each character of the first string until there is a mismatch at
+ // the same position in any other string. Adapted from http://goo.gl/YGukMM.
+ for (size_t affix_len = 0; affix_len < strings[0].size(); affix_len++) {
+ size_t base_string_index =
+ findCommonSuffix ? strings[0].size() - affix_len - 1 : affix_len;
+ for (size_t i = 1; i < strings.size(); i++) {
+ size_t compared_string_index =
+ findCommonSuffix ? strings[i].size() - affix_len - 1 : affix_len;
+ if (affix_len >= strings[i].size() ||
+ strings[i][compared_string_index] != strings[0][base_string_index]) {
+ // Mismatch found.
+ return affix_len;
+ }
+ }
+ }
+ return strings[0].size();
+}
+
+// Find the longest prefix in |strings| when only considering entries with a
+// |minimal_length|.
+size_t FindLongestCommonPrefixLengthInStringsWithMinimalLength(
+ const NamePieces& strings,
+ size_t minimal_length) {
+ if (strings.empty())
+ return 0;
+
+ NamePieces filtered_strings;
+
+ // Any strings less than |minimal_length| are not considered when processing
+ // for a common prefix.
+ std::copy_if(
+ strings.begin(), strings.end(), std::back_inserter(filtered_strings),
+ [&](base::StringPiece16 s) { return s.length() >= minimal_length; });
+
+ if (filtered_strings.empty())
+ return 0;
+
+ return FindLongestCommonAffixLength(filtered_strings, false);
+}
+
+// Returns true if |parseable_name| is a valid parseable_name. Current criterion
+// is the |autofill::kParseableNameValidationRe| regex.
+bool IsValidParseableName(const base::StringPiece16 parseable_name) {
+ static const base::string16 kParseableNameValidationPattern =
+ base::UTF8ToUTF16(kParseableNameValidationRe);
+ return MatchesPattern(parseable_name, kParseableNameValidationPattern);
+}
+
+// Tries to strip |offset_left| and |offset_right| from entriees in
+// |field_names| and checks if the resulting names are still valid parseable
+// names. If not possible, return |base::nullopt|.
+OptionalNamePieces GetStrippedParseableNamesIfValid(
+ const NamePieces& field_names,
+ size_t offset_left,
+ size_t offset_right,
+ size_t minimal_string_length_to_strip) {
+ NamePieces stripped_names;
+ stripped_names.reserve(field_names.size());
+
+ for (auto& parseable_name : field_names) {
+ // This check allows to only strip affixes from long enough strings.
+ stripped_names.push_back(
+ parseable_name.size() > offset_right + offset_left &&
+ parseable_name.size() >= minimal_string_length_to_strip
+ ? parseable_name.substr(offset_left, parseable_name.size() -
+ offset_right - offset_left)
+ : parseable_name);
+
+ if (!IsValidParseableName(stripped_names.back()))
+ return base::nullopt;
+ }
+
+ return base::make_optional(stripped_names);
+}
+
+// Tries to remove common affixes from |field_names| and returns the result. If
+// neither a common affix exists, or if one or more of the resulting strings is
+// not a valid parseable name, |base::nullopt| is returned.
+// The number of names in |field_names| must exceed
+// |kCommonNameAffixRemovalFieldNumberThreshold| in order to make the affix
+// removal possible. Also, the length of an affix must exceed
+// |kMinCommonNameAffixLength| to be removed.
+OptionalNamePieces RemoveCommonAffixesIfPossible(
+ const NamePieces& field_names) {
+ // Updates the field name parsed by heuristics if several criteria are met.
+ // Several fields must be present in the form.
+ if (field_names.size() < kCommonNameAffixRemovalFieldNumberThreshold)
+ return base::nullopt;
+
+ size_t longest_prefix_length =
+ FindLongestCommonAffixLength(field_names, false);
+ size_t longest_suffix_length =
+ FindLongestCommonAffixLength(field_names, true);
+
+ // Don't remove the common affix if it's not long enough.
+ if (longest_prefix_length < kMinCommonNameAffixLength)
+ longest_prefix_length = 0;
+
+ if (longest_suffix_length < kMinCommonNameAffixLength)
+ longest_suffix_length = 0;
+
+ // If neither a common prefix of suffix was found return false.
+ if (longest_prefix_length == 0 && longest_suffix_length == 0) {
+ return base::nullopt;
+ }
+
+ // Otherwise try to reduce the names.
+ return GetStrippedParseableNamesIfValid(field_names, longest_prefix_length,
+ longest_suffix_length,
+ /*minimal_string_length_to_strip=*/0);
+}
+
+// Tries to remove common prefixes from |field_names| and returns the result. If
+// neither a common prefix exists, or if one or more of the resulting strings is
+// not a valid parseable name, |base::nullopt| is returned.
+// The number of names in |field_names| must exceed
+// |kCommonNamePrefixRemovalFieldThreshold| in order to make the prefix
+// removal possible. Also, the length of a prefix must exceed
+// |kMinCommonNamePrefixLength| to be removed.
+OptionalNamePieces RemoveCommonPrefixIfPossible(const NamePieces& field_names) {
+ // Updates the field name parsed by heuristics if several criteria are met.
+ // Several fields must be present in the form.
+ if (field_names.size() < kCommonNamePrefixRemovalFieldThreshold)
+ return base::nullopt;
+
+ size_t longest_prefix_length =
+ FindLongestCommonAffixLength(field_names, false);
+
+ // Don't remove the common affix if it's not long enough.
+ if (longest_prefix_length < kMinCommonNamePrefixLength)
+ return base::nullopt;
+
+ // Otherwise try to reduce the names.
+ return GetStrippedParseableNamesIfValid(
+ field_names, longest_prefix_length, /*offset_right=*/0,
+ /*minimal_string_length_to_strip=*/kMinCommonNamePrefixLength);
+}
+
+// If possible, returns field names with a removed common prefix that is common
+// to the subset of names in |field_names| with a minimal length of
+// |kMinCommonNameLongPrefixLength|.
+// The number of names in |field_names| must exceed
+// |kCommonNamePrefixRemovalFieldThreshold| in order to make the prefix
+// removal possible. Also, the length of a prefix must exceed
+// |kMinCommonNameLongPrefixLength| to be removed.
+OptionalNamePieces RemoveCommonPrefixForNamesWithMinimalLengthIfPossible(
+ const NamePieces& field_names) {
+ // Update the field name parsed by heuristics if several criteria are met.
+ // Several fields must be present in the form.
+ if (field_names.size() < kCommonNamePrefixRemovalFieldThreshold)
+ return base::nullopt;
+
+ const size_t longest_prefix =
+ FindLongestCommonPrefixLengthInStringsWithMinimalLength(
+ field_names, kMinCommonNameLongPrefixLength);
+ if (longest_prefix < kMinCommonNameLongPrefixLength) {
+ return base::nullopt;
+ }
+
+ return GetStrippedParseableNamesIfValid(field_names, longest_prefix, 0,
+ kMinCommonNameLongPrefixLength);
+}
+
+std::vector<base::string16> GetParseableNames(const NamePieces& field_names) {
+ OptionalNamePieces parseable_names = base::nullopt;
+
+ std::vector<base::string16> result;
+ result.reserve(field_names.size());
+
+ // If the feature is enabled, try to remove a common affix. If this is not
+ // possible try to remove lengthy prefixes that may be missing in short names.
+ if (base::FeatureList::IsEnabled(features::kAutofillLabelAffixRemoval)) {
+ // Try to remove both common suffixes and prefixes that are common to all
+ // fields.
+ parseable_names = RemoveCommonAffixesIfPossible(field_names);
+ if (!parseable_names.has_value()) {
+ // Remove prefix common to string that have a minimum length given by
+ // |kMinCommonNamePrefixLength|.
+ parseable_names =
+ RemoveCommonPrefixForNamesWithMinimalLengthIfPossible(field_names);
+ }
+
+ } else {
+ parseable_names = RemoveCommonPrefixIfPossible(field_names);
+ }
+
+ // If there are no parseable names after affix removal, return the original
+ // field names.
+ base::ranges::transform(
+ parseable_names.has_value() ? parseable_names.value() : field_names,
+ std::back_inserter(result), [](auto& s) { return base::string16(s); });
+
+ return result;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_processing/name_processing_util.h b/chromium/components/autofill/core/browser/form_processing/name_processing_util.h
new file mode 100644
index 00000000000..9500b42796a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_processing/name_processing_util.h
@@ -0,0 +1,64 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PROCESSING_NAME_PROCESSING_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PROCESSING_NAME_PROCESSING_UTIL_H_
+
+#include <vector>
+
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
+#include "components/autofill/core/browser/form_structure.h"
+
+namespace autofill {
+
+#ifdef UNIT_TEST
+size_t FindLongestCommonAffixLength(
+ const std::vector<base::StringPiece16>& strings,
+ bool findCommonSuffix);
+
+bool IsValidParseableName(const base::StringPiece16 parseable_name);
+
+base::Optional<std::vector<base::StringPiece16>> RemoveCommonAffixesIfPossible(
+ const std::vector<base::StringPiece16>& field_names);
+
+size_t FindLongestCommonPrefixLengthInStringsWithMinimalLength(
+ const std::vector<base::StringPiece16>& strings,
+ size_t minimal_length);
+
+base::Optional<std::vector<base::StringPiece16>>
+GetStrippedParseableNamesIfValid(
+ const std::vector<base::StringPiece16>& field_names,
+ size_t offset_left,
+ size_t offset_right,
+ size_t minimal_string_length_to_strip);
+
+base::Optional<std::vector<base::StringPiece16>> RemoveCommonPrefixIfPossible(
+ const std::vector<base::StringPiece16>& field_names);
+
+base::Optional<std::vector<base::StringPiece16>>
+RemoveCommonPrefixForNamesWithMinimalLengthIfPossible(
+ const std::vector<base::StringPiece16>& field_names);
+#endif
+
+// Determines and returns the parseable names for |field_names|.
+// With the |kAutofillLabelAffixRemoval| feature enabled, first it is tried to
+// remove a common affix from all names in |field_names|. If this is not
+// possible, it is attempted to remove long prefixes from a subset of names in
+// |field_names| which exceed a given length. If the
+// |kAutofillLabelAffixRemoval| is disabled, a prefix removal is attempted. In
+// any case, if a affix/prefix removal is not possible, the original names in
+// |field_names| are returned.
+//
+// Beware, this function works on string pieces and therefore, it should not be
+// called with temporary objects. Also, the underlying strings should not be
+// modified before the last usage of the result.
+std::vector<base::string16> GetParseableNames(
+ const std::vector<base::StringPiece16>& field_names);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PROCESSING_NAME_PROCESSING_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/form_processing/name_processing_util_unittest.cc b/chromium/components/autofill/core/browser/form_processing/name_processing_util_unittest.cc
new file mode 100644
index 00000000000..4481d9a0240
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_processing/name_processing_util_unittest.cc
@@ -0,0 +1,338 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/form_processing/name_processing_util.h"
+
+#include "base/feature_list.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+namespace {
+std::vector<base::StringPiece16> StringsToStringPieces(
+ const std::vector<base::string16>& strings) {
+ std::vector<base::StringPiece16> string_pieces;
+ for (const auto& s : strings) {
+ string_pieces.emplace_back(base::StringPiece16(s));
+ }
+ return string_pieces;
+}
+} // namespace
+
+namespace autofill {
+
+// Tests that the validity of parseable names is determined correctly.
+TEST(NameProcessingUtil, IsValidParseableName) {
+ // Parseable name should not be empty.
+ EXPECT_FALSE(IsValidParseableName(ASCIIToUTF16("")));
+ // Parseable name should not be solely numerical.
+ EXPECT_FALSE(IsValidParseableName(ASCIIToUTF16("1265125")));
+
+ // Valid parseable name cases.
+ EXPECT_TRUE(IsValidParseableName(ASCIIToUTF16("a23")));
+ EXPECT_TRUE(IsValidParseableName(ASCIIToUTF16("*)&%@")));
+}
+
+// Tests that the correct length of prefixes and suffixes are returned.
+TEST(NameProcessingUtil, FindLongestCommonAffixLength) {
+ auto String16ToStringPiece16 = [](std::vector<base::string16>& vin,
+ std::vector<base::StringPiece16>& vout) {
+ vout.clear();
+ for (auto& str : vin)
+ vout.push_back(str);
+ };
+
+ // Normal prefix case.
+ std::vector<base::string16> strings;
+ std::vector<base::StringPiece16> stringPieces;
+ strings.push_back(ASCIIToUTF16("123456XXX123456789"));
+ strings.push_back(ASCIIToUTF16("12345678XXX012345678_foo"));
+ strings.push_back(ASCIIToUTF16("1234567890123456"));
+ strings.push_back(ASCIIToUTF16("1234567XXX901234567890"));
+ String16ToStringPiece16(strings, stringPieces);
+ size_t affixLength = FindLongestCommonAffixLength(stringPieces, false);
+ EXPECT_EQ(ASCIIToUTF16("123456").size(), affixLength);
+
+ // Normal suffix case.
+ strings.clear();
+ strings.push_back(ASCIIToUTF16("black and gold dress"));
+ strings.push_back(ASCIIToUTF16("work_address"));
+ strings.push_back(ASCIIToUTF16("123456XXX1234_home_address"));
+ strings.push_back(ASCIIToUTF16("1234567890123456_city_address"));
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, true);
+ EXPECT_EQ(ASCIIToUTF16("dress").size(), affixLength);
+
+ // Handles no common prefix.
+ strings.clear();
+ strings.push_back(ASCIIToUTF16("1234567890123456"));
+ strings.push_back(ASCIIToUTF16("4567890123456789"));
+ strings.push_back(ASCIIToUTF16("7890123456789012"));
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, false);
+ EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
+
+ // Handles no common suffix.
+ strings.clear();
+ strings.push_back(ASCIIToUTF16("1234567890123456"));
+ strings.push_back(ASCIIToUTF16("4567890123456789"));
+ strings.push_back(ASCIIToUTF16("7890123456789012"));
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, true);
+ EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
+
+ // Only one string, prefix case.
+ strings.clear();
+ strings.push_back(ASCIIToUTF16("1234567890"));
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, false);
+ EXPECT_EQ(ASCIIToUTF16("1234567890").size(), affixLength);
+
+ // Only one string, suffix case.
+ strings.clear();
+ strings.push_back(ASCIIToUTF16("1234567890"));
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, true);
+ EXPECT_EQ(ASCIIToUTF16("1234567890").size(), affixLength);
+
+ // Empty vector, prefix case.
+ strings.clear();
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, false);
+ EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
+
+ // Empty vector, suffix case.
+ strings.clear();
+ String16ToStringPiece16(strings, stringPieces);
+ affixLength = FindLongestCommonAffixLength(stringPieces, true);
+ EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
+}
+
+// Tests the determination of the length of the longest common prefix for
+// strings with a minimal length.
+TEST(NameProcessingUtil,
+ FindLongestCommonPrefixLengthForStringsWithMinimalLength) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("aabbccddeeff"));
+ strings.push_back(ASCIIToUTF16("aabbccddeeffgg"));
+ strings.push_back(ASCIIToUTF16("zzz"));
+ strings.push_back(ASCIIToUTF16("aabbc___"));
+ EXPECT_EQ(FindLongestCommonPrefixLengthInStringsWithMinimalLength(
+ StringsToStringPieces(strings), 4),
+ 5U);
+ EXPECT_EQ(FindLongestCommonPrefixLengthInStringsWithMinimalLength(
+ StringsToStringPieces(strings), 3),
+ 0U);
+}
+
+// Tests that a |base::nullopt| is returned if no common affix was removed.
+TEST(NameProcessingUtil, RemoveCommonAffixesIfPossible_NotPossible) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abc"));
+ strings.push_back(ASCIIToUTF16("def"));
+ strings.push_back(ASCIIToUTF16("abcd"));
+ strings.push_back(ASCIIToUTF16("abcdef"));
+
+ EXPECT_EQ(RemoveCommonAffixesIfPossible(StringsToStringPieces(strings)),
+ base::nullopt);
+}
+
+// Tests that both the prefix and the suffix are removed.
+TEST(NameProcessingUtil, RemoveCommonAffixesIfPossible) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abcaazzz"));
+ strings.push_back(ASCIIToUTF16("abcbbzzz"));
+ strings.push_back(ASCIIToUTF16("abccczzz"));
+
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aa"));
+ expectation.push_back(ASCIIToUTF16("bb"));
+ expectation.push_back(ASCIIToUTF16("cc"));
+
+ EXPECT_EQ(RemoveCommonAffixesIfPossible(StringsToStringPieces(strings)),
+ StringsToStringPieces(expectation));
+}
+
+// Tests that a |base::nullopt| is returned if no common prefix was removed.
+TEST(NameProcessingUtil, RemoveCommonPrefixIfPossible_NotPossible) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abc"));
+ strings.push_back(ASCIIToUTF16("def"));
+ strings.push_back(ASCIIToUTF16("abcd"));
+ strings.push_back(ASCIIToUTF16("abcdef"));
+
+ EXPECT_EQ(RemoveCommonPrefixIfPossible(StringsToStringPieces(strings)),
+ base::nullopt);
+}
+
+// Tests that prefix is removed correctly.
+TEST(NameProcessingUtil, RemoveCommonPrefixIfPossible) {
+ std::vector<base::string16> strings;
+ // The strings contain a long common prefix that can be removed.
+ strings.push_back(ASCIIToUTF16("ccccccccccccccccaazzz"));
+ strings.push_back(ASCIIToUTF16("ccccccccccccccccbbzzz"));
+ strings.push_back(ASCIIToUTF16("cccccccccccccccccczzz"));
+
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aazzz"));
+ expectation.push_back(ASCIIToUTF16("bbzzz"));
+ expectation.push_back(ASCIIToUTF16("cczzz"));
+
+ EXPECT_EQ(RemoveCommonPrefixIfPossible(StringsToStringPieces(strings)),
+ StringsToStringPieces(expectation));
+}
+
+// Tests that prefix is removed correctly for fields with a minimal length.
+TEST(NameProcessingUtil,
+ RemoveCommonPrefixForFieldsWithMinimalLengthIfPossible) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("ccccccccccccccccaazzz"));
+ // This name is too short to be considered and is skipped both in the
+ // detection of prefixes as well as in the removal.
+ strings.push_back(ASCIIToUTF16("abc"));
+ strings.push_back(ASCIIToUTF16("cccccccccccccccccczzz"));
+
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aazzz"));
+ expectation.push_back(ASCIIToUTF16("abc"));
+ expectation.push_back(ASCIIToUTF16("cczzz"));
+
+ EXPECT_EQ(RemoveCommonPrefixForNamesWithMinimalLengthIfPossible(
+ StringsToStringPieces(strings)),
+ StringsToStringPieces(expectation));
+}
+
+// Tests that prefix is not removed because it is too short.
+TEST(NameProcessingUtil, RemoveCommonPrefixIfPossible_TooShort) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abcaazzz"));
+ strings.push_back(ASCIIToUTF16("abcbbzzz"));
+ strings.push_back(ASCIIToUTF16("abccczzz"));
+
+ EXPECT_EQ(RemoveCommonPrefixIfPossible(StringsToStringPieces(strings)),
+ base::nullopt);
+}
+
+// Tests that the strings are correctly stripped.
+TEST(NameProcessingUtil, GetStrippedParseableNamesIfValid) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abcaazzz"));
+ strings.push_back(ASCIIToUTF16("abcbbzzz"));
+ strings.push_back(ASCIIToUTF16("abccczzz"));
+
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aaz"));
+ expectation.push_back(ASCIIToUTF16("bbz"));
+ expectation.push_back(ASCIIToUTF16("ccz"));
+
+ EXPECT_EQ(
+ GetStrippedParseableNamesIfValid(StringsToStringPieces(strings), 3, 2, 1),
+ StringsToStringPieces(expectation));
+}
+
+// Tests that a |base::nullopt| is returned if one of stripped names is not
+// valid.
+TEST(NameProcessingUtil, GetStrippedParseableNamesIfValid_NotValid) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abcaazzz"));
+ // This string is not valid because only the "1" is left after stripping.
+ strings.push_back(ASCIIToUTF16("abc1zz"));
+ strings.push_back(ASCIIToUTF16("abccczzz"));
+
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aaz"));
+ expectation.push_back(ASCIIToUTF16("bbz"));
+ expectation.push_back(ASCIIToUTF16("ccz"));
+
+ EXPECT_EQ(
+ GetStrippedParseableNamesIfValid(StringsToStringPieces(strings), 3, 2, 1),
+ base::nullopt);
+}
+
+// Tests that the parseable names are returned correctly.
+TEST(NameProcessingUtil, GetParseableNames_OnlyPrefix) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abcaazzz1"));
+ strings.push_back(ASCIIToUTF16("abcbbzzz2"));
+ strings.push_back(ASCIIToUTF16("abccczzz3"));
+
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillLabelAffixRemoval);
+
+ // With the feature turned on, the prefix is removed.
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aazzz1"));
+ expectation.push_back(ASCIIToUTF16("bbzzz2"));
+ expectation.push_back(ASCIIToUTF16("cczzz3"));
+
+ EXPECT_EQ(GetParseableNames(StringsToStringPieces(strings)), expectation);
+}
+
+// Tests that the parseable names are returned correctly.
+TEST(NameProcessingUtil, GetParseableNames_OnlySuffix) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("1aazzz"));
+ strings.push_back(ASCIIToUTF16("2bbzzz"));
+ strings.push_back(ASCIIToUTF16("3cczzz"));
+
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillLabelAffixRemoval);
+
+ // With the feature turned on, the suffix is removed.
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("1aa"));
+ expectation.push_back(ASCIIToUTF16("2bb"));
+ expectation.push_back(ASCIIToUTF16("3cc"));
+
+ EXPECT_EQ(GetParseableNames(StringsToStringPieces(strings)), expectation);
+}
+
+// Tests that the parseable names are returned correctly.
+TEST(NameProcessingUtil, GetParseableNames_Affix) {
+ std::vector<base::string16> strings;
+ strings.push_back(ASCIIToUTF16("abcaazzz"));
+ strings.push_back(ASCIIToUTF16("abcbbzzz"));
+ strings.push_back(ASCIIToUTF16("abccczzz"));
+
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillLabelAffixRemoval);
+
+ // With the feature turned on, the prefix and affix is removed.
+ std::vector<base::string16> expectation;
+ expectation.push_back(ASCIIToUTF16("aa"));
+ expectation.push_back(ASCIIToUTF16("bb"));
+ expectation.push_back(ASCIIToUTF16("cc"));
+
+ EXPECT_EQ(GetParseableNames(StringsToStringPieces(strings)), expectation);
+
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitAndDisableFeature(
+ features::kAutofillLabelAffixRemoval);
+
+ // With the feature turned off, the names are too short for a prefix removal.
+ expectation.clear();
+ expectation.push_back(ASCIIToUTF16("abcaazzz"));
+ expectation.push_back(ASCIIToUTF16("abcbbzzz"));
+ expectation.push_back(ASCIIToUTF16("abccczzz"));
+ EXPECT_EQ(GetParseableNames(StringsToStringPieces(strings)), expectation);
+
+ // But very long prefixes are still removed.
+ strings.clear();
+ strings.push_back(ASCIIToUTF16("1234567890ABCDEFGabcaazzz"));
+ strings.push_back(ASCIIToUTF16("1234567890ABCDEFGabcbbzzz"));
+ strings.push_back(ASCIIToUTF16("1234567890ABCDEFGabccczzz"));
+
+ expectation.clear();
+ expectation.push_back(ASCIIToUTF16("aazzz"));
+ expectation.push_back(ASCIIToUTF16("bbzzz"));
+ expectation.push_back(ASCIIToUTF16("cczzz"));
+ EXPECT_EQ(GetParseableNames(StringsToStringPieces(strings)), expectation);
+}
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index 9bd72190efa..9a13c2ba9be 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -16,6 +16,7 @@
#include "base/base64.h"
#include "base/command_line.h"
+#include "base/containers/fixed_flat_map.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
@@ -38,6 +39,8 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/field_candidates.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/form_processing/label_processing_util.h"
+#include "components/autofill/core/browser/form_processing/name_processing_util.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/randomized_encoder.h"
#include "components/autofill/core/browser/rationalization_util.h"
@@ -49,6 +52,7 @@
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/autofill_util.h"
+#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
@@ -71,29 +75,6 @@ constexpr char kShippingMode[] = "shipping";
// Default section name for the fields.
constexpr char kDefaultSection[] = "-default";
-// Only removing common name prefixes if we have a minimum number of fields and
-// a minimum prefix length. These values are chosen to avoid cases such as two
-// fields with "address1" and "address2" and be effective against web frameworks
-// which prepend prefixes such as "ctl01$ctl00$MainContentRegion$" on all
-// fields.
-constexpr int kCommonNamePrefixRemovalFieldThreshold = 3;
-constexpr int kMinCommonNamePrefixLength = 16;
-
-// Affix removal configuration. Only remove short affixes if they are common
-// to all field names and there is at least the minimum number of fields.
-// If no affix common to all field names is found, search for a long
-// prefix common to a subset of the fields. This case helps include cases of
-// prefixes prepended by web frameworks.
-//
-// Minimum required number of available fields for trying to remove affixes.
-constexpr int kCommonNameAffixRemovalFieldNumberThreshold = 3;
-// Minimum required length for affixes common to all field names.
-constexpr int kMinCommonNameAffixLength = 3;
-// Minimum required length for prefixes common to a subset of the field names.
-constexpr int kMinCommonNameLongPrefixLength = 16;
-// Regex for checking if |parseable_name| is valid after stripping affixes.
-constexpr char kParseableNameValidationRe[] = "\\D";
-
// Returns true if the scheme given by |url| is one for which autofill is
// allowed to activate. By default this only returns true for HTTP and HTTPS.
bool HasAllowedScheme(const GURL& url) {
@@ -580,18 +561,65 @@ void EncodeFieldMetadataForQuery(const FormFieldData& field,
// For example, for Autofill to support fields of type
// "PHONE_HOME_COUNTRY_CODE", there would need to be at least one other field
// of type "PHONE_HOME_NUMBER" or "PHONE_HOME_CITY_AND_NUMBER".
-const std::unordered_map<ServerFieldType, ServerFieldTypeSet>&
-GetTypeRelationshipMap() {
- // Initialized and cached on first use.
- static const auto* const rules =
- new std::unordered_map<ServerFieldType, ServerFieldTypeSet>(
+const auto& GetTypeRelationshipMap() {
+ static const auto rules =
+ base::MakeFixedFlatMap<ServerFieldType, ServerFieldTypeSet>(
{{PHONE_HOME_COUNTRY_CODE,
{PHONE_HOME_NUMBER, PHONE_HOME_CITY_AND_NUMBER}}});
- return *rules;
+ return rules;
}
} // namespace
+class FormStructure::SectionedFieldsIndexes {
+ public:
+ SectionedFieldsIndexes() = default;
+ ~SectionedFieldsIndexes() = default;
+
+ size_t LastFieldIndex() const {
+ if (sectioned_indexes_.empty())
+ return std::numeric_limits<size_t>::max(); // Shouldn't happen.
+ return sectioned_indexes_.back().back();
+ }
+
+ void AddFieldIndex(const size_t index, bool is_new_section) {
+ if (is_new_section || Empty()) {
+ sectioned_indexes_.emplace_back();
+ }
+ sectioned_indexes_.back().push_back(index);
+ }
+
+ void WalkForwardToTheNextSection() { current_section_ptr_++; }
+
+ bool IsFinished() const {
+ return current_section_ptr_ >= sectioned_indexes_.size();
+ }
+
+ size_t CurrentIndex() const {
+ return current_section_ptr_ < sectioned_indexes_.size()
+ ? sectioned_indexes_[current_section_ptr_].front()
+ : std::numeric_limits<size_t>::max();
+ }
+
+ const std::vector<size_t>* CurrentSection() const {
+ return current_section_ptr_ < sectioned_indexes_.size()
+ ? &sectioned_indexes_[current_section_ptr_]
+ : nullptr;
+ }
+
+ void Reset() { current_section_ptr_ = 0; }
+
+ bool Empty() const { return sectioned_indexes_.empty(); }
+
+ private:
+ // A vector of sections. Each section is a vector of some of the indexes
+ // that belong to the same section. The sections and indexes are sorted by
+ // their order of appearance on the form.
+ std::vector<std::vector<size_t>> sectioned_indexes_;
+ // Points to a vector of indexes that belong to the same section.
+ size_t current_section_ptr_ = 0;
+};
+
FormStructure::FormStructure(const FormData& form)
: id_attribute_(form.id_attribute),
name_attribute_(form.name_attribute),
@@ -644,23 +672,24 @@ FormStructure::FormStructure(
FormStructure::~FormStructure() = default;
-void FormStructure::DetermineHeuristicTypes(LogManager* log_manager) {
+void FormStructure::DetermineHeuristicTypes(
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ LogManager* log_manager) {
const auto determine_heuristic_types_start_time =
AutofillTickClock::NowTicks();
// First, try to detect field types based on each field's |autocomplete|
// attribute value.
- if (!was_parsed_for_autocomplete_attributes_)
- ParseFieldTypesFromAutocompleteAttributes();
+ ParseFieldTypesFromAutocompleteAttributes();
// Then if there are enough active fields, and if we are dealing with either a
// proper <form> or a <form>-less checkout, run the heuristics and server
// prediction routines.
if (ShouldRunHeuristics()) {
const FieldCandidatesMap field_type_map = FormField::ParseFormFields(
- fields_, page_language_, is_form_tag_, log_manager);
+ fields_, current_page_language_, is_form_tag_, log_manager);
for (const auto& field : fields_) {
- const auto iter = field_type_map.find(field->unique_name());
+ const auto iter = field_type_map.find(field->unique_renderer_id);
if (iter != field_type_map.end()) {
field->set_heuristic_type(iter->second.BestHeuristicType());
}
@@ -687,6 +716,10 @@ void FormStructure::DetermineHeuristicTypes(LogManager* log_manager) {
1 << AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT;
}
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillParsingPatternsLanguageDetection)) {
+ RationalizeRepeatedFields(form_interactions_ukm_logger);
+ }
RationalizeFieldTypePredictions();
AutofillMetrics::LogDetermineHeuristicTypesTiming(
@@ -698,6 +731,7 @@ bool FormStructure::EncodeUploadRequest(
bool form_was_autofilled,
const std::string& login_form_signature,
bool observed_submission,
+ bool is_raw_metadata_uploading_enabled,
AutofillUploadContents* upload,
std::vector<FormSignature>* encoded_signatures) const {
DCHECK(AllTypesCaptured(*this, available_field_types));
@@ -711,8 +745,8 @@ bool FormStructure::EncodeUploadRequest(
upload->set_data_present(EncodeFieldTypes(available_field_types));
upload->set_passwords_revealed(passwords_were_revealed_);
upload->set_has_form_tag(is_form_tag_);
- if (!page_language_.empty() && randomized_encoder_ != nullptr) {
- upload->set_language(page_language_);
+ if (!current_page_language_->empty() && randomized_encoder_ != nullptr) {
+ upload->set_language(current_page_language_.value());
}
auto triggering_event = (submission_event_ != SubmissionIndicatorEvent::NONE)
@@ -730,7 +764,7 @@ bool FormStructure::EncodeUploadRequest(
upload);
}
- if (IsAutofillFieldMetadataEnabled()) {
+ if (is_raw_metadata_uploading_enabled) {
upload->set_action_signature(StrToHash64Bit(target_url_.host()));
if (!form_name().empty())
upload->set_form_name(base::UTF16ToUTF8(form_name()));
@@ -750,7 +784,8 @@ bool FormStructure::EncodeUploadRequest(
if (IsMalformed())
return false; // Malformed form, skip it.
- EncodeFormForUpload(upload, encoded_signatures);
+ EncodeFormForUpload(is_raw_metadata_uploading_enabled, upload,
+ encoded_signatures);
return true;
}
@@ -864,6 +899,12 @@ void FormStructure::ProcessQueryResponse(
std::vector<AutofillQueryResponse::FormSuggestion::FieldSuggestion::
FieldPrediction>
server_predictions;
+
+ if (current_field.has_primary_type_prediction()) {
+ field->set_server_type_prediction_is_override(
+ current_field.primary_type_prediction_is_override());
+ }
+
if (current_field.predictions_size() == 0) {
AutofillQueryResponse::FormSuggestion::FieldSuggestion::FieldPrediction
field_prediction;
@@ -890,6 +931,8 @@ void FormStructure::ProcessQueryResponse(
form->UpdateAutofillCount();
form->RationalizeRepeatedFields(form_interactions_ukm_logger);
form->RationalizeFieldTypePredictions();
+ // TODO(crbug.com/1154080): By calling this with false, autocomplete section
+ // attributes will be ignored.
form->IdentifySections(false);
}
@@ -935,13 +978,6 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions(
return forms;
}
-// static
-bool FormStructure::IsAutofillFieldMetadataEnabled() {
- const std::string group_name =
- base::FieldTrialList::FindFullName("AutofillFieldMetadata");
- return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
-}
-
std::unique_ptr<FormStructure> FormStructure::CreateForPasswordManagerUpload(
FormSignature form_signature,
const std::vector<FieldSignature>& field_signatures) {
@@ -1123,7 +1159,17 @@ void FormStructure::RetrieveFromCache(
}
}
field->set_server_type(cached_field->server_type());
+ field->set_server_type_prediction_is_override(
+ cached_field->server_type_prediction_is_override());
field->set_previously_autofilled(cached_field->previously_autofilled());
+
+ // Only retrieve an overall prediction from cache if a server prediction
+ // is set.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillRetrieveOverallPredictionsFromCache) &&
+ field->server_type() != NO_SERVER_DATA) {
+ field->SetTypeTo(cached_field->Type());
+ }
}
}
@@ -1153,6 +1199,8 @@ void FormStructure::LogQualityMetrics(
size_t num_detected_field_types = 0;
size_t num_edited_autofilled_fields = 0;
+ size_t num_of_accepted_autofilled_fields = 0;
+ size_t num_of_corrected_autofilled_fields = 0;
bool did_autofill_all_possible_fields = true;
bool did_autofill_some_possible_fields = false;
bool is_for_credit_card = IsCompleteCreditCardForm();
@@ -1196,6 +1244,13 @@ void FormStructure::LogQualityMetrics(
}
++num_detected_field_types;
+
+ // Count the number of autofilled and corrected fields.
+ if (field->is_autofilled)
+ ++num_of_accepted_autofilled_fields;
+ else if (field->previously_autofilled())
+ ++num_of_corrected_autofilled_fields;
+
if (field->is_autofilled)
did_autofill_some_possible_fields = true;
else if (!field->only_fill_when_focused())
@@ -1234,6 +1289,11 @@ void FormStructure::LogQualityMetrics(
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS;
}
+ // Log the number of autofilled fields at submission time.
+ AutofillMetrics::LogNumberOfAutofilledFieldsAtSubmission(
+ num_of_accepted_autofilled_fields,
+ num_of_corrected_autofilled_fields);
+
// Unlike the other times, the |submission_time| should always be
// available.
DCHECK(!submission_time.is_null());
@@ -1284,6 +1344,9 @@ void FormStructure::LogQualityMetricsBasedOnAutocomplete(
}
void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
+ if (was_parsed_for_autocomplete_attributes_)
+ return;
+
has_author_specified_types_ = false;
has_author_specified_sections_ = false;
has_author_specified_upi_vpa_hint_ = false;
@@ -1456,17 +1519,13 @@ FormData FormStructure::ToFormData() const {
data.is_formless_checkout = is_formless_checkout_;
data.unique_renderer_id = unique_renderer_id_;
- for (size_t i = 0; i < fields_.size(); ++i) {
- data.fields.push_back(FormFieldData(*fields_[i]));
+ for (const auto& field : fields_) {
+ data.fields.push_back(*field);
}
return data;
}
-FormStructure::SectionedFieldsIndexes::SectionedFieldsIndexes() {}
-
-FormStructure::SectionedFieldsIndexes::~SectionedFieldsIndexes() {}
-
void FormStructure::RationalizeCreditCardFieldPredictions() {
bool cc_first_name_found = false;
bool cc_last_name_found = false;
@@ -1644,16 +1703,17 @@ void FormStructure::RationalizeAddressLineFields(
for (sections_of_address_indexes->Reset();
!sections_of_address_indexes->IsFinished();
sections_of_address_indexes->WalkForwardToTheNextSection()) {
- auto current_section = sections_of_address_indexes->CurrentSection();
+ auto* current_section = sections_of_address_indexes->CurrentSection();
// The rationalization only applies to sections that have 2 or 3 visible
// street address predictions.
- if (current_section.size() != 2 && current_section.size() != 3) {
+ if (!current_section ||
+ (current_section->size() != 2 && current_section->size() != 3)) {
continue;
}
int nb_address_rationalized = 0;
- for (auto field_index : current_section) {
+ for (auto field_index : *current_section) {
switch (nb_address_rationalized) {
case 0:
ApplyRationalizationsToFieldAndLog(field_index, ADDRESS_HOME_LINE1,
@@ -1758,7 +1818,7 @@ bool FormStructure::FieldShouldBeRationalizedToCountry(size_t upper_index) {
for (int field_index = upper_index - 1; field_index >= 0; --field_index) {
if (fields_[field_index]->IsVisible() &&
AutofillType(fields_[field_index]->Type().GetStorableType()).group() ==
- ADDRESS_HOME &&
+ FieldTypeGroup::kAddressHome &&
fields_[field_index]->section == fields_[upper_index]->section) {
return false;
}
@@ -1784,10 +1844,6 @@ void FormStructure::RationalizeAddressStateCountry(
while (!sections_of_state_indexes->IsFinished() ||
!sections_of_country_indexes->IsFinished()) {
- auto current_section_of_state_indexes =
- sections_of_state_indexes->CurrentSection();
- auto current_section_of_country_indexes =
- sections_of_country_indexes->CurrentSection();
// If there are still sections left with both country and state type, and
// state and country current sections are equal, then that section has both
// state and country. No rationalization needed.
@@ -1800,22 +1856,33 @@ void FormStructure::RationalizeAddressStateCountry(
continue;
}
- size_t upper_index = 0, lower_index = 0;
+ size_t upper_index = 0;
+ size_t lower_index = 0;
+
+ auto* current_section_of_state_indexes =
+ sections_of_state_indexes->CurrentSection();
+ auto* current_section_of_country_indexes =
+ sections_of_country_indexes->CurrentSection();
+ DCHECK(current_section_of_state_indexes ||
+ current_section_of_country_indexes);
// If country section is before the state ones, it means that that section
// misses states, and the other way around.
- if (current_section_of_state_indexes < current_section_of_country_indexes) {
+ if (!current_section_of_country_indexes ||
+ (current_section_of_state_indexes &&
+ *current_section_of_state_indexes <
+ *current_section_of_country_indexes)) {
// We only rationalize when we have exactly two visible fields of a kind.
- if (current_section_of_state_indexes.size() == 2) {
- upper_index = current_section_of_state_indexes[0];
- lower_index = current_section_of_state_indexes[1];
+ if (current_section_of_state_indexes->size() == 2) {
+ upper_index = (*current_section_of_state_indexes)[0];
+ lower_index = (*current_section_of_state_indexes)[1];
}
sections_of_state_indexes->WalkForwardToTheNextSection();
} else {
// We only rationalize when we have exactly two visible fields of a kind.
- if (current_section_of_country_indexes.size() == 2) {
- upper_index = current_section_of_country_indexes[0];
- lower_index = current_section_of_country_indexes[1];
+ if (current_section_of_country_indexes->size() == 2) {
+ upper_index = (*current_section_of_country_indexes)[0];
+ lower_index = (*current_section_of_country_indexes)[1];
}
sections_of_country_indexes->WalkForwardToTheNextSection();
}
@@ -1855,24 +1922,25 @@ void FormStructure::RationalizeRepeatedFields(
// indexes of fields whose types are predicted as FULL_NAME by the server.
SectionedFieldsIndexes sectioned_field_indexes_by_type[MAX_VALID_FIELD_TYPE];
- for (const auto& field : fields_) {
+ for (size_t i = 0; i < fields_.size(); ++i) {
+ const AutofillField& field = *fields_[i];
// The hidden fields are not considered when rationalizing.
- if (!field->IsVisible())
+ if (!field.IsVisible())
continue;
// The billing and non-billing types are aggregated.
- auto current_type = field->Type().GetStorableType();
+ auto current_type = field.Type().GetStorableType();
if (current_type != UNKNOWN_TYPE && current_type < MAX_VALID_FIELD_TYPE) {
// Look at the sectioned field indexes for the current type, if the
// current field belongs to that section, then the field index should be
// added to that same section, otherwise, start a new section.
sectioned_field_indexes_by_type[current_type].AddFieldIndex(
- &field - &fields_[0],
+ i,
/*is_new_section*/ sectioned_field_indexes_by_type[current_type]
.Empty() ||
fields_[sectioned_field_indexes_by_type[current_type]
.LastFieldIndex()]
- ->section != field->section);
+ ->section != field.section);
}
}
@@ -1890,19 +1958,7 @@ void FormStructure::RationalizeRepeatedFields(
void FormStructure::RationalizeFieldTypePredictions() {
RationalizeCreditCardFieldPredictions();
for (const auto& field : fields_) {
- if (base::FeatureList::IsEnabled(features::kAutofillOffNoServerData) &&
- !field->should_autocomplete && field->server_type() == NO_SERVER_DATA &&
- field->heuristic_type() != CREDIT_CARD_VERIFICATION_CODE) {
- // When the field has autocomplete off, and the server returned no
- // prediction, then assume Autofill is not useful for the current field.
- // Special case for CVC (crbug.com/968036). We never send votes for CVC
- // fields, but we still fill them when the user inputs them via the CVC
- // prompt. Since Autofill doesn't trigger from a CVC field, we can keep
- // the client-side predictions for this type.
- field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
- } else {
- field->SetTypeTo(field->Type());
- }
+ field->SetTypeTo(field->Type());
}
RationalizeTypeRelationships();
}
@@ -1930,17 +1986,11 @@ void FormStructure::EncodeFormForQuery(
if (is_rich_query_enabled_) {
EncodeFieldMetadataForQuery(*field, added_field->mutable_metadata());
}
-
- if (IsAutofillFieldMetadataEnabled()) {
- added_field->set_control_type(field->form_control_type);
-
- if (!field->name.empty())
- added_field->set_name(base::UTF16ToUTF8(field->name));
- }
}
}
void FormStructure::EncodeFormForUpload(
+ bool is_raw_metadata_uploading_enabled,
AutofillUploadContents* upload,
std::vector<FormSignature>* encoded_signatures) const {
DCHECK(!IsMalformed());
@@ -2003,7 +2053,7 @@ void FormStructure::EncodeFormForUpload(
added_field->mutable_randomized_field_metadata());
}
- if (IsAutofillFieldMetadataEnabled()) {
+ if (is_raw_metadata_uploading_enabled) {
added_field->set_type(field->form_control_type);
if (!field->name.empty())
@@ -2035,12 +2085,192 @@ bool FormStructure::IsMalformed() const {
return false;
}
+void FormStructure::IdentifySectionsWithNewMethod() {
+ if (fields_.empty())
+ return;
+
+ const bool is_enabled_autofill_redundant_name_sectioning =
+ base::FeatureList::IsEnabled(
+ features::kAutofillSectionUponRedundantNameInfo);
+
+ // Creates a unique name for the section that starts with |field|.
+ // TODO(crbug/896689): Cleanup once experiment is launched.
+ auto get_section_name = [](const AutofillField& field) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillNameSectionsWithRendererIds)) {
+ return base::StrCat(
+ {field.name, base::ASCIIToUTF16("_"),
+ base::NumberToString16(field.unique_renderer_id.value())});
+ } else {
+ return field.unique_name();
+ }
+ };
+
+ base::string16 current_section = get_section_name(*fields_.front());
+
+ // Keep track of the types we've seen in this section.
+ ServerFieldTypeSet seen_types;
+ ServerFieldType previous_type = UNKNOWN_TYPE;
+
+ // Boolean flag that is set to true when a field in the current section
+ // has the autocomplete-section attribute defined.
+ bool previous_autocomplete_section_present = false;
+
+ bool is_hidden_section = false;
+ base::string16 last_visible_section;
+ for (const auto& field : fields_) {
+ const ServerFieldType current_type = field->Type().GetStorableType();
+ // All credit card fields belong to the same section that's different
+ // from address sections.
+ if (AutofillType(current_type).group() == FieldTypeGroup::kCreditCard) {
+ field->section = "credit-card";
+ continue;
+ }
+
+ bool already_saw_current_type = seen_types.count(current_type) > 0;
+
+ // Forms often ask for multiple phone numbers -- e.g. both a daytime and
+ // evening phone number. Our phone number detection is also generally a
+ // little off. Hence, ignore this field type as a signal here.
+ if (AutofillType(current_type).group() == FieldTypeGroup::kPhoneHome)
+ already_saw_current_type = false;
+
+ if (is_enabled_autofill_redundant_name_sectioning) {
+ // Forms sometimes have a different format of inputting names in
+ // different sections. If we believe a new name is being entered, assume
+ // it is a new section (unless there are two identical inputs in a row).
+ if (current_type == NAME_FULL)
+ already_saw_current_type |= (seen_types.count(NAME_LAST) > 0);
+ }
+
+ bool ignored_field = !field->IsVisible();
+
+ // This is the first visible field after a hidden section. Consider it as
+ // the continuation of the last visible section.
+ if (!ignored_field && is_hidden_section) {
+ current_section = last_visible_section;
+ }
+
+ // Start a new section by an ignored field, only if the next field is also
+ // already seen.
+ size_t field_index = &field - &fields_[0];
+ if (ignored_field &&
+ (is_hidden_section ||
+ !((field_index + 1) < fields_.size() &&
+ seen_types.count(
+ fields_[field_index + 1]->Type().GetStorableType()) > 0))) {
+ already_saw_current_type = false;
+ }
+
+ // Some forms have adjacent fields of the same type. Two common examples:
+ // * Forms with two email fields, where the second is meant to "confirm"
+ // the first.
+ // * Forms with a <select> menu for states in some countries, and a
+ // freeform <input> field for states in other countries. (Usually,
+ // only one of these two will be visible for any given choice of
+ // country.)
+ // Generally, adjacent fields of the same type belong in the same logical
+ // section.
+ if (current_type == previous_type)
+ already_saw_current_type = false;
+
+ // Boolean flag that is set to true when the |field| has
+ // autocomplete-section attribute defined.
+ bool autocomplete_section_attribute_present =
+ (field->section != kDefaultSection);
+
+ // Boolean flag that is set to true when the |field| has
+ // autocomplete-section attribute defined and is different that the
+ // previous field.
+ bool different_autocomplete_section_than_previous =
+ (autocomplete_section_attribute_present &&
+ (!field_index || fields_[field_index - 1]->section != field->section));
+
+ // Start a new section if the |current_type| was already seen or the
+ // autocomplete-section attribute is defined for the |field| which is
+ // different than the previous field.
+ if (current_type != UNKNOWN_TYPE &&
+ (already_saw_current_type ||
+ different_autocomplete_section_than_previous)) {
+ // Keep track of seen_types if the new section is hidden. The next
+ // visible section might be the continuation of the previous visible
+ // section.
+ if (ignored_field) {
+ is_hidden_section = true;
+ last_visible_section = current_section;
+ }
+
+ if (!is_hidden_section && (!autocomplete_section_attribute_present ||
+ different_autocomplete_section_than_previous))
+ seen_types.clear();
+
+ if (autocomplete_section_attribute_present &&
+ !previous_autocomplete_section_present) {
+ // If this field is the first field within the section with a defined
+ // autocomplete section, then change the section attribute of all the
+ // parsed fields in the current section to |field->section|.
+ int i = static_cast<int>(field_index - 1);
+ while (i >= 0 &&
+ base::UTF8ToUTF16(fields_[i]->section) == current_section) {
+ fields_[i]->section = field->section;
+ i--;
+ }
+ }
+
+ // The end of a section, so start a new section.
+ current_section = get_section_name(*field);
+
+ // The section described in the autocomplete section attribute
+ // overrides the value determined by the heuristic.
+ if (autocomplete_section_attribute_present)
+ current_section = base::UTF8ToUTF16(field->section);
+
+ previous_autocomplete_section_present =
+ autocomplete_section_attribute_present;
+ }
+
+ // Only consider a type "seen" if it was not ignored. Some forms have
+ // sections for different locales, only one of which is enabled at a
+ // time. Each section may duplicate some information (e.g. postal code)
+ // and we don't want that to cause section splits.
+ // Also only set |previous_type| when the field was not ignored. This
+ // prevents ignored fields from breaking up fields that are otherwise
+ // adjacent.
+ if (!ignored_field) {
+ seen_types.insert(current_type);
+ previous_type = current_type;
+ is_hidden_section = false;
+ }
+
+ field->section = base::UTF16ToUTF8(current_section);
+ }
+
+ // Ensure that credit card and address fields are in separate sections.
+ // This simplifies the section-aware logic in autofill_manager.cc.
+ for (const auto& field : fields_) {
+ FieldTypeGroup field_type_group = field->Type().group();
+ if (field_type_group == FieldTypeGroup::kCreditCard)
+ field->section = field->section + "-cc";
+ else
+ field->section = field->section + "-default";
+ }
+
+ // Since this function has changed the sections, subsequent calls to
+ // ParseFieldTypesFromAutocompleteAttributes(), which modifies the
+ // sections, too, should not be no-ops.
+ was_parsed_for_autocomplete_attributes_ = false;
+}
+
+// TODO(crbug/1153539): Make sectioning less stateful, less std::string-based.
void FormStructure::IdentifySections(bool has_author_specified_sections) {
if (fields_.empty())
return;
- const bool is_enabled_autofill_new_sectioning =
- base::FeatureList::IsEnabled(features::kAutofillUseNewSectioningMethod);
+ if (base::FeatureList::IsEnabled(features::kAutofillUseNewSectioningMethod)) {
+ IdentifySectionsWithNewMethod();
+ return;
+ }
+
const bool is_enabled_autofill_redundant_name_sectioning =
base::FeatureList::IsEnabled(
features::kAutofillSectionUponRedundantNameInfo);
@@ -2058,24 +2288,20 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
}
};
- if (!has_author_specified_sections || is_enabled_autofill_new_sectioning) {
+ if (!has_author_specified_sections) {
base::string16 current_section = get_section_name(*fields_.front());
// Keep track of the types we've seen in this section.
- std::set<ServerFieldType> seen_types;
+ ServerFieldTypeSet seen_types;
ServerFieldType previous_type = UNKNOWN_TYPE;
- // Boolean flag that is set to true when a field in the current section
- // has the autocomplete-section attribute defined.
- bool previous_autocomplete_section_present = false;
-
bool is_hidden_section = false;
base::string16 last_visible_section;
for (const auto& field : fields_) {
const ServerFieldType current_type = field->Type().GetStorableType();
// All credit card fields belong to the same section that's different
// from address sections.
- if (AutofillType(current_type).group() == CREDIT_CARD) {
+ if (AutofillType(current_type).group() == FieldTypeGroup::kCreditCard) {
field->section = "credit-card";
continue;
}
@@ -2085,7 +2311,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
// Forms often ask for multiple phone numbers -- e.g. both a daytime and
// evening phone number. Our phone number detection is also generally a
// little off. Hence, ignore this field type as a signal here.
- if (AutofillType(current_type).group() == PHONE_HOME)
+ if (AutofillType(current_type).group() == FieldTypeGroup::kPhoneHome)
already_saw_current_type = false;
if (is_enabled_autofill_redundant_name_sectioning) {
@@ -2127,31 +2353,10 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
if (current_type == previous_type)
already_saw_current_type = false;
- // Boolean flag that is set to true when the |field| has
- // autocomplete-section attribute defined.
- bool autocomplete_section_attribute_present = false;
- if (is_enabled_autofill_new_sectioning)
- autocomplete_section_attribute_present =
- (field->section != kDefaultSection);
-
- // Boolean flag that is set to true when the |field| has
- // autocomplete-section attribute defined and is different that the
- // previous field.
- bool different_autocomplete_section_than_previous = false;
- if (is_enabled_autofill_new_sectioning) {
- different_autocomplete_section_than_previous =
- (autocomplete_section_attribute_present &&
- (!field_index ||
- fields_[field_index - 1]->section != field->section));
- }
-
// Start a new section if the |current_type| was already seen or the
// autocomplete-section attribute is defined for the |field| which is
// different than the previous field.
- if (current_type != UNKNOWN_TYPE &&
- (already_saw_current_type ||
- (is_enabled_autofill_new_sectioning &&
- different_autocomplete_section_than_previous))) {
+ if (current_type != UNKNOWN_TYPE && already_saw_current_type) {
// Keep track of seen_types if the new section is hidden. The next
// visible section might be the continuation of the previous visible
// section.
@@ -2160,38 +2365,11 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
last_visible_section = current_section;
}
- if (!is_hidden_section &&
- (!is_enabled_autofill_new_sectioning ||
- !autocomplete_section_attribute_present ||
- different_autocomplete_section_than_previous))
+ if (!is_hidden_section)
seen_types.clear();
- if (is_enabled_autofill_new_sectioning &&
- autocomplete_section_attribute_present &&
- !previous_autocomplete_section_present) {
- // If this field is the first field within the section with a defined
- // autocomplete section, then change the section attribute of all the
- // parsed fields in the current section to |field->section|.
- int i = static_cast<int>(field_index - 1);
- while (i >= 0 &&
- base::UTF8ToUTF16(fields_[i]->section) == current_section) {
- fields_[i]->section = field->section;
- i--;
- }
- }
-
// The end of a section, so start a new section.
current_section = get_section_name(*field);
-
- if (is_enabled_autofill_new_sectioning) {
- // The section described in the autocomplete section attribute
- // overrides the value determined by the heuristic.
- if (autocomplete_section_attribute_present)
- current_section = base::UTF8ToUTF16(field->section);
-
- previous_autocomplete_section_present =
- autocomplete_section_attribute_present;
- }
}
// Only consider a type "seen" if it was not ignored. Some forms have
@@ -2215,11 +2393,16 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
// This simplifies the section-aware logic in autofill_manager.cc.
for (const auto& field : fields_) {
FieldTypeGroup field_type_group = field->Type().group();
- if (field_type_group == CREDIT_CARD)
+ if (field_type_group == FieldTypeGroup::kCreditCard)
field->section = field->section + "-cc";
else
field->section = field->section + "-default";
}
+
+ // Since this function has changed the sections, subsequent calls to
+ // ParseFieldTypesFromAutocompleteAttributes(), which modifies the
+ // sections, too, should not be no-ops.
+ was_parsed_for_autocomplete_attributes_ = false;
}
bool FormStructure::ShouldSkipField(const FormFieldData& field) const {
@@ -2227,183 +2410,71 @@ bool FormStructure::ShouldSkipField(const FormFieldData& field) const {
}
void FormStructure::ProcessExtractedFields() {
- if (base::FeatureList::IsEnabled(
- autofill::features::kAutofillLabelAffixRemoval)) {
- // Updates the field name parsed by heuristics if several criteria are met.
- // Several fields must be present in the form.
- if (field_count() < kCommonNameAffixRemovalFieldNumberThreshold)
- return;
-
- std::vector<base::StringPiece16> names;
- names.reserve(field_count());
- for (const auto& field : *this)
- names.push_back(field->name);
-
- int longest_prefix_length = FindLongestCommonAffixLength(names, false);
- int longest_suffix_length = FindLongestCommonAffixLength(names, true);
-
- // Don't remove the common affix if it's not long enough.
- if (longest_prefix_length < kMinCommonNameAffixLength)
- longest_prefix_length = 0;
-
- if (longest_suffix_length < kMinCommonNameAffixLength)
- longest_suffix_length = 0;
-
- bool success =
- SetStrippedParseableNames(longest_prefix_length, longest_suffix_length);
-
- // Don't search for inconsistent prefix if valid affixes are found.
- if (success && longest_prefix_length + longest_suffix_length > 0)
- return;
+ // Extracts the |parseable_name_| by removing common affixes from the
+ // field names.
+ ExtractParseableFieldNames();
- // Functionality for stripping a prefix only common to a subset
- // of field names.
- // This is needed because an exceptional field may be missing a prefix
- // which is otherwise consistently applied--for instance, a framework
- // may only apply a prefix to those fields which are bound when POSTing.
- names.clear();
- for (const auto& field : *this)
- if (field->name.size() > kMinCommonNameLongPrefixLength)
- names.push_back(field->name);
-
- if (names.size() < kCommonNamePrefixRemovalFieldThreshold)
- return;
-
- const int longest_long_prefix_length =
- FindLongestCommonAffixLength(names, false);
-
- if (longest_long_prefix_length >= kMinCommonNameLongPrefixLength)
- SetStrippedParseableNames(longest_long_prefix_length, 0);
-
- return;
+ // TODO(crbug/1165780): Remove once shared labels are launched.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForParsingWithSharedLabels)) {
+ // Extracts the |parsable_label_| for each field.
+ ExtractParseableFieldLabels();
}
+}
- // Update the field name parsed by heuristics if several criteria are met.
- // Several fields must be present in the form.
- if (field_count() < kCommonNamePrefixRemovalFieldThreshold)
- return;
-
- // Find the longest common prefix within all the field names.
- std::vector<base::string16> names;
- names.reserve(field_count());
- for (const auto& field : *this)
- names.push_back(field->name);
+void FormStructure::ExtractParseableFieldLabels() {
+ std::vector<base::StringPiece16> field_labels;
+ field_labels.reserve(field_count());
+ for (const auto& field : *this) {
+ // Skip fields that are not a text input or not visible.
+ if (!field->IsTextInputElement() || !field->IsVisible()) {
+ continue;
+ }
+ field_labels.push_back(field->label);
+ }
- const base::string16 longest_prefix = FindLongestCommonPrefix(names);
- if (longest_prefix.size() < kMinCommonNamePrefixLength)
+ // Determine the parsable labels and write them back.
+ base::Optional<std::vector<base::string16>> parsable_labels =
+ GetParseableLabels(field_labels);
+ // If not single label was split, the function can return, because the
+ // |parsable_label_| is assigned to |label| by default.
+ if (!parsable_labels.has_value()) {
return;
-
- // The name without the prefix will be used for heuristics parsing.
- for (auto& field : *this) {
- if (field->name.size() > longest_prefix.size()) {
- field->set_parseable_name(
- field->name.substr(longest_prefix.size(), field->name.size()));
- }
}
-}
-bool FormStructure::SetStrippedParseableNames(size_t offset_left,
- size_t offset_right) {
- // Keeps track if all stripped strings are valid according to
- // |IsValidParseableName()|. If at least one string is invalid,
- // all |parseable_name| are reset to |name|.
- bool should_keep = true;
+ size_t idx = 0;
for (auto& field : *this) {
- // This check allows to only strip affixes from long enough strings.
- if (field->name.size() > offset_right + offset_left) {
- field->set_parseable_name(field->name.substr(
- offset_left, field->name.size() - offset_right - offset_left));
- } else {
- field->set_parseable_name(field->name);
+ if (!field->IsTextInputElement() || !field->IsVisible()) {
+ // For those fields, set the original label.
+ field->set_parseable_label(field->label);
+ continue;
}
-
- should_keep &= IsValidParseableName(field->parseable_name());
- if (!should_keep)
- break;
+ DCHECK(idx < parsable_labels->size());
+ field->set_parseable_label(parsable_labels->at(idx++));
}
-
- // Reset if some stripped string was invalid.
- if (!should_keep) {
- for (auto& field : *this)
- field->set_parseable_name(field->name);
- }
-
- return should_keep;
}
-bool FormStructure::IsValidParseableName(
- base::string16 candidateParseableName) {
- static const base::string16 kParseableNameValidationPattern =
- base::UTF8ToUTF16(kParseableNameValidationRe);
- if (MatchesPattern(candidateParseableName, kParseableNameValidationPattern))
- return true;
-
- return false;
-}
-
-// static
-size_t FormStructure::FindLongestCommonAffixLength(
- const std::vector<base::StringPiece16>& strings,
- bool findCommonSuffix) {
- if (strings.empty())
- return 0;
-
- // Go through each character of the first string until there is a mismatch at
- // the same position in any other string. Adapted from http://goo.gl/YGukMM.
- for (size_t affix_len = 0; affix_len < strings[0].size(); affix_len++) {
- size_t base_string_index =
- findCommonSuffix ? strings[0].size() - affix_len - 1 : affix_len;
- for (size_t i = 1; i < strings.size(); i++) {
- size_t compared_string_index =
- findCommonSuffix ? strings[i].size() - affix_len - 1 : affix_len;
- if (affix_len >= strings[i].size() ||
- strings[i][compared_string_index] != strings[0][base_string_index]) {
- // Mismatch found.
- return affix_len;
- }
- }
+void FormStructure::ExtractParseableFieldNames() {
+ // Create a vector of string pieces containing the field names.
+ std::vector<base::StringPiece16> names;
+ names.reserve(field_count());
+ for (const auto& field : *this) {
+ names.push_back(base::StringPiece16(field->name));
}
- return strings[0].size();
-}
-// static
-base::string16 FormStructure::FindLongestCommonPrefix(
- const std::vector<base::string16>& strings) {
- if (strings.empty())
- return base::string16();
-
- std::vector<base::string16> filtered_strings;
-
- // Any strings less than kMinCommonNamePrefixLength are neither modified
- // nor considered when processing for a common prefix.
- std::copy_if(
- strings.begin(), strings.end(), std::back_inserter(filtered_strings),
- [](base::string16 s) { return s.size() >= kMinCommonNamePrefixLength; });
-
- if (filtered_strings.empty())
- return base::string16();
-
- // Go through each character of the first string until there is a mismatch at
- // the same position in any other string. Adapted from http://goo.gl/YGukMM.
- for (size_t prefix_len = 0; prefix_len < filtered_strings[0].size();
- prefix_len++) {
- for (size_t i = 1; i < filtered_strings.size(); i++) {
- if (prefix_len >= filtered_strings[i].size() ||
- filtered_strings[i].at(prefix_len) !=
- filtered_strings[0].at(prefix_len)) {
- // Mismatch found.
- return filtered_strings[i].substr(0, prefix_len);
- }
- }
+ // Determine the parseable names and write them into the corresponding field.
+ std::vector<base::string16> parseable_names = GetParseableNames(names);
+ DCHECK_EQ(parseable_names.size(), field_count());
+ size_t idx = 0;
+ for (auto& field : *this) {
+ field->set_parseable_name(parseable_names.at(idx++));
}
- return filtered_strings[0];
}
-std::set<FormType> FormStructure::GetFormTypes() const {
- std::set<FormType> form_types;
+DenseSet<FormType> FormStructure::GetFormTypes() const {
+ DenseSet<FormType> form_types;
for (const auto& field : fields_) {
- form_types.insert(
- FormTypes::FieldTypeGroupToFormType(field->Type().group()));
+ form_types.insert(FieldTypeGroupToFormType(field->Type().group()));
}
return form_types;
}
@@ -2425,7 +2496,7 @@ void FormStructure::set_randomized_encoder(
void FormStructure::RationalizeTypeRelationships() {
// Create a local set of all the types for faster lookup.
- std::unordered_set<ServerFieldType> types;
+ ServerFieldTypeSet types;
for (const auto& field : fields_) {
types.insert(field->Type().GetStorableType());
}
@@ -2434,21 +2505,11 @@ void FormStructure::RationalizeTypeRelationships() {
for (const auto& field : fields_) {
ServerFieldType field_type = field->Type().GetStorableType();
- const auto& ruleset_iterator = type_relationship_rules.find(field_type);
+ const auto* ruleset_iterator = type_relationship_rules.find(field_type);
if (ruleset_iterator != type_relationship_rules.end()) {
// We have relationship rules for this type. Verify that at least one of
// the required related type is present.
- bool found = false;
- for (ServerFieldType required_type : ruleset_iterator->second) {
- if (types.find(required_type) != types.end()) {
- // Found a required type, we can break as we only need one required
- // type to respect the rule.
- found = true;
- break;
- }
- }
-
- if (!found) {
+ if (!types.contains_any(ruleset_iterator->second)) {
// No required type was found, the current field failed the relationship
// requirements for its type. Disabling Autofill for this field.
field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index 58a8a8d48dc..8151d28eb09 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -24,6 +24,8 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
+#include "components/autofill/core/common/dense_set.h"
+#include "components/autofill/core/common/language_code.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/renderer_id.h"
#include "url/gurl.h"
@@ -66,7 +68,9 @@ class FormStructure {
// Runs several heuristics against the form fields to determine their possible
// types.
- void DetermineHeuristicTypes(LogManager* log_manager = nullptr);
+ void DetermineHeuristicTypes(
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ LogManager* log_manager);
// Encodes the proto |upload| request from this FormStructure, and stores
// the (single) FormSignature and the signatures of the fields to be uploaded
@@ -78,6 +82,7 @@ class FormStructure {
bool form_was_autofilled,
const std::string& login_form_signature,
bool observed_submission,
+ bool is_raw_metadata_uploading_enabled,
autofill::AutofillUploadContents* upload,
std::vector<FormSignature>* encoded_signatures) const;
@@ -104,9 +109,6 @@ class FormStructure {
static std::vector<FormDataPredictions> GetFieldTypePredictions(
const std::vector<FormStructure*>& form_structures);
- // Returns whether sending autofill field metadata to the server is enabled.
- static bool IsAutofillFieldMetadataEnabled();
-
// Creates FormStructure that has bare minimum information for uploading
// votes, namely form and field signatures. Warning: do not use for Autofill
// code, since it is likely missing some fields.
@@ -281,7 +283,7 @@ class FormStructure {
FormData ToFormData() const;
// Returns the possible form types.
- std::set<FormType> GetFormTypes() const;
+ DenseSet<FormType> GetFormTypes() const;
bool passwords_were_revealed() const { return passwords_were_revealed_; }
void set_passwords_were_revealed(bool passwords_were_revealed) {
@@ -359,16 +361,20 @@ class FormStructure {
// - Name for Autofill of first field
base::string16 GetIdentifierForRefill() const;
- int developer_engagement_metrics() { return developer_engagement_metrics_; }
+ int developer_engagement_metrics() const {
+ return developer_engagement_metrics_;
+ }
void set_randomized_encoder(std::unique_ptr<RandomizedEncoder> encoder);
void set_is_rich_query_enabled(bool v) { is_rich_query_enabled_ = v; }
- const std::string& page_language() const { return page_language_; }
+ const LanguageCode& current_page_language() const {
+ return current_page_language_;
+ }
- void set_page_language(std::string language) {
- page_language_ = std::move(language);
+ void set_current_page_language(LanguageCode language) {
+ current_page_language_ = std::move(language);
}
bool value_from_dynamic_change_form() const {
@@ -406,51 +412,9 @@ class FormStructure {
FRIEND_TEST_ALL_PREFIXES(ParameterizedFormStructureTest,
RationalizePhoneNumber_RunsOncePerSection);
- class SectionedFieldsIndexes {
- public:
- SectionedFieldsIndexes();
- ~SectionedFieldsIndexes();
-
- size_t LastFieldIndex() const {
- if (sectioned_indexes.empty())
- return (size_t)-1; // Shouldn't happen.
- return sectioned_indexes.back().back();
- }
-
- void AddFieldIndex(const size_t index, bool is_new_section) {
- if (is_new_section || Empty()) {
- sectioned_indexes.push_back(std::vector<size_t>(1, index));
- return;
- }
- sectioned_indexes.back().push_back(index);
- }
-
- void WalkForwardToTheNextSection() { current_section_ptr++; }
-
- bool IsFinished() const {
- return current_section_ptr >= sectioned_indexes.size();
- }
-
- size_t CurrentIndex() const { return CurrentSection()[0]; }
-
- std::vector<size_t> CurrentSection() const {
- if (current_section_ptr < sectioned_indexes.size())
- return sectioned_indexes[current_section_ptr];
- return std::vector<size_t>(1, (size_t)-1); // To handle edge cases.
- }
-
- void Reset() { current_section_ptr = 0; }
-
- bool Empty() const { return sectioned_indexes.empty(); }
-
- private:
- // A vector of sections. Each section is a vector of some of the indexes
- // that belong to the same section. The sections and indexes are sorted by
- // their order of appearance on the form.
- std::vector<std::vector<size_t>> sectioned_indexes;
- // Points to a vector of indexes that belong to the same section.
- size_t current_section_ptr = 0;
- };
+ // This class wraps a vector of vectors of field indices. The indices of a
+ // vector belong to the same group.
+ class SectionedFieldsIndexes;
// Parses the field types from the server query response. |forms| must be the
// same as the one passed to EncodeQueryRequest when constructing the query.
@@ -531,6 +495,7 @@ class FormStructure {
std::vector<FormSignature>* queried_form_signatures) const;
void EncodeFormForUpload(
+ bool is_raw_metadata_uploading_enabled,
autofill::AutofillUploadContents* upload,
std::vector<FormSignature>* encoded_signatures) const;
@@ -547,6 +512,7 @@ class FormStructure {
// If |has_author_specified_sections| is true, only the second pass --
// distinguishing credit card sections from non-credit card ones -- is made.
void IdentifySections(bool has_author_specified_sections);
+ void IdentifySectionsWithNewMethod();
// Returns true if field should be skipped when talking to Autofill server.
bool ShouldSkipField(const FormFieldData& field) const;
@@ -554,38 +520,16 @@ class FormStructure {
// Further processes the extracted |fields_|.
void ProcessExtractedFields();
- // Tries to set |parseable_name| fields by stripping the given offsets from
- // both sides of the |name| fields.
- // Sets |parseable_name| to |name| if the sum of offsets is bigger than
- // |name|.
- // Sets all |parseable_name| to |name| without modification and returns
- // false if a name fails the |IsValidParseableName()| check after stripping.
- bool SetStrippedParseableNames(size_t offset_left, size_t offset_right);
-
- // Returns true if |string| is a valid parseable_name. Current criterion
- // is the |autofill::kParseableNameValidationRe| regex.
- static bool IsValidParseableName(base::string16 string);
-
- // Returns the length of the longest common prefix found within |strings|
- // if |findCommonSuffix| is false. Otherwise returns longest common suffix.
- static size_t FindLongestCommonAffixLength(
- const std::vector<base::StringPiece16>& strings,
- bool findCommonSuffix = false);
-
- // Returns the longest common prefix found within |strings|. Strings below a
- // threshold length defined by |kMinCommonNamePrefixLength| are excluded
- // when performing this check; this is needed because an exceptional
- // field may be missing a prefix which is otherwise consistently applied.
- // For instance, a framework may only apply a prefix to those fields
- // which are bound when POSTing.
- //
- // Soon to be replaced by FindLongestCommonPrefixLength
- static base::string16 FindLongestCommonPrefix(
- const std::vector<base::string16>& strings);
-
- // The language detected for this form's page, prior to any translations
+ // Extracts the parseable field name by removing a common affix.
+ void ExtractParseableFieldNames();
+
+ // Extract parseable field labels by potentially splitting labels between
+ // adjacent fields.
+ void ExtractParseableFieldLabels();
+
+ // The language detected for this form's page, before any translations
// performed by Chrome.
- std::string page_language_;
+ LanguageCode current_page_language_;
// The id attribute of the form.
base::string16 id_attribute_;
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 4e894075277..fc22851c9c7 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -11,7 +11,6 @@
#include "base/base64.h"
#include "base/command_line.h"
#include "base/feature_list.h"
-#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -19,7 +18,6 @@
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_form_test_utils.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
#include "components/autofill/core/browser/randomized_encoder.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -66,6 +64,19 @@ void AddFieldSuggestionToForm(
field_suggestion->set_primary_type_prediction(field_type);
}
+void AddFieldOverrideToForm(
+ ::autofill::AutofillQueryResponse_FormSuggestion* form_suggestion,
+ autofill::FormFieldData field_data,
+ ServerFieldType field_type) {
+ AddFieldSuggestionToForm(form_suggestion, field_data, field_type);
+
+ DCHECK_GT(form_suggestion->field_suggestions().size(), 0);
+ form_suggestion
+ ->mutable_field_suggestions(form_suggestion->field_suggestions().size() -
+ 1)
+ ->set_primary_type_prediction_is_override(true);
+}
+
} // namespace
class FormStructureTestImpl : public test::FormStructureTest {
@@ -74,28 +85,14 @@ class FormStructureTestImpl : public test::FormStructureTest {
return base::NumberToString(StrToHash64Bit(str));
}
- void SetUp() override {
- // By default this trial is enabled on tests.
- EnableAutofillMetadataFieldTrial();
- }
-
protected:
- void InitFeature(base::test::ScopedFeatureList* feature_list,
- const base::Feature& feature,
- bool is_enabled) {
- if (is_enabled)
- feature_list->InitAndEnableFeature(feature);
- else
- feature_list->InitAndDisableFeature(feature);
- }
-
bool FormShouldBeParsed(const FormData form) {
return FormStructure(form).ShouldBeParsed();
}
bool FormIsAutofillable(const FormData& form) {
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
return form_structure.IsAutofillable();
}
@@ -107,12 +104,6 @@ class FormStructureTestImpl : public test::FormStructureTest {
return FormStructure(form).ShouldBeQueried();
}
- void DisableAutofillMetadataFieldTrial() {
- field_trial_ = nullptr;
- scoped_feature_list_.Reset();
- scoped_feature_list_.Init();
- }
-
void SetUpForEncoder() {
scoped_feature_list_.Reset();
scoped_feature_list_.InitWithFeatures(
@@ -126,21 +117,9 @@ class FormStructureTestImpl : public test::FormStructureTest {
return FieldRendererId(++id_counter_);
}
- protected:
- TestPatternProvider test_pattern_provider_;
-
private:
- void EnableAutofillMetadataFieldTrial() {
- scoped_feature_list_.Reset();
- scoped_feature_list_.Init();
- field_trial_ = base::FieldTrialList::CreateFieldTrial(
- "AutofillFieldMetadata", "Enabled");
- field_trial_->group();
- }
-
uint32_t id_counter_ = 10;
base::test::ScopedFeatureList scoped_feature_list_;
- scoped_refptr<base::FieldTrial> field_trial_;
};
class ParameterizedFormStructureTest
@@ -638,27 +617,32 @@ TEST_F(FormStructureTestImpl, StripCommonNameAffix) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("ctl01$ctl00$ShippingAddressCreditPhone$firstname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("ctl01$ctl00$ShippingAddressCreditPhone$lastname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("ctl01$ctl00$ShippingAddressCreditPhone$email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("ctl01$ctl00$ShippingAddressCreditPhone$phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("ctl01$ctl00$ShippingAddressCreditPhone$submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -1101,7 +1085,7 @@ TEST_F(FormStructureTestImpl,
// Default configuration.
{
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ASSERT_EQ(2U, form_structure.field_count());
ASSERT_EQ(0U, form_structure.autofill_count());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
@@ -1147,7 +1131,7 @@ TEST_F(FormStructureTestImpl,
FormData form_copy = form;
form_copy.fields.pop_back();
FormStructure form_structure(form_copy);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
ASSERT_EQ(1U, form_structure.field_count());
ASSERT_EQ(1U, form_structure.autofill_count());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
@@ -1192,7 +1176,7 @@ TEST_F(FormStructureTestImpl, PasswordFormShouldBeQueried) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure.has_password_field());
EXPECT_TRUE(form_structure.ShouldBeQueried());
EXPECT_TRUE(form_structure.ShouldBeUploaded());
@@ -1257,7 +1241,7 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributeWithSections) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure.IsAutofillable());
// Expect the correct number of fields.
@@ -1312,7 +1296,7 @@ TEST_F(FormStructureTestImpl,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
// Expect the correct number of fields.
ASSERT_EQ(6U, form_structure.field_count());
@@ -1346,7 +1330,7 @@ TEST_F(FormStructureTestImpl,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
// Expect the correct number of fields.
ASSERT_EQ(2U, form_structure.field_count());
@@ -1392,7 +1376,7 @@ TEST_F(FormStructureTestImpl,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
// Expect the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
@@ -1466,7 +1450,7 @@ TEST_F(FormStructureTestImpl, HeuristicsSample8) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(10U, form_structure->field_count());
ASSERT_EQ(9U, form_structure->autofill_count());
@@ -1540,7 +1524,7 @@ TEST_F(FormStructureTestImpl, HeuristicsSample6) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(7U, form_structure->field_count());
ASSERT_EQ(6U, form_structure->autofill_count());
@@ -1614,7 +1598,7 @@ TEST_F(FormStructureTestImpl, HeuristicsLabelsOnly) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(8U, form_structure->field_count());
ASSERT_EQ(7U, form_structure->autofill_count());
@@ -1678,7 +1662,7 @@ TEST_F(FormStructureTestImpl, HeuristicsCreditCardInfo) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(6U, form_structure->field_count());
ASSERT_EQ(5U, form_structure->autofill_count());
@@ -1746,7 +1730,7 @@ TEST_F(FormStructureTestImpl, HeuristicsCreditCardInfoWithUnknownCardField) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(7U, form_structure->field_count());
ASSERT_EQ(5U, form_structure->autofill_count());
@@ -1798,7 +1782,7 @@ TEST_F(FormStructureTestImpl, ThreeAddressLines) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
@@ -1843,7 +1827,7 @@ TEST_F(FormStructureTestImpl, SurplusAddressLinesIgnored) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1891,7 +1875,7 @@ TEST_F(FormStructureTestImpl, ThreeAddressLinesExpedia) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
EXPECT_EQ(4U, form_structure->autofill_count());
@@ -1933,7 +1917,7 @@ TEST_F(FormStructureTestImpl, TwoAddressLinesEbay) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(3U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1970,7 +1954,7 @@ TEST_F(FormStructureTestImpl, HeuristicsStateWithProvince) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(3U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -2048,7 +2032,7 @@ TEST_F(FormStructureTestImpl, HeuristicsWithBilling) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(11U, form_structure->field_count());
ASSERT_EQ(11U, form_structure->autofill_count());
@@ -2102,7 +2086,7 @@ TEST_F(FormStructureTestImpl, ThreePartPhoneNumber) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
@@ -2151,7 +2135,7 @@ TEST_F(FormStructureTestImpl, HeuristicsInfernoCC) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -2212,7 +2196,7 @@ TEST_F(FormStructureTestImpl, HeuristicsInferCCNames_NamesNotFirst) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -2277,7 +2261,7 @@ TEST_F(FormStructureTestImpl, HeuristicsInferCCNames_NamesFirst) {
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -2355,16 +2339,11 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
- test::FillQueryField(query_form->add_fields(), 412125936U, "name_on_card",
- "text");
- test::FillQueryField(query_form->add_fields(), 1917667676U, "billing_address",
- "text");
- test::FillQueryField(query_form->add_fields(), 2226358947U, "card_number",
- "text");
- test::FillQueryField(query_form->add_fields(), 747221617U, "expiration_month",
- "text");
- test::FillQueryField(query_form->add_fields(), 4108155786U, "expiration_year",
- "text");
+ query_form->add_fields()->set_signature(412125936U);
+ query_form->add_fields()->set_signature(1917667676U);
+ query_form->add_fields()->set_signature(2226358947U);
+ query_form->add_fields()->set_signature(747221617U);
+ query_form->add_fields()->set_signature(4108155786U);
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -2413,19 +2392,13 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
query_form = query.add_forms();
query_form->set_signature(form_structure3.form_signature().value());
- test::FillQueryField(query_form->add_fields(), 412125936U, "name_on_card",
- "text");
- test::FillQueryField(query_form->add_fields(), 1917667676U, "billing_address",
- "text");
- test::FillQueryField(query_form->add_fields(), 2226358947U, "card_number",
- "text");
- test::FillQueryField(query_form->add_fields(), 747221617U, "expiration_month",
- "text");
- test::FillQueryField(query_form->add_fields(), 4108155786U, "expiration_year",
- "text");
+ query_form->add_fields()->set_signature(412125936U);
+ query_form->add_fields()->set_signature(1917667676U);
+ query_form->add_fields()->set_signature(2226358947U);
+ query_form->add_fields()->set_signature(747221617U);
+ query_form->add_fields()->set_signature(4108155786U);
for (int i = 0; i < 5; ++i) {
- test::FillQueryField(query_form->add_fields(), 509334676U, "address",
- "text");
+ query_form->add_fields()->set_signature(509334676U);
}
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -2580,7 +2553,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -2700,7 +2673,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload,
+ available_field_types, false, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -2713,7 +2686,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload2,
+ available_field_types, true, std::string(), true, true, &encoded_upload2,
&signatures));
encoded_upload2.SerializeToString(&encoded_upload_string);
@@ -2768,7 +2741,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3,
+ available_field_types, false, std::string(), true, true, &encoded_upload3,
&signatures));
encoded_upload3.SerializeToString(&encoded_upload_string);
@@ -2786,7 +2759,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
form.url = GURL("http://www.foo.com/");
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -2904,7 +2877,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload,
+ available_field_types, false, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -2924,7 +2897,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3045,7 +3018,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload,
+ available_field_types, false, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -3062,7 +3035,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3180,7 +3153,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload,
+ available_field_types, false, std::string(), true, true, &encoded_upload,
&signatures));
EXPECT_EQ(signatures, expected_signatures);
@@ -3194,7 +3167,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload2,
+ available_field_types, true, std::string(), true, true, &encoded_upload2,
&signatures));
EXPECT_EQ(signatures, expected_signatures);
@@ -3252,7 +3225,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3,
+ available_field_types, false, std::string(), true, true, &encoded_upload3,
&signatures));
EXPECT_EQ(signatures, expected_signatures);
@@ -3283,7 +3256,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
AutofillUploadContents encoded_upload4;
EXPECT_FALSE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload4,
+ available_field_types, false, std::string(), true, true, &encoded_upload4,
&signatures));
}
@@ -3297,7 +3270,7 @@ TEST_F(FormStructureTestImpl,
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.label = ASCIIToUTF16("First Name");
@@ -3418,7 +3391,8 @@ TEST_F(FormStructureTestImpl,
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, "42", true, &encoded_upload, &signatures));
+ available_field_types, true, "42", true, true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3434,7 +3408,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3507,7 +3481,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
AutofillUploadContents encoded_upload;
std::vector<FormSignature> signatures;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -3516,8 +3490,6 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
}
TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
- DisableAutofillMetadataFieldTrial();
-
std::unique_ptr<FormStructure> form_structure;
std::vector<ServerFieldTypeSet> possible_field_types;
std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities;
@@ -3526,7 +3498,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3617,7 +3589,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true,
+ /*is_raw_metadata_uploading_enabled=*/false, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -3634,7 +3607,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3708,7 +3681,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
available_field_types, true, std::string(),
- /* observed_submission= */ false, &encoded_upload, &signatures));
+ /* observed_submission= */ false, true, &encoded_upload, &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3724,7 +3697,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3790,7 +3763,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -3878,7 +3851,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithCssClassesAndIds) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -3898,7 +3871,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
// Setting the form name which we expect to see in the upload.
form.name = ASCIIToUTF16("myform");
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -3963,7 +3936,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -3980,7 +3953,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -4053,7 +4026,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -4062,9 +4035,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
}
// Sending field metadata to the server is disabled.
-TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
- DisableAutofillMetadataFieldTrial();
-
+TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadata) {
+ // Metadata uploading is disabled by a parameter of |EncodeUploadRequest|.
std::unique_ptr<FormStructure> form_structure;
std::vector<ServerFieldTypeSet> possible_field_types;
std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities;
@@ -4073,7 +4045,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
form.is_form_tag = true;
form_structure = std::make_unique<FormStructure>(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
FormFieldData field;
field.form_control_type = "text";
@@ -4154,7 +4126,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload,
+ available_field_types, true, std::string(), true,
+ /*is_raw_metadata_uploading_enabled=*/false, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -4235,7 +4208,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
- std::string(), true,
+ std::string(), true, true,
&encoded_upload, &signatures));
std::string encoded_upload_string;
@@ -4266,7 +4239,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload2,
+ available_field_types, false, std::string(), true, true, &encoded_upload2,
&signatures));
encoded_upload2.SerializeToString(&encoded_upload_string);
@@ -4320,7 +4293,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3,
+ available_field_types, false, std::string(), true, true, &encoded_upload3,
&signatures));
encoded_upload3.SerializeToString(&encoded_upload_string);
@@ -4352,7 +4325,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
AutofillUploadContents encoded_upload4;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload4,
+ available_field_types, false, std::string(), true, true, &encoded_upload4,
&signatures));
encoded_upload4.SerializeToString(&encoded_upload_string);
@@ -4420,7 +4393,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
AutofillUploadContents encoded_upload5;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload5,
+ available_field_types, false, std::string(), true, true, &encoded_upload5,
&signatures));
encoded_upload5.SerializeToString(&encoded_upload_string);
@@ -4530,7 +4503,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload,
+ available_field_types, false, std::string(), true, true, &encoded_upload,
&signatures));
std::string encoded_upload_string;
@@ -4554,7 +4527,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload2,
+ available_field_types, false, std::string(), true, true, &encoded_upload2,
&signatures));
encoded_upload2.SerializeToString(&encoded_upload_string);
@@ -4572,7 +4545,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3,
+ available_field_types, false, std::string(), true, true, &encoded_upload3,
&signatures));
encoded_upload3.SerializeToString(&encoded_upload_string);
@@ -4598,7 +4571,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
AutofillUploadContents encoded_upload4;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload4,
+ available_field_types, false, std::string(), true, true, &encoded_upload4,
&signatures));
encoded_upload4.SerializeToString(&encoded_upload_string);
@@ -4633,7 +4606,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_PasswordsRevealed) {
EXPECT_TRUE(form_structure.EncodeUploadRequest(
{{}} /* available_field_types */, false /* form_was_autofilled */,
std::string() /* login_form_signature */, true /* observed_submission */,
- &upload, &signatures));
+ true /* is_raw_metadata_uploading_enabled */, &upload, &signatures));
EXPECT_EQ(true, upload.passwords_revealed());
}
@@ -4657,7 +4630,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_IsFormTag) {
EXPECT_TRUE(form_structure.EncodeUploadRequest(
{{}} /* available_field_types */, false /* form_was_autofilled */,
std::string() /* login_form_signature */,
- true /* observed_submission */, &upload, &signatures));
+ true /* observed_submission */,
+ false /* is_raw_metadata_uploading_enabled */, &upload, &signatures));
EXPECT_EQ(is_form_tag, upload.has_form_tag());
}
}
@@ -4714,7 +4688,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) {
ASSERT_TRUE(form_structure.EncodeUploadRequest(
{{}} /* available_field_types */, false /* form_was_autofilled */,
std::string() /* login_form_signature */, true /* observed_submission */,
- &upload, &signatures));
+ false /* is_raw_metadata_uploading_enabled */, &upload, &signatures));
const auto form_signature = form_structure.form_signature();
@@ -4857,7 +4831,7 @@ TEST_F(FormStructureTestImpl, Metadata_OnlySendFullUrlWithUserConsent) {
form_structure.set_randomized_encoder(RandomizedEncoder::Create(&prefs));
AutofillUploadContents upload = AutofillUploadContents();
std::vector<FormSignature> signatures;
- form_structure.EncodeUploadRequest({}, true, "", true, &upload,
+ form_structure.EncodeUploadRequest({}, true, "", true, true, &upload,
&signatures);
EXPECT_EQ(has_consent, upload.randomized_form_metadata().has_url());
@@ -5010,9 +4984,8 @@ TEST_F(FormStructureTestImpl, SkipFieldTest) {
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
- test::FillQueryField(query_form->add_fields(), 239111655U, "username",
- "text");
- test::FillQueryField(query_form->add_fields(), 420638584U, "email", "text");
+ query_form->add_fields()->set_signature(239111655U);
+ query_form->add_fields()->set_signature(420638584U);
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -5066,11 +5039,9 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLabels) {
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
- test::FillQueryField(query_form->add_fields(), 239111655U, "username",
- "text");
- test::FillQueryField(query_form->add_fields(), 420638584U, "email", "text");
- test::FillQueryField(query_form->add_fields(), 2051817934U, "password",
- "password");
+ query_form->add_fields()->set_signature(239111655U);
+ query_form->add_fields()->set_signature(420638584U);
+ query_form->add_fields()->set_signature(2051817934U);
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -5125,11 +5096,9 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
- test::FillQueryField(query_form->add_fields(), 239111655U, "username",
- "text");
- test::FillQueryField(query_form->add_fields(), 420638584U, "email", "text");
- test::FillQueryField(query_form->add_fields(), 2051817934U, "password",
- "password");
+ query_form->add_fields()->set_signature(239111655U);
+ query_form->add_fields()->set_signature(420638584U);
+ query_form->add_fields()->set_signature(2051817934U);
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -5177,9 +5146,8 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
- test::FillQueryField(query_form->add_fields(), 239111655U, "username",
- "text");
- test::FillQueryField(query_form->add_fields(), 1318412689U, nullptr, "text");
+ query_form->add_fields()->set_signature(239111655U);
+ query_form->add_fields()->set_signature(1318412689U);
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -5196,59 +5164,6 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
EXPECT_EQ(expected_query_string, encoded_query_string);
}
-// Sending field metadata to the server is disabled.
-TEST_F(FormStructureTestImpl, EncodeQueryRequest_DisabledMetadataTrial) {
- DisableAutofillMetadataFieldTrial();
-
- FormData form;
- // No name set for the form.
- form.url = GURL("http://cool.com");
- form.action = form.url.Resolve("/login");
-
- FormFieldData field;
- field.label = ASCIIToUTF16("username");
- field.name = ASCIIToUTF16("username");
- field.form_control_type = "text";
- field.unique_renderer_id = MakeFieldRendererId();
- form.fields.push_back(field);
-
- field.label = base::string16();
- field.name = ASCIIToUTF16("country");
- field.form_control_type = "text";
- field.check_status = FormFieldData::CheckStatus::kNotCheckable;
- field.unique_renderer_id = MakeFieldRendererId();
- form.fields.push_back(field);
-
- FormStructure form_structure(form);
- std::vector<FormStructure*> forms;
- forms.push_back(&form_structure);
- std::vector<FormSignature> encoded_signatures;
- AutofillPageQueryRequest encoded_query;
-
- // Create the expected query and serialize it to a string.
- AutofillPageQueryRequest query;
- query.set_client_version(GetProductNameAndVersionForUserAgent());
- AutofillPageQueryRequest::Form* query_form = query.add_forms();
- query_form->set_signature(form_structure.form_signature().value());
-
- test::FillQueryField(query_form->add_fields(), 239111655U, nullptr, nullptr);
- test::FillQueryField(query_form->add_fields(), 3654076265U, nullptr, nullptr);
-
- std::string expected_query_string;
- ASSERT_TRUE(query.SerializeToString(&expected_query_string));
-
- const FormSignature kExpectedSignature(7635954436925888745UL);
-
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
- &encoded_signatures));
- ASSERT_EQ(1U, encoded_signatures.size());
- EXPECT_EQ(kExpectedSignature, encoded_signatures.front());
-
- std::string encoded_query_string;
- encoded_query.SerializeToString(&encoded_query_string);
- EXPECT_EQ(expected_query_string, encoded_query_string);
-}
-
TEST_F(FormStructureTestImpl, PossibleValues) {
FormData form_data;
form_data.url = GURL("http://www.foo.com/");
@@ -5294,6 +5209,110 @@ TEST_F(FormStructureTestImpl, PossibleValues) {
EXPECT_EQ(0U, form_structure2.PossibleValues(ADDRESS_BILLING_COUNTRY).size());
}
+// Test that server predictions get precedence over htmll types if they are
+// overrides.
+TEST_F(FormStructureTestImpl, ParseQueryResponse_ServerPredictionIsOverride) {
+ FormData form_data;
+ FormFieldData field;
+ form_data.url = GURL("http://foo.com");
+ field.form_control_type = "text";
+
+ // Just some field.
+ field.label = ASCIIToUTF16("some field");
+ field.name = ASCIIToUTF16("some_field");
+ // But this field has an autocomplete attribute.
+ field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
+ form_data.fields.push_back(field);
+
+ // Some other field.
+ field.label = ASCIIToUTF16("some other field");
+ field.name = ASCIIToUTF16("some_other_field");
+ // Which has the same attribute.
+ field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
+ form_data.fields.push_back(field);
+
+ // Setup the query response with an override for the name field to be a first
+ // name.
+ AutofillQueryResponse response;
+ auto* form_suggestion = response.add_form_suggestions();
+ AddFieldOverrideToForm(form_suggestion, form_data.fields[0], NAME_FIRST);
+ AddFieldSuggestionToForm(form_suggestion, form_data.fields[1], NAME_LAST);
+
+ std::string response_string = SerializeAndEncode(response);
+
+ // Disable the feature which gives overrides precedence.
+ {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndDisableFeature(
+ features::kAutofillServerTypeTakesPrecedence);
+
+ // Parse the response and update the field type predictions.
+ FormStructure form(form_data);
+ form.DetermineHeuristicTypes(nullptr, nullptr);
+ std::vector<FormStructure*> forms{&form};
+ FormStructure::ParseApiQueryResponse(
+ response_string, forms, test::GetEncodedSignatures(forms), nullptr);
+ ASSERT_EQ(form.field_count(), 2U);
+
+ // Validate the type predictions.
+ EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->heuristic_type());
+ EXPECT_EQ(HTML_TYPE_NAME, form.field(0)->html_type());
+ EXPECT_EQ(NAME_FIRST, form.field(0)->server_type());
+ EXPECT_EQ(UNKNOWN_TYPE, form.field(1)->heuristic_type());
+ EXPECT_EQ(HTML_TYPE_NAME, form.field(1)->html_type());
+ EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
+
+ // Validate that the overrides are set correctly.
+ EXPECT_TRUE(form.field(0)->server_type_prediction_is_override());
+ EXPECT_FALSE(form.field(1)->server_type_prediction_is_override());
+
+ // Validate that the html prediction won.
+ EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FULL);
+ EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FULL);
+ }
+
+ // Enable the feature to give overrides precedence.
+ {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndEnableFeature(
+ features::kAutofillServerTypeTakesPrecedence);
+
+ // Parse the response and update the field type predictions.
+ FormStructure form(form_data);
+ form.DetermineHeuristicTypes(nullptr, nullptr);
+ std::vector<FormStructure*> forms{&form};
+ FormStructure::ParseApiQueryResponse(
+ response_string, forms, test::GetEncodedSignatures(forms), nullptr);
+ ASSERT_EQ(form.field_count(), 2U);
+
+ // Validate the type predictions.
+ EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->heuristic_type());
+ EXPECT_EQ(HTML_TYPE_NAME, form.field(0)->html_type());
+ EXPECT_EQ(NAME_FIRST, form.field(0)->server_type());
+ EXPECT_EQ(UNKNOWN_TYPE, form.field(1)->heuristic_type());
+ EXPECT_EQ(HTML_TYPE_NAME, form.field(1)->html_type());
+ EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
+
+ // Validate that the overrides are set correctly.
+ EXPECT_TRUE(form.field(0)->server_type_prediction_is_override());
+ EXPECT_FALSE(form.field(1)->server_type_prediction_is_override());
+
+ // Validate that the server prediction won for the first field.
+ EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
+ EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FULL);
+
+ // Validate that the server override cannot be altered.
+ form.field(0)->SetTypeTo(AutofillType(NAME_FULL));
+ EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
+
+ // Validate that that the non-override can be altered.
+ form.field(1)->SetTypeTo(AutofillType(NAME_FIRST));
+ EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FIRST);
+ }
+}
+
// Test the heuristic prediction for NAME_LAST_SECOND overrides server
// predictions.
TEST_F(FormStructureTestImpl,
@@ -5310,22 +5329,25 @@ TEST_F(FormStructureTestImpl,
// First name field.
field.label = ASCIIToUTF16("Nombre");
field.name = ASCIIToUTF16("Nombre");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
// First last name field.
// Should be identified by local heuristics.
field.label = ASCIIToUTF16("Apellido Paterno");
field.name = ASCIIToUTF16("apellido_paterno");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
// Second last name field.
// Should be identified by local heuristics.
field.label = ASCIIToUTF16("Apellido Materno");
field.name = ASCIIToUTF16("apellido materno");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
FormStructure form(form_data);
- form.DetermineHeuristicTypes();
+ form.DetermineHeuristicTypes(nullptr, nullptr);
// Setup the query response.
AutofillQueryResponse response;
@@ -5393,25 +5415,29 @@ TEST_F(FormStructureTestImpl,
// Field for the name.
field.label = ASCIIToUTF16("Name");
field.name = ASCIIToUTF16("Name");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
// Field for the street name.
field.label = ASCIIToUTF16("Street Name");
field.name = ASCIIToUTF16("street_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
// Field for the house number.
field.label = ASCIIToUTF16("House Number");
field.name = ASCIIToUTF16("house_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
// Field for the postal code.
field.label = ASCIIToUTF16("ZIP");
field.name = ASCIIToUTF16("ZIP");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
FormStructure form(form_data);
- form.DetermineHeuristicTypes();
+ form.DetermineHeuristicTypes(nullptr, nullptr);
// Setup the query response.
AutofillQueryResponse response;
@@ -5474,19 +5500,22 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_TooManyTypes) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("fname");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lname");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
field.autocomplete_attribute = "address-level2";
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
FormStructure form(form_data);
- form.DetermineHeuristicTypes();
+ form.DetermineHeuristicTypes(nullptr, nullptr);
// Setup the query response.
AutofillQueryResponse response;
@@ -5560,7 +5589,7 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_UnknownType) {
form_data.fields.push_back(field);
FormStructure form(form_data);
- form.DetermineHeuristicTypes();
+ form.DetermineHeuristicTypes(nullptr, nullptr);
// Setup the query response.
AutofillQueryResponse response;
@@ -5788,7 +5817,7 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_AuthorDefinedTypes) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- forms.front()->DetermineHeuristicTypes();
+ forms.front()->DetermineHeuristicTypes(nullptr, nullptr);
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
@@ -6025,140 +6054,6 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeMultiMonth_2) {
EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(3)->Type().GetStorableType());
}
-TEST_F(FormStructureTestImpl, SetStrippedParseableNames) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kAutofillLabelAffixRemoval);
-}
-
-TEST_F(FormStructureTestImpl, IsValidParseableName) {
- // Parseable name should not be empty.
- EXPECT_FALSE(FormStructure::IsValidParseableName(ASCIIToUTF16("")));
- // Parseable name should not be solely numerical.
- EXPECT_FALSE(FormStructure::IsValidParseableName(ASCIIToUTF16("1265125")));
-
- // Valid parseable name cases.
- EXPECT_TRUE(FormStructure::IsValidParseableName(ASCIIToUTF16("a23")));
- EXPECT_TRUE(FormStructure::IsValidParseableName(ASCIIToUTF16("*)&%@")));
-}
-
-TEST_F(FormStructureTestImpl, FindLongestCommonAffixLength) {
- auto String16ToStringPiece16 = [](std::vector<base::string16>& vin,
- std::vector<base::StringPiece16>& vout) {
- vout.clear();
- for (auto& str : vin)
- vout.push_back(str);
- };
-
- // Normal prefix case.
- std::vector<base::string16> strings;
- std::vector<base::StringPiece16> stringPieces;
- strings.push_back(ASCIIToUTF16("123456XXX123456789"));
- strings.push_back(ASCIIToUTF16("12345678XXX012345678_foo"));
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- strings.push_back(ASCIIToUTF16("1234567XXX901234567890"));
- String16ToStringPiece16(strings, stringPieces);
- size_t affixLength =
- FormStructure::FindLongestCommonAffixLength(stringPieces, false);
- EXPECT_EQ(ASCIIToUTF16("123456").size(), affixLength);
-
- // Normal suffix case.
- strings.clear();
- strings.push_back(ASCIIToUTF16("black and gold dress"));
- strings.push_back(ASCIIToUTF16("work_address"));
- strings.push_back(ASCIIToUTF16("123456XXX1234_home_address"));
- strings.push_back(ASCIIToUTF16("1234567890123456_city_address"));
- String16ToStringPiece16(strings, stringPieces);
- affixLength = FormStructure::FindLongestCommonAffixLength(stringPieces, true);
- EXPECT_EQ(ASCIIToUTF16("dress").size(), affixLength);
-
- // Handles no common prefix.
- strings.clear();
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- strings.push_back(ASCIIToUTF16("4567890123456789"));
- strings.push_back(ASCIIToUTF16("7890123456789012"));
- String16ToStringPiece16(strings, stringPieces);
- affixLength =
- FormStructure::FindLongestCommonAffixLength(stringPieces, false);
- EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
-
- // Handles no common suffix.
- strings.clear();
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- strings.push_back(ASCIIToUTF16("4567890123456789"));
- strings.push_back(ASCIIToUTF16("7890123456789012"));
- String16ToStringPiece16(strings, stringPieces);
- affixLength = FormStructure::FindLongestCommonAffixLength(stringPieces, true);
- EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
-
- // Only one string, prefix case.
- strings.clear();
- strings.push_back(ASCIIToUTF16("1234567890"));
- String16ToStringPiece16(strings, stringPieces);
- affixLength =
- FormStructure::FindLongestCommonAffixLength(stringPieces, false);
- EXPECT_EQ(ASCIIToUTF16("1234567890").size(), affixLength);
-
- // Only one string, suffix case.
- strings.clear();
- strings.push_back(ASCIIToUTF16("1234567890"));
- String16ToStringPiece16(strings, stringPieces);
- affixLength = FormStructure::FindLongestCommonAffixLength(stringPieces, true);
- EXPECT_EQ(ASCIIToUTF16("1234567890").size(), affixLength);
-
- // Empty vector, prefix case.
- strings.clear();
- String16ToStringPiece16(strings, stringPieces);
- affixLength =
- FormStructure::FindLongestCommonAffixLength(stringPieces, false);
- EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
-
- // Empty vector, suffix case.
- strings.clear();
- String16ToStringPiece16(strings, stringPieces);
- affixLength = FormStructure::FindLongestCommonAffixLength(stringPieces, true);
- EXPECT_EQ(ASCIIToUTF16("").size(), affixLength);
-}
-
-TEST_F(FormStructureTestImpl, FindLongestCommonPrefix) {
- // Normal case: All strings are longer than threshold; some are common.
- std::vector<base::string16> strings;
- strings.push_back(ASCIIToUTF16("1234567890123456789"));
- strings.push_back(ASCIIToUTF16("123456789012345678_foo"));
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- strings.push_back(ASCIIToUTF16("12345678901234567890"));
- base::string16 prefix = FormStructure::FindLongestCommonPrefix(strings);
- EXPECT_EQ(ASCIIToUTF16("1234567890123456"), prefix);
-
- // Handles no common prefix.
- strings.clear();
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- strings.push_back(ASCIIToUTF16("4567890123456789"));
- strings.push_back(ASCIIToUTF16("7890123456789012"));
- prefix = FormStructure::FindLongestCommonPrefix(strings);
- EXPECT_EQ(ASCIIToUTF16(""), prefix);
-
- // Some strings less than threshold length.
- strings.clear();
- strings.push_back(ASCIIToUTF16("12345678901234567890"));
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- strings.push_back(ASCIIToUTF16(""));
- strings.push_back(ASCIIToUTF16("12345"));
- strings.push_back(ASCIIToUTF16("12345678"));
- prefix = FormStructure::FindLongestCommonPrefix(strings);
- EXPECT_EQ(ASCIIToUTF16("1234567890123456"), prefix);
-
- // Only one string.
- strings.clear();
- strings.push_back(ASCIIToUTF16("1234567890123456"));
- prefix = FormStructure::FindLongestCommonPrefix(strings);
- EXPECT_EQ(ASCIIToUTF16("1234567890123456"), prefix);
-
- // Empty vector.
- strings.clear();
- prefix = FormStructure::FindLongestCommonPrefix(strings);
- EXPECT_EQ(ASCIIToUTF16(""), prefix);
-}
-
TEST_P(ParameterizedFormStructureTest,
RationalizePhoneNumber_RunsOncePerSection) {
bool section_with_renderer_ids = GetParam();
@@ -6781,7 +6676,7 @@ TEST_F(FormStructureTestImpl,
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
@@ -6878,7 +6773,7 @@ TEST_F(
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
@@ -6984,7 +6879,7 @@ TEST_F(FormStructureTestImpl,
forms.push_back(&form_structure);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
@@ -7276,7 +7171,7 @@ TEST_F(FormStructureTestImpl,
forms.push_back(&form_structure);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
AddFieldSuggestionToForm(form_suggestion, form.fields[0], NAME_FULL);
@@ -7490,14 +7385,8 @@ INSTANTIATE_TEST_SUITE_P(All, ParameterizedFormStructureTest, testing::Bool());
// Tests that, when the flag is off, we will not set the predicted type to
// unknown for fields that have no server data and autocomplete off, and when
// the flag is ON, we will overwrite the predicted type.
-TEST_P(ParameterizedFormStructureTest,
+TEST_F(ParameterizedFormStructureTest,
NoServerData_AutocompleteOff_FlagDisabled_NoOverwrite) {
- base::test::ScopedFeatureList scoped_features;
-
- bool flag_enabled = GetParam();
- scoped_features.InitWithFeatureState(features::kAutofillOffNoServerData,
- flag_enabled);
-
FormData form;
form.url = GURL("http://foo.com");
FormFieldData field;
@@ -7541,7 +7430,7 @@ TEST_P(ParameterizedFormStructureTest,
FormStructure form_structure(form);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
@@ -7554,8 +7443,7 @@ TEST_P(ParameterizedFormStructureTest,
ASSERT_EQ(4U, forms[0]->field_count());
// Only NAME_LAST should be affected by the flag.
- EXPECT_EQ(flag_enabled ? UNKNOWN_TYPE : NAME_LAST,
- forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType());
EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(2)->Type().GetStorableType());
@@ -7564,13 +7452,7 @@ TEST_P(ParameterizedFormStructureTest,
// Tests that we never overwrite the CVC heuristic-predicted type, even if there
// is no server data (votes) for every CC fields.
-TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
- base::test::ScopedFeatureList scoped_features;
-
- bool flag_enabled = GetParam();
- scoped_features.InitWithFeatureState(features::kAutofillOffNoServerData,
- flag_enabled);
-
+TEST_F(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
FormData form;
form.url = GURL("http://foo.com");
FormFieldData field;
@@ -7611,7 +7493,7 @@ TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
FormStructure form_structure(form);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
@@ -7623,18 +7505,11 @@ TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
- // If flag is enabled, fields should have been overwritten to Unknown.
- if (flag_enabled) {
- EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(0)->Type().GetStorableType());
- EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(1)->Type().GetStorableType());
- EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(2)->Type().GetStorableType());
- } else {
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- forms[0]->field(0)->Type().GetStorableType());
- EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType());
- EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
- forms[0]->field(2)->Type().GetStorableType());
- }
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
+ forms[0]->field(2)->Type().GetStorableType());
// Regardless of the flag, the CVC field should not have been overwritten.
EXPECT_EQ(CREDIT_CARD_VERIFICATION_CODE,
@@ -7643,13 +7518,7 @@ TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
// Tests that we never overwrite the CVC heuristic-predicted type, even if there
// is server data (votes) for every other CC fields.
-TEST_P(ParameterizedFormStructureTest, WithServerDataCCFields_CVC_NoOverwrite) {
- base::test::ScopedFeatureList scoped_features;
-
- bool flag_enabled = GetParam();
- scoped_features.InitWithFeatureState(features::kAutofillOffNoServerData,
- flag_enabled);
-
+TEST_F(ParameterizedFormStructureTest, WithServerDataCCFields_CVC_NoOverwrite) {
FormData form;
form.url = GURL("http://foo.com");
FormFieldData field;
@@ -7692,7 +7561,7 @@ TEST_P(ParameterizedFormStructureTest, WithServerDataCCFields_CVC_NoOverwrite) {
FormStructure form_structure(form);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
@@ -7785,7 +7654,7 @@ TEST_P(RationalizationFieldTypeFilterTest, Rationalization_Rules_Filter_Out) {
FormStructure form_structure(form);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
@@ -7853,7 +7722,7 @@ TEST_P(RationalizationFieldTypeRelationshipsTest,
FormStructure form_structure(form);
// Will identify the sections based on the heuristics types.
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
@@ -7926,12 +7795,12 @@ TEST_F(FormStructureTestImpl, CreateForPasswordManagerUpload) {
ASSERT_EQ(FieldSignature(100u), form->field(2)->GetFieldSignature());
EXPECT_TRUE(form->EncodeUploadRequest(
{} /* available_field_types */, false /* form_was_autofilled */,
- "" /*login_form_signature*/, true /*observed_submission*/, &upload,
- &signatures));
+ "" /*login_form_signature*/, true /*observed_submission*/,
+ true /* is_raw_metadata_uploading_enabled */, &upload, &signatures));
}
// Tests if a new logical form is started with the second appearance of a field
-// of type |NAME|.
+// of type |FieldTypeGroup::kName|.
TEST_P(ParameterizedFormStructureTest, NoAutocompleteSectionNames) {
bool section_with_renderer_ids = GetParam();
base::test::ScopedFeatureList scoped_features;
diff --git a/chromium/components/autofill/core/browser/form_types.cc b/chromium/components/autofill/core/browser/form_types.cc
index 8d19644088b..ebea4c71017 100644
--- a/chromium/components/autofill/core/browser/form_types.cc
+++ b/chromium/components/autofill/core/browser/form_types.cc
@@ -7,27 +7,26 @@
namespace autofill {
-// static
-FormType FormTypes::FieldTypeGroupToFormType(FieldTypeGroup field_type_group) {
+FormType FieldTypeGroupToFormType(FieldTypeGroup field_type_group) {
switch (field_type_group) {
- case NAME:
- case NAME_BILLING:
- case EMAIL:
- case COMPANY:
- case ADDRESS_HOME:
- case ADDRESS_BILLING:
- case PHONE_HOME:
- case PHONE_BILLING:
- return ADDRESS_FORM;
- case CREDIT_CARD:
- return CREDIT_CARD_FORM;
- case USERNAME_FIELD:
- case PASSWORD_FIELD:
- return PASSWORD_FORM;
- case NO_GROUP:
- case TRANSACTION:
- case UNFILLABLE:
- return UNKNOWN_FORM_TYPE;
+ case FieldTypeGroup::kName:
+ case FieldTypeGroup::kNameBilling:
+ case FieldTypeGroup::kEmail:
+ case FieldTypeGroup::kCompany:
+ case FieldTypeGroup::kAddressHome:
+ case FieldTypeGroup::kAddressBilling:
+ case FieldTypeGroup::kPhoneHome:
+ case FieldTypeGroup::kPhoneBilling:
+ return FormType::kAddressForm;
+ case FieldTypeGroup::kCreditCard:
+ return FormType::kCreditCardForm;
+ case FieldTypeGroup::kUsernameField:
+ case FieldTypeGroup::kPasswordField:
+ return FormType::kPasswordForm;
+ case FieldTypeGroup::kNoGroup:
+ case FieldTypeGroup::kTransaction:
+ case FieldTypeGroup::kUnfillable:
+ return FormType::kUnknownFormType;
}
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_types.h b/chromium/components/autofill/core/browser/form_types.h
index 2c36914c826..516ffec3fd3 100644
--- a/chromium/components/autofill/core/browser/form_types.h
+++ b/chromium/components/autofill/core/browser/form_types.h
@@ -9,17 +9,15 @@
namespace autofill {
-enum FormType : int {
- UNKNOWN_FORM_TYPE,
- ADDRESS_FORM,
- CREDIT_CARD_FORM,
- PASSWORD_FORM
+enum class FormType : int {
+ kUnknownFormType,
+ kAddressForm,
+ kCreditCardForm,
+ kPasswordForm,
+ kMaxValue = kPasswordForm
};
-class FormTypes {
- public:
- static FormType FieldTypeGroupToFormType(FieldTypeGroup field_type_group);
-};
+FormType FieldTypeGroupToFormType(FieldTypeGroup field_type_group);
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
index 1e5ed929936..614000521de 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
@@ -27,8 +27,6 @@ AlternativeStateNameMap* AlternativeStateNameMap::GetInstance() {
return g_alternative_state_name_map.get();
}
-AlternativeStateNameMap::AlternativeStateNameMap() = default;
-
// static
AlternativeStateNameMap::StateName AlternativeStateNameMap::NormalizeStateName(
const StateName& text) {
@@ -38,6 +36,18 @@ AlternativeStateNameMap::StateName AlternativeStateNameMap::NormalizeStateName(
return StateName(normalized_text);
}
+// static
+base::Optional<AlternativeStateNameMap::CanonicalStateName>
+AlternativeStateNameMap::GetCanonicalStateName(
+ const std::string& country_code,
+ const base::string16& state_name) {
+ return AlternativeStateNameMap::GetInstance()->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode(country_code),
+ AlternativeStateNameMap::StateName(state_name));
+}
+
+AlternativeStateNameMap::AlternativeStateNameMap() = default;
+
base::Optional<AlternativeStateNameMap::CanonicalStateName>
AlternativeStateNameMap::GetCanonicalStateName(
const CountryCode& country_code,
@@ -82,17 +92,13 @@ base::Optional<StateEntry> AlternativeStateNameMap::GetEntry(
GetCanonicalStateName(country_code, normalized_state_string_from_profile,
/*is_state_name_normalized=*/true);
- if (!canonical_state_name) {
- canonical_state_name =
- CanonicalStateName(normalized_state_string_from_profile.value());
+ if (canonical_state_name) {
+ auto it = localized_state_names_map_.find(
+ {country_code, canonical_state_name.value()});
+ if (it != localized_state_names_map_.end())
+ return it->second;
}
- DCHECK(canonical_state_name);
- auto it = localized_state_names_map_.find(
- {country_code, canonical_state_name.value()});
- if (it != localized_state_names_map_.end())
- return it->second;
-
return base::nullopt;
}
@@ -101,7 +107,7 @@ void AlternativeStateNameMap::AddEntry(
const StateName& normalized_state_value_from_profile,
const StateEntry& state_entry,
const std::vector<StateName>& normalized_alternative_state_names,
- CanonicalStateName* normalized_canonical_state_name) {
+ const CanonicalStateName& normalized_canonical_state_name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
// Example:
@@ -120,25 +126,17 @@ void AlternativeStateNameMap::AddEntry(
// ("DE", "Bayern") -> "Bayern"
// ("DE", "BY") -> "Bayern"
// ("DE", "Bavaria") -> "Bayern"
-
if (localized_state_names_map_.size() == kMaxMapSize ||
GetCanonicalStateName(country_code, normalized_state_value_from_profile,
/*is_state_name_normalized=*/true)) {
return;
}
- if (normalized_canonical_state_name) {
- localized_state_names_map_[{
- country_code, *normalized_canonical_state_name}] = state_entry;
- for (const auto& alternative_name : normalized_alternative_state_names) {
- localized_state_names_reverse_lookup_map_[{
- country_code, alternative_name}] = *normalized_canonical_state_name;
- }
- } else {
- localized_state_names_map_[{
- country_code,
- CanonicalStateName(normalized_state_value_from_profile.value())}] =
- state_entry;
+ localized_state_names_map_[{country_code, normalized_canonical_state_name}] =
+ state_entry;
+ for (const auto& alternative_name : normalized_alternative_state_names) {
+ localized_state_names_reverse_lookup_map_[{
+ country_code, alternative_name}] = normalized_canonical_state_name;
}
}
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h
index 1ed11eaa6c6..5af1556d6ec 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h
@@ -12,7 +12,7 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/strings/string16.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
namespace autofill {
// AlternativeStateNameMap encapsulates mappings from state names in the
@@ -62,39 +62,44 @@ namespace autofill {
// b. ("US", "CA") -> "California"
// c. ("US", "TheGoldenState") -> "California"
//
-// Example: Assuming the user creates an unknown state in the profile
-// "Random State".
-// 1. Entries added to the |localized_state_names_map_| are:
-// ("RandomState", Empty StateEntry object)
-// 2. Nothing is added to the
-// |localized_state_names_reverse_lookup_map_| in this case
+// In case, the user has an unknown state in the profile, nothing is added to
+// the AlternativeStateNameMap;
class AlternativeStateNameMap {
public:
// Represents ISO 3166-1 alpha-2 codes (always uppercase ASCII).
- using CountryCode = util::StrongAlias<class CountryCodeTag, std::string>;
+ using CountryCode = base::StrongAlias<class CountryCodeTag, std::string>;
// Represents either a canonical state name, or an abbreviation, or an
// alternative name or normalized state name from the profile.
- using StateName = util::StrongAlias<class StateNameTag, base::string16>;
+ using StateName = base::StrongAlias<class StateNameTag, base::string16>;
// States can be represented as different strings (different spellings,
// translations, abbreviations). All representations of a single state in a
// single country are mapped to the same canonical name.
using CanonicalStateName =
- util::StrongAlias<class CanonicalStateNameTag, base::string16>;
+ base::StrongAlias<class CanonicalStateNameTag, base::string16>;
static AlternativeStateNameMap* GetInstance();
+ // Removes |kCharsToStrip| from |text| and returns the normalized text.
+ static StateName NormalizeStateName(const StateName& text);
+
+ // Calls |GetCanonicalStateName()| member method of AlternativeStateNameMap
+ // and returns the canonical state name corresponding to |country_code| and
+ // |state_name| if present.
+ static base::Optional<AlternativeStateNameMap::CanonicalStateName>
+ GetCanonicalStateName(const std::string& country_code,
+ const base::string16& state_name);
+
~AlternativeStateNameMap() = delete;
AlternativeStateNameMap(const AlternativeStateNameMap&) = delete;
AlternativeStateNameMap& operator=(const AlternativeStateNameMap&) = delete;
- // Removes |kCharsToStrip| from |text| and returns the normalized text.
- static StateName NormalizeStateName(const StateName& text);
-
// Returns the canonical name (StateEntry::canonical_name) from the
// |localized_state_names_map_| based on
// (|country_code|, |state_name|).
+ // |is_state_name_normalized| denotes whether the |state_name| has been
+ // normalized or not.
base::Optional<CanonicalStateName> GetCanonicalStateName(
const CountryCode& country_code,
const StateName& state_name,
@@ -109,18 +114,16 @@ class AlternativeStateNameMap {
// Adds ((|country_code|, state key), |state_entry|) to the
// |localized_state_names_map_|, where state key corresponds to
- // |normalized_canonical_state_name| if it is not null, or to
- // |normalized_state_value_from_profile| otherwise.
- // If |normalized_canonical_state_name| is not null, each entry from
- // |normalized_alternative_state_names| is added as a tuple
- // ((|country_code|, entry), |normalized_canonical_state_name|) to the
+ // |normalized_canonical_state_name|.
+ // Also, each entry from |normalized_alternative_state_names| is added as a
+ // tuple ((|country_code|, |entry|), |normalized_canonical_state_name|) to the
// |localized_state_names_reverse_lookup_map_|.
void AddEntry(
const CountryCode& country_code,
const StateName& normalized_state_value_from_profile,
const StateEntry& state_entry,
const std::vector<StateName>& normalized_alternative_state_names,
- CanonicalStateName* normalized_canonical_state_name);
+ const CanonicalStateName& normalized_canonical_state_name);
// Returns true if the |localized_state_names_map_| is empty.
bool IsLocalisedStateNamesMapEmpty() const;
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc
index 9435c583dbf..54ba574c204 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc
@@ -5,7 +5,6 @@
#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
namespace autofill {
@@ -25,6 +24,12 @@ void ClearAlternativeStateNameMapForTesting() {
->ClearAlternativeStateNameMapForTesting();
}
+AlternativeStateNameMap::StateName NormalizeAndConvertToUTF16(
+ const std::string& text) {
+ return AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16(text)));
+}
+
void PopulateAlternativeStateNameMapForTesting(
const std::string& country_code,
const std::string& key,
@@ -33,22 +38,24 @@ void PopulateAlternativeStateNameMapForTesting(
StateEntry state_entry;
PopulateStateEntry(test_state_entry, &state_entry);
std::vector<AlternativeStateNameMap::StateName> alternatives;
- AlternativeStateNameMap::CanonicalStateName canonical_state_name =
- AlternativeStateNameMap::CanonicalStateName(
- base::ASCIIToUTF16(test_state_entry.canonical_name));
alternatives.emplace_back(
- AlternativeStateNameMap::StateName(canonical_state_name.value()));
+ NormalizeAndConvertToUTF16(test_state_entry.canonical_name));
+ AlternativeStateNameMap::CanonicalStateName canonical_state_name;
+ if (!alternatives.empty()) {
+ canonical_state_name = AlternativeStateNameMap::CanonicalStateName(
+ alternatives.back().value());
+ }
+
for (const auto& abbr : test_state_entry.abbreviations)
- alternatives.emplace_back(
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16(abbr)));
- for (const auto& alternative_name : test_state_entry.alternative_names)
- alternatives.emplace_back(AlternativeStateNameMap::StateName(
- base::ASCIIToUTF16(alternative_name)));
+ alternatives.emplace_back(NormalizeAndConvertToUTF16(abbr));
+ for (const auto& alternative_name : test_state_entry.alternative_names) {
+ alternatives.emplace_back(NormalizeAndConvertToUTF16(alternative_name));
+ }
AlternativeStateNameMap::GetInstance()->AddEntry(
AlternativeStateNameMap::CountryCode(country_code),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16(key)),
- state_entry, alternatives, &canonical_state_name);
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16(key)), state_entry,
+ alternatives, canonical_state_name);
}
}
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h
index 0c86be629a8..29cfa66220a 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h
@@ -6,6 +6,7 @@
#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
#include "base/optional.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
#include "components/autofill/core/browser/proto/states.pb.h"
namespace autofill {
@@ -30,6 +31,10 @@ void PopulateStateEntry(const TestStateEntry& test_state_entry,
// Clears the map for testing purposes.
void ClearAlternativeStateNameMapForTesting();
+// Normalizes the text using |AlternativeStateNameMap::NormalizeStateName()|.
+AlternativeStateNameMap::StateName NormalizeAndConvertToUTF16(
+ const std::string& text);
+
// Inserts a StateEntry instance into AlternativeStateNameMap for testing.
void PopulateAlternativeStateNameMapForTesting(
const std::string& country_code = "DE",
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc
index 268b41cec02..04523a93b18 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc
@@ -24,30 +24,24 @@ TEST(AlternativeStateNameMapTest, IsEntryAddedToMap) {
TEST(AlternativeStateNameMapTest, StateCanonicalString) {
test::ClearAlternativeStateNameMapForTesting();
test::PopulateAlternativeStateNameMapForTesting();
- AlternativeStateNameMap* alternative_state_name_map =
- AlternativeStateNameMap::GetInstance();
const char* const kValidMatches[] = {"Bavaria", "BY", "Bayern", "by",
"BAVARIA", "B.Y", "BAYern", "B-Y"};
+
for (const char* valid_match : kValidMatches) {
SCOPED_TRACE(valid_match);
- EXPECT_NE(alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("DE"),
- AlternativeStateNameMap::StateName(
- base::ASCIIToUTF16(valid_match))),
+ EXPECT_NE(AlternativeStateNameMap::GetCanonicalStateName(
+ "DE", base::ASCIIToUTF16(valid_match)),
base::nullopt);
}
- EXPECT_EQ(
- alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("US"),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
- base::nullopt);
- EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("DE"),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16(""))),
+
+ EXPECT_EQ(AlternativeStateNameMap::GetCanonicalStateName(
+ "US", base::ASCIIToUTF16("Bavaria")),
+ base::nullopt);
+ EXPECT_EQ(AlternativeStateNameMap::GetCanonicalStateName(
+ "DE", base::ASCIIToUTF16("")),
base::nullopt);
- EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode(""),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16(""))),
+ EXPECT_EQ(AlternativeStateNameMap::GetCanonicalStateName(
+ "", base::ASCIIToUTF16("")),
base::nullopt);
}
@@ -57,18 +51,12 @@ TEST(AlternativeStateNameMapTest, SeparateEntryForDifferentCounties) {
test::ClearAlternativeStateNameMapForTesting();
test::PopulateAlternativeStateNameMapForTesting("DE");
test::PopulateAlternativeStateNameMapForTesting("US");
- AlternativeStateNameMap* alternative_state_name_map =
- AlternativeStateNameMap::GetInstance();
- EXPECT_NE(
- alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("DE"),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
- base::nullopt);
- EXPECT_NE(
- alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("US"),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
- base::nullopt);
+ EXPECT_NE(AlternativeStateNameMap::GetCanonicalStateName(
+ "DE", base::ASCIIToUTF16("Bavaria")),
+ base::nullopt);
+ EXPECT_NE(AlternativeStateNameMap::GetCanonicalStateName(
+ "US", base::ASCIIToUTF16("Bavaria")),
+ base::nullopt);
}
// Tests that |AlternativeStateNameMap::NormalizeStateName()| removes "-", " "
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc
index 3c85158b61e..715556cd211 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
@@ -22,6 +23,8 @@
#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "components/autofill/core/browser/geo/country_data.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_l10n_util.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/prefs/pref_service.h"
@@ -50,9 +53,11 @@ std::string LoadDataFromFile(const base::FilePath& file) {
} // namespace
-AlternativeStateNameMapUpdater::AlternativeStateNameMapUpdater()
- : task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {}
+AlternativeStateNameMapUpdater::AlternativeStateNameMapUpdater(
+ PrefService* local_state,
+ PersonalDataManager* personal_data_manager)
+ : personal_data_manager_(personal_data_manager),
+ local_state_(local_state) {}
AlternativeStateNameMapUpdater::~AlternativeStateNameMapUpdater() = default;
@@ -61,7 +66,7 @@ bool AlternativeStateNameMapUpdater::ContainsState(
const std::vector<AlternativeStateNameMap::StateName>&
stripped_alternative_state_names,
const AlternativeStateNameMap::StateName&
- stripped_state_values_from_profile) {
+ stripped_state_value_from_profile) {
l10n::CaseInsensitiveCompare compare;
// Returns true if |str1| is same as |str2| in a case-insensitive comparison.
@@ -69,32 +74,91 @@ bool AlternativeStateNameMapUpdater::ContainsState(
stripped_alternative_state_names,
[&](const AlternativeStateNameMap::StateName& text) {
return compare.StringsEqual(text.value(),
- stripped_state_values_from_profile.value());
+ stripped_state_value_from_profile.value());
});
}
+void AlternativeStateNameMapUpdater::OnPersonalDataFinishedProfileTasks() {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ PopulateAlternativeStateNameMap();
+ }
+}
+
+void AlternativeStateNameMapUpdater::PopulateAlternativeStateNameMap(
+ base::OnceClosure callback) {
+ DCHECK(personal_data_manager_);
+ std::vector<AutofillProfile*> profiles =
+ personal_data_manager_->GetProfiles();
+
+ CountryToStateNamesListMapping country_to_state_names_map;
+ for (AutofillProfile* profile : profiles) {
+ const AutofillType country_code_type(HTML_TYPE_COUNTRY_CODE,
+ HTML_MODE_NONE);
+ const AlternativeStateNameMap::CountryCode country(
+ base::UTF16ToUTF8(profile->GetInfo(
+ country_code_type, personal_data_manager_->app_locale())));
+
+ const AlternativeStateNameMap::StateName state_name(
+ profile->GetInfo(AutofillType(ADDRESS_HOME_STATE),
+ personal_data_manager_->app_locale()));
+ const AlternativeStateNameMap::StateName normalized_state =
+ AlternativeStateNameMap::NormalizeStateName(state_name);
+
+ if (country.value().empty() || normalized_state.value().empty())
+ continue;
+
+ if (parsed_state_values_.find({country, normalized_state}) !=
+ parsed_state_values_.end()) {
+ continue;
+ }
+
+ country_to_state_names_map[country].push_back(normalized_state);
+ parsed_state_values_.insert({country, normalized_state});
+ }
+
+ LoadStatesData(std::move(country_to_state_names_map), local_state_,
+ std::move(callback));
+}
+
void AlternativeStateNameMapUpdater::LoadStatesData(
- const CountryToStateNamesListMapping& country_to_state_names_map,
+ CountryToStateNamesListMapping country_to_state_names_map,
PrefService* pref_service,
base::OnceClosure done_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Get the states data installation path from |pref_service|.
- const std::string data_download_path =
- pref_service->GetString(prefs::kAutofillStatesDataDir);
+ DCHECK(pref_service);
+
+ // Get the states data installation path from |pref_service| which is set by
+ // the component updater once it downloads the states data and should be safe
+ // to use.
+ const base::FilePath data_download_path =
+ pref_service->GetFilePath(prefs::kAutofillStatesDataDir);
+
+ const std::vector<std::string>& country_codes =
+ CountryDataMap::GetInstance()->country_codes();
+
+ // Remove all invalid country names.
+ base::EraseIf(country_to_state_names_map,
+ [&country_codes](
+ const CountryToStateNamesListMapping::value_type& entry) {
+ return !base::Contains(country_codes, entry.first.value());
+ });
// If the installed directory path is empty, it means that the component is
// not ready for use yet.
- if (data_download_path.empty()) {
+ if (data_download_path.empty() || country_to_state_names_map.empty()) {
+ is_alternative_state_name_map_populated_ = true;
std::move(done_callback).Run();
return;
}
- const std::vector<std::string>& country_codes =
- CountryDataMap::GetInstance()->country_codes();
+ pending_init_done_callbacks_.push_back(std::move(done_callback));
// The |country_to_state_names_map| maps country_code names to a vector of
// state names that are associated with this corresponding country.
for (const auto& entry : country_to_state_names_map) {
+ // country_code is used as the filename.
+ // Example -> File "DE" contains the geographical states data of Germany.
const AlternativeStateNameMap::CountryCode& country_code = entry.first;
const std::vector<AlternativeStateNameMap::StateName>& states =
entry.second;
@@ -104,20 +168,12 @@ void AlternativeStateNameMapUpdater::LoadStatesData(
if (!base::Contains(country_codes, country_code.value()))
continue;
- // country_code is used as the filename.
- // Example -> File "DE" contains the geographical states data of Germany.
- // |data_download_path| is set by the component updater once it downloads
- // the states data and should be safe to use.
- const base::FilePath file_path =
- base::FilePath::FromUTF8Unsafe(data_download_path)
- .AppendASCII(country_code.value());
-
++number_pending_init_tasks_;
- pending_init_done_callbacks_.push_back(std::move(done_callback));
base::PostTaskAndReplyWithResult(
- task_runner_.get(), FROM_HERE,
- base::BindOnce(&LoadDataFromFile, file_path),
+ GetTaskRunner().get(), FROM_HERE,
+ base::BindOnce(&LoadDataFromFile,
+ data_download_path.AppendASCII(country_code.value())),
base::BindOnce(
&AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent,
weak_ptr_factory_.GetWeakPtr(), states));
@@ -145,6 +201,9 @@ void AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent(
std::vector<bool> match_found(stripped_state_values_from_profiles.size(),
false);
+ AlternativeStateNameMap* alternative_state_name_map =
+ AlternativeStateNameMap::GetInstance();
+
// Iterates over the states data loaded from the file and builds a list of
// the state names and its variations. For each value v in
// |stripped_state_values_from_profiles|, v is compared with the values in
@@ -152,47 +211,37 @@ void AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent(
// comparison results in a match, the corresponding entry is added to the
// |AlternativeStateNameMap|.
for (const auto& state_entry : states_data.states()) {
- DCHECK(state_entry.has_canonical_name());
- AlternativeStateNameMap::CanonicalStateName state_canonical_name =
- AlternativeStateNameMap::CanonicalStateName(
- base::UTF8ToUTF16(state_entry.canonical_name()));
-
// Build a list of all the names of the state (including its
// abbreviations) in |state_names|.
const std::vector<AlternativeStateNameMap::StateName> state_names =
ExtractAllStateNames(state_entry);
+ // Canonical name is always the first entry in the |state_names|.
+ DCHECK(!state_names.empty());
+ AlternativeStateNameMap::CanonicalStateName
+ normalized_canonical_state_name(state_names[0].value());
+
for (size_t i = 0; i < stripped_state_values_from_profiles.size(); i++) {
if (match_found[i])
continue;
- // If |stripped_state_values_from_profile[i] is in the set of names of
+ // If |stripped_state_values_from_profile[i]| is in the set of names of
// the state under consideration, add it to the AlternativeStateNameMap.
if (ContainsState(state_names,
stripped_state_values_from_profiles[i])) {
- AlternativeStateNameMap::GetInstance()->AddEntry(
+ alternative_state_name_map->AddEntry(
country_code, stripped_state_values_from_profiles[i], state_entry,
- state_names, &state_canonical_name);
+ state_names, normalized_canonical_state_name);
match_found[i] = true;
}
}
}
-
- for (size_t i = 0; i < stripped_state_values_from_profiles.size(); i++) {
- // In case, no match is found, insert an |empty_state_entry| object
- // to the map.
- if (!match_found[i]) {
- StateEntry empty_state_entry;
- AlternativeStateNameMap::GetInstance()->AddEntry(
- country_code, stripped_state_values_from_profiles[i],
- empty_state_entry, {}, nullptr);
- }
- }
}
// When all pending tasks are completed, trigger and clear the pending
// callbacks.
if (number_pending_init_tasks_ == 0) {
+ is_alternative_state_name_map_populated_ = true;
for (auto& callback : std::exchange(pending_init_done_callbacks_, {}))
std::move(callback).Run();
}
@@ -223,4 +272,13 @@ AlternativeStateNameMapUpdater::ExtractAllStateNames(
return state_names;
}
+scoped_refptr<base::SequencedTaskRunner>&
+AlternativeStateNameMapUpdater::GetTaskRunner() {
+ if (!task_runner_) {
+ task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
+ }
+ return task_runner_;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h
index ab1caabaf66..9e1868dd570 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h
@@ -10,44 +10,59 @@
#include <vector>
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
class PrefService;
namespace autofill {
+class PersonalDataManager;
+
using CountryToStateNamesListMapping =
std::map<AlternativeStateNameMap::CountryCode,
std::vector<AlternativeStateNameMap::StateName>>;
// The AlternativeStateNameMap is a singleton to map between canonical state
-// names and alternative representations. This class encapsulates all aspects
-// about loading state data from disk and adding it to the
-// AlternativeStateNameMap.
-class AlternativeStateNameMapUpdater {
+// names and alternative representations. This class acts as an observer to the
+// PersonalDataManager and encapsulates all aspects about loading state data
+// from disk and adding it to the AlternativeStateNameMap.
+class AlternativeStateNameMapUpdater : public PersonalDataManagerObserver {
public:
- AlternativeStateNameMapUpdater();
- ~AlternativeStateNameMapUpdater();
+ AlternativeStateNameMapUpdater(PrefService* local_state,
+ PersonalDataManager* personal_data_manager);
+ ~AlternativeStateNameMapUpdater() override;
AlternativeStateNameMapUpdater(const AlternativeStateNameMapUpdater&) =
delete;
AlternativeStateNameMapUpdater& operator=(
const AlternativeStateNameMapUpdater&) = delete;
- // Creates and posts jobs to the |task_runner_| for reading the state data
- // files and populating AlternativeStateNameMap. Once all files are read and
- // the data is incorporated into AlternativeStateNameMap, |done_callback| is
- // fired. |country_to_state_names_map| specifies which state data of which
- // countries to load.
- // Each call to LoadStatesData triggers loading state data files, so requests
- // should be batched up.
- void LoadStatesData(
- const CountryToStateNamesListMapping& country_to_state_names_map,
- PrefService* pref_service,
- base::OnceClosure done_callback);
+ // PersonalDataManagerObserver:
+ void OnPersonalDataFinishedProfileTasks() override;
+
+ // Extracts the country and state values from the profiles and adds them to
+ // the AlternativeStateNameMap.
+ void PopulateAlternativeStateNameMap(
+ base::OnceClosure callback = base::DoNothing());
+
+ // Getter method for |is_alternative_state_name_map_populated_|.
+ bool is_alternative_state_name_map_populated() const {
+ return is_alternative_state_name_map_populated_;
+ }
#if defined(UNIT_TEST)
+ // A wrapper around |LoadStatesData| used for testing purposes.
+ void LoadStatesDataForTesting(
+ CountryToStateNamesListMapping country_to_state_names_map,
+ PrefService* pref_service,
+ base::OnceClosure done_callback) {
+ LoadStatesData(std::move(country_to_state_names_map), pref_service,
+ std::move(done_callback));
+ }
+
// A wrapper around |ProcessLoadedStateFileContent| used for testing purposes.
void ProcessLoadedStateFileContentForTesting(
const std::vector<AlternativeStateNameMap::StateName>&
@@ -64,11 +79,11 @@ class AlternativeStateNameMapUpdater {
const std::vector<AlternativeStateNameMap::StateName>&
stripped_alternative_state_names,
const AlternativeStateNameMap::StateName&
- stripped_state_values_from_profile) {
+ stripped_state_value_from_profile) {
return ContainsState(stripped_alternative_state_names,
- stripped_state_values_from_profile);
+ stripped_state_value_from_profile);
}
-#endif
+#endif // defined(UNIT_TEST)
private:
// Compares |stripped_state_value_from_profile| with the entries in
@@ -77,7 +92,18 @@ class AlternativeStateNameMapUpdater {
const std::vector<AlternativeStateNameMap::StateName>&
stripped_alternative_state_names,
const AlternativeStateNameMap::StateName&
- stripped_state_values_from_profile);
+ stripped_state_value_from_profile);
+
+ // Creates and posts jobs to the |task_runner_| for reading the state data
+ // files and populating AlternativeStateNameMap. Once all files are read and
+ // the data is incorporated into AlternativeStateNameMap, |done_callback| is
+ // fired. |country_to_state_names_map| specifies which state data of which
+ // countries to load.
+ // Each call to LoadStatesData triggers loading state data files, so requests
+ // should be batched up.
+ void LoadStatesData(CountryToStateNamesListMapping country_to_state_names_map,
+ PrefService* pref_service,
+ base::OnceClosure done_callback);
// Each entry in |state_values_from_profiles| is compared with the states
// |data| read from the files and then inserted into the
@@ -92,15 +118,34 @@ class AlternativeStateNameMapUpdater {
std::vector<AlternativeStateNameMap::StateName> ExtractAllStateNames(
const StateEntry& state_entry);
+ // Lazily initializes and returns |task_runner_|.
+ scoped_refptr<base::SequencedTaskRunner>& GetTaskRunner();
+
// TaskRunner for reading files from disk.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ // A pointer to an instance of PersonalDataManager used to fetch the profiles
+ // data and register this class as an obsever.
+ PersonalDataManager* const personal_data_manager_ = nullptr;
+
+ // The browser local_state that stores the states data installation path.
+ PrefService* const local_state_ = nullptr;
+
// In case of concurrent requests to load states data, the callbacks are
// queued in |pending_init_done_callbacks_| and triggered once the
// |number_pending_init_tasks_| returns to 0.
std::vector<base::OnceClosure> pending_init_done_callbacks_;
int number_pending_init_tasks_ = 0;
+ // False, if the AlternativeStateNameMap has not been populated yet.
+ bool is_alternative_state_name_map_populated_ = false;
+
+ // Keeps track of all the state values from the current profile that have been
+ // parsed.
+ std::set<std::pair<AlternativeStateNameMap::CountryCode,
+ AlternativeStateNameMap::StateName>>
+ parsed_state_values_;
+
SEQUENCE_CHECKER(sequence_checker_);
// base::WeakPtr ensures that the callback bound to the object is canceled
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
index 97a6eb1038a..7633ea97630 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
@@ -8,10 +8,15 @@
#include "base/files/scoped_temp_dir.h"
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -22,27 +27,66 @@ using base::UTF8ToUTF16;
namespace autofill {
+class MockAlternativeStateNameMapUpdater
+ : public AlternativeStateNameMapUpdater {
+ public:
+ MockAlternativeStateNameMapUpdater(base::OnceClosure callback,
+ PrefService* local_state,
+ PersonalDataManager* personal_data_manager)
+ : AlternativeStateNameMapUpdater(local_state, personal_data_manager),
+ callback_(std::move(callback)) {}
+
+ // PersonalDataManagerObserver:
+ void OnPersonalDataFinishedProfileTasks() override {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ PopulateAlternativeStateNameMap(std::move(callback_));
+ }
+ }
+
+ private:
+ base::OnceClosure callback_;
+};
+
class AlternativeStateNameMapUpdaterTest : public ::testing::Test {
public:
- AlternativeStateNameMapUpdaterTest()
- : pref_service_(test::PrefServiceForTesting()) {}
+ AlternativeStateNameMapUpdaterTest() = default;
void SetUp() override {
+ feature_.InitAndEnableFeature(
+ features::kAutofillUseAlternativeStateNameMap);
+
+ autofill_client_.SetPrefs(test::PrefServiceForTesting());
ASSERT_TRUE(data_install_dir_.CreateUniqueTempDir());
+ personal_data_manager_.Init(/*profile_database=*/database_,
+ /*account_database=*/nullptr,
+ /*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
+ /*identity_manager=*/nullptr,
+ /*client_profile_validator=*/nullptr,
+ /*history_service=*/nullptr,
+ /*is_off_the_record=*/false);
+ alternative_state_name_map_updater_ =
+ std::make_unique<AlternativeStateNameMapUpdater>(
+ autofill_client_.GetPrefs(), &personal_data_manager_);
}
const base::FilePath& GetPath() const { return data_install_dir_.GetPath(); }
void WritePathToPref(const base::FilePath& file_path) {
- pref_service_->SetFilePath(autofill::prefs::kAutofillStatesDataDir,
- file_path);
+ autofill_client_.GetPrefs()->SetFilePath(
+ autofill::prefs::kAutofillStatesDataDir, file_path);
}
protected:
base::test::TaskEnvironment task_environment_;
- AlternativeStateNameMapUpdater alternative_state_name_map_updater;
- std::unique_ptr<PrefService> pref_service_;
+ TestAutofillClient autofill_client_;
+ scoped_refptr<AutofillWebDataService> database_;
+ std::unique_ptr<AlternativeStateNameMapUpdater>
+ alternative_state_name_map_updater_;
base::ScopedTempDir data_install_dir_;
+ base::test::ScopedFeatureList feature_;
+ TestPersonalDataManager personal_data_manager_;
};
// Tests that the states data is added to AlternativeStateNameMap.
@@ -61,17 +105,15 @@ TEST_F(AlternativeStateNameMapUpdaterTest, EntryAddedToStateMap) {
std::vector<bool> state_data_present = {true, true, true, true,
false, false, false, false};
- alternative_state_name_map_updater.ProcessLoadedStateFileContentForTesting(
+ alternative_state_name_map_updater_->ProcessLoadedStateFileContentForTesting(
test_strings, states_data, base::DoNothing());
AlternativeStateNameMap* alternative_state_name_map =
AlternativeStateNameMap::GetInstance();
DCHECK(!alternative_state_name_map->IsLocalisedStateNamesMapEmpty());
-
for (size_t i = 0; i < test_strings.size(); i++) {
SCOPED_TRACE(test_strings[i]);
- EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("DE"),
- test_strings[i]) != base::nullopt,
+ EXPECT_EQ(AlternativeStateNameMap::GetCanonicalStateName(
+ "DE", test_strings[i].value()) != base::nullopt,
state_data_present[i]);
}
}
@@ -84,19 +126,41 @@ TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesData) {
base::WriteFile(GetPath().AppendASCII("DE"),
test::CreateStatesProtoAsString());
WritePathToPref(GetPath());
+ CountryToStateNamesListMapping country_to_state_names_list_mapping = {
+ {AlternativeStateNameMap::CountryCode("DE"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))}}};
+ base::RunLoop run_loop;
+ alternative_state_name_map_updater_->LoadStatesDataForTesting(
+ country_to_state_names_list_mapping, autofill_client_.GetPrefs(),
+ run_loop.QuitClosure());
+ run_loop.Run();
+
+ EXPECT_NE(AlternativeStateNameMap::GetCanonicalStateName(
+ "DE", ASCIIToUTF16("Bavaria")),
+ base::nullopt);
+}
+
+// Tests that there is no insertion in the AlternativeStateNameMap when a
+// garbage country code is supplied to the LoadStatesData for which the states
+// data file does not exist.
+TEST_F(AlternativeStateNameMapUpdaterTest, NoTaskIsPosted) {
+ test::ClearAlternativeStateNameMapForTesting();
+ base::WriteFile(GetPath().AppendASCII("DE"),
+ test::CreateStatesProtoAsString());
+ WritePathToPref(GetPath());
+
+ CountryToStateNamesListMapping country_to_state_names_list_mapping = {
+ {AlternativeStateNameMap::CountryCode("DEE"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))}}};
base::RunLoop run_loop;
- alternative_state_name_map_updater.LoadStatesData(
- {{AlternativeStateNameMap::CountryCode("DE"),
- {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))}}},
- pref_service_.get(), run_loop.QuitClosure());
+ alternative_state_name_map_updater_->LoadStatesDataForTesting(
+ country_to_state_names_list_mapping, autofill_client_.GetPrefs(),
+ run_loop.QuitClosure());
run_loop.Run();
- EXPECT_NE(
- AlternativeStateNameMap::GetInstance()->GetCanonicalStateName(
- AlternativeStateNameMap::CountryCode("DE"),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
- base::nullopt);
+ EXPECT_TRUE(
+ AlternativeStateNameMap::GetInstance()->IsLocalisedStateNamesMapEmpty());
}
// Tests that the AlternativeStateNameMap is populated when
@@ -112,17 +176,20 @@ TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesDataUTF8) {
.alternative_names = {"Parana", "State of Parana"}}));
WritePathToPref(GetPath());
+ CountryToStateNamesListMapping country_to_state_names_list_mapping = {
+ {AlternativeStateNameMap::CountryCode("ES"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Parana"))}}};
+
base::RunLoop run_loop;
- alternative_state_name_map_updater.LoadStatesData(
- {{AlternativeStateNameMap::CountryCode("ES"),
- {AlternativeStateNameMap::StateName(ASCIIToUTF16("Parana"))}}},
- pref_service_.get(), run_loop.QuitClosure());
+ alternative_state_name_map_updater_->LoadStatesDataForTesting(
+ country_to_state_names_list_mapping, autofill_client_.GetPrefs(),
+ run_loop.QuitClosure());
run_loop.Run();
base::Optional<StateEntry> entry1 =
AlternativeStateNameMap::GetInstance()->GetEntry(
AlternativeStateNameMap::CountryCode("ES"),
- AlternativeStateNameMap::StateName(base::UTF8ToUTF16("Paraná")));
+ AlternativeStateNameMap::StateName(UTF8ToUTF16("Paraná")));
EXPECT_NE(entry1, base::nullopt);
EXPECT_EQ(entry1->canonical_name(), "Paraná");
EXPECT_THAT(entry1->abbreviations(),
@@ -133,7 +200,7 @@ TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesDataUTF8) {
base::Optional<StateEntry> entry2 =
AlternativeStateNameMap::GetInstance()->GetEntry(
AlternativeStateNameMap::CountryCode("ES"),
- AlternativeStateNameMap::StateName(base::UTF8ToUTF16("Parana")));
+ AlternativeStateNameMap::StateName(UTF8ToUTF16("Parana")));
EXPECT_NE(entry2, base::nullopt);
EXPECT_EQ(entry2->canonical_name(), "Paraná");
EXPECT_THAT(entry2->abbreviations(),
@@ -142,18 +209,101 @@ TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesDataUTF8) {
{"Parana", "State of Parana"}));
}
+// Tests that the AlternativeStateNameMap is populated when
+// |StateNameMapUpdater::LoadStatesData()| is called for states data of
+// multiple countries simultaneously.
+TEST_F(AlternativeStateNameMapUpdaterTest,
+ TestLoadStatesDataOfMultipleCountriesSimultaneously) {
+ test::ClearAlternativeStateNameMapForTesting();
+
+ base::WriteFile(GetPath().AppendASCII("DE"),
+ test::CreateStatesProtoAsString());
+ base::WriteFile(
+ GetPath().AppendASCII("ES"),
+ test::CreateStatesProtoAsString(
+ "ES", {.canonical_name = "Paraná",
+ .abbreviations = {"PR"},
+ .alternative_names = {"Parana", "State of Parana"}}));
+ WritePathToPref(GetPath());
+
+ CountryToStateNamesListMapping country_to_state_names = {
+ {AlternativeStateNameMap::CountryCode("ES"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Parana"))}},
+ {AlternativeStateNameMap::CountryCode("DE"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))}}};
+
+ base::RunLoop run_loop;
+ alternative_state_name_map_updater_->LoadStatesDataForTesting(
+ country_to_state_names, autofill_client_.GetPrefs(),
+ run_loop.QuitClosure());
+ run_loop.Run();
+
+ base::Optional<StateEntry> entry1 =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode("ES"),
+ AlternativeStateNameMap::StateName(UTF8ToUTF16("Paraná")));
+ EXPECT_NE(entry1, base::nullopt);
+ EXPECT_EQ(entry1->canonical_name(), "Paraná");
+ EXPECT_THAT(entry1->abbreviations(),
+ testing::UnorderedElementsAreArray({"PR"}));
+ EXPECT_THAT(entry1->alternative_names(), testing::UnorderedElementsAreArray(
+ {"Parana", "State of Parana"}));
+
+ base::Optional<StateEntry> entry2 =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(UTF8ToUTF16("Bavaria")));
+ EXPECT_NE(entry2, base::nullopt);
+ EXPECT_EQ(entry2->canonical_name(), "Bavaria");
+ EXPECT_THAT(entry2->abbreviations(),
+ testing::UnorderedElementsAreArray({"BY"}));
+ EXPECT_THAT(entry2->alternative_names(),
+ testing::UnorderedElementsAreArray({"Bayern"}));
+}
+
// Tests the |StateNameMapUpdater::ContainsState()| functionality.
TEST_F(AlternativeStateNameMapUpdaterTest, ContainsState) {
EXPECT_TRUE(AlternativeStateNameMapUpdater::ContainsStateForTesting(
- {AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bayern")),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("BY"))},
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))));
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("BY"))},
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))));
EXPECT_FALSE(AlternativeStateNameMapUpdater::ContainsStateForTesting(
- {AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bayern")),
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("BY"))},
- AlternativeStateNameMap::StateName(base::ASCIIToUTF16("California"))));
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("BY"))},
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("California"))));
+}
+
+// Tests that the |AlternativeStateNameMap| is populated with the help of the
+// |MockAlternativeStateNameMapUpdater| observer when a new profile is added to
+// the PDM.
+TEST_F(AlternativeStateNameMapUpdaterTest,
+ PopulateAlternativeStateNameUsingObserver) {
+ test::ClearAlternativeStateNameMapForTesting();
+ WritePathToPref(GetPath());
+ base::WriteFile(GetPath().AppendASCII("DE"),
+ test::CreateStatesProtoAsString());
+
+ AutofillProfile profile;
+ profile.SetInfo(ADDRESS_HOME_STATE, base::ASCIIToUTF16("Bavaria"), "en-US");
+ profile.SetInfo(ADDRESS_HOME_COUNTRY, base::ASCIIToUTF16("DE"), "en-US");
+
+ base::RunLoop run_loop;
+ MockAlternativeStateNameMapUpdater mock_alternative_state_name_updater(
+ run_loop.QuitClosure(), autofill_client_.GetPrefs(),
+ &personal_data_manager_);
+ personal_data_manager_.AddObserver(&mock_alternative_state_name_updater);
+ personal_data_manager_.AddProfile(profile);
+ run_loop.Run();
+ personal_data_manager_.RemoveObserver(&mock_alternative_state_name_updater);
+
+ EXPECT_FALSE(
+ AlternativeStateNameMap::GetInstance()->IsLocalisedStateNamesMapEmpty());
+ EXPECT_NE(AlternativeStateNameMap::GetCanonicalStateName(
+ "DE", base::ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::CanonicalStateName(
+ base::ASCIIToUTF16("Bayern")));
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.cc b/chromium/components/autofill/core/browser/geo/autofill_country.cc
index 121868e521a..b415b59908b 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/string_util.h"
#include "components/autofill/core/browser/geo/country_data.h"
#include "components/autofill/core/browser/geo/country_names.h"
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
index 487d46e1990..39892b620ea 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
@@ -5,7 +5,7 @@
#include <set>
#include <string>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/geo/country_data.h"
diff --git a/chromium/components/autofill/core/browser/geo/subkey_requester.cc b/chromium/components/autofill/core/browser/geo/subkey_requester.cc
index 0eb5da274bc..11c8fdae233 100644
--- a/chromium/components/autofill/core/browser/geo/subkey_requester.cc
+++ b/chromium/components/autofill/core/browser/geo/subkey_requester.cc
@@ -38,8 +38,8 @@ class SubKeyRequest : public SubKeyRequester::Request {
address_validator_(address_validator),
on_subkeys_received_(std::move(on_subkeys_received)),
has_responded_(false),
- on_timeout_(base::BindRepeating(&SubKeyRequest::OnRulesLoaded,
- base::Unretained(this))) {
+ on_timeout_(base::BindOnce(&SubKeyRequest::OnRulesLoaded,
+ base::Unretained(this))) {
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, on_timeout_.callback(),
base::TimeDelta::FromSeconds(timeout_seconds));
@@ -74,7 +74,7 @@ class SubKeyRequest : public SubKeyRequester::Request {
SubKeyReceiverCallback on_subkeys_received_;
bool has_responded_;
- base::CancelableCallback<void()> on_timeout_;
+ base::CancelableOnceClosure on_timeout_;
DISALLOW_COPY_AND_ASSIGN(SubKeyRequest);
};
diff --git a/chromium/components/autofill/core/browser/logging/log_router.cc b/chromium/components/autofill/core/browser/logging/log_router.cc
index f31dd7cb997..320e235458b 100644
--- a/chromium/components/autofill/core/browser/logging/log_router.cc
+++ b/chromium/components/autofill/core/browser/logging/log_router.cc
@@ -36,7 +36,7 @@ void LogRouter::ProcessLog(const std::string& text) {
void LogRouter::ProcessLog(base::Value&& node) {
// This may not be called when there are no receivers (i.e., the router is
// inactive), because in that case the logs cannot be displayed.
- DCHECK(receivers_.might_have_observers());
+ DCHECK(!receivers_.empty());
accumulated_logs_.emplace_back(std::move(node));
for (LogReceiver& receiver : receivers_)
receiver.LogEntry(accumulated_logs_.back());
@@ -45,7 +45,7 @@ void LogRouter::ProcessLog(base::Value&& node) {
bool LogRouter::RegisterManager(LogManager* manager) {
DCHECK(manager);
managers_.AddObserver(manager);
- return receivers_.might_have_observers();
+ return !receivers_.empty();
}
void LogRouter::UnregisterManager(LogManager* manager) {
@@ -56,9 +56,9 @@ void LogRouter::UnregisterManager(LogManager* manager) {
const std::vector<base::Value>& LogRouter::RegisterReceiver(
LogReceiver* receiver) {
DCHECK(receiver);
- DCHECK(accumulated_logs_.empty() || receivers_.might_have_observers());
+ DCHECK(accumulated_logs_.empty() || !receivers_.empty());
- if (!receivers_.might_have_observers()) {
+ if (receivers_.empty()) {
for (LogManager& manager : managers_)
manager.OnLogRouterAvailabilityChanged(true);
}
@@ -69,7 +69,7 @@ const std::vector<base::Value>& LogRouter::RegisterReceiver(
void LogRouter::UnregisterReceiver(LogReceiver* receiver) {
DCHECK(receivers_.HasObserver(receiver));
receivers_.RemoveObserver(receiver);
- if (!receivers_.might_have_observers()) {
+ if (receivers_.empty()) {
// |accumulated_logs_| can become very long; use the swap instead of clear()
// to ensure that the memory is freed.
std::vector<base::Value>().swap(accumulated_logs_);
diff --git a/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns.h b/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns.h
new file mode 100644
index 00000000000..3c8607d079c
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns.h
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_DEFAULT_REGEX_PATTERNS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_DEFAULT_REGEX_PATTERNS_H_
+
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+
+namespace autofill {
+
+PatternProvider::Map CreateDefaultRegexPatterns();
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_DEFAULT_REGEX_PATTERNS_H_
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
index 3aaeb3d97a9..b7818c26d0c 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
@@ -5,11 +5,15 @@
#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/values.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/language_code.h"
#include "components/grit/components_resources.h"
#include "ui/base/resource/resource_bundle.h"
@@ -19,7 +23,6 @@ namespace field_type_parsing {
namespace {
-const char kPatternIdentifierKey[] = "pattern_identifier";
const char kPositivePatternKey[] = "positive_pattern";
const char kNegativePatternKey[] = "negative_pattern";
const char kPositiveScoreKey[] = "positive_score";
@@ -29,13 +32,11 @@ const char kVersionKey[] = "version";
bool ParseMatchingPattern(PatternProvider::Map& patterns,
const std::string& field_type,
- const std::string& language,
+ const LanguageCode& language,
const base::Value& value) {
if (!value.is_dict())
return false;
- const std::string* pattern_identifier =
- value.FindStringKey(kPatternIdentifierKey);
const std::string* positive_pattern =
value.FindStringKey(kPositivePatternKey);
const std::string* negative_pattern =
@@ -47,18 +48,17 @@ bool ParseMatchingPattern(PatternProvider::Map& patterns,
base::Optional<int> match_field_input_types =
value.FindIntKey(kMatchFieldInputTypesKey);
- if (!pattern_identifier || !positive_pattern || !positive_score ||
- !match_field_attributes || !match_field_input_types)
+ if (!positive_pattern || !positive_score || !match_field_attributes ||
+ !match_field_input_types)
return false;
autofill::MatchingPattern new_pattern;
- new_pattern.pattern_identifier = *pattern_identifier;
new_pattern.positive_pattern = *positive_pattern;
new_pattern.positive_score = *positive_score;
if (negative_pattern != nullptr) {
new_pattern.negative_pattern = *negative_pattern;
} else {
- new_pattern.negative_pattern = base::nullopt;
+ new_pattern.negative_pattern = "";
}
new_pattern.match_field_attributes = match_field_attributes.value();
new_pattern.match_field_input_types = match_field_input_types.value();
@@ -71,24 +71,25 @@ bool ParseMatchingPattern(PatternProvider::Map& patterns,
std::vector<MatchingPattern>* pattern_list = &patterns[field_type][language];
pattern_list->push_back(new_pattern);
- DVLOG(2) << "Correctly parsed MatchingPattern with identifier |"
- << new_pattern.pattern_identifier << "|.";
+ DVLOG(2) << "Correctly parsed MatchingPattern with with type " << field_type
+ << ", language " << language.value() << ", pattern "
+ << new_pattern.positive_pattern << ".";
return true;
}
-// Callback which is used once the JSON is parsed.
-// |overwrite_equal_version| should be true when loading a remote
-// configuration. If the configuration versions are equal or
-// both unspecified (i.e. set to 0) this prioritizes the remote
+// Callback which is used once the JSON is parsed. If the configuration versions
+// are equal or both unspecified (i.e. set to 0) this prioritizes the remote
// configuration over the local one.
-void OnJsonParsed(bool overwrite_equal_version,
- base::OnceClosure done_callback,
- data_decoder::DataDecoder::ValueOrError result) {
- // Skip any processing in case of an error.
+void OnJsonParsed(data_decoder::DataDecoder::ValueOrError result) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillParsingPatternsFromRemote)) {
+ DVLOG(1) << "Remote patterns are disabled.";
+ return;
+ }
+
if (!result.value) {
DVLOG(1) << "Failed to parse PatternProvider configuration JSON string.";
- std::move(done_callback).Run();
return;
}
@@ -98,15 +99,12 @@ void OnJsonParsed(bool overwrite_equal_version,
if (patterns && version.IsValid()) {
DVLOG(1) << "Successfully parsed PatternProvider configuration.";
-
PatternProvider& pattern_provider = PatternProvider::GetInstance();
pattern_provider.SetPatterns(std::move(patterns.value()),
- std::move(version), overwrite_equal_version);
+ std::move(version));
} else {
DVLOG(1) << "Failed to parse PatternProvider configuration JSON object.";
}
-
- std::move(done_callback).Run();
}
} // namespace
@@ -130,7 +128,7 @@ base::Optional<PatternProvider::Map> GetConfigurationFromJsonObject(
}
for (const auto& value : field_type_dict->DictItems()) {
- const std::string& language = value.first;
+ LanguageCode language(value.first);
const base::Value* inner_list = &value.second;
if (!inner_list->is_list()) {
@@ -144,7 +142,7 @@ base::Optional<PatternProvider::Map> GetConfigurationFromJsonObject(
matchingPatternObj);
if (!success) {
DVLOG(1) << "Found incorrect |MatchingPattern| object in list |"
- << field_type << "|, language |" << language << "|.";
+ << field_type << "|, language |" << language.value() << "|.";
return base::nullopt;
}
}
@@ -170,35 +168,8 @@ base::Version ExtractVersionFromJsonObject(base::Value& root) {
}
void PopulateFromJsonString(std::string json_string) {
- data_decoder::DataDecoder::ParseJsonIsolated(
- std::move(json_string),
- base::BindOnce(&OnJsonParsed, true, base::DoNothing::Once()));
-}
-
-void PopulateFromResourceBundle(base::OnceClosure done_callback) {
- if (!ui::ResourceBundle::HasSharedInstance()) {
- VLOG(1) << "Resource Bundle unavailable to load Autofill Matching Pattern "
- "definitions.";
- std::move(done_callback).Run();
- return;
- }
-
- ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-
- // Load the string from the Resource Bundle on a worker thread, then
- // securely parse the JSON in a separate process and call |OnJsonParsed|
- // with the result.
- base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::MayBlock()},
- base::BindOnce(&ui::ResourceBundle::LoadDataResourceString,
- base::Unretained(&bundle), IDR_AUTOFILL_REGEX_JSON),
- base::BindOnce(
- [](base::OnceClosure done_callback, std::string resource_string) {
- data_decoder::DataDecoder::ParseJsonIsolated(
- std::move(resource_string),
- base::BindOnce(&OnJsonParsed, false, std::move(done_callback)));
- },
- std::move(done_callback)));
+ data_decoder::DataDecoder::ParseJsonIsolated(std::move(json_string),
+ base::BindOnce(&OnJsonParsed));
}
base::Optional<PatternProvider::Map>
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
index a9cd570a644..de78bc26736 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
@@ -9,6 +9,8 @@
#include "base/json/json_reader.h"
#include "base/test/gtest_util.h"
#include "base/version.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/common/language_code.h"
#include "components/grit/components_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
@@ -21,11 +23,11 @@ namespace field_type_parsing {
// parsed to the map structure used by |PatternProvider| as
// expected, given the input is valid.
TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
- std::string JSON_message = R"(
+ std::string json_message = R"(
{
"version": "1.0",
"FULL_NAME": {
- "en_us": [
+ "en": [
{
"pattern_identifier": "Name_en",
"positive_pattern": "name|full name",
@@ -47,7 +49,7 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
]
},
"ADDRESS": {
- "en_us": [
+ "en": [
{
"pattern_identifier": "Address",
"positive_pattern": "address",
@@ -59,14 +61,14 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
]
}
})";
- base::Optional<base::Value> JSON_object =
- base::JSONReader::Read(JSON_message);
+ base::Optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
- ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
- base::Version version = ExtractVersionFromJsonObject(JSON_object.value());
+ base::Version version = ExtractVersionFromJsonObject(json_object.value());
base::Optional<PatternProvider::Map> optional_patterns =
- GetConfigurationFromJsonObject(JSON_object.value());
+ GetConfigurationFromJsonObject(json_object.value());
ASSERT_TRUE(version.IsValid());
ASSERT_TRUE(optional_patterns);
@@ -78,20 +80,19 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
ASSERT_EQ(2U, patterns.size());
ASSERT_TRUE(patterns.count("FULL_NAME"));
ASSERT_EQ(2U, patterns["FULL_NAME"].size());
- ASSERT_TRUE(patterns["FULL_NAME"].count("en_us"));
- ASSERT_TRUE(patterns["FULL_NAME"].count("fr"));
+ ASSERT_TRUE(patterns["FULL_NAME"].count(LanguageCode("en")));
+ ASSERT_TRUE(patterns["FULL_NAME"].count(LanguageCode("fr")));
ASSERT_TRUE(patterns.count("ADDRESS"));
ASSERT_EQ(1U, patterns["ADDRESS"].size());
- ASSERT_TRUE(patterns["ADDRESS"].count("en_us"));
+ ASSERT_TRUE(patterns["ADDRESS"].count(LanguageCode("en")));
// Test one |MatchingPattern| to check that they are parsed correctly.
- MatchingPattern* pattern = &patterns["FULL_NAME"]["fr"][0];
+ MatchingPattern* pattern = &patterns["FULL_NAME"][LanguageCode("fr")][0];
- ASSERT_EQ("Name_fr", pattern->pattern_identifier);
ASSERT_EQ("nom|prenom", pattern->positive_pattern);
ASSERT_EQ("compagne", pattern->negative_pattern);
- ASSERT_EQ("fr", pattern->language);
+ ASSERT_EQ(LanguageCode("fr"), pattern->language);
ASSERT_NEAR(2.0, pattern->positive_score, 1e-6);
ASSERT_EQ(2, pattern->match_field_attributes);
ASSERT_EQ(3 << 2, pattern->match_field_input_types);
@@ -100,11 +101,11 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
// Test that the parser does not return anything if some |MatchingPattern|
// object is missing a property.
TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
- std::string JSON_message = R"(
+ std::string json_message = R"(
{
"version": "1.0",
"FULL_NAME": {
- "en_us": [
+ "en": [
{
"pattern_identifier": "Name_en",
"positive_pattern": "name|full name",
@@ -125,13 +126,13 @@ TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
]
}
})";
- base::Optional<base::Value> JSON_object =
- base::JSONReader::Read(JSON_message);
+ base::Optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
- ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
base::Optional<PatternProvider::Map> optional_patterns =
- GetConfigurationFromJsonObject(JSON_object.value());
+ GetConfigurationFromJsonObject(json_object.value());
ASSERT_FALSE(optional_patterns);
}
@@ -139,12 +140,11 @@ TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
// Test that the parser correctly sets the default version if
// it is not present in the configuration.
TEST(PatternConfigurationParserTest, MalformedMissingVersion) {
- std::string JSON_message = R"(
+ std::string json_message = R"(
{
"FULL_NAME": {
- "en_us": [
+ "en": [
{
- "pattern_identifier": "Name_en",
"positive_pattern": "name|full name",
"positive_score": 2.0,
"negative_pattern": "company",
@@ -154,12 +154,12 @@ TEST(PatternConfigurationParserTest, MalformedMissingVersion) {
]
}
})";
- base::Optional<base::Value> JSON_object =
- base::JSONReader::Read(JSON_message);
+ base::Optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
- ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
- base::Version version = ExtractVersionFromJsonObject(JSON_object.value());
+ base::Version version = ExtractVersionFromJsonObject(json_object.value());
ASSERT_EQ(base::Version("0"), version);
}
@@ -167,11 +167,10 @@ TEST(PatternConfigurationParserTest, MalformedMissingVersion) {
// Test that the parser does not return anything if the inner key points
// to a single object instead of a list.
TEST(PatternConfigurationParserTest, MalformedNotList) {
- std::string JSON_message = R"(
+ std::string json_message = R"(
{
"FULL_NAME": {
- "en_us": {
- "pattern_identifier": "Name_en",
+ "en": {
"positive_pattern": "name|full name",
"positive_score": 2.0,
"negative_pattern": "company",
@@ -180,13 +179,13 @@ TEST(PatternConfigurationParserTest, MalformedNotList) {
}
}
})";
- base::Optional<base::Value> JSON_object =
- base::JSONReader::Read(JSON_message);
+ base::Optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
- ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
base::Optional<PatternProvider::Map> optional_patterns =
- GetConfigurationFromJsonObject(JSON_object.value());
+ GetConfigurationFromJsonObject(json_object.value());
ASSERT_FALSE(optional_patterns);
}
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
index 349c0d8c39a..f1e0d9090f4 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
@@ -13,6 +13,7 @@
#include "base/no_destructor.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
+#include "components/autofill/core/browser/pattern_provider/default_regex_patterns.h"
#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -27,10 +28,10 @@ void EnrichPatternsWithEnVersion(
PatternProvider::Map* type_and_lang_to_patterns) {
DCHECK(type_and_lang_to_patterns);
for (auto& p : *type_and_lang_to_patterns) {
- std::map<std::string, std::vector<MatchingPattern>>& lang_to_patterns =
+ std::map<LanguageCode, std::vector<MatchingPattern>>& lang_to_patterns =
p.second;
- auto it = lang_to_patterns.find(kSourceCodeLanguage);
+ auto it = lang_to_patterns.find(LanguageCode(kSourceCodeLanguage));
if (it == lang_to_patterns.end())
continue;
std::vector<MatchingPattern> en_patterns = it->second;
@@ -39,10 +40,10 @@ void EnrichPatternsWithEnVersion(
}
for (auto& q : lang_to_patterns) {
- const std::string& page_language = q.first;
+ const LanguageCode& page_language = q.first;
std::vector<MatchingPattern>& patterns = q.second;
- if (page_language != kSourceCodeLanguage) {
+ if (page_language != LanguageCode(kSourceCodeLanguage)) {
patterns.insert(patterns.end(), en_patterns.begin(), en_patterns.end());
}
}
@@ -52,7 +53,7 @@ void EnrichPatternsWithEnVersion(
// Sorts patterns in descending order by their score.
void SortPatternsByScore(PatternProvider::Map* type_and_lang_to_patterns) {
for (auto& p : *type_and_lang_to_patterns) {
- std::map<std::string, std::vector<MatchingPattern>>& lang_to_patterns =
+ std::map<LanguageCode, std::vector<MatchingPattern>>& lang_to_patterns =
p.second;
for (auto& q : lang_to_patterns) {
std::vector<MatchingPattern>& patterns = q.second;
@@ -65,44 +66,27 @@ void SortPatternsByScore(PatternProvider::Map* type_and_lang_to_patterns) {
}
}
-PatternProvider* PatternProvider::g_pattern_provider = nullptr;
-
// static
PatternProvider& PatternProvider::GetInstance() {
- if (!g_pattern_provider) {
- static base::NoDestructor<PatternProvider> instance;
- g_pattern_provider = instance.get();
- // TODO(crbug/1147608) This is an ugly hack to avoid loading the JSON. The
- // motivation is that some Android unit tests fail because a dependency is
- // missing. Instead of fixing this dependency, we'll go for an alternative
- // solution that avoids the whole async/sync problem.
- if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
- base::FeatureList::IsEnabled(
- features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
- field_type_parsing::PopulateFromResourceBundle();
- }
+ static base::NoDestructor<PatternProvider> instance;
+ static bool initialized = false;
+ if (!initialized) {
+ instance->SetPatterns(CreateDefaultRegexPatterns(), base::Version());
+ initialized = true;
}
- return *g_pattern_provider;
-}
-
-// static
-void PatternProvider::ResetPatternProvider() {
- g_pattern_provider = nullptr;
+ return *instance;
}
PatternProvider::PatternProvider() = default;
PatternProvider::~PatternProvider() = default;
void PatternProvider::SetPatterns(PatternProvider::Map patterns,
- const base::Version version,
- const bool overwrite_equal_version) {
+ const base::Version& version) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!pattern_version_.IsValid() || pattern_version_ < version ||
- (overwrite_equal_version && pattern_version_ == version)) {
- patterns_ = patterns;
+ if (!pattern_version_.IsValid() ||
+ (version.IsValid() && pattern_version_ <= version)) {
+ patterns_ = std::move(patterns);
pattern_version_ = version;
EnrichPatternsWithEnVersion(&patterns_);
SortPatternsByScore(&patterns_);
@@ -111,15 +95,15 @@ void PatternProvider::SetPatterns(PatternProvider::Map patterns,
const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
const std::string& pattern_name,
- const std::string& page_language) const {
+ const LanguageCode& page_language) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug.com/1134496): Remove feature check once launched.
if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToSelectFieldParsingPatterns)) {
+ features::kAutofillParsingPatternsLanguageDependent)) {
auto outer_it = patterns_.find(pattern_name);
if (outer_it != patterns_.end()) {
- const std::map<std::string, std::vector<MatchingPattern>>&
+ const std::map<LanguageCode, std::vector<MatchingPattern>>&
lang_to_pattern = outer_it->second;
auto inner_it = lang_to_pattern.find(page_language);
if (inner_it != lang_to_pattern.end()) {
@@ -130,10 +114,8 @@ const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
}
}
return GetAllPatternsByType(pattern_name);
- } else if (
- base::FeatureList::IsEnabled(
- features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ } else if (base::FeatureList::IsEnabled(
+ features::kAutofillParsingPatternsNegativeMatching)) {
return GetAllPatternsByType(pattern_name);
} else {
return {};
@@ -142,15 +124,14 @@ const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
ServerFieldType type,
- const std::string& page_language) const {
- std::string pattern_name = AutofillType(type).ToString();
- return GetMatchPatterns(pattern_name, page_language);
+ const LanguageCode& page_language) const {
+ return GetMatchPatterns(AutofillType::ServerFieldTypeToString(type),
+ page_language);
}
const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
ServerFieldType type) const {
- std::string type_str = AutofillType(type).ToString();
- return GetAllPatternsByType(type_str);
+ return GetAllPatternsByType(AutofillType::ServerFieldTypeToString(type));
}
const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
@@ -158,16 +139,16 @@ const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
auto it = patterns_.find(type);
if (it == patterns_.end())
return {};
- const std::map<std::string, std::vector<MatchingPattern>>& type_patterns =
+ const std::map<LanguageCode, std::vector<MatchingPattern>>& type_patterns =
it->second;
std::vector<MatchingPattern> all_language_patterns;
for (const auto& p : type_patterns) {
- const std::string& page_language = p.first;
+ const LanguageCode& page_language = p.first;
const std::vector<MatchingPattern>& language_patterns = p.second;
for (const MatchingPattern& mp : language_patterns) {
- if (page_language == kSourceCodeLanguage ||
- mp.language != kSourceCodeLanguage) {
+ if (page_language == LanguageCode(kSourceCodeLanguage) ||
+ mp.language != LanguageCode(kSourceCodeLanguage)) {
all_language_patterns.push_back(mp);
}
}
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
index 4ddd9cf6469..767ad35788e 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
@@ -11,10 +11,12 @@
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
+#include "base/types/strong_alias.h"
#include "base/version.h"
#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
+#include "components/autofill/core/common/language_code.h"
namespace autofill {
@@ -25,28 +27,25 @@ class PatternProvider {
public:
// The outer keys are field types or other pattern names. The inner keys are
// page languages in lower case.
- // TODO(crbug/1142413): decide on uppercase or lowercase.
using Map = std::map<std::string,
- std::map<std::string, std::vector<MatchingPattern>>>;
+ std::map<LanguageCode, std::vector<MatchingPattern>>>;
// Returns a reference to the global Pattern Provider.
static PatternProvider& GetInstance();
// Setter for loading patterns from external storage.
- void SetPatterns(const Map patterns,
- const base::Version version,
- const bool overwrite_equal_version);
+ void SetPatterns(const Map patterns, const base::Version& version);
// Find the patterns for a given ServerFieldType and for a given
// |page_language|.
const std::vector<MatchingPattern> GetMatchPatterns(
ServerFieldType type,
- const std::string& page_language) const;
+ const LanguageCode& page_language) const;
// Find the patterns for a given |pattern_name| and a given |page_language|.
const std::vector<MatchingPattern> GetMatchPatterns(
const std::string& pattern_name,
- const std::string& page_language) const;
+ const LanguageCode& page_language) const;
// Find all patterns, across all languages, for a given server field |type|.
const std::vector<MatchingPattern> GetAllPatternsByType(
@@ -57,30 +56,14 @@ class PatternProvider {
const std::string& type) const;
protected:
- // Sets a provider to be used for tests.
- static void SetPatternProviderForTesting(PatternProvider* pattern_provider) {
- DCHECK(pattern_provider);
- g_pattern_provider = pattern_provider;
- }
-
- // Resets the provider pointer if the object behind it gets deleted.
- static void ResetPatternProvider();
-
PatternProvider();
~PatternProvider();
- const Map& patterns() const { return patterns_; }
-
private:
- FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderPipelineTest,
- TestParsingEquivalent);
- FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderPipelineTest,
- DefaultPatternProviderLoads);
+ FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderTest, TestDefaultEqualsJson);
friend class base::NoDestructor<PatternProvider>;
- static PatternProvider* g_pattern_provider;
-
// Sequence checker to ensure thread-safety for pattern swapping.
// All functions accessing the |patterns_| member variable are
// expected to be called from the UI thread.
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
index 5222b67d903..c3faf37c79f 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
@@ -16,199 +16,193 @@
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/language_code.h"
+#include "components/grit/components_resources.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
namespace autofill {
namespace {
+LanguageCode kLanguageDe("de");
+LanguageCode kLanguageEn("en");
+
MatchingPattern GetCompanyPatternEn() {
autofill::MatchingPattern m_p;
- m_p.pattern_identifier = "kCompanyPatternEn";
m_p.positive_pattern = "company|business|organization|organisation";
- m_p.positive_score = 1.1f;
+ m_p.positive_score = 1.1;
m_p.negative_pattern = "";
m_p.match_field_attributes = MATCH_NAME;
m_p.match_field_input_types = MATCH_TEXT;
- m_p.language = "en";
+ m_p.language = kLanguageEn;
return m_p;
}
MatchingPattern GetCompanyPatternDe() {
autofill::MatchingPattern m_p;
- m_p.pattern_identifier = "kCompanyPatternDe";
m_p.positive_pattern = "|(?<!con)firma|firmenname";
- m_p.positive_score = 1.1f;
+ m_p.positive_score = 1.1;
m_p.negative_pattern = "";
m_p.match_field_attributes = MATCH_LABEL | MATCH_NAME;
m_p.match_field_input_types = MATCH_TEXT;
- m_p.language = "de";
+ m_p.language = kLanguageDe;
return m_p;
}
// Pattern Provider with custom values set for testing.
class UnitTestPatternProvider : public PatternProvider {
public:
- UnitTestPatternProvider();
+ UnitTestPatternProvider()
+ : UnitTestPatternProvider({GetCompanyPatternDe()},
+ {GetCompanyPatternEn()}) {}
+
UnitTestPatternProvider(const std::vector<MatchingPattern>& de_patterns,
- const std::vector<MatchingPattern>& en_patterns);
- ~UnitTestPatternProvider();
+ const std::vector<MatchingPattern>& en_patterns) {
+ Map patterns;
+ auto& company_patterns =
+ patterns[AutofillType::ServerFieldTypeToString(COMPANY_NAME)];
+ company_patterns[kLanguageDe] = de_patterns;
+ company_patterns[kLanguageEn] = en_patterns;
+ SetPatterns(std::move(patterns), base::Version());
+ }
};
-UnitTestPatternProvider::UnitTestPatternProvider()
- : UnitTestPatternProvider({GetCompanyPatternDe()},
- {GetCompanyPatternEn()}) {}
-
-UnitTestPatternProvider::UnitTestPatternProvider(
- const std::vector<MatchingPattern>& de_patterns,
- const std::vector<MatchingPattern>& en_patterns) {
- PatternProvider::SetPatternProviderForTesting(this);
- Map patterns;
- auto& company_patterns = patterns[AutofillType(COMPANY_NAME).ToString()];
- company_patterns["de"] = de_patterns;
- company_patterns["en"] = en_patterns;
- SetPatterns(patterns, base::Version(), true);
+// Called when the JSON bundle has been parsed, and sets the PatternProvider's
+// patterns.
+void OnJsonParsed(base::OnceClosure done_callback,
+ data_decoder::DataDecoder::ValueOrError result) {
+ base::Version version =
+ field_type_parsing::ExtractVersionFromJsonObject(result.value.value());
+ base::Optional<PatternProvider::Map> patterns =
+ field_type_parsing::GetConfigurationFromJsonObject(result.value.value());
+ ASSERT_TRUE(patterns);
+ ASSERT_TRUE(version.IsValid());
+ PatternProvider& pattern_provider = PatternProvider::GetInstance();
+ pattern_provider.SetPatterns(std::move(patterns.value()), std::move(version));
+ std::move(done_callback).Run();
}
-UnitTestPatternProvider::~UnitTestPatternProvider() {
- PatternProvider::ResetPatternProvider();
+// Loads the string from the Resource Bundle on a worker thread.
+void LoadPatternsFromResourceBundle() {
+ ASSERT_TRUE(ui::ResourceBundle::HasSharedInstance());
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ base::RunLoop run_loop;
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock()},
+ base::BindOnce(&ui::ResourceBundle::LoadDataResourceString,
+ base::Unretained(&bundle), IDR_AUTOFILL_REGEX_JSON),
+ base::BindOnce(
+ [](base::OnceClosure done_callback, std::string resource_string) {
+ data_decoder::DataDecoder::ParseJsonIsolated(
+ std::move(resource_string),
+ base::BindOnce(&OnJsonParsed, std::move(done_callback)));
+ },
+ run_loop.QuitClosure()));
+ run_loop.Run();
}
} // namespace
-class AutofillPatternProviderTest : public testing::Test {
- protected:
- UnitTestPatternProvider pattern_provider_;
-
- ~AutofillPatternProviderTest() override = default;
-};
-
bool operator==(const MatchingPattern& mp1, const MatchingPattern& mp2) {
- return (mp1.language == mp2.language &&
- mp1.match_field_attributes == mp2.match_field_attributes &&
- mp1.match_field_input_types == mp2.match_field_input_types &&
- mp1.negative_pattern == mp2.negative_pattern &&
- mp1.pattern_identifier == mp2.pattern_identifier &&
- mp1.positive_pattern == mp2.positive_pattern &&
- mp1.positive_score == mp2.positive_score);
+ return mp1.language == mp2.language &&
+ mp1.positive_pattern == mp2.positive_pattern &&
+ mp1.negative_pattern == mp2.negative_pattern &&
+ mp1.positive_score == mp2.positive_score &&
+ mp1.match_field_attributes == mp2.match_field_attributes &&
+ mp1.match_field_input_types == mp2.match_field_input_types;
}
-TEST(AutofillPatternProvider, Single_Match) {
+TEST(AutofillPatternProviderTest, Single_Match) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
- features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
+ features::kAutofillParsingPatternsLanguageDependent);
- MatchingPattern kCompanyPatternEn = GetCompanyPatternEn();
- MatchingPattern kCompanyPatternDe = GetCompanyPatternDe();
- UnitTestPatternProvider* pattern_provider = new UnitTestPatternProvider();
- auto pattern_store = pattern_provider->GetMatchPatterns("COMPANY_NAME", "en");
-
- ASSERT_EQ(pattern_store.size(), 1u);
- EXPECT_EQ(pattern_store[0], kCompanyPatternEn);
+ UnitTestPatternProvider p;
+ EXPECT_THAT(p.GetMatchPatterns("COMPANY_NAME", kLanguageEn),
+ ::testing::ElementsAre(GetCompanyPatternEn()));
+ EXPECT_THAT(
+ p.GetMatchPatterns("COMPANY_NAME", kLanguageDe),
+ ::testing::ElementsAre(GetCompanyPatternDe(), GetCompanyPatternEn()));
}
-// Test that the default pattern provider loads without crashing.
-TEST(AutofillPatternProviderPipelineTest, DefaultPatternProviderLoads) {
- base::test::ScopedFeatureList scoped_feature_list;
- // Enable so that PatternProvider::GetInstance() actually does load the JSON.
- scoped_feature_list.InitAndEnableFeature(
- autofill::features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
-
- base::test::TaskEnvironment task_environment_;
- data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
-
- base::RunLoop run_loop;
- field_type_parsing::PopulateFromResourceBundle(run_loop.QuitClosure());
- run_loop.Run();
- PatternProvider& default_pattern_provider = PatternProvider::GetInstance();
-
- EXPECT_FALSE(default_pattern_provider.patterns().empty());
-
- // Call the getter to ensure sequence checks work correctly.
- default_pattern_provider.GetMatchPatterns("EMAIL_ADDRESS", "en");
+TEST(AutofillPatternProviderTest, BasedOnMatchType) {
+ UnitTestPatternProvider p;
+ EXPECT_THAT(
+ p.GetAllPatternsByType("COMPANY_NAME"),
+ ::testing::ElementsAre(GetCompanyPatternDe(), GetCompanyPatternEn()));
}
-// Test that the TestPatternProvider class uses a PatternProvider::Map
-// equivalent to the DefaultPatternProvider. This is also an example of what is
-// needed to test the DefaultPatternProvider. Warning: If this crashes, check
-// that no state carried over from other tests using the singleton.
-TEST(AutofillPatternProviderPipelineTest, TestParsingEquivalent) {
- base::test::ScopedFeatureList scoped_feature_list;
- // Enable so that PatternProvider::GetInstance() actually does load the JSON.
- scoped_feature_list.InitAndEnableFeature(
- autofill::features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
-
+TEST(AutofillPatternProviderTest, TestDefaultEqualsJson) {
base::test::TaskEnvironment task_environment_;
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
- base::RunLoop run_loop;
- field_type_parsing::PopulateFromResourceBundle(run_loop.QuitClosure());
- run_loop.Run();
- PatternProvider& default_pattern_provider = PatternProvider::GetInstance();
+ auto default_version = PatternProvider::GetInstance().pattern_version_;
+ auto default_patterns = PatternProvider::GetInstance().patterns_;
- TestPatternProvider test_pattern_provider;
+ // We want to make sure that the JSON loading actually does set the patterns.
+ // To this end, manipulate the current patterns. Then |default_patterns| can
+ // only be identical to |json_patterns| if loading the JSON updates the
+ // patterns.
+ PatternProvider::GetInstance().patterns_.clear();
+ ASSERT_NE(default_patterns, PatternProvider::GetInstance().patterns_);
- EXPECT_EQ(default_pattern_provider.patterns(),
- test_pattern_provider.patterns());
-}
+ // Load the JSON explicitly from the file.
+ LoadPatternsFromResourceBundle();
-TEST(AutofillPatternProvider, BasedOnMatchType) {
- UnitTestPatternProvider p;
- ASSERT_GT(p.GetAllPatternsByType("COMPANY_NAME").size(), 0u);
- EXPECT_EQ(p.GetAllPatternsByType("COMPANY_NAME"),
- std::vector<MatchingPattern>(
- {GetCompanyPatternDe(), GetCompanyPatternEn()}));
- EXPECT_EQ(p.GetAllPatternsByType("COMPANY_NAME").size(), 2u);
+ auto json_version = PatternProvider::GetInstance().pattern_version_;
+ auto json_patterns = PatternProvider::GetInstance().patterns_;
+
+ EXPECT_FALSE(default_version.IsValid());
+ EXPECT_TRUE(json_version.IsValid());
+ EXPECT_EQ(default_patterns, json_patterns);
}
-TEST(AutofillPatternProvider, UnknownLanguages) {
+TEST(AutofillPatternProviderTest, UnknownLanguages) {
{
base::test::ScopedFeatureList feature;
feature.InitWithFeatures(
// enabled
- {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+ {features::kAutofillParsingPatternsLanguageDependent},
// disabled
- {features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+ {features::kAutofillParsingPatternsNegativeMatching});
UnitTestPatternProvider p;
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", ""),
- p.GetAllPatternsByType("COMPANY_NAME"));
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "blabla"),
- p.GetAllPatternsByType("COMPANY_NAME"));
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("")),
+ p.GetAllPatternsByType(COMPANY_NAME));
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("io")),
+ p.GetAllPatternsByType(COMPANY_NAME));
}
{
base::test::ScopedFeatureList feature;
feature.InitWithFeatures(
// enabled
- {features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ {features::kAutofillParsingPatternsNegativeMatching},
// disabled
- {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+ {features::kAutofillParsingPatternsLanguageDependent});
UnitTestPatternProvider p;
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", ""),
- p.GetAllPatternsByType("COMPANY_NAME"));
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "blabla"),
- p.GetAllPatternsByType("COMPANY_NAME"));
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("")),
+ p.GetAllPatternsByType(COMPANY_NAME));
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("io")),
+ p.GetAllPatternsByType(COMPANY_NAME));
}
}
-TEST(AutofillPatternProvider, EnrichPatternsWithEnVersion) {
+TEST(AutofillPatternProviderTest, EnrichPatternsWithEnVersion) {
{
base::test::ScopedFeatureList feature;
feature.InitWithFeatures(
// enabled
- {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+ {features::kAutofillParsingPatternsLanguageDependent},
// disabled
- {features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+ {features::kAutofillParsingPatternsNegativeMatching});
UnitTestPatternProvider p;
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "en"),
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageEn),
std::vector<MatchingPattern>{GetCompanyPatternEn()});
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "de"),
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageDe),
std::vector<MatchingPattern>(
{GetCompanyPatternDe(), GetCompanyPatternEn()}));
}
@@ -217,26 +211,25 @@ TEST(AutofillPatternProvider, EnrichPatternsWithEnVersion) {
base::test::ScopedFeatureList feature;
feature.InitWithFeatures(
// enabled
- {features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ {features::kAutofillParsingPatternsNegativeMatching},
// disabled
- {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+ {features::kAutofillParsingPatternsLanguageDependent});
UnitTestPatternProvider p;
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "en"),
- std::vector<MatchingPattern>({GetCompanyPatternDe(),
- GetCompanyPatternEn()}));
- EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "de"),
- std::vector<MatchingPattern>({GetCompanyPatternDe(),
- GetCompanyPatternEn()}));
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageEn),
+ std::vector<MatchingPattern>(
+ {GetCompanyPatternDe(), GetCompanyPatternEn()}));
+ EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageDe),
+ std::vector<MatchingPattern>(
+ {GetCompanyPatternDe(), GetCompanyPatternEn()}));
}
}
-TEST(AutofillPatternProvider, SortPatternsByScore) {
+TEST(AutofillPatternProviderTest, SortPatternsByScore) {
base::test::ScopedFeatureList feature;
feature.InitWithFeatures(
// enabled
- {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns,
- features::kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ {features::kAutofillParsingPatternsLanguageDependent,
+ features::kAutofillParsingPatternsNegativeMatching},
// disabled
{});
std::vector<MatchingPattern> de_input_patterns;
@@ -250,7 +243,7 @@ TEST(AutofillPatternProvider, SortPatternsByScore) {
de_input_patterns[3].positive_score = 3.0;
UnitTestPatternProvider p(de_input_patterns, {});
const std::vector<MatchingPattern>& de_patterns =
- p.GetMatchPatterns(COMPANY_NAME, "de");
+ p.GetMatchPatterns(COMPANY_NAME, kLanguageDe);
ASSERT_EQ(de_patterns.size(), de_input_patterns.size());
EXPECT_EQ(de_patterns[0].positive_score, 5.0);
EXPECT_EQ(de_patterns[1].positive_score, 3.0);
diff --git a/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
index 16778eac24e..6dc7780d233 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
+++ b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
@@ -20,6 +20,16 @@
"match_field_input_types": 1
}
],
+ "es" : [
+ {
+ "pattern_identifier": "es_street_name",
+ "positive_pattern": "calle",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
"ru" : [
{
"pattern_identifier": "ru_street_name",
@@ -41,6 +51,68 @@
}
]
},
+ "ADDRESS_HOME_APT_NUM": {
+ "en": [
+ {
+ "pattern_identifier": "en_apartment_number",
+ "positive_pattern": "apartment",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_apartment_number",
+ "positive_pattern": "interior|número.*apartamento",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_apartment_number",
+ "positive_pattern": "wohnung",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_apartment_number",
+ "positive_pattern": "квартир",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_apartment_number",
+ "positive_pattern": "numero.*appartamento",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_apartment_number",
+ "positive_pattern": "numéro.*appartement",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
"ADDRESS_HOME_HOUSE_NUMBER":{
"en": [
{
@@ -49,7 +121,7 @@
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_input_types": 69
}
],
"de": [
@@ -59,7 +131,7 @@
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_input_types": 69
}
],
"pt": [
@@ -69,9 +141,19 @@
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_input_types": 69
}
],
+ "es": [
+ {
+ "pattern_identifier": "es_house_number",
+ "positive_pattern": "n(u|ú)mero.*apartamento|exterior",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
"ru": [
{
"pattern_identifier": "ru_house_number",
@@ -79,7 +161,7 @@
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_input_types": 69
}
]
},
@@ -137,9 +219,39 @@
"match_field_attributes": 3,
"match_field_input_types": 1
}
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_address_name_ignored_preserving",
+ "positive_pattern": "adres ([İi]sim|başlığı|adı)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_address_name_ignored_preserving",
+ "positive_pattern": "identificação do endereço",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_address_name_ignored_preserving",
+ "positive_pattern": "(label|judul|nama) alamat",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
]
},
- "COMPANY": {
+ "COMPANY_NAME": {
"en": [
{
"pattern_identifier": "en_company_preserving",
@@ -210,7 +322,7 @@
"match_field_input_types": 1
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_company_preserving",
"positive_pattern": "单位|公司",
@@ -239,6 +351,16 @@
"match_field_attributes": 3,
"match_field_input_types": 1
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_company_preserving",
+ "positive_pattern": "(nama.?)?perusahaan",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
]
},
"ADDRESS_LINE_1": {
@@ -253,7 +375,7 @@
},
{
"pattern_identifier": "en_address_line_1_label_preserving",
- "positive_pattern": "(^\\W*address)|(address\\W*$)|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|recipient|home|work|office|school|business|mail)[\\s\\-]+address|address\\s+(of|for|to|from)",
+ "positive_pattern": "(^\\W*address)|(address\\W*$)|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|recipient|home|work|office|school|business|mail)[\\s\\-]+address|address\\s+(of|for|to|from)|street.*(house|building|apartment|floor)|(house|building|apartment|floor).*street",
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 1,
@@ -352,30 +474,30 @@
"negative_pattern": null,
"match_field_attributes": 3,
"match_field_input_types": 1
- }
- ],
- "zh": [
+ },
{
- "pattern_identifier": "zh_address_line_1_preserving",
- "positive_pattern": "地址",
+ "pattern_identifier": "ru_address_line_1_label_preserving",
+ "positive_pattern": "улиц.*(дом|корпус|квартир|этаж)|(дом|корпус|квартир|этаж).*улиц",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
+ "match_field_attributes": 1,
"match_field_input_types": 1
- },
+ }
+ ],
+ "zh-CN": [
{
- "pattern_identifier": "zh_address_line_1_label_preserving",
+ "pattern_identifier": "zh_address_line_1_preserving",
"positive_pattern": "地址",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
+ "match_field_attributes": 3,
"match_field_input_types": 1
}
],
"tr": [
{
"pattern_identifier": "tr_address_line_1_preserving",
- "positive_pattern": "(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)",
+ "positive_pattern": "(\\b|_)adres(?! tarifi)(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -383,7 +505,7 @@
},
{
"pattern_identifier": "tr_address_line_1_label_preserving",
- "positive_pattern": "(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)",
+ "positive_pattern": "(\\b|_)adres(?! tarifi)(\\b|_)|(sokak|cadde).*(apartman|bina|daire|mahalle)|(apartman|bina|daire|mahalle).*(sokak|cadde)",
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 1,
@@ -408,6 +530,25 @@
"match_field_attributes": 1,
"match_field_input_types": 1
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_address_line_1_preserving",
+ "positive_pattern": "^alamat",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ,
+ {
+ "pattern_identifier": "id_address_line_1_label_preserving",
+ "positive_pattern": "^alamat",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
]
},
"ADDRESS_LINE_2": {
@@ -515,7 +656,7 @@
"match_field_input_types": 1
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_address_line_2_preserving",
"positive_pattern": "地址2",
@@ -647,7 +788,7 @@
"match_field_input_types": 137
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_country_preserving",
"positive_pattern": "国家",
@@ -686,6 +827,16 @@
"match_field_attributes": 3,
"match_field_input_types": 137
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_country_preserving",
+ "positive_pattern": "negara",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
]
},
"COUNTRY_LOCATION": {
@@ -801,10 +952,20 @@
"match_field_input_types": 69
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_zip_code_preserving",
- "positive_pattern": "邮政编码|邮编|郵遞區號",
+ "positive_pattern": "邮政编码|邮编",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "zh-TW": [
+ {
+ "pattern_identifier": "zh_tw_zip_code_preserving",
+ "positive_pattern": "郵遞區號",
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -830,6 +991,16 @@
"match_field_attributes": 3,
"match_field_input_types": 69
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_zip_code_preserving",
+ "positive_pattern": "kode.?pos",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
]
},
"ZIP_4": {
@@ -854,6 +1025,48 @@
}
]
},
+ "ADDRESS_HOME_DEPENDENT_LOCALITY": {
+ "en": [
+ {
+ "pattern_identifier": "en_dependent_locality_preserving",
+ "positive_pattern": "neighbo(u)?rhood",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_dependent_locality_preserving",
+ "positive_pattern": "bairro",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_dependent_locality_preserving",
+ "positive_pattern": "mahalle|köy",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_dependent_locality_preserving",
+ "positive_pattern": "kecamatan",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
"CITY": {
"en": [
{
@@ -928,14 +1141,14 @@
"ru": [
{
"pattern_identifier": "ru_city_preserving",
- "positive_pattern": "Город|Населённый.?пункт",
+ "positive_pattern": "Город|Насел(е|ё)нный.?пункт",
"positive_score": 1.1,
"negative_pattern": null,
"match_field_attributes": 3,
"match_field_input_types": 137
}
],
- "zh": [
+ "zh-TW": [
{
"pattern_identifier": "zh_city_preserving",
"positive_pattern": "市|分區",
@@ -994,6 +1207,16 @@
"match_field_attributes": 3,
"match_field_input_types": 137
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_city_preserving",
+ "positive_pattern": "kota|kabupaten",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
]
},
"STATE": {
@@ -1037,7 +1260,7 @@
"match_field_input_types": 137
}
],
- "zh": [
+ "zh-TW": [
{
"pattern_identifier": "zh_state_preserving",
"positive_pattern": "省|地區",
@@ -1096,6 +1319,16 @@
"match_field_attributes": 3,
"match_field_input_types": 137
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_state_preserving",
+ "positive_pattern": "provinci",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
]
},
"SEARCH_TERM": {
@@ -1119,7 +1352,7 @@
"match_field_input_types": 145
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_search_term_preserving",
"positive_pattern": "搜索",
@@ -1293,7 +1526,7 @@
"match_field_input_types": 1
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_name_on_card_preserving",
"positive_pattern": "信用卡开户名|开户名|持卡人姓名|持卡人姓名",
@@ -1302,6 +1535,16 @@
"match_field_attributes": 3,
"match_field_input_types": 1
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_name_on_card_preserving",
+ "positive_pattern": "nama.*kartu",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
]
},
"NAME_ON_CARD_CONTEXTUAL": {
@@ -1357,10 +1600,20 @@
"match_field_input_types": 101
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_card_number_preserving",
- "positive_pattern": "信用卡号|信用卡号码|信用卡卡號",
+ "positive_pattern": "信用卡号|信用卡号码",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "zh-TW": [
+ {
+ "pattern_identifier": "zh_card_number_preserving",
+ "positive_pattern": "信用卡卡號",
"positive_score": 1.0,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -1406,6 +1659,16 @@
"match_field_attributes": 3,
"match_field_input_types": 101
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_card_number_preserving",
+ "positive_pattern": "no.*kartu",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
]
},
"CREDIT_CARD_VERIFICATION_CODE": {
@@ -1501,7 +1764,7 @@
"match_field_input_types": 205
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_card_exp_month_preserving",
"positive_pattern": "月",
@@ -1510,6 +1773,16 @@
"match_field_attributes": 3,
"match_field_input_types": 205
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_card_exp_month_preserving",
+ "positive_pattern": "masa berlaku|berlaku hingga",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
]
},
"CREDIT_CARD_EXP_YEAR": {
@@ -1583,7 +1856,7 @@
"match_field_input_types": 205
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_card_exp_year_preserving",
"positive_pattern": "年|有效期",
@@ -1698,6 +1971,16 @@
"match_field_attributes": 3,
"match_field_input_types": 205
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_card_exp_date_preserving",
+ "positive_pattern": "masa berlaku|berlaku hingga",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
]
},
"CREDIT_CARD_EXP_MONTH_BEFORE_YEAR": {
@@ -1816,17 +2099,27 @@
"ru": [
{
"pattern_identifier": "ru_email_preserving",
- "positive_pattern": "Электронной.?Почты",
+ "positive_pattern": "Электронн(ая|ой).?Почт(а|ы)",
"positive_score": 1.4,
"negative_pattern": null,
"match_field_attributes": 3,
"match_field_input_types": 3
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_email_preserving",
- "positive_pattern": "邮件|邮箱|電郵地址",
+ "positive_pattern": "邮件|邮箱",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "zh-TW": [
+ {
+ "pattern_identifier": "zh_email_preserving",
+ "positive_pattern": "電郵地址",
"positive_score": 1.4,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -1892,16 +2185,6 @@
"positive_score": 0.9,
"negative_pattern": null,
"match_field_attributes": 3,
- "match_field_input_types": 137
- }
- ],
- "tr": [
- {
- "pattern_identifier": "tr_name_ignored_preserving",
- "positive_pattern": "adres başlığınız",
- "positive_score": 0.9,
- "negative_pattern": null,
- "match_field_attributes": 3,
"match_field_input_types": 137
}
],
@@ -1915,7 +2198,7 @@
"match_field_input_types": 137
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_name_ignored_preserving",
"positive_pattern": "用户名",
@@ -1940,7 +2223,7 @@
"en": [
{
"pattern_identifier": "en_full_name_preserving",
- "positive_pattern": "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name|name.*first.*last|firstandlastname",
+ "positive_pattern": "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name|name.*first.*last|firstandlastname|contact.?(name|person)",
"positive_score": 0.9,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -1960,7 +2243,7 @@
"fr": [
{
"pattern_identifier": "fr_full_name_preserving",
- "positive_pattern": "^nom(?!bre)",
+ "positive_pattern": "^nom(?![a-zA-Z])",
"positive_score": 0.9,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -1997,7 +2280,7 @@
"match_field_input_types": 1
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_full_name_preserving",
"positive_pattern": "姓名",
@@ -2007,6 +2290,16 @@
"match_field_input_types": 1
}
],
+ "ru": [
+ {
+ "pattern_identifier": "ru_full_name_preserving",
+ "positive_pattern": "контактное.?лицо",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
"tr": [
{
"pattern_identifier": "tr_full_name_preserving",
@@ -2026,6 +2319,16 @@
"match_field_attributes": 3,
"match_field_input_types": 1
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_full_name_preserving",
+ "positive_pattern": "nama.?(lengkap|penerima|kamu)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
]
},
"NAME_SPECIFIC": {
@@ -2180,6 +2483,16 @@
"match_field_attributes": 3,
"match_field_input_types": 1
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_first_name_preserving",
+ "positive_pattern": "nama depan",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
]
},
"MIDDLE_INITIAL": {
@@ -2240,7 +2553,7 @@
"fr": [
{
"pattern_identifier": "fr_last_name_preserving",
- "positive_pattern": "famille|^nom(?!bre)",
+ "positive_pattern": "famille|^nom(?![a-zA-Z])",
"positive_score": 0.9,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -2336,6 +2649,16 @@
"match_field_attributes": 3,
"match_field_input_types": 1
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_last_name_preserving",
+ "positive_pattern": "nama belakang",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
]
},
"LAST_NAME_FIRST": {
@@ -2416,7 +2739,7 @@
"ru": [
{
"pattern_identifier": "ru_honorific_prefix_preserving",
- "positive_pattern": "обраще́ние|зва́ние",
+ "positive_pattern": "обращение|звание",
"positive_score": 0.9,
"negative_pattern": null,
"match_field_attributes": 3,
@@ -2535,7 +2858,7 @@
"match_field_input_types": 69
}
],
- "zh": [
+ "zh-CN": [
{
"pattern_identifier": "zh_phone_preserving",
"positive_pattern": "电话",
@@ -2564,6 +2887,16 @@
"match_field_attributes": 3,
"match_field_input_types": 69
}
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_phone_preserving",
+ "positive_pattern": "telepon|ponsel|(nomor|no\\.?).?(hp|handphone)",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
]
},
"AUGMENTED_PHONE_COUNTRY_CODE": {
diff --git a/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc
deleted file mode 100644
index e6e1a075863..00000000000
--- a/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
-
-#include "base/feature_list.h"
-#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
-#include "components/autofill/core/common/autofill_features.h"
-
-namespace autofill {
-
-TestPatternProvider::TestPatternProvider() {
- // TODO(crbug/1147608) This is an ugly hack to avoid loading the JSON. The
- // motivation is that some Android unit tests fail because a dependency is
- // missing. Instead of fixing this dependency, we'll go for an alternative
- // solution that avoids the whole async/sync problem.
- if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
- base::FeatureList::IsEnabled(
- features::
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
- base::Optional<PatternProvider::Map> patterns =
- field_type_parsing::GetPatternsFromResourceBundleSynchronously();
- if (patterns)
- SetPatterns(patterns.value(), base::Version(), true);
-
- PatternProvider::SetPatternProviderForTesting(this);
- }
-}
-
-TestPatternProvider::~TestPatternProvider() {
- PatternProvider::ResetPatternProvider();
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h
deleted file mode 100644
index dc923237777..00000000000
--- a/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_TEST_PATTERN_PROVIDER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_TEST_PATTERN_PROVIDER_H_
-
-#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
-
-namespace autofill {
-
-// The pattern provider to be used in tests. Loads the MatchingPattern
-// configuration synchronously from the Resource Bundle and sets itself as the
-// global PatternProvider.
-class TestPatternProvider : public PatternProvider {
- public:
- TestPatternProvider();
- ~TestPatternProvider();
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_TEST_PATTERN_PROVIDER_H_
diff --git a/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py b/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py
new file mode 100755
index 00000000000..4bd93d80565
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import io
+import json
+import sys
+
+def to_string_literal(json_string_literal):
+ return json.dumps(json_string_literal)
+
+def build_cpp_map_population(input):
+ lines = []
+ def output(line):
+ lines.append(line)
+
+ output('JsonPattern patterns[] = {')
+ for key1 in input:
+ for key2 in input[key1]:
+ for pattern in input[key1][key2]:
+ name = to_string_literal(key1)
+ language = to_string_literal(key2)
+ positive_pattern = pattern['positive_pattern']
+ negative_pattern = pattern['negative_pattern']
+ positive_score = pattern['positive_score']
+ match_field_attributes = pattern['match_field_attributes']
+ match_field_input_types = pattern['match_field_input_types']
+
+ positive_pattern = to_string_literal(positive_pattern)
+
+ if negative_pattern is None:
+ negative_pattern = 'nullptr';
+ else:
+ negative_pattern = to_string_literal(negative_pattern)
+
+ # Shift to the right to match the MatchFieldTypes enum, which
+ # temporarily starts at 1<<2 instead of 1<<0.
+ match_field_input_types = '{} << 2'.format(match_field_input_types)
+
+ output('{')
+ output('.name = {},'.format(name))
+ output('.language = {},'.format(language))
+ output('.positive_pattern = {},'.format(positive_pattern))
+ output('.negative_pattern = {},'.format(negative_pattern))
+ output('.positive_score = {},'.format(positive_score))
+ output('.match_field_attributes = {},'.format(match_field_attributes))
+ output('.match_field_input_types = {},'.format(match_field_input_types))
+ output('},')
+
+ output('};')
+
+ return lines
+
+
+def build_cpp_function(cpp, output_handle):
+ def output(s):
+ # unicode() exists and is necessary only in Python 2, not in Python 3.
+ if sys.version_info[0] < 3:
+ s = unicode(s, 'utf-8')
+ output_handle.write(s)
+
+ output('// Copyright 2020 The Chromium Authors. All rights reserved.\n')
+ output('// Use of this source code is governed by a BSD-style license ')
+ output('that can be\n')
+ output('// found in the LICENSE file.\n')
+ output('\n')
+ output('#include "components/autofill/core/browser/pattern_provider/'\
+ 'default_regex_patterns.h"\n')
+ output('#include "components/autofill/core/common/language_code.h"\n')
+ output('\n')
+ output('namespace autofill {\n')
+ output('\n')
+ output('PatternProvider::Map CreateDefaultRegexPatterns() {\n')
+ output(' struct JsonPattern {\n')
+ output(' const char* name;\n')
+ output(' const char* language;\n')
+ output(' const char* positive_pattern;\n')
+ output(' const char* negative_pattern;\n')
+ output(' float positive_score;\n')
+ output(' uint8_t match_field_attributes;\n')
+ output(' uint16_t match_field_input_types;\n')
+ output(' };\n')
+ output('\n')
+ for line in build_cpp_map_population(cpp):
+ output(line)
+ output('\n')
+ output(' PatternProvider::Map map;\n')
+ output(' size_t len = sizeof(patterns) / sizeof(patterns[0]);\n')
+ output(' for (size_t i = 0; i < len; ++i) {\n')
+ output(' const JsonPattern& p = patterns[i];\n')
+ output(' MatchingPattern mp;\n')
+ output(' mp.language = LanguageCode(p.language);\n')
+ output(' mp.positive_pattern = p.positive_pattern;\n')
+ output(' mp.negative_pattern = '
+ 'p.negative_pattern ? p.negative_pattern : "";\n')
+ output(' mp.positive_score = p.positive_score;\n')
+ output(' mp.match_field_input_types = p.match_field_input_types;\n')
+ output(' mp.match_field_attributes = p.match_field_attributes;\n')
+ output(' map[p.name][LanguageCode(p.language)].push_back(mp);\n')
+ output(' }\n')
+ output(' return map;\n')
+ output('}\n')
+ output('\n')
+ output('}')
+
+if __name__ == '__main__':
+ input_file = sys.argv[1]
+ output_file = sys.argv[2]
+ with io.open(input_file, 'r', encoding='utf-8') as input_handle:
+ input_json = json.load(input_handle)
+ with io.open(output_file, 'w', encoding='utf-8') as output_handle:
+ build_cpp_function(input_json, output_handle)
diff --git a/chromium/components/autofill/core/browser/payments/OWNERS b/chromium/components/autofill/core/browser/payments/OWNERS
index c3fbe351b77..8b40deb104f 100644
--- a/chromium/components/autofill/core/browser/payments/OWNERS
+++ b/chromium/components/autofill/core/browser/payments/OWNERS
@@ -1 +1,2 @@
jsaul@google.com
+siyua@chromium.org
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
index 0dbee443856..7784a1e9241 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -14,8 +14,10 @@
#include "base/timer/timer.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
@@ -66,6 +68,60 @@ void AutofillOfferManager::UpdateSuggestionsWithOffers(
l10n_util::GetStringUTF16(IDS_AUTOFILL_OFFERS_CASHBACK);
}
}
+ // Sort the suggestions such that suggestions with offers are shown at the
+ // top.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSortSuggestionsBasedOnOfferPresence)) {
+ std::sort(suggestions.begin(), suggestions.end(),
+ [](const Suggestion& a, const Suggestion& b) {
+ if (!a.offer_label.empty() && b.offer_label.empty()) {
+ return true;
+ }
+ return false;
+ });
+ }
+}
+
+bool AutofillOfferManager::IsUrlEligible(const GURL& last_committed_url) {
+ GURL last_committed_url_origin = last_committed_url.GetOrigin();
+ return base::ranges::count(eligible_merchant_domains_,
+ last_committed_url_origin);
+}
+
+std::tuple<std::vector<GURL>, GURL, CreditCard*>
+AutofillOfferManager::GetEligibleDomainsAndCardForOfferForUrl(
+ const GURL& last_committed_url) {
+ std::vector<GURL> linked_domains;
+ std::vector<AutofillOfferData*> offers =
+ personal_data_->GetCreditCardOffers();
+ CreditCard* card = nullptr;
+ // Initialize to an empty url.
+ GURL offer_details_url = GURL();
+
+ // Check which offer is eligible on current domain, then return the full set
+ // of domains for that offer.
+ for (auto* offer : offers) {
+ if (IsOfferEligible(*offer, last_committed_url.GetOrigin())) {
+ for (auto& domain : offer->merchant_domain) {
+ linked_domains.emplace_back(domain);
+ }
+ // Pick first card in the vector. The UI shows only one card's
+ // information.
+ card = offer->eligible_instrument_id.empty()
+ ? nullptr
+ : personal_data_->GetCreditCardByInstrumentId(
+ offer->eligible_instrument_id[0]);
+ offer_details_url = GURL(offer->offer_details_url);
+ break;
+ }
+ }
+
+ // Remove duplicates in domains.
+ base::ranges::sort(linked_domains);
+ linked_domains.erase(base::ranges::unique(linked_domains),
+ linked_domains.end());
+
+ return std::make_tuple(linked_domains, offer_details_url, card);
}
void AutofillOfferManager::UpdateEligibleMerchantDomains() {
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
index df9fceef080..dab84da0594 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <map>
#include <string>
+#include <tuple>
#include <vector>
#include "base/strings/string16.h"
@@ -22,6 +23,8 @@
namespace autofill {
+class CreditCard;
+
// Manages all Autofill related offers. One per frame; owned by the
// AutofillManager.
class AutofillOfferManager : public KeyedService,
@@ -42,7 +45,19 @@ class AutofillOfferManager : public KeyedService,
void UpdateSuggestionsWithOffers(const GURL& last_committed_url,
std::vector<Suggestion>& suggestions);
+ // Returns true only if the domain of |last_committed_url| has an offer.
+ bool IsUrlEligible(const GURL& last_committed_url);
+
+ // Returns the set of domains and the card linked to a specific offer that
+ // contains the domain of |last_committed_url|. Also return the
+ // offer_details_url which redirects to a GPay surface with more details about
+ // the offer.
+ std::tuple<std::vector<GURL>, GURL, CreditCard*>
+ GetEligibleDomainsAndCardForOfferForUrl(const GURL& last_committed_url);
+
private:
+ FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest, IsUrlEligible);
+
// Queries |personal_data_| to reset the elements of
// |eligible_merchant_domains_|
void UpdateEligibleMerchantDomains();
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
index 85f7277904a..24bac17c4c1 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
@@ -3,9 +3,11 @@
// found in the LICENSE file.
#include <memory>
+#include <tuple>
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
@@ -14,6 +16,7 @@
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/strings/grit/components_strings.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,10 +27,12 @@ namespace autofill {
namespace {
const char kTestGuid[] = "00000000-0000-0000-0000-000000000001";
+const char kTestGuid2[] = "00000000-0000-0000-0000-000000000002";
const char kTestNumber[] = "4234567890123456"; // Visa
const char kTestUrl[] = "http://www.example.com/";
const char kTestUrlWithParam[] =
"http://www.example.com/en/payments?name=checkout";
+const char kOfferDetailsUrl[] = "http://pay.google.com";
} // namespace
@@ -41,6 +46,7 @@ class AutofillOfferManagerTest : public testing::Test {
personal_data_manager_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -51,21 +57,25 @@ class AutofillOfferManagerTest : public testing::Test {
}
CreditCard CreateCreditCard(std::string guid,
- std::string number = kTestNumber) {
+ std::string number = kTestNumber,
+ int64_t instrument_id = 0) {
CreditCard card = CreditCard();
test::SetCreditCardInfo(&card, "Jane Doe", number.c_str(),
test::NextMonth().c_str(), test::NextYear().c_str(),
"1");
card.set_guid(guid);
+ card.set_instrument_id(instrument_id);
card.set_record_type(CreditCard::MASKED_SERVER_CARD);
personal_data_manager_.AddServerCreditCard(card);
return card;
}
- void CreateCreditCardOfferForCard(const CreditCard& card,
- std::string offer_reward_amount,
- bool expired = false) {
+ AutofillOfferData CreateCreditCardOfferForCard(
+ const CreditCard& card,
+ std::string offer_reward_amount,
+ bool expired = false,
+ std::vector<GURL> domains = {GURL(kTestUrl)}) {
AutofillOfferData offer_data;
offer_data.offer_id = 4444;
offer_data.offer_reward_amount = offer_reward_amount;
@@ -74,9 +84,10 @@ class AutofillOfferManagerTest : public testing::Test {
} else {
offer_data.expiry = AutofillClock::Now() + base::TimeDelta::FromDays(2);
}
- offer_data.merchant_domain = {GURL(kTestUrl)};
+ offer_data.merchant_domain = std::move(domains);
offer_data.eligible_instrument_id = {card.instrument_id()};
- personal_data_manager_.AddCreditCardOfferData(offer_data);
+ offer_data.offer_details_url = GURL(kOfferDetailsUrl);
+ return offer_data;
}
protected:
@@ -86,11 +97,13 @@ class AutofillOfferManagerTest : public testing::Test {
scoped_refptr<AutofillWebDataService> database_;
TestPersonalDataManager personal_data_manager_;
std::unique_ptr<AutofillOfferManager> autofill_offer_manager_ = nullptr;
+ base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_EligibleCashback) {
CreditCard card = CreateCreditCard(kTestGuid);
- CreateCreditCardOfferForCard(card, "5%");
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(card, "5%"));
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
@@ -103,7 +116,8 @@ TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_EligibleCashback) {
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_ExpiredOffer) {
CreditCard card = CreateCreditCard(kTestGuid);
- CreateCreditCardOfferForCard(card, "5%", /*expired=*/true);
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(card, "5%", /*expired=*/true));
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
@@ -115,7 +129,8 @@ TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_ExpiredOffer) {
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_WrongUrl) {
CreditCard card = CreateCreditCard(kTestGuid);
- CreateCreditCardOfferForCard(card, "5%");
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(card, "5%"));
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
@@ -125,4 +140,150 @@ TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_WrongUrl) {
EXPECT_TRUE(suggestions[0].offer_label.empty());
}
+TEST_F(AutofillOfferManagerTest,
+ UpdateSuggestionsWithOffer_SuggestionsSortedByOfferPresence) {
+ CreditCard cardWithoutOffer = CreateCreditCard(kTestGuid);
+ CreditCard cardWithOffer =
+ CreateCreditCard(kTestGuid2, "4111111111111111", 100);
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(cardWithOffer, "5%"));
+
+ std::vector<Suggestion> suggestions = {Suggestion(), Suggestion()};
+ suggestions[0].backend_id = kTestGuid;
+ suggestions[1].backend_id = kTestGuid2;
+ autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrlWithParam),
+ suggestions);
+
+ // offer_label was set on suggestions[1] but then was sorted to become
+ // suggestion[0]
+ EXPECT_TRUE(!suggestions[0].offer_label.empty());
+ EXPECT_TRUE(suggestions[1].offer_label.empty());
+ EXPECT_EQ(suggestions[0].backend_id, kTestGuid2);
+ EXPECT_EQ(suggestions[1].backend_id, kTestGuid);
+}
+
+TEST_F(AutofillOfferManagerTest,
+ UpdateSuggestionsWithOffer_SuggestionsNotSortedByOfferPresence_ExpOff) {
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillSortSuggestionsBasedOnOfferPresence);
+ CreditCard cardWithoutOffer = CreateCreditCard(kTestGuid);
+ CreditCard cardWithOffer =
+ CreateCreditCard(kTestGuid2, "4111111111111111", 100);
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(cardWithOffer, "5%"));
+
+ std::vector<Suggestion> suggestions = {Suggestion(), Suggestion()};
+ suggestions[0].backend_id = kTestGuid;
+ suggestions[1].backend_id = kTestGuid2;
+ autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrlWithParam),
+ suggestions);
+
+ // offer_label was set on suggestions[1] and wasn't sorted because experiment
+ // is turned off.
+ EXPECT_TRUE(suggestions[0].offer_label.empty());
+ EXPECT_TRUE(!suggestions[1].offer_label.empty());
+ EXPECT_EQ(suggestions[0].backend_id, kTestGuid);
+ EXPECT_EQ(suggestions[1].backend_id, kTestGuid2);
+}
+
+TEST_F(AutofillOfferManagerTest,
+ UpdateSuggestionsWithOffer_SuggestionsNotSortedIfAllCardsHaveOffers) {
+ CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100);
+ CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101);
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(card1, "5%"));
+ personal_data_manager_.AddCreditCardOfferData(
+ CreateCreditCardOfferForCard(card2, "5%"));
+
+ std::vector<Suggestion> suggestions = {Suggestion(), Suggestion()};
+ suggestions[0].backend_id = kTestGuid;
+ suggestions[1].backend_id = kTestGuid2;
+ autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrlWithParam),
+ suggestions);
+
+ EXPECT_EQ(suggestions[0].backend_id, kTestGuid);
+ EXPECT_EQ(suggestions[1].backend_id, kTestGuid2);
+}
+
+TEST_F(AutofillOfferManagerTest, IsUrlEligible) {
+ CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100);
+ CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101);
+ personal_data_manager_.AddCreditCardOfferData(CreateCreditCardOfferForCard(
+ card1, "5%", /*expired=*/false,
+ {GURL("http://www.google.com"), GURL("http://www.youtube.com")}));
+ personal_data_manager_.AddCreditCardOfferData(CreateCreditCardOfferForCard(
+ card2, "10%", /*expired=*/false, {GURL("http://maps.google.com")}));
+ autofill_offer_manager_->UpdateEligibleMerchantDomains();
+
+ EXPECT_TRUE(
+ autofill_offer_manager_->IsUrlEligible(GURL("http://www.google.com")));
+ EXPECT_FALSE(
+ autofill_offer_manager_->IsUrlEligible(GURL("http://www.example.com")));
+ EXPECT_TRUE(
+ autofill_offer_manager_->IsUrlEligible(GURL("http://maps.google.com")));
+}
+
+TEST_F(AutofillOfferManagerTest,
+ GetEligibleDomainsAndCardForOfferForUrl_ReturnNothingWhenFindNoMatch) {
+ CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100);
+ personal_data_manager_.AddCreditCardOfferData(CreateCreditCardOfferForCard(
+ card1, "5%", /*expired=*/false,
+ {GURL("http://www.google.com"), GURL("http://www.youtube.com")}));
+
+ auto result =
+ autofill_offer_manager_->GetEligibleDomainsAndCardForOfferForUrl(
+ GURL("http://www.example.com"));
+ EXPECT_EQ(0U, std::get<0>(result).size());
+ EXPECT_EQ(GURL(), std::get<1>(result));
+ EXPECT_EQ(nullptr, std::get<2>(result));
+}
+
+TEST_F(AutofillOfferManagerTest,
+ GetEligibleDomainsAndCardForOfferForUrl_ReturnCorrectSetWhenFindMatch) {
+ CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100);
+ CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101);
+
+ personal_data_manager_.AddCreditCardOfferData(CreateCreditCardOfferForCard(
+ card1, "5%", /*expired=*/false,
+ /*domains=*/
+ {GURL("http://www.google.com"), GURL("http://www.youtube.com")}));
+ personal_data_manager_.AddCreditCardOfferData(CreateCreditCardOfferForCard(
+ card2, "5%", /*expired=*/false,
+ /*domains=*/
+ {GURL("http://www.example.com"), GURL("http://www.example2.com")}));
+
+ auto result =
+ autofill_offer_manager_->GetEligibleDomainsAndCardForOfferForUrl(
+ GURL("http://www.example.com"));
+ std::vector<GURL> eligible_domain = std::get<0>(result);
+ EXPECT_EQ(2U, eligible_domain.size());
+ EXPECT_NE(eligible_domain.end(),
+ std::find(eligible_domain.begin(), eligible_domain.end(),
+ GURL("http://www.example.com")));
+ EXPECT_NE(eligible_domain.end(),
+ std::find(eligible_domain.begin(), eligible_domain.end(),
+ GURL("http://www.example2.com")));
+ EXPECT_EQ(GURL(kOfferDetailsUrl), std::get<1>(result));
+ EXPECT_EQ(101, std::get<2>(result)->instrument_id());
+}
+
+TEST_F(
+ AutofillOfferManagerTest,
+ GetEligibleDomainsAndCardForOfferForUrl_ReturnNoCardWhenFindNoMatchedCardData) {
+ CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100);
+ AutofillOfferData offer_data1 = CreateCreditCardOfferForCard(
+ card1, "5%", /*expired=*/false,
+ {GURL("http://www.google.com"), GURL("http://www.youtube.com")});
+ offer_data1.eligible_instrument_id.clear();
+ personal_data_manager_.AddCreditCardOfferData(offer_data1);
+
+ auto result =
+ autofill_offer_manager_->GetEligibleDomainsAndCardForOfferForUrl(
+ GURL("http://www.google.com"));
+ EXPECT_EQ(2U, std::get<0>(result).size());
+ EXPECT_EQ(GURL(kOfferDetailsUrl), std::get<1>(result));
+ EXPECT_EQ(nullptr, std::get<2>(result));
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
new file mode 100644
index 00000000000..b1d73910379
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
@@ -0,0 +1,103 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h"
+
+#include <utility>
+
+#include "base/check_op.h"
+#include "base/notreached.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/branding_buildflags.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/grit/components_scaled_resources.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "components/infobars/core/infobar_manager.h"
+#include "components/prefs/pref_service.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+AutofillOfferNotificationInfoBarDelegateMobile::
+ AutofillOfferNotificationInfoBarDelegateMobile(
+ const GURL& offer_details_url,
+ const CreditCard& card)
+ : credit_card_identifier_string_(
+ card.CardIdentifierStringForAutofillDisplay()),
+ network_icon_id_(CreditCard::IconResourceId(card.network())),
+ deep_link_url_(offer_details_url),
+ user_manually_closed_infobar_(false) {
+ AutofillMetrics::LogOfferNotificationInfoBarShown();
+}
+
+AutofillOfferNotificationInfoBarDelegateMobile::
+ ~AutofillOfferNotificationInfoBarDelegateMobile() {
+ if (!user_manually_closed_infobar_) {
+ AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
+ AutofillMetrics::OfferNotificationInfoBarResultMetric::
+ OFFER_NOTIFICATION_INFOBAR_IGNORED);
+ }
+}
+
+void AutofillOfferNotificationInfoBarDelegateMobile::OnOfferDeepLinkClicked(
+ GURL url) {
+ AutofillMetrics::LogOfferNotificationInfoBarDeepLinkClicked();
+ infobar()->owner()->OpenURL(url, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+}
+
+int AutofillOfferNotificationInfoBarDelegateMobile::GetIconId() const {
+ return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER;
+}
+
+base::string16 AutofillOfferNotificationInfoBarDelegateMobile::GetMessageText()
+ const {
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_OFFERS_REMINDER_TITLE);
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutofillOfferNotificationInfoBarDelegateMobile::GetIdentifier() const {
+ return AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE;
+}
+
+int AutofillOfferNotificationInfoBarDelegateMobile::GetButtons() const {
+ return BUTTON_OK;
+}
+
+base::string16 AutofillOfferNotificationInfoBarDelegateMobile::GetButtonLabel(
+ InfoBarButton button) const {
+ if (button == BUTTON_OK) {
+ return l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_OFFERS_REMINDER_POSITIVE_BUTTON_LABEL);
+ }
+
+ NOTREACHED() << "Unsupported button label requested: " << button;
+ return base::string16();
+}
+
+void AutofillOfferNotificationInfoBarDelegateMobile::InfoBarDismissed() {
+ AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
+ AutofillMetrics::OfferNotificationInfoBarResultMetric::
+ OFFER_NOTIFICATION_INFOBAR_CLOSED);
+ user_manually_closed_infobar_ = true;
+}
+
+bool AutofillOfferNotificationInfoBarDelegateMobile::Accept() {
+ AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
+ AutofillMetrics::OfferNotificationInfoBarResultMetric::
+ OFFER_NOTIFICATION_INFOBAR_ACKNOWLEDGED);
+ user_manually_closed_infobar_ = true;
+ return true;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h
new file mode 100644
index 00000000000..a4a0e967d9a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h
@@ -0,0 +1,70 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE_MOBILE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE_MOBILE_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/payments/legal_message_line.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+namespace autofill {
+
+class CreditCard;
+
+// An InfoBarDelegate that provides the information required to display an
+// InfoBar when an offer is available on the merchant website.
+class AutofillOfferNotificationInfoBarDelegateMobile
+ : public ConfirmInfoBarDelegate {
+ public:
+ AutofillOfferNotificationInfoBarDelegateMobile(const GURL& offer_details_url,
+ const CreditCard& card);
+
+ ~AutofillOfferNotificationInfoBarDelegateMobile() override;
+
+ AutofillOfferNotificationInfoBarDelegateMobile(
+ const AutofillOfferNotificationInfoBarDelegateMobile&) = delete;
+ AutofillOfferNotificationInfoBarDelegateMobile& operator=(
+ const AutofillOfferNotificationInfoBarDelegateMobile&) = delete;
+
+ const base::string16& credit_card_identifier_string() const {
+ return credit_card_identifier_string_;
+ }
+ int network_icon_id() { return network_icon_id_; }
+ const GURL& deep_link_url() const { return deep_link_url_; }
+
+ // Called when the offer details deep link was clicked.
+ virtual void OnOfferDeepLinkClicked(GURL url);
+
+ // ConfirmInfoBarDelegate:
+ int GetIconId() const override;
+ base::string16 GetMessageText() const override;
+ infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+ int GetButtons() const override;
+ base::string16 GetButtonLabel(InfoBarButton button) const override;
+ void InfoBarDismissed() override;
+ bool Accept() override;
+
+ private:
+ // Identifier for the credit card associated with the offer.
+ base::string16 credit_card_identifier_string_;
+ // Resource id for the icon representing the network of the credit card.
+ int network_icon_id_;
+ // URL that links to the offer details page in the Google Pay app.
+ GURL deep_link_url_;
+ // Indicates whether the user manually closed the infobar by clicking on the X
+ // icon or the Got it button.
+ bool user_manually_closed_infobar_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE_MOBILE_H_
diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
index 25ea9af5ec7..0ca6a1d2065 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
@@ -13,7 +13,6 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/prefs/pref_service.h"
-#include "components/sync/driver/sync_auth_util.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
@@ -34,8 +33,6 @@ AutofillWalletModelTypeController::AutofillWalletModelTypeController(
type == syncer::AUTOFILL_WALLET_METADATA ||
type == syncer::AUTOFILL_WALLET_OFFER);
SubscribeToPrefChanges();
- // TODO(crbug.com/906995): remove this observing mechanism once all sync
- // datatypes are stopped by ProfileSyncService, when sync is paused.
sync_service_->AddObserver(this);
}
@@ -56,8 +53,6 @@ AutofillWalletModelTypeController::AutofillWalletModelTypeController(
type == syncer::AUTOFILL_WALLET_METADATA ||
type == syncer::AUTOFILL_WALLET_OFFER);
SubscribeToPrefChanges();
- // TODO(crbug.com/906995): remove this observing mechanism once all sync
- // datatypes are stopped by ProfileSyncService, when sync is paused.
sync_service_->AddObserver(this);
}
@@ -85,10 +80,6 @@ void AutofillWalletModelTypeController::Stop(
syncer::DataTypeController::PreconditionState
AutofillWalletModelTypeController::GetPreconditionState() const {
DCHECK(CalledOnValidThread());
- // Not being in a persistent error state implies not being in a web signout
- // state.
- // TODO(https://crbug.com/819729): Add integration tests for web signout and
- // other persistent auth errors.
bool preconditions_met =
pref_service_->GetBoolean(
autofill::prefs::kAutofillWalletImportEnabled) &&
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
index 9b38d40a594..560f30b57c8 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -30,7 +30,6 @@
#include "components/autofill/core/browser/payments/webauthn_callback_types.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -260,18 +259,16 @@ void CreditCardAccessManager::FetchCreditCard(
return;
}
- if (base::FeatureList::IsEnabled(features::kAutofillCacheServerCardInfo)) {
- // If card has been previously unmasked, use cached data.
- std::unordered_map<std::string, CachedServerCardInfo>::iterator it =
- unmasked_card_cache_.find(card->server_id());
- if (it != unmasked_card_cache_.end()) { // key is in cache
- accessor->OnCreditCardFetched(/*did_succeed=*/true,
- /*CreditCard=*/&it->second.card,
- /*cvc=*/it->second.cvc);
- base::UmaHistogramCounts1000("Autofill.UsedCachedServerCard",
- ++it->second.cache_uses);
- return;
- }
+ // If card has been previously unmasked, use cached data.
+ std::unordered_map<std::string, CachedServerCardInfo>::iterator it =
+ unmasked_card_cache_.find(card->server_id());
+ if (it != unmasked_card_cache_.end()) { // key is in cache
+ accessor->OnCreditCardFetched(/*did_succeed=*/true,
+ /*credit_card=*/&it->second.card,
+ /*cvc=*/it->second.cvc);
+ base::UmaHistogramCounts1000("Autofill.UsedCachedServerCard",
+ ++it->second.cache_uses);
+ return;
}
// Latency metrics should only be logged if the user is verifiable and the
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index 68b1b1ccf5a..faa396e337d 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -147,6 +147,7 @@ class CreditCardAccessManagerTest : public testing::Test {
personal_data_manager_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -1838,8 +1839,6 @@ TEST_F(CreditCardAccessManagerTest, AuthenticationInProgress) {
// Ensures that the use of |unmasked_card_cache_| is set and logged correctly.
TEST_F(CreditCardAccessManagerTest, FetchCreditCardUsesUnmaskedCardCache) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillCacheServerCardInfo);
base::HistogramTester histogram_tester;
CreateServerCard(kTestGUID, kTestNumber, /*masked=*/false);
CreditCard* unmasked_card =
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
index c5ce8b4d8ba..1f3916fe2e6 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
@@ -4,6 +4,8 @@
#include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
+#include <memory>
+
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
@@ -28,11 +30,13 @@ void CreditCardCVCAuthenticator::Authenticate(
PersonalDataManager* personal_data_manager,
const base::TimeTicks& form_parsed_timestamp) {
requester_ = requester;
- if (!card)
- return OnFullCardRequestFailed();
- full_card_request_.reset(new payments::FullCardRequest(
+ if (!card) {
+ return OnFullCardRequestFailed(
+ payments::FullCardRequest::FailureType::GENERIC_FAILURE);
+ }
+ full_card_request_ = std::make_unique<payments::FullCardRequest>(
client_, client_->GetPaymentsClient(), personal_data_manager,
- form_parsed_timestamp));
+ form_parsed_timestamp);
full_card_request_->GetFullCard(*card, AutofillClient::UNMASK_FOR_AUTOFILL,
weak_ptr_factory_.GetWeakPtr(),
weak_ptr_factory_.GetWeakPtr());
@@ -54,7 +58,8 @@ void CreditCardCVCAuthenticator::OnFullCardRequestSucceeded(
.with_card_authorization_token(response.card_authorization_token));
}
-void CreditCardCVCAuthenticator::OnFullCardRequestFailed() {
+void CreditCardCVCAuthenticator::OnFullCardRequestFailed(
+ payments::FullCardRequest::FailureType failure_type) {
requester_->OnCVCAuthenticationComplete(
CVCAuthenticationResponse().with_did_succeed(false));
}
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
index fee486eb2fe..20fe78c46e8 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
@@ -95,7 +95,8 @@ class CreditCardCVCAuthenticator
const payments::FullCardRequest& full_card_request,
const CreditCard& card,
const base::string16& cvc) override;
- void OnFullCardRequestFailed() override;
+ void OnFullCardRequestFailed(
+ payments::FullCardRequest::FailureType failure_type) override;
// payments::FullCardRequest::UIDelegate
void ShowUnmaskPrompt(const CreditCard& card,
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
index 41b50dbab78..8430cb6dbb1 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
@@ -85,6 +85,7 @@ class CreditCardCVCAuthenticatorTest : public testing::Test {
personal_data_manager_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index d7b17fdd33d..51882104cf3 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -520,7 +520,8 @@ void CreditCardFIDOAuthenticator::OnFullCardRequestSucceeded(
requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/true, &card, cvc);
}
-void CreditCardFIDOAuthenticator::OnFullCardRequestFailed() {
+void CreditCardFIDOAuthenticator::OnFullCardRequestFailed(
+ payments::FullCardRequest::FailureType failure_type) {
DCHECK_EQ(AUTHENTICATION_FLOW, current_flow_);
current_flow_ = NONE_FLOW;
requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false);
@@ -573,10 +574,13 @@ CreditCardFIDOAuthenticator::ParseCreationOptions(
options->relying_party.icon_url = GURL(*icon_url);
const std::string gaia =
- autofill_client_->GetIdentityManager()->GetPrimaryAccountInfo().gaia;
+ autofill_client_->GetIdentityManager()
+ ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
+ .gaia;
options->user.id = std::vector<uint8_t>(gaia.begin(), gaia.end());
- options->user.name =
- autofill_client_->GetIdentityManager()->GetPrimaryAccountInfo().email;
+ options->user.name = autofill_client_->GetIdentityManager()
+ ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
+ .email;
base::Optional<AccountInfo> account_info =
autofill_client_->GetIdentityManager()
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
index 93b11355f9a..c857d8481c6 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
@@ -194,7 +194,8 @@ class CreditCardFIDOAuthenticator
const payments::FullCardRequest& full_card_request,
const CreditCard& card,
const base::string16& cvc) override;
- void OnFullCardRequestFailed() override;
+ void OnFullCardRequestFailed(
+ payments::FullCardRequest::FailureType failure_type) override;
// Converts |request_options| from JSON to mojom pointer.
PublicKeyCredentialRequestOptionsPtr ParseRequestOptions(
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
index effc89380ae..a8180c90fcb 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
@@ -114,6 +114,7 @@ class CreditCardFIDOAuthenticatorTest : public testing::Test {
personal_data_manager_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
index 2addf2ad08f..dbd58bb9209 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -43,7 +43,6 @@
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_util.h"
-#include "components/infobars/core/infobar_feature.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "url/gurl.h"
@@ -216,9 +215,8 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card. Calling LogSaveCardRequestExpirationDateReasonMetric
// would trigger a DCHECK.
- if (!(base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
// Remove once both flags are deleted.
LogSaveCardRequestExpirationDateReasonMetric();
}
@@ -229,9 +227,8 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
}
#if defined(OS_IOS)
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
// iOS's new credit card save dialog requires the user to enter both
// cardholder name and expiration date before saving. Regardless of what
// Chrome thought it needed to do before, disable both of the previous
@@ -776,9 +773,8 @@ int CreditCardSaveManager::GetDetectedValues() const {
// card unless the user provides both a valid cardholder name and expiration
// date.
#if defined(OS_IOS)
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
detected_values |= DetectedValue::USER_PROVIDED_NAME;
detected_values |= DetectedValue::USER_PROVIDED_EXPIRATION_DATE;
}
@@ -852,9 +848,8 @@ void CreditCardSaveManager::OnUserDidAcceptUploadHelper(
// the user, but not through the fix flow triggered via
// |should_request_name_from_user_|.
DCHECK(should_request_name_from_user_ ||
- (base::FeatureList::IsEnabled(
- autofill::features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot)));
+ base::FeatureList::IsEnabled(
+ autofill::features::kAutofillSaveCardInfobarEditSupport));
#else
DCHECK(should_request_name_from_user_);
#endif
@@ -873,9 +868,8 @@ void CreditCardSaveManager::OnUserDidAcceptUploadHelper(
// the user, but not through the fix flow triggered via
// |should_request_expiration_date_from_user_|.
DCHECK(should_request_expiration_date_from_user_ ||
- (base::FeatureList::IsEnabled(
- autofill::features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot)));
+ base::FeatureList::IsEnabled(
+ autofill::features::kAutofillSaveCardInfobarEditSupport));
#else
DCHECK(should_request_expiration_date_from_user_);
#endif
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index 1868db7fc2b..50fce2c7cf0 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -31,7 +31,6 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
@@ -51,7 +50,6 @@
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "components/infobars/core/infobar_feature.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/ukm/test_ukm_recorder.h"
@@ -132,6 +130,7 @@ class CreditCardSaveManagerTest : public testing::Test {
personal_data_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
+ /*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
@@ -175,7 +174,7 @@ class CreditCardSaveManagerTest : public testing::Test {
}
void FormsSeen(const std::vector<FormData>& forms) {
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
}
void FormSubmitted(const FormData& form) {
@@ -349,8 +348,6 @@ class CreditCardSaveManagerTest : public testing::Test {
MockPersonalDataManager personal_data_;
MockAutocompleteHistoryManager autocomplete_history_manager_;
syncer::TestSyncService sync_service_;
- base::test::ScopedFeatureList scoped_feature_list_;
- TestPatternProvider test_pattern_provider_;
// Ends up getting owned (and destroyed) by TestFormDataImporter:
TestCreditCardSaveManager* credit_card_save_manager_;
// Ends up getting owned (and destroyed) by TestAutofillClient:
@@ -517,7 +514,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) {
EXPECT_EQ(1U, personal_data_.GetProfiles().size());
AutofillProfile only_country;
only_country.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"), "en-US");
- only_country.FinalizeAfterImport();
EXPECT_EQ(1U, payments_client_->addresses_in_upload_details().size());
// AutofillProfile::Compare will ignore the difference in guid between our
// actual profile being sent and the expected one constructed here.
@@ -2961,9 +2957,8 @@ TEST_F(CreditCardSaveManagerTest,
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
return;
}
#endif
@@ -3013,9 +3008,8 @@ TEST_F(CreditCardSaveManagerTest,
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
return;
}
#endif
@@ -3065,9 +3059,8 @@ TEST_F(CreditCardSaveManagerTest,
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
return;
}
#endif
@@ -3117,9 +3110,8 @@ TEST_F(CreditCardSaveManagerTest,
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
return;
}
#endif
@@ -3170,9 +3162,8 @@ TEST_F(
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
- if ((base::FeatureList::IsEnabled(
- features::kAutofillSaveCardInfobarEditSupport) &&
- base::FeatureList::IsEnabled(kIOSInfobarUIReboot))) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSaveCardInfobarEditSupport)) {
return;
}
#endif
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc
index cc7f49a34f1..438e7e594f3 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc
@@ -24,7 +24,7 @@ int CreditCardSaveStrikeDatabase::GetMaxStrikesLimit() {
return 3;
}
-int64_t CreditCardSaveStrikeDatabase::GetExpiryTimeMicros() {
+base::Optional<int64_t> CreditCardSaveStrikeDatabase::GetExpiryTimeMicros() {
// Expiry time is 6 months.
return (int64_t)1000000 * 60 * 60 * 24 * 180;
}
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h
index 6e0a86536b1..6ce21bee328 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h
@@ -22,7 +22,7 @@ class CreditCardSaveStrikeDatabase : public StrikeDatabaseIntegratorBase {
std::string GetProjectPrefix() override;
int GetMaxStrikesLimit() override;
- int64_t GetExpiryTimeMicros() override;
+ base::Optional<int64_t> GetExpiryTimeMicros() override;
bool UniqueIdsRequired() override;
};
diff --git a/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc
index 33e4db3a8b2..08926ea170e 100644
--- a/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc
+++ b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc
@@ -30,7 +30,8 @@ int FidoAuthenticationStrikeDatabase::GetMaxStrikesLimit() {
return 3;
}
-int64_t FidoAuthenticationStrikeDatabase::GetExpiryTimeMicros() {
+base::Optional<int64_t>
+FidoAuthenticationStrikeDatabase::GetExpiryTimeMicros() {
// Expiry time is six months.
return (int64_t)1000000 * 60 * 60 * 24 * 30 * 6;
}
diff --git a/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h
index 343c5d576d2..5ee994ea02e 100644
--- a/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h
+++ b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h
@@ -30,7 +30,7 @@ class FidoAuthenticationStrikeDatabase : public StrikeDatabaseIntegratorBase {
std::string GetProjectPrefix() override;
int GetMaxStrikesLimit() override;
- int64_t GetExpiryTimeMicros() override;
+ base::Optional<int64_t> GetExpiryTimeMicros() override;
bool UniqueIdsRequired() override;
};
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc
index a09cde2fded..16acda82fdc 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc
@@ -82,7 +82,7 @@ void FullCardRequest::GetFullCard(
// |result_delegate_| is already set, then immediately reject the new request
// through the method parameter |result_delegate_|.
if (result_delegate_) {
- result_delegate_->OnFullCardRequestFailed();
+ result_delegate_->OnFullCardRequestFailed(FailureType::GENERIC_FAILURE);
return;
}
@@ -160,7 +160,7 @@ void FullCardRequest::OnUnmaskPromptAccepted(
void FullCardRequest::OnUnmaskPromptClosed() {
if (result_delegate_)
- result_delegate_->OnFullCardRequestFailed();
+ result_delegate_->OnFullCardRequestFailed(FailureType::PROMPT_CLOSED);
Reset();
}
@@ -216,10 +216,15 @@ void FullCardRequest::OnDidGetRealPan(
// Neither PERMANENT_FAILURE nor NETWORK_ERROR allow retry.
case AutofillClient::PERMANENT_FAILURE:
- // Intentional fall through.
+ if (result_delegate_) {
+ result_delegate_->OnFullCardRequestFailed(
+ FailureType::VERIFICATION_DECLINED);
+ }
+ Reset();
+ break;
case AutofillClient::NETWORK_ERROR: {
if (result_delegate_)
- result_delegate_->OnFullCardRequestFailed();
+ result_delegate_->OnFullCardRequestFailed(FailureType::GENERIC_FAILURE);
Reset();
break;
}
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h
index 20c9408860f..b09fbb8d213 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.h
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.h
@@ -32,6 +32,24 @@ namespace payments {
// TODO(crbug/1061638): Refactor to use base::WaitableEvent where possible.
class FullCardRequest final : public CardUnmaskDelegate {
public:
+ // The type of failure.
+ enum FailureType {
+ // The user closed the prompt. The following scenarios are possible:
+ // 1) The user declined to enter their CVC and closed the prompt.
+ // 2) The user provided their CVC, got auth declined and then closed the
+ // prompt without attempting a second time.
+ // 3) The user provided their CVC and closed the prompt before waiting for
+ // the result.
+ PROMPT_CLOSED,
+
+ // The card could not be looked up due to card auth declined or failed.
+ VERIFICATION_DECLINED,
+
+ // The request failed for technical reasons, such as a closing page or lack
+ // of network connection.
+ GENERIC_FAILURE
+ };
+
// The interface for receiving the full card details.
class ResultDelegate {
public:
@@ -40,7 +58,7 @@ class FullCardRequest final : public CardUnmaskDelegate {
const payments::FullCardRequest& full_card_request,
const CreditCard& card,
const base::string16& cvc) = 0;
- virtual void OnFullCardRequestFailed() = 0;
+ virtual void OnFullCardRequestFailed(FailureType failure_type) = 0;
};
// The delegate responsible for displaying the unmask prompt UI.
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 909a3562728..d7967c39587 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -42,7 +42,8 @@ class MockResultDelegate : public FullCardRequest::ResultDelegate,
void(const payments::FullCardRequest&,
const CreditCard&,
const base::string16&));
- MOCK_METHOD0(OnFullCardRequestFailed, void());
+ MOCK_METHOD1(OnFullCardRequestFailed,
+ void(payments::FullCardRequest::FailureType));
};
// The delegate responsible for displaying the unmask prompt UI.
@@ -87,7 +88,8 @@ class FullCardRequestTest : public testing::Test {
request_ = std::make_unique<FullCardRequest>(
&autofill_client_, payments_client_.get(), &personal_data_);
personal_data_.SetAccountInfoForPayments(
- autofill_client_.GetIdentityManager()->GetPrimaryAccountInfo());
+ autofill_client_.GetIdentityManager()->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSync));
// Silence the warning from PaymentsClient about matching sync and Payments
// server types.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -402,7 +404,9 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForExpiredFullServerCard) {
// Only one request at a time should be allowed.
TEST_F(FullCardRequestTest, OneRequestAtATime) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+ EXPECT_CALL(
+ *result_delegate(),
+ OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(), OnUnmaskVerificationResult(_)).Times(0);
@@ -418,7 +422,7 @@ TEST_F(FullCardRequestTest, OneRequestAtATime) {
// After the first request completes, it's OK to start the second request.
TEST_F(FullCardRequestTest, SecondRequestOkAfterFirstFinished) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed()).Times(0);
+ EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed(_)).Times(0);
EXPECT_CALL(
*result_delegate(),
OnFullCardRequestSucceeded(testing::Ref(*request()),
@@ -450,7 +454,9 @@ TEST_F(FullCardRequestTest, SecondRequestOkAfterFirstFinished) {
// If the user cancels the CVC prompt,
// FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
TEST_F(FullCardRequestTest, ClosePromptWithoutUserInput) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+ EXPECT_CALL(
+ *result_delegate(),
+ OnFullCardRequestFailed(FullCardRequest::FailureType::PROMPT_CLOSED));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(), OnUnmaskVerificationResult(_)).Times(0);
@@ -464,7 +470,9 @@ TEST_F(FullCardRequestTest, ClosePromptWithoutUserInput) {
// If the server provides an empty PAN with PERMANENT_FAILURE error,
// FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
TEST_F(FullCardRequestTest, PermanentFailure) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+ EXPECT_CALL(*result_delegate(),
+ OnFullCardRequestFailed(
+ FullCardRequest::FailureType::VERIFICATION_DECLINED));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(),
OnUnmaskVerificationResult(AutofillClient::PERMANENT_FAILURE));
@@ -483,7 +491,9 @@ TEST_F(FullCardRequestTest, PermanentFailure) {
// If the server provides an empty PAN with NETWORK_ERROR error,
// FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
TEST_F(FullCardRequestTest, NetworkError) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+ EXPECT_CALL(
+ *result_delegate(),
+ OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(),
OnUnmaskVerificationResult(AutofillClient::NETWORK_ERROR));
@@ -502,7 +512,9 @@ TEST_F(FullCardRequestTest, NetworkError) {
// If the server provides an empty PAN with TRY_AGAIN_FAILURE, the user can
// manually cancel out of the dialog.
TEST_F(FullCardRequestTest, TryAgainFailureGiveUp) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+ EXPECT_CALL(
+ *result_delegate(),
+ OnFullCardRequestFailed(FullCardRequest::FailureType::PROMPT_CLOSED));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(),
OnUnmaskVerificationResult(AutofillClient::TRY_AGAIN_FAILURE));
@@ -521,7 +533,7 @@ TEST_F(FullCardRequestTest, TryAgainFailureGiveUp) {
// If the server provides an empty PAN with TRY_AGAIN_FAILURE, the user can
// correct their mistake and resubmit.
TEST_F(FullCardRequestTest, TryAgainFailureRetry) {
- EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed()).Times(0);
+ EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed(_)).Times(0);
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
testing::Ref(*request()),
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
index ec61627e313..2f3dd6e8a35 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -10,6 +10,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
index a7286883894..bb3b77081de 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
@@ -28,7 +28,6 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
-#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_local_card_migration_manager.h"
@@ -111,7 +110,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
}
void FormsSeen(const std::vector<FormData>& forms) {
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks());
+ autofill_manager_->OnFormsSeen(forms);
}
void FormSubmitted(const FormData& form) {
@@ -314,7 +313,6 @@ class LocalCardMigrationManagerTest : public testing::Test {
MockAutocompleteHistoryManager autocomplete_history_manager_;
syncer::TestSyncService sync_service_;
base::test::ScopedFeatureList scoped_feature_list_;
- TestPatternProvider test_pattern_provider_;
// Ends up getting owned (and destroyed) by TestAutofillClient:
TestStrikeDatabase* strike_database_;
// Ends up getting owned (and destroyed) by TestFormDataImporter:
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc
index 422cfa20532..f277e8944b4 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc
@@ -30,14 +30,12 @@ int LocalCardMigrationStrikeDatabase::GetMaxStrikesLimit() {
return 6;
}
-int64_t LocalCardMigrationStrikeDatabase::GetExpiryTimeMicros() {
+base::Optional<int64_t>
+LocalCardMigrationStrikeDatabase::GetExpiryTimeMicros() {
// Ideally, we should be able to annotate cards deselected at migration time
// as cards the user is not interested in uploading. Until then, we have been
- // asked to not expire local card migration strikes based on a time limit.
- // This option does not yet exist, so as a workaround the expiry time is set
- // to the maximum amount (roughly 292,000 years).
- // TODO(jsaul): Create an option to disable expiry time completely.
- return std::numeric_limits<int64_t>::max();
+ // asked to not expire local card migration strikes.
+ return base::nullopt;
}
bool LocalCardMigrationStrikeDatabase::UniqueIdsRequired() {
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h
index 08d228d071e..5f732c05928 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h
@@ -31,7 +31,7 @@ class LocalCardMigrationStrikeDatabase : public StrikeDatabaseIntegratorBase {
std::string GetProjectPrefix() override;
int GetMaxStrikesLimit() override;
- int64_t GetExpiryTimeMicros() override;
+ base::Optional<int64_t> GetExpiryTimeMicros() override;
bool UniqueIdsRequired() override;
};
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index 7417d5ea3e1..06cd9bfdf62 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -218,11 +218,8 @@ base::Value BuildCreditCardDictionary(const CreditCard& credit_card,
SetStringIfNotEmpty(credit_card, CREDIT_CARD_NAME_FULL, app_locale,
"cardholder_name", card);
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableCardNicknameUpstream) &&
- credit_card.HasNonEmptyValidNickname()) {
+ if (credit_card.HasNonEmptyValidNickname())
card.SetKey("nickname", base::Value(credit_card.nickname()));
- }
card.SetKey("encrypted_pan", base::Value("__param:" + pan_field_name));
return card;
@@ -825,9 +822,7 @@ class UploadCardRequest : public PaymentsRequest {
if (base::StringToInt(exp_year, &value))
request_dict.SetKey("expiration_year", base::Value(value));
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableCardNicknameUpstream) &&
- request_details_.card.HasNonEmptyValidNickname()) {
+ if (request_details_.card.HasNonEmptyValidNickname()) {
request_dict.SetKey("nickname",
base::Value(request_details_.card.nickname()));
}
diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
index d96c2f31f4b..0ee7b134ddf 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -374,7 +374,7 @@ class PaymentsClientTest : public testing::Test {
profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16(zip), "en-US");
profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16(phone_number),
"en-US");
-
+ profile.FinalizeAfterImport();
return profile;
}
};
@@ -905,9 +905,6 @@ TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) {
}
TEST_F(PaymentsClientTest, UploadIncludesCardNickname) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableCardNicknameUpstream);
-
StartUploading(/*include_cvc=*/true, /*include_nickname=*/true);
IssueOAuthToken();
@@ -917,21 +914,7 @@ TEST_F(PaymentsClientTest, UploadIncludesCardNickname) {
std::string::npos);
}
-TEST_F(PaymentsClientTest, UploadDoesNotIncludeCardNicknameFlagDisabled) {
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillEnableCardNicknameUpstream);
-
- StartUploading(/*include_cvc=*/true, /*include_nickname=*/true);
- IssueOAuthToken();
-
- // Card nickname was not set.
- EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
-}
-
TEST_F(PaymentsClientTest, UploadDoesNotIncludeCardNicknameEmptyNickname) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableCardNicknameUpstream);
-
StartUploading(/*include_cvc=*/true, /*include_nickname=*/false);
IssueOAuthToken();
@@ -1132,9 +1115,6 @@ TEST_F(PaymentsClientTest,
}
TEST_F(PaymentsClientTest, MigrationRequestIncludesCardNickname) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableCardNicknameUpstream);
-
StartMigrating(/*has_cardholder_name=*/true,
/*set_nickname_to_first_card=*/true);
IssueOAuthToken();
@@ -1150,18 +1130,6 @@ TEST_F(PaymentsClientTest, MigrationRequestIncludesCardNickname) {
EXPECT_FALSE(GetUploadData().find("nickname", pos + 1) != std::string::npos);
}
-TEST_F(PaymentsClientTest, MigrationRequestExcludesCardNicknameIfFlagDisabled) {
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillEnableCardNicknameUpstream);
-
- StartMigrating(/*has_cardholder_name=*/true,
- /*set_nickname_for_first_card=*/true);
- IssueOAuthToken();
-
- // Nickname was not set.
- EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
-}
-
TEST_F(PaymentsClientTest, MigrationSuccessWithSaveResult) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
diff --git a/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc
index 039ea214d05..30f94046132 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc
+++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc
@@ -73,11 +73,15 @@ void StrikeDatabaseIntegratorBase::ClearAllStrikes() {
}
void StrikeDatabaseIntegratorBase::RemoveExpiredStrikes() {
+ if (!GetExpiryTimeMicros().has_value()) {
+ // Strikes don't expire.
+ return;
+ }
std::vector<std::string> expired_keys;
for (auto entry : strike_database_->strike_map_cache_) {
if (AutofillClock::Now().ToDeltaSinceWindowsEpoch().InMicroseconds() -
entry.second.last_update_timestamp() >
- GetExpiryTimeMicros()) {
+ GetExpiryTimeMicros().value()) {
if (strike_database_->GetStrikes(entry.first) > 0) {
expired_keys.push_back(entry.first);
base::UmaHistogramCounts1000(
diff --git a/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h
index 1600d4b973b..60538eaed43 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h
+++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h
@@ -57,14 +57,14 @@ class StrikeDatabaseIntegratorBase {
protected:
// Removes all strikes in which it has been longer than GetExpiryTimeMicros()
// past |last_update_timestamp|.
- // TODO(crbug/1061639): Provide option to NOT expire strikes, perhaps by
- // GetExpiryTimeMicros() return a base::Optional.
void RemoveExpiredStrikes();
private:
FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest,
StrikeDatabaseEmptyOnAutofillRemoveEverything);
FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+ NonExpiringStrikesDoNotExpire);
+ FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
RemoveExpiredStrikesTest);
FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
GetKeyForStrikeDatabaseIntegratorUniqueIdTest);
@@ -98,8 +98,9 @@ class StrikeDatabaseIntegratorBase {
// opportunity stops being offered.
virtual int GetMaxStrikesLimit() = 0;
- // Returns the time after which the most recent strike should expire.
- virtual int64_t GetExpiryTimeMicros() = 0;
+ // Returns the time after which the most recent strike should expire. If the
+ // Optional is empty, then strikes don't expire.
+ virtual base::Optional<int64_t> GetExpiryTimeMicros() = 0;
// Returns whether or not a unique string identifier is required for every
// strike in this project.
diff --git a/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc
index 6e6d37b9577..6cb36f3bfc4 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc
+++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc
@@ -12,6 +12,14 @@ const char kProjectPrefix[] = "StrikeDatabaseIntegratorTest";
const int kMaxStrikesLimit = 6;
StrikeDatabaseIntegratorTestStrikeDatabase::
+ StrikeDatabaseIntegratorTestStrikeDatabase(
+ StrikeDatabase* strike_database,
+ base::Optional<int64_t> expiry_time_micros)
+ : StrikeDatabaseIntegratorTestStrikeDatabase(strike_database) {
+ expiry_time_micros_ = expiry_time_micros;
+}
+
+StrikeDatabaseIntegratorTestStrikeDatabase::
StrikeDatabaseIntegratorTestStrikeDatabase(StrikeDatabase* strike_database)
: StrikeDatabaseIntegratorBase(strike_database) {
RemoveExpiredStrikes();
@@ -28,9 +36,9 @@ int StrikeDatabaseIntegratorTestStrikeDatabase::GetMaxStrikesLimit() {
return kMaxStrikesLimit;
}
-int64_t StrikeDatabaseIntegratorTestStrikeDatabase::GetExpiryTimeMicros() {
- // Expiry time is 1 year.
- return (int64_t)1000000 * 60 * 60 * 24 * 365;
+base::Optional<int64_t>
+StrikeDatabaseIntegratorTestStrikeDatabase::GetExpiryTimeMicros() {
+ return expiry_time_micros_;
}
bool StrikeDatabaseIntegratorTestStrikeDatabase::UniqueIdsRequired() {
diff --git a/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h
index efe4a4584d6..c26e36af08f 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h
+++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h
@@ -18,18 +18,25 @@ namespace autofill {
class StrikeDatabaseIntegratorTestStrikeDatabase
: public StrikeDatabaseIntegratorBase {
public:
- StrikeDatabaseIntegratorTestStrikeDatabase(StrikeDatabase* strike_database);
+ StrikeDatabaseIntegratorTestStrikeDatabase(
+ StrikeDatabase* strike_database,
+ base::Optional<int64_t> expiry_time_micros);
+ explicit StrikeDatabaseIntegratorTestStrikeDatabase(
+ StrikeDatabase* strike_database);
~StrikeDatabaseIntegratorTestStrikeDatabase() override;
std::string GetProjectPrefix() override;
int GetMaxStrikesLimit() override;
- int64_t GetExpiryTimeMicros() override;
+ base::Optional<int64_t> GetExpiryTimeMicros() override;
bool UniqueIdsRequired() override;
void SetUniqueIdsRequired(bool unique_ids_required);
private:
bool unique_ids_required_ = false;
+ base::Optional<int64_t> expiry_time_micros_ =
+ static_cast<int64_t>(1000000) * 60 * 60 * 24 *
+ 365; // Default expiry time is 1 year.
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc
index e35e0bd9d6a..e87e7df4a68 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc
@@ -36,6 +36,9 @@ class StrikeDatabaseIntegratorTestStrikeDatabaseTest : public ::testing::Test {
strike_database_ =
std::make_unique<StrikeDatabaseIntegratorTestStrikeDatabase>(
strike_database_service_.get());
+ no_expiry_strike_database_ =
+ std::make_unique<StrikeDatabaseIntegratorTestStrikeDatabase>(
+ strike_database_service_.get(), base::nullopt);
}
void TearDown() override {
@@ -54,6 +57,8 @@ class StrikeDatabaseIntegratorTestStrikeDatabaseTest : public ::testing::Test {
std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> db_provider_;
std::unique_ptr<StrikeDatabase> strike_database_service_;
std::unique_ptr<StrikeDatabaseIntegratorTestStrikeDatabase> strike_database_;
+ std::unique_ptr<StrikeDatabaseIntegratorTestStrikeDatabase>
+ no_expiry_strike_database_;
private:
base::HistogramTester histogram_tester_;
@@ -113,6 +118,22 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
}
TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+ NonExpiringStrikesDoNotExpire) {
+ autofill::TestAutofillClock test_clock;
+ test_clock.SetNow(AutofillClock::Now());
+ no_expiry_strike_database_->AddStrikes(1);
+ EXPECT_EQ(1, no_expiry_strike_database_->GetStrikes());
+
+ // Advance clock very far into the future.
+ test_clock.Advance(base::TimeDelta::FromDays(INT_MAX));
+
+ no_expiry_strike_database_->RemoveExpiredStrikes();
+
+ // Strike should not be removed.
+ EXPECT_EQ(1, no_expiry_strike_database_->GetStrikes());
+}
+
+TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
RemoveExpiredStrikesTest) {
autofill::TestAutofillClock test_clock;
test_clock.SetNow(AutofillClock::Now());
@@ -121,7 +142,7 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
// Advance clock to past expiry time.
test_clock.Advance(base::TimeDelta::FromMicroseconds(
- strike_database_->GetExpiryTimeMicros() + 1));
+ strike_database_->GetExpiryTimeMicros().value() + 1));
// One strike should be removed.
strike_database_->RemoveExpiredStrikes();
@@ -133,7 +154,7 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
// Advance clock to past expiry time.
test_clock.Advance(base::TimeDelta::FromMicroseconds(
- strike_database_->GetExpiryTimeMicros() + 1));
+ strike_database_->GetExpiryTimeMicros().value() + 1));
// Strike count should be one less than the max limit.
strike_database_->RemoveExpiredStrikes();
@@ -149,7 +170,7 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
// Advance clock to past expiry time.
test_clock.Advance(base::TimeDelta::FromMicroseconds(
- strike_database_->GetExpiryTimeMicros() + 1));
+ strike_database_->GetExpiryTimeMicros().value() + 1));
// One strike should be removed.
strike_database_->RemoveExpiredStrikes();
@@ -161,7 +182,7 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
// Advance clock to past expiry time.
test_clock.Advance(base::TimeDelta::FromMicroseconds(
- strike_database_->GetExpiryTimeMicros() + 1));
+ strike_database_->GetExpiryTimeMicros().value() + 1));
// Strike count should be one less than the max limit.
strike_database_->RemoveExpiredStrikes();
@@ -283,7 +304,7 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
// Advance clock to past the entry for |unique_id_1|'s expiry time.
test_clock.Advance(base::TimeDelta::FromMicroseconds(
- strike_database_->GetExpiryTimeMicros() + 1));
+ strike_database_->GetExpiryTimeMicros().value() + 1));
strike_database_->AddStrike(unique_id_2);
strike_database_->RemoveExpiredStrikes();
@@ -295,7 +316,7 @@ TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
// Advance clock to past |unique_id_2|'s expiry time.
test_clock.Advance(base::TimeDelta::FromMicroseconds(
- strike_database_->GetExpiryTimeMicros() + 1));
+ strike_database_->GetExpiryTimeMicros().value() + 1));
strike_database_->RemoveExpiredStrikes();
diff --git a/chromium/components/autofill/core/browser/payments/test_strike_database.h b/chromium/components/autofill/core/browser/payments/test_strike_database.h
index 803a1f152e4..7fb5fb53a06 100644
--- a/chromium/components/autofill/core/browser/payments/test_strike_database.h
+++ b/chromium/components/autofill/core/browser/payments/test_strike_database.h
@@ -12,6 +12,7 @@
#include <vector>
#include "components/autofill/core/browser/payments/strike_database.h"
+#include "components/autofill/core/browser/proto/strike_data.pb.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 11d891b1282..caabfdf41a8 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/i18n/timezone.h"
@@ -26,6 +27,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_download_manager.h"
#include "components/autofill/core/browser/autofill_experiments.h"
@@ -117,12 +119,6 @@ bool FindByContents(const C& container, const T& needle) {
});
}
-bool IsSyncEnabledFor(const syncer::SyncService* sync_service,
- syncer::ModelType model_type) {
- return sync_service != nullptr && sync_service->CanSyncFeatureStart() &&
- sync_service->GetPreferredDataTypes().Has(model_type);
-}
-
// Receives the loaded profiles from the web data service and stores them in
// |*dest|. The pending handle is the address of the pending handle
// corresponding to this request type. This function is used to save bShouldoth
@@ -263,8 +259,7 @@ PersonalDataManager::PersonalDataManager(
const std::string& app_locale,
const std::string& variations_country_code)
: app_locale_(app_locale),
- variations_country_code_(variations_country_code),
- test_data_creator_(kDisusedDataModelDeletionTimeDelta, app_locale_) {
+ variations_country_code_(variations_country_code) {
database_helper_ = std::make_unique<PersonalDatabaseHelper>(this);
}
@@ -275,6 +270,7 @@ void PersonalDataManager::Init(
scoped_refptr<AutofillWebDataService> profile_database,
scoped_refptr<AutofillWebDataService> account_database,
PrefService* pref_service,
+ PrefService* local_state,
signin::IdentityManager* identity_manager,
AutofillProfileValidator* client_profile_validator,
history::HistoryService* history_service,
@@ -291,10 +287,14 @@ void PersonalDataManager::Init(
base::BindRepeating(&PersonalDataManager::ResetProfileValidity,
base::Unretained(this)));
+ alternative_state_name_map_updater_ =
+ std::make_unique<AlternativeStateNameMapUpdater>(local_state, this);
+ AddObserver(alternative_state_name_map_updater_.get());
+
// Listen for URL deletions from browsing history.
history_service_ = history_service;
if (history_service_)
- history_service_->AddObserver(this);
+ history_service_observation_.Observe(history_service_);
// Listen for account cookie deletion by the user.
identity_manager_ = identity_manager;
@@ -324,14 +324,8 @@ void PersonalDataManager::Init(
Refresh();
- // Check if profile cleanup has already been performed this major version.
- is_autofill_profile_cleanup_pending_ =
- pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) >=
- CHROME_VERSION_MAJOR;
- DVLOG(1) << "Autofill profile cleanup "
- << (is_autofill_profile_cleanup_pending_ ? "needs to be"
- : "has already been")
- << " performed for this version";
+ personal_data_manager_cleaner_ = std::make_unique<PersonalDataManagerCleaner>(
+ this, alternative_state_name_map_updater_.get(), pref_service);
}
PersonalDataManager::~PersonalDataManager() {
@@ -339,6 +333,9 @@ PersonalDataManager::~PersonalDataManager() {
CancelPendingLocalQuery(&pending_creditcards_query_);
CancelPendingLocalQuery(&pending_upi_ids_query_);
CancelPendingServerQueries();
+
+ if (alternative_state_name_map_updater_)
+ RemoveObserver(alternative_state_name_map_updater_.get());
}
void PersonalDataManager::Shutdown() {
@@ -347,7 +344,7 @@ void PersonalDataManager::Shutdown() {
sync_service_ = nullptr;
if (history_service_)
- history_service_->RemoveObserver(this);
+ history_service_observation_.Reset();
history_service_ = nullptr;
if (identity_manager_)
@@ -494,24 +491,12 @@ void PersonalDataManager::OnWebDataServiceRequestDone(
if (!HasPendingQueries() && database_helper_->GetServerDatabase()) {
// On initial data load, is_data_loaded_ will be false here.
if (!is_data_loaded_) {
- // If sync is enabled for addresses, defer running cleanups until address
- // sync has started; otherwise, do it now.
- if (!IsSyncEnabledFor(sync_service_, syncer::AUTOFILL_PROFILE))
- ApplyAddressFixesAndCleanups();
-
- // If sync is enabled for credit cards, defer running cleanups until card
- // sync has started; otherwise, do it now.
- if (!IsSyncEnabledFor(sync_service_, syncer::AUTOFILL_WALLET_DATA))
- ApplyCardFixesAndCleanups();
-
- // Log address, credit card and offer startup metrics.
- LogStoredProfileMetrics();
- LogStoredCreditCardMetrics();
- LogStoredOfferMetrics();
+ is_data_loaded_ = true;
+ personal_data_manager_cleaner_
+ ->CleanupDataAndNotifyPersonalDataObservers();
+ } else {
+ NotifyPersonalDataObserver();
}
-
- is_data_loaded_ = true;
- NotifyPersonalDataObserver();
}
}
@@ -530,15 +515,7 @@ void PersonalDataManager::AutofillAddressConversionCompleted() {
}
void PersonalDataManager::SyncStarted(syncer::ModelType model_type) {
- // Run deferred autofill address profile startup code.
- // See: OnSyncServiceInitialized
- if (model_type == syncer::AUTOFILL_PROFILE)
- ApplyAddressFixesAndCleanups();
-
- // Run deferred credit card startup code.
- // See: OnSyncServiceInitialized
- if (model_type == syncer::AUTOFILL_WALLET_DATA)
- ApplyCardFixesAndCleanups();
+ personal_data_manager_cleaner_->SyncStarted(model_type);
}
void PersonalDataManager::OnStateChanged(syncer::SyncService* sync_service) {
@@ -565,7 +542,8 @@ CoreAccountInfo PersonalDataManager::GetAccountInfoForPaymentsServer() const {
// the user has disabled sync.
// In both cases, the AccountInfo will be empty if the user is not signed in.
return sync_service_ ? sync_service_->GetAuthenticatedAccountInfo()
- : identity_manager_->GetPrimaryAccountInfo();
+ : identity_manager_->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSync);
}
// TODO(crbug.com/903914): Clean up this function so that it's more clear what
@@ -583,8 +561,6 @@ void PersonalDataManager::OnAccountsCookieDeletedByUserAction() {
::autofill::prefs::ClearSyncTransportOptIns(pref_service_);
}
-// TODO(crbug.com/903896): Generalize this to all the possible states relavant
-// to Autofill.
AutofillSyncSigninState PersonalDataManager::GetSyncSigninState() const {
// Check if the user is signed out.
if (!sync_service_ || !identity_manager_ ||
@@ -592,21 +568,16 @@ AutofillSyncSigninState PersonalDataManager::GetSyncSigninState() const {
return AutofillSyncSigninState::kSignedOut;
}
- // Check if the user has turned on sync.
- if (sync_service_->IsSyncFeatureEnabled()) {
- // TODO(crbug.com/906995): Remove this once the kStopSyncInPausedState
- // feature is launched.
- if (syncer::IsWebSignout(sync_service_->GetAuthError())) {
- return AutofillSyncSigninState::kSyncPaused;
- }
- return AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled;
- }
-
if (sync_service_->GetTransportState() ==
syncer::SyncService::TransportState::PAUSED) {
return AutofillSyncSigninState::kSyncPaused;
}
+ // Check if the user has turned on sync.
+ if (sync_service_->IsSyncFeatureEnabled()) {
+ return AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled;
+ }
+
// Check if the feature is enabled and if Wallet data types are supported.
if (base::FeatureList::IsEnabled(
features::kAutofillEnableAccountWalletStorage) &&
@@ -631,46 +602,58 @@ void PersonalDataManager::MarkObserversInsufficientFormDataForImport() {
observer.OnInsufficientFormData();
}
-void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) {
+void PersonalDataManager::RecordUseOf(
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card) {
if (is_off_the_record_)
return;
- CreditCard* credit_card = GetCreditCardByGUID(data_model.guid());
- if (credit_card) {
- credit_card->RecordAndLogUse();
+ if (absl::holds_alternative<const CreditCard*>(profile_or_credit_card)) {
+ CreditCard* credit_card = GetCreditCardByGUID(
+ absl::get<const CreditCard*>(profile_or_credit_card)->guid());
- if (credit_card->record_type() == CreditCard::LOCAL_CARD) {
- // Fail silently if there's no local database, because we need to support
- // this for tests.
- if (database_helper_->GetLocalDatabase()) {
- database_helper_->GetLocalDatabase()->UpdateCreditCard(*credit_card);
+ if (credit_card) {
+ credit_card->RecordAndLogUse();
+
+ if (credit_card->record_type() == CreditCard::LOCAL_CARD) {
+ // Fail silently if there's no local database, because we need to
+ // support this for tests.
+ if (database_helper_->GetLocalDatabase()) {
+ database_helper_->GetLocalDatabase()->UpdateCreditCard(*credit_card);
+ }
+ } else {
+ DCHECK(database_helper_->GetServerDatabase())
+ << "Recording use of server card without server storage.";
+ database_helper_->GetServerDatabase()->UpdateServerCardMetadata(
+ *credit_card);
}
- } else {
- DCHECK(database_helper_->GetServerDatabase())
- << "Recording use of server card without server storage.";
- database_helper_->GetServerDatabase()->UpdateServerCardMetadata(
- *credit_card);
- }
- Refresh();
- return;
+ Refresh();
+ return;
+ }
}
- AutofillProfile* profile = GetProfileByGUID(data_model.guid());
- if (profile) {
- profile->RecordAndLogUse();
+ if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+ // TODO(crbug.com/941498): Server profiles are not recorded therefore
+ // GetProfileByGUID returns null for them.
+ AutofillProfile* profile = GetProfileByGUID(
+ absl::get<const AutofillProfile*>(profile_or_credit_card)->guid());
- switch (profile->record_type()) {
- case AutofillProfile::LOCAL_PROFILE:
- UpdateProfileInDB(*profile, /*enforced=*/true);
- break;
- case AutofillProfile::SERVER_PROFILE:
- DCHECK(database_helper_->GetServerDatabase())
- << "Recording use of server address without server storage.";
- database_helper_->GetServerDatabase()->UpdateServerAddressMetadata(
- *profile);
- Refresh();
- break;
+ if (profile) {
+ profile->RecordAndLogUse();
+
+ switch (profile->record_type()) {
+ case AutofillProfile::LOCAL_PROFILE:
+ UpdateProfileInDB(*profile, /*enforced=*/true);
+ break;
+ case AutofillProfile::SERVER_PROFILE:
+ DCHECK(database_helper_->GetServerDatabase())
+ << "Recording use of server address without server storage.";
+ database_helper_->GetServerDatabase()->UpdateServerAddressMetadata(
+ *profile);
+ Refresh();
+ break;
+ }
}
}
}
@@ -862,17 +845,19 @@ void PersonalDataManager::UpdateServerCreditCard(
Refresh();
}
-void PersonalDataManager::UpdateServerCardMetadata(
- const CreditCard& credit_card) {
- DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type());
-
+void PersonalDataManager::UpdateServerCardsMetadata(
+ const std::vector<CreditCard>& credit_cards) {
if (is_off_the_record_)
return;
DCHECK(database_helper_->GetServerDatabase())
<< "Updating server card metadata without server storage.";
- database_helper_->GetServerDatabase()->UpdateServerCardMetadata(credit_card);
+ for (const auto& credit_card : credit_cards) {
+ DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type());
+ database_helper_->GetServerDatabase()->UpdateServerCardMetadata(
+ credit_card);
+ }
Refresh();
}
@@ -950,6 +935,11 @@ void PersonalDataManager::SetSyncServiceForTest(
sync_service_->AddObserver(this);
}
+void PersonalDataManager::AddOfferDataForTest(
+ std::unique_ptr<AutofillOfferData> offer_data) {
+ autofill_offer_data_.push_back(std::move(offer_data));
+}
+
void PersonalDataManager::
RemoveAutofillProfileByGUIDAndBlankCreditCardReference(
const std::string& guid) {
@@ -1007,6 +997,16 @@ CreditCard* PersonalDataManager::GetCreditCardByNumber(
return nullptr;
}
+CreditCard* PersonalDataManager::GetCreditCardByInstrumentId(
+ int64_t instrument_id) {
+ const std::vector<CreditCard*> credit_cards = GetCreditCards();
+ for (CreditCard* credit_card : credit_cards) {
+ if (credit_card->instrument_id() == instrument_id)
+ return credit_card;
+ }
+ return nullptr;
+}
+
void PersonalDataManager::GetNonEmptyTypes(
ServerFieldTypeSet* non_empty_types) const {
for (AutofillProfile* profile : GetProfiles())
@@ -1290,8 +1290,6 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
return unique_suggestions;
}
-// TODO(crbug.com/613187): Investigate if it would be more efficient to dedupe
-// with a vector instead of a list.
const std::vector<CreditCard*> PersonalDataManager::GetCreditCardsToSuggest(
bool include_server_cards) const {
if (!IsAutofillCreditCardEnabled())
@@ -1438,32 +1436,6 @@ void PersonalDataManager::SetPrefService(PrefService* pref_service) {
}
}
-void PersonalDataManager::ClearProfileNonSettingsOrigins() {
- for (AutofillProfile* profile : GetProfiles()) {
- if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) {
- profile->set_origin(std::string());
- UpdateProfileInDB(*profile, /*enforced=*/true);
- }
- }
-}
-
-void PersonalDataManager::ClearCreditCardNonSettingsOrigins() {
- bool has_updated = false;
-
- for (CreditCard* card : GetLocalCreditCards()) {
- if (card->origin() != kSettingsOrigin && !card->origin().empty()) {
- card->set_origin(std::string());
- database_helper_->GetLocalDatabase()->UpdateCreditCard(*card);
- has_updated = true;
- }
- }
-
- // Refresh the local cache and send notifications to observers if a changed
- // was made.
- if (has_updated)
- Refresh();
-}
-
void PersonalDataManager::OnValidated(const AutofillProfile* profile) {
if (!profile)
return;
@@ -1957,7 +1929,9 @@ bool PersonalDataManager::IsServerCard(const CreditCard* credit_card) const {
bool PersonalDataManager::ShouldShowCardsFromAccountOption() const {
// The feature is only for Linux, Windows and Mac.
-#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) || \
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || defined(OS_WIN) || \
defined(OS_APPLE)
// This option should only be shown for users that have not enabled the Sync
// Feature and that have server credit cards available.
@@ -1981,8 +1955,8 @@ bool PersonalDataManager::ShouldShowCardsFromAccountOption() const {
return !is_opted_in;
#else
return false;
-#endif // #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) || \
- // defined(OS_APPLE)
+#endif // #if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) ||
+ // defined(OS_WIN) || defined(OS_APPLE)
}
void PersonalDataManager::OnUserAcceptedCardsFromAccountOption() {
@@ -2164,206 +2138,6 @@ std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
return suggestions;
}
-void PersonalDataManager::RemoveOrphanAutofillTableRows() {
- // Don't run if the fix has already been applied.
- if (pref_service_->GetBoolean(prefs::kAutofillOrphanRowsRemoved))
- return;
-
- if (!database_helper_->GetLocalDatabase())
- return;
-
- database_helper_->GetLocalDatabase()->RemoveOrphanAutofillTableRows();
-
- // Set the pref so that this fix is never run again.
- pref_service_->SetBoolean(prefs::kAutofillOrphanRowsRemoved, true);
-}
-
-bool PersonalDataManager::ApplyDedupingRoutine() {
- if (!is_autofill_profile_cleanup_pending_)
- return false;
-
- is_autofill_profile_cleanup_pending_ = false;
-
- // No need to de-duplicate if there are less than two profiles.
- if (web_profiles_.size() < 2) {
- DVLOG(1) << "Autofill profile de-duplication not needed.";
- return false;
- }
-
- // Check if de-duplication has already been performed this major version.
- if (pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) >=
- CHROME_VERSION_MAJOR) {
- DVLOG(1)
- << "Autofill profile de-duplication already performed for this version";
- return false;
- }
-
- DVLOG(1) << "Starting autofill profile de-duplication.";
- std::unordered_set<std::string> profiles_to_delete;
- profiles_to_delete.reserve(web_profiles_.size());
-
- // Create the map used to update credit card's billing addresses after the
- // dedupe.
- std::unordered_map<std::string, std::string> guids_merge_map;
-
- // The changes can't happen directly on the web_profiles_, but need to be
- // updated in the database at first, and then updated on the web_profiles_.
- // Therefore, we need a copy of web_profiles_ to keep track of the changes.
- std::vector<std::unique_ptr<AutofillProfile>> new_profiles;
- for (const auto& it : web_profiles_) {
- new_profiles.push_back(std::make_unique<AutofillProfile>(*(it.get())));
- }
-
- DedupeProfiles(&new_profiles, &profiles_to_delete, &guids_merge_map);
-
- // Apply the profile changes to the database.
- for (const auto& profile : new_profiles) {
- // If the profile was set to be deleted, remove it from the database,
- // otherwise update it.
- if (profiles_to_delete.count(profile->guid())) {
- RemoveProfileFromDB(profile->guid());
- } else {
- UpdateProfileInDB(*(profile.get()));
- }
- }
-
- UpdateCardsBillingAddressReference(guids_merge_map);
-
- // Set the pref to the current major version.
- pref_service_->SetInteger(prefs::kAutofillLastVersionDeduped,
- CHROME_VERSION_MAJOR);
- return true;
-}
-
-void PersonalDataManager::DedupeProfiles(
- std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
- std::unordered_set<std::string>* profiles_to_delete,
- std::unordered_map<std::string, std::string>* guids_merge_map) const {
- AutofillMetrics::LogNumberOfProfilesConsideredForDedupe(
- existing_profiles->size());
-
- // Sort the profiles by frecency with all the verified profiles at the end.
- // That way the most relevant profiles will get merged into the less relevant
- // profiles, which keeps the syntax of the most relevant profiles data.
- // Verified profiles are put at the end because they do not merge into other
- // profiles, so the loop can be stopped when we reach those. However they need
- // to be in the vector because an unverified profile trying to merge into a
- // similar verified profile will be discarded.
- base::Time comparison_time = AutofillClock::Now();
- std::sort(existing_profiles->begin(), existing_profiles->end(),
- [comparison_time](const std::unique_ptr<AutofillProfile>& a,
- const std::unique_ptr<AutofillProfile>& b) {
- if (a->IsVerified() != b->IsVerified())
- return !a->IsVerified();
- return a->HasGreaterFrecencyThan(b.get(), comparison_time);
- });
-
- AutofillProfileComparator comparator(app_locale_);
-
- for (size_t i = 0; i < existing_profiles->size(); ++i) {
- AutofillProfile* profile_to_merge = (*existing_profiles)[i].get();
-
- // If the profile was set to be deleted, skip it. It has already been
- // merged into another profile.
- if (profiles_to_delete->count(profile_to_merge->guid()))
- continue;
-
- // If we have reached the verified profiles, stop trying to merge. Verified
- // profiles do not get merged.
- if (profile_to_merge->IsVerified())
- break;
-
- // If we have not reached the last profile, try to merge |profile_to_merge|
- // with all the less relevant |existing_profiles|.
- for (size_t j = i + 1; j < existing_profiles->size(); ++j) {
- AutofillProfile* existing_profile = (*existing_profiles)[j].get();
-
- // Don't try to merge a profile that was already set for deletion.
- if (profiles_to_delete->count(existing_profile->guid()))
- continue;
-
- // Move on if the profiles are not mergeable.
- if (!comparator.AreMergeable(*existing_profile, *profile_to_merge))
- continue;
-
- // The profiles are found to be mergeable. Attempt to update the existing
- // profile. This returns true if the merge was successful, or if the
- // merge would have been successful but the existing profile IsVerified()
- // and will not accept updates from profile_to_merge.
- if (existing_profile->SaveAdditionalInfo(*profile_to_merge,
- app_locale_)) {
- // Keep track that a credit card using |profile_to_merge|'s GUID as its
- // billing address id should replace it by |existing_profile|'s GUID.
- guids_merge_map->emplace(profile_to_merge->guid(),
- existing_profile->guid());
-
- // Since |profile_to_merge| was a duplicate of |existing_profile|
- // and was merged successfully, it can now be deleted.
- profiles_to_delete->insert(profile_to_merge->guid());
-
- // Now try to merge the new resulting profile with the rest of the
- // existing profiles.
- profile_to_merge = existing_profile;
-
- // Verified profiles do not get merged. Save some time by not
- // trying.
- if (profile_to_merge->IsVerified())
- break;
- }
- }
- }
- AutofillMetrics::LogNumberOfProfilesRemovedDuringDedupe(
- profiles_to_delete->size());
-}
-
-void PersonalDataManager::UpdateCardsBillingAddressReference(
- const std::unordered_map<std::string, std::string>& guids_merge_map) {
- /* Here is an example of what the graph might look like.
-
- A -> B
- \
- -> E
- /
- C -> D
- */
-
- for (auto* credit_card : GetCreditCards()) {
- // If the credit card is not associated with a billing address, skip it.
- if (credit_card->billing_address_id().empty())
- break;
-
- // If the billing address profile associated with the card has been merged,
- // replace it by the id of the profile in which it was merged. Repeat the
- // process until the billing address has not been merged into another one.
- std::unordered_map<std::string, std::string>::size_type nb_guid_changes = 0;
- bool was_modified = false;
- auto it = guids_merge_map.find(credit_card->billing_address_id());
- while (it != guids_merge_map.end()) {
- was_modified = true;
- credit_card->set_billing_address_id(it->second);
- it = guids_merge_map.find(credit_card->billing_address_id());
-
- // Out of abundance of caution.
- if (nb_guid_changes > guids_merge_map.size()) {
- NOTREACHED();
- // Cancel the changes for that card.
- was_modified = false;
- break;
- }
- }
-
- // If the card was modified, apply the changes to the database.
- if (was_modified) {
- if (credit_card->record_type() == CreditCard::LOCAL_CARD)
- database_helper_->GetLocalDatabase()->UpdateCreditCard(*credit_card);
- else
- database_helper_->GetServerDatabase()->UpdateServerCardMetadata(
- *credit_card);
- }
- }
- Refresh();
-}
-
void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() {
// If the full Sync feature isn't enabled, then do NOT convert any Wallet
// addresses to local ones.
@@ -2381,109 +2155,6 @@ void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() {
app_locale_, GetAccountInfoForPaymentsServer().email);
}
-bool PersonalDataManager::DeleteDisusedCreditCards() {
- // Only delete local cards, as server cards are managed by Payments.
- auto cards = GetLocalCreditCards();
-
- // Early exit when there is no local cards.
- if (cards.empty()) {
- return true;
- }
-
- std::vector<std::string> guid_to_delete;
- for (CreditCard* card : cards) {
- if (card->IsDeletable()) {
- guid_to_delete.push_back(card->guid());
- }
- }
-
- size_t num_deleted_cards = guid_to_delete.size();
-
- for (auto const& guid : guid_to_delete) {
- database_helper_->GetLocalDatabase()->RemoveCreditCard(guid);
- }
-
- if (num_deleted_cards > 0) {
- Refresh();
- }
-
- AutofillMetrics::LogNumberOfCreditCardsDeletedForDisuse(num_deleted_cards);
-
- return true;
-}
-
-bool PersonalDataManager::DeleteDisusedAddresses() {
- const std::vector<AutofillProfile*>& profiles = GetProfiles();
-
- // Early exit when there are no profiles.
- if (profiles.empty()) {
- DVLOG(1) << "There are no profiles";
- return true;
- }
-
- std::unordered_set<std::string> used_billing_address_guids;
- for (CreditCard* card : GetCreditCards()) {
- if (!card->IsDeletable()) {
- used_billing_address_guids.insert(card->billing_address_id());
- }
- }
-
- std::vector<std::string> guids_to_delete;
- for (AutofillProfile* profile : profiles) {
- if (profile->IsDeletable() &&
- !used_billing_address_guids.count(profile->guid())) {
- guids_to_delete.push_back(profile->guid());
- }
- }
-
- size_t num_deleted_addresses = guids_to_delete.size();
-
- for (auto const& guid : guids_to_delete) {
- RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid);
- }
-
- if (num_deleted_addresses > 0) {
- Refresh();
- }
-
- AutofillMetrics::LogNumberOfAddressesDeletedForDisuse(num_deleted_addresses);
-
- return true;
-}
-
-void PersonalDataManager::ApplyAddressFixesAndCleanups() {
- // Validate profiles once per major.
- UpdateClientValidityStates(GetProfiles());
-
- // One-time fix, otherwise NOP.
- RemoveOrphanAutofillTableRows();
-
- // Once per major version, otherwise NOP.
- ApplyDedupingRoutine();
-
- DeleteDisusedAddresses();
-
- // If feature AutofillCreateDataForTest is enabled, and once per user profile
- // startup.
- test_data_creator_.MaybeAddTestProfiles(base::BindRepeating(
- &PersonalDataManager::AddProfile, base::Unretained(this)));
-
- // Ran everytime it is called.
- ClearProfileNonSettingsOrigins();
-}
-
-void PersonalDataManager::ApplyCardFixesAndCleanups() {
- DeleteDisusedCreditCards();
-
- // If feature AutofillCreateDataForTest is enabled, and once per user profile
- // startup.
- test_data_creator_.MaybeAddTestCreditCards(base::BindRepeating(
- &PersonalDataManager::AddCreditCard, base::Unretained(this)));
-
- // Ran everytime it is called.
- ClearCreditCardNonSettingsOrigins();
-}
-
void PersonalDataManager::ResetProfileValidity() {
synced_profile_validity_.reset();
profiles_server_validities_need_update_ = true;
@@ -2697,11 +2368,6 @@ void PersonalDataManager::MigrateUserOptedInWalletSyncTransportIfNeeded() {
base::string16 PersonalDataManager::GetDisplayNicknameForCreditCard(
const CreditCard& card) const {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableCardNicknameManagement)) {
- return base::string16();
- }
-
// Always prefer a local nickname if available.
if (card.HasNonEmptyValidNickname() &&
card.record_type() == CreditCard::LOCAL_CARD)
@@ -2719,4 +2385,14 @@ base::string16 PersonalDataManager::GetDisplayNicknameForCreditCard(
return card.nickname();
}
+bool PersonalDataManager::IsSyncEnabledFor(syncer::ModelType model_type) {
+ return sync_service_ != nullptr && sync_service_->CanSyncFeatureStart() &&
+ sync_service_->GetPreferredDataTypes().Has(model_type);
+}
+
+scoped_refptr<AutofillWebDataService> PersonalDataManager::GetLocalDatabase() {
+ DCHECK(database_helper_);
+ return database_helper_->GetLocalDatabase();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index eea8c516658..0ccbd642d61 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -17,6 +17,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_profile_validator.h"
@@ -24,16 +25,18 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
-#include "components/autofill/core/browser/data_model/test_data_creator.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_updater.h"
#include "components/autofill/core/browser/payments/account_info_getter.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
+#include "components/autofill/core/browser/personal_data_manager_cleaner.h"
#include "components/autofill/core/browser/proto/server.pb.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
+#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"
@@ -43,7 +46,7 @@
#include "components/sync/driver/sync_service_observer.h"
#include "components/webdata/common/web_data_service_consumer.h"
-class Browser;
+class Profile;
class PrefService;
class RemoveAutofillTester;
@@ -93,6 +96,7 @@ class PersonalDataManager : public KeyedService,
void Init(scoped_refptr<AutofillWebDataService> profile_database,
scoped_refptr<AutofillWebDataService> account_database,
PrefService* pref_service,
+ PrefService* local_state,
signin::IdentityManager* identity_manager,
AutofillProfileValidator* client_profile_validator,
history::HistoryService* history_service,
@@ -143,9 +147,11 @@ class PersonalDataManager : public KeyedService,
// imported from a form.
void MarkObserversInsufficientFormDataForImport();
- // Called to indicate |data_model| was used (to fill in a form). Updates
- // the database accordingly. Can invalidate |data_model|.
- virtual void RecordUseOf(const AutofillDataModel& data_model);
+ // Called to indicate |profile_or_credit_card| was used (to fill in a form).
+ // Updates the database accordingly.
+ virtual void RecordUseOf(
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card);
// Saves |imported_profile| to the WebDB if it exists. Returns the guid of
// the new or updated profile, or the empty string if no profile was saved.
@@ -201,9 +207,10 @@ class PersonalDataManager : public KeyedService,
// status can be changed. Looks up the card by server ID.
virtual void UpdateServerCreditCard(const CreditCard& credit_card);
- // Updates the use stats and billing address id for the server |credit_card|.
- // Looks up the card by server_id.
- virtual void UpdateServerCardMetadata(const CreditCard& credit_card);
+ // Updates the use stats and billing address id for the server |credit_cards|.
+ // Looks up the cards by server_id.
+ virtual void UpdateServerCardsMetadata(
+ const std::vector<CreditCard>& credit_cards);
// Resets the card for |guid| to the masked state.
void ResetFullServerCard(const std::string& guid);
@@ -228,6 +235,10 @@ class PersonalDataManager : public KeyedService,
// owned by this class and must outlive |this|.
void SetSyncServiceForTest(syncer::SyncService* sync_service);
+ // Adds the offer data to local cache for tests. This does not affect data in
+ // the real database.
+ void AddOfferDataForTest(std::unique_ptr<AutofillOfferData> offer_data);
+
// Returns the credit card with the specified |guid|, or nullptr if there is
// no credit card with the specified |guid|.
virtual CreditCard* GetCreditCardByGUID(const std::string& guid);
@@ -236,7 +247,11 @@ class PersonalDataManager : public KeyedService,
// no credit card with the specified |number|.
virtual CreditCard* GetCreditCardByNumber(const std::string& number);
- // Gets the field types availabe in the stored address and credit card data.
+ // Returns the credit card with the specified |instrument_id|, or nullptr if
+ // there is no credit card with the specified |instrument_id|.
+ CreditCard* GetCreditCardByInstrumentId(int64_t instrument_id);
+
+ // Gets the field types available in the stored address and credit card data.
void GetNonEmptyTypes(ServerFieldTypeSet* non_empty_types) const;
// Returns whether the personal data has been loaded from the web database.
@@ -293,10 +308,6 @@ class PersonalDataManager : public KeyedService,
bool field_is_autofilled,
const std::vector<ServerFieldType>& field_types);
- // Tries to delete disused addresses once per major version if the
- // feature is enabled.
- bool DeleteDisusedAddresses();
-
// Returns the credit cards to suggest to the user. Those have been deduped
// and ordered by frecency with the expired cards put at the end of the
// vector. If |include_server_cards| is false, server side cards should not
@@ -321,10 +332,6 @@ class PersonalDataManager : public KeyedService,
const base::string16& field_contents,
bool include_server_cards);
- // Tries to delete disused credit cards once per major version if the
- // feature is enabled.
- bool DeleteDisusedCreditCards();
-
// Re-loads profiles and credit cards from the WebDatabase asynchronously.
// In the general case, this is a no-op and will re-create the same
// in-memory model as existed prior to the call. If any change occurred to
@@ -349,6 +356,14 @@ class PersonalDataManager : public KeyedService,
void set_variations_country_code_for_testing(std::string country_code) {
variations_country_code_ = country_code;
}
+
+ // Returns the raw pointer to PersonalDataManagerCleaner used for testing
+ // purposes.
+ PersonalDataManagerCleaner* personal_data_manager_cleaner_for_testing()
+ const {
+ DCHECK(personal_data_manager_cleaner_);
+ return personal_data_manager_cleaner_.get();
+ }
#endif
// Returns our best guess for the country a user is likely to use when
@@ -421,6 +436,9 @@ class PersonalDataManager : public KeyedService,
client_profile_validator_ = validator;
}
+ // Returns true if the PDM is in the off-the-record mode.
+ bool IsOffTheRecord() { return is_off_the_record_; }
+
protected:
// Only PersonalDataManagerFactory and certain tests can create instances of
// PersonalDataManager.
@@ -491,15 +509,12 @@ class PersonalDataManager : public KeyedService,
PersonalDataManagerTest,
GetCreditCardSuggestions_NoCreditCardsAddedIfDisabled);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ClearProfileNonSettingsOrigins);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ClearCreditCardNonSettingsOrigins);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
RequestProfileServerValidity);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
GetProfileSuggestions_Validity);
friend class autofill::AutofillInteractiveTest;
+ friend class autofill::PersonalDataManagerCleaner;
friend class autofill::PersonalDataManagerFactory;
friend class AutofillMetricsTest;
friend class FormDataImporterTest;
@@ -517,7 +532,7 @@ class PersonalDataManager : public KeyedService,
friend void autofill_helper::SetCreditCards(
int,
std::vector<autofill::CreditCard>*);
- friend void SetTestProfiles(Browser* browser,
+ friend void SetTestProfiles(Profile* base_profile,
std::vector<AutofillProfile>* profiles);
// Sets |web_profiles_| to the contents of |profiles| and updates the web
@@ -578,11 +593,6 @@ class PersonalDataManager : public KeyedService,
// this class and must outlive |this|.
void SetPrefService(PrefService* pref_service);
- // Clears the value of the origin field of the autofill profiles or cards that
- // were not created from the settings page.
- void ClearProfileNonSettingsOrigins();
- void ClearCreditCardNonSettingsOrigins();
-
// Called when the |profile| is validated by the AutofillProfileValidator,
// updates the profiles on the |ongoing_profile_changes_| and the DB.
virtual void OnValidated(const AutofillProfile* profile);
@@ -637,6 +647,11 @@ class PersonalDataManager : public KeyedService,
// The observers.
base::ObserverList<PersonalDataManagerObserver>::Unchecked observers_;
+ // Used to populate AlternativeStateNameMap with the geographical state data
+ // (including their abbreviations and localized names).
+ std::unique_ptr<AlternativeStateNameMapUpdater>
+ alternative_state_name_map_updater_;
+
// |profile_valditiies_need_update| whenever the profile validities are out of
bool profiles_server_validities_need_update_ = true;
@@ -664,36 +679,6 @@ class PersonalDataManager : public KeyedService,
const base::string16& field_contents,
const std::vector<CreditCard*>& cards_to_suggest) const;
- // Runs the routine that removes the orphan rows in the autofill tables if
- // it's never been done.
- void RemoveOrphanAutofillTableRows();
-
- // Applies the deduping routine once per major version if the feature is
- // enabled. Calls DedupeProfiles with the content of |web_profiles_| as a
- // parameter. Removes the profiles to delete from the database and updates the
- // others. Also updates the credit cards' billing address references. Returns
- // true if the routine was run.
- bool ApplyDedupingRoutine();
-
- // Goes through all the |existing_profiles| and merges all similar unverified
- // profiles together. Also discards unverified profiles that are similar to a
- // verified profile. All the profiles except the results of the merges will be
- // added to |profile_guids_to_delete|. This routine should be run once per
- // major version. Records all the merges into the |guids_merge_map|.
- //
- // This method should only be called by ApplyDedupingRoutine. It is split for
- // testing purposes.
- void DedupeProfiles(
- std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
- std::unordered_set<std::string>* profile_guids_to_delete,
- std::unordered_map<std::string, std::string>* guids_merge_map) const;
-
- // Updates the credit cards' billing address reference based on the merges
- // that happened during the dedupe, as defined in |guids_merge_map|. Also
- // updates the cards entries in the database.
- void UpdateCardsBillingAddressReference(
- const std::unordered_map<std::string, std::string>& guids_merge_map);
-
// Converts the Wallet addresses to local autofill profiles. This should be
// called after all the syncable data has been processed (local cards and
// profiles, Wallet data and metadata). Also updates Wallet cards' billing
@@ -728,12 +713,6 @@ class PersonalDataManager : public KeyedService,
void RemoveAutofillProfileByGUIDAndBlankCreditCardReference(
const std::string& guid);
- // Applies various fixes and cleanups on autofill addresses.
- void ApplyAddressFixesAndCleanups();
-
- // Applies various fixes and cleanups on autofill credit cards.
- void ApplyCardFixesAndCleanups();
-
// Resets |synced_profile_validity_|.
void ResetProfileValidity();
@@ -773,6 +752,12 @@ class PersonalDataManager : public KeyedService,
// one copy has a nickname, take that.
base::string16 GetDisplayNicknameForCreditCard(const CreditCard& card) const;
+ // Returns true if the sync is enabled for |model_type|.
+ bool IsSyncEnabledFor(syncer::ModelType model_type);
+
+ // Returns the database that is used for storing local data.
+ scoped_refptr<AutofillWebDataService> GetLocalDatabase();
+
// Stores the |app_locale| supplied on construction.
const std::string app_locale_;
@@ -799,6 +784,11 @@ class PersonalDataManager : public KeyedService,
// |profile_validities_need_update_| whenever this is changed.
std::unique_ptr<UserProfileValidityMap> synced_profile_validity_;
+ // PersonalDataManagerCleaner is used to apply various address and credit
+ // card fixes/cleanups one time at browser startup or when the sync starts.
+ // PersonalDataManagerCleaner is declared as a friend class.
+ std::unique_ptr<PersonalDataManagerCleaner> personal_data_manager_cleaner_;
+
// A timely ordered list of ongoing changes for each profile.
std::unordered_map<std::string, std::deque<AutofillProfileDeepChange>>
ongoing_profile_changes_;
@@ -834,17 +824,12 @@ class PersonalDataManager : public KeyedService,
// An observer to listen for changes to prefs::kAutofillWalletImportEnabled.
std::unique_ptr<BooleanPrefMember> wallet_enabled_pref_;
- // True if autofill profile cleanup needs to be performed.
- bool is_autofill_profile_cleanup_pending_ = false;
-
- // Used to create test data. If the AutofillCreateDataForTest feature is
- // enabled, this helper creates autofill profiles and credit card data that
- // would otherwise be difficult to create manually using the UI.
- TestDataCreator test_data_creator_;
-
// Whether sync should be considered on in a test.
bool is_syncing_for_test_ = false;
+ base::ScopedObservation<history::HistoryService, HistoryServiceObserver>
+ history_service_observation_{this};
+
base::WeakPtrFactory<PersonalDataManager> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(PersonalDataManager);
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc b/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc
new file mode 100644
index 00000000000..b1f46d6979e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc
@@ -0,0 +1,455 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/personal_data_manager_cleaner.h"
+
+#include "base/logging.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/prefs/pref_service.h"
+
+namespace autofill {
+
+PersonalDataManagerCleaner::PersonalDataManagerCleaner(
+ PersonalDataManager* personal_data_manager,
+ AlternativeStateNameMapUpdater* alternative_state_name_map_updater,
+ PrefService* pref_service)
+ : test_data_creator_(kDisusedDataModelDeletionTimeDelta,
+ personal_data_manager->app_locale()),
+ personal_data_manager_(personal_data_manager),
+ pref_service_(pref_service),
+ alternative_state_name_map_updater_(alternative_state_name_map_updater) {
+ // Check if profile cleanup has already been performed this major version.
+ is_autofill_profile_cleanup_pending_ =
+ pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) <
+ CHROME_VERSION_MAJOR;
+ DVLOG(1) << "Autofill profile cleanup "
+ << (is_autofill_profile_cleanup_pending_ ? "needs to be"
+ : "has already been")
+ << " performed for this version";
+}
+
+PersonalDataManagerCleaner::~PersonalDataManagerCleaner() = default;
+
+void PersonalDataManagerCleaner::CleanupDataAndNotifyPersonalDataObservers() {
+ // The profile de-duplication is run once every major chrome version. If the
+ // profile de-duplication has not run for the |CHROME_VERSION_MAJOR| yet,
+ // |AlternativeStateNameMap| needs to be populated first. Otherwise,
+ // defer the insertion to when the observers are notified.
+ if (!alternative_state_name_map_updater_
+ ->is_alternative_state_name_map_populated() &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap) &&
+ is_autofill_profile_cleanup_pending_) {
+ alternative_state_name_map_updater_->PopulateAlternativeStateNameMap(
+ base::BindOnce(&PersonalDataManagerCleaner::
+ CleanupDataAndNotifyPersonalDataObservers,
+ weak_ptr_factory_.GetWeakPtr()));
+ return;
+ }
+
+ // If sync is enabled for addresses, defer running cleanups until address
+ // sync has started; otherwise, do it now.
+ if (!personal_data_manager_->IsSyncEnabledFor(syncer::AUTOFILL_PROFILE))
+ ApplyAddressFixesAndCleanups();
+
+ // If sync is enabled for credit cards, defer running cleanups until card
+ // sync has started; otherwise, do it now.
+ if (!personal_data_manager_->IsSyncEnabledFor(syncer::AUTOFILL_WALLET_DATA))
+ ApplyCardFixesAndCleanups();
+
+ // Log address, credit card and offer startup metrics.
+ personal_data_manager_->LogStoredProfileMetrics();
+ personal_data_manager_->LogStoredCreditCardMetrics();
+ personal_data_manager_->LogStoredOfferMetrics();
+
+ personal_data_manager_->NotifyPersonalDataObserver();
+}
+
+void PersonalDataManagerCleaner::SyncStarted(syncer::ModelType model_type) {
+ // The profile de-duplication is run once every major chrome version. If the
+ // profile de-duplication has not run for the |CHROME_VERSION_MAJOR| yet,
+ // |AlternativeStateNameMap| needs to be populated first. Otherwise,
+ // defer the insertion to when the observers are notified.
+ if (!alternative_state_name_map_updater_
+ ->is_alternative_state_name_map_populated() &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap) &&
+ is_autofill_profile_cleanup_pending_) {
+ alternative_state_name_map_updater_->PopulateAlternativeStateNameMap(
+ base::BindOnce(&PersonalDataManagerCleaner::SyncStarted,
+ weak_ptr_factory_.GetWeakPtr(), model_type));
+ return;
+ }
+
+ // Run deferred autofill address profile startup code.
+ // See: PersonalDataManager::OnSyncServiceInitialized
+ if (model_type == syncer::AUTOFILL_PROFILE)
+ ApplyAddressFixesAndCleanups();
+
+ // Run deferred credit card startup code.
+ // See: PersonalDataManager::OnSyncServiceInitialized
+ if (model_type == syncer::AUTOFILL_WALLET_DATA)
+ ApplyCardFixesAndCleanups();
+}
+
+void PersonalDataManagerCleaner::ApplyAddressFixesAndCleanups() {
+ // Validate profiles once per major.
+ personal_data_manager_->UpdateClientValidityStates(
+ personal_data_manager_->GetProfiles());
+
+ // One-time fix, otherwise NOP.
+ RemoveOrphanAutofillTableRows();
+
+ // Once per major version, otherwise NOP.
+ ApplyDedupingRoutine();
+
+ // Once per major version, otherwise NOP.
+ DeleteDisusedAddresses();
+
+ // If feature AutofillCreateDataForTest is enabled, and once per user profile
+ // startup.
+ test_data_creator_.MaybeAddTestProfiles(base::BindRepeating(
+ &PersonalDataManagerCleaner::AddProfileForTest, base::Unretained(this)));
+
+ // Ran everytime it is called.
+ ClearProfileNonSettingsOrigins();
+}
+
+void PersonalDataManagerCleaner::ApplyCardFixesAndCleanups() {
+ // Once per major version, otherwise NOP.
+ DeleteDisusedCreditCards();
+
+ // If feature AutofillCreateDataForTest is enabled, and once per user profile
+ // startup.
+ test_data_creator_.MaybeAddTestCreditCards(
+ base::BindRepeating(&PersonalDataManagerCleaner::AddCreditCardForTest,
+ base::Unretained(this)));
+
+ // Ran everytime it is called.
+ ClearCreditCardNonSettingsOrigins();
+}
+
+void PersonalDataManagerCleaner::RemoveOrphanAutofillTableRows() {
+ // Don't run if the fix has already been applied.
+ if (pref_service_->GetBoolean(prefs::kAutofillOrphanRowsRemoved))
+ return;
+
+ scoped_refptr<AutofillWebDataService> local_db =
+ personal_data_manager_->GetLocalDatabase();
+ if (!local_db)
+ return;
+
+ local_db->RemoveOrphanAutofillTableRows();
+
+ // Set the pref so that this fix is never run again.
+ pref_service_->SetBoolean(prefs::kAutofillOrphanRowsRemoved, true);
+}
+
+bool PersonalDataManagerCleaner::ApplyDedupingRoutine() {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableProfileDeduplication)) {
+ return false;
+ }
+
+ // Check if de-duplication has already been performed on this major version.
+ if (!is_autofill_profile_cleanup_pending_) {
+ DVLOG(1)
+ << "Autofill profile de-duplication already performed for this version";
+ return false;
+ }
+
+ const std::vector<AutofillProfile*>& profiles =
+ personal_data_manager_->GetProfiles();
+
+ // No need to de-duplicate if there are less than two profiles.
+ if (profiles.size() < 2) {
+ DVLOG(1) << "Autofill profile de-duplication not needed.";
+ return false;
+ }
+
+ DVLOG(1) << "Starting autofill profile de-duplication.";
+ std::unordered_set<std::string> profiles_to_delete;
+ profiles_to_delete.reserve(profiles.size());
+
+ // Create the map used to update credit card's billing addresses after the
+ // dedupe.
+ std::unordered_map<std::string, std::string> guids_merge_map;
+
+ // The changes can't happen directly on the profiles, but need to be
+ // updated in the database at first, and then updated on the profiles.
+ // Therefore, we need a copy of profiles to keep track of the changes.
+ std::vector<std::unique_ptr<AutofillProfile>> new_profiles;
+ for (auto* it : profiles) {
+ new_profiles.push_back(std::make_unique<AutofillProfile>(*it));
+ }
+
+ DedupeProfiles(&new_profiles, &profiles_to_delete, &guids_merge_map);
+
+ // Apply the profile changes to the database.
+ for (const auto& profile : new_profiles) {
+ // If the profile was set to be deleted, remove it from the database,
+ // otherwise update it.
+ if (profiles_to_delete.count(profile->guid())) {
+ personal_data_manager_->RemoveProfileFromDB(profile->guid());
+ } else {
+ personal_data_manager_->UpdateProfileInDB(*(profile.get()));
+ }
+ }
+
+ UpdateCardsBillingAddressReference(guids_merge_map);
+
+ is_autofill_profile_cleanup_pending_ = false;
+ // Set the pref to the current major version.
+ pref_service_->SetInteger(prefs::kAutofillLastVersionDeduped,
+ CHROME_VERSION_MAJOR);
+
+ return true;
+}
+
+void PersonalDataManagerCleaner::DedupeProfiles(
+ std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
+ std::unordered_set<std::string>* profiles_to_delete,
+ std::unordered_map<std::string, std::string>* guids_merge_map) const {
+ AutofillMetrics::LogNumberOfProfilesConsideredForDedupe(
+ existing_profiles->size());
+
+ // Sort the profiles by frecency with all the verified profiles at the end.
+ // That way the most relevant profiles will get merged into the less relevant
+ // profiles, which keeps the syntax of the most relevant profiles data.
+ // Verified profiles are put at the end because they do not merge into other
+ // profiles, so the loop can be stopped when we reach those. However they need
+ // to be in the vector because an unverified profile trying to merge into a
+ // similar verified profile will be discarded.
+ base::Time comparison_time = AutofillClock::Now();
+ std::sort(existing_profiles->begin(), existing_profiles->end(),
+ [comparison_time](const std::unique_ptr<AutofillProfile>& a,
+ const std::unique_ptr<AutofillProfile>& b) {
+ if (a->IsVerified() != b->IsVerified())
+ return !a->IsVerified();
+ return a->HasGreaterFrecencyThan(b.get(), comparison_time);
+ });
+
+ AutofillProfileComparator comparator(personal_data_manager_->app_locale());
+
+ for (size_t i = 0; i < existing_profiles->size(); ++i) {
+ AutofillProfile* profile_to_merge = (*existing_profiles)[i].get();
+
+ // If the profile was set to be deleted, skip it. It has already been
+ // merged into another profile.
+ if (profiles_to_delete->count(profile_to_merge->guid()))
+ continue;
+
+ // If we have reached the verified profiles, stop trying to merge. Verified
+ // profiles do not get merged.
+ if (profile_to_merge->IsVerified())
+ break;
+
+ // If we have not reached the last profile, try to merge |profile_to_merge|
+ // with all the less relevant |existing_profiles|.
+ for (size_t j = i + 1; j < existing_profiles->size(); ++j) {
+ AutofillProfile* existing_profile = (*existing_profiles)[j].get();
+
+ // Don't try to merge a profile that was already set for deletion.
+ if (profiles_to_delete->count(existing_profile->guid()))
+ continue;
+
+ // Move on if the profiles are not mergeable.
+ if (!comparator.AreMergeable(*existing_profile, *profile_to_merge))
+ continue;
+
+ // The profiles are found to be mergeable. Attempt to update the existing
+ // profile. This returns true if the merge was successful, or if the
+ // merge would have been successful but the existing profile IsVerified()
+ // and will not accept updates from profile_to_merge.
+ if (existing_profile->SaveAdditionalInfo(
+ *profile_to_merge, personal_data_manager_->app_locale())) {
+ // Keep track that a credit card using |profile_to_merge|'s GUID as its
+ // billing address id should replace it by |existing_profile|'s GUID.
+ guids_merge_map->emplace(profile_to_merge->guid(),
+ existing_profile->guid());
+
+ // Since |profile_to_merge| was a duplicate of |existing_profile|
+ // and was merged successfully, it can now be deleted.
+ profiles_to_delete->insert(profile_to_merge->guid());
+
+ // Now try to merge the new resulting profile with the rest of the
+ // existing profiles.
+ profile_to_merge = existing_profile;
+
+ // Verified profiles do not get merged. Save some time by not
+ // trying.
+ if (profile_to_merge->IsVerified())
+ break;
+ }
+ }
+ }
+ AutofillMetrics::LogNumberOfProfilesRemovedDuringDedupe(
+ profiles_to_delete->size());
+}
+
+void PersonalDataManagerCleaner::UpdateCardsBillingAddressReference(
+ const std::unordered_map<std::string, std::string>& guids_merge_map) {
+ /* Here is an example of what the graph might look like.
+
+ A -> B
+ \
+ -> E
+ /
+ C -> D
+ */
+
+ std::vector<CreditCard> server_cards_to_be_updated;
+ for (auto* credit_card : personal_data_manager_->GetCreditCards()) {
+ // If the credit card is not associated with a billing address, skip it.
+ if (credit_card->billing_address_id().empty())
+ break;
+
+ // If the billing address profile associated with the card has been merged,
+ // replace it by the id of the profile in which it was merged. Repeat the
+ // process until the billing address has not been merged into another one.
+ std::unordered_map<std::string, std::string>::size_type nb_guid_changes = 0;
+ bool was_modified = false;
+ auto it = guids_merge_map.find(credit_card->billing_address_id());
+ while (it != guids_merge_map.end()) {
+ was_modified = true;
+ credit_card->set_billing_address_id(it->second);
+ it = guids_merge_map.find(credit_card->billing_address_id());
+
+ // Out of abundance of caution.
+ if (nb_guid_changes > guids_merge_map.size()) {
+ NOTREACHED();
+ // Cancel the changes for that card.
+ was_modified = false;
+ break;
+ }
+ }
+
+ // If the card was modified, apply the changes to the database.
+ if (was_modified) {
+ if (credit_card->record_type() == CreditCard::LOCAL_CARD)
+ personal_data_manager_->GetLocalDatabase()->UpdateCreditCard(
+ *credit_card);
+ else
+ server_cards_to_be_updated.push_back(*credit_card);
+ }
+ }
+
+ // In case, there are server cards that need to be updated,
+ // |PersonalDataManager::Refresh()| is called after they are updated.
+ if (server_cards_to_be_updated.empty())
+ personal_data_manager_->Refresh();
+ else
+ personal_data_manager_->UpdateServerCardsMetadata(
+ server_cards_to_be_updated);
+}
+
+bool PersonalDataManagerCleaner::DeleteDisusedAddresses() {
+ const std::vector<AutofillProfile*>& profiles =
+ personal_data_manager_->GetProfiles();
+
+ // Early exit when there are no profiles.
+ if (profiles.empty()) {
+ DVLOG(1) << "There are no profiles";
+ return true;
+ }
+
+ std::unordered_set<std::string> used_billing_address_guids;
+ for (CreditCard* card : personal_data_manager_->GetCreditCards()) {
+ if (!card->IsDeletable()) {
+ used_billing_address_guids.insert(card->billing_address_id());
+ }
+ }
+
+ std::vector<std::string> guids_to_delete;
+ for (AutofillProfile* profile : profiles) {
+ if (profile->IsDeletable() &&
+ !used_billing_address_guids.count(profile->guid())) {
+ guids_to_delete.push_back(profile->guid());
+ }
+ }
+
+ size_t num_deleted_addresses = guids_to_delete.size();
+
+ for (auto const& guid : guids_to_delete) {
+ personal_data_manager_
+ ->RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid);
+ }
+
+ if (num_deleted_addresses > 0) {
+ personal_data_manager_->Refresh();
+ }
+
+ AutofillMetrics::LogNumberOfAddressesDeletedForDisuse(num_deleted_addresses);
+
+ return true;
+}
+
+void PersonalDataManagerCleaner::ClearProfileNonSettingsOrigins() {
+ for (AutofillProfile* profile : personal_data_manager_->GetProfiles()) {
+ if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) {
+ profile->set_origin(std::string());
+ personal_data_manager_->UpdateProfileInDB(*profile, /*enforced=*/true);
+ }
+ }
+}
+
+void PersonalDataManagerCleaner::ClearCreditCardNonSettingsOrigins() {
+ bool has_updated = false;
+
+ for (CreditCard* card : personal_data_manager_->GetLocalCreditCards()) {
+ if (card->origin() != kSettingsOrigin && !card->origin().empty()) {
+ card->set_origin(std::string());
+ personal_data_manager_->GetLocalDatabase()->UpdateCreditCard(*card);
+ has_updated = true;
+ }
+ }
+
+ // Refresh the local cache and send notifications to observers if a changed
+ // was made.
+ if (has_updated)
+ personal_data_manager_->Refresh();
+}
+
+bool PersonalDataManagerCleaner::DeleteDisusedCreditCards() {
+ // Only delete local cards, as server cards are managed by Payments.
+ auto cards = personal_data_manager_->GetLocalCreditCards();
+
+ // Early exit when there is no local cards.
+ if (cards.empty())
+ return true;
+
+ std::vector<CreditCard> cards_to_delete;
+ for (CreditCard* card : cards) {
+ if (card->IsDeletable()) {
+ cards_to_delete.push_back(*card);
+ }
+ }
+
+ size_t num_deleted_cards = cards_to_delete.size();
+
+ if (num_deleted_cards > 0)
+ personal_data_manager_->DeleteLocalCreditCards(cards_to_delete);
+
+ AutofillMetrics::LogNumberOfCreditCardsDeletedForDisuse(num_deleted_cards);
+
+ return true;
+}
+
+void PersonalDataManagerCleaner::AddProfileForTest(
+ const AutofillProfile& profile) {
+ personal_data_manager_->AddProfile(profile);
+}
+
+void PersonalDataManagerCleaner::AddCreditCardForTest(
+ const CreditCard& credit_card) {
+ personal_data_manager_->AddCreditCard(credit_card);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_cleaner.h b/chromium/components/autofill/core/browser/personal_data_manager_cleaner.h
new file mode 100644
index 00000000000..8f970f66254
--- /dev/null
+++ b/chromium/components/autofill/core/browser/personal_data_manager_cleaner.h
@@ -0,0 +1,164 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_CLEANER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_CLEANER_H_
+
+#include <unordered_set>
+
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/test_data_creator.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_updater.h"
+#include "components/sync/base/model_type.h"
+
+class PrefService;
+
+namespace autofill {
+
+class PersonalDataManager;
+
+// PersonalDataManagerCleaner is responsible for applying address and credit
+// card cleanups once on browser startup provided that the sync is enabled or
+// when the sync starts.
+class PersonalDataManagerCleaner {
+ public:
+ PersonalDataManagerCleaner(
+ PersonalDataManager* personal_data_manager,
+ AlternativeStateNameMapUpdater* alternative_state_name_map_updater,
+ PrefService* pref_service);
+ ~PersonalDataManagerCleaner();
+ PersonalDataManagerCleaner(const PersonalDataManagerCleaner&) = delete;
+ PersonalDataManagerCleaner& operator=(const PersonalDataManagerCleaner&) =
+ delete;
+
+ // Applies address and credit card fixes and cleanups if the sync is enabled.
+ // Also, logs address, credit card and offer startup metrics.
+ void CleanupDataAndNotifyPersonalDataObservers();
+
+ // Applies address/credit card fixes and cleanups depending on the
+ // |model_type|.
+ void SyncStarted(syncer::ModelType model_type);
+
+#if defined(UNIT_TEST)
+ // A wrapper around |ApplyDedupingRoutine()| used for testing purposes.
+ bool ApplyDedupingRoutineForTesting() { return ApplyDedupingRoutine(); }
+
+ // A wrapper around |DedupeProfiles()| used for testing purposes.
+ void DedupeProfilesForTesting(
+ std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
+ std::unordered_set<std::string>* profile_guids_to_delete,
+ std::unordered_map<std::string, std::string>* guids_merge_map) const {
+ DedupeProfiles(existing_profiles, profile_guids_to_delete, guids_merge_map);
+ }
+
+ // A wrapper around |UpdateCardsBillingAddressReference()| used for testing
+ // purposes.
+ void UpdateCardsBillingAddressReferenceForTesting(
+ const std::unordered_map<std::string, std::string>& guids_merge_map) {
+ UpdateCardsBillingAddressReference(guids_merge_map);
+ }
+
+ // A wrapper around |DeleteDisusedAddresses()| used for testing purposes.
+ bool DeleteDisusedAddressesForTesting() { return DeleteDisusedAddresses(); }
+
+ // A wrapper around |DeleteDisusedCreditCards()| used for testing purposes.
+ bool DeleteDisusedCreditCardsForTesting() {
+ return DeleteDisusedCreditCards();
+ }
+
+ // A wrapper around |ClearProfileNonSettingsOrigins()| used for testing
+ // purposes.
+ void ClearProfileNonSettingsOriginsForTesting() {
+ ClearProfileNonSettingsOrigins();
+ }
+
+ // A wrapper around |ClearCreditCardNonSettingsOrigins()| used for testing
+ // purposes.
+ void ClearCreditCardNonSettingsOriginsForTesting() {
+ ClearCreditCardNonSettingsOrigins();
+ }
+#endif // defined(UNIT_TEST)
+
+ private:
+ // Applies various fixes and cleanups on autofill addresses.
+ void ApplyAddressFixesAndCleanups();
+
+ // Applies various fixes and cleanups on autofill credit cards.
+ void ApplyCardFixesAndCleanups();
+
+ // Runs the routine that removes the orphan rows in the autofill tables if
+ // it's never been done.
+ void RemoveOrphanAutofillTableRows();
+
+ // Applies the deduping routine once per major version if the feature is
+ // enabled. Calls DedupeProfiles with the content of
+ // |PersonalDataManager::GetProfiles()| as a parameter. Removes the profiles
+ // to delete from the database and updates the others. Also updates the credit
+ // cards billing address references. Returns true if the routine was run.
+ bool ApplyDedupingRoutine();
+
+ // Goes through all the |existing_profiles| and merges all similar unverified
+ // profiles together. Also discards unverified profiles that are similar to a
+ // verified profile. All the profiles except the results of the merges will be
+ // added to |profile_guids_to_delete|. This routine should be run once per
+ // major version. Records all the merges into the |guids_merge_map|.
+ //
+ // This method should only be called by ApplyDedupingRoutine. It is split for
+ // testing purposes.
+ void DedupeProfiles(
+ std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
+ std::unordered_set<std::string>* profile_guids_to_delete,
+ std::unordered_map<std::string, std::string>* guids_merge_map) const;
+
+ // Updates the credit cards billing address references based on the merges
+ // that happened during the dedupe, as defined in |guids_merge_map|. Also
+ // updates the cards entries in the database.
+ void UpdateCardsBillingAddressReference(
+ const std::unordered_map<std::string, std::string>& guids_merge_map);
+
+ // Tries to delete disused addresses once per major version if the
+ // feature is enabled.
+ bool DeleteDisusedAddresses();
+
+ // Tries to delete disused credit cards once per major version if the
+ // feature is enabled.
+ bool DeleteDisusedCreditCards();
+
+ // Clears the value of the origin field of the autofill profiles or cards that
+ // were not created from the settings page.
+ void ClearProfileNonSettingsOrigins();
+ void ClearCreditCardNonSettingsOrigins();
+
+ // Used for adding test data by |test_data_creator_|.
+ void AddProfileForTest(const AutofillProfile& profile);
+ void AddCreditCardForTest(const CreditCard& credit_card);
+
+ // True if autofill profile cleanup needs to be performed.
+ bool is_autofill_profile_cleanup_pending_ = false;
+
+ // Used to create test data. If the AutofillCreateDataForTest feature is
+ // enabled, this helper creates autofill profiles and credit card data that
+ // would otherwise be difficult to create manually using the UI.
+ TestDataCreator test_data_creator_;
+
+ // The personal data manager, used to load and update the personal data
+ // from/to the web database.
+ PersonalDataManager* const personal_data_manager_ = nullptr;
+
+ // The PrefService used by this instance.
+ PrefService* const pref_service_ = nullptr;
+
+ // The AlternativeStateNameMapUpdater, used to populate
+ // AlternativeStateNameMap with the geographical state data.
+ AlternativeStateNameMapUpdater* const alternative_state_name_map_updater_ =
+ nullptr;
+
+ // base::WeakPtr ensures that the callback bound to the object is canceled
+ // when that object is destroyed.
+ base::WeakPtrFactory<PersonalDataManagerCleaner> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_CLEANER_H_
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
index 99b095478df..70d5a739895 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -31,11 +31,13 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
@@ -68,6 +70,11 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
+
+using structured_address::HonorificPrefixEnabled;
+using structured_address::StructuredAddressesEnabled;
+using structured_address::StructuredNamesEnabled;
+
namespace {
const char kPrimaryAccountEmail[] = "syncuser@example.com";
@@ -83,15 +90,6 @@ ACTION_P(QuitMessageLoop, loop) {
loop->Quit();
}
-bool StructuredNames() {
- return base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames);
-}
-
-bool StructuredAddress() {
- return base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInAddresses);
-}
class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
public:
@@ -240,7 +238,7 @@ class PersonalDataManagerTestBase {
features::kAutofillEnableAccountWalletStorage)
? scoped_refptr<AutofillWebDataService>(account_database_service_)
: nullptr,
- prefs_.get(), identity_test_env_.identity_manager(),
+ prefs_.get(), prefs_.get(), identity_test_env_.identity_manager(),
TestAutofillProfileValidator::GetInstance(),
/*history_service=*/nullptr, is_incognito);
@@ -369,10 +367,6 @@ class PersonalDataManagerHelper : public PersonalDataManagerTestBase {
return PersonalDataManagerTestBase::TurnOnSyncFeature(personal_data_.get());
}
- void EnableAutofillProfileCleanup() {
- personal_data_->is_autofill_profile_cleanup_pending_ = true;
- }
-
void SetUpReferenceProfile(const AutofillProfile& profile) {
ASSERT_EQ(0U, personal_data_->GetProfiles().size());
@@ -449,7 +443,9 @@ class PersonalDataManagerHelper : public PersonalDataManagerTestBase {
// Cards are automatically remasked on Linux since full server cards are not
// supported.
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
personal_data_->ResetFullServerCard(
personal_data_->GetCreditCards()[0]->guid());
#endif
@@ -580,7 +576,7 @@ class PersonalDataManagerMigrationTest : public PersonalDataManagerHelper,
public:
PersonalDataManagerMigrationTest()
: PersonalDataManagerHelper(
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
{ ::switches::kAccountIdMigration }
#endif
) {
@@ -603,7 +599,6 @@ class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
personal_data_->pref_service_->SetInteger(
prefs::kAutofillLastVersionValidated,
atoi(version_info::GetVersionNumber().c_str()));
- personal_data_->is_autofill_profile_cleanup_pending_ = true;
}
void TearDown() override {
@@ -885,6 +880,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_CrazyCharacters) {
base::WideToUTF16(L"861088828000"));
profile1.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY),
base::WideToUTF16(L"India"), "en-US");
+ profile1.FinalizeAfterImport();
profiles.push_back(profile1);
AutofillProfile profile2;
@@ -894,11 +890,13 @@ TEST_F(PersonalDataManagerTest, AddProfile_CrazyCharacters) {
L"\u8def1915\u53f7"));
profile2.SetRawInfo(NAME_LAST, base::WideToUTF16(L"aguantó"));
profile2.SetRawInfo(ADDRESS_HOME_ZIP, base::WideToUTF16(L"HOME 94043"));
+ profile2.FinalizeAfterImport();
profiles.push_back(profile2);
AutofillProfile profile3;
profile3.SetRawInfo(EMAIL_ADDRESS, base::WideToUTF16(L"sue@example.com"));
profile3.SetRawInfo(COMPANY_NAME, base::WideToUTF16(L"Company X"));
+ profile3.FinalizeAfterImport();
profiles.push_back(profile3);
AutofillProfile profile4;
@@ -917,6 +915,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_CrazyCharacters) {
L"\u0905\u092a\u094b\u0932\u094b "
L"\u091f\u093e\u092f\u0930\u094d\u0938 "
L"\u0906\u0926\u093f"));
+ profile4.FinalizeAfterImport();
profiles.push_back(profile4);
AutofillProfile profile5;
@@ -928,6 +927,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_CrazyCharacters) {
base::WideToUTF16(L"111111111111110000GOOGLE"));
profile5.SetRawInfo(EMAIL_ADDRESS, base::WideToUTF16(L"page@000000.com"));
profile5.SetRawInfo(COMPANY_NAME, base::WideToUTF16(L"Google"));
+ profile5.FinalizeAfterImport();
profiles.push_back(profile5);
AutofillProfile profile6;
@@ -944,6 +944,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_CrazyCharacters) {
L"\u064a \u0639\u0645\u0631 "
L"\u0627\u0644\u0628\u0634\u064a\u0631"));
profile6.SetRawInfo(ADDRESS_HOME_ZIP, base::WideToUTF16(L"HOME 94043"));
+ profile6.FinalizeAfterImport();
profiles.push_back(profile6);
AutofillProfile profile7;
@@ -960,6 +961,7 @@ TEST_F(PersonalDataManagerTest, AddProfile_CrazyCharacters) {
base::WideToUTF16(L"15466784565"));
profile7.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY),
base::WideToUTF16(L"United States"), "en-US");
+ profile7.FinalizeAfterImport();
profiles.push_back(profile7);
personal_data_->SetProfiles(&profiles);
@@ -1403,7 +1405,7 @@ TEST_F(PersonalDataManagerTest, KeepExistingLocalDataOnSignIn) {
/*disabled_features=*/{});
// ClearPrimaryAccount is not supported on CrOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Sign out.
identity_test_env_.ClearPrimaryAccount();
EXPECT_EQ(AutofillSyncSigninState::kSignedOut,
@@ -1739,25 +1741,27 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
// For structured names and addresses, there are more non-empty types.
// TODO(crbug.com/1103421): Clean once launched.
unsigned int non_empty_types_expectation = 15;
- if (StructuredNames())
+ if (StructuredNamesEnabled())
non_empty_types_expectation += 1;
// TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddress())
+ if (StructuredAddressesEnabled())
non_empty_types_expectation += 2;
+ if (HonorificPrefixEnabled())
+ non_empty_types_expectation += 1;
EXPECT_EQ(non_empty_types_expectation, non_empty_types.size());
EXPECT_TRUE(non_empty_types.count(NAME_FIRST));
EXPECT_TRUE(non_empty_types.count(NAME_LAST));
// TODO(crbug.com/1103421): Clean once launched.
- if (StructuredNames())
+ if (StructuredNamesEnabled())
EXPECT_TRUE(non_empty_types.count(NAME_LAST_SECOND));
EXPECT_TRUE(non_empty_types.count(NAME_FULL));
EXPECT_TRUE(non_empty_types.count(EMAIL_ADDRESS));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE1));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_ADDRESS));
// TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddress()) {
+ if (StructuredAddressesEnabled()) {
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_NAME));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_HOUSE_NUMBER));
}
@@ -1791,17 +1795,19 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
non_empty_types_expectation = 19;
// For structured names, there is one more non-empty type.
// TODO(crbug.com/1103421): Clean once launched.
- if (StructuredNames())
+ if (StructuredNamesEnabled())
+ non_empty_types_expectation += 1;
+ if (HonorificPrefixEnabled())
non_empty_types_expectation += 1;
// TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddress())
+ if (StructuredAddressesEnabled())
non_empty_types_expectation += 2;
EXPECT_EQ(non_empty_types_expectation, non_empty_types.size());
EXPECT_TRUE(non_empty_types.count(NAME_FIRST));
EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE));
EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE_INITIAL));
// TODO(crbug.com/1103421): Clean once launched.
- if (StructuredNames())
+ if (StructuredNamesEnabled())
EXPECT_TRUE(non_empty_types.count(NAME_LAST));
EXPECT_TRUE(non_empty_types.count(NAME_FULL));
EXPECT_TRUE(non_empty_types.count(EMAIL_ADDRESS));
@@ -1810,7 +1816,7 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE2));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_ADDRESS));
// TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddress()) {
+ if (StructuredAddressesEnabled()) {
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_NAME));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_HOUSE_NUMBER));
}
@@ -1837,10 +1843,12 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
// For structured names, there is one more non-empty type.
// TODO(crbug.com/1103421): Clean once launched.
non_empty_types_expectation = 29;
- if (StructuredNames())
+ if (StructuredNamesEnabled())
+ non_empty_types_expectation += 1;
+ if (HonorificPrefixEnabled())
non_empty_types_expectation += 1;
// TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddress())
+ if (StructuredAddressesEnabled())
non_empty_types_expectation += 2;
EXPECT_EQ(non_empty_types_expectation, non_empty_types.size());
EXPECT_TRUE(non_empty_types.count(NAME_FIRST));
@@ -1848,7 +1856,7 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE_INITIAL));
EXPECT_TRUE(non_empty_types.count(NAME_LAST));
EXPECT_TRUE(non_empty_types.count(NAME_FULL));
- if (StructuredNames())
+ if (StructuredNamesEnabled())
EXPECT_TRUE(non_empty_types.count(NAME_LAST));
EXPECT_TRUE(non_empty_types.count(EMAIL_ADDRESS));
EXPECT_TRUE(non_empty_types.count(COMPANY_NAME));
@@ -1856,7 +1864,7 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE2));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_ADDRESS));
// TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddress()) {
+ if (StructuredAddressesEnabled()) {
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_NAME));
EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_HOUSE_NUMBER));
}
@@ -3524,8 +3532,7 @@ TEST_F(PersonalDataManagerTest,
server_cards.push_back(credit_card1);
server_cards.push_back(credit_card2);
SetServerCards(server_cards);
- personal_data_->UpdateServerCardMetadata(credit_card1);
- personal_data_->UpdateServerCardMetadata(credit_card2);
+ personal_data_->UpdateServerCardsMetadata({credit_card1, credit_card2});
// Add an expired local card last used 180 days ago.
CreditCard credit_card3("1141084B-72D7-4B73-90CF-3D6AC154673B",
@@ -3917,18 +3924,21 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) {
TestAutofillClock test_clock;
test_clock.SetNow(kArbitraryTime);
+ auto Check = [](const AutofillDataModel& data_model, size_t use_count,
+ base::Time use_date, base::Time modification_date) {
+ EXPECT_EQ(use_count, data_model.use_count());
+ EXPECT_EQ(use_date, data_model.use_date());
+ EXPECT_EQ(modification_date, data_model.modification_date());
+ };
+
AutofillProfile profile(test::GetFullProfile());
- EXPECT_EQ(1U, profile.use_count());
- EXPECT_EQ(kArbitraryTime, profile.use_date());
- EXPECT_EQ(kArbitraryTime, profile.modification_date());
+ Check(profile, 1u, kArbitraryTime, kArbitraryTime);
AddProfileToPersonalDataManager(profile);
CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
- EXPECT_EQ(1U, credit_card.use_count());
- EXPECT_EQ(kArbitraryTime, credit_card.use_date());
- EXPECT_EQ(kArbitraryTime, credit_card.modification_date());
+ Check(credit_card, 1u, kArbitraryTime, kArbitraryTime);
personal_data_->AddCreditCard(credit_card);
// Make sure everything is set up correctly.
@@ -3943,40 +3953,43 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) {
personal_data_->GetProfileByGUID(profile.guid());
ASSERT_TRUE(added_profile);
EXPECT_EQ(*added_profile, profile);
- EXPECT_EQ(1U, added_profile->use_count());
- EXPECT_EQ(kArbitraryTime, added_profile->use_date());
- EXPECT_EQ(kArbitraryTime, added_profile->modification_date());
-
- base::RunLoop run_loop;
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillOnce(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
-
- personal_data_->RecordUseOf(profile);
-
- run_loop.Run();
+ Check(*added_profile, 1u, kArbitraryTime, kArbitraryTime);
CreditCard* added_card =
personal_data_->GetCreditCardByGUID(credit_card.guid());
ASSERT_TRUE(added_card);
EXPECT_EQ(*added_card, credit_card);
- EXPECT_EQ(1U, added_card->use_count());
- EXPECT_EQ(kArbitraryTime, added_card->use_date());
- EXPECT_EQ(kArbitraryTime, added_card->modification_date());
- personal_data_->RecordUseOf(credit_card);
+ Check(*added_card, 1u, kArbitraryTime, kArbitraryTime);
+
+ // Use |profile|, then verify usage stats.
+ base::RunLoop profile_run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&profile_run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ personal_data_->RecordUseOf(&profile);
+ profile_run_loop.Run();
- // Verify usage stats are updated.
added_profile = personal_data_->GetProfileByGUID(profile.guid());
+ added_card = personal_data_->GetCreditCardByGUID(credit_card.guid());
ASSERT_TRUE(added_profile);
- EXPECT_EQ(2U, added_profile->use_count());
- EXPECT_EQ(kSomeLaterTime, added_profile->use_date());
- EXPECT_EQ(kArbitraryTime, added_profile->modification_date());
+ ASSERT_TRUE(added_card);
+ Check(*added_profile, 2u, kSomeLaterTime, kArbitraryTime);
+ Check(*added_card, 1u, kArbitraryTime, kArbitraryTime);
+
+ // Use |credit_card|, then verify usage stats.
+ base::RunLoop credit_card_run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&credit_card_run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ personal_data_->RecordUseOf(&credit_card);
+ credit_card_run_loop.Run();
+ added_profile = personal_data_->GetProfileByGUID(profile.guid());
added_card = personal_data_->GetCreditCardByGUID(credit_card.guid());
+ ASSERT_TRUE(added_profile);
ASSERT_TRUE(added_card);
- EXPECT_EQ(2U, added_card->use_count());
- EXPECT_EQ(kSomeLaterTime, added_card->use_date());
- EXPECT_EQ(kArbitraryTime, added_card->modification_date());
+ Check(*added_profile, 2u, kSomeLaterTime, kArbitraryTime);
+ Check(*added_card, 2u, kSomeLaterTime, kArbitraryTime);
}
TEST_F(PersonalDataManagerTest, ClearAllServerData) {
@@ -4068,8 +4081,6 @@ class SaveImportedProfileTest
}
}
- bool StructuredNames() const { return structured_names_enabled_; }
-
private:
bool structured_names_enabled_;
base::test::ScopedFeatureList scoped_features_;
@@ -4143,9 +4154,10 @@ TEST_P(SaveImportedProfileTest, SaveImportedProfile) {
// date were properly updated.
EXPECT_EQ(1U, saved_profiles.front()->use_count());
EXPECT_EQ(kSomeLaterTime, saved_profiles.front()->use_date());
- // For structured names, the modification date is only updated when the
+
+ // For structured addresses, the modification date is only updated when the
// profile actually changes.
- if (StructuredNames()) {
+ if (StructuredNamesEnabled() || StructuredAddressesEnabled()) {
EXPECT_EQ(*saved_profiles.front() == original_profile ? kArbitraryTime
: kSomeLaterTime,
saved_profiles.front()->modification_date());
@@ -4591,13 +4603,11 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4));
existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5));
- // Enable the profile cleanup.
- EnableAutofillProfileCleanup();
-
base::HistogramTester histogram_tester;
std::unordered_map<std::string, std::string> guids_merge_map;
std::unordered_set<std::string> profiles_to_delete;
- personal_data_->DedupeProfiles(&existing_profiles, &profiles_to_delete,
+ personal_data_->personal_data_manager_cleaner_for_testing()
+ ->DedupeProfilesForTesting(&existing_profiles, &profiles_to_delete,
&guids_merge_map);
// 5 profiles were considered for dedupe.
histogram_tester.ExpectUniqueSample(
@@ -4676,13 +4686,11 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4));
existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5));
- // Enable the profile cleanup.
- EnableAutofillProfileCleanup();
-
std::unordered_map<std::string, std::string> guids_merge_map;
std::unordered_set<std::string> profiles_to_delete;
- personal_data_->DedupeProfiles(&existing_profiles, &profiles_to_delete,
+ personal_data_->personal_data_manager_cleaner_for_testing()
+ ->DedupeProfilesForTesting(&existing_profiles, &profiles_to_delete,
&guids_merge_map);
// The two profile merges should be recorded in the map.
@@ -4739,7 +4747,8 @@ TEST_F(PersonalDataManagerTest, UpdateCardsBillingAddressReference) {
personal_data_->server_credit_cards_.push_back(
std::unique_ptr<CreditCard>(credit_card4));
- personal_data_->UpdateCardsBillingAddressReference(guids_merge_map);
+ personal_data_->personal_data_manager_cleaner_for_testing()
+ ->UpdateCardsBillingAddressReferenceForTesting(guids_merge_map);
// The first card's billing address should now be E.
EXPECT_EQ("E", credit_card1->billing_address_id());
@@ -4755,6 +4764,9 @@ TEST_F(PersonalDataManagerTest, UpdateCardsBillingAddressReference) {
// based on the deduped profiles.
TEST_F(PersonalDataManagerTest,
ApplyDedupingRoutine_CardsBillingAddressIdUpdated) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// A set of 6 profiles will be created. They should merge in this way:
// 1 -> 2 -> 3
// 4 -> 5
@@ -4856,11 +4868,8 @@ TEST_F(PersonalDataManagerTest,
EXPECT_EQ(6U, personal_data_->GetProfiles().size());
EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
// Get the profiles and cards sorted by frecency to have a deterministic
@@ -4895,6 +4904,9 @@ TEST_F(PersonalDataManagerTest,
// never lose information and keep the syntax of the profile with the higher
// frecency score.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a profile with a higher frecency score.
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
@@ -4926,13 +4938,10 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
// Make sure the 3 profiles were saved;
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
base::HistogramTester histogram_tester;
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -4983,11 +4992,16 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
// original data when deduping with similar profiles, even if it has a higher
// frecency score.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a verified profile with a higher frecency score.
AutofillProfile profile1(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(&profile1, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
+ test::SetProfileInfo(
+ &profile1, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
+ "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
+ "12345678910", /*finalize=*/true,
+ /*status=*/structured_address::VerificationStatus::kUserVerified);
profile1.set_use_count(7);
profile1.set_use_date(kMuchLaterTime);
@@ -5014,13 +5028,10 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
// Make sure the 3 profiles were saved.
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
base::HistogramTester histogram_tester;
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5036,6 +5047,13 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
histogram_tester.ExpectUniqueSample(
"Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
+ // Although the profile was verified, the structure of the street address
+ // still evolved with future observations. In this case, the "." was added
+ // from a later observation.
+ profile1.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, base::UTF8ToUTF16("Evergreen Terrace"),
+ structured_address::VerificationStatus::kParsed);
+ //
// Only the verified |profile1| with its original data should have been kept.
EXPECT_EQ(profile1.guid(), profiles[0]->guid());
EXPECT_TRUE(profile1 == *profiles[0]);
@@ -5047,6 +5065,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
// original data when deduping with similar profiles, even if it has a lower
// frecency score.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a profile to dedupe with a higher frecency score.
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
@@ -5065,9 +5086,11 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
// Create a similar verified profile with a lower frecency score.
AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(&profile3, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
+ test::SetProfileInfo(
+ &profile3, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
+ "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
+ "12345678910", /*finalize=*/true,
+ /*status=*/structured_address::VerificationStatus::kUserVerified);
profile3.set_use_count(3);
profile3.set_use_date(kArbitraryTime);
@@ -5078,13 +5101,10 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
// Make sure the 3 profiles were saved.
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
base::HistogramTester histogram_tester;
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5110,6 +5130,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
// Tests that ApplyDedupingRoutine does not merge unverified data into
// a verified profile. Also tests that two verified profiles don't get merged.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a profile to dedupe with a higher frecency score.
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
@@ -5120,17 +5143,22 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
// Create a similar verified profile with a medium frecency score.
AutofillProfile profile2(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
+ test::SetProfileInfo(
+ &profile2, "Homer", "J", "Simpson", "homer.simpson@abc.com", "Fox",
+ "742 Evergreen Terrace.", "", "Springfield", "IL", "91601", "", "",
+ /*finalize=*/true,
+ /*status=*/structured_address::VerificationStatus::kUserVerified);
+
profile2.set_use_count(5);
profile2.set_use_date(kSomeLaterTime);
// Create a similar verified profile with a lower frecency score.
AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(&profile3, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
+ test::SetProfileInfo(
+ &profile3, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
+ "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
+ "12345678910", /*finalize=*/true,
+ /*status*/ structured_address::VerificationStatus::kUserVerified);
profile3.set_use_count(3);
profile3.set_use_date(kArbitraryTime);
@@ -5141,19 +5169,23 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
// Make sure the 3 profiles were saved.
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
base::HistogramTester histogram_tester;
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
// Get the profiles, sorted by frecency to have a deterministic order.
std::vector<AutofillProfile*> profiles =
personal_data_->GetProfilesToSuggest();
+ // Although the profile was verified, the structure of the street address
+ // still evolved with future observations. In this case, the "." was removed
+ // from a later observation.
+ profile2.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, base::UTF8ToUTF16("Evergreen Terrace"),
+ structured_address::VerificationStatus::kParsed);
+
// |profile1| should have been discarded because the saved profile with the
// highest frecency score is verified (|profile2|). Therefore, |profile1|'s
// data should not have been merged with |profile2|'s data. Then |profile2|
@@ -5183,6 +5215,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
// that the resulting profiles have the right values, has no effect on the other
// profiles and that the data of verified profiles is not modified.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a Homer home profile with a higher frecency score than other Homer
// profiles.
AutofillProfile Homer1(base::GenerateGUID(), test::kEmptyOrigin);
@@ -5256,16 +5291,13 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// Make sure the 7 profiles were saved;
EXPECT_EQ(7U, personal_data_->GetProfiles().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
base::HistogramTester histogram_tester;
// |Homer1| should get merged into |Homer2| which should then be merged into
// |Homer3|. |Marge2| should be discarded in favor of |Marge1| which is
// verified. |Homer4| and |Barney| should not be deduped at all.
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
// Get the profiles, sorted by frecency to have a deterministic order.
@@ -5320,40 +5352,18 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
EXPECT_TRUE(Barney == *profiles[3]);
}
-// Tests that ApplyDedupingRoutine is not run if the feature is disabled.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_FeatureDisabled) {
- // Create a profile to dedupe.
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
-
- // Create a similar profile.
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
-
- // Make sure both profiles were saved.
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-
- // The deduping routine should not be run.
- EXPECT_FALSE(personal_data_->ApplyDedupingRoutine());
-
- // Both profiles should still be present.
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-}
-
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfZeroProfiles) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
EXPECT_TRUE(personal_data_->GetProfiles().empty());
- EnableAutofillProfileCleanup();
- EXPECT_FALSE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_FALSE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
}
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a profile to dedupe.
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Homer", "J", "Simpson",
@@ -5363,16 +5373,16 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
AddProfileToPersonalDataManager(profile);
EXPECT_EQ(1U, personal_data_->GetProfiles().size());
-
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
- EXPECT_FALSE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_FALSE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
}
// Tests that ApplyDedupingRoutine is not run a second time on the same major
// version.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
// Create a profile to dedupe.
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
@@ -5390,12 +5400,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
- // Enable the profile cleanup now. Otherwise it would be triggered by the
- // calls to AddProfile.
- EnableAutofillProfileCleanup();
-
// The deduping routine should be run a first time.
- EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5414,11 +5421,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
// Make sure |profile3| was saved.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
- // Re-enable the profile cleanup now that the profile was added.
- EnableAutofillProfileCleanup();
-
// The deduping routine should not be run.
- EXPECT_FALSE(personal_data_->ApplyDedupingRoutine());
+ EXPECT_FALSE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ApplyDedupingRoutineForTesting());
// The two duplicate profiles should still be present.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -5493,7 +5498,8 @@ TEST_F(PersonalDataManagerTest,
EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
// DeleteDisusedAddresses should return true.
- EXPECT_TRUE(personal_data_->DeleteDisusedAddresses());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->DeleteDisusedAddressesForTesting());
WaitForOnPersonalDataChanged();
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -5571,8 +5577,7 @@ TEST_F(PersonalDataManagerTest,
server_cards.push_back(credit_card5);
server_cards.push_back(credit_card6);
SetServerCards(server_cards);
- personal_data_->UpdateServerCardMetadata(credit_card5);
- personal_data_->UpdateServerCardMetadata(credit_card6);
+ personal_data_->UpdateServerCardsMetadata({credit_card5, credit_card6});
WaitForOnPersonalDataChanged();
EXPECT_EQ(6U, personal_data_->GetCreditCards().size());
@@ -5581,7 +5586,8 @@ TEST_F(PersonalDataManagerTest,
base::HistogramTester histogram_tester;
// DeleteDisusedCreditCards should return true to indicate it was run.
- EXPECT_TRUE(personal_data_->DeleteDisusedCreditCards());
+ EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
+ ->DeleteDisusedCreditCardsForTesting());
// Wait for the data to be refreshed.
WaitForOnPersonalDataChanged();
@@ -5670,7 +5676,7 @@ TEST_F(PersonalDataManagerTest,
// Wallet only provides a full name, so the above first and last names
// will be ignored when the profile is written to the DB.
- if (!StructuredNames()) {
+ if (!StructuredNamesEnabled()) {
server_profiles.back().SetRawInfo(NAME_FULL,
base::ASCIIToUTF16("John Doe"));
}
@@ -5910,7 +5916,7 @@ TEST_F(
// Wallet only provides a full name, so the above first and last names
// will be ignored when the profile is written to the DB.
// This step happens automatically for structured names.
- if (!StructuredNames()) {
+ if (!StructuredNamesEnabled()) {
server_profiles.back().SetRawInfo(NAME_FULL,
base::ASCIIToUTF16("John Doe"));
}
@@ -6621,7 +6627,9 @@ TEST_F(PersonalDataManagerTest, CreateDataForTest) {
// These tests are not applicable on Linux since it does not support full server
// cards.
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// Test that calling OnSyncServiceInitialized with a null sync service remasks
// full server cards.
TEST_F(PersonalDataManagerTest, OnSyncServiceInitialized_NoSyncService) {
@@ -6670,7 +6678,7 @@ TEST_F(PersonalDataManagerTest, OnSyncServiceInitialized_NotActiveSyncService) {
// OnSyncServiceInitialized.
personal_data_->OnSyncShutdown(&sync_service);
}
-#endif // !defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
#if !defined(OS_ANDROID)
TEST_F(PersonalDataManagerTest, ExcludeServerSideCards) {
@@ -6752,8 +6760,8 @@ TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode_NeedOptIn) {
EXPECT_EQ(1U, personal_data_->GetLocalCreditCards().size());
EXPECT_EQ(2U, personal_data_->GetServerCreditCards().size());
}
-#endif // defined(OS_WIN) || defined(OS_MAC) ||
- // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) ||
+ // defined(OS_CHROMEOS)
// Tests that all the non settings origins of autofill profiles are cleared but
// that the settings origins are untouched.
@@ -6800,7 +6808,8 @@ TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) {
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.Times(2); // The setting of profiles 0 and 2 will be cleared.
- personal_data_->ClearProfileNonSettingsOrigins();
+ personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ClearProfileNonSettingsOriginsForTesting();
run_loop.Run();
ASSERT_EQ(4U, personal_data_->GetProfiles().size());
@@ -6850,7 +6859,8 @@ TEST_F(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins) {
WaitForOnPersonalDataChanged();
ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
- personal_data_->ClearCreditCardNonSettingsOrigins();
+ personal_data_->personal_data_manager_cleaner_for_testing()
+ ->ClearCreditCardNonSettingsOriginsForTesting();
WaitForOnPersonalDataChanged();
ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
@@ -7005,7 +7015,7 @@ TEST_F(PersonalDataManagerTest, UseCorrectStorageForDifferentCards) {
// Set server card metadata.
server_card.set_use_count(15);
- personal_data_->UpdateServerCardMetadata(server_card);
+ personal_data_->UpdateServerCardsMetadata({server_card});
WaitForOnPersonalDataChanged();
@@ -7477,7 +7487,7 @@ TEST_F(PersonalDataManagerMigrationTest,
}
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_IOS) && !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// The method should return false if one of these is not respected:
// * The sync_service is not null
@@ -7590,7 +7600,8 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
histogram_tester.ExpectTotalCount(kHistogramName, 0);
}
}
-#else // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#else // !defined(OS_ANDROID) && !defined(OS_IOS) &&
+ // !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// The method should return false if one of these is not respected:
// * The sync_service is not null
@@ -7664,7 +7675,8 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
personal_data_->SetSyncServiceForTest(nullptr);
EXPECT_FALSE(personal_data_->ShouldShowCardsFromAccountOption());
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#endif // !defined(OS_ANDROID) && !defined(OS_IOS) &&
+ // !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// Make a non-primary account available with both a refresh token and cookie
@@ -7713,7 +7725,7 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
}
// ClearPrimaryAccount is not supported on CrOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Check that the sync state is |SignedOut| when the account info is empty.
{
identity_test_env_.ClearPrimaryAccount();
@@ -7728,7 +7740,7 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
sync_service_.SetAuthenticatedAccountInfo(primary_account_info);
sync_service_.SetIsAuthenticatedAccountPrimary(true);
// MakePrimaryAccountAvailable is not supported on CrOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
identity_test_env_.MakePrimaryAccountAvailable(primary_account_info.email);
#endif
@@ -7771,7 +7783,7 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
// Account wallet storage only makes sense together with support for
// unconsented primary accounts, i.e. on Win/Mac/Linux.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
{
base::test::ScopedFeatureList scoped_features;
scoped_features.InitAndEnableFeature(
@@ -7830,7 +7842,7 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
EXPECT_FALSE(prefs::IsUserOptedInWalletSyncTransport(
prefs_.get(), active_info.account_id));
}
-#endif // !defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
///////////////////////////////////////////////////////////
// kSignedInAndSyncFeature
@@ -7947,16 +7959,6 @@ class PersonalDataManagerTestForSharingNickname
base::string16 local_nickname_;
base::string16 server_nickname_;
base::string16 expected_nickname_;
-
- protected:
- void SetUp() override {
- PersonalDataManagerTest::SetUp();
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableCardNicknameManagement);
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(,
diff --git a/chromium/components/autofill/core/browser/proto/api_v1.proto b/chromium/components/autofill/core/browser/proto/api_v1.proto
index 0b26c68c576..f0b2cf17214 100644
--- a/chromium/components/autofill/core/browser/proto/api_v1.proto
+++ b/chromium/components/autofill/core/browser/proto/api_v1.proto
@@ -65,12 +65,14 @@ message AutofillPageQueryRequest {
message AutofillQueryResponse {
// Next ID: 2
message FormSuggestion {
- // Next ID: 6
+ // Next ID: 7
message FieldSuggestion {
// Prediction made on a field.
message FieldPrediction {
// The predicted field type.
optional int32 type = 1;
+ // Indicates if the prediction is an override.
+ optional bool override = 2 [default = false];
}
// Signature identifying the field that is the same as in the request.
optional fixed32 field_signature = 1;
@@ -85,6 +87,8 @@ message AutofillQueryResponse {
// For fields of type NEW_PASSWORD and ACCOUNT_CREATION_PASSWORD, this may
// specify requirements for the generation of passwords.
optional .autofill.PasswordRequirementsSpec password_requirements = 5;
+ // Indicates that the primary prediction is an override.
+ optional bool primary_type_prediction_is_override = 6 [default = false];
};
// Suggestions on the fields in the same form.
repeated FieldSuggestion field_suggestions = 1;
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index ea2d2a5f4b8..b84518378d1 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -229,7 +229,7 @@ message AutofillUploadContents {
// The secondary form signature is calculated based on field types instead of
// names and is used if the primary one is unstable, i.e. the field names
- // change on every page load.
+ // change on every page load. Not used currently.
optional fixed64 secondary_form_signature = 34;
// True if the autofill feature was used to fill this form, false otherwise.
@@ -329,13 +329,14 @@ message AutofillUploadContents {
message AutofillTypeValiditiesPair {
// Type of the field, e.g. what type of personal data the user entered in
// that field before form submission. A list of all data types can be
- // found in:
+ // found in: components/autofill/core/browser/field_types.h
required int32 type = 1;
// The validity of the type, which is determined based on the validity of
// the user's profile data. A list of all validity states can be found
- // here: components/autofill/core/browser/field_types.h
+ // here: components/autofill/core/browser/data_model/autofill_data_model.h
// The validity state of a type is used to experiment if only using valid
// data would result in better predictions.
+ // TODO(crbug.com/1174203): Remove the validity.
repeated int32 validity = 2;
}
// A list of possible types for the field with their corresponding validity
@@ -350,9 +351,9 @@ message AutofillUploadContents {
// Signature of the form action host (e.g. Hash64Bit("example.com")).
optional fixed64 action_signature = 13;
- // Signature of the form which is used for password generation debugging.
- // Currently is used when password generated on a password field of a
- // registration form is used on a password field of a login form.
+ // Signature of the form. This is currently used when password generated on a
+ // password field of a registration form is used on a password field of a
+ // login form.
optional fixed64 login_form_signature = 14;
// Whether a form submission event was observed.
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 952ffdfb555..98beaeb88a0 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -4,11 +4,13 @@
#include "components/autofill/core/browser/test_autofill_client.h"
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/version_info/channel.h"
#if !defined(OS_IOS)
#include "components/autofill/core/browser/payments/test_internal_authenticator.h"
@@ -22,6 +24,10 @@ TestAutofillClient::TestAutofillClient()
TestAutofillClient::~TestAutofillClient() {}
+version_info::Channel TestAutofillClient::GetChannel() const {
+ return channel_for_testing_;
+}
+
PersonalDataManager* TestAutofillClient::GetPersonalDataManager() {
return &test_personal_data_manager_;
}
@@ -32,6 +38,10 @@ TestAutofillClient::GetAutocompleteHistoryManager() {
}
PrefService* TestAutofillClient::GetPrefs() {
+ return const_cast<PrefService*>(base::as_const(*this).GetPrefs());
+}
+
+const PrefService* TestAutofillClient::GetPrefs() const {
return prefs_.get();
}
@@ -75,7 +85,7 @@ AutofillOfferManager* TestAutofillClient::GetAutofillOfferManager() {
return autofill_offer_manager_.get();
}
-const GURL& TestAutofillClient::GetLastCommittedURL() {
+const GURL& TestAutofillClient::GetLastCommittedURL() const {
return last_committed_url_;
}
@@ -88,6 +98,10 @@ translate::LanguageState* TestAutofillClient::GetLanguageState() {
return &mock_translate_driver_.GetLanguageState();
}
+translate::TranslateDriver* TestAutofillClient::GetTranslateDriver() {
+ return &mock_translate_driver_;
+}
+
#if !defined(OS_IOS)
std::unique_ptr<InternalAuthenticator>
TestAutofillClient::CreateCreditCardInternalAuthenticator(
@@ -206,6 +220,10 @@ void TestAutofillClient::ConfirmCreditCardFillAssist(
std::move(callback).Run();
}
+void TestAutofillClient::ConfirmSaveAddressProfile(
+ const AutofillProfile& profile,
+ AddressProfileSavePromptCallback callback) {}
+
bool TestAutofillClient::HasCreditCardScanFeature() {
return false;
}
@@ -247,7 +265,7 @@ void TestAutofillClient::DidFillOrPreviewField(
const base::string16& autofilled_value,
const base::string16& profile_full_name) {}
-bool TestAutofillClient::IsContextSecure() {
+bool TestAutofillClient::IsContextSecure() const {
// Simplified secure context check for tests.
return form_origin_.SchemeIs("https");
}
@@ -256,7 +274,7 @@ bool TestAutofillClient::ShouldShowSigninPromo() {
return false;
}
-bool TestAutofillClient::AreServerCardsSupported() {
+bool TestAutofillClient::AreServerCardsSupported() const {
return true;
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index 64c139007d2..682274a1759 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -28,6 +28,7 @@
#include "components/translate/core/browser/language_state.h"
#include "components/translate/core/browser/mock_translate_driver.h"
#include "components/ukm/test_ukm_recorder.h"
+#include "components/version_info/channel.h"
#include "services/metrics/public/cpp/delegating_ukm_recorder.h"
#if !defined(OS_IOS)
@@ -43,9 +44,11 @@ class TestAutofillClient : public AutofillClient {
~TestAutofillClient() override;
// AutofillClient:
+ version_info::Channel GetChannel() const override;
PersonalDataManager* GetPersonalDataManager() override;
AutocompleteHistoryManager* GetAutocompleteHistoryManager() override;
PrefService* GetPrefs() override;
+ const PrefService* GetPrefs() const override;
syncer::SyncService* GetSyncService() override;
signin::IdentityManager* GetIdentityManager() override;
FormDataImporter* GetFormDataImporter() override;
@@ -55,9 +58,10 @@ class TestAutofillClient : public AutofillClient {
ukm::SourceId GetUkmSourceId() override;
AddressNormalizer* GetAddressNormalizer() override;
AutofillOfferManager* GetAutofillOfferManager() override;
- const GURL& GetLastCommittedURL() override;
+ const GURL& GetLastCommittedURL() const override;
security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override;
translate::LanguageState* GetLanguageState() override;
+ translate::TranslateDriver* GetTranslateDriver() override;
#if !defined(OS_IOS)
std::unique_ptr<InternalAuthenticator> CreateCreditCardInternalAuthenticator(
content::RenderFrameHost* rfh) override;
@@ -118,6 +122,9 @@ class TestAutofillClient : public AutofillClient {
void CreditCardUploadCompleted(bool card_saved) override;
void ConfirmCreditCardFillAssist(const CreditCard& card,
base::OnceClosure callback) override;
+ void ConfirmSaveAddressProfile(
+ const AutofillProfile& profile,
+ AddressProfileSavePromptCallback callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(CreditCardScanCallback callback) override;
void ShowAutofillPopup(
@@ -141,9 +148,9 @@ class TestAutofillClient : public AutofillClient {
// By default, TestAutofillClient will report that the context is
// secure. This can be adjusted by calling set_form_origin() with an
// http:// URL.
- bool IsContextSecure() override;
+ bool IsContextSecure() const override;
bool ShouldShowSigninPromo() override;
- bool AreServerCardsSupported() override;
+ bool AreServerCardsSupported() const override;
void ExecuteCommand(int id) override;
// RiskDataLoader:
@@ -230,6 +237,10 @@ class TestAutofillClient : public AutofillClient {
autofill_offer_manager_ = std::move(autofill_offer_manager);
}
+ void set_channel_for_testing(const version_info::Channel channel) {
+ channel_for_testing_ = channel;
+ }
+
GURL form_origin() { return form_origin_; }
ukm::TestUkmRecorder* GetTestUkmRecorder();
@@ -265,6 +276,8 @@ class TestAutofillClient : public AutofillClient {
// otherwise.
base::Optional<bool> credit_card_name_fix_flow_bubble_was_shown_;
+ version_info::Channel channel_for_testing_ = version_info::Channel::UNKNOWN;
+
// Populated if local save or upload was offered.
base::Optional<SaveCreditCardOptions> save_credit_card_options_;
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.cc b/chromium/components/autofill/core/browser/test_autofill_provider.cc
deleted file mode 100644
index ac9248b8d08..00000000000
--- a/chromium/components/autofill/core/browser/test_autofill_provider.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/test_autofill_provider.h"
-
-namespace autofill {
-
-void TestAutofillProvider::OnQueryFormFieldAutofill(
- AutofillHandlerProxy* handler,
- int32_t id,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box,
- bool autoselect_first_suggestion) {}
-
-void TestAutofillProvider::OnTextFieldDidChange(
- AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box,
- const base::TimeTicks timestamp) {}
-
-void TestAutofillProvider::OnTextFieldDidScroll(
- AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box) {}
-
-void TestAutofillProvider::OnSelectControlDidChange(
- AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box) {}
-
-void TestAutofillProvider::OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
- bool had_interacted_form) {}
-
-void TestAutofillProvider::OnFocusOnFormField(AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box) {}
-
-void TestAutofillProvider::OnDidFillAutofillFormData(
- AutofillHandlerProxy* handler,
- const FormData& form,
- base::TimeTicks timestamp) {}
-
-void TestAutofillProvider::OnFormsSeen(AutofillHandlerProxy* handler,
- const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) {}
-
-void TestAutofillProvider::OnHidePopup(AutofillHandlerProxy* handler) {}
-
-void TestAutofillProvider::Reset(AutofillHandlerProxy* handler) {}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.h b/chromium/components/autofill/core/browser/test_autofill_provider.h
index db7234195fa..1c498e1bc5b 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.h
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.h
@@ -19,38 +19,40 @@ class TestAutofillProvider : public AutofillProvider {
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
- bool autoselect_first_suggestion) override;
+ bool autoselect_first_suggestion) override {}
void OnTextFieldDidChange(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
- const base::TimeTicks timestamp) override;
+ const base::TimeTicks timestamp) override {}
void OnTextFieldDidScroll(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
- const gfx::RectF& bounding_box) override;
+ const gfx::RectF& bounding_box) override {}
void OnSelectControlDidChange(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
- const gfx::RectF& bounding_box) override;
+ const gfx::RectF& bounding_box) override {}
void OnFormSubmitted(AutofillHandlerProxy* handler,
const FormData& form,
bool known_success,
mojom::SubmissionSource source) override {}
void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
- bool had_interacted_form) override;
+ bool had_interacted_form) override {}
void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
- const gfx::RectF& bounding_box) override;
+ const gfx::RectF& bounding_box) override {}
void OnDidFillAutofillFormData(AutofillHandlerProxy* handler,
const FormData& form,
- base::TimeTicks timestamp) override;
+ base::TimeTicks timestamp) override {}
void OnFormsSeen(AutofillHandlerProxy* handler,
- const std::vector<FormData>& forms,
- const base::TimeTicks timestamp) override;
- void OnHidePopup(AutofillHandlerProxy* handler) override;
- void Reset(AutofillHandlerProxy* handler) override;
+ const std::vector<FormData>& forms) override {}
+ void OnHidePopup(AutofillHandlerProxy* handler) override {}
+ void OnServerPredictionsAvailable(AutofillHandlerProxy* handler) override {}
+ void OnServerQueryRequestError(AutofillHandlerProxy* handler,
+ FormSignature form_signature) override {}
+ void Reset(AutofillHandlerProxy* handler) override {}
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc
index 79b2f682339..0913a4a265d 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc
@@ -23,14 +23,24 @@ AutofillSyncSigninState TestPersonalDataManager::GetSyncSigninState() const {
return sync_and_signin_state_;
}
-void TestPersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) {
- CreditCard* credit_card = GetCreditCardWithGUID(data_model.guid().c_str());
- if (credit_card)
- credit_card->RecordAndLogUse();
-
- AutofillProfile* profile = GetProfileWithGUID(data_model.guid().c_str());
- if (profile)
- profile->RecordAndLogUse();
+void TestPersonalDataManager::RecordUseOf(
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card) {
+ if (absl::holds_alternative<const CreditCard*>(profile_or_credit_card)) {
+ CreditCard* credit_card = GetCreditCardByGUID(
+ absl::get<const CreditCard*>(profile_or_credit_card)->guid());
+
+ if (credit_card)
+ credit_card->RecordAndLogUse();
+ }
+
+ if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+ AutofillProfile* profile = GetProfileByGUID(
+ absl::get<const AutofillProfile*>(profile_or_credit_card)->guid());
+
+ if (profile)
+ profile->RecordAndLogUse();
+ }
}
std::string TestPersonalDataManager::SaveImportedProfile(
diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h
index fe773963e63..6524c6b87d5 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h
@@ -32,7 +32,8 @@ class TestPersonalDataManager : public PersonalDataManager {
// or to make things easier in general to toggle.
void OnSyncServiceInitialized(syncer::SyncService* sync_service) override;
AutofillSyncSigninState GetSyncSigninState() const override;
- void RecordUseOf(const AutofillDataModel& data_model) override;
+ void RecordUseOf(absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card) override;
std::string SaveImportedProfile(
const AutofillProfile& imported_profile) override;
std::string SaveImportedCreditCard(
diff --git a/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc b/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc
index 1728083a998..89675db21d3 100644
--- a/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc
+++ b/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/strings/string_piece.h"
+#include "base/trace_event/memory_usage_estimator.h"
#include "components/autofill/core/browser/ui/accessory_sheet_enums.h"
namespace autofill {
@@ -17,7 +18,10 @@ UserInfo::Field::Field(base::string16 display_text,
: display_text_(std::move(display_text)),
a11y_description_(std::move(a11y_description)),
is_obfuscated_(is_obfuscated),
- selectable_(selectable) {}
+ selectable_(selectable),
+ estimated_memory_use_by_strings_(
+ base::trace_event::EstimateMemoryUsage(display_text_) +
+ base::trace_event::EstimateMemoryUsage(a11y_description_)) {}
UserInfo::Field::Field(base::string16 display_text,
base::string16 a11y_description,
@@ -28,7 +32,11 @@ UserInfo::Field::Field(base::string16 display_text,
a11y_description_(std::move(a11y_description)),
id_(std::move(id)),
is_obfuscated_(is_obfuscated),
- selectable_(selectable) {}
+ selectable_(selectable),
+ estimated_memory_use_by_strings_(
+ base::trace_event::EstimateMemoryUsage(display_text_) +
+ base::trace_event::EstimateMemoryUsage(a11y_description_) +
+ base::trace_event::EstimateMemoryUsage(id_)) {}
UserInfo::Field::Field(const Field& field) = default;
@@ -47,6 +55,10 @@ bool UserInfo::Field::operator==(const UserInfo::Field& field) const {
selectable_ == field.selectable_;
}
+size_t UserInfo::Field::EstimateMemoryUsage() const {
+ return sizeof(UserInfo::Field) + estimated_memory_use_by_strings_;
+}
+
std::ostream& operator<<(std::ostream& os, const UserInfo::Field& field) {
os << "(display text: \"" << field.display_text() << "\", "
<< "a11y_description: \"" << field.a11y_description() << "\", "
@@ -62,7 +74,10 @@ UserInfo::UserInfo(std::string origin)
: UserInfo(std::move(origin), IsPslMatch(false)) {}
UserInfo::UserInfo(std::string origin, IsPslMatch is_psl_match)
- : origin_(std::move(origin)), is_psl_match_(is_psl_match) {}
+ : origin_(std::move(origin)),
+ is_psl_match_(is_psl_match),
+ estimated_dynamic_memory_use_(
+ base::trace_event::EstimateMemoryUsage(origin_)) {}
UserInfo::UserInfo(const UserInfo& user_info) = default;
@@ -79,6 +94,10 @@ bool UserInfo::operator==(const UserInfo& user_info) const {
is_psl_match_ == user_info.is_psl_match_;
}
+size_t UserInfo::EstimateMemoryUsage() const {
+ return sizeof(UserInfo) + estimated_dynamic_memory_use_;
+}
+
std::ostream& operator<<(std::ostream& os, const UserInfo& user_info) {
os << "origin: \"" << user_info.origin() << "\", "
<< "is_psl_match: " << std::boolalpha << user_info.is_psl_match() << ", "
@@ -91,7 +110,10 @@ std::ostream& operator<<(std::ostream& os, const UserInfo& user_info) {
FooterCommand::FooterCommand(base::string16 display_text,
autofill::AccessoryAction action)
- : display_text_(std::move(display_text)), accessory_action_(action) {}
+ : display_text_(std::move(display_text)),
+ accessory_action_(action),
+ estimated_memory_use_by_strings_(
+ base::trace_event::EstimateMemoryUsage(display_text_)) {}
FooterCommand::FooterCommand(const FooterCommand& footer_command) = default;
@@ -110,6 +132,10 @@ bool FooterCommand::operator==(const FooterCommand& fc) const {
accessory_action_ == fc.accessory_action_;
}
+size_t FooterCommand::EstimateMemoryUsage() const {
+ return sizeof(FooterCommand) + estimated_memory_use_by_strings_;
+}
+
std::ostream& operator<<(std::ostream& os, const FooterCommand& fc) {
return os << "(display text: \"" << fc.display_text() << "\", "
<< "action: " << static_cast<int>(fc.accessory_action()) << ")";
@@ -120,7 +146,9 @@ OptionToggle::OptionToggle(base::string16 display_text,
autofill::AccessoryAction action)
: display_text_(display_text),
enabled_(enabled),
- accessory_action_(action) {}
+ accessory_action_(action),
+ estimated_memory_use_by_strings_(
+ base::trace_event::EstimateMemoryUsage(display_text_)) {}
OptionToggle::OptionToggle(const OptionToggle& option_toggle) = default;
@@ -139,6 +167,10 @@ bool OptionToggle::operator==(const OptionToggle& option_toggle) const {
accessory_action_ == option_toggle.accessory_action_;
}
+size_t OptionToggle::EstimateMemoryUsage() const {
+ return sizeof(OptionToggle) + estimated_memory_use_by_strings_;
+}
+
std::ostream& operator<<(std::ostream& os, const OptionToggle& ot) {
return os << "(display text: \"" << ot.display_text() << "\", "
<< "state: " << ot.is_enabled() << ", "
@@ -193,6 +225,17 @@ bool AccessorySheetData::operator==(const AccessorySheetData& data) const {
footer_commands_ == data.footer_commands_;
}
+size_t AccessorySheetData::EstimateMemoryUsage() const {
+ return sizeof(AccessorySheetData) +
+ base::trace_event::EstimateMemoryUsage(title_) +
+ base::trace_event::EstimateMemoryUsage(warning_) +
+ (option_toggle_
+ ? base::trace_event::EstimateMemoryUsage(option_toggle_.value())
+ : 0) +
+ base::trace_event::EstimateIterableMemoryUsage(user_info_list_) +
+ base::trace_event::EstimateIterableMemoryUsage(footer_commands_);
+}
+
std::ostream& operator<<(std::ostream& os, const AccessorySheetData& data) {
os << data.get_sheet_type() << " with title: \"" << data.title();
if (data.option_toggle().has_value()) {
diff --git a/chromium/components/autofill/core/browser/ui/accessory_sheet_data.h b/chromium/components/autofill/core/browser/ui/accessory_sheet_data.h
index 32bc5e00016..38408e17550 100644
--- a/chromium/components/autofill/core/browser/ui/accessory_sheet_data.h
+++ b/chromium/components/autofill/core/browser/ui/accessory_sheet_data.h
@@ -10,7 +10,7 @@
#include "base/optional.h"
#include "base/strings/string16.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "components/autofill/core/browser/ui/accessory_sheet_enums.h"
namespace password_manager {
@@ -56,16 +56,23 @@ class UserInfo {
bool operator==(const UserInfo::Field& field) const;
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+ size_t EstimateMemoryUsage() const;
+
private:
+ // IMPORTANT(https://crbug.com/1169167): Add the size of newly added strings
+ // to the memory estimation member!
base::string16 display_text_;
base::string16 a11y_description_;
std::string id_; // Optional, if needed to complete filling.
bool is_obfuscated_;
bool selectable_;
+ size_t estimated_memory_use_by_strings_ = 0;
};
using IsPslMatch =
- util::StrongAlias<password_manager::IsPublicSuffixMatchTag, bool>;
+ base::StrongAlias<password_manager::IsPublicSuffixMatchTag, bool>;
UserInfo();
explicit UserInfo(std::string origin);
@@ -78,7 +85,10 @@ class UserInfo {
UserInfo& operator=(const UserInfo& user_info);
UserInfo& operator=(UserInfo&& user_info);
- void add_field(Field field) { fields_.push_back(std::move(field)); }
+ void add_field(Field field) {
+ estimated_dynamic_memory_use_ += field.EstimateMemoryUsage();
+ fields_.push_back(std::move(field));
+ }
const std::vector<Field>& fields() const { return fields_; }
const std::string& origin() const { return origin_; }
@@ -86,10 +96,17 @@ class UserInfo {
bool operator==(const UserInfo& user_info) const;
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+ size_t EstimateMemoryUsage() const;
+
private:
+ // IMPORTANT(https://crbug.com/1169167): Add the size of newly added strings
+ // to the memory estimation member!
std::string origin_;
IsPslMatch is_psl_match_{false};
std::vector<Field> fields_;
+ size_t estimated_dynamic_memory_use_ = 0;
};
std::ostream& operator<<(std::ostream& out, const UserInfo::Field& field);
@@ -115,9 +132,16 @@ class FooterCommand {
bool operator==(const FooterCommand& fc) const;
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+ size_t EstimateMemoryUsage() const;
+
private:
+ // IMPORTANT(https://crbug.com/1169167): Add the size of newly added strings
+ // to the memory estimation member!
base::string16 display_text_;
autofill::AccessoryAction accessory_action_;
+ size_t estimated_memory_use_by_strings_ = 0;
};
std::ostream& operator<<(std::ostream& out, const FooterCommand& fc);
@@ -147,10 +171,17 @@ class OptionToggle {
bool operator==(const OptionToggle& option_toggle) const;
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+ size_t EstimateMemoryUsage() const;
+
private:
+ // IMPORTANT(https://crbug.com/1169167): Add the size of newly added strings
+ // to the memory estimation member!
base::string16 display_text_;
bool enabled_;
autofill::AccessoryAction accessory_action_;
+ size_t estimated_memory_use_by_strings_ = 0;
};
// Represents the contents of a bottom sheet tab below the keyboard accessory,
@@ -204,6 +235,10 @@ class AccessorySheetData {
bool operator==(const AccessorySheetData& data) const;
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+ size_t EstimateMemoryUsage() const;
+
private:
AccessoryTabType sheet_type_;
base::string16 title_;
diff --git a/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter.cc b/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter.cc
index 3284654bdd1..61fe081b4a5 100644
--- a/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter.cc
@@ -34,14 +34,15 @@ base::string16 AddressContactFormLabelFormatter::GetLabelForProfile(
FieldTypeGroup focused_group) const {
std::vector<base::string16> label_parts;
- bool street_address_is_focused = focused_group == ADDRESS_HOME &&
- IsStreetAddressPart(focused_field_type());
+ bool street_address_is_focused =
+ focused_group == FieldTypeGroup::kAddressHome &&
+ IsStreetAddressPart(focused_field_type());
bool non_street_address_is_focused =
- focused_group == ADDRESS_HOME &&
+ focused_group == FieldTypeGroup::kAddressHome &&
!IsStreetAddressPart(focused_field_type());
- if (focused_group != NAME && !non_street_address_is_focused &&
- data_util::ContainsName(groups())) {
+ if (focused_group != FieldTypeGroup::kName &&
+ !non_street_address_is_focused && data_util::ContainsName(groups())) {
AddLabelPartIfNotEmpty(
GetLabelName(field_types_for_labels(), profile, app_locale()),
&label_parts);
@@ -54,11 +55,11 @@ base::string16 AddressContactFormLabelFormatter::GetLabelForProfile(
&label_parts);
}
- if (focused_group != PHONE_HOME && phone_disambiguates_) {
+ if (focused_group != FieldTypeGroup::kPhoneHome && phone_disambiguates_) {
AddLabelPartIfNotEmpty(GetLabelPhone(profile, app_locale()), &label_parts);
}
- if (focused_group != EMAIL && email_disambiguates_) {
+ if (focused_group != FieldTypeGroup::kEmail && email_disambiguates_) {
AddLabelPartIfNotEmpty(GetLabelEmail(profile, app_locale()), &label_parts);
}
diff --git a/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter.cc b/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter.cc
index 3f41ec73c3a..df9e38e2f7a 100644
--- a/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter.cc
@@ -27,7 +27,7 @@ AddressEmailFormLabelFormatter::~AddressEmailFormLabelFormatter() {}
base::string16 AddressEmailFormLabelFormatter::GetLabelForProfile(
const AutofillProfile& profile,
FieldTypeGroup focused_group) const {
- return focused_group == ADDRESS_HOME &&
+ return focused_group == FieldTypeGroup::kAddressHome &&
!IsStreetAddressPart(focused_field_type())
? GetLabelForProfileOnFocusedNonStreetAddress(
form_has_street_address_, profile, app_locale(),
@@ -46,20 +46,21 @@ base::string16 AddressEmailFormLabelFormatter::
FieldTypeGroup focused_group) const {
std::vector<base::string16> label_parts;
- if (focused_group != NAME && data_util::ContainsName(groups())) {
+ if (focused_group != FieldTypeGroup::kName &&
+ data_util::ContainsName(groups())) {
AddLabelPartIfNotEmpty(
GetLabelName(field_types_for_labels(), profile, app_locale()),
&label_parts);
}
- if (focused_group != ADDRESS_HOME) {
+ if (focused_group != FieldTypeGroup::kAddressHome) {
AddLabelPartIfNotEmpty(
GetLabelAddress(form_has_street_address_, profile, app_locale(),
field_types_for_labels()),
&label_parts);
}
- if (focused_group != EMAIL) {
+ if (focused_group != FieldTypeGroup::kEmail) {
AddLabelPartIfNotEmpty(GetLabelEmail(profile, app_locale()), &label_parts);
}
diff --git a/chromium/components/autofill/core/browser/ui/address_form_label_formatter.cc b/chromium/components/autofill/core/browser/ui/address_form_label_formatter.cc
index 3f9665f3b05..4b958ea3157 100644
--- a/chromium/components/autofill/core/browser/ui/address_form_label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/address_form_label_formatter.cc
@@ -27,7 +27,7 @@ AddressFormLabelFormatter::~AddressFormLabelFormatter() {}
base::string16 AddressFormLabelFormatter::GetLabelForProfile(
const AutofillProfile& profile,
FieldTypeGroup focused_group) const {
- if (focused_group != ADDRESS_HOME) {
+ if (focused_group != FieldTypeGroup::kAddressHome) {
return GetLabelNationalAddress(field_types_for_labels(), profile,
app_locale());
} else {
diff --git a/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter.cc b/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter.cc
index 543c86c312f..e39cf7ec209 100644
--- a/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter.cc
@@ -27,7 +27,7 @@ AddressPhoneFormLabelFormatter::~AddressPhoneFormLabelFormatter() {}
base::string16 AddressPhoneFormLabelFormatter::GetLabelForProfile(
const AutofillProfile& profile,
FieldTypeGroup focused_group) const {
- return focused_group == ADDRESS_HOME &&
+ return focused_group == FieldTypeGroup::kAddressHome &&
!IsStreetAddressPart(focused_field_type())
? GetLabelForProfileOnFocusedNonStreetAddress(
form_has_street_address_, profile, app_locale(),
@@ -45,17 +45,18 @@ base::string16 AddressPhoneFormLabelFormatter::
const AutofillProfile& profile,
FieldTypeGroup focused_group) const {
std::vector<base::string16> label_parts;
- if (focused_group != NAME && data_util::ContainsName(groups())) {
+ if (focused_group != FieldTypeGroup::kName &&
+ data_util::ContainsName(groups())) {
AddLabelPartIfNotEmpty(
GetLabelName(field_types_for_labels(), profile, app_locale()),
&label_parts);
}
- if (focused_group != PHONE_HOME) {
+ if (focused_group != FieldTypeGroup::kPhoneHome) {
AddLabelPartIfNotEmpty(GetLabelPhone(profile, app_locale()), &label_parts);
}
- if (focused_group != ADDRESS_HOME) {
+ if (focused_group != FieldTypeGroup::kAddressHome) {
AddLabelPartIfNotEmpty(
GetLabelAddress(form_has_street_address_, profile, app_locale(),
field_types_for_labels()),
diff --git a/chromium/components/autofill/core/browser/ui/contact_form_label_formatter.cc b/chromium/components/autofill/core/browser/ui/contact_form_label_formatter.cc
index 163f8d0d1c8..90fbf0c7033 100644
--- a/chromium/components/autofill/core/browser/ui/contact_form_label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/contact_form_label_formatter.cc
@@ -30,17 +30,18 @@ base::string16 ContactFormLabelFormatter::GetLabelForProfile(
const AutofillProfile& profile,
FieldTypeGroup focused_group) const {
std::vector<base::string16> label_parts;
- if (focused_group != NAME && data_util::ContainsName(groups())) {
+ if (focused_group != FieldTypeGroup::kName &&
+ data_util::ContainsName(groups())) {
AddLabelPartIfNotEmpty(
GetLabelName(field_types_for_labels(), profile, app_locale()),
&label_parts);
}
- if (focused_group != PHONE_HOME) {
+ if (focused_group != FieldTypeGroup::kPhoneHome) {
AddLabelPartIfNotEmpty(MaybeGetPhone(profile), &label_parts);
}
- if (focused_group != EMAIL) {
+ if (focused_group != FieldTypeGroup::kEmail) {
AddLabelPartIfNotEmpty(MaybeGetEmail(profile), &label_parts);
}
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter.cc b/chromium/components/autofill/core/browser/ui/label_formatter.cc
index 5f87d687d7b..3044f0f6685 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/label_formatter.cc
@@ -18,6 +18,7 @@
#include "components/autofill/core/browser/ui/contact_form_label_formatter.h"
#include "components/autofill/core/browser/ui/label_formatter_utils.h"
#include "components/autofill/core/browser/ui/mobile_label_formatter.h"
+#include "components/autofill/core/common/dense_set.h"
namespace autofill {
@@ -40,14 +41,15 @@ LabelFormatter::LabelFormatter(const std::vector<AutofillProfile*>& profiles,
focused_field_type_(focused_field_type),
groups_(groups) {
const FieldTypeGroup focused_group = GetFocusedNonBillingGroup();
- std::set<FieldTypeGroup> groups_for_labels{NAME, ADDRESS_HOME, EMAIL,
- PHONE_HOME};
+ DenseSet<FieldTypeGroup> groups_for_labels{
+ FieldTypeGroup::kName, FieldTypeGroup::kAddressHome,
+ FieldTypeGroup::kEmail, FieldTypeGroup::kPhoneHome};
// If a user is focused on an address field, then parts of the address may be
// shown in the label. For example, if the user is focusing on a street
// address field, then it may be helpful to show the city in the label.
// Otherwise, the focused field should not appear in the label.
- if (focused_group != ADDRESS_HOME) {
+ if (focused_group != FieldTypeGroup::kAddressHome) {
groups_for_labels.erase(focused_group);
}
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter.h b/chromium/components/autofill/core/browser/ui/label_formatter.h
index 4ca3c891aa8..ab19f4fc103 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter.h
+++ b/chromium/components/autofill/core/browser/ui/label_formatter.h
@@ -53,7 +53,7 @@ class LabelFormatter {
// Returns the FieldTypeGroup with which |focused_field_type_| is associated.
// Billing field types are mapped to their corresponding home address field
// types. For example, if focused_field_type_ is ADDRESS_BILLING_ZIP, then
- // the resulting FieldTypeGroup is ADDRESS_HOME instead of ADDRESS_BILLING.
+ // the resulting FieldTypeGroup is kAddressHome instead of kAddressBilling.
FieldTypeGroup GetFocusedNonBillingGroup() const;
const std::string& app_locale() const { return app_locale_; }
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc b/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc
index 91f1a6ebf7a..36fb2647450 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc
+++ b/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc
@@ -135,7 +135,7 @@ std::vector<ServerFieldType> ExtractSpecifiedAddressFieldTypes(
auto should_be_extracted =
[&extract_street_address_types](ServerFieldType type) -> bool {
return AutofillType(AutofillType(type).GetStorableType()).group() ==
- ADDRESS_HOME &&
+ FieldTypeGroup::kAddressHome &&
(extract_street_address_types ? IsStreetAddressPart(type)
: !IsStreetAddressPart(type));
};
@@ -148,21 +148,6 @@ std::vector<ServerFieldType> ExtractSpecifiedAddressFieldTypes(
return extracted_address_types;
}
-std::vector<ServerFieldType> ExtractAddressFieldTypes(
- const std::vector<ServerFieldType>& types) {
- std::vector<ServerFieldType> only_address_types;
-
- // Note that GetStorableType maps billing fields to their corresponding non-
- // billing fields, e.g. ADDRESS_HOME_ZIP is mapped to ADDRESS_BILLING_ZIP.
- std::copy_if(
- types.begin(), types.end(), std::back_inserter(only_address_types),
- [](ServerFieldType type) {
- return AutofillType(AutofillType(type).GetStorableType()).group() ==
- ADDRESS_HOME;
- });
- return only_address_types;
-}
-
std::vector<ServerFieldType> TypesWithoutFocusedField(
const std::vector<ServerFieldType>& types,
ServerFieldType field_type_to_remove) {
@@ -301,7 +286,8 @@ base::string16 GetLabelName(const std::vector<ServerFieldType>& types,
// The form contains neither a full name field nor a first name field,
// so choose some name field in the form and make it the label text.
for (const ServerFieldType type : types) {
- if (AutofillType(AutofillType(type).GetStorableType()).group() == NAME) {
+ if (AutofillType(AutofillType(type).GetStorableType()).group() ==
+ FieldTypeGroup::kName) {
return profile.GetInfo(AutofillType(type), app_locale);
}
}
@@ -390,31 +376,34 @@ bool HaveSameStreetAddresses(const std::vector<AutofillProfile*>& profiles,
bool HasUnfocusedEmailField(FieldTypeGroup focused_group,
uint32_t form_groups) {
- return ContainsEmail(form_groups) && focused_group != EMAIL;
+ return ContainsEmail(form_groups) && focused_group != FieldTypeGroup::kEmail;
}
bool HasUnfocusedNameField(FieldTypeGroup focused_group, uint32_t form_groups) {
- return ContainsName(form_groups) && focused_group != NAME;
+ return ContainsName(form_groups) && focused_group != FieldTypeGroup::kName;
}
bool HasUnfocusedNonStreetAddressField(
ServerFieldType focused_field,
FieldTypeGroup focused_group,
const std::vector<ServerFieldType>& types) {
- return HasNonStreetAddress(types) && (focused_group != ADDRESS_HOME ||
- !IsNonStreetAddressPart(focused_field));
+ return HasNonStreetAddress(types) &&
+ (focused_group != FieldTypeGroup::kAddressHome ||
+ !IsNonStreetAddressPart(focused_field));
}
bool HasUnfocusedPhoneField(FieldTypeGroup focused_group,
uint32_t form_groups) {
- return ContainsPhone(form_groups) && focused_group != PHONE_HOME;
+ return ContainsPhone(form_groups) &&
+ focused_group != FieldTypeGroup::kPhoneHome;
}
bool HasUnfocusedStreetAddressField(ServerFieldType focused_field,
FieldTypeGroup focused_group,
const std::vector<ServerFieldType>& types) {
return HasStreetAddress(types) &&
- (focused_group != ADDRESS_HOME || !IsStreetAddressPart(focused_field));
+ (focused_group != FieldTypeGroup::kAddressHome ||
+ !IsStreetAddressPart(focused_field));
}
bool FormHasOnlyNonStreetAddressFields(
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter_utils.h b/chromium/components/autofill/core/browser/ui/label_formatter_utils.h
index 1528e4c48ac..14b33ac0139 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter_utils.h
+++ b/chromium/components/autofill/core/browser/ui/label_formatter_utils.h
@@ -52,11 +52,6 @@ std::vector<ServerFieldType> ExtractSpecifiedAddressFieldTypes(
bool extract_street_address_types,
const std::vector<ServerFieldType>& types);
-// Returns a collection of the types in |types| that belong to the
-// ADDRESS_HOME or ADDRESS_BILLING FieldTypeGroups.
-std::vector<ServerFieldType> ExtractAddressFieldTypes(
- const std::vector<ServerFieldType>& types);
-
// Returns a collection of the types in |types| without |field_type_to_remove|.
std::vector<ServerFieldType> TypesWithoutFocusedField(
const std::vector<ServerFieldType>& types,
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
index 5c0830950ce..5d43b44cf42 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
@@ -182,6 +182,12 @@ base::string16 CardUnmaskPromptControllerImpl::GetInstructionsMessage() const {
return l10n_util::GetStringFUTF16(
ids, card_.CardIdentifierStringForAutofillDisplay());
#else
+ // For Google Pay Plex cards, show a specific message that include
+ // instructions to find the CVC for their Plex card.
+ if (card_.IsGoogleIssuedCard()) {
+ return l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_GOOGLE_ISSUED_CARD);
+ }
return l10n_util::GetStringUTF16(
card_.record_type() == autofill::CreditCard::LOCAL_CARD
? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_LOCAL_CARD
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
index cf32d1ecbe4..f6eec72b843 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
@@ -308,6 +308,10 @@ class LoggingValidationTestForNickname
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
+#if defined(OS_ANDROID)
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
+#endif
SetCreditCardForTesting(card_has_nickname_
? test::GetMaskedServerCardWithNickname()
: test::GetMaskedServerCard());
@@ -635,6 +639,10 @@ class CvcInputValidationTest : public CardUnmaskPromptControllerImplGenericTest,
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
+#if defined(OS_ANDROID)
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
+#endif
}
private:
@@ -674,6 +682,10 @@ class CvcInputAmexValidationTest
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
+#if defined(OS_ANDROID)
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
+#endif
}
private:
@@ -722,6 +734,10 @@ class ExpirationDateValidationTest
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
+#if defined(OS_ANDROID)
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
+#endif
}
private:
diff --git a/chromium/components/autofill/core/browser/ui/suggestion.h b/chromium/components/autofill/core/browser/ui/suggestion.h
index c69aa387f65..8c9c505888d 100644
--- a/chromium/components/autofill/core/browser/ui/suggestion.h
+++ b/chromium/components/autofill/core/browser/ui/suggestion.h
@@ -9,13 +9,13 @@
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "ui/gfx/image/image.h"
namespace autofill {
struct Suggestion {
- using IsLoading = util::StrongAlias<class IsLoadingTag, bool>;
+ using IsLoading = base::StrongAlias<class IsLoadingTag, bool>;
enum MatchMode {
PREFIX_MATCH, // for prefix matched suggestions;
diff --git a/chromium/components/autofill/core/browser/ui/suggestion_selection.cc b/chromium/components/autofill/core/browser/ui/suggestion_selection.cc
index 1281ad65ae9..fe7e487bd12 100644
--- a/chromium/components/autofill/core/browser/ui/suggestion_selection.cc
+++ b/chromium/components/autofill/core/browser/ui/suggestion_selection.cc
@@ -108,7 +108,7 @@ std::vector<Suggestion> GetPrefixMatchedSuggestions(
/* is_masked_server_card= */ false, &prefix_matched_suggestion)) {
matched_profiles->push_back(profile);
- if (type.group() == PHONE_HOME) {
+ if (type.group() == FieldTypeGroup::kPhoneHome) {
bool format_phone;
#if defined(OS_ANDROID) || defined(OS_IOS)
@@ -213,7 +213,8 @@ bool IsValidSuggestionForFieldContents(base::string16 suggestion_canon,
// Phones should do a substring match because they can be trimmed to remove
// the first parts (e.g. country code or prefix). It is still considered a
// prefix match in order to put it at the top of the suggestions.
- if ((type.group() == PHONE_HOME || type.group() == PHONE_BILLING) &&
+ if ((type.group() == FieldTypeGroup::kPhoneHome ||
+ type.group() == FieldTypeGroup::kPhoneBilling) &&
suggestion_canon.find(field_contents_canon) != base::string16::npos) {
return true;
}
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index deee50f2db7..7eb2b39ff0c 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -204,9 +204,9 @@ bool IsSSN(const base::string16& text) {
return false;
int area;
- if (!base::StringToInt(
- base::StringPiece16(number_string.begin(), number_string.begin() + 3),
- &area)) {
+ if (!base::StringToInt(base::MakeStringPiece16(number_string.begin(),
+ number_string.begin() + 3),
+ &area)) {
return false;
}
if (area < 1 || area == 666 || area >= 900) {
@@ -214,16 +214,16 @@ bool IsSSN(const base::string16& text) {
}
int group;
- if (!base::StringToInt(base::StringPiece16(number_string.begin() + 3,
- number_string.begin() + 5),
+ if (!base::StringToInt(base::MakeStringPiece16(number_string.begin() + 3,
+ number_string.begin() + 5),
&group) ||
group == 0) {
return false;
}
int serial;
- if (!base::StringToInt(base::StringPiece16(number_string.begin() + 5,
- number_string.begin() + 9),
+ if (!base::StringToInt(base::MakeStringPiece16(number_string.begin() + 5,
+ number_string.begin() + 9),
&serial) ||
serial == 0) {
return false;
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
index 9cda0484f05..eaa0208daf3 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -18,11 +18,11 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/model_type_change_processor.h"
#include "components/sync/model/mutable_data_batch.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/sync_metadata_store_change_list.h"
+#include "components/sync/model/sync_metadata_store_change_list.h"
#include "net/base/escape.h"
using base::Optional;
@@ -306,7 +306,7 @@ AutocompleteSyncBridge::AutocompleteSyncBridge(
web_data_backend_(backend) {
DCHECK(web_data_backend_);
- scoped_observer_.Add(web_data_backend_);
+ scoped_observation_.Observe(web_data_backend_);
LoadMetadata();
}
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
index 197e46af932..a700a7aba1a 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/supports_user_data.h"
#include "base/threading/thread_checker.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
@@ -79,9 +79,9 @@ class AutocompleteSyncBridge
// SupportsUserData, so it's guaranteed to outlive |this|.
AutofillWebDataBackend* const web_data_backend_;
- ScopedObserver<AutofillWebDataBackend,
- AutofillWebDataServiceObserverOnDBSequence>
- scoped_observer_{this};
+ base::ScopedObservation<AutofillWebDataBackend,
+ AutofillWebDataServiceObserverOnDBSequence>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(AutocompleteSyncBridge);
};
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
index 4c580c90dc0..44fc22b4c55 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -24,13 +24,13 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h"
#include "components/sync/base/client_tag_hash.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/model_error.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
-#include "components/sync/test/test_matchers.h"
+#include "components/sync/test/model/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
index d6f098f58b0..02d8bc8b044 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
@@ -10,8 +10,8 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/guid.h"
-#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile_sync_util.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
@@ -21,13 +21,13 @@
#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model/model_type_change_processor.h"
#include "components/sync/model/mutable_data_batch.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/sync_metadata_store_change_list.h"
+#include "components/sync/model/sync_metadata_store_change_list.h"
using base::Optional;
using base::UTF16ToUTF8;
@@ -82,7 +82,7 @@ AutofillProfileSyncBridge::AutofillProfileSyncBridge(
web_data_backend_(backend) {
DCHECK(web_data_backend_);
- scoped_observer_.Add(web_data_backend_);
+ scoped_observation_.Observe(web_data_backend_);
LoadMetadata();
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h
index d03693a76ea..be44a88d238 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/supports_user_data.h"
#include "base/threading/thread_checker.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
@@ -107,9 +107,9 @@ class AutofillProfileSyncBridge
// SupportsUserData, so it's guaranteed to outlive |this|.
AutofillWebDataBackend* const web_data_backend_;
- ScopedObserver<AutofillWebDataBackend,
- AutofillWebDataServiceObserverOnDBSequence>
- scoped_observer_{this};
+ base::ScopedObservation<AutofillWebDataBackend,
+ AutofillWebDataServiceObserverOnDBSequence>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncBridge);
};
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
index 171f079d9f8..7c56186a303 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
@@ -32,12 +32,12 @@
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/sync/base/client_tag_hash.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
-#include "components/sync/model/entity_data.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/sync/test/model/sync_error_factory_mock.h"
@@ -183,6 +183,7 @@ AutofillProfile ConstructCompleteProfile() {
profile.SetRawInfo(ADDRESS_HOME_PREMISE_NAME, ASCIIToUTF16("Premise"));
profile.set_language_code("en");
profile.SetClientValidityFromBitfieldValue(kValidityStateBitfield);
+ profile.FinalizeAfterImport();
return profile;
}
@@ -415,6 +416,7 @@ TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Added) {
AutofillProfile local(kGuidA, kHttpsOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
+ local.FinalizeAfterImport();
AutofillProfileChange change(AutofillProfileChange::ADD, kGuidA, &local);
EXPECT_CALL(
@@ -560,9 +562,11 @@ TEST_P(AutofillProfileSyncBridgeTest, GetAllDataForDebugging) {
AutofillProfile local1 = AutofillProfile(kGuidA, kHttpsOrigin);
local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local1.FinalizeAfterImport();
AutofillProfile local2 = AutofillProfile(kGuidB, kHttpsOrigin);
local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+ local2.FinalizeAfterImport();
AddAutofillProfilesToTable({local1, local2});
EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(local1, local2));
@@ -572,9 +576,11 @@ TEST_P(AutofillProfileSyncBridgeTest, GetData) {
AutofillProfile local1 = AutofillProfile(kGuidA, kHttpsOrigin);
local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local1.FinalizeAfterImport();
AutofillProfile local2 = AutofillProfile(kGuidB, kHttpsOrigin);
local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+ local2.FinalizeAfterImport();
AddAutofillProfilesToTable({local1, local2});
std::vector<AutofillProfile> data;
@@ -595,10 +601,11 @@ TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData) {
AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin);
local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-
+ local1.FinalizeAfterImport();
AutofillProfile local2 = AutofillProfile(kGuidB, std::string());
local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+ local2.FinalizeAfterImport();
AddAutofillProfilesToTable({local1, local2});
@@ -688,6 +695,7 @@ TEST_P(AutofillProfileSyncBridgeTest, ProfileMigration) {
// the server.
TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToServer) {
AutofillProfile local = ConstructCompleteProfile();
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// This complete profile is fully uploaded to sync.
@@ -714,26 +722,42 @@ TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToClient) {
TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_IdenticalProfiles) {
AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin);
- local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
- local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local1.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("John"),
+ structured_address::VerificationStatus::kObserved);
+ local1.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"),
+ structured_address::VerificationStatus::kObserved);
+ local1.FinalizeAfterImport();
AutofillProfile local2 = AutofillProfile(kGuidB, kSettingsOrigin);
- local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
- local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
-
+ local2.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("Tom"),
+ structured_address::VerificationStatus::kObserved);
+ local2.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"),
+ structured_address::VerificationStatus::kObserved);
+ local2.FinalizeAfterImport();
AddAutofillProfilesToTable({local1, local2});
// The synced profiles are identical to the local ones, except that the guids
// are different.
-
AutofillProfile remote1 = AutofillProfile(kGuidC, kHttpsOrigin);
- remote1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
- remote1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ remote1.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("John"),
+ structured_address::VerificationStatus::kObserved);
+ remote1.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"),
+ structured_address::VerificationStatus::kObserved);
remote1.FinalizeAfterImport();
AutofillProfile remote2 = AutofillProfile(kGuidD, kHttpsOrigin);
- remote2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
- remote2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+ remote2.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("Tom"),
+ structured_address::VerificationStatus::kObserved);
+ remote2.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"),
+ structured_address::VerificationStatus::kObserved);
remote2.FinalizeAfterImport();
AutofillProfileSpecifics remote1_specifics =
@@ -762,6 +786,7 @@ TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_NonSimilarProfiles) {
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
local.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("K."));
local.SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile are not similar as the names are different (all other
@@ -937,6 +962,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
MergeSyncData_SimilarProfiles_LocalOriginPreserved) {
AutofillProfile local(kGuidA, kHttpsOrigin);
local.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
AutofillProfile remote_profile = AutofillProfile(kGuidB, kHttpOrigin);
@@ -964,6 +990,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest,
MergeSyncData_SimilarProfiles_LocalExistingOriginPreserved) {
AutofillProfile local(kGuidA, kHttpsOrigin);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// Remote data does not have an origin value.
@@ -980,6 +1007,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
// Expect the local autofill profile to still have an origin after sync.
AutofillProfile merged(local);
merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ merged.FinalizeAfterImport();
EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
}
@@ -991,6 +1019,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
MergeSyncData_SimilarProfiles_LocalMissingOriginPreserved) {
AutofillProfile local = AutofillProfile(kGuidA, std::string());
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// Create a Sync profile identical to |local|, except with no origin set.
@@ -1010,6 +1039,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest, ApplySyncChanges) {
AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
StartSyncing({});
@@ -1106,17 +1136,25 @@ TEST_P(AutofillProfileSyncBridgeTest,
remote.set_address_home_street_address(
"456 El Camino Real\n"
"Suite #1337");
+ remote.set_address_home_street_address_status(
+ sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED);
EXPECT_CALL(*backend(), CommitChanges());
-
StartSyncing({remote});
// Verify that full street address takes precedence over address lines.
AutofillProfile local(kGuidA, kHttpsOrigin);
- local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("456 El Camino Real\n"
- "Suite #1337"));
- local.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("456 El Camino Real"));
- local.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Suite #1337"));
+ local.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS,
+ ASCIIToUTF16("456 El Camino Real\n"
+ "Suite #1337"),
+ structured_address::VerificationStatus::kObserved);
+ local.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_LINE1, ASCIIToUTF16("456 El Camino Real"),
+ structured_address::VerificationStatus::kObserved);
+ local.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_LINE2, ASCIIToUTF16("Suite #1337"),
+ structured_address::VerificationStatus::kObserved);
+ local.FinalizeAfterImport();
EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
}
@@ -1128,8 +1166,10 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest,
RemoteWithSameGuid_StreetAddress_NoUpdateToEmptyStreetAddressSyncedUp) {
AutofillProfile local(kGuidA, kHttpsOrigin);
- local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("123 Example St.\n"
- "Apt. 42"));
+ local.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("123 Example St.\nApt. 42"),
+ structured_address::VerificationStatus::kObserved);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// Create a Sync profile identical to |profile|, except without street address
@@ -1310,6 +1350,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
// Expect local autofill profile to still have the validity state after.
AutofillProfile merged(local);
merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ merged.FinalizeAfterImport();
// No update to sync, the local validity bitfield should stay untouched.
EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
@@ -1324,6 +1365,7 @@ TEST_P(AutofillProfileSyncBridgeTest,
// Local autofill profile has an empty full name.
AutofillProfile local(kGuidA, kHttpsOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// Remote data does not have a full name value.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
index 6718b8c760b..d31aa724c7d 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
+#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile_sync_util.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
index 03f8b7baef7..6ce404382e4 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
@@ -139,11 +139,13 @@ TEST_F(AutofillProfileSyncDifferenceTrackerTest,
IncorporateRemoteProfileShouldOverwriteProfileWithSameKey) {
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile is completely different but it has the same key.
AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
@@ -158,11 +160,13 @@ TEST_F(AutofillProfileSyncDifferenceTrackerTest,
IncorporateRemoteProfileShouldOverwriteUnverifiedProfileByVerified) {
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpsOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile has the same key but it is not verified.
AutofillProfile remote = AutofillProfile(kSmallerGuid, kSettingsOrigin);
remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
@@ -177,12 +181,13 @@ TEST_F(AutofillProfileSyncDifferenceTrackerTest,
IncorporateRemoteProfileShouldNotOverwriteVerifiedProfileByUnverified) {
AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile has the same key but it is not verified.
AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
// Nothing gets uploaded to sync and the local profile wins.
@@ -196,6 +201,7 @@ TEST_F(AutofillProfileSyncDifferenceTrackerTest,
IncorporateRemoteProfileShouldNotOverwriteFullNameByEmptyString) {
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(NAME_FULL, ASCIIToUTF16("John"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile has the same key.
@@ -204,7 +210,7 @@ TEST_F(AutofillProfileSyncDifferenceTrackerTest,
AutofillProfile merged(remote);
merged.SetRawInfo(NAME_FULL, ASCIIToUTF16("John"));
-
+ merged.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
// Nothing gets uploaded to sync and the remote profile wins except for the
@@ -221,6 +227,7 @@ TEST_F(
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile is identical to the local one, except that the guids and
@@ -228,7 +235,7 @@ TEST_F(
AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpsOrigin);
remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
// Nothing gets uploaded to sync and the remote profile wins.
@@ -243,14 +250,24 @@ TEST_F(
AutofillProfileSyncDifferenceTrackerTest,
IncorporateRemoteProfileShouldKeepRemoteKeyAndLocalOriginWhenMergingDuplicateProfileWithBiggerKey) {
AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
- local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
- local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("John"),
+ structured_address::VerificationStatus::kObserved);
+ local.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"),
+ structured_address::VerificationStatus::kObserved);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile has the same key.
AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpsOrigin);
- remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
- remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ remote.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("John"),
+ structured_address::VerificationStatus::kObserved);
+ remote.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"),
+ structured_address::VerificationStatus::kObserved);
+ remote.FinalizeAfterImport();
AutofillProfile merged(remote);
merged.set_origin(kSettingsOrigin);
@@ -272,6 +289,7 @@ TEST_F(
AutofillProfile local = AutofillProfile(kBiggerGuid, kHttpOrigin);
local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile is identical to the local one, except that the guids and
@@ -279,7 +297,7 @@ TEST_F(
AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
// Nothing gets uploaded to sync and the remote profile wins.
@@ -294,18 +312,27 @@ TEST_F(
AutofillProfileSyncDifferenceTrackerTest,
IncorporateRemoteProfileShouldKeepLocalKeyAndRemoteOriginWhenMergingDuplicateProfileWithSmallerKey) {
AutofillProfile local = AutofillProfile(kBiggerGuid, kHttpsOrigin);
- local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
- local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("John"),
+ structured_address::VerificationStatus::kUserVerified);
+ local.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"),
+ structured_address::VerificationStatus::kUserVerified);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile has the same key.
AutofillProfile remote = AutofillProfile(kSmallerGuid, kSettingsOrigin);
- remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
- remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ remote.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, ASCIIToUTF16("John"),
+ structured_address::VerificationStatus::kUserVerified);
+ remote.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"),
+ structured_address::VerificationStatus::kUserVerified);
+ remote.FinalizeAfterImport();
AutofillProfile merged(local);
merged.set_origin(kSettingsOrigin);
-
IncorporateRemoteProfile(remote);
// Nothing gets uploaded to sync and the remote profile wins except for the
@@ -363,6 +390,7 @@ TEST_F(AutofillProfileSyncDifferenceTrackerTest,
AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
MockCallback<base::OnceClosure> autofill_changes_callback;
@@ -400,6 +428,7 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
local.set_use_count(27);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile matches the local one (except for origin and use count).
@@ -407,7 +436,7 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
remote.set_use_count(13);
-
+ remote.FinalizeAfterImport();
// The remote profile wins (as regards the storage key).
AutofillProfile merged(remote);
// The local origin wins when merging.
@@ -430,6 +459,7 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
local.set_use_count(13);
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile matches the local one and has some additional data.
@@ -438,7 +468,7 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
// Merging two profile takes their max use count, so use count of 27 is taken.
remote.set_use_count(27);
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
MergeSimilarEntriesForInitialSync();
@@ -454,13 +484,14 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
local.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile has a different street address.
AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpOrigin);
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2st st"));
remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
MergeSimilarEntriesForInitialSync();
@@ -477,13 +508,14 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
// The local entry is verified, should not get merged.
AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile is similar to the local one.
AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpOrigin);
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
MergeSimilarEntriesForInitialSync();
@@ -499,6 +531,7 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
MergeSimilarEntriesForInitialSyncDoesNotMatchRemoteVerifiedEntry) {
AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+ local.FinalizeAfterImport();
AddAutofillProfilesToTable({local});
// The remote profile is similar to the local one but is verified and thus it
@@ -506,7 +539,7 @@ TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
AutofillProfile remote = AutofillProfile(kBiggerGuid, kSettingsOrigin);
remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
-
+ remote.FinalizeAfterImport();
IncorporateRemoteProfile(remote);
MergeSimilarEntriesForInitialSync();
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
index e7a4a3a53d8..374a557d888 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
@@ -16,7 +16,7 @@
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_util.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
using autofill::data_util::TruncateUTF8;
using sync_pb::AutofillWalletSpecifics;
@@ -373,6 +373,9 @@ AutofillProfile ProfileFromSpecifics(
profile.GenerateServerProfileIdentifier();
+ // Call the finalization routine to parse the structure of the name and the
+ // address into their components.
+ profile.FinalizeAfterImport();
return profile;
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
index ed222801aee..fd4759dc6a2 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
@@ -8,8 +8,8 @@
#include <memory>
#include <string>
+#include "components/sync/engine/entity_data.h"
#include "components/sync/model/entity_change.h"
-#include "components/sync/model/entity_data.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
index b22bdd06e51..ac068999eca 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
@@ -18,7 +18,7 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/client_tag_hash.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index 2d14512f1f7..52ea59d94bb 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -213,8 +213,10 @@ bool AddAutofillProfileNames(const AutofillProfile& profile,
"conjunction_last_name, conjunction_last_name_status, "
"second_last_name, second_last_name_status, "
"last_name, last_name_status, "
- "full_name, full_name_status) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ "full_name, full_name_status, "
+ "full_name_with_honorific_prefix, "
+ "full_name_with_honorific_prefix_status) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
s.BindString(0, profile.guid());
s.BindString16(1, profile.GetRawInfo(NAME_HONORIFIC_PREFIX));
s.BindInt(2, profile.GetVerificationStatusInt(NAME_HONORIFIC_PREFIX));
@@ -232,6 +234,9 @@ bool AddAutofillProfileNames(const AutofillProfile& profile,
s.BindInt(14, profile.GetVerificationStatusInt(NAME_LAST));
s.BindString16(15, profile.GetRawInfo(NAME_FULL));
s.BindInt(16, profile.GetVerificationStatusInt(NAME_FULL));
+ s.BindString16(17, profile.GetRawInfo(NAME_FULL_WITH_HONORIFIC_PREFIX));
+ s.BindInt(
+ 18, profile.GetVerificationStatusInt(NAME_FULL_WITH_HONORIFIC_PREFIX));
return s.Run();
}
// Add the new name.
@@ -271,8 +276,10 @@ bool AddAutofillProfileAddresses(const AutofillProfile& profile,
"state, state_status, "
"zip_code, zip_code_status, "
"sorting_code, sorting_code_status, "
- "country_code, country_code_status) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ "country_code, country_code_status, "
+ "apartment_number, apartment_number_status, "
+ "floor, floor_status) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
s.BindString(0, profile.guid());
s.BindString16(1, profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
@@ -301,6 +308,10 @@ bool AddAutofillProfileAddresses(const AutofillProfile& profile,
s.BindInt(22, profile.GetVerificationStatusInt(ADDRESS_HOME_SORTING_CODE));
s.BindString16(23, profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
s.BindInt(24, profile.GetVerificationStatusInt(ADDRESS_HOME_COUNTRY));
+ s.BindString16(25, profile.GetRawInfo(ADDRESS_HOME_APT_NUM));
+ s.BindInt(26, profile.GetVerificationStatusInt(ADDRESS_HOME_APT_NUM));
+ s.BindString16(27, profile.GetRawInfo(ADDRESS_HOME_FLOOR));
+ s.BindInt(28, profile.GetVerificationStatusInt(ADDRESS_HOME_FLOOR));
return s.Run();
}
@@ -319,7 +330,8 @@ bool AddAutofillProfileNamesToProfile(sql::Database* db,
"conjunction_last_name, conjunction_last_name_status, "
"second_last_name, second_last_name_status, "
"last_name, last_name_status, "
- "full_name, full_name_status "
+ "full_name, full_name_status, "
+ "full_name_with_honorific_prefix, full_name_with_honorific_prefix_status "
"FROM autofill_profile_names "
"WHERE guid=? "
"LIMIT 1"));
@@ -352,6 +364,9 @@ bool AddAutofillProfileNamesToProfile(sql::Database* db,
NAME_LAST, s.ColumnString16(13), s.ColumnInt(14));
profile->SetRawInfoWithVerificationStatusInt(
NAME_FULL, s.ColumnString16(15), s.ColumnInt(16));
+ profile->SetRawInfoWithVerificationStatusInt(
+ NAME_FULL_WITH_HONORIFIC_PREFIX, s.ColumnString16(17),
+ s.ColumnInt(18));
} else {
// If structured components are not enabled, only use the legacy
// structure.
@@ -388,7 +403,9 @@ bool AddAutofillProfileAddressesToProfile(sql::Database* db,
"state, state_status, "
"zip_code, zip_code_status, "
"sorting_code, sorting_code_status, "
- "country_code, country_code_status "
+ "country_code, country_code_status, "
+ "apartment_number, apartment_number_status, "
+ "floor, floor_status "
"FROM autofill_profile_addresses "
"WHERE guid=? "
"LIMIT 1"));
@@ -455,6 +472,10 @@ bool AddAutofillProfileAddressesToProfile(sql::Database* db,
ADDRESS_HOME_SORTING_CODE, sorting_code, s.ColumnInt(22));
profile->SetRawInfoWithVerificationStatusInt(ADDRESS_HOME_COUNTRY,
country, s.ColumnInt(24));
+ profile->SetRawInfoWithVerificationStatusInt(
+ ADDRESS_HOME_APT_NUM, s.ColumnString16(25), s.ColumnInt(26));
+ profile->SetRawInfoWithVerificationStatusInt(
+ ADDRESS_HOME_FLOOR, s.ColumnString16(27), s.ColumnInt(28));
} else {
// Remove the structured information from the table for
// eventual deletion consistency.
@@ -759,6 +780,12 @@ bool AutofillTable::MigrateToVersion(int version,
case 90:
*update_compatible_version = false;
return MigrateToVersion90AddNewStructuredAddressColumns();
+ case 91:
+ *update_compatible_version = false;
+ return MigrateToVersion91AddMoreStructuredAddressColumns();
+ case 92:
+ *update_compatible_version = false;
+ return MigrateToVersion92AddNewPrefixedNameColumn();
}
return true;
}
@@ -3260,6 +3287,27 @@ bool AutofillTable::MigrateToVersion88AddNewNameColumns() {
return true;
}
+bool AutofillTable::MigrateToVersion92AddNewPrefixedNameColumn() {
+ if (!db_->DoesColumnExist("autofill_profile_names",
+ "full_name_with_honorific_prefix") &&
+ !db_->Execute(
+ base::StrCat({"ALTER TABLE autofill_profile_names ADD COLUMN ",
+ "full_name_with_honorific_prefix", " VARCHAR"})
+ .c_str())) {
+ return false;
+ }
+ if (!db_->DoesColumnExist("autofill_profile_names",
+ "full_name_with_honorific_prefix_status") &&
+ !db_->Execute(
+ base::StrCat({"ALTER TABLE autofill_profile_names ADD COLUMN ",
+ "full_name_with_honorific_prefix_status",
+ " INTEGER DEFAULT 0"})
+ .c_str())) {
+ return false;
+ }
+ return true;
+}
+
bool AutofillTable::MigrateToVersion86RemoveUnmaskedCreditCardsUseColumns() {
// Sqlite does not support "alter table drop column" syntax, so it has be
// done manually.
@@ -3317,6 +3365,35 @@ bool AutofillTable::MigrateToVersion90AddNewStructuredAddressColumns() {
}
return true;
}
+
+bool AutofillTable::MigrateToVersion91AddMoreStructuredAddressColumns() {
+ if (!db_->DoesTableExist("autofill_profile_addresses"))
+ InitProfileAddressesTable();
+
+ for (const char* column : {"apartment_number", "floor"}) {
+ if (!db_->DoesColumnExist("autofill_profile_addresses", column) &&
+ !db_->Execute(
+ base::StrCat({"ALTER TABLE autofill_profile_addresses ADD COLUMN ",
+ column, " VARCHAR"})
+ .c_str())) {
+ return false;
+ }
+ }
+
+ for (const char* column : {"apartment_number_status", "floor_status"}) {
+ // The default value of 0 corresponds to the verification status
+ // |kNoStatus|.
+ if (!db_->DoesColumnExist("autofill_profile_addresses", column) &&
+ !db_->Execute(
+ base::StrCat({"ALTER TABLE autofill_profile_addresses ADD COLUMN ",
+ column, " INTEGER DEFAULT 0"})
+ .c_str())) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool AutofillTable::
MigrateToVersion89AddInstrumentIdColumnToMaskedCreditCard() {
// Add the new instrument_id column to the masked_credit_cards table and set
@@ -3633,24 +3710,27 @@ bool AutofillTable::InitProfileNamesTable() {
if (!db_->DoesTableExist("autofill_profile_names")) {
// The default value of 0 corresponds to the verification status
// |kNoStatus|.
- if (!db_->Execute("CREATE TABLE autofill_profile_names ( "
- "guid VARCHAR, "
- "first_name VARCHAR, "
- "middle_name VARCHAR, "
- "last_name VARCHAR, "
- "full_name VARCHAR, "
- "honorific_prefix VARCHAR, "
- "first_last_name VARCHAR, "
- "conjunction_last_name VARCHAR, "
- "second_last_name VARCHAR, "
- "honorific_prefix_status INTEGER DEFAULT 0, "
- "first_name_status INTEGER DEFAULT 0, "
- "middle_name_status INTEGER DEFAULT 0, "
- "last_name_status INTEGER DEFAULT 0, "
- "first_last_name_status INTEGER DEFAULT 0, "
- "conjunction_last_name_status INTEGER DEFAULT 0, "
- "second_last_name_status INTEGER DEFAULT 0, "
- "full_name_status INTEGER DEFAULT 0)")) {
+ if (!db_->Execute(
+ "CREATE TABLE autofill_profile_names ( "
+ "guid VARCHAR, "
+ "first_name VARCHAR, "
+ "middle_name VARCHAR, "
+ "last_name VARCHAR, "
+ "full_name VARCHAR, "
+ "honorific_prefix VARCHAR, "
+ "first_last_name VARCHAR, "
+ "conjunction_last_name VARCHAR, "
+ "second_last_name VARCHAR, "
+ "honorific_prefix_status INTEGER DEFAULT 0, "
+ "first_name_status INTEGER DEFAULT 0, "
+ "middle_name_status INTEGER DEFAULT 0, "
+ "last_name_status INTEGER DEFAULT 0, "
+ "first_last_name_status INTEGER DEFAULT 0, "
+ "conjunction_last_name_status INTEGER DEFAULT 0, "
+ "second_last_name_status INTEGER DEFAULT 0, "
+ "full_name_status INTEGER DEFAULT 0, "
+ "full_name_with_honorific_prefix VARCHAR, "
+ "full_name_with_honorific_prefix_status INTEGER DEFAULT 0)")) {
NOTREACHED();
return false;
}
@@ -3687,7 +3767,11 @@ bool AutofillTable::InitProfileAddressesTable() {
"state_status INTEGER DEFAULT 0, "
"zip_code_status INTEGER DEFAULT 0, "
"sorting_code_status INTEGER DEFAULT 0, "
- "country_code_status INTEGER DEFAULT 0)")) {
+ "country_code_status INTEGER DEFAULT 0, "
+ "apartment_number VARCHAR, "
+ "floor VARCHAR, "
+ "apartment_number_status INTEGER DEFAULT 0, "
+ "floor_status INTEGER DEFAULT 0)")) {
NOTREACHED();
return false;
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index 8d3824c9653..91b13512f01 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -125,6 +125,8 @@ struct PaymentsCustomerData;
// or organizations that might not be geographically
// contiguous.
// premise_name The name of the premise.
+// apartment_number The number of the apartment.
+// floor The floor in which the apartment is located.
// street_address_status
// street_name_status
// dependent_street_name_status
@@ -137,6 +139,8 @@ struct PaymentsCustomerData;
// zip_code_status
// country_code_status
// sorting_code_status
+// apartment_number_status
+// floor_status
// Each token of the address has an additional validation
// status that indicates if Autofill parsed the value out
// of an unstructured (last) name, or if autofill formatted
@@ -165,6 +169,9 @@ struct PaymentsCustomerData;
// consisting of a single part are stored in the second
// part by default.
// full_name The unstructured full name of a person.
+// full_name_with_honorific_prefix
+// The combination of the full name and the honorific
+// prefix.
// honorific_prefix_status
// first_name_status
// middle_name_status
@@ -172,6 +179,7 @@ struct PaymentsCustomerData;
// first_last_name_status
// conjunction_last_name_status
// second_last_name_status
+// full_name_with_honorific_prefix_status
// Each token of the names has an additional validation
// status that indicates if Autofill parsed the value out
// of an unstructured (last) name, or if autofill formatted
@@ -674,6 +682,8 @@ class AutofillTable : public WebDatabaseTable,
bool MigrateToVersion88AddNewNameColumns();
bool MigrateToVersion89AddInstrumentIdColumnToMaskedCreditCard();
bool MigrateToVersion90AddNewStructuredAddressColumns();
+ bool MigrateToVersion91AddMoreStructuredAddressColumns();
+ bool MigrateToVersion92AddNewPrefixedNameColumn();
// Max data length saved in the table, AKA the maximum length allowed for
// form data.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index aa3324298db..92683da27b8 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -849,8 +849,9 @@ TEST_F(AutofillTableTest, RemoveExpiredFormElements_NotOldEnough) {
TEST_F(AutofillTableTest,
AutofillProfile_StructuredNames_BackAndForthMigration) {
// Enable the structured names.
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ scoped_feature_list_.InitWithFeatures(
+ {features::kAutofillEnableSupportForMoreStructureInNames},
+ {features::kAutofillEnableSupportForMoreStructureInAddresses});
AutofillProfile structured_name_profile;
structured_name_profile.set_origin(std::string());
@@ -1046,7 +1047,7 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
profile.SetRawInfoWithVerificationStatus(
ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("Street Name House Number Premise Subpremise"),
+ ASCIIToUTF16("Street Name House Number Premise APT 10 Floor 2"),
VerificationStatus::kUserVerified);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_NAME,
ASCIIToUTF16("Street Name"),
@@ -1079,8 +1080,12 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
ASCIIToUTF16("House Number"),
VerificationStatus::kUserVerified);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_SUBPREMISE,
- ASCIIToUTF16("Subpremise"),
+ ASCIIToUTF16("APT 10 Floor 2"),
VerificationStatus::kUserVerified);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_APT_NUM, ASCIIToUTF16("10"), VerificationStatus::kParsed);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_FLOOR, ASCIIToUTF16("2"), VerificationStatus::kParsed);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_PREMISE_NAME,
ASCIIToUTF16("Premise"),
VerificationStatus::kUserVerified);
@@ -1108,6 +1113,12 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
EXPECT_EQ(db_profile->GetVerificationStatus(ADDRESS_HOME_SUBPREMISE),
VerificationStatus::kUserVerified);
+ EXPECT_EQ(db_profile->GetVerificationStatus(ADDRESS_HOME_APT_NUM),
+ VerificationStatus::kParsed);
+
+ EXPECT_EQ(db_profile->GetVerificationStatus(ADDRESS_HOME_FLOOR),
+ VerificationStatus::kParsed);
+
EXPECT_EQ(db_profile->GetVerificationStatus(ADDRESS_HOME_PREMISE_NAME),
VerificationStatus::kUserVerified);
@@ -1136,7 +1147,9 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
ASCIIToUTF16("House Number"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_SUBPREMISE),
- ASCIIToUTF16("Subpremise"));
+ ASCIIToUTF16("APT 10 Floor 2"));
+ EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_APT_NUM), ASCIIToUTF16("10"));
+ EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_FLOOR), ASCIIToUTF16("2"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_PREMISE_NAME),
ASCIIToUTF16("Premise"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY),
@@ -1287,8 +1300,9 @@ TEST_F(AutofillTableTest,
// names.
TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
// Enable the structured names.
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ scoped_feature_list_.InitWithFeatures(
+ {features::kAutofillEnableSupportForMoreStructureInNames},
+ {features::kAutofillEnableSupportForMoreStructureInAddresses});
AutofillProfile home_profile;
home_profile.set_origin(std::string());
@@ -1298,6 +1312,10 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
// NAME_HONORIFIC_PREFIX, ASCIIToUTF16("Dr."),
// VerificationStatus::kObserved);
+ home_profile.SetRawInfoWithVerificationStatus(NAME_HONORIFIC_PREFIX,
+ ASCIIToUTF16("Dr."),
+ VerificationStatus::kObserved);
+
home_profile.SetRawInfoWithVerificationStatus(
NAME_FIRST, ASCIIToUTF16("John"), VerificationStatus::kObserved);
@@ -1320,6 +1338,11 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
NAME_FULL, ASCIIToUTF16("John Q. Agent 007 Smith"),
VerificationStatus::kObserved);
+ home_profile.SetRawInfoWithVerificationStatus(
+ NAME_FULL_WITH_HONORIFIC_PREFIX,
+ ASCIIToUTF16("Dr. John Q. Agent 007 Smith"),
+ VerificationStatus::kObserved);
+
home_profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
home_profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
home_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
@@ -1462,8 +1485,9 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
TEST_F(AutofillTableTest, AutofillProfile) {
// Disable the structured names since this test is only applicable if
// structured names are not used.
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillEnableSupportForMoreStructureInNames);
+ scoped_feature_list_.InitWithFeatures(
+ {}, {features::kAutofillEnableSupportForMoreStructureInAddresses,
+ features::kAutofillEnableSupportForMoreStructureInNames});
// Add a 'Home' profile with non-default data. The specific values are not
// important.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
index c89d012e159..746f529720b 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -23,10 +23,10 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_util.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/mutable_data_batch.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/sync_metadata_store_change_list.h"
+#include "components/sync/model/sync_metadata_store_change_list.h"
namespace autofill {
@@ -330,7 +330,7 @@ AutofillWalletMetadataSyncBridge::AutofillWalletMetadataSyncBridge(
: ModelTypeSyncBridge(std::move(change_processor)),
web_data_backend_(web_data_backend) {
DCHECK(web_data_backend_);
- scoped_observer_.Add(web_data_backend_);
+ scoped_observation_.Observe(web_data_backend_);
LoadDataCacheAndMetadata();
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
index 43d98a1eb62..e66390b84e1 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
@@ -10,7 +10,7 @@
#include <unordered_set>
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/sequence_checker.h"
#include "base/supports_user_data.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
@@ -124,9 +124,9 @@ class AutofillWalletMetadataSyncBridge
// SupportsUserData, so it's guaranteed to outlive |this|.
AutofillWebDataBackend* const web_data_backend_;
- ScopedObserver<AutofillWebDataBackend,
- AutofillWebDataServiceObserverOnDBSequence>
- scoped_observer_{this};
+ base::ScopedObservation<AutofillWebDataBackend,
+ AutofillWebDataServiceObserverOnDBSequence>
+ scoped_observation_{this};
// Cache of the local data that allows figuring out the diff for local
// changes; keyed by storage keys.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
index f646c276c19..c0bc6688b43 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
@@ -30,9 +30,9 @@
#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/client_tag_hash.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/data_batch.h"
-#include "components/sync/model/entity_data.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/webdata/common/web_database.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
index bc4c93b79ba..36a70eb8898 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
@@ -15,9 +15,9 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/sync/base/hash_util.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/mutable_data_batch.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/sync_metadata_store_change_list.h"
+#include "components/sync/model/sync_metadata_store_change_list.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
index 5658421d159..c68ffc5acf1 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
@@ -25,10 +25,10 @@
#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/hash_util.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
+#include "components/sync/model/in_memory_metadata_change_list.h"
#include "components/sync/model/sync_data.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/in_memory_metadata_change_list.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index 47f257894e1..04421a3e523 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -25,10 +25,10 @@
#include "components/sync/base/data_type_histogram.h"
#include "components/sync/base/hash_util.h"
#include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/mutable_data_batch.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/sync_metadata_store_change_list.h"
+#include "components/sync/model/sync_metadata_store_change_list.h"
using sync_pb::AutofillWalletSpecifics;
using syncer::EntityData;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index ce186b41372..aa7b8cc416e 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -34,14 +34,14 @@
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/model/entity_data.h"
+#include "components/sync/engine/entity_data.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
+#include "components/sync/model/in_memory_metadata_change_list.h"
#include "components/sync/model/sync_data.h"
-#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/model_impl/in_memory_metadata_change_list.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
-#include "components/sync/test/test_matchers.h"
+#include "components/sync/test/model/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index 948b48e1485..319e579b989 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -41,6 +41,7 @@ static_library("common") {
"form_field_data_predictions.h",
"gaia_id_hash.cc",
"gaia_id_hash.h",
+ "language_code.h",
"logging/log_buffer.cc",
"logging/log_buffer.h",
"password_form_fill_data.cc",
@@ -58,6 +59,7 @@ static_library("common") {
deps = [
"//base",
"//base:i18n",
+ "//build:chromeos_buildflags",
# Note: Can't use mojom:mojo_types here, as that already depends on :common.
"//components/autofill/core/common/mojom:mojo_types_shared",
diff --git a/chromium/components/autofill/core/common/autofill_constants.h b/chromium/components/autofill/core/common/autofill_constants.h
index 07428810cc3..6e1efcc22c7 100644
--- a/chromium/components/autofill/core/common/autofill_constants.h
+++ b/chromium/components/autofill/core/common/autofill_constants.h
@@ -68,12 +68,14 @@ const int64_t kAutocompleteRetentionPolicyPeriodInDays = 14 * 31;
// Limits the number of times the value of a specific type can be filled into a
// form.
-constexpr int kTypeValueFormFillingLimit = 9;
-
// Credit card numbers are sometimes distributed between up to 19 individual
-// fields. Therefore, credit cards need a higher limit compared to
-// |kTypeValueFormFillingLimit|.
-constexpr int kCreditCardTypeValueFormFillingLimit = 19;
+// fields. Therefore, credit cards need a higher limit.
+// State fields are effecectively unlimited because there are sometimes hidden
+// fields select boxes, each with a list of states for one specific countries,
+// which are displayed only upon country selection.
+constexpr size_t kTypeValueFormFillingLimit = 9;
+constexpr size_t kCreditCardTypeValueFormFillingLimit = 19;
+constexpr size_t kStateTypeValueFormFillingLimit = 1000;
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_data_validation.cc b/chromium/components/autofill/core/common/autofill_data_validation.cc
index 67010537037..9fb6165979d 100644
--- a/chromium/components/autofill/core/common/autofill_data_validation.cc
+++ b/chromium/components/autofill/core/common/autofill_data_validation.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/common/autofill_data_validation.h"
+#include "base/ranges/algorithm.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
@@ -38,60 +39,29 @@ bool IsValidFormFieldData(const FormFieldData& field) {
}
bool IsValidFormData(const FormData& form) {
- if (!IsValidString16(form.name) || !IsValidGURL(form.url) ||
- !IsValidGURL(form.action))
- return false;
-
- if (form.fields.size() > kMaxListSize)
- return false;
-
- for (const FormFieldData& field : form.fields) {
- if (!IsValidFormFieldData(field))
- return false;
- }
-
- return true;
+ return IsValidString16(form.name) && IsValidGURL(form.url) &&
+ IsValidGURL(form.action) && form.fields.size() <= kMaxListSize &&
+ base::ranges::all_of(form.fields, &IsValidFormFieldData);
}
bool IsValidPasswordFormFillData(const PasswordFormFillData& form) {
- if (!IsValidString16(form.name) || !IsValidGURL(form.url) ||
- !IsValidGURL(form.action) || !IsValidFormFieldData(form.username_field) ||
- !IsValidFormFieldData(form.password_field) ||
- !IsValidString(form.preferred_realm)) {
- return false;
- }
-
- for (const auto& it : form.additional_logins) {
- if (!IsValidString16(it.username) || !IsValidString16(it.password) ||
- !IsValidString(it.realm))
- return false;
- }
-
- return true;
+ return IsValidString16(form.name) && IsValidGURL(form.url) &&
+ IsValidGURL(form.action) &&
+ IsValidFormFieldData(form.username_field) &&
+ IsValidFormFieldData(form.password_field) &&
+ IsValidString(form.preferred_realm) &&
+ base::ranges::all_of(form.additional_logins, [](const auto& login) {
+ return IsValidString16(login.username) &&
+ IsValidString16(login.password) && IsValidString(login.realm);
+ });
}
bool IsValidString16Vector(const std::vector<base::string16>& v) {
- if (v.size() > kMaxListSize)
- return false;
-
- for (const base::string16& str : v) {
- if (!IsValidString16(str))
- return false;
- }
-
- return true;
+ return v.size() <= kMaxListSize && base::ranges::all_of(v, &IsValidString16);
}
bool IsValidFormDataVector(const std::vector<FormData>& v) {
- if (v.size() > kMaxListSize)
- return false;
-
- for (const FormData& form : v) {
- if (!IsValidFormData(form))
- return false;
- }
-
- return true;
+ return v.size() <= kMaxListSize && base::ranges::all_of(v, &IsValidFormData);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index 349361c1c7b..866f6a9274a 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_service.h"
@@ -20,6 +21,12 @@
namespace autofill {
namespace features {
+// Controls if Autocomplete suggestions are only shown/stored for meaningful
+// field names.
+// TODO(crbug.com/1181759): Remove once launched.
+const base::Feature kAutocompleteFilterForMeaningfulNames{
+ "AutocompleteFilterForMeaningfulNames", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls if Autofill sends votes for the new address types.
const base::Feature kAutofillAddressEnhancementVotes{
"kAutofillAddressEnhancementVotes", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -45,16 +52,6 @@ const base::Feature kAutofillAllowDuplicateFormSubmissions{
const base::Feature kAutofillAllowNonHttpActivation{
"AutofillAllowNonHttpActivation", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillAlwaysFillAddresses{
- "AlwaysFillAddresses", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether negative patterns are used to parse the field type.
-// TODO(crbug.com/1132831): Remove once launched.
-const base::Feature
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics{
- "AutofillApplyNegativePatternsForFieldTypeDetectionHeuristics",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls the use of GET (instead of POST) to fetch cacheable autofill query
// responses.
const base::Feature kAutofillCacheQueryResponses{
@@ -63,12 +60,32 @@ const base::Feature kAutofillCacheQueryResponses{
const base::Feature kAutofillCreateDataForTest{
"AutofillCreateDataForTest", base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls if the heuristic field parsing utilizes shared labels.
+// TODO(crbug/1165780): Remove once shared labels are launched.
+const base::Feature kAutofillEnableSupportForParsingWithSharedLabels{
+ "AutofillEnableSupportForParsingWithSharedLabels",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Kill switch for Autofill filling.
+const base::Feature kAutofillDisableFilling{"AutofillDisableFilling",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Kill switch for Autofill address import.
+const base::Feature kAutofillDisableAddressImport{
+ "AutofillDisableAddressImport", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls if Chrome support filling and importing apartment numbers.
+// TODO(crbug.com/1153715): Remove once launched.
+const base::Feature kAutofillEnableSupportForApartmentNumbers{
+ "AutofillEnableSupportForApartmentNumbers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether we download server credit cards to the ephemeral
// account-based storage when sync the transport is enabled.
const base::Feature kAutofillEnableAccountWalletStorage {
"AutofillEnableAccountWalletStorage",
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_IOS)
- // Wallet transport is only currently available on Win/Mac/Linux.
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_IOS)
+ // Wallet transport is only currently available on Win/Mac/Linux/Android.
// (Somehow, swapping this check makes iOS unhappy?)
base::FEATURE_DISABLED_BY_DEFAULT
#else
@@ -78,14 +95,28 @@ const base::Feature kAutofillEnableAccountWalletStorage {
// Controls whether to detect and fill the augmented phone country code field
// when enabled.
+// TODO(crbug.com/1150890) Remove once launched
const base::Feature kAutofillEnableAugmentedPhoneCountryCode{
"AutofillEnableAugmentedPhoneCountryCode",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls if Autofill parses ADDRESS_HOME_DEPENDENT_LOCALITY.
+// TODO(crbug.com/1157405): Remove once launched.
+const base::Feature kAutofillEnableDependentLocalityParsing{
+ "AutofillEnableDependentLocalityParsing",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether we show "Hide suggestions" item in the suggestions menu.
const base::Feature kAutofillEnableHideSuggestionsUI{
"AutofillEnableHideSuggestionsUI", base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls whether to save the first number in a form with multiple phone
+// numbers instead of aborting the import.
+// TODO(crbug.com/1167484) Remove once launched
+const base::Feature kAutofillEnableImportWhenMultiplePhoneNumbers{
+ "AutofillEnableImportWhenMultiplePhoneNumbers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled and user has single account, a footer indicating user's e-mail
// address and profile picture will appear at the bottom of InfoBars which has
// corresponding account indication footer flags on.
@@ -101,6 +132,14 @@ const base::Feature kAutofillEnableInfoBarAccountIndicationFooterForSyncUsers{
"AutofillEnableInfoBarAccountIndicationFooterForSyncUsers",
base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, the precedence is given to the field label over the name when
+// they match different types. Applied only for parsing of address forms in
+// Turkish.
+// TODO(crbug.com/1156315): Remove once launched.
+const base::Feature kAutofillEnableLabelPrecedenceForTurkishAddresses{
+ "AutofillEnableLabelPrecedenceForTurkishAddresses",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled and user is signed in, a footer indicating user's e-mail address
// and profile picture will appear at the bottom of corresponding password
// InfoBars.
@@ -108,6 +147,11 @@ const base::Feature kAutofillEnablePasswordInfoBarAccountIndicationFooter{
"AutofillEnablePasswordInfoBarAccountIndicationFooter",
base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, the address profile deduplication logic runs after the browser
+// startup, once per chrome version.
+const base::Feature kAutofillEnableProfileDeduplication{
+ "AutofillEnableProfileDeduplication", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls if Autofill supports new structure in names.
// TODO(crbug.com/1098943): Remove once launched.
const base::Feature kAutofillEnableSupportForMoreStructureInNames{
@@ -129,9 +173,9 @@ const base::Feature kAutofillEnableSupportForMergingSubsetNames{
// Controls whether honorific prefix is shown and editable in Autofill Settings
// on Android, iOS and Desktop.
// TODO(crbug.com/1141460): Remove once launched.
-const base::Feature kAutofillEnableUIForHonorificPrefixesInSettings{
- "AutofillEnableUIForHonorificPrefixesInSettings",
- base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillEnableSupportForHonorificPrefixes{
+ "AutofillEnableSupportForHonorificPrefixes",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether or not all datalist shall be extracted into FormFieldData.
// This feature is enabled in both WebView and WebLayer where all datalists
@@ -148,6 +192,12 @@ const base::Feature kAutofillExtractAllDatalists{
const base::Feature kAutofillFixFillableFieldTypes{
"AutofillFixFillableFieldTypes", base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls if a server prediction with a prediction source |OVERRIDE| is
+// granted precedence over html type attributes.
+// TODO(crbug.com/1170384) Remove once launched
+const base::Feature kAutofillServerTypeTakesPrecedence{
+ "AutofillServerTypeTakesPrecedence", base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, Autofill will use FormRendererIds instead of
// GetIdentifierForRefill() to identify forms during refills.
// TODO(crbug/896689): Remove once experiment is finished.
@@ -160,12 +210,12 @@ const base::Feature kAutofillRefillWithRendererIds{
const base::Feature kAutofillNameSectionsWithRendererIds{
"AutofillNameSectionsWithRendererIds", base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, autofill suggestions are displayed in the keyboard accessory
+// When enabled, Autofill suggestions are displayed in the keyboard accessory
// instead of the regular popup.
const base::Feature kAutofillKeyboardAccessory{
"AutofillKeyboardAccessory", base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, autofill will use new logic to strip both prefixes
+// When enabled, Autofill will use new logic to strip both prefixes
// and suffixes when setting FormStructure::parseable_name_
extern const base::Feature kAutofillLabelAffixRemoval{
"AutofillLabelAffixRemoval", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -176,13 +226,33 @@ const base::Feature kAutofillPruneSuggestions{
const base::Feature kAutofillMetadataUploads{"AutofillMetadataUploads",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillOffNoServerData{"AutofillOffNoServerData",
- base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will load remote patterns via the component updater.
+// TODO(crbug/1121990): Remove once launched.
+extern const base::Feature kAutofillParsingPatternsFromRemote{
+ "AutofillParsingPatternsFromRemote", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables detection of language from Translate.
+// TODO(crbug/1150895): Cleanup when launched.
+const base::Feature kAutofillParsingPatternsLanguageDetection{
+ "AutofillParsingPatternsLanguageDetection",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether negative patterns are used to parse the field type.
+// TODO(crbug.com/1132831): Remove once launched.
+const base::Feature kAutofillParsingPatternsNegativeMatching{
+ "AutofillParsingPatternsNegativeMatching",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether page language is used to match patterns.
+// TODO(crbug.com/1134496): Remove once launched.
+const base::Feature kAutofillParsingPatternsLanguageDependent{
+ "AutofillParsingPatternsLanguageDependent",
+ base::FEATURE_DISABLED_BY_DEFAULT};
-// If feature is enabled, autofill will be disabled for mixed forms (forms on
+// If feature is enabled, Autofill will be disabled for mixed forms (forms on
// HTTPS sites that submit over HTTP).
const base::Feature kAutofillPreventMixedFormsFilling{
- "AutofillPreventMixedFormsFilling", base::FEATURE_DISABLED_BY_DEFAULT};
+ "AutofillPreventMixedFormsFilling", base::FEATURE_ENABLED_BY_DEFAULT};
// If the feature is enabled, FormTracker's probable-form-submission detection
// is disabled and replaced with browser-side detection.
@@ -194,6 +264,11 @@ const base::Feature kAutofillProbableFormSubmissionInBrowser{
const base::Feature kAutofillProfileClientValidation{
"AutofillProfileClientValidation", base::FEATURE_DISABLED_BY_DEFAULT};
+// TODO(crbug.com/1101280): Remove once feature is tested.
+const base::Feature kAutofillProfileImportFromUnfocusableFields{
+ "AutofillProfileImportFromUnfocusableFields",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether Autofill uses server-side validation to ensure that fields
// with invalid data are not suggested.
const base::Feature kAutofillProfileServerValidation{
@@ -206,6 +281,11 @@ const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout{
"AutofillRestrictUnownedFieldsToFormlessCheckout",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls whether or not overall prediction are retrieved from the cache.
+const base::Feature kAutofillRetrieveOverallPredictionsFromCache{
+ "AutofillRetrieveOverallPredictionsFromCache",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// On Canary and Dev channels only, this feature flag instructs chrome to send
// rich form/field metadata with queries. This will trigger the use of richer
// field-type predictions model on the server, for testing/evaluation of those
@@ -241,10 +321,11 @@ const base::Feature kAutofillShowTypePredictions{
const base::Feature kAutofillSkipComparingInferredLabels{
"AutofillSkipComparingInferredLabels", base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls whether to skip fields whose last seen value differs from the
-// initially value.
-const base::Feature kAutofillSkipFillingFieldsWithChangedValues{
- "AutofillSkipFillingFieldsWithChangedValues",
+// Controls whether we require an expiration date or verification field when a
+// name field is detected for a credit card, but we aren't confident it's not
+// a non-credit card specific name field.
+const base::Feature kAutofillStrictContextualCardNameConditions{
+ "AutofillStrictContextualCardNameConditions",
base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether Autofill should search prefixes of all words/tokens when
@@ -274,12 +355,6 @@ const base::Feature kAutofillUseImprovedLabelDisambiguation{
const base::Feature kAutofillUseNewSectioningMethod{
"AutofillUseNewSectioningMethod", base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls whether page language is used to match patterns.
-// TODO(crbug.com/1134496): Remove once launched.
-const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns{
- "AutofillUsePageLanguageToSelectFieldParsingPatterns",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
#if defined(OS_ANDROID)
// Controls whether the Autofill manual fallback for Addresses and Payments is
// present on Android.
@@ -306,9 +381,22 @@ const char kAutofillUseMobileLabelDisambiguationParameterShowOne[] = "show-one";
// TODO(crbug/1131038): Remove once it's launched.
const base::Feature kAutofillUseUniqueRendererIDsOnIOS{
"AutofillUseUniqueRendererIDsOnIOS", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether the creation of new address profiles is enabled in settings
+// on IOS.
+// TODO(crbug/1167105): Remove once it's launched.
+const base::Feature kAutofillEnableNewAddressProfileCreationInSettingsOnIOS{
+ "AutofillEnableNewAddressProfileCreationInSettingsOnIOS",
+ base::FEATURE_DISABLED_BY_DEFAULT};
#endif
#if defined(OS_ANDROID)
+// Controls whether Android autofill (WebView and WebLayer) should query the
+// Autofill server for the server field type predictions and send them to
+// Android autofill service.
+const base::Feature kAndroidAutofillQueryServerFieldTypes{
+ "AndroidAutofillQueryServerFieldTypes", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether the Wallet (GPay) integration requires first-sync-setup to
// be complete.
// TODO(crbug.com/1134564): Clean up after launch.
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index 8209085714b..934b73830d6 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -21,55 +21,66 @@ namespace autofill {
namespace features {
// All features in alphabetical order.
+extern const base::Feature kAutocompleteFilterForMeaningfulNames;
extern const base::Feature kAutofillAddressEnhancementVotes;
extern const base::Feature kAutofillAddressProfileSavePrompt;
extern const base::Feature kAutofillAllowDuplicateFormSubmissions;
extern const base::Feature kAutofillAllowNonHttpActivation;
-extern const base::Feature kAutofillAlwaysFillAddresses;
-extern const base::Feature
- kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics;
extern const base::Feature kAutofillCacheQueryResponses;
extern const base::Feature kAutofillCreateDataForTest;
+extern const base::Feature kAutofillDisableFilling;
+extern const base::Feature kAutofillDisableAddressImport;
extern const base::Feature kAutofillEnableAccountWalletStorage;
extern const base::Feature kAutofillEnableAugmentedPhoneCountryCode;
+extern const base::Feature kAutofillEnableDependentLocalityParsing;
extern const base::Feature kAutofillEnableHideSuggestionsUI;
+extern const base::Feature kAutofillEnableImportWhenMultiplePhoneNumbers;
extern const base::Feature
kAutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers;
extern const base::Feature
kAutofillEnableInfoBarAccountIndicationFooterForSyncUsers;
extern const base::Feature
kAutofillEnablePasswordInfoBarAccountIndicationFooter;
+extern const base::Feature kAutofillEnableSupportForApartmentNumbers;
+extern const base::Feature kAutofillEnableLabelPrecedenceForTurkishAddresses;
+extern const base::Feature kAutofillEnableProfileDeduplication;
+extern const base::Feature kAutofillEnableSupportForParsingWithSharedLabels;
extern const base::Feature kAutofillEnableSupportForMoreStructureInNames;
extern const base::Feature kAutofillEnableSupportForMoreStructureInAddresses;
extern const base::Feature kAutofillEnableSupportForMergingSubsetNames;
-extern const base::Feature kAutofillEnableUIForHonorificPrefixesInSettings;
+extern const base::Feature kAutofillEnableSupportForHonorificPrefixes;
extern const base::Feature kAutofillExtractAllDatalists;
extern const base::Feature kAutofillFixFillableFieldTypes;
+extern const base::Feature kAutofillServerTypeTakesPrecedence;
extern const base::Feature kAutofillRefillWithRendererIds;
extern const base::Feature kAutofillNameSectionsWithRendererIds;
extern const base::Feature kAutofillKeyboardAccessory;
extern const base::Feature kAutofillLabelAffixRemoval;
extern const base::Feature kAutofillPruneSuggestions;
extern const base::Feature kAutofillMetadataUploads;
-extern const base::Feature kAutofillOffNoServerData;
+extern const base::Feature kAutofillParsingPatternsFromRemote;
+extern const base::Feature kAutofillParsingPatternsLanguageDetection;
+extern const base::Feature kAutofillParsingPatternsNegativeMatching;
+extern const base::Feature kAutofillParsingPatternsLanguageDependent;
extern const base::Feature kAutofillPreventMixedFormsFilling;
extern const base::Feature kAutofillProbableFormSubmissionInBrowser;
extern const base::Feature kAutofillProfileClientValidation;
+extern const base::Feature kAutofillProfileImportFromUnfocusableFields;
extern const base::Feature kAutofillProfileServerValidation;
extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout;
+extern const base::Feature kAutofillRetrieveOverallPredictionsFromCache;
extern const base::Feature kAutofillRichMetadataQueries;
extern const base::Feature kAutofillSaveAndFillVPA;
extern const base::Feature kAutofillSectionUponRedundantNameInfo;
extern const base::Feature kAutofillServerCommunication;
extern const base::Feature kAutofillShowTypePredictions;
extern const base::Feature kAutofillSkipComparingInferredLabels;
-extern const base::Feature kAutofillSkipFillingFieldsWithChangedValues;
+extern const base::Feature kAutofillStrictContextualCardNameConditions;
extern const base::Feature kAutofillTokenPrefixMatching;
extern const base::Feature kAutofillUploadThrottling;
extern const base::Feature kAutofillUseAlternativeStateNameMap;
extern const base::Feature kAutofillUseImprovedLabelDisambiguation;
extern const base::Feature kAutofillUseNewSectioningMethod;
-extern const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns;
#if defined(OS_ANDROID)
extern const base::Feature kAutofillManualFallbackAndroid;
@@ -91,9 +102,12 @@ bool IsMacViewsAutofillPopupExperimentEnabled();
#if defined(OS_IOS)
extern const base::Feature kAutofillUseUniqueRendererIDsOnIOS;
+extern const base::Feature
+ kAutofillEnableNewAddressProfileCreationInSettingsOnIOS;
#endif // OS_IOS
#if defined(OS_ANDROID)
+extern const base::Feature kAndroidAutofillQueryServerFieldTypes;
extern const base::Feature kWalletRequiresFirstSyncSetupComplete;
#endif
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc
index 8d74f541c6c..1bcfa67eb48 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.cc
+++ b/chromium/components/autofill/core/common/autofill_payments_features.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_service.h"
@@ -28,11 +29,6 @@ const base::Feature kAutofillAlwaysReturnCloudTokenizedCard{
"AutofillAlwaysReturnCloudTokenizedCard",
base::FEATURE_DISABLED_BY_DEFAULT};
-// If enabled, when a server card is unmasked, its info will be cached until
-// page navigation to simplify consecutive fills on the same page.
-const base::Feature kAutofillCacheServerCardInfo{
- "AutofillCacheServerCardInfo", base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kAutofillCreditCardAblationExperiment{
"AutofillCreditCardAblationExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -40,8 +36,8 @@ const base::Feature kAutofillCreditCardAblationExperiment{
// credit cards from Google payments.
const base::Feature kAutofillCreditCardAuthentication{
"AutofillCreditCardAuthentication",
-#if defined(OS_WIN) || defined(OS_MAC)
- // Better Auth project is fully launched on Win/Mac.
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_ANDROID)
+ // Better Auth project is fully launched on Win/Mac/Clank.
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -54,31 +50,26 @@ const base::Feature kAutofillCreditCardAuthentication{
const base::Feature kAutofillCreditCardUploadFeedback{
"AutofillCreditCardUploadFeedback", base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, the credit card nicknames will be manageable. They can be
-// modified locally.
-const base::Feature kAutofillEnableCardNicknameManagement{
- "AutofillEnableCardNicknameManagement", base::FEATURE_DISABLED_BY_DEFAULT};
-
// When enabled, shows the Google Pay logo on CVC prompt on Android.
const base::Feature kAutofillDownstreamCvcPromptUseGooglePayLogo{
"AutofillDownstreamCvcPromptUseGooglePayLogo",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, the credit card nicknames will be manageable. They can be
-// uploaded to Payments.
-const base::Feature kAutofillEnableCardNicknameUpstream{
- "AutofillEnableCardNicknameUpstream", base::FEATURE_DISABLED_BY_DEFAULT};
-
-// When enabled, autofill payments bubbles' result will be recorded as either
-// 'accepted', 'cancelled', 'closed', 'not interacted' or 'lost focus'.
-const base::Feature kAutofillEnableFixedPaymentsBubbleLogging{
- "AutofillEnableFixedPaymentsBubbleLogging",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls whether we show a Google-issued card in the suggestions list.
const base::Feature kAutofillEnableGoogleIssuedCard{
"AutofillEnableGoogleIssuedCard", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, a notification will be displayed on page navigation if the
+// domain has an eligible credit card linked offer or reward.
+const base::Feature kAutofillEnableOfferNotification{
+ "AutofillEnableOfferNotification", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled, offers will be displayed in the Clank keyboard accessory during
+// downstream.
+const base::Feature kAutofillEnableOffersInClankKeyboardAccessory{
+ "AutofillEnableOffersInClankKeyboardAccessory",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, offer data will be retrieved during downstream and shown in
// the dropdown list.
const base::Feature kAutofillEnableOffersInDownstream{
@@ -90,11 +81,6 @@ const base::Feature kAutofillEnableSaveCardInfoBarAccountIndicationFooter{
"AutofillEnableSaveCardInfoBarAccountIndicationFooter",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, all payments related bubbles will not be dismissed upon page
-// navigation.
-const base::Feature kAutofillEnableStickyPaymentsBubble{
- "AutofillEnableStickyPaymentsBubble", base::FEATURE_DISABLED_BY_DEFAULT};
-
// When enabled, Autofill data related icons will be shown in the status
// chip in toolbar along with the avatar toolbar button.
const base::Feature kAutofillEnableToolbarStatusChip{
@@ -114,6 +100,11 @@ const base::Feature kAutofillSaveCardDismissOnNavigation{
const base::Feature kAutofillSaveCardInfobarEditSupport{
"AutofillSaveCardInfobarEditSupport", base::FEATURE_ENABLED_BY_DEFAULT};
+// When enabled, suggestions with offers will be shown at the top.
+const base::Feature kAutofillSortSuggestionsBasedOnOfferPresence{
+ "AutofillSortSuggestionsBasedOnOfferPresence",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// Controls offering credit card upload to Google Payments. Cannot ever be
// ENABLED_BY_DEFAULT because the feature state depends on the user's country.
// There are countries we simply can't turn this on for, and they change over
@@ -128,8 +119,10 @@ const base::Feature kAutofillUpstreamAllowAllEmailDomains{
"AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT};
bool ShouldShowImprovedUserConsentForCreditCardSave() {
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
#if defined(OS_WIN) || defined(OS_APPLE) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+ (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// The new user consent UI is fully launched on MacOS, Windows and Linux.
return true;
#else
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h
index 4cadf5421ad..82c39b64954 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.h
+++ b/chromium/components/autofill/core/common/autofill_payments_features.h
@@ -20,23 +20,21 @@ namespace features {
// All features in alphabetical order.
extern const base::Feature kAutofillAlwaysReturnCloudTokenizedCard;
-extern const base::Feature kAutofillCacheServerCardInfo;
extern const base::Feature kAutofillCreditCardAblationExperiment;
extern const base::Feature kAutofillCreditCardAuthentication;
extern const base::Feature kAutofillCreditCardUploadFeedback;
extern const base::Feature kAutofillDownstreamCvcPromptUseGooglePayLogo;
-extern const base::Feature kAutofillEnableCardNicknameManagement;
-extern const base::Feature kAutofillEnableCardNicknameUpstream;
-extern const base::Feature kAutofillEnableFixedPaymentsBubbleLogging;
extern const base::Feature kAutofillEnableGoogleIssuedCard;
+extern const base::Feature kAutofillEnableOfferNotification;
+extern const base::Feature kAutofillEnableOffersInClankKeyboardAccessory;
extern const base::Feature kAutofillEnableOffersInDownstream;
extern const base::Feature
kAutofillEnableSaveCardInfoBarAccountIndicationFooter;
-extern const base::Feature kAutofillEnableStickyPaymentsBubble;
extern const base::Feature kAutofillEnableToolbarStatusChip;
extern const base::Feature kAutofillEnableVirtualCard;
extern const base::Feature kAutofillSaveCardDismissOnNavigation;
extern const base::Feature kAutofillSaveCardInfobarEditSupport;
+extern const base::Feature kAutofillSortSuggestionsBasedOnOfferPresence;
extern const base::Feature kAutofillUpstream;
extern const base::Feature kAutofillUpstreamAllowAllEmailDomains;
diff --git a/chromium/components/autofill/core/common/autofill_util.cc b/chromium/components/autofill/core/common/autofill_util.cc
index d9a17f403a6..807dd4458cb 100644
--- a/chromium/components/autofill/core/common/autofill_util.cc
+++ b/chromium/components/autofill/core/common/autofill_util.cc
@@ -126,10 +126,6 @@ bool IsDesktopPlatform() {
#endif
}
-bool ShouldSkipField(const FormFieldData& field) {
- return IsCheckable(field.check_status);
-}
-
bool IsCheckable(const FormFieldData::CheckStatus& check_status) {
return check_status != FormFieldData::CheckStatus::kNotCheckable;
}
diff --git a/chromium/components/autofill/core/common/autofill_util.h b/chromium/components/autofill/core/common/autofill_util.h
index 240c7a31090..f2e0f271c0b 100644
--- a/chromium/components/autofill/core/common/autofill_util.h
+++ b/chromium/components/autofill/core/common/autofill_util.h
@@ -67,8 +67,6 @@ size_t GetTextSelectionStart(const base::string16& suggestion,
// Android or iOS is considered desktop.
bool IsDesktopPlatform();
-bool ShouldSkipField(const FormFieldData& field);
-
bool IsCheckable(const FormFieldData::CheckStatus& check_status);
bool IsChecked(const FormFieldData::CheckStatus& check_status);
void SetCheckStatus(FormFieldData* form_field_data,
diff --git a/chromium/components/autofill/core/common/dense_set.h b/chromium/components/autofill/core/common/dense_set.h
index cd52b04a025..3f4897d74dc 100644
--- a/chromium/components/autofill/core/common/dense_set.h
+++ b/chromium/components/autofill/core/common/dense_set.h
@@ -23,18 +23,18 @@ namespace autofill {
// representation.
//
// The lower and upper bounds of elements storable in a container are
-// [T(0), kEnd).
+// [T(0), kMaxValue]. By default, kMaxValue is T::kMaxValue.
//
// Internally, the set is represented as a std::bitset.
//
// Time and space complexity depend on std::bitset:
// - insert(), erase(), contains() should run in time O(1)
-// - empty(), size(), iteration should run in time O(kEnd)
-// - sizeof(DenseSet) should be ceil(kEnd / 8) bytes.
+// - empty(), size(), iteration should run in time O(kMaxValue)
+// - sizeof(DenseSet) should be ceil(kMaxValue / 8) bytes.
//
// Iterators are invalidated when the owning container is destructed or moved,
// or when the element the iterator points to is erased from the container.
-template <typename T, T kEnd>
+template <typename T, T kMaxValue = T::kMaxValue>
class DenseSet {
private:
using Index = std::make_unsigned_t<T>;
@@ -194,6 +194,9 @@ class DenseSet {
return {find(x), !contained};
}
+ // Inserts all values of |xs| into the present set.
+ void insert_all(const DenseSet& xs) { bitset_ |= xs.bitset_; }
+
// Erases the element whose index matches the index of |x| and returns the
// number of erased elements (0 or 1).
size_t erase(T x) {
@@ -220,6 +223,9 @@ class DenseSet {
return last;
}
+ // Erases all values of |xs| into the present set.
+ void erase_all(const DenseSet& xs) { bitset_ &= ~xs.bitset_; }
+
// Lookup.
// Returns 1 if |x| is an element, otherwise 0.
@@ -233,6 +239,21 @@ class DenseSet {
// Returns true if |x| is an element, else |false|.
bool contains(T x) const { return bitset_.test(value_to_index(x)); }
+ // Returns true if some element of |xs| is an element, else |false|.
+ bool contains_none(const DenseSet& xs) const {
+ return (bitset_ & xs.bitset_).none();
+ }
+
+ // Returns true if some element of |xs| is an element, else |false|.
+ bool contains_any(const DenseSet& xs) const {
+ return (bitset_ & xs.bitset_).any();
+ }
+
+ // Returns true if every elements of |xs| is an element, else |false|.
+ bool contains_all(const DenseSet& xs) const {
+ return (bitset_ & xs.bitset_) == xs.bitset_;
+ }
+
// Returns an iterator to the first element not less than the |x|, or end().
const_iterator lower_bound(T x) const {
const_iterator it(this, value_to_index(x));
@@ -255,12 +276,12 @@ class DenseSet {
};
static constexpr Index value_to_index(T x) {
- DCHECK(index_to_value(0) <= x && x < kEnd);
+ DCHECK(index_to_value(0) <= x && x <= kMaxValue);
return base::checked_cast<Index>(x);
}
static constexpr T index_to_value(Index i) {
- DCHECK_LT(i, base::checked_cast<Index>(kEnd));
+ DCHECK_LE(i, base::checked_cast<Index>(kMaxValue));
using UnderlyingType =
typename std::conditional_t<std::is_enum<T>::value,
std::underlying_type<T>, Wrapper>::type;
@@ -268,9 +289,9 @@ class DenseSet {
}
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
- static_assert(index_to_value(0) <= kEnd, "");
+ static_assert(0 <= base::checked_cast<Index>(kMaxValue) + 1, "");
- std::bitset<base::checked_cast<Index>(kEnd)> bitset_{};
+ std::bitset<base::checked_cast<Index>(kMaxValue) + 1> bitset_{};
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/dense_set_unittest.cc b/chromium/components/autofill/core/common/dense_set_unittest.cc
index c6df3972962..d99bc000495 100644
--- a/chromium/components/autofill/core/common/dense_set_unittest.cc
+++ b/chromium/components/autofill/core/common/dense_set_unittest.cc
@@ -19,9 +19,9 @@ TEST(DenseSet, initialization) {
Three = 3,
Four = 4,
Five = 5,
- kEnd = 6
+ kMaxValue = Five,
};
- using DS = DenseSet<T, T::kEnd>;
+ using DS = DenseSet<T>;
DS s;
EXPECT_TRUE(s.empty());
@@ -45,9 +45,9 @@ TEST(DenseSet, iterators_begin_end) {
Three = 3,
Four = 4,
Five = 5,
- kEnd = 6
+ kMaxValue = Five,
};
- using DS = DenseSet<T, T::kEnd>;
+ using DS = DenseSet<T, T::kMaxValue>;
DS s;
s.insert(T::Two);
@@ -88,9 +88,9 @@ TEST(DenseSet, iterators_begin_end_reverse) {
Three = 3,
Four = 4,
Five = 5,
- kEnd = 6
+ kMaxValue = Five,
};
- using DS = DenseSet<T, T::kEnd>;
+ using DS = DenseSet<T>;
DS s;
s.insert(T::Two);
@@ -123,8 +123,15 @@ TEST(DenseSet, iterators_begin_end_reverse) {
}
TEST(DenseSet, iterators_rbegin_rend) {
- enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
- using DS = DenseSet<T, T::kEnd>;
+ enum class T {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kMaxValue = Five
+ };
+ using DS = DenseSet<T, T::kMaxValue>;
DS s;
s.insert(T::Two);
@@ -160,8 +167,15 @@ TEST(DenseSet, iterators_rbegin_rend) {
}
TEST(DenseSet, lookup) {
- enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
- using DS = DenseSet<T, T::kEnd>;
+ enum class T {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kMaxValue = Five
+ };
+ using DS = DenseSet<T, T::kMaxValue>;
DS s;
s.insert(T::Two);
@@ -199,11 +213,37 @@ TEST(DenseSet, lookup) {
EXPECT_NE(s.find(T::Three), s.lower_bound(T::Three));
EXPECT_EQ(s.find(T::Four), s.lower_bound(T::Four));
EXPECT_EQ(s.find(T::Five), s.lower_bound(T::Five));
+
+ DS t;
+ EXPECT_TRUE(t.empty());
+ EXPECT_TRUE(t.contains_none({}));
+ EXPECT_FALSE(t.contains_any({}));
+ EXPECT_TRUE(t.contains_all({}));
+
+ t.insert_all(s);
+ EXPECT_EQ(s, t);
+ EXPECT_FALSE(s.contains_none(t));
+ EXPECT_TRUE(s.contains_any(t));
+ EXPECT_TRUE(s.contains_all(t));
+ EXPECT_TRUE(s.contains_none({}));
+ EXPECT_FALSE(s.contains_any({}));
+ EXPECT_TRUE(s.contains_all({}));
+
+ t.erase(t.begin());
+ EXPECT_FALSE(s.contains_none(t));
+ EXPECT_TRUE(s.contains_any(t));
+ EXPECT_TRUE(s.contains_all(t));
+ EXPECT_FALSE(t.contains_none(s));
+ EXPECT_FALSE(t.contains_all(s));
+ EXPECT_TRUE(t.contains_any(s));
+ EXPECT_TRUE(s.contains_none({}));
+ EXPECT_FALSE(s.contains_any({}));
+ EXPECT_TRUE(s.contains_all({}));
}
TEST(DenseSet, iterators_lower_upper_bound) {
- enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
- using DS = DenseSet<T, T::kEnd>;
+ enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5 };
+ using DS = DenseSet<T, T::Five>;
DS s;
s.insert(T::Two);
@@ -276,8 +316,8 @@ TEST(DenseSet, max_size) {
// const int Three = 3;
const int Four = 4;
// const int Five = 5;
- const int kEnd = 6;
- using DS = DenseSet<int, kEnd>;
+ const int kMaxValue = 5;
+ using DS = DenseSet<int, kMaxValue>;
DS s;
EXPECT_TRUE(s.empty());
@@ -301,8 +341,8 @@ TEST(DenseSet, modifiers) {
const size_t Three = 3;
const size_t Four = 4;
// const size_t Five = 5;
- const size_t kEnd = 6;
- using DS = DenseSet<size_t, kEnd>;
+ const size_t kMaxValue = 5;
+ using DS = DenseSet<size_t, kMaxValue>;
DS s;
s.insert(Two);
@@ -375,7 +415,35 @@ TEST(DenseSet, modifiers) {
s.clear();
EXPECT_EQ(s, DS());
- EXPECT_EQ(s.size(), 0u);
+ EXPECT_TRUE(s.empty());
+
+ s.insert(Three);
+ s.insert_all(t);
+ EXPECT_EQ(s.size(), 4u);
+ EXPECT_EQ(t.size(), 3u);
+ EXPECT_NE(s, t);
+ EXPECT_FALSE(s.contains_none(t));
+ EXPECT_TRUE(s.contains_any(t));
+ EXPECT_TRUE(s.contains_all(t));
+ EXPECT_TRUE(s.contains(Three));
+ EXPECT_FALSE(t.contains_none(s));
+ EXPECT_TRUE(t.contains_any(s));
+ EXPECT_FALSE(t.contains_all(s));
+
+ s.erase_all(t);
+ EXPECT_EQ(s.size(), 1u);
+ EXPECT_TRUE(s.contains(Three));
+ EXPECT_TRUE(s.contains_none(t));
+ EXPECT_FALSE(s.contains_any(t));
+ EXPECT_FALSE(s.contains_all(t));
+
+ s.insert_all(t);
+ s.erase(Three);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(s, t);
+
+ s.erase_all(t);
+ EXPECT_TRUE(s.empty());
EXPECT_INSERTION(s, *t.begin(), true);
EXPECT_TRUE(s.contains(One));
@@ -389,8 +457,8 @@ TEST(DenseSet, modifiers) {
}
TEST(DenseSet, std_set) {
- constexpr size_t kEnd = 50;
- DenseSet<size_t, kEnd> dense_set;
+ constexpr size_t kMaxValue = 50;
+ DenseSet<size_t, kMaxValue> dense_set;
std::set<size_t> std_set;
auto expect_equivalence = [&] {
@@ -401,7 +469,7 @@ TEST(DenseSet, std_set) {
auto random_insert = [&] {
expect_equivalence();
- size_t value = base::RandUint64() % kEnd;
+ size_t value = base::RandUint64() % kMaxValue;
auto p = dense_set.insert(value);
auto q = std_set.insert(value);
EXPECT_EQ(p.second, q.second);
@@ -412,13 +480,13 @@ TEST(DenseSet, std_set) {
auto random_erase = [&] {
expect_equivalence();
- size_t value = base::RandUint64() % kEnd;
+ size_t value = base::RandUint64() % kMaxValue;
EXPECT_EQ(dense_set.erase(value), std_set.erase(value));
};
auto random_erase_iterator = [&] {
expect_equivalence();
- size_t value = base::RandUint64() % kEnd;
+ size_t value = base::RandUint64() % kMaxValue;
auto it = dense_set.find(value);
auto jt = std_set.find(value);
EXPECT_EQ(it == dense_set.end(), jt == std_set.end());
@@ -434,8 +502,8 @@ TEST(DenseSet, std_set) {
auto random_erase_range = [&] {
expect_equivalence();
- size_t min_value = base::RandUint64() % kEnd;
- size_t max_value = base::RandUint64() % kEnd;
+ size_t min_value = base::RandUint64() % kMaxValue;
+ size_t max_value = base::RandUint64() % kMaxValue;
min_value = std::min(min_value, max_value);
max_value = std::max(min_value, max_value);
dense_set.erase(dense_set.lower_bound(min_value),
@@ -444,11 +512,11 @@ TEST(DenseSet, std_set) {
std_set.upper_bound(max_value));
};
- for (size_t i = 0; i < kEnd; ++i) {
+ for (size_t i = 0; i < kMaxValue; ++i) {
random_insert();
}
- for (size_t i = 0; i < kEnd / 2; ++i) {
+ for (size_t i = 0; i < kMaxValue / 2; ++i) {
random_erase();
}
@@ -457,11 +525,11 @@ TEST(DenseSet, std_set) {
std_set.clear();
expect_equivalence();
- for (size_t i = 0; i < kEnd; ++i) {
+ for (size_t i = 0; i < kMaxValue; ++i) {
random_insert();
}
- for (size_t i = 0; i < kEnd; ++i) {
+ for (size_t i = 0; i < kMaxValue; ++i) {
random_erase_iterator();
}
@@ -470,11 +538,11 @@ TEST(DenseSet, std_set) {
std_set.clear();
expect_equivalence();
- for (size_t i = 0; i < kEnd; ++i) {
+ for (size_t i = 0; i < kMaxValue; ++i) {
random_insert();
}
- for (size_t i = 0; i < kEnd; ++i) {
+ for (size_t i = 0; i < kMaxValue; ++i) {
random_erase_range();
}
diff --git a/chromium/components/autofill/core/common/field_data_manager.cc b/chromium/components/autofill/core/common/field_data_manager.cc
index 90712097017..860c8f63c79 100644
--- a/chromium/components/autofill/core/common/field_data_manager.cc
+++ b/chromium/components/autofill/core/common/field_data_manager.cc
@@ -13,7 +13,6 @@ FieldDataManager::FieldDataManager() = default;
void FieldDataManager::ClearData() {
field_value_and_properties_map_.clear();
- autofilled_values_map_.clear();
}
bool FieldDataManager::HasFieldData(FieldRendererId id) const {
@@ -21,7 +20,7 @@ bool FieldDataManager::HasFieldData(FieldRendererId id) const {
field_value_and_properties_map_.end();
}
-base::string16 FieldDataManager::GetUserTypedValue(FieldRendererId id) const {
+base::string16 FieldDataManager::GetUserInput(FieldRendererId id) const {
DCHECK(HasFieldData(id));
return field_value_and_properties_map_.at(id).first.value_or(
base::string16());
@@ -86,30 +85,6 @@ bool FieldDataManager::WasAutofilledOnUserTrigger(FieldRendererId id) const {
FieldPropertiesFlags::kAutofilledOnUserTrigger);
}
-bool FieldDataManager::WasAutofilledOnPageLoad(FieldRendererId id) const {
- return HasFieldData(id) && (GetFieldPropertiesMask(id) &
- FieldPropertiesFlags::kAutofilledOnPageLoad);
-}
-
-void FieldDataManager::UpdateFieldDataWithAutofilledValue(
- FieldRendererId id,
- const base::string16& value,
- FieldPropertiesMask mask) {
- // Typed value has no interest once it is rewritten with an autofilled value.
- if (HasFieldData(id))
- field_value_and_properties_map_.at(id).first.reset();
- UpdateFieldDataMapWithNullValue(id, mask);
- autofilled_values_map_[id] = value;
-}
-
-base::Optional<base::string16> FieldDataManager::GetAutofilledValue(
- FieldRendererId id) const {
- if (autofilled_values_map_.count(id))
- return base::Optional<base::string16>(autofilled_values_map_.at(id));
- else
- return base::nullopt;
-}
-
FieldDataManager::~FieldDataManager() = default;
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/field_data_manager.h b/chromium/components/autofill/core/common/field_data_manager.h
index 501eabc9f4b..5ce658e6099 100644
--- a/chromium/components/autofill/core/common/field_data_manager.h
+++ b/chromium/components/autofill/core/common/field_data_manager.h
@@ -38,7 +38,9 @@ class FieldDataManager : public base::RefCounted<FieldDataManager> {
void UpdateFieldDataMapWithNullValue(FieldRendererId id,
FieldPropertiesMask mask);
- base::string16 GetUserTypedValue(FieldRendererId id) const;
+ // Returns value that was either typed or manually autofilled into the field.
+ base::string16 GetUserInput(FieldRendererId id) const;
+
FieldPropertiesMask GetFieldPropertiesMask(FieldRendererId id) const;
// Check if the string |value| is saved in |field_value_and_properties_map_|.
@@ -52,24 +54,12 @@ class FieldDataManager : public base::RefCounted<FieldDataManager> {
return field_value_and_properties_map_;
}
- bool WasAutofilledOnPageLoad(FieldRendererId id) const;
-
- // Update data with autofilled value.
- void UpdateFieldDataWithAutofilledValue(FieldRendererId id,
- const base::string16& value,
- FieldPropertiesMask mask);
-
- base::Optional<base::string16> GetAutofilledValue(FieldRendererId id) const;
-
private:
friend class base::RefCounted<FieldDataManager>;
~FieldDataManager();
FieldDataMap field_value_and_properties_map_;
-
- // Stores values autofilled either on page load or on user trigger.
- std::map<FieldRendererId, base::string16> autofilled_values_map_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/field_data_manager_unittest.cc b/chromium/components/autofill/core/common/field_data_manager_unittest.cc
index 8c56453876e..ca525b3a14a 100644
--- a/chromium/components/autofill/core/common/field_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/common/field_data_manager_unittest.cc
@@ -44,14 +44,14 @@ TEST_F(FieldDataManagerTest, UpdateFieldDataMap) {
FieldPropertiesFlags::kUserTyped);
const FieldRendererId id(control_elements_[0].unique_renderer_id);
EXPECT_TRUE(field_data_manager->HasFieldData(id));
- EXPECT_EQ(UTF8ToUTF16("first"), field_data_manager->GetUserTypedValue(id));
+ EXPECT_EQ(UTF8ToUTF16("first"), field_data_manager->GetUserInput(id));
EXPECT_EQ(FieldPropertiesFlags::kUserTyped,
field_data_manager->GetFieldPropertiesMask(id));
field_data_manager->UpdateFieldDataMap(
control_elements_[0].unique_renderer_id, UTF8ToUTF16("newvalue"),
FieldPropertiesFlags::kAutofilled);
- EXPECT_EQ(UTF8ToUTF16("newvalue"), field_data_manager->GetUserTypedValue(id));
+ EXPECT_EQ(UTF8ToUTF16("newvalue"), field_data_manager->GetUserInput(id));
FieldPropertiesMask mask =
FieldPropertiesFlags::kUserTyped | FieldPropertiesFlags::kAutofilled;
EXPECT_EQ(mask, field_data_manager->GetFieldPropertiesMask(id));
@@ -75,14 +75,14 @@ TEST_F(FieldDataManagerTest, UpdateFieldDataMapWithNullValue) {
FieldPropertiesFlags::kUserTyped);
const FieldRendererId id(control_elements_[0].unique_renderer_id);
EXPECT_TRUE(field_data_manager->HasFieldData(id));
- EXPECT_EQ(base::string16(), field_data_manager->GetUserTypedValue(id));
+ EXPECT_EQ(base::string16(), field_data_manager->GetUserInput(id));
EXPECT_EQ(FieldPropertiesFlags::kUserTyped,
field_data_manager->GetFieldPropertiesMask(id));
field_data_manager->UpdateFieldDataMapWithNullValue(
control_elements_[0].unique_renderer_id,
FieldPropertiesFlags::kAutofilled);
- EXPECT_EQ(base::string16(), field_data_manager->GetUserTypedValue(id));
+ EXPECT_EQ(base::string16(), field_data_manager->GetUserInput(id));
FieldPropertiesMask mask =
FieldPropertiesFlags::kUserTyped | FieldPropertiesFlags::kAutofilled;
EXPECT_EQ(mask, field_data_manager->GetFieldPropertiesMask(id));
@@ -90,7 +90,7 @@ TEST_F(FieldDataManagerTest, UpdateFieldDataMapWithNullValue) {
field_data_manager->UpdateFieldDataMap(
control_elements_[0].unique_renderer_id, control_elements_[0].value,
FieldPropertiesFlags::kAutofilled);
- EXPECT_EQ(UTF8ToUTF16("first"), field_data_manager->GetUserTypedValue(id));
+ EXPECT_EQ(UTF8ToUTF16("first"), field_data_manager->GetUserInput(id));
}
TEST_F(FieldDataManagerTest, FindMachedValue) {
@@ -105,23 +105,4 @@ TEST_F(FieldDataManagerTest, FindMachedValue) {
field_data_manager->FindMachedValue(UTF8ToUTF16("second_element")));
}
-TEST_F(FieldDataManagerTest, UpdateFieldDataMapWithAutofilledValue) {
- const scoped_refptr<FieldDataManager> field_data_manager =
- base::MakeRefCounted<FieldDataManager>();
- const FieldRendererId id(control_elements_[0].unique_renderer_id);
- // Add a typed value to make sure it will be cleared.
- field_data_manager->UpdateFieldDataMap(id, ASCIIToUTF16("typedvalue"), 0);
-
- field_data_manager->UpdateFieldDataWithAutofilledValue(
- id, ASCIIToUTF16("autofilled"),
- FieldPropertiesFlags::kAutofilledOnPageLoad);
-
- EXPECT_TRUE(field_data_manager->HasFieldData(id));
- EXPECT_EQ(base::string16(), field_data_manager->GetUserTypedValue(id));
- EXPECT_EQ(UTF8ToUTF16("autofilled"),
- field_data_manager->GetAutofilledValue(id));
- EXPECT_EQ(FieldPropertiesFlags::kAutofilledOnPageLoad,
- field_data_manager->GetFieldPropertiesMask(id));
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc
index 0861134e659..dd5ccbc4791 100644
--- a/chromium/components/autofill/core/common/form_data.cc
+++ b/chromium/components/autofill/core/common/form_data.cc
@@ -145,7 +145,7 @@ bool FormData::IdentityComparator::operator()(const FormData& a,
bool FormHasNonEmptyPasswordField(const FormData& form) {
for (const auto& field : form.fields) {
if (field.IsPasswordInputElement()) {
- if (!field.value.empty() || !field.typed_value.empty())
+ if (!field.value.empty() || !field.user_input.empty())
return true;
}
}
diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc
index fc998f879ef..26585e31b65 100644
--- a/chromium/components/autofill/core/common/form_field_data.cc
+++ b/chromium/components/autofill/core/common/form_field_data.cc
@@ -417,7 +417,7 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field) {
<< "text_direction=" << field.text_direction << " "
<< "is_enabled=" << field.is_enabled << " "
<< "is_readonly=" << field.is_readonly << " "
- << "typed_value=" << field.typed_value << " "
+ << "user_input=" << field.user_input << " "
<< "properties_mask=" << field.properties_mask << " "
<< "label_source=" << field.label_source << " "
<< "bounds=" << field.bounds.ToString();
diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h
index 84becbef96c..d9778424a43 100644
--- a/chromium/components/autofill/core/common/form_field_data.h
+++ b/chromium/components/autofill/core/common/form_field_data.h
@@ -173,7 +173,9 @@ struct FormFieldData {
// serialised for storage.
bool is_enabled = false;
bool is_readonly = false;
- base::string16 typed_value;
+ // Contains value that was either manually typed or autofilled on user
+ // trigger.
+ base::string16 user_input;
// For the HTML snippet |<option value="US">United States</option>|, the
// value is "US" and the contents are "United States".
diff --git a/chromium/components/autofill/core/common/language_code.h b/chromium/components/autofill/core/common/language_code.h
new file mode 100644
index 00000000000..ae6570fea99
--- /dev/null
+++ b/chromium/components/autofill/core/common/language_code.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_LANGUAGE_CODE_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_LANGUAGE_CODE_H_
+
+#include <cctype>
+#include <string>
+#include <utility>
+
+#include "base/check.h"
+#include "base/ranges/algorithm.h"
+#include "base/types/strong_alias.h"
+
+namespace autofill {
+
+// Following the implicit conventions in //components/translate, a LanguageCode
+// is a lowercase alphabetic string of length up to 3, or "zh-CN", or "zh-TW". A
+// non-exhaustive list of common values is
+// translate::kDefaultSupportedLanguages.
+// C++ small string optimization keeps these objects lightweight so that copying
+// should not be a worry.
+class LanguageCode
+ : public base::StrongAlias<class LanguageCodeTag, std::string> {
+ private:
+ using BaseClass = base::StrongAlias<LanguageCodeTag, std::string>;
+
+ public:
+ LanguageCode() = default;
+ explicit LanguageCode(const char* s) : BaseClass(s) { Check(); }
+ explicit LanguageCode(std::string&& s) : BaseClass(std::move(s)) { Check(); }
+ explicit LanguageCode(const std::string& s) : BaseClass(s) { Check(); }
+
+ private:
+ void Check() {
+ DCHECK(((*this)->size() <= 3 && base::ranges::all_of(value(), &islower)) ||
+ value() == "zh-CN" || value() == "zh-TW")
+ << "Unexpected language code '" << value() << "'";
+ }
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_LANGUAGE_CODE_H_
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
index 4c35cd75787..f0a1654c991 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
@@ -132,7 +132,7 @@ struct FormFieldData {
mojo_base.mojom.TextDirection text_direction;
bool is_enabled;
bool is_readonly;
- mojo_base.mojom.String16 typed_value;
+ mojo_base.mojom.String16 user_input;
array<mojo_base.mojom.String16> option_values;
array<mojo_base.mojom.String16> option_contents;
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 7f8ccc299c0..7f9fb938595 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -90,7 +90,7 @@ bool StructTraits<
out->is_enabled = data.is_enabled();
out->is_readonly = data.is_readonly();
- if (!data.ReadTypedValue(&out->typed_value))
+ if (!data.ReadUserInput(&out->user_input))
return false;
if (!data.ReadOptionValues(&out->option_values))
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 8b910689db4..4863cad0561 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -153,8 +153,8 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView,
return r.is_readonly;
}
- static const base::string16& typed_value(const autofill::FormFieldData& r) {
- return r.typed_value;
+ static const base::string16& user_input(const autofill::FormFieldData& r) {
+ return r.user_input;
}
static const std::vector<base::string16>& option_values(
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
index 5b9b8780e67..6e9744467b3 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
@@ -187,7 +187,7 @@ void ExpectFormFieldData(const FormFieldData& expected,
const FormFieldData& passed) {
EXPECT_TRUE(EquivalentData(expected, passed));
EXPECT_EQ(expected.value, passed.value);
- EXPECT_EQ(expected.typed_value, passed.typed_value);
+ EXPECT_EQ(expected.user_input, passed.user_input);
std::move(closure).Run();
}
@@ -256,7 +256,7 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) {
input.role = FormFieldData::RoleAttribute::kPresentation;
input.text_direction = base::i18n::RIGHT_TO_LEFT;
input.properties_mask = FieldPropertiesFlags::kHadFocus;
- input.typed_value = base::ASCIIToUTF16("TestTypedValue");
+ input.user_input = base::ASCIIToUTF16("TestTypedValue");
input.bounds = gfx::RectF(1, 2, 10, 100);
base::RunLoop loop;
@@ -286,7 +286,7 @@ TEST_F(AutofillTypeTraitsTestImpl, PassDataListFormFieldData) {
input.role = FormFieldData::RoleAttribute::kPresentation;
input.text_direction = base::i18n::RIGHT_TO_LEFT;
input.properties_mask = FieldPropertiesFlags::kHadFocus;
- input.typed_value = base::ASCIIToUTF16("TestTypedValue");
+ input.user_input = base::ASCIIToUTF16("TestTypedValue");
input.bounds = gfx::RectF(1, 2, 10, 100);
base::RunLoop loop;
diff --git a/chromium/components/autofill/core/common/signatures.cc b/chromium/components/autofill/core/common/signatures.cc
index ea5b9129dfc..b6078f82dc2 100644
--- a/chromium/components/autofill/core/common/signatures.cc
+++ b/chromium/components/autofill/core/common/signatures.cc
@@ -74,6 +74,10 @@ FormSignature CalculateFormSignature(const FormData& form_data) {
std::string form_signature_field_names;
+ auto ShouldSkipField = [](const FormFieldData& field) {
+ return IsCheckable(field.check_status);
+ };
+
for (const FormFieldData& field : form_data.fields) {
if (!ShouldSkipField(field)) {
// Add all supported form fields (including with empty names) to the
diff --git a/chromium/components/autofill/ios/browser/BUILD.gn b/chromium/components/autofill/ios/browser/BUILD.gn
index edbcb3f6c66..5d55496daa7 100644
--- a/chromium/components/autofill/ios/browser/BUILD.gn
+++ b/chromium/components/autofill/ios/browser/BUILD.gn
@@ -41,12 +41,15 @@ source_set("browser") {
"//components/autofill/ios/form_util",
"//components/prefs:prefs",
"//components/prefs/ios",
+ "//components/ukm/ios:ukm_url_recorder",
"//google_apis",
"//ios/web/common",
"//ios/web/public",
"//ios/web/public/deprecated",
"//ios/web/public/js_messaging",
"//ios/web/public/security",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp",
"//ui/accessibility",
"//ui/gfx/geometry",
@@ -93,10 +96,10 @@ source_set("unit_tests") {
"//components/leveldb_proto:leveldb_proto",
"//components/prefs",
"//ios/web/public",
- "//ios/web/public/deprecated",
"//ios/web/public/js_messaging",
"//ios/web/public/test",
"//ios/web/public/test/fakes",
+ "//services/metrics/public/cpp:ukm_builders",
"//testing/gmock",
"//testing/gtest",
"//third_party/ocmock",
diff --git a/chromium/components/autofill/ios/browser/DEPS b/chromium/components/autofill/ios/browser/DEPS
index cfaa9b06ddf..c11a8a4cbb6 100644
--- a/chromium/components/autofill/ios/browser/DEPS
+++ b/chromium/components/autofill/ios/browser/DEPS
@@ -1,6 +1,8 @@
include_rules = [
+ "+components/ukm/ios",
"+ios/web/common",
"+ios/web/public",
+ "+services/metrics/public",
"+services/network/public/cpp",
"+third_party/ocmock",
]
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm
index c33daac5902..422adbc7dc9 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent.mm
@@ -4,6 +4,8 @@
#import "components/autofill/ios/browser/autofill_agent.h"
+#import <UIKit/UIKit.h>
+
#include <memory>
#include <string>
#include <utility>
@@ -48,8 +50,8 @@
#import "components/prefs/ios/pref_observer_bridge.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
+#include "components/ukm/ios/ukm_url_recorder.h"
#include "ios/web/common/url_scheme_util.h"
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
#include "ios/web/public/deprecated/url_verification_constants.h"
#include "ios/web/public/js_messaging/web_frame.h"
#include "ios/web/public/js_messaging/web_frame_util.h"
@@ -57,6 +59,7 @@
#import "ios/web/public/navigation/navigation_context.h"
#import "ios/web/public/web_state.h"
#import "ios/web/public/web_state_observer_bridge.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
@@ -106,35 +109,6 @@ void GetFormField(autofill::FormFieldData* field,
}
}
-void UpdateFieldManagerWithFillingResults(
- scoped_refptr<FieldDataManager> fieldDataManager,
- NSString* jsonString,
- size_t numFieldsInFormData) {
- std::map<uint32_t, base::string16> fillingResults;
- if (autofill::ExtractFillingResults(jsonString, &fillingResults)) {
- for (auto& fillData : fillingResults) {
- fieldDataManager->UpdateFieldDataWithAutofilledValue(
- FieldRendererId(fillData.first), fillData.second,
- kAutofilledOnUserTrigger);
- }
- }
- // TODO(crbug/1131038): Remove once the experiment is over.
- UMA_HISTOGRAM_BOOLEAN("Autofill.FormFillSuccessIOS", !fillingResults.empty());
-}
-
-void UpdateFieldManagerForClearedIDs(
- scoped_refptr<FieldDataManager> fieldDataManager,
- NSString* jsonString) {
- std::vector<uint32_t> clearingResults;
- if (autofill::ExtractIDs(jsonString, &clearingResults)) {
- for (auto uniqueID : clearingResults) {
- fieldDataManager->UpdateFieldDataWithAutofilledValue(
- FieldRendererId(uniqueID), base::string16(),
- kAutofilledOnUserTrigger);
- }
- }
-}
-
} // namespace
@interface AutofillAgent () <CRWWebStateObserver,
@@ -270,7 +244,7 @@ autofillManagerFromWebState:(web::WebState*)webState
ofFormsSeen:(const FormDataVector&)forms {
DCHECK(autofillManager);
DCHECK(!forms.empty());
- autofillManager->OnFormsSeen(forms, base::TimeTicks::Now());
+ autofillManager->OnFormsSeen(forms);
}
// Notifies the autofill manager when forms are submitted.
@@ -425,6 +399,17 @@ autofillManagerFromWebState:(web::WebState*)webState
completion(_mostRecentSuggestions, self);
}
+- (void)updateFieldManagerForClearedIDs:(NSString*)jsonString {
+ std::vector<uint32_t> clearingResults;
+ if (autofill::ExtractIDs(jsonString, &clearingResults)) {
+ for (auto uniqueID : clearingResults) {
+ _fieldDataManager->UpdateFieldDataMap(FieldRendererId(uniqueID),
+ base::string16(),
+ kAutofilledOnUserTrigger);
+ }
+ }
+}
+
- (void)didSelectSuggestion:(FormSuggestion*)suggestion
form:(NSString*)formName
uniqueFormID:(FormRendererId)uniqueFormID
@@ -471,8 +456,8 @@ autofillManagerFromWebState:(web::WebState*)webState
AutofillAgent* strongSelf = weakSelf;
if (!strongSelf)
return;
- UpdateFieldManagerForClearedIDs(
- strongSelf->_fieldDataManager, jsonString);
+ [strongSelf
+ updateFieldManagerForClearedIDs:jsonString];
suggestionHandledCompletionCopy();
}];
@@ -933,13 +918,31 @@ autofillManagerFromWebState:(web::WebState*)webState
if (!strongSelf)
return;
if (success) {
- strongSelf->_fieldDataManager->UpdateFieldDataWithAutofilledValue(
+ strongSelf->_fieldDataManager->UpdateFieldDataMap(
uniqueFieldID, value, kAutofilledOnUserTrigger);
}
suggestionHandledCompletionCopy();
}];
}
+- (void)updateFieldManagerWithFillingResults:(NSString*)jsonString {
+ std::map<uint32_t, base::string16> fillingResults;
+ if (autofill::ExtractFillingResults(jsonString, &fillingResults)) {
+ for (auto& fillData : fillingResults) {
+ _fieldDataManager->UpdateFieldDataMap(FieldRendererId(fillData.first),
+ fillData.second,
+ kAutofilledOnUserTrigger);
+ }
+ }
+ // TODO(crbug/1131038): Remove once the experiment is over.
+ UMA_HISTOGRAM_BOOLEAN("Autofill.FormFillSuccessIOS", !fillingResults.empty());
+
+ ukm::SourceId source_id = ukm::GetSourceIdForWebStateDocument(_webState);
+ ukm::builders::Autofill_FormFillSuccessIOS(source_id)
+ .SetFormFillSuccess(!fillingResults.empty())
+ .Record(ukm::UkmRecorder::Get());
+}
+
// Sends the the |data| to |frame| to actually fill the data.
- (void)sendData:(std::unique_ptr<base::Value>)data
toFrame:(web::WebFrame*)frame {
@@ -948,7 +951,6 @@ autofillManagerFromWebState:(web::WebState*)webState
SuggestionHandledCompletion suggestionHandledCompletionCopy =
[_suggestionHandledCompletion copy];
_suggestionHandledCompletion = nil;
- size_t numFieldsInFormData = data->FindPath("fields")->DictSize();
[_jsAutofillManager fillForm:std::move(data)
forceFillFieldIdentifier:SysUTF16ToNSString(_pendingAutocompleteField)
forceFillFieldUniqueID:_pendingAutocompleteFieldID
@@ -957,9 +959,7 @@ autofillManagerFromWebState:(web::WebState*)webState
AutofillAgent* strongSelf = weakSelf;
if (!strongSelf)
return;
- UpdateFieldManagerWithFillingResults(
- strongSelf->_fieldDataManager, jsonString,
- numFieldsInFormData);
+ [strongSelf updateFieldManagerWithFillingResults:jsonString];
// It is possible that the fill was not initiated by selecting
// a suggestion in this case the callback is nil.
if (suggestionHandledCompletionCopy)
diff --git a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
index 1dac7ebe0d1..2e1a8d31875 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
@@ -4,6 +4,7 @@
#import "components/autofill/ios/browser/autofill_agent.h"
+#include "base/mac/bundle_locations.h"
#include "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#include "base/test/scoped_feature_list.h"
@@ -18,12 +19,15 @@
#import "components/autofill/ios/browser/js_autofill_manager.h"
#include "components/autofill/ios/form_util/unique_id_data_tab_helper.h"
#include "components/prefs/pref_service.h"
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
+#include "ios/web/public/js_messaging/web_frame_util.h"
+#include "ios/web/public/test/fakes/fake_browser_state.h"
+#include "ios/web/public/test/fakes/fake_web_client.h"
#include "ios/web/public/test/fakes/fake_web_frame.h"
#import "ios/web/public/test/fakes/fake_web_frames_manager.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
#include "ios/web/public/test/web_task_environment.h"
+#import "ios/web/public/test/web_test_with_web_state.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
@@ -39,9 +43,14 @@
using autofill::POPUP_ITEM_ID_CLEAR_FORM;
using autofill::POPUP_ITEM_ID_SHOW_ACCOUNT_CARDS;
using autofill::FormRendererId;
+using autofill::FieldDataManager;
using autofill::FieldRendererId;
using base::test::ios::WaitUntilCondition;
+@interface AutofillAgent (Testing)
+- (void)updateFieldManagerWithFillingResults:(NSString*)jsonString;
+@end
+
// Subclass of web::FakeWebFrame that allow to set a callback before any
// JavaScript call. This callback can be used to check the state of the page.
class FakeWebFrameCallback : public web::FakeWebFrame {
@@ -72,30 +81,26 @@ class AutofillAgentTests : public PlatformTest {
void AddWebFrame(std::unique_ptr<web::WebFrame> frame) {
web::WebFrame* frame_ptr = frame.get();
fake_web_frames_manager_->AddWebFrame(std::move(frame));
- test_web_state_.OnWebFrameDidBecomeAvailable(frame_ptr);
+ fake_web_state_.OnWebFrameDidBecomeAvailable(frame_ptr);
}
void RemoveWebFrame(const std::string& frame_id) {
web::WebFrame* frame_ptr =
fake_web_frames_manager_->GetFrameWithId(frame_id);
- test_web_state_.OnWebFrameWillBecomeUnavailable(frame_ptr);
+ fake_web_state_.OnWebFrameWillBecomeUnavailable(frame_ptr);
fake_web_frames_manager_->RemoveWebFrame(frame_id);
}
void SetUp() override {
PlatformTest::SetUp();
- // Mock CRWJSInjectionReceiver for verifying interactions.
- mock_js_injection_receiver_ =
- [OCMockObject mockForClass:[CRWJSInjectionReceiver class]];
- test_web_state_.SetBrowserState(&test_browser_state_);
- test_web_state_.SetJSInjectionReceiver(mock_js_injection_receiver_);
- test_web_state_.SetContentIsHTML(true);
+ fake_web_state_.SetBrowserState(&fake_browser_state_);
+ fake_web_state_.SetContentIsHTML(true);
auto frames_manager = std::make_unique<web::FakeWebFramesManager>();
fake_web_frames_manager_ = frames_manager.get();
- test_web_state_.SetWebFramesManager(std::move(frames_manager));
+ fake_web_state_.SetWebFramesManager(std::move(frames_manager));
GURL url("https://example.com");
- test_web_state_.SetCurrentURL(url);
+ fake_web_state_.SetCurrentURL(url);
auto main_frame = std::make_unique<web::FakeWebFrame>("frameID", true, url);
fake_main_frame_ = main_frame.get();
AddWebFrame(std::move(main_frame));
@@ -103,21 +108,20 @@ class AutofillAgentTests : public PlatformTest {
prefs_ = autofill::test::PrefServiceForTesting();
autofill::prefs::SetAutofillProfileEnabled(prefs_.get(), true);
autofill::prefs::SetAutofillCreditCardEnabled(prefs_.get(), true);
- UniqueIDDataTabHelper::CreateForWebState(&test_web_state_);
+ UniqueIDDataTabHelper::CreateForWebState(&fake_web_state_);
autofill_agent_ =
[[AutofillAgent alloc] initWithPrefService:prefs_.get()
- webState:&test_web_state_];
+ webState:&fake_web_state_];
}
web::WebTaskEnvironment task_environment_;
- web::TestBrowserState test_browser_state_;
- web::TestWebState test_web_state_;
+ web::FakeBrowserState fake_browser_state_;
+ web::FakeWebState fake_web_state_;
web::FakeWebFrame* fake_main_frame_ = nullptr;
web::FakeWebFramesManager* fake_web_frames_manager_ = nullptr;
autofill::TestAutofillClient client_;
std::unique_ptr<PrefService> prefs_;
AutofillAgent* autofill_agent_;
- id mock_js_injection_receiver_;
DISALLOW_COPY_AND_ASSIGN(AutofillAgentTests);
};
@@ -135,7 +139,7 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTestWithFrameMessaging) {
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
- &test_web_state_, &client_, nil, locale,
+ &fake_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
@@ -184,8 +188,8 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTestWithFrameMessaging) {
form.fields.push_back(field);
[autofill_agent_
fillFormData:form
- inFrame:test_web_state_.GetWebFramesManager()->GetMainWebFrame()];
- test_web_state_.WasShown();
+ inFrame:fake_web_state_.GetWebFramesManager()->GetMainWebFrame()];
+ fake_web_state_.WasShown();
EXPECT_EQ(
"__gCrWeb.autofill.fillForm({\"fields\":{\"name\":{\"section\":\"\","
"\"value\":\"name_value\"},"
@@ -207,7 +211,7 @@ TEST_F(AutofillAgentTests,
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
- &test_web_state_, &client_, nil, locale,
+ &fake_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
@@ -256,8 +260,8 @@ TEST_F(AutofillAgentTests,
form.fields.push_back(field);
[autofill_agent_
fillFormData:form
- inFrame:test_web_state_.GetWebFramesManager()->GetMainWebFrame()];
- test_web_state_.WasShown();
+ inFrame:fake_web_state_.GetWebFramesManager()->GetMainWebFrame()];
+ fake_web_state_.WasShown();
EXPECT_EQ("__gCrWeb.autofill.fillForm({\"fields\":{\"1\":{\"section\":\"\","
"\"value\":\"number_value\"},"
"\"2\":{\"section\":\"\",\"value\":\"name_value\"}},"
@@ -278,7 +282,7 @@ TEST_F(AutofillAgentTests,
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
- &test_web_state_, &client_, nil, locale,
+ &fake_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
@@ -318,8 +322,8 @@ TEST_F(AutofillAgentTests,
// Fields are in alphabetical order.
[autofill_agent_
fillFormData:form
- inFrame:test_web_state_.GetWebFramesManager()->GetMainWebFrame()];
- test_web_state_.WasShown();
+ inFrame:fake_web_state_.GetWebFramesManager()->GetMainWebFrame()];
+ fake_web_state_.WasShown();
EXPECT_EQ("__gCrWeb.autofill.fillForm({\"fields\":{\"field1\":{\"section\":"
"\"\",\"value\":\"value "
"2\"},\"region\":{\"section\":\"\",\"value\":\"California\"}},"
@@ -350,9 +354,9 @@ TEST_F(AutofillAgentTests,
[autofill_agent_ checkIfSuggestionsAvailableForForm:form_query
isMainFrame:YES
hasUserGesture:YES
- webState:&test_web_state_
+ webState:&fake_web_state_
completionHandler:nil];
- test_web_state_.WasShown();
+ fake_web_state_.WasShown();
EXPECT_EQ("__gCrWeb.autofill.extractForms(1, true);",
fake_main_frame_->GetLastJavaScriptCall());
}
@@ -377,12 +381,12 @@ TEST_F(AutofillAgentTests,
[autofill_agent_ checkIfSuggestionsAvailableForForm:form_query
isMainFrame:YES
hasUserGesture:NO
- webState:&test_web_state_
+ webState:&fake_web_state_
completionHandler:^(BOOL success) {
completion_handler_success = success;
completion_handler_called = YES;
}];
- test_web_state_.WasShown();
+ fake_web_state_.WasShown();
// Wait until the expected handler is called.
WaitUntilCondition(^bool() {
@@ -420,9 +424,9 @@ TEST_F(AutofillAgentTests, onSuggestionsReady_ShowAccountCards) {
typedValue:@""
frameID:@"frameID"];
[autofill_agent_ retrieveSuggestionsForForm:form_query
- webState:&test_web_state_
+ webState:&fake_web_state_
completionHandler:completionHandler];
- test_web_state_.WasShown();
+ fake_web_state_.WasShown();
// Wait until the expected handler is called.
WaitUntilCondition(^bool() {
@@ -468,9 +472,9 @@ TEST_F(AutofillAgentTests, onSuggestionsReady_ClearForm) {
typedValue:@""
frameID:@"frameID"];
[autofill_agent_ retrieveSuggestionsForForm:form_query
- webState:&test_web_state_
+ webState:&fake_web_state_
completionHandler:completionHandler];
- test_web_state_.WasShown();
+ fake_web_state_.WasShown();
// Wait until the expected handler is called.
WaitUntilCondition(^bool() {
@@ -518,9 +522,9 @@ TEST_F(AutofillAgentTests, onSuggestionsReady_ClearFormWithGPay) {
typedValue:@""
frameID:@"frameID"];
[autofill_agent_ retrieveSuggestionsForForm:form_query
- webState:&test_web_state_
+ webState:&fake_web_state_
completionHandler:completionHandler];
- test_web_state_.WasShown();
+ fake_web_state_.WasShown();
// Wait until the expected handler is called.
WaitUntilCondition(^bool() {
@@ -539,20 +543,20 @@ TEST_F(AutofillAgentTests, onSuggestionsReady_ClearFormWithGPay) {
TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
- &test_web_state_, &client_, nil, locale,
+ &fake_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
// Remove the current main frame.
RemoveWebFrame(fake_main_frame_->GetFrameId());
// Both frames available, then page loaded.
- test_web_state_.SetLoading(true);
+ fake_web_state_.SetLoading(true);
auto main_frame_unique =
std::make_unique<web::FakeWebFrame>("main", true, GURL());
web::FakeWebFrame* main_frame = main_frame_unique.get();
AddWebFrame(std::move(main_frame_unique));
autofill::AutofillDriverIOS* main_frame_driver =
- autofill::AutofillDriverIOS::FromWebStateAndWebFrame(&test_web_state_,
+ autofill::AutofillDriverIOS::FromWebStateAndWebFrame(&fake_web_state_,
main_frame);
EXPECT_TRUE(main_frame_driver->IsInMainFrame());
auto iframe_unique = std::make_unique<FakeWebFrameCallback>(
@@ -562,13 +566,13 @@ TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
FakeWebFrameCallback* iframe = iframe_unique.get();
AddWebFrame(std::move(iframe_unique));
autofill::AutofillDriverIOS* iframe_driver =
- autofill::AutofillDriverIOS::FromWebStateAndWebFrame(&test_web_state_,
+ autofill::AutofillDriverIOS::FromWebStateAndWebFrame(&fake_web_state_,
iframe);
EXPECT_FALSE(iframe_driver->IsInMainFrame());
EXPECT_FALSE(main_frame_driver->is_processed());
EXPECT_FALSE(iframe_driver->is_processed());
- test_web_state_.SetLoading(false);
- test_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
+ fake_web_state_.SetLoading(false);
+ fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
EXPECT_TRUE(main_frame_driver->is_processed());
EXPECT_TRUE(iframe_driver->is_processed());
RemoveWebFrame(main_frame->GetFrameId());
@@ -578,20 +582,20 @@ TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
main_frame_unique = std::make_unique<web::FakeWebFrame>("main", true, GURL());
main_frame = main_frame_unique.get();
main_frame_driver = autofill::AutofillDriverIOS::FromWebStateAndWebFrame(
- &test_web_state_, main_frame);
+ &fake_web_state_, main_frame);
iframe_unique = std::make_unique<FakeWebFrameCallback>(
"iframe", false, GURL(), [main_frame_driver]() {
EXPECT_TRUE(main_frame_driver->is_processed());
});
iframe = iframe_unique.get();
iframe_driver = autofill::AutofillDriverIOS::FromWebStateAndWebFrame(
- &test_web_state_, iframe);
- test_web_state_.SetLoading(true);
+ &fake_web_state_, iframe);
+ fake_web_state_.SetLoading(true);
AddWebFrame(std::move(main_frame_unique));
EXPECT_FALSE(main_frame_driver->is_processed());
EXPECT_FALSE(iframe_driver->is_processed());
- test_web_state_.SetLoading(false);
- test_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
+ fake_web_state_.SetLoading(false);
+ fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
EXPECT_TRUE(main_frame_driver->is_processed());
EXPECT_FALSE(iframe_driver->is_processed());
AddWebFrame(std::move(iframe_unique));
@@ -604,17 +608,17 @@ TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
main_frame_unique = std::make_unique<web::FakeWebFrame>("main", true, GURL());
main_frame = main_frame_unique.get();
main_frame_driver = autofill::AutofillDriverIOS::FromWebStateAndWebFrame(
- &test_web_state_, main_frame);
+ &fake_web_state_, main_frame);
iframe_unique = std::make_unique<FakeWebFrameCallback>(
"iframe", false, GURL(), [main_frame_driver]() {
EXPECT_TRUE(main_frame_driver->is_processed());
});
iframe = iframe_unique.get();
iframe_driver = autofill::AutofillDriverIOS::FromWebStateAndWebFrame(
- &test_web_state_, iframe);
- test_web_state_.SetLoading(true);
- test_web_state_.SetLoading(false);
- test_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
+ &fake_web_state_, iframe);
+ fake_web_state_.SetLoading(true);
+ fake_web_state_.SetLoading(false);
+ fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
EXPECT_FALSE(main_frame_driver->is_processed());
EXPECT_FALSE(iframe_driver->is_processed());
AddWebFrame(std::move(main_frame_unique));
@@ -630,17 +634,17 @@ TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
main_frame_unique = std::make_unique<web::FakeWebFrame>("main", true, GURL());
main_frame = main_frame_unique.get();
main_frame_driver = autofill::AutofillDriverIOS::FromWebStateAndWebFrame(
- &test_web_state_, main_frame);
+ &fake_web_state_, main_frame);
iframe_unique = std::make_unique<FakeWebFrameCallback>(
"iframe", false, GURL(), [main_frame_driver]() {
EXPECT_TRUE(main_frame_driver->is_processed());
});
iframe = iframe_unique.get();
iframe_driver = autofill::AutofillDriverIOS::FromWebStateAndWebFrame(
- &test_web_state_, iframe);
- test_web_state_.SetLoading(true);
- test_web_state_.SetLoading(false);
- test_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
+ &fake_web_state_, iframe);
+ fake_web_state_.SetLoading(true);
+ fake_web_state_.SetLoading(false);
+ fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
EXPECT_FALSE(main_frame_driver->is_processed());
EXPECT_FALSE(iframe_driver->is_processed());
AddWebFrame(std::move(iframe_unique));
@@ -652,3 +656,23 @@ TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
RemoveWebFrame(main_frame->GetFrameId());
RemoveWebFrame(iframe->GetFrameId());
}
+
+TEST_F(AutofillAgentTests, UpdateFieldManagerWithFillingResults) {
+ auto test_recorder = std::make_unique<ukm::TestAutoSetUkmRecorder>();
+
+ [autofill_agent_ updateFieldManagerWithFillingResults:@"{\"1\":\"Val1\"}"];
+
+ // Check recorded FieldDataManager data.
+ UniqueIDDataTabHelper* uniqueIDDataTabHelper =
+ UniqueIDDataTabHelper::FromWebState(&fake_web_state_);
+ scoped_refptr<FieldDataManager> fieldDataManager =
+ uniqueIDDataTabHelper->GetFieldDataManager();
+ EXPECT_TRUE(fieldDataManager->WasAutofilledOnUserTrigger(FieldRendererId(1)));
+
+ // Check recorded UKM.
+ auto entries = test_recorder->GetEntriesByName(
+ ukm::builders::Autofill_FormFillSuccessIOS::kEntryName);
+ // Expect one recorded metric.
+ ASSERT_EQ(1u, entries.size());
+ test_recorder->ExpectEntryMetric(entries[0], "FormFillSuccess", true);
+}
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.h b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
index c04142313b1..ad73457b698 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.h
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
@@ -99,8 +99,6 @@ class AutofillDriverIOS : public AutofillDriver {
// AutofillManager instance via which this object drives the shared Autofill
// code.
AutofillManager autofill_manager_;
- // AutofillExternalDelegate instance that is passed to the AutofillManager.
- AutofillExternalDelegate autofill_external_delegate_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
index f72958bede1..0ad76b76877 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -54,10 +54,8 @@ AutofillDriverIOS::AutofillDriverIOS(
AutofillManager::AutofillDownloadManagerState enable_download_manager)
: web_state_(web_state),
bridge_(bridge),
- autofill_manager_(this, client, app_locale, enable_download_manager),
- autofill_external_delegate_(&autofill_manager_, this) {
+ autofill_manager_(this, client, app_locale, enable_download_manager) {
web_frame_id_ = web::GetWebFrameId(web_frame);
- autofill_manager_.SetExternalDelegate(&autofill_external_delegate_);
}
AutofillDriverIOS::~AutofillDriverIOS() {}
diff --git a/chromium/components/autofill/ios/browser/autofill_util.h b/chromium/components/autofill/ios/browser/autofill_util.h
index a533b81674c..8d6e48d9235 100644
--- a/chromium/components/autofill/ios/browser/autofill_util.h
+++ b/chromium/components/autofill/ios/browser/autofill_util.h
@@ -9,7 +9,6 @@
#import "ios/web/public/js_messaging/web_frame.h"
-@class CRWJSInjectionReceiver;
class GURL;
namespace base {
diff --git a/chromium/components/autofill/ios/browser/js_suggestion_manager.h b/chromium/components/autofill/ios/browser/js_suggestion_manager.h
index 953742feb73..425e4ae9cb8 100644
--- a/chromium/components/autofill/ios/browser/js_suggestion_manager.h
+++ b/chromium/components/autofill/ios/browser/js_suggestion_manager.h
@@ -5,70 +5,90 @@
#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_JS_SUGGESTION_MANAGER_H_
#define COMPONENTS_AUTOFILL_IOS_BROWSER_JS_SUGGESTION_MANAGER_H_
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#import "ios/web/public/web_state_user_data.h"
+
+namespace base {
+class Value;
+} // namespace base
namespace web {
-class WebFramesManager;
-} // namespace
-
-// Loads the JavaScript file, suggestion_manager.js, which contains form parsing
-// and autofill functions.
-@interface JsSuggestionManager : NSObject
-
-// Designated initializer. |receiver| should not be nil.
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
- NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
-// Sets the WebFrames manager associated with the receiver.
-- (void)setWebFramesManager:(web::WebFramesManager*)framesManager;
-
-// Focuses the next focusable element in tab order inside the web frame with
-// frame id |frameID|. No action if there is no such element.
-- (void)selectNextElementInFrameWithID:(NSString*)frameID;
-
-// Focuses the next focusable element in tab order after the element specified
-// by |formName| and |fieldName| in tab order inside the web frame with frame id
-// |frameID|. No action if there is no such element.
-- (void)selectNextElementInFrameWithID:(NSString*)frameID
- afterForm:(NSString*)formName
- field:(NSString*)fieldName;
-
-// Focuses the previous focusable element in tab order inside the web frame with
-// frame id |frameID|. No action if there is no such element.
-- (void)selectPreviousElementInFrameWithID:(NSString*)frameID;
-
-// Focuses the previous focusable element in tab order from the element
-// specified by |formName| and |fieldName| in tab order inside the web frame
-// with frame id |frameID|. No action if there is no such element.
-- (void)selectPreviousElementInFrameWithID:(NSString*)frameID
- beforeForm:(NSString*)formName
- field:(NSString*)fieldName;
-
-// Checks if the frame with frame id |frameID| contains a next and previous
-// element. |completionHandler| is called with 2 BOOLs, the first indicating if
-// a previous element was found, and the second indicating if a next element was
-// found. |completionHandler| cannot be nil.
-- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
- completionHandler:(void (^)(BOOL, BOOL))
- completionHandler;
-
-// Checks if the frame with frame id |frameID| contains a next and previous
-// element starting from the field specified by |formName| and |fieldName|.
-// |completionHandler| is called with 2 BOOLs, the first indicating if a
-// previous element was found, and the second indicating if a next element was
-// found. |completionHandler| cannot be nil.
-- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
- forForm:(NSString*)formName
- field:(NSString*)fieldName
- completionHandler:(void (^)(BOOL, BOOL))
- completionHandler;
-
-// Closes the keyboard and defocuses the active input element in the frame with
-// frame id |frameID|.
-- (void)closeKeyboardForFrameWithID:(NSString*)frameID;
-
-@end
+class WebFrame;
+class WebState;
+} // namespace web
+
+namespace autofill {
+
+class JsSuggestionManager : public web::WebStateUserData<JsSuggestionManager> {
+ public:
+ ~JsSuggestionManager() override;
+
+ static JsSuggestionManager* GetOrCreateForWebState(web::WebState* web_state);
+
+ // Focuses the next focusable element in tab order inside the web frame with
+ // frame id |frame_ID|. No action if there is no such element.
+ void SelectNextElementInFrameWithID(const std::string& frame_ID);
+
+ // Focuses the next focusable element in tab order after the element specified
+ // by |form_name| and |field_name| in tab order inside the web frame with
+ // frame id |frame_ID|. No action if there is no such element.
+ void SelectNextElementInFrameWithID(const std::string& frame_ID,
+ const std::string& form_name,
+ const std::string& field_name);
+
+ // Focuses the previous focusable element in tab order inside the web frame
+ // with frame id |frame_ID|. No action if there is no such element.
+ void SelectPreviousElementInFrameWithID(const std::string& frame_ID);
+
+ // Focuses the previous focusable element in tab order from the element
+ // specified by |form_name| and |field_name| in tab order inside the web frame
+ // with frame id |frame_ID|. No action if there is no such element.
+ void SelectPreviousElementInFrameWithID(const std::string& frame_ID,
+ const std::string& form_name,
+ const std::string& field_name);
+
+ // Checks if the frame with frame id |frame_ID| contains a next and previous
+ // element. |completionHandler| is called with 2 bools, the first indicating
+ // if a previous element was found, and the second indicating if a next
+ // element was found. |completionHcompletion_handlerandler| cannot be nil.
+ void FetchPreviousAndNextElementsPresenceInFrameWithID(
+ const std::string& frame_ID,
+ base::OnceCallback<void(bool, bool)> completion_handler);
+
+ // Checks if the frame with frame id |frame_ID| contains a next and previous
+ // element starting from the field specified by |form_name| and |field_name|.
+ // |completionHandler| is called with 2 BOOLs, the first indicating if a
+ // previous element was found, and the second indicating if a next element was
+ // found. |completion_handler| cannot be nil.
+ void FetchPreviousAndNextElementsPresenceInFrameWithID(
+ const std::string& frame_ID,
+ const std::string& form_name,
+ const std::string& field_name,
+ base::OnceCallback<void(bool, bool)> completion_handler);
+
+ // Closes the keyboard and defocuses the active input element in the frame
+ // with frame id |frame_ID|.
+ void CloseKeyboardForFrameWithID(const std::string& frame_ID);
+
+ private:
+ explicit JsSuggestionManager(web::WebState* web_state);
+
+ void PreviousAndNextElementsPresenceResult(
+ base::OnceCallback<void(bool, bool)> completion_handler,
+ const base::Value* res);
+
+ web::WebFrame* GetFrameWithFrameID(const std::string& frame_ID);
+
+ web::WebState* web_state_;
+
+ base::WeakPtrFactory<JsSuggestionManager> weak_ptr_factory_;
+
+ friend class web::WebStateUserData<JsSuggestionManager>;
+
+ WEB_STATE_USER_DATA_KEY_DECL();
+};
+
+} // namespace autofill
#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_JS_SUGGESTION_MANAGER_H_
diff --git a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
index 7826e68fbae..2b207468e32 100644
--- a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
+++ b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
@@ -4,6 +4,7 @@
#import "components/autofill/ios/browser/js_suggestion_manager.h"
+#import <Foundation/Foundation.h>
#include <vector>
#include "base/bind.h"
@@ -14,7 +15,6 @@
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "components/autofill/ios/browser/autofill_util.h"
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
#include "ios/web/public/js_messaging/web_frame.h"
#include "ios/web/public/js_messaging/web_frames_manager.h"
@@ -22,115 +22,125 @@
#error "This file requires ARC support."
#endif
-@implementation JsSuggestionManager {
- // The injection receiver used to evaluate JavaScript.
- __weak CRWJSInjectionReceiver* _receiver;
- web::WebFramesManager* _webFramesManager;
-}
+namespace autofill {
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
- DCHECK(receiver);
- self = [super init];
- if (self) {
- _receiver = receiver;
- }
- return self;
-}
+JsSuggestionManager::JsSuggestionManager(web::WebState* web_state)
+ : web_state_(web_state), weak_ptr_factory_(this) {}
-- (void)setWebFramesManager:(web::WebFramesManager*)framesManager {
- _webFramesManager = framesManager;
-}
+JsSuggestionManager::~JsSuggestionManager() = default;
-#pragma mark -
-#pragma mark ProtectedMethods
+// static
+JsSuggestionManager* JsSuggestionManager::GetOrCreateForWebState(
+ web::WebState* web_state) {
+ JsSuggestionManager* helper = FromWebState(web_state);
+ if (!helper) {
+ CreateForWebState(web_state);
+ helper = FromWebState(web_state);
+ DCHECK(helper);
+ }
+ return helper;
+}
-- (void)selectNextElementInFrameWithID:(NSString*)frameID {
- [self selectNextElementInFrameWithID:frameID afterForm:@"" field:@""];
+void JsSuggestionManager::SelectNextElementInFrameWithID(
+ const std::string& frame_ID) {
+ SelectNextElementInFrameWithID(frame_ID, "", "");
}
-- (void)selectNextElementInFrameWithID:(NSString*)frameID
- afterForm:(NSString*)formName
- field:(NSString*)fieldName {
+void JsSuggestionManager::SelectNextElementInFrameWithID(
+ const std::string& frame_ID,
+ const std::string& form_name,
+ const std::string& field_name) {
std::vector<base::Value> parameters;
- parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
- parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
- autofill::ExecuteJavaScriptFunction(
- "suggestion.selectNextElement", parameters,
- [self frameWithFrameID:frameID], autofill::JavaScriptResultCallback());
+ parameters.push_back(base::Value(form_name));
+ parameters.push_back(base::Value(field_name));
+ autofill::ExecuteJavaScriptFunction("suggestion.selectNextElement",
+ parameters, GetFrameWithFrameID(frame_ID),
+ autofill::JavaScriptResultCallback());
}
-- (void)selectPreviousElementInFrameWithID:(NSString*)frameID {
- [self selectPreviousElementInFrameWithID:frameID beforeForm:@"" field:@""];
+void JsSuggestionManager::SelectPreviousElementInFrameWithID(
+ const std::string& frame_ID) {
+ SelectPreviousElementInFrameWithID(frame_ID, "", "");
}
-- (void)selectPreviousElementInFrameWithID:(NSString*)frameID
- beforeForm:(NSString*)formName
- field:(NSString*)fieldName {
+void JsSuggestionManager::SelectPreviousElementInFrameWithID(
+ const std::string& frame_ID,
+ const std::string& form_name,
+ const std::string& field_name) {
std::vector<base::Value> parameters;
- parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
- parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
- autofill::ExecuteJavaScriptFunction(
- "suggestion.selectPreviousElement", parameters,
- [self frameWithFrameID:frameID], autofill::JavaScriptResultCallback());
+ parameters.push_back(base::Value(form_name));
+ parameters.push_back(base::Value(field_name));
+ autofill::ExecuteJavaScriptFunction("suggestion.selectPreviousElement",
+ parameters, GetFrameWithFrameID(frame_ID),
+ autofill::JavaScriptResultCallback());
}
-- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
- completionHandler:
- (void (^)(BOOL,
- BOOL))completionHandler {
- [self fetchPreviousAndNextElementsPresenceInFrameWithID:frameID
- forForm:@""
- field:@""
- completionHandler:completionHandler];
+void JsSuggestionManager::FetchPreviousAndNextElementsPresenceInFrameWithID(
+ const std::string& frame_ID,
+ base::OnceCallback<void(bool, bool)> completion_handler) {
+ FetchPreviousAndNextElementsPresenceInFrameWithID(
+ frame_ID, "", "", std::move(completion_handler));
}
-- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
- forForm:(NSString*)formName
- field:(NSString*)fieldName
- completionHandler:
- (void (^)(BOOL,
- BOOL))completionHandler {
- DCHECK(completionHandler);
+void JsSuggestionManager::FetchPreviousAndNextElementsPresenceInFrameWithID(
+ const std::string& frame_ID,
+ const std::string& form_name,
+ const std::string& field_name,
+ base::OnceCallback<void(bool, bool)> completion_handler) {
+ DCHECK(completion_handler);
std::vector<base::Value> parameters;
- parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
- parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
+ parameters.push_back(base::Value(form_name));
+ parameters.push_back(base::Value(field_name));
autofill::ExecuteJavaScriptFunction(
"suggestion.hasPreviousNextElements", parameters,
- [self frameWithFrameID:frameID],
- autofill::CreateStringCallback(^(NSString* result) {
- // The result maybe an empty string here due to 2 reasons:
- // 1) When there is an exception running the JS
- // 2) There is a race when the page is changing due to which
- // JSSuggestionManager has not yet injected __gCrWeb.suggestion
- // object Handle this case gracefully. If a page has overridden
- // Array.toString, the string returned may not contain a ",",
- // hence this is a defensive measure to early return.
- NSArray* components = [result componentsSeparatedByString:@","];
- if (components.count != 2) {
- completionHandler(NO, NO);
- return;
- }
-
- DCHECK([components[0] isEqualToString:@"true"] ||
- [components[0] isEqualToString:@"false"]);
- BOOL hasPreviousElement = [components[0] isEqualToString:@"true"];
- DCHECK([components[1] isEqualToString:@"true"] ||
- [components[1] isEqualToString:@"false"]);
- BOOL hasNextElement = [components[1] isEqualToString:@"true"];
- completionHandler(hasPreviousElement, hasNextElement);
- }));
+ GetFrameWithFrameID(frame_ID),
+ base::BindOnce(
+ &JsSuggestionManager::PreviousAndNextElementsPresenceResult,
+ weak_ptr_factory_.GetWeakPtr(), std::move(completion_handler)));
}
-- (void)closeKeyboardForFrameWithID:(NSString*)frameID {
+void JsSuggestionManager::PreviousAndNextElementsPresenceResult(
+ base::OnceCallback<void(bool, bool)> completion_handler,
+ const base::Value* res) {
+ NSString* result = nil;
+ if (res && res->is_string()) {
+ result = base::SysUTF8ToNSString(res->GetString());
+ }
+ // The result maybe an empty string here due to 2 reasons:
+ // 1) When there is an exception running the JS
+ // 2) There is a race when the page is changing due to which
+ // JSSuggestionManager has not yet injected __gCrWeb.suggestion
+ // object Handle this case gracefully. If a page has overridden
+ // Array.toString, the string returned may not contain a ",",
+ // hence this is a defensive measure to early return.
+ NSArray* components = [result componentsSeparatedByString:@","];
+ if (components.count != 2) {
+ std::move(completion_handler).Run(false, false);
+ return;
+ }
+
+ DCHECK([components[0] isEqualToString:@"true"] ||
+ [components[0] isEqualToString:@"false"]);
+ bool has_previous_element = [components[0] isEqualToString:@"true"];
+ DCHECK([components[1] isEqualToString:@"true"] ||
+ [components[1] isEqualToString:@"false"]);
+ bool has_next_element = [components[1] isEqualToString:@"true"];
+ std::move(completion_handler).Run(has_previous_element, has_next_element);
+}
+
+void JsSuggestionManager::CloseKeyboardForFrameWithID(
+ const std::string& frame_ID) {
std::vector<base::Value> parameters;
- autofill::ExecuteJavaScriptFunction(
- "suggestion.blurActiveElement", parameters,
- [self frameWithFrameID:frameID], autofill::JavaScriptResultCallback());
+ autofill::ExecuteJavaScriptFunction("suggestion.blurActiveElement",
+ parameters, GetFrameWithFrameID(frame_ID),
+ autofill::JavaScriptResultCallback());
}
-- (web::WebFrame*)frameWithFrameID:(NSString*)frameID {
- DCHECK(_webFramesManager);
- return _webFramesManager->GetFrameWithId(base::SysNSStringToUTF8(frameID));
+web::WebFrame* JsSuggestionManager::GetFrameWithFrameID(
+ const std::string& frame_ID) {
+ return web_state_->GetWebFramesManager()->GetFrameWithId(frame_ID);
}
-@end
+WEB_STATE_USER_DATA_KEY_IMPL(JsSuggestionManager)
+
+} // namspace autofill
diff --git a/chromium/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm b/chromium/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm
index 091d9d7c5df..07cd5182b2c 100644
--- a/chromium/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm
@@ -6,7 +6,7 @@
#include "components/autofill/ios/form_util/test_form_activity_observer.h"
#import "ios/web/public/test/fakes/fake_web_frame.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -72,10 +72,10 @@ class FormActivityObserverBridgeTest : public PlatformTest {
public:
FormActivityObserverBridgeTest()
: observer_([[FakeFormActivityObserver alloc] init]),
- observer_bridge_(&test_web_state_, observer_) {}
+ observer_bridge_(&fake_web_state_, observer_) {}
protected:
- web::TestWebState test_web_state_;
+ web::FakeWebState fake_web_state_;
FakeFormActivityObserver* observer_;
autofill::FormActivityObserverBridge observer_bridge_;
};
@@ -88,11 +88,11 @@ TEST_F(FormActivityObserverBridgeTest, DocumentSubmitted) {
bool has_user_gesture = true;
bool form_in_main_frame = true;
web::FakeWebFrame sender_frame("sender_frame", true, GURL::EmptyGURL());
- observer_bridge_.DocumentSubmitted(&test_web_state_, &sender_frame,
+ observer_bridge_.DocumentSubmitted(&fake_web_state_, &sender_frame,
kTestFormName, kTestFormData,
has_user_gesture, form_in_main_frame);
ASSERT_TRUE([observer_ submitDocumentInfo]);
- EXPECT_EQ(&test_web_state_, [observer_ submitDocumentInfo]->web_state);
+ EXPECT_EQ(&fake_web_state_, [observer_ submitDocumentInfo]->web_state);
EXPECT_EQ(&sender_frame, [observer_ submitDocumentInfo]->sender_frame);
EXPECT_EQ(kTestFormName, [observer_ submitDocumentInfo]->form_name);
EXPECT_EQ(kTestFormData, [observer_ submitDocumentInfo]->form_data);
@@ -112,10 +112,10 @@ TEST_F(FormActivityObserverBridgeTest, FormActivityRegistered) {
params.type = "type";
params.value = "value";
params.input_missing = true;
- observer_bridge_.FormActivityRegistered(&test_web_state_, &sender_frame,
+ observer_bridge_.FormActivityRegistered(&fake_web_state_, &sender_frame,
params);
ASSERT_TRUE([observer_ formActivityInfo]);
- EXPECT_EQ(&test_web_state_, [observer_ formActivityInfo]->web_state);
+ EXPECT_EQ(&fake_web_state_, [observer_ formActivityInfo]->web_state);
EXPECT_EQ(&sender_frame, [observer_ formActivityInfo]->sender_frame);
EXPECT_EQ(params.form_name,
[observer_ formActivityInfo]->form_activity.form_name);
diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h
index 976a4634857..72461af86fd 100644
--- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h
+++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.h
@@ -69,7 +69,7 @@ class FormActivityTabHelper
base::ObserverList<FormActivityObserver>::Unchecked observers_;
// Subscription for JS message.
- std::unique_ptr<web::WebState::ScriptCommandSubscription> subscription_;
+ base::CallbackListSubscription subscription_;
WEB_STATE_USER_DATA_KEY_DECL();
diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm
index 9acd740d56f..99f01745ae9 100644
--- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm
@@ -9,8 +9,8 @@
#import "components/autofill/ios/form_util/test_form_activity_observer.h"
#include "ios/web/public/js_messaging/web_frame.h"
#import "ios/web/public/js_messaging/web_frames_manager.h"
-#import "ios/web/public/test/fakes/test_web_client.h"
-#import "ios/web/public/test/fakes/test_web_state_observer_util.h"
+#import "ios/web/public/test/fakes/fake_web_client.h"
+#import "ios/web/public/test/fakes/fake_web_state_observer_util.h"
#import "ios/web/public/test/js_test_util.h"
#import "ios/web/public/test/web_js_test.h"
#import "ios/web/public/test/web_test_with_web_state.h"
@@ -18,7 +18,7 @@
using web::WebFrame;
-class FormTestClient : public web::TestWebClient {
+class FormTestClient : public web::FakeWebClient {
public:
NSString* GetDocumentStartScriptForAllFrames(
web::BrowserState* browser_state) const override {
diff --git a/chromium/components/autofill/ios/form_util/form_unittest.mm b/chromium/components/autofill/ios/form_util/form_unittest.mm
index 3f505ad8cd7..dd6971a6738 100644
--- a/chromium/components/autofill/ios/form_util/form_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/form_unittest.mm
@@ -6,8 +6,7 @@
#include "components/autofill/ios/form_util/form_activity_tab_helper.h"
#include "components/autofill/ios/form_util/test_form_activity_observer.h"
#import "ios/web/public/browser_state.h"
-#import "ios/web/public/test/fakes/test_web_client.h"
-#include "ios/web/public/test/fakes/test_web_state_observer.h"
+#import "ios/web/public/test/fakes/fake_web_client.h"
#import "ios/web/public/test/js_test_util.h"
#import "ios/web/public/test/web_js_test.h"
#import "ios/web/public/test/web_test_with_web_state.h"
@@ -20,7 +19,7 @@
using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kWaitForJSCompletionTimeout;
-class FormTestClient : public web::TestWebClient {
+class FormTestClient : public web::FakeWebClient {
public:
NSString* GetDocumentStartScriptForAllFrames(
web::BrowserState* browser_state) const override {
diff --git a/chromium/components/autofill/ios/form_util/resources/fill.js b/chromium/components/autofill/ios/form_util/resources/fill.js
index 6117e8b8a26..4526098a344 100644
--- a/chromium/components/autofill/ios/form_util/resources/fill.js
+++ b/chromium/components/autofill/ios/form_util/resources/fill.js
@@ -145,14 +145,11 @@ __gCrWeb.fill.ROLE_ATTRIBUTE_PRESENTATION = 0;
__gCrWeb.fill.RENDERER_ID_NOT_SET = '-1';
/**
- * The name of the JS Symbol used to set stable unique form and field IDs.
+ * The JS Symbol object used to set stable unique form and field IDs.
*
- * This variable is |kNotSetRendererID| from
- * chromium/src/components/autofill/ios/browser/autofill_util.h
- *
- * @const {string}
+ * @const {symbol}
*/
-__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME = '__gChrome~uniqueID';
+__gCrWeb.fill.ID_SYMBOL = window.Symbol.for('__gChrome~uniqueID');
/**
* Returns true if an element can be autocompleted.
@@ -2310,8 +2307,7 @@ __gCrWeb.fill.extractAutofillableElementsFromSet = function(controlElements) {
* @param {int} nextAvailableID Next available integer.
*/
__gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) {
- const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
- document[uniqueID] = nextAvailableID;
+ document[__gCrWeb.fill.ID_SYMBOL] = nextAvailableID;
};
/**
@@ -2319,7 +2315,7 @@ __gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) {
*/
__gCrWeb.fill.setUniqueIDIfNeeded = function(element) {
try {
- const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
+ const uniqueID = __gCrWeb.fill.ID_SYMBOL;
// Do not assign element id value if the base value for the document
// is not set.
if (typeof document[uniqueID] !== 'undefined' &&
@@ -2336,7 +2332,7 @@ __gCrWeb.fill.setUniqueIDIfNeeded = function(element) {
*/
__gCrWeb.fill.getUniqueID = function(element) {
try {
- const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
+ const uniqueID = __gCrWeb.fill.ID_SYMBOL;
if (typeof element[uniqueID] !== 'undefined' && !isNaN(element[uniqueID])) {
return element[uniqueID].toString();
} else {
diff --git a/chromium/components/autofill/ios/form_util/resources/form.js b/chromium/components/autofill/ios/form_util/resources/form.js
index e857c9e88b5..135f3dbfd2f 100644
--- a/chromium/components/autofill/ios/form_util/resources/form.js
+++ b/chromium/components/autofill/ios/form_util/resources/form.js
@@ -280,8 +280,7 @@ __gCrWeb.form.getFormElementFromUniqueFormId = function(identifier) {
const forms = document.forms;
for (let i = 0; i < forms.length; i++) {
const form = forms[i];
- const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
- if (identifier === form[uniqueID]) {
+ if (identifier.toString() === __gCrWeb.fill.getUniqueID(form)) {
return form;
}
}
diff --git a/chromium/components/autofill/ios/form_util/resources/form_handlers.js b/chromium/components/autofill/ios/form_util/resources/form_handlers.js
index 69f0d8d2c9c..81344804475 100644
--- a/chromium/components/autofill/ios/form_util/resources/form_handlers.js
+++ b/chromium/components/autofill/ios/form_util/resources/form_handlers.js
@@ -28,6 +28,11 @@ __gCrWeb.formHandlers = {};
let formMutationObserver = null;
/**
+ * The MutationObserver tracking the latest password field that had user input.
+ */
+let passwordFieldsObserver = null;
+
+/**
* The form mutation message scheduled to be sent to browser.
*/
let formMutationMessageToSend = null;
@@ -77,8 +82,87 @@ function getFullyQualifiedUrl_(originalURL) {
}
/**
- * Focus, input, change, keyup and blur events for form elements (form and input
- * elements) are messaged to the main application for broadcast to
+ * @param {Element} A form element to check.
+ * @return {boolean} Whether the element is an input of type password.
+ */
+function isPasswordField_(element) {
+ return element.tagName === 'INPUT' && element.type === 'password';
+}
+
+/**
+ * Installs a MutationObserver to track the last password field that had
+ * user input.
+ * @param {Element} A password field that should be observed.
+ * @suppress {checkTypes} Required for for...of loop on mutations.
+ */
+function trackPasswordField_(field) {
+ if (passwordFieldsObserver) {
+ passwordFieldsObserver.disconnect();
+ }
+
+ passwordFieldsObserver = new MutationObserver(function(mutations) {
+ for (let i = 0; i < mutations.length; i++) {
+ const mutation = mutations[i];
+ if (mutation.attributeName !== 'value') {
+ return;
+ }
+ const target = mutation.target;
+ const form = target.form;
+ let shouldNotifyPasswordManager = true;
+ if (form) {
+ // Verify that all password fields are cleared.
+ for (let i = 0; i < form.elements.length; i++) {
+ if (isPasswordField_(form.elements[i]) &&
+ form.elements[i].value !== '') {
+ shouldNotifyPasswordManager = false;
+ }
+ }
+ }
+ if (!shouldNotifyPasswordManager) {
+ return;
+ }
+ const formData = form ?
+ __gCrWeb.passwords.getPasswordFormData(form, window) :
+ __gCrWeb.passwords.getPasswordFormDataFromUnownedElements(window);
+ if (target.value === '') {
+ const msg = {
+ 'command': 'form.activity',
+ 'formName': '',
+ 'uniqueFormID': '',
+ 'fieldIdentifier': '',
+ 'uniqueFieldID': '',
+ 'fieldType': '',
+ 'type': 'password_form_cleared',
+ 'value': __gCrWeb.stringify(formData),
+ 'hasUserGesture': false
+ };
+ sendMessageOnNextLoop_(msg);
+ }
+ }
+ });
+ passwordFieldsObserver.observe(field, {attributes: true});
+}
+
+
+/**
+ * @param {Element} A form that was reset.
+ * @return {boolean} Whether the form contains password fields that had user
+ * typed or manually filled input.
+ */
+function shouldNotifyAboutFormReset_(form) {
+ for (let i = 0; i < form.elements.length; i++) {
+ const element = form.elements[i];
+ if (isPasswordField_(element) &&
+ __gCrWeb.form.wasEditedByUser.get(element)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Focus, input, change, keyup, blur and reset events for form elements (form
+ * and input elements) are messaged to the main application for broadcast to
* WebStateObservers.
* Events will be included in a message to be sent in a future runloop (without
* delay). If an event is already scheduled to be sent, it is replaced by |evt|.
@@ -87,6 +171,8 @@ function getFullyQualifiedUrl_(originalURL) {
* replace it.
* Only the events targeting the active element (or the previously active in
* case of 'blur') are sent to the main application.
+ * 'reset' events are sent to the main application only if they are targeting
+ * a password form that has user input in it.
* This is done with a single event handler for each type being added to the
* main document element which checks the source element of the event; this
* is much easier to manage than adding handlers to individual elements.
@@ -98,8 +184,6 @@ function formActivity_(evt) {
target.tagName)) {
return;
}
- const value = target.value || '';
- const fieldType = target.type || '';
if (evt.type !== 'blur') {
lastFocusedElement = document.activeElement;
}
@@ -107,21 +191,43 @@ function formActivity_(evt) {
__gCrWeb.form.wasEditedByUser !== null) {
__gCrWeb.form.wasEditedByUser.set(target, evt.isTrusted);
}
- if (target !== lastFocusedElement) {
+
+ // Notify FormActivityTabHelper about form reset if the form contains
+ // password fields that had user typed or manually filled input.
+ const isPasswordFormReset = target.tagName === 'FORM' &&
+ evt.type === 'reset' && shouldNotifyAboutFormReset_(target);
+
+ if (target !== lastFocusedElement && !isPasswordFormReset) {
return;
}
- __gCrWeb.fill.setUniqueIDIfNeeded(target.form);
- __gCrWeb.fill.setUniqueIDIfNeeded(target);
- const formUniqueId = __gCrWeb.fill.getUniqueID(target.form);
- const fieldUniqueId = __gCrWeb.fill.getUniqueID(target);
+ const form = target.tagName === 'FORM' ? target : target.form;
+ const field = target.tagName === 'FORM' ? null : target;
+
+ __gCrWeb.fill.setUniqueIDIfNeeded(form);
+ const formUniqueId = __gCrWeb.fill.getUniqueID(form);
+ __gCrWeb.fill.setUniqueIDIfNeeded(field);
+ const fieldUniqueId = __gCrWeb.fill.getUniqueID(field);
+
+ const fieldType = target.type || '';
+ const fieldValue = target.value || '';
+ const value = isPasswordFormReset ?
+ __gCrWeb.stringify(__gCrWeb.passwords.getPasswordFormData(form, window)) :
+ fieldValue;
+ const type = isPasswordFormReset ? 'password_form_cleared' : evt.type;
+
+ if ((evt.type === 'change' || evt.type === 'input') &&
+ isPasswordField_(target)) {
+ trackPasswordField_(evt.target);
+ }
+
const msg = {
'command': 'form.activity',
- 'formName': __gCrWeb.form.getFormIdentifier(target.form),
+ 'formName': __gCrWeb.form.getFormIdentifier(form),
'uniqueFormID': formUniqueId,
- 'fieldIdentifier': __gCrWeb.form.getFieldIdentifier(target),
+ 'fieldIdentifier': __gCrWeb.form.getFieldIdentifier(field),
'uniqueFieldID': fieldUniqueId,
'fieldType': fieldType,
- 'type': evt.type,
+ 'type': type,
'value': value,
'hasUserGesture': evt.isTrusted
};
@@ -178,6 +284,7 @@ function attachListeners_() {
document.addEventListener('blur', formActivity_, true);
document.addEventListener('change', formActivity_, true);
document.addEventListener('input', formActivity_, true);
+ document.addEventListener('reset', formActivity_, true);
/**
* Other events are watched at the bubbling phase as this seems adequate in
@@ -276,8 +383,7 @@ __gCrWeb.formHandlers['trackFormMutations'] = function(delay) {
const formGone = removedElements.find(function(element) {
if (element.tagName.match(/(FORM)/)) {
for (let k = 0; k < element.elements.length; k++) {
- if (element.elements[k].tagName.match(/(INPUT)/) &&
- element.elements[k].type === 'password') {
+ if (isPasswordField_(element.elements[k])) {
return true;
}
}
diff --git a/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm b/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm
index 426c93a7d3b..a44851cecaf 100644
--- a/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm
@@ -4,7 +4,7 @@
#include "components/autofill/ios/form_util/unique_id_data_tab_helper.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#include "testing/platform_test.h"
@@ -16,8 +16,8 @@
// Test fixture for TabIdTabHelper class.
class UniqueIDDataTabHelperTest : public PlatformTest {
protected:
- web::TestWebState first_web_state_;
- web::TestWebState second_web_state_;
+ web::FakeWebState first_web_state_;
+ web::FakeWebState second_web_state_;
};
// Tests that a tab ID is returned for a WebState, and tab ID's are different