summaryrefslogtreecommitdiff
path: root/chromium/components/autofill
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-03-12 09:13:00 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-03-16 09:58:26 +0000
commit03561cae90f1d99b5c54b1ef3be69f10e882b25e (patch)
treecc5f0958e823c044e7ae51cc0117fe51432abe5e /chromium/components/autofill
parentfa98118a45f7e169f8846086dc2c22c49a8ba310 (diff)
downloadqtwebengine-chromium-03561cae90f1d99b5c54b1ef3be69f10e882b25e.tar.gz
BASELINE: Update Chromium to 88.0.4324.208
Change-Id: I3ae87d23e4eff4b4a469685658740a213600c667 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/autofill')
-rw-r--r--chromium/components/autofill/android/BUILD.gn2
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.cc35
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.h16
-rw-r--r--chromium/components/autofill/android/provider/form_data_android.h2
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java20
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java12
-rw-r--r--chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java7
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc4
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h2
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc1
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc12
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc17
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_agent.mojom2
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_driver.mojom12
-rw-r--r--chromium/components/autofill/content/renderer/OWNERS9
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc24
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h6
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc1
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc6
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.cc15
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.h5
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.h2
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc84
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h23
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc1
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.h1
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc17
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.h6
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn23
-rw-r--r--chromium/components/autofill/core/browser/OWNERS2
-rw-r--r--chromium/components/autofill/core/browser/address_normalization_manager.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_normalizer_impl.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc2
-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/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html1
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html1
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util.cc6
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc5
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc21
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.cc27
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.h29
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc113
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h28
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc280
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc1297
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.h3
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc (renamed from chromium/components/autofill/core/common/autofill_regex_constants.cc)26
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.h (renamed from chromium/components/autofill/core/common/autofill_regex_constants.h)6
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.cc (renamed from chromium/components/autofill/core/common/autofill_regexes.cc)10
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.h (renamed from chromium/components/autofill/core/common/autofill_regexes.h)6
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes_unittest.cc232
-rw-r--r--chromium/components/autofill/core/browser/data_model/address.cc54
-rw-r--r--chromium/components/autofill/core/browser/data_model/address_unittest.cc83
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.cc4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.cc80
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc5
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc12
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.h4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc51
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h15
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc21
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc56
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc62
-rw-r--r--chromium/components/autofill/core/browser/data_model/contact_info.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/data_model_utils.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc69
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.h5
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc242
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.cc323
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.h62
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc127
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc29
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h8
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc125
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.h11
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc25
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.cc6
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.cc57
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.h20
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc89
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.cc127
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc21
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.cc53
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.h9
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.cc7
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc17
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.cc7
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc17
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.cc20
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc115
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h4
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc832
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc156
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.h181
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc69
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h47
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc119
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc226
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h113
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc159
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.cc17
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.h23
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/geo/country_data.cc1058
-rw-r--r--chromium/components/autofill/core/browser/geo/country_data.h27
-rw-r--r--chromium/components/autofill/core/browser/geo/subkey_requester.cc2
-rw-r--r--chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/logging/log_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc24
-rw-r--r--chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h11
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/DEPS5
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc228
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h60
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc196
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc167
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h87
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc238
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json2947
-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
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h9
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc32
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc9
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.h1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc2
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc11
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/proto/BUILD.gn1
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto1
-rw-r--r--chromium/components/autofill/core/browser/proto/states.proto31
-rw-r--r--chromium/components/autofill/core/browser/rationalization_util_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager.h1
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.cc4
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.h3
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model.cc2
-rw-r--r--chromium/components/autofill/core/browser/validation.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc30
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc7
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc2
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn10
-rw-r--r--chromium/components/autofill/core/common/OWNERS4
-rw-r--r--chromium/components/autofill/core/common/autofill_constants.cc19
-rw-r--r--chromium/components/autofill/core/common/autofill_constants.h6
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc147
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h32
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.cc6
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs.cc8
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes_unittest.cc232
-rw-r--r--chromium/components/autofill/core/common/autofill_util.cc2
-rw-r--r--chromium/components/autofill/core/common/dense_set.h278
-rw-r--r--chromium/components/autofill/core/common/dense_set_unittest.cc484
-rw-r--r--chromium/components/autofill/core/common/logging/log_buffer.cc14
-rw-r--r--chromium/components/autofill/core/common/mojom/BUILD.gn4
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types.mojom14
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc2
-rw-r--r--chromium/components/autofill/core/common/password_form.cc301
-rw-r--r--chromium/components/autofill/core/common/password_form.h388
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h1
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.cc44
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h17
-rw-r--r--chromium/components/autofill/core/common/password_generation_util.h4
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.cc4
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.h2
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm16
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.mm2
208 files changed, 9495 insertions, 4487 deletions
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
index 150a6db3bd8..9f15164b1a8 100644
--- a/chromium/components/autofill/android/BUILD.gn
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
java_strings_grd("autofill_strings_grd") {
grd_file = "java/strings/autofill_strings.grd"
@@ -20,6 +21,7 @@ android_resources("autofill_java_resources") {
"java/res/layout/autofill_dropdown_item_refresh.xml",
"java/res/values/colors.xml",
"java/res/values/dimens.xml",
+ "java/res/values/styles.xml",
]
deps = [
":autofill_strings_grd",
diff --git a/chromium/components/autofill/android/provider/autofill_provider_android.cc b/chromium/components/autofill/android/provider/autofill_provider_android.cc
index a9a7099e5e0..157142cde47 100644
--- a/chromium/components/autofill/android/provider/autofill_provider_android.cc
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.cc
@@ -86,8 +86,7 @@ void AutofillProviderAndroid::OnQueryFormFieldAutofill(
// Focus or field value change will also trigger the query, so it should be
// ignored if the form is same.
- if (ShouldStartNewSession(handler, form))
- StartNewSession(handler, form, field, bounding_box);
+ MaybeStartNewSession(handler, form, field, bounding_box);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
@@ -105,18 +104,24 @@ void AutofillProviderAndroid::OnQueryFormFieldAutofill(
}
}
-bool AutofillProviderAndroid::ShouldStartNewSession(
+void AutofillProviderAndroid::MaybeStartNewSession(
AutofillHandlerProxy* handler,
- const FormData& form) {
- // Only start a new session when form or handler is changed, the change of
- // handler indicates query from other frame and a new session is needed.
- return !IsCurrentlyLinkedForm(form) || !IsCurrentlyLinkedHandler(handler);
-}
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box) {
+ // Don't start a new session when the new form is similar to the old form, the
+ // new handler is the same as the current handler, and the coordinates of the
+ // relevant form field haven't changed.
+ if (form_ && form_->SimilarFormAs(form) &&
+ IsCurrentlyLinkedHandler(handler)) {
+ size_t index;
+ if (form_->GetFieldIndex(field, &index) &&
+ handler->driver()->TransformBoundingBoxToViewportCoordinates(
+ form.fields[index].bounds) == form_->form().fields[index].bounds) {
+ return;
+ }
+ }
-void AutofillProviderAndroid::StartNewSession(AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
@@ -221,8 +226,7 @@ void AutofillProviderAndroid::OnSelectControlDidChange(
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) {
- if (ShouldStartNewSession(handler, form))
- StartNewSession(handler, form, field, bounding_box);
+ MaybeStartNewSession(handler, form, field, bounding_box);
FireFormFieldDidChanged(handler, form, field, bounding_box);
}
@@ -255,7 +259,8 @@ void AutofillProviderAndroid::OnFormSubmitted(AutofillHandlerProxy* handler,
}
void AutofillProviderAndroid::OnFocusNoLongerOnForm(
- AutofillHandlerProxy* handler) {
+ AutofillHandlerProxy* handler,
+ bool had_interacted_form) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!IsCurrentlyLinkedHandler(handler))
return;
diff --git a/chromium/components/autofill/android/provider/autofill_provider_android.h b/chromium/components/autofill/android/provider/autofill_provider_android.h
index 5ed22d4e6ae..618517ca585 100644
--- a/chromium/components/autofill/android/provider/autofill_provider_android.h
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.h
@@ -56,7 +56,8 @@ class AutofillProviderAndroid : public AutofillProvider {
const FormData& form,
bool known_success,
mojom::SubmissionSource source) override;
- void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override;
+ void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) override;
void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
@@ -99,13 +100,12 @@ class AutofillProviderAndroid : public AutofillProvider {
gfx::RectF ToClientAreaBound(const gfx::RectF& bounding_box);
- bool ShouldStartNewSession(AutofillHandlerProxy* handler,
- const FormData& form);
-
- void StartNewSession(AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box);
+ // Starts a new session, but only if |form| or |handler| doesn't match the
+ // current session.
+ void MaybeStartNewSession(AutofillHandlerProxy* handler,
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box);
void Reset();
diff --git a/chromium/components/autofill/android/provider/form_data_android.h b/chromium/components/autofill/android/provider/form_data_android.h
index 8882a788673..96002f62c94 100644
--- a/chromium/components/autofill/android/provider/form_data_android.h
+++ b/chromium/components/autofill/android/provider/form_data_android.h
@@ -54,7 +54,7 @@ class FormDataAndroid {
void ApplyHeuristicFieldType(const FormStructure& form);
- const FormData& form_for_testing() { return form_; }
+ const FormData& form() { return form_; }
private:
// Same as the form passed in from constructor, but FormFieldData's bounds is
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 b9b4da26a6b..e92fdb19c61 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
@@ -14,11 +14,11 @@ import android.view.autofill.AutofillValue;
import androidx.annotation.VisibleForTesting;
+import org.chromium.base.CollectionUtil;
import org.chromium.base.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
/**
* The class to call Android's AutofillManager.
@@ -158,25 +158,9 @@ public class AutofillManagerWrapper {
mInputUIObservers.add(new WeakReference<InputUIObserver>(observer));
}
- public void removeInputUIObserver(InputUIObserver observer) {
- if (observer == null) return;
- for (Iterator<WeakReference<InputUIObserver>> i = mInputUIObservers.listIterator();
- i.hasNext();) {
- WeakReference<InputUIObserver> o = i.next();
- if (o.get() == null || o.get() == observer) i.remove();
- }
- }
-
@VisibleForTesting
public void notifyInputUIChange() {
- for (Iterator<WeakReference<InputUIObserver>> i = mInputUIObservers.listIterator();
- i.hasNext();) {
- WeakReference<InputUIObserver> o = i.next();
- InputUIObserver observer = o.get();
- if (observer == null) {
- i.remove();
- continue;
- }
+ for (InputUIObserver observer : CollectionUtil.strengthen(mInputUIObservers)) {
observer.onInputUIShown();
}
}
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 1546b3dca28..226f0dc55a7 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
@@ -29,6 +29,7 @@ import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.annotations.VerifiesOnO;
import org.chromium.base.metrics.ScopedSysTraceEvent;
import org.chromium.components.version_info.VersionConstants;
+import org.chromium.content_public.browser.RenderCoordinates;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsAccessibility;
import org.chromium.ui.DropdownItem;
@@ -715,8 +716,16 @@ public class AutofillProvider {
return mDatalistPopup;
}
+ private Rect transformToWindowBounds(RectF rect) {
+ // Refer to crbug.com/1085294 for the reason of offset.
+ // The current version of Mockito didn't support mock static method, adding extra method so
+ // the transform can be tested.
+ return transformToWindowBoundsWithOffsetY(
+ rect, RenderCoordinates.fromWebContents(mWebContents).getContentOffsetYPixInt());
+ }
+
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public Rect transformToWindowBounds(RectF rect) {
+ public Rect transformToWindowBoundsWithOffsetY(RectF rect, int offsetY) {
// Convert bounds to device pixel.
WindowAndroid windowAndroid = mWebContents.getTopLevelNativeWindow();
DisplayAndroid displayAndroid = windowAndroid.getDisplay();
@@ -726,6 +735,7 @@ public class AutofillProvider {
matrix.setScale(dipScale, dipScale);
int[] location = new int[2];
mContainerView.getLocationOnScreen(location);
+ location[1] += offsetY;
matrix.postTranslate(location[0], location[1]);
matrix.mapRect(bounds);
return new Rect(
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 7b017f0c419..5d63ae0630b 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
@@ -106,10 +106,11 @@ public class AutofillProviderTest {
@Test
public void testTransformToWindowBounds() {
RectF source = new RectF(10, 20, 300, 400);
- Rect result = mAutofillProvider.transformToWindowBounds(source);
+ final int offsetY = 10;
+ Rect result = mAutofillProvider.transformToWindowBoundsWithOffsetY(source, offsetY);
assertEquals(10 * EXPECTED_DIP_SCALE + LOCATION_X, result.left, 0);
- assertEquals(20 * EXPECTED_DIP_SCALE + LOCATION_Y, result.top, 0);
+ assertEquals(20 * EXPECTED_DIP_SCALE + LOCATION_Y + offsetY, result.top, 0);
assertEquals(300 * EXPECTED_DIP_SCALE + LOCATION_X, result.right, 0);
- assertEquals(400 * EXPECTED_DIP_SCALE + LOCATION_Y, result.bottom, 0);
+ assertEquals(400 * EXPECTED_DIP_SCALE + LOCATION_Y + offsetY, result.bottom, 0);
}
}
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index c657114d28a..3c37af33dac 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -287,8 +287,8 @@ void ContentAutofillDriver::HidePopup() {
autofill_handler_->OnHidePopup();
}
-void ContentAutofillDriver::FocusNoLongerOnForm() {
- autofill_handler_->OnFocusNoLongerOnForm();
+void ContentAutofillDriver::FocusNoLongerOnForm(bool had_interacted_form) {
+ autofill_handler_->OnFocusNoLongerOnForm(had_interacted_form);
}
void ContentAutofillDriver::FocusOnFormField(const FormData& form,
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index 1a8df440236..efa287202f4 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -128,7 +128,7 @@ class ContentAutofillDriver : public AutofillDriver,
const gfx::RectF& bounding_box,
bool autoselect_first_suggestion) override;
void HidePopup() override;
- void FocusNoLongerOnForm() override;
+ void FocusNoLongerOnForm(bool had_interacted_form) override;
void FocusOnFormField(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
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 1906bc92438..3862c76d670 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -25,7 +25,6 @@
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/frame_navigate_params.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index e23505a78d0..994561d81ae 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -20,7 +20,7 @@
#include "base/cpu.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
@@ -221,8 +221,9 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
// Ensures that any observer registrations for the GPU data are cleaned up by
// the time this object is destroyed.
- ScopedObserver<content::GpuDataManager, content::GpuDataManagerObserver>
- gpu_observer_{this};
+ base::ScopedObservation<content::GpuDataManager,
+ content::GpuDataManagerObserver>
+ gpu_observation_{this};
// Data that will be passed on to the next loading phase. See the comment for
// GetFingerprint() for a description of these variables.
@@ -295,7 +296,7 @@ FingerprintDataLoader::FingerprintDataLoader(
// Load GPU data if needed.
if (gpu_data_manager_->GpuAccessAllowed(nullptr) &&
!gpu_data_manager_->IsEssentialGpuInfoAvailable()) {
- gpu_observer_.Add(gpu_data_manager_);
+ gpu_observation_.Observe(gpu_data_manager_);
OnGpuInfoUpdate();
}
@@ -326,7 +327,8 @@ void FingerprintDataLoader::OnGpuInfoUpdate() {
if (!gpu_data_manager_->IsEssentialGpuInfoAvailable())
return;
- gpu_observer_.Remove(gpu_data_manager_);
+ DCHECK(gpu_observation_.IsObservingSource(gpu_data_manager_));
+ gpu_observation_.RemoveObservation();
MaybeFillFingerprint();
}
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index 663ebeaab86..885c1d4206d 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -75,16 +75,17 @@ class AutofillRiskFingerprintTest : public content::ContentBrowserTest {
unavailable_screen_bounds_(0, 0, 101, 11) {}
void SetUpOnMainThread() override {
- device::mojom::Geoposition position;
- position.latitude = kLatitude;
- position.longitude = kLongitude;
- position.altitude = kAltitude;
- position.accuracy = kAccuracy;
- position.timestamp = base::Time::UnixEpoch() +
- base::TimeDelta::FromMilliseconds(kGeolocationTime);
+ auto position = device::mojom::Geoposition::New();
+ position->latitude = kLatitude;
+ position->longitude = kLongitude;
+ position->altitude = kAltitude;
+ position->accuracy = kAccuracy;
+ position->timestamp = base::Time::UnixEpoch() +
+ base::TimeDelta::FromMilliseconds(kGeolocationTime);
geolocation_overrider_ =
- std::make_unique<device::ScopedGeolocationOverrider>(position);
+ std::make_unique<device::ScopedGeolocationOverrider>(
+ std::move(position));
}
void GetFingerprintTestCallback(base::OnceClosure continuation_callback,
diff --git a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
index 28b90f991f2..28e6bd73674 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
@@ -118,7 +118,7 @@ interface PasswordGenerationAgent {
// Tells the renderer to find a focused element, and if it is a password field
// eligible for generation then to trigger generation by returning
// non-empty PasswordGenerationUIData.
- UserTriggeredGeneratePassword() => (PasswordGenerationUIData? data);
+ TriggeredGeneratePassword() => (PasswordGenerationUIData? data);
// Tells the renderer that a password can be generated on the fields
// identified by |form|.
diff --git a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
index 6807ea2b937..106f0d69d37 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
@@ -61,8 +61,12 @@ interface AutofillDriver {
// Instructs the browser to hide the Autofill popup if it is open.
HidePopup();
- // Sent when the current form is no longer focused.
- FocusNoLongerOnForm();
+ // Sent when either (a) focus moves off of any form element, or (b) focus
+ // moves off of the form that the user had previously interacted with to a
+ // different form. |had_interacted_form| indicates whether there was such a
+ // previously-interacted form.
+ // TODO(crbug.com/1140473): Remove need to pass |had_interacted_form|.
+ FocusNoLongerOnForm(bool had_interacted_form);
// Notification that a form field is focused.
FocusOnFormField(FormData form,
@@ -108,6 +112,10 @@ interface PasswordManagerDriver {
// FRAME_DETACHED.
SameDocumentNavigation(SubmissionIndicatorEvent submission_indication_event);
+ // Notification that password form was cleared. This is used as a signal of
+ // a successful submission for change password forms.
+ PasswordFormCleared(FormData form_data);
+
// Sends |log| to browser for displaying to the user. Only strings passed as
// an argument to methods overriding SavePasswordProgressLogger::SendLog may
// become |log|, because those are guaranteed to be sanitized.
diff --git a/chromium/components/autofill/content/renderer/OWNERS b/chromium/components/autofill/content/renderer/OWNERS
index 15f8279c885..39dfee96ce7 100644
--- a/chromium/components/autofill/content/renderer/OWNERS
+++ b/chromium/components/autofill/content/renderer/OWNERS
@@ -1,7 +1,2 @@
-per-file *password*=dvadym@chromium.org
-per-file *password*=kolos@chromium.org
-per-file *password*=vasilii@chromium.org
-
-per-file *username*=dvadym@chromium.org
-per-file *username*=kolos@chromium.org
-per-file *username*=vasilii@chromium.org
+per-file *password*=file://components/password_manager/OWNERS
+per-file *username*=file://components/password_manager/OWNERS
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index c7e7044d8b9..95ff56c0a45 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -40,7 +40,6 @@
#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"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
#include "content/public/common/content_switches.h"
@@ -217,11 +216,9 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
HidePopup();
if (element.IsNull()) {
- if (!last_interacted_form_.IsNull()) {
- // Focus moved away from the last interacted form to somewhere else on
- // the page.
- GetAutofillDriver()->FocusNoLongerOnForm();
- }
+ // Focus moved away from the last interacted form (if any) to somewhere else
+ // on the page.
+ GetAutofillDriver()->FocusNoLongerOnForm(!last_interacted_form_.IsNull());
return;
}
@@ -232,7 +229,7 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
(!input || last_interacted_form_ != input->Form())) {
// The focused element is not part of the last interacted form (could be
// in a different form).
- GetAutofillDriver()->FocusNoLongerOnForm();
+ GetAutofillDriver()->FocusNoLongerOnForm(/*had_interacted_form=*/true);
focus_moved_to_new_form = true;
}
@@ -930,6 +927,14 @@ bool AutofillAgent::ShouldSuppressKeyboard(
autofill_assistant_agent_->ShouldSuppressKeyboard());
}
+void AutofillAgent::FormElementReset(const WebFormElement& form) {
+ password_autofill_agent_->InformAboutFormClearing(form);
+}
+
+void AutofillAgent::PasswordFieldReset(const WebInputElement& element) {
+ password_autofill_agent_->InformAboutFieldClearing(element);
+}
+
void AutofillAgent::SelectWasUpdated(
const blink::WebFormControlElement& element) {
// Look for the form and field associated with the select element. If they are
@@ -1106,6 +1111,11 @@ void AutofillAgent::RemoveFormObserver(Observer* observer) {
form_tracker_.RemoveObserver(observer);
}
+void AutofillAgent::TrackAutofilledElement(
+ const blink::WebFormControlElement& element) {
+ form_tracker_.TrackAutofilledElement(element);
+}
+
base::Optional<FormData> AutofillAgent::GetSubmittedForm() const {
if (!last_interacted_form_.IsNull()) {
FormData form;
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index b88c2b490e7..a6d4cbeb9ec 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -34,6 +34,7 @@ namespace blink {
class WebNode;
class WebView;
class WebFormControlElement;
+class WebFormElement;
template <typename T>
class WebVector;
} // namespace blink
@@ -118,6 +119,9 @@ class AutofillAgent : public content::RenderFrameObserver,
void AddFormObserver(Observer* observer);
void RemoveFormObserver(Observer* observer);
+ // Instructs `form_tracker_` to track the autofilled `element`.
+ void TrackAutofilledElement(const blink::WebFormControlElement& element);
+
FormTracker* form_tracker_for_testing() { return &form_tracker_; }
void SelectWasUpdated(const blink::WebFormControlElement& element);
@@ -191,6 +195,8 @@ class AutofillAgent : public content::RenderFrameObserver,
const blink::WebFormControlElement& element) override;
bool ShouldSuppressKeyboard(
const blink::WebFormControlElement& element) override;
+ void FormElementReset(const blink::WebFormElement& form) override;
+ void PasswordFieldReset(const blink::WebInputElement& element) override;
void HandleFocusChangeComplete();
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index 2ba2414738c..f42cf808f28 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -28,7 +28,6 @@
#include "build/build_config.h"
#include "components/autofill/core/common/autofill_data_validation.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/field_data_manager.h"
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index a64c24aa9ae..a4aca1d571a 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -105,9 +105,9 @@ bool IsFormInteresting(const FormData& form, size_t num_editable_elements) {
// If there are no autocomplete attributes, the form needs to have at least
// the required number of editable fields for the prediction routines to be a
// candidate for autofill.
- return num_editable_elements >= MinRequiredFieldsForHeuristics() ||
- num_editable_elements >= MinRequiredFieldsForQuery() ||
- num_editable_elements >= MinRequiredFieldsForUpload() ||
+ return num_editable_elements >= kMinRequiredFieldsForHeuristics ||
+ num_editable_elements >= kMinRequiredFieldsForQuery ||
+ num_editable_elements >= kMinRequiredFieldsForUpload ||
(all_fields_are_passwords &&
num_editable_elements >=
kRequiredFieldsForFormsWithOnlyPasswordFields);
diff --git a/chromium/components/autofill/content/renderer/form_tracker.cc b/chromium/components/autofill/content/renderer/form_tracker.cc
index f4f99702c69..0afae7d2a75 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.cc
+++ b/chromium/components/autofill/content/renderer/form_tracker.cc
@@ -106,6 +106,21 @@ void FormTracker::SelectControlDidChange(const WebFormControlElement& element) {
Observer::ElementChangeSource::SELECT_CHANGED));
}
+void FormTracker::TrackAutofilledElement(const WebFormControlElement& element) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
+ DCHECK(element.IsAutofilled());
+
+ if (ignore_control_changes_)
+ return;
+
+ ResetLastInteractedElements();
+ if (element.Form().IsNull())
+ last_interacted_formless_element_ = element;
+ else
+ last_interacted_form_ = element.Form();
+ TrackElement();
+}
+
void FormTracker::FireProbablyFormSubmittedForTesting() {
FireProbablyFormSubmitted();
}
diff --git a/chromium/components/autofill/content/renderer/form_tracker.h b/chromium/components/autofill/content/renderer/form_tracker.h
index 7498871c373..ea0e7ca31aa 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.h
+++ b/chromium/components/autofill/content/renderer/form_tracker.h
@@ -73,6 +73,11 @@ class FormTracker : public content::RenderFrameObserver {
void TextFieldDidChange(const blink::WebFormControlElement& element);
void SelectControlDidChange(const blink::WebFormControlElement& element);
+ // Tells the tracker to track the autofilled `element`. Since autofilling a
+ // form or field won't trigger the regular *DidChange events, the tracker
+ // won't be notified of this `element` otherwise.
+ void TrackAutofilledElement(const blink::WebFormControlElement& element);
+
void set_ignore_control_changes(bool ignore_control_changes) {
ignore_control_changes_ = ignore_control_changes;
}
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.h b/chromium/components/autofill/content/renderer/html_based_username_detector.h
index 5a32cb4a353..ef1c22a4b90 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.h
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.h
@@ -8,7 +8,7 @@
#include <map>
#include <vector>
-#include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_input_element.h"
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index 7e4b3154b54..83a970ccad2 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -570,6 +570,11 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
}
}
+void PasswordAutofillAgent::TrackAutofilledElement(
+ const blink::WebFormControlElement& element) {
+ autofill_agent_->TrackAutofilledElement(element);
+}
+
bool PasswordAutofillAgent::FillSuggestion(
const WebFormControlElement& control_element,
const base::string16& username,
@@ -640,6 +645,7 @@ void PasswordAutofillAgent::FillField(WebInputElement* input,
const FieldRendererId input_id(input->UniqueRendererFormControlId());
field_data_manager_->UpdateFieldDataMap(
input_id, credential, FieldPropertiesFlags::kAutofilledOnUserTrigger);
+ TrackAutofilledElement(*input);
}
void PasswordAutofillAgent::FillPasswordFieldAndSave(
@@ -797,19 +803,6 @@ bool PasswordAutofillAgent::ShouldSuppressKeyboard() {
bool PasswordAutofillAgent::TryToShowTouchToFill(
const WebFormControlElement& control_element) {
- // Don't show Touch To Fill if it should only be enabled for insecure origins
- // and we are currently on a potentially trustworthy origin.
- if (base::GetFieldTrialParamByFeatureAsBool(features::kAutofillTouchToFill,
- "insecure-origins-only",
- /*default_value=*/false) &&
- render_frame()
- ->GetWebFrame()
- ->GetDocument()
- .GetSecurityOrigin()
- .IsPotentiallyTrustworthy()) {
- return false;
- }
-
if (touch_to_fill_state_ != TouchToFillState::kShouldShow)
return false;
@@ -1380,6 +1373,51 @@ PasswordAutofillAgent::GetFormDataFromUnownedInputElements() {
&button_titles_cache_);
}
+void PasswordAutofillAgent::InformAboutFormClearing(
+ const WebFormElement& form) {
+ if (!FrameCanAccessPasswordManager())
+ return;
+ for (const auto& element : form.GetFormControlElements()) {
+ FieldRendererId element_id(element.UniqueRendererFormControlId());
+ // Notify PasswordManager if |form| has password fields that have user typed
+ // input or input autofilled on user trigger.
+ if (IsPasswordFieldFilledByUser(element)) {
+ NotifyPasswordManagerAboutClearedForm(form);
+ return;
+ }
+ }
+}
+
+void PasswordAutofillAgent::InformAboutFieldClearing(
+ const WebInputElement& cleared_element) {
+ if (!FrameCanAccessPasswordManager())
+ return;
+ DCHECK(cleared_element.Value().IsEmpty());
+ FieldRendererId field_id(cleared_element.UniqueRendererFormControlId());
+ // Ignore fields that had no user input or autofill on user trigger.
+ if (!field_data_manager_->DidUserType(field_id) &&
+ !field_data_manager_->WasAutofilledOnUserTrigger(field_id)) {
+ return;
+ }
+
+ WebFormElement form = cleared_element.Form();
+ if (form.IsNull()) {
+ // Process password field clearing for fields outside the <form> tag.
+ if (auto unowned_form_data = GetFormDataFromUnownedInputElements())
+ GetPasswordManagerDriver()->PasswordFormCleared(*unowned_form_data);
+ return;
+ }
+ // Process field clearing for a form under a <form> tag.
+ // Only notify PasswordManager in case all user filled password fields were
+ // cleared.
+ bool cleared_all_password_fields = base::ranges::all_of(
+ form.GetFormControlElements(), [this](const auto& el) {
+ return !IsPasswordFieldFilledByUser(el) || el.Value().IsEmpty();
+ });
+ if (cleared_all_password_fields)
+ NotifyPasswordManagerAboutClearedForm(form);
+}
+
////////////////////////////////////////////////////////////////////////////////
// PasswordAutofillAgent, private:
@@ -1868,4 +1906,24 @@ bool PasswordAutofillAgent::CanShowPopupWithoutPasswords(
IsElementEditable(password_element);
}
+bool PasswordAutofillAgent::IsPasswordFieldFilledByUser(
+ const WebFormControlElement& element) const {
+ FieldRendererId element_id(element.UniqueRendererFormControlId());
+ return element.FormControlTypeForAutofill() == "password" &&
+ (field_data_manager_->DidUserType(element_id) ||
+ field_data_manager_->WasAutofilledOnUserTrigger(element_id));
+}
+
+void PasswordAutofillAgent::NotifyPasswordManagerAboutClearedForm(
+ const WebFormElement& cleared_form) {
+ const auto extract_mask = static_cast<form_util::ExtractMask>(
+ form_util::EXTRACT_VALUE | form_util::EXTRACT_OPTIONS);
+ FormData form_data;
+ if (WebFormElementToFormData(cleared_form, WebFormControlElement(),
+ field_data_manager_.get(), extract_mask,
+ &form_data, nullptr)) {
+ GetPasswordManagerDriver()->PasswordFormCleared(form_data);
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index 3738a1fc7b2..040f7aecada 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -24,7 +24,6 @@
#include "components/autofill/content/renderer/html_based_username_detector.h"
#include "components/autofill/core/common/field_data_manager.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
-#include "components/autofill/core/common/password_form.h"
#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"
@@ -163,6 +162,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// shown.
void UpdateStateForTextChange(const blink::WebInputElement& element);
+ // Instructs `autofill_agent_` to track the autofilled `element`.
+ void TrackAutofilledElement(const blink::WebFormControlElement& element);
+
// Fills the username and password fields of this form with the given values.
// Returns true if the fields were filled, false otherwise.
bool FillSuggestion(const blink::WebFormControlElement& control_element,
@@ -221,6 +223,16 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
std::unique_ptr<FormData> GetFormDataFromUnownedInputElements();
+ // Notification that form element was cleared by HTMLFormElement::reset()
+ // method. This can be used as a signal of a successful submission for change
+ // password forms.
+ void InformAboutFormClearing(const blink::WebFormElement& form);
+
+ // Notification that input element was cleared by HTMLInputValue::SetValue()
+ // method by setting an empty value. This can be used as a signal of a
+ // successful submission for change password forms.
+ void InformAboutFieldClearing(const blink::WebInputElement& element);
+
bool logging_state_active() const { return logging_state_active_; }
// Determine whether the current frame is allowed to access the password
@@ -465,6 +477,15 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
bool CanShowPopupWithoutPasswords(
const blink::WebInputElement& password_element) const;
+ // Returns true if the element is of type 'password' and has either user typed
+ // input or input autofilled on user trigger.
+ bool IsPasswordFieldFilledByUser(
+ const blink::WebFormControlElement& element) const;
+
+ // Extracts and sends the form data of |cleared_form| to PasswordManager.
+ void NotifyPasswordManagerAboutClearedForm(
+ const blink::WebFormElement& cleared_form);
+
// The logins we have filled so far with their associated info.
WebInputToPasswordInfoMap web_input_to_password_info_;
// A (sort-of) reverse map to |web_input_to_password_info_|.
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
index 93824cae0bd..81cea7d92e2 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "components/autofill/content/renderer/html_based_username_detector.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/renderer_id.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/base/url_util.h"
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
index 07a2ad05095..1685530ea03 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -14,7 +14,6 @@
#include "base/strings/string_piece.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/html_based_username_detector.h"
-#include "components/autofill/core/common/password_form.h"
#include "third_party/blink/public/platform/web_string.h"
#include "url/gurl.h"
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index a87d298ca38..dea5a37779b 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -19,7 +19,6 @@
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/signatures.h"
@@ -232,6 +231,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
if (!render_frame())
return;
password_element.SetAutofillState(WebAutofillState::kAutofilled);
+ password_agent_->TrackAutofilledElement(password_element);
// Advance focus to the next input field. We assume password fields in
// an account creation form are always adjacent.
render_frame()->GetRenderView()->GetWebView()->AdvanceFocus(false);
@@ -290,10 +290,10 @@ void PasswordGenerationAgent::FoundFormEligibleForGeneration(
}
}
-void PasswordGenerationAgent::UserTriggeredGeneratePassword(
- UserTriggeredGeneratePasswordCallback callback) {
- if (SetUpUserTriggeredGeneration()) {
- LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP);
+void PasswordGenerationAgent::TriggeredGeneratePassword(
+ TriggeredGeneratePasswordCallback callback) {
+ if (SetUpTriggeredGeneration()) {
+ LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP);
// If the field is not |type=password|, the list of suggestions
// should not be populated with passwords to avoid filling them in a
// clear-text field.
@@ -320,7 +320,7 @@ void PasswordGenerationAgent::UserTriggeredGeneratePassword(
}
}
-bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() {
+bool PasswordGenerationAgent::SetUpTriggeredGeneration() {
if (last_focused_password_element_.IsNull() || !render_frame())
return false;
@@ -493,6 +493,11 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
*presaved_form_data, generated_password);
}
}
+
+ // Notify `password_agent_` of text changes to the other confirmation
+ // password fields.
+ for (const auto& element : current_generation_item_->password_elements_)
+ password_agent_->UpdateStateForTextChange(element);
}
return true;
}
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h
index 2eeb0e3044e..37fb76215b0 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.h
@@ -59,8 +59,8 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
const PasswordFormGenerationData& form) override;
// Sets |generation_element_| to the focused password field and responds back
// if the generation was triggered successfully.
- void UserTriggeredGeneratePassword(
- UserTriggeredGeneratePasswordCallback callback) override;
+ void TriggeredGeneratePassword(
+ TriggeredGeneratePasswordCallback callback) override;
// Returns true if the field being changed is one where a generated password
// is being offered. Updates the state of the popup if necessary.
@@ -110,7 +110,7 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
// Helper function which takes care of the form processing and collecting the
// information which is required to show the generation popup. Returns true if
// all required information is collected.
- bool SetUpUserTriggeredGeneration();
+ bool SetUpTriggeredGeneration();
// This is called whenever automatic generation could be offered.
// If manual generation was already requested, automatic generation will
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 6c76bdbd609..a747fd5924f 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -55,6 +55,8 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
void SameDocumentNavigation(autofill::mojom::SubmissionIndicatorEvent
submission_indication_event) override {}
+ void PasswordFormCleared(const autofill::FormData& form_data) override {}
+
void ShowPasswordSuggestions(base::i18n::TextDirection text_direction,
const base::string16& typed_username,
int options,
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 3447ad7a303..b0dcbce1521 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -25,6 +25,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_rewriter.cc",
"address_rewriter.h",
"autocomplete_history_manager.cc",
@@ -71,6 +73,10 @@ static_library("browser") {
"autofill_profile_validator.h",
"autofill_provider.cc",
"autofill_provider.h",
+ "autofill_regex_constants.cc",
+ "autofill_regex_constants.h",
+ "autofill_regexes.cc",
+ "autofill_regexes.h",
"autofill_subject.cc",
"autofill_subject.h",
"autofill_type.cc",
@@ -151,6 +157,10 @@ static_library("browser") {
"form_types.h",
"geo/address_i18n.cc",
"geo/address_i18n.h",
+ "geo/alternative_state_name_map.cc",
+ "geo/alternative_state_name_map.h",
+ "geo/alternative_state_name_map_updater.cc",
+ "geo/alternative_state_name_map_updater.h",
"geo/autofill_country.cc",
"geo/autofill_country.h",
"geo/country_data.cc",
@@ -183,6 +193,8 @@ static_library("browser") {
"metrics/form_event_logger_base.cc",
"metrics/form_event_logger_base.h",
"metrics/form_events.h",
+ "pattern_provider/pattern_configuration_parser.cc",
+ "pattern_provider/pattern_configuration_parser.h",
"pattern_provider/pattern_provider.cc",
"pattern_provider/pattern_provider.h",
"payments/account_info_getter.h",
@@ -390,6 +402,7 @@ static_library("browser") {
"//crypto",
"//google_apis",
"//net",
+ "//services/data_decoder/public/cpp:cpp",
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp",
@@ -440,12 +453,16 @@ static_library("test_support") {
"autofill_test_utils.h",
"data_driven_test.cc",
"data_driven_test.h",
+ "geo/alternative_state_name_map_test_utils.cc",
+ "geo/alternative_state_name_map_test_utils.h",
"geo/test_region_data_loader.cc",
"geo/test_region_data_loader.h",
"logging/stub_log_manager.cc",
"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",
@@ -576,6 +593,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_rewriter_unittest.cc",
"autocomplete_history_manager_unittest.cc",
"autofill_address_policy_handler_unittest.cc",
@@ -591,6 +609,7 @@ source_set("unit_tests") {
"autofill_profile_sync_util_unittest.cc",
"autofill_profile_validation_util_unittest.cc",
"autofill_profile_validator_unittest.cc",
+ "autofill_regexes_unittest.cc",
"autofill_subject_unittest.cc",
"autofill_type_unittest.cc",
"data_model/address_unittest.cc",
@@ -620,6 +639,8 @@ source_set("unit_tests") {
"form_parsing/search_field_unittest.cc",
"form_structure_unittest.cc",
"geo/address_i18n_unittest.cc",
+ "geo/alternative_state_name_map_unittest.cc",
+ "geo/alternative_state_name_map_updater_unittest.cc",
"geo/autofill_country_unittest.cc",
"geo/country_names_for_locale_unittest.cc",
"geo/country_names_unittest.cc",
@@ -628,6 +649,7 @@ source_set("unit_tests") {
"logging/log_buffer_submitter_unittest.cc",
"logging/log_manager_unittest.cc",
"logging/log_router_unittest.cc",
+ "pattern_provider/pattern_configuration_parser_unittest.cc",
"pattern_provider/pattern_provider_unittest.cc",
"payments/autofill_offer_manager_unittest.cc",
"payments/credit_card_access_manager_unittest.cc",
@@ -727,6 +749,7 @@ source_set("unit_tests") {
"//google_apis",
"//google_apis:test_support",
"//net:test_support",
+ "//services/data_decoder/public/cpp:test_support",
"//services/metrics/public/cpp:ukm_builders",
"//services/network:test_support",
"//services/network/public/cpp",
diff --git a/chromium/components/autofill/core/browser/OWNERS b/chromium/components/autofill/core/browser/OWNERS
index c23e8389686..711aa7cc667 100644
--- a/chromium/components/autofill/core/browser/OWNERS
+++ b/chromium/components/autofill/core/browser/OWNERS
@@ -1,4 +1,2 @@
-parastoog@google.com
-
per-file *type_controller*=jkrcal@chromium.org
per-file *type_controller*=file://components/sync/OWNERS
diff --git a/chromium/components/autofill/core/browser/address_normalization_manager.cc b/chromium/components/autofill/core/browser/address_normalization_manager.cc
index a83ef900e07..708572b38d4 100644
--- a/chromium/components/autofill/core/browser/address_normalization_manager.cc
+++ b/chromium/components/autofill/core/browser/address_normalization_manager.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/address_normalizer.h"
diff --git a/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc b/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc
index b8a775340c2..e7f89b09415 100644
--- a/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/autofill/core/browser/test_address_normalizer.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl.cc b/chromium/components/autofill/core/browser/address_normalizer_impl.cc
index 85ff881f2fa..335589e92bf 100644
--- a/chromium/components/autofill/core/browser/address_normalizer_impl.cc
+++ b/chromium/components/autofill/core/browser/address_normalizer_impl.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/check_op.h"
#include "base/location.h"
diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc b/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc
index a3c5cfe306a..dc3206e2822 100644
--- a/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/address_normalizer.h"
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
new file mode 100644
index 00000000000..4081c68239a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc
@@ -0,0 +1,25 @@
+// 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
new file mode 100644
index 00000000000..69ac2d01511
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h
@@ -0,0 +1,39 @@
+// 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
new file mode 100644
index 00000000000..b73b0dc35e5
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc
@@ -0,0 +1,34 @@
+// 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/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
index 2eb1f5540ac..83dbe8e0995 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
@@ -5,6 +5,7 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<meta charset="utf-8">
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="autofill_and_password_manager_internals.js"></script>
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
index d48f3884ed1..918dd3bfa40 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
@@ -10,6 +10,7 @@
injected by web. -->
<script src="chrome://resources/js/ios/web_ui.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="autofill_and_password_manager_internals.js"></script>
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc
index 21daf5d37ac..d8b5520cfc4 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util.cc
@@ -185,8 +185,7 @@ bool IsHangulCharacter(UChar32 c) {
// characters or spaces. |name| should already be confirmed to be a CJK name, as
// per |IsCJKName()|.
bool IsHangulName(base::StringPiece16 name) {
- for (base::i18n::UTF16CharIterator iter(name.data(), name.length());
- !iter.end(); iter.Advance()) {
+ for (base::i18n::UTF16CharIterator iter(name); !iter.end(); iter.Advance()) {
UChar32 c = iter.get();
if (!IsHangulCharacter(c) && !base::IsUnicodeWhitespace(c)) {
return false;
@@ -367,8 +366,7 @@ bool IsCJKName(base::StringPiece16 name) {
static const base::char16 kMiddleDot = u'\u00B7';
bool previous_was_cjk = false;
size_t word_count = 0;
- for (base::i18n::UTF16CharIterator iter(name.data(), name.length());
- !iter.end(); iter.Advance()) {
+ for (base::i18n::UTF16CharIterator iter(name); !iter.end(); iter.Advance()) {
UChar32 c = iter.get();
const bool is_cjk = IsCJKCharacter(c);
if (!is_cjk && !base::IsUnicodeWhitespace(c) && c != kKatakanaMiddleDot &&
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 74b0009b7e3..923f8c9071c 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -1341,7 +1341,7 @@ class AutofillServerCommunicationTest
driver_ = std::make_unique<TestAutofillDriver>();
driver_->SetSharedURLLoaderFactory(shared_url_loader_factory_);
driver_->SetIsolationInfo(net::IsolationInfo::Create(
- net::IsolationInfo::RedirectMode::kUpdateNothing,
+ net::IsolationInfo::RequestType::kOther,
url::Origin::Create(GURL("https://abc.com")),
url::Origin::Create(GURL("https://xyz.com")), net::SiteForCookies()));
@@ -2062,8 +2062,7 @@ TEST_P(AutofillUploadTest, ThrottlingDisabled) {
// Enabled.
{},
// Disabled
- {features::kAutofillUploadThrottling,
- features::kAutofillEnforceMinRequiredFieldsForUpload});
+ {features::kAutofillUploadThrottling});
FormData form;
FormData small_form;
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
index e9f6e3c3c50..23b169a68b2 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
diff --git a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
index 47c3f1bd4a2..7e0893d3adb 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
@@ -4,7 +4,7 @@
#include "components/autofill/core/browser/autofill_experiments.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_metrics.h"
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 5cd990ebb73..6a81dc37934 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -13,7 +13,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_experiments.h"
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index 376f1b8381f..41610aa4482 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -143,6 +143,27 @@ AutofillType AutofillField::ComputedType() const {
believe_server = believe_server &&
!(AutofillType(server_type_).group() == PASSWORD_FIELD &&
heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
+
+ // For new name tokens the heuristic predictions get precedence over the
+ // server predictions.
+ // TODO(crbug.com/1098943): Remove feature check once launched.
+ believe_server =
+ believe_server &&
+ !(base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInNames) &&
+ (heuristic_type_ == NAME_LAST_SECOND ||
+ heuristic_type_ == NAME_LAST_FIRST));
+
+ // For new address tokens the heuristic predictions get precedence over the
+ // server predictions.
+ // TODO(crbug.com/1098943): Remove feature check once launched.
+ believe_server =
+ believe_server &&
+ !(base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInAddresses) &&
+ (heuristic_type_ == ADDRESS_HOME_STREET_NAME ||
+ heuristic_type_ == ADDRESS_HOME_HOUSE_NUMBER));
+
if (believe_server)
return AutofillType(server_type_);
}
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 177004fffb2..f8889cfce9f 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -48,6 +48,10 @@ FormFieldData CreateFieldByRole(ServerFieldType role) {
field.label = ASCIIToUTF16("E-mail address");
field.name = ASCIIToUTF16("email");
break;
+ case ServerFieldType::ADDRESS_HOME_LINE1:
+ field.label = ASCIIToUTF16("Address");
+ field.name = ASCIIToUTF16("home_line_one");
+ break;
case ServerFieldType::ADDRESS_HOME_CITY:
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
@@ -84,11 +88,19 @@ FormFieldData CreateFieldByRole(ServerFieldType role) {
return field;
}
-FormData GetFormData(const FormAttributes& form_attributes) {
+FormData GetFormData(const TestFormAttributes& test_form_attributes) {
FormData form_data;
- form_data.url = GURL(form_attributes.form_url);
- for (const FieldDataDescription& field_description : form_attributes.fields) {
+ form_data.url = GURL(test_form_attributes.url);
+ form_data.action = GURL(test_form_attributes.action);
+ form_data.name = ASCIIToUTF16(test_form_attributes.name);
+ static int field_count = 0;
+ if (test_form_attributes.unique_renderer_id)
+ form_data.unique_renderer_id = *test_form_attributes.unique_renderer_id;
+ if (test_form_attributes.main_frame_origin)
+ form_data.main_frame_origin = *test_form_attributes.main_frame_origin;
+ for (const FieldDataDescription& field_description :
+ test_form_attributes.fields) {
FormFieldData field = CreateFieldByRole(field_description.role);
field.form_control_type = field_description.form_control_type;
field.is_focusable = field_description.is_focusable;
@@ -98,11 +110,16 @@ FormData GetFormData(const FormAttributes& form_attributes) {
field.label = ASCIIToUTF16(field_description.label);
if (ASCIIToUTF16(field_description.name) != ASCIIToUTF16(kNameText))
field.name = ASCIIToUTF16(field_description.name);
+ if (field_description.value)
+ field.value = ASCIIToUTF16(*field_description.value);
+ if (field_description.is_autofilled)
+ field.is_autofilled = *field_description.is_autofilled;
+ field.unique_renderer_id = FieldRendererId(field_count++);
field.should_autocomplete = field_description.should_autocomplete;
form_data.fields.push_back(field);
}
- form_data.is_formless_checkout = form_attributes.is_formless_checkout;
- form_data.is_form_tag = form_attributes.is_form_tag;
+ form_data.is_formless_checkout = test_form_attributes.is_formless_checkout;
+ form_data.is_form_tag = test_form_attributes.is_form_tag;
return form_data;
}
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.h b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
index 6ec1180c09c..0c4c9b936c1 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
@@ -26,7 +26,10 @@ constexpr char kLabelText[] = "label";
constexpr char kNameText[] = "name";
// Default form url.
-constexpr char kFormUrl[] = "http://www.foo.com/";
+constexpr char kFormUrl[] = "http://example.com/form.html";
+
+// Default form action url.
+constexpr char kFormActionUrl[] = "http://example.com/submit.html";
} // namespace
@@ -39,17 +42,23 @@ struct FieldDataDescription {
bool is_focusable = true;
const char* label = kLabelText;
const char* name = kNameText;
+ base::Optional<const char*> value = base::nullopt;
const char* autocomplete_attribute = nullptr;
const char* form_control_type = "text";
bool should_autocomplete = true;
+ base::Optional<bool> is_autofilled = base::nullopt;
};
// Attributes provided to the test form.
template <typename = void>
-struct FormAttributes {
- const char* description_for_logging = "";
- std::vector<FieldDataDescription<>> fields = {};
- const char* form_url = kFormUrl;
+struct TestFormAttributes {
+ const char* description_for_logging;
+ std::vector<FieldDataDescription<>> fields;
+ base::Optional<FormRendererId> unique_renderer_id = base::nullopt;
+ const char* name = "TestForm";
+ const char* url = kFormUrl;
+ const char* action = kFormActionUrl;
+ base::Optional<url::Origin> main_frame_origin = base::nullopt;
bool is_formless_checkout = false;
bool is_form_tag = true;
};
@@ -57,7 +66,7 @@ struct FormAttributes {
// Flags determining whether the corresponding check should be run on the test
// form.
template <typename = void>
-struct FormFlags {
+struct TestFormFlags {
// false means the function is not to be called.
bool determine_heuristic_type = false;
bool parse_query_response = false;
@@ -90,15 +99,15 @@ struct ExpectedFieldTypeValues {
// Describes a test case for the parser.
template <typename = void>
struct FormStructureTestCase {
- FormAttributes<> form_attributes;
- FormFlags<> form_flags;
+ TestFormAttributes<> form_attributes;
+ TestFormFlags<> form_flags;
ExpectedFieldTypeValues<> expected_field_types;
};
} // namespace internal
using FieldDataDescription = internal::FieldDataDescription<>;
-using FormAttributes = internal::FormAttributes<>;
+using TestFormAttributes = internal::TestFormAttributes<>;
using FormStructureTestCase = internal::FormStructureTestCase<>;
// Describes the |form_data|. Use this in SCOPED_TRACE if other logging
@@ -109,7 +118,7 @@ testing::Message DescribeFormData(const FormData& form_data);
FormFieldData CreateFieldByRole(ServerFieldType role);
// Creates a FormData to be fed to the parser.
-FormData GetFormData(const FormAttributes& form_attributes);
+FormData GetFormData(const TestFormAttributes& test_form_attributes);
class FormStructureTest : public testing::Test {
protected:
diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc
index c7474a25dfa..b8f647955ae 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler.cc
@@ -30,6 +30,10 @@ const size_t kAutofillHandlerMaxFormCacheSize = 100;
// if not found.
AutofillField* FindAutofillFillField(const FormStructure& form,
const FormFieldData& field) {
+ for (const auto& f : form) {
+ if (field.unique_renderer_id == f->unique_renderer_id)
+ return f.get();
+ }
for (const auto& cur_field : form) {
if (cur_field->SameFieldAs(field)) {
return cur_field.get();
@@ -99,17 +103,11 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
// code would have ignored the cache hit we update the FormStructure's
// FormSignature.
// Otherwise, if the experiment disabled, we just ignore the cache hit.
- //
- // TODO(crbug.com/1100231) Clean up when experiment is complete.
- const bool kOldBehavior = !base::FeatureList::IsEnabled(
- features::kAutofillKeepInitialFormValuesInCache);
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;
- if (kOldBehavior)
- cached_form_structure = nullptr;
break;
}
}
@@ -120,7 +118,7 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
continue;
DCHECK(form_structure);
- if (update_form_signature && !kOldBehavior)
+ if (update_form_signature)
form_structure->set_form_signature(CalculateFormSignature(form));
new_forms.push_back(&form);
diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h
index d476cd02d5a..18b7d0b42c3 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.h
+++ b/chromium/components/autofill/core/browser/autofill_handler.h
@@ -89,8 +89,9 @@ class AutofillHandler {
void OnFormsSeen(const std::vector<FormData>& forms,
const base::TimeTicks timestamp);
- // Invoked when focus is no longer on form.
- virtual void OnFocusNoLongerOnForm() = 0;
+ // 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.
+ virtual void OnFocusNoLongerOnForm(bool had_interacted_form) = 0;
// Invoked when |form| has been filled with the value given by
// SendFormDataToRenderer.
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
index 4a917d09f4b..41fd6d405e2 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -74,8 +74,8 @@ void AutofillHandlerProxy::OnFormsParsed(
const std::vector<const FormData*>& form_structures,
const base::TimeTicks timestamp) {}
-void AutofillHandlerProxy::OnFocusNoLongerOnForm() {
- provider_->OnFocusNoLongerOnForm(this);
+void AutofillHandlerProxy::OnFocusNoLongerOnForm(bool had_interacted_form) {
+ provider_->OnFocusNoLongerOnForm(this, had_interacted_form);
}
void AutofillHandlerProxy::OnDidFillAutofillFormData(
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.h b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
index 741b30da102..8d2f0287888 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.h
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
@@ -20,7 +20,7 @@ class AutofillHandlerProxy : public AutofillHandler {
AutofillProvider* provider);
~AutofillHandlerProxy() override;
- void OnFocusNoLongerOnForm() override;
+ void OnFocusNoLongerOnForm(bool had_interacted_form) override;
void OnDidFillAutofillFormData(const FormData& form,
const base::TimeTicks timestamp) override;
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index a9dd2e727dd..9f4f5f3688e 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -451,7 +451,9 @@ AutofillManager::FillingContext::FillingContext(
*optional_credit_card,
optional_cvc ? *optional_cvc : base::string16()))
: base::nullopt),
- filled_field_name(field.unique_name()),
+ 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);
@@ -1137,7 +1139,13 @@ void AutofillManager::FillProfileForm(const autofill::AutofillProfile& profile,
/*query_id=*/-1, form, field, profile);
}
-void AutofillManager::OnFocusNoLongerOnForm() {
+void AutofillManager::OnFocusNoLongerOnForm(bool had_interacted_form) {
+ // For historical reasons, Chrome takes action on this message only if focus
+ // was previously on a form with which the user had interacted.
+ // TODO(crbug.com/1140473): Remove need for this short-circuit.
+ if (!had_interacted_form)
+ return;
+
ProcessPendingFormForUpload();
#if defined(OS_CHROMEOS)
@@ -1607,7 +1615,8 @@ void AutofillManager::Reset() {
credit_card_action_ = AutofillDriver::FORM_DATA_ACTION_PREVIEW;
initial_interaction_timestamp_ = TimeTicks();
external_delegate_->Reset();
- filling_contexts_map_.clear();
+ filling_context_by_renderer_id_.clear();
+ filling_context_by_unique_name_.clear();
}
AutofillManager::AutofillManager(
@@ -1739,9 +1748,9 @@ void AutofillManager::FillOrPreviewDataModelForm(
DCHECK_EQ(form_structure->field_count(), form.fields.size());
if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) {
- filling_contexts_map_[form_structure->GetIdentifierForRefill()] =
- std::make_unique<FillingContext>(*autofill_field, optional_profile,
- optional_credit_card, optional_cvc);
+ SetFillingContext(*form_structure, std::make_unique<FillingContext>(
+ *autofill_field, optional_profile,
+ optional_credit_card, optional_cvc));
}
// Only record the types that are filled for an eventual refill if all the
@@ -1750,11 +1759,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
// A form with the given name is already filled.
// A refill has not been attempted for that form yet.
// This fill is not a refill attempt.
- FillingContext* filling_context = nullptr;
- auto itr =
- filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
- if (itr != filling_contexts_map_.end())
- filling_context = itr->second.get();
+ FillingContext* filling_context = GetFillingContext(*form_structure);
bool could_attempt_refill = filling_context != nullptr &&
!filling_context->attempted_refill && !is_refill;
@@ -2094,10 +2099,8 @@ void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms,
// been a refill attempt on that form yet, start the process of triggering a
// refill.
if (ShouldTriggerRefill(*form_structure)) {
- auto itr =
- filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
- DCHECK(itr != filling_contexts_map_.end());
- FillingContext* filling_context = itr->second.get();
+ 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.
@@ -2464,18 +2467,44 @@ void AutofillManager::FillFieldWithValue(AutofillField* autofill_field,
}
}
+// TODO(crbug/896689): Remove code duplication once experiment is finished.
+void AutofillManager::SetFillingContext(
+ const FormStructure& form,
+ std::unique_ptr<FillingContext> context) {
+ if (base::FeatureList::IsEnabled(features::kAutofillRefillWithRendererIds)) {
+ filling_context_by_renderer_id_[form.unique_renderer_id()] =
+ std::move(context);
+ } else {
+ filling_context_by_unique_name_[form.GetIdentifierForRefill()] =
+ std::move(context);
+ }
+}
+
+// TODO(crbug/896689): Remove code duplication once experiment is finished.
+AutofillManager::FillingContext* AutofillManager::GetFillingContext(
+ const FormStructure& form) {
+ if (base::FeatureList::IsEnabled(features::kAutofillRefillWithRendererIds)) {
+ auto it = filling_context_by_renderer_id_.find(form.unique_renderer_id());
+ return it != filling_context_by_renderer_id_.end() ? it->second.get()
+ : nullptr;
+ } else {
+ auto it =
+ filling_context_by_unique_name_.find(form.GetIdentifierForRefill());
+ return it != filling_context_by_unique_name_.end() ? it->second.get()
+ : nullptr;
+ }
+}
+
bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) {
- // Should not refill if a form with the same name has not been filled
- // before.
- auto itr =
- filling_contexts_map_.find(form_structure.GetIdentifierForRefill());
- if (itr == filling_contexts_map_.end())
+ // Should not refill if a form with the same FormRendererId has not been
+ // filled before.
+ FillingContext* filling_context = GetFillingContext(form_structure);
+ if (filling_context == nullptr)
return false;
address_form_event_logger_->OnDidSeeFillableDynamicForm(sync_state_,
form_structure);
- FillingContext* filling_context = itr->second.get();
base::TimeTicks now = AutofillTickClock::NowTicks();
base::TimeDelta delta = now - filling_context->original_fill_time;
@@ -2499,16 +2528,14 @@ void AutofillManager::TriggerRefill(const FormData& form) {
address_form_event_logger_->OnDidRefill(sync_state_, *form_structure);
- auto itr =
- filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
+ FillingContext* filling_context = GetFillingContext(*form_structure);
// Since GetIdentifierForRefill() is not stable across dynamic changes,
- // |filling_contexts_map_| may not contain the element anymore.
- if (itr == filling_contexts_map_.end())
+ // |filling_context_by_unique_name_| may not contain the element anymore.
+ // TODO(crbug/896689): Can be replaced with DCHECK once experiment is over.
+ if (filling_context == nullptr)
return;
- FillingContext* filling_context = itr->second.get();
-
// The refill attempt can happen from different paths, some of which happen
// after waiting for a while. Therefore, although this condition has been
// checked prior to calling TriggerRefill, it may not hold, when we get
@@ -2519,14 +2546,44 @@ void AutofillManager::TriggerRefill(const FormData& form) {
filling_context->attempted_refill = true;
// Try to find the field from which the original field originated.
+ // Precedence is given to look up by |filled_field_renderer_id|.
+ // If that is unsuccessful, look up is done by |filled_field_signature|.
+ // TODO(crbug/896689): Clean up after feature launch.
AutofillField* autofill_field = nullptr;
for (const std::unique_ptr<AutofillField>& field : *form_structure) {
- if (field->unique_name() == filling_context->filled_field_name) {
+ // TODO(crbug/896689): Clean up once experiment is over.
+ if ((base::FeatureList::IsEnabled(
+ features::kAutofillRefillWithRendererIds) &&
+ field->unique_renderer_id ==
+ filling_context->filled_field_renderer_id) ||
+ (!base::FeatureList::IsEnabled(
+ features::kAutofillRefillWithRendererIds) &&
+ field->unique_name() == filling_context->filled_field_unique_name)) {
autofill_field = field.get();
break;
}
}
+ // If the field was deleted, look for one with a matching signature. Prefer
+ // visible and newer fields over invisible or older ones.
+ if (base::FeatureList::IsEnabled(features::kAutofillRefillWithRendererIds) &&
+ autofill_field == nullptr) {
+ auto is_better = [](const AutofillField& f, const AutofillField& g) {
+ return std::forward_as_tuple(f.IsVisible(),
+ f.unique_renderer_id.value()) >
+ std::forward_as_tuple(g.IsVisible(), g.unique_renderer_id.value());
+ };
+
+ for (const std::unique_ptr<AutofillField>& field : *form_structure) {
+ if (field->GetFieldSignature() ==
+ filling_context->filled_field_signature) {
+ if (autofill_field == nullptr || is_better(*field, *autofill_field)) {
+ autofill_field = field.get();
+ }
+ }
+ }
+ }
+
// If it was not found cancel the refill.
if (!autofill_field)
return;
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index fc6e8bc4714..d2cecaf5e00 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -217,7 +217,7 @@ class AutofillManager : public AutofillHandler,
void DidSuppressPopup(const FormData& form, const FormFieldData& field);
// AutofillHandler:
- void OnFocusNoLongerOnForm() override;
+ void OnFocusNoLongerOnForm(bool had_interacted_form) override;
void OnFocusOnFormFieldImpl(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
@@ -388,6 +388,9 @@ class AutofillManager : public AutofillHandler,
// Exposed for testing.
bool is_rich_query_enabled() const { return is_rich_query_enabled_; }
+ // Exposed for testing.
+ FormData* pending_form_data() { return pending_form_data_.get(); }
+
private:
// Keeps track of the filling context for a form, used to make refill attemps.
struct FillingContext {
@@ -406,8 +409,12 @@ class AutofillManager : public AutofillHandler,
// empty.
const base::Optional<AutofillProfile> profile;
const base::Optional<std::pair<CreditCard, base::string16>> credit_card;
- // The name of the field that was initially filled.
- const base::string16 filled_field_name;
+ // 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|.
+ const FieldRendererId filled_field_renderer_id;
+ const FieldSignature filled_field_signature;
+ const base::string16 filled_field_unique_name;
// The time at which the initial fill occurred.
const base::TimeTicks original_fill_time;
// The timer used to trigger a refill.
@@ -582,7 +589,14 @@ class AutofillManager : public AutofillHandler,
uint32_t profile_form_bitmask,
std::string* failure_to_fill);
- // Whether there should be an attemps to refill the form. Returns true if all
+ // TODO(crbug/896689): Remove code duplication once experiment is finished.
+ void SetFillingContext(const FormStructure& form,
+ std::unique_ptr<FillingContext> context);
+
+ // TODO(crbug/896689): Remove code duplication once experiment is finished.
+ FillingContext* GetFillingContext(const FormStructure& form);
+
+ // Whether there should be an attempts to refill the form. Returns true if all
// the following are satisfied:
// There have been no refill on that page yet.
// A non empty form name was recorded in a previous fill
@@ -618,6 +632,7 @@ class AutofillManager : public AutofillHandler,
void SetDataList(const std::vector<base::string16>& values,
const std::vector<base::string16>& labels);
+
AutofillClient* const client_;
LogManager* log_manager_;
@@ -714,8 +729,11 @@ class AutofillManager : public AutofillHandler,
// A map of form names to FillingContext instances used to make refill
// attempts for dynamic forms.
+ // TODO(crbug/896689): Remove code duplication once experiment is finished.
+ std::map<FormRendererId, std::unique_ptr<FillingContext>>
+ filling_context_by_renderer_id_;
std::map<base::string16, std::unique_ptr<FillingContext>>
- filling_contexts_map_;
+ filling_context_by_unique_name_;
// Tracks whether or not rich query encoding is enabled for this client.
const bool is_rich_query_enabled_ = false;
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 7d296d95b25..d801bda0abb 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -37,6 +37,7 @@
#include "components/autofill/core/browser/data_model/credit_card.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"
@@ -94,9 +95,6 @@ using testing::UnorderedElementsAre;
namespace autofill {
-using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
-using features::kAutofillEnforceMinRequiredFieldsForQuery;
-using features::kAutofillEnforceMinRequiredFieldsForUpload;
using features::kAutofillRestrictUnownedFieldsToFormlessCheckout;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
@@ -637,6 +635,7 @@ class AutofillManagerTest : public testing::Test {
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) {
@@ -953,9 +952,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
// them have an autocomplete attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_MinFieldsEnforced_NoAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForHeuristics);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -987,9 +983,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
// suggestions are only made for the one that has the attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_MinFieldsEnforced_WithOneAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForHeuristics);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -1018,86 +1011,11 @@ TEST_P(AutofillManagerStructuredProfileTest,
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
-// Test that suggestions are returned by default when there are less than
-// three fields and none of them have an autocomplete attribute.
-TEST_P(AutofillManagerStructuredProfileTest,
- GetProfileSuggestions_NoMinFieldsEnforced_NoAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("MyForm");
- 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);
- form.fields.push_back(field);
- test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
- form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- // Ensure that autocomplete manager is called for both fields.
- EXPECT_CALL(*(autocomplete_history_manager_.get()),
- OnGetAutocompleteSuggestions)
- .Times(0);
-
- GetAutofillSuggestions(form, form.fields[0]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Charles", "Charles Hardin Holley", "", 1),
- Suggestion("Elvis", "Elvis Aaron Presley", "", 2));
-
- GetAutofillSuggestions(form, form.fields[1]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Holley", "Charles Hardin Holley", "", 1),
- Suggestion("Presley", "Elvis Aaron Presley", "", 2));
-}
-
-// Test that for form with two fields with one that has an autocomplete
-// attribute, suggestions are made for both if small form support is enabled
-// (no minimum number of fields enforced).
-TEST_P(AutofillManagerStructuredProfileTest,
- GetProfileSuggestions_NoMinFieldsEnforced_WithOneAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("MyForm");
- 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);
- field.autocomplete_attribute = "given-name";
- form.fields.push_back(field);
- test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
- field.autocomplete_attribute = "";
- form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- GetAutofillSuggestions(form, form.fields[0]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Charles", "Charles Hardin Holley", "", 1),
- Suggestion("Elvis", "Elvis Aaron Presley", "", 2));
-
- GetAutofillSuggestions(form, form.fields[1]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Holley", "Charles Hardin Holley", "", 1),
- Suggestion("Presley", "Elvis Aaron Presley", "", 2));
-}
-
// Test that for a form with two fields with autocomplete attributes,
// suggestions are made for both fields. This is true even if a minimum number
// of fields is enforced.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_SmallFormWithTwoAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForHeuristics);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -2123,6 +2041,79 @@ TEST_P(AutofillManagerStructuredProfileTest,
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
+// Test that the correct section is filled.
+TEST_F(AutofillManagerTest, FillTriggeredSection) {
+ // Set up our form data.
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ size_t index_of_trigger_field = form.fields.size();
+ test::CreateTestAddressFormData(&form);
+ FormsSeen({form});
+
+ // Check that the form has been parsed into two sections.
+ ASSERT_NE(form.fields.size(), 0u);
+ ASSERT_EQ(index_of_trigger_field, form.fields.size() / 2);
+ {
+ FormStructure* form_structure;
+ AutofillField* autofill_field;
+ bool found = autofill_manager_->GetCachedFormAndField(
+ form, form.fields[index_of_trigger_field], &form_structure,
+ &autofill_field);
+ ASSERT_TRUE(found);
+ for (size_t i = 0; i < form.fields.size() / 2; ++i) {
+ size_t j = form.fields.size() / 2 + i;
+ ASSERT_EQ(form_structure->field(i)->name, form_structure->field(j)->name);
+ ASSERT_NE(form_structure->field(i)->section,
+ form_structure->field(j)->section);
+ ASSERT_TRUE(form_structure->field(i)->SameFieldAs(form.fields[j]));
+ ASSERT_TRUE(form_structure->field(j)->SameFieldAs(form.fields[i]));
+ }
+ }
+
+ const char guid[] = "00000000-0000-0000-0000-000000000001";
+ AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
+ ASSERT_TRUE(profile);
+ EXPECT_EQ(1U, profile->use_count());
+ EXPECT_NE(base::Time(), profile->use_date());
+
+ int response_page_id = 0;
+ FormData response_data;
+ FillAutofillFormDataAndSaveResults(
+ kDefaultPageID, form, form.fields[index_of_trigger_field],
+ MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
+ // Extract the sections into individual forms to reduce boiler plate code.
+ size_t mid = response_data.fields.size() / 2;
+ FormData section1 = response_data;
+ FormData section2 = response_data;
+ section1.fields.erase(section1.fields.begin() + mid, section1.fields.end());
+ section2.fields.erase(section2.fields.begin(), section2.fields.end() - mid);
+ // First section should be empty, second should be filled.
+ ExpectFilledForm(response_page_id, section1, kDefaultPageID, "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "", "", true, false,
+ false);
+ ExpectFilledAddressFormElvis(response_page_id, section2, kDefaultPageID,
+ false);
+}
+
+// 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
+// needed.
+TEST_F(AutofillManagerTest,
+ ShouldIgnoreLossOfFocusWithNoPreviouslyInteractedForm) {
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+
+ autofill_manager_->UpdatePendingForm(form);
+ ASSERT_TRUE(autofill_manager_->pending_form_data()->SameFormAs(form));
+
+ // Receiving a notification that focus is no longer on the form *without* the
+ // renderer having a previously-interacted form should not result in
+ // any changes to the pending form.
+ autofill_manager_->OnFocusNoLongerOnForm(/*had_interacted_form=*/false);
+ EXPECT_TRUE(autofill_manager_->pending_form_data()->SameFormAs(form));
+}
+
TEST_F(AutofillManagerTest,
ShouldNotShowCreditCardsSuggestionsIfCreditCardAutofillDisabled) {
DisableCreditCardAutofill();
@@ -6484,7 +6475,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks());
// Simulate lost of focus on the form.
- autofill_manager_->OnFocusNoLongerOnForm();
+ autofill_manager_->OnFocusNoLongerOnForm(true);
}
// Test that navigating with a filled form sends an upload with types matching
@@ -6589,7 +6580,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
AutofillTickClock::NowTicks());
// Simulate lost of focus on the form.
- autofill_manager_->OnFocusNoLongerOnForm();
+ autofill_manager_->OnFocusNoLongerOnForm(true);
}
// Test that suggestions are returned for credit card fields with an
@@ -7291,60 +7282,18 @@ TEST_P(AutofillManagerStructuredProfileTest, ShouldUploadForm) {
test::CreateTestFormField("Name", "name", "", "text", &field);
form.fields.push_back(field);
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
- // With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Add a second field to the form.
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
- // With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has less than 3 fields but has autocomplete attribute.
form.fields[0].autocomplete_attribute = "given-name";
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
- // With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has more than 3 fields, no autocomplete attribute.
form.fields[0].autocomplete_attribute = "";
@@ -7370,21 +7319,8 @@ TEST_P(AutofillManagerStructuredProfileTest, ShouldUploadForm) {
test::CreateTestFormField("Password", "password", "", "password", &field);
form.fields.push_back(field);
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
// With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Autofill disabled.
autofill_manager_->SetAutofillProfileEnabled(false);
@@ -7593,55 +7529,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
}
}
-// Test that with small form upload enabled but heuristics and query disabled
-// we get uploads but not quality metrics.
-TEST_P(AutofillManagerStructuredProfileTest,
- SmallForm_Upload_NoHeuristicsOrQuery) {
- // Setup the feature environment.
- base::test::ScopedFeatureList features;
- features.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery},
- // Disabled.
- {kAutofillEnforceMinRequiredFieldsForUpload});
-
- // Add a local card to allow data matching for upload votes.
- CreditCard credit_card =
- autofill::test::GetRandomCreditCard(CreditCard::LOCAL_CARD);
- personal_data_.AddCreditCard(credit_card);
-
- // Set up the form.
- FormData form;
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
- FormFieldData field;
- test::CreateTestFormField("Unknown", "unknown", "", "text", &field);
- form.fields.push_back(field);
-
- // Have the browser encounter the form.
- FormsSeen({form});
-
- // Populate the form with a credit card value.
- form.fields.back().value = credit_card.number();
-
- // Setup expectation on the test autofill manager (these are validated
- // during the simlulated submit).
- autofill_manager_->SetExpectedSubmittedFieldTypes({{CREDIT_CARD_NUMBER}});
- autofill_manager_->SetExpectedObservedSubmission(true);
- autofill_manager_->SetCallParentUploadFormData(true);
- EXPECT_CALL(*download_manager_,
- StartUploadRequest(_, false, _, std::string(), true, _));
-
- base::HistogramTester histogram_tester;
- FormSubmitted(form);
-
- EXPECT_EQ(FormStructure(form).FormSignatureAsStr(),
- autofill_manager_->GetSubmittedFormSignature());
-
- histogram_tester.ExpectTotalCount("Autofill.FieldPrediction.CreditCard", 0);
-}
-
// Test that is_all_server_suggestions is true if there are only
// full_server_card and masked_server_card on file.
TEST_P(AutofillManagerStructuredProfileTest,
@@ -8990,10 +8877,7 @@ class OnFocusOnFormFieldTest : public AutofillManagerTest,
// Enabled
{},
// Disabled
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload,
- kAutofillRestrictUnownedFieldsToFormlessCheckout});
+ {kAutofillRestrictUnownedFieldsToFormlessCheckout});
}
void TearDown() override {
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index b3d84109576..b9da1edcafb 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -26,11 +26,13 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_external_delegate.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/metrics/address_form_event_logger.h"
#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"
@@ -80,9 +82,6 @@ using ::testing::UnorderedPointwise;
namespace autofill {
-using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
-using features::kAutofillEnforceMinRequiredFieldsForQuery;
-using features::kAutofillEnforceMinRequiredFieldsForUpload;
using mojom::SubmissionSource;
using SyncSigninState = AutofillSyncSigninState;
@@ -357,10 +356,6 @@ class AutofillMetricsTest : public testing::Test {
bool include_masked_server_credit_card,
bool include_full_server_credit_card);
- // Creates a masked server card with a nickname, and adds it to existing
- // credit card list.
- void AddMaskedServerCreditCardWithNickname();
-
void AddMaskedServerCreditCardWithOffer(std::string guid,
std::string offer_reward_amount,
GURL url,
@@ -388,6 +383,7 @@ class AutofillMetricsTest : public testing::Test {
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
std::unique_ptr<AutofillExternalDelegate> external_delegate_;
base::test::ScopedFeatureList scoped_feature_list_;
+ TestPatternProvider test_pattern_provider_;
private:
void CreateTestAutofillProfiles();
@@ -562,13 +558,6 @@ void AutofillMetricsTest::RecreateCreditCards(
personal_data_->Refresh();
}
-void AutofillMetricsTest::AddMaskedServerCreditCardWithNickname() {
- CreditCard masked_server_credit_card =
- test::GetMaskedServerCardWithNickname();
- personal_data_->AddServerCreditCard(masked_server_credit_card);
- personal_data_->Refresh();
-}
-
void AutofillMetricsTest::AddMaskedServerCreditCardWithOffer(
std::string guid,
std::string offer_reward_amount,
@@ -640,53 +629,43 @@ INSTANTIATE_TEST_SUITE_P(AutofillMetricsTest,
// Test that we log quality metrics appropriately.
TEST_F(AutofillMetricsTest, QualityMetrics) {
// Set up our form data.
- 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.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Autofilled", "autofilled", "Elvis Aaron Presley",
- "text", &field);
- field.is_autofilled = true;
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FIRST);
-
- test::CreateTestFormField("Autofill Failed", "autofillfailed",
- "buddy@gmail.com", "text", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_NUMBER);
- server_types.push_back(EMAIL_ADDRESS);
-
- test::CreateTestFormField("Empty", "empty", "", "text", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FIRST);
-
- test::CreateTestFormField("Unknown", "unknown", "garbage", "text", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_NUMBER);
- server_types.push_back(EMAIL_ADDRESS);
-
- test::CreateTestFormField("Select", "select", "USA", "select-one", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(UNKNOWN_TYPE);
- server_types.push_back(NO_SERVER_DATA);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "tel", &field);
- field.is_autofilled = true;
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
+ FormData form =
+ test::GetFormData({.description_for_logging = "QualityMetrics",
+ .fields = {{.label = "Autofilled",
+ .name = "autofilled",
+ .value = "Elvis Aaron Presley",
+ .is_autofilled = true},
+ {.label = "Autofill Failed",
+ .name = "autofillfailed",
+ .value = "buddy@gmail.com",
+ .is_autofilled = false},
+ {.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);
@@ -829,50 +808,31 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
// Test that the ProfileImportStatus logs a no import.
TEST_F(AutofillMetricsTest, ProfileImportStatus_NoImport) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "InvalidState", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "00000000000000000", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "NoACountry", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportStatus_NoImport",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = "Invalid State"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP,
+ .value = "00000000000000000"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY,
+ .value = "NoACountry"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -902,50 +862,28 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_NoImport) {
// Test that the ProfileImportStatus logs a regular import.
TEST_F(AutofillMetricsTest, ProfileImportStatus_RegularImport) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportStatus_RegularImport",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -975,54 +913,40 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_RegularImport) {
// Test that the ProfileImportStatus logs a section union mport.
TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- // Assign a specific section.
- field.autocomplete_attribute = "section-billing locality";
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- // Make the state a different section than the city.
- field.autocomplete_attribute = "section-shipping address-level1";
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportStatus_UnionImport",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY,
+ .value = "New York",
+ .autocomplete_attribute = "section-billing locality"},
+ // Add the last field of the form into a new section.
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = "CA",
+ .autocomplete_attribute = "section-shipping address-level1"}}});
+
+ // Set the heuristic types.
+ std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE};
+
+ // Set the server types.
+ std::vector<ServerFieldType> server_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1034,39 +958,16 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
base::HistogramTester histogram_tester;
std::string histogram = "Autofill.AddressProfileImportStatus";
- // Disable the union import feature.
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
-
- // Simulate form submission.
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
+ // Verify that one profile was imported using the union of the two sections.
histogram_tester.ExpectBucketCount(
histogram,
AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT, 0);
histogram_tester.ExpectBucketCount(
histogram, AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT,
- 1);
- histogram_tester.ExpectBucketCount(
- histogram,
- AutofillMetrics::AddressProfileImportStatusMetric::SECTION_UNION_IMPORT,
0);
-
- // Enable the union import feature.
- scoped_feature_list_.Reset();
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
- // Simulate form submission.
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
-
- histogram_tester.ExpectBucketCount(
- histogram,
- AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT, 0);
- histogram_tester.ExpectBucketCount(
- histogram, AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT,
- 1);
histogram_tester.ExpectBucketCount(
histogram,
AutofillMetrics::AddressProfileImportStatusMetric::SECTION_UNION_IMPORT,
@@ -1077,50 +978,28 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
// 'perfect' profile import.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_AllFulfilled) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportRequirements_AllFulfilled",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1178,49 +1057,28 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_AllFulfilled) {
// ADDRESS_HOME_LINE1 is missing.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_MissingHomeLineOne) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_MissingHomeLineOne",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1280,50 +1138,30 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_MissingHomeLineOne) {
TEST_F(AutofillMetricsTest,
ProfileImportRequirements_AllFulfilledForNonStateCountry) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "Germany", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_AllFulfilledForNonStateCountry",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY,
+ .value = "Germany"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1381,56 +1219,38 @@ TEST_F(AutofillMetricsTest,
TEST_F(AutofillMetricsTest,
ProfileImportRequirements_FilledButInvalidZipEmailAndState) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "DefNotAState", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "1234567890", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
-
- test::CreateTestFormField("Email1", "email1", "test_noat_test.io", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(EMAIL_ADDRESS);
- server_types.push_back(EMAIL_ADDRESS);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_FilledButInvalidZipEmailAndState",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = "DefNotAState"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "1234567890"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"},
+ {.role = ServerFieldType::EMAIL_ADDRESS,
+ .value = "test_noat_test.io"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS};
+ std::vector<ServerFieldType> server_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1488,61 +1308,41 @@ TEST_F(AutofillMetricsTest,
// profile with multiple email addresses.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_NonUniqueEmail) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
-
- test::CreateTestFormField("Email1", "email1", "test@test.io", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(EMAIL_ADDRESS);
- server_types.push_back(EMAIL_ADDRESS);
-
- test::CreateTestFormField("Email2", "email2", "not_test@test.io", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(EMAIL_ADDRESS);
- server_types.push_back(EMAIL_ADDRESS);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportRequirements_NonUniqueEmail",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"},
+ {.role = ServerFieldType::EMAIL_ADDRESS,
+ .value = "test_noat_test.io"},
+ {.label = "Email1",
+ .name = ".email1",
+ .value = "not_test@test.io"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS,
+ EMAIL_ADDRESS};
+ std::vector<ServerFieldType> server_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS,
+ EMAIL_ADDRESS};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1600,50 +1400,29 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_NonUniqueEmail) {
// missing.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_OnlyAddressLineOne) {
// 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");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_OnlyAddressLineOne",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = ""},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = ""}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -3200,92 +2979,6 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Unknown", 0);
}
-// Verify that when a field is annotated with the autocomplete attribute, its
-// predicted type is remembered when quality metrics are logged.
-TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
- // Allow heuristics to run (and be accepted) for small forms.
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
-
- // Set up our form data. Note that the fields have default values not found
- // in the user profiles. They will be changed between the time the form is
- // seen/parsed, and the time it is submitted.
- FormData form;
- FormFieldData field;
- 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.main_frame_origin =
- url::Origin::Create(GURL("http://example_root.com/form.html"));
-
- test::CreateTestFormField("Select", "select", "USA", "select-one", &field);
- form.fields.push_back(field);
- form.fields.back().autocomplete_attribute = "country";
-
- test::CreateTestFormField("Unknown", "Unknown", "", "text", &field);
- form.fields.push_back(field);
-
- test::CreateTestFormField("Phone", "phone", "", "tel", &field);
- form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
-
- base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
-
- // We change the value of the text fields to change the default/seen values
- // (hence the values are not cleared in UpdateFromCache). The new values
- // match what is in the test profile.
- form.fields[1].value = base::ASCIIToUTF16("79401");
- form.fields[2].value = base::ASCIIToUTF16("2345678901");
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
-
- for (const std::string source : {"Heuristic", "Server", "Overall"}) {
- std::string histogram_name =
- "Autofill.FieldPredictionQuality.ByFieldType." + source;
- // First verify that country was not predicted by client or server.
- {
- SCOPED_TRACE("ADDRESS_HOME_COUNTRY");
- histogram_tester.ExpectBucketCount(
- histogram_name,
- GetFieldTypeGroupPredictionQualityMetric(
- ADDRESS_HOME_COUNTRY,
- source == "Overall" ? AutofillMetrics::TRUE_POSITIVE
- : AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
- 1);
- }
-
- // We did not predict zip code because it did not have an autocomplete
- // attribute, nor client or server predictions.
- {
- SCOPED_TRACE("ADDRESS_HOME_ZIP");
- histogram_tester.ExpectBucketCount(
- histogram_name,
- GetFieldTypeGroupPredictionQualityMetric(
- ADDRESS_HOME_ZIP, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
- 1);
- }
-
- // Phone should have been predicted by the heuristics but not the server.
- {
- SCOPED_TRACE("PHONE_HOME_WHOLE_NUMBER");
- histogram_tester.ExpectBucketCount(
- histogram_name,
- GetFieldTypeGroupPredictionQualityMetric(
- PHONE_HOME_WHOLE_NUMBER,
- source == "Server" ? AutofillMetrics::FALSE_NEGATIVE_UNKNOWN
- : AutofillMetrics::TRUE_POSITIVE),
- 1);
- }
-
- // Sanity check.
- histogram_tester.ExpectTotalCount(histogram_name, 3);
- }
-}
-
// Test that we behave sanely when the cached form differs from the submitted
// one.
TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
@@ -3426,8 +3119,6 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
// Verify that when submitting a non-autofillable form, the stored profile
// metric is not logged.
TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForHeuristics);
// Construct a non-fillable form.
FormData form;
form.unique_renderer_id = MakeFormRendererId();
@@ -3729,19 +3420,6 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
histogram_tester.ExpectTotalCount("Autofill.DeveloperEngagement", 0);
}
- // Otherwise, log developer engagement for all forms.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
- autofill_manager_->Reset();
- histogram_tester.ExpectUniqueSample(
- "Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS, 1);
- }
-
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
forms.back().fields.push_back(field);
@@ -3827,9 +3505,6 @@ TEST_F(AutofillMetricsTest,
// Ensure no entries are logged when loading a non-fillable form.
{
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
autofill_manager_->Reset();
@@ -3907,14 +3582,6 @@ TEST_F(AutofillMetricsTest,
// Verify that we correctly log UKM for form parsed with type hints regarding
// developer engagement.
TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload},
- // Disabled.
- {});
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
@@ -3930,27 +3597,11 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
test::CreateTestFormField("Payment", "payment", "", "text", &field);
field.autocomplete_attribute = "upi-vpa";
form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
-
- // Expect the "upi-vpa hint" metric to be logged and the "form loaded" form
- // interaction event to be logged.
- {
- SCOPED_TRACE("VPA is the only hint");
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
-
- VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
- /* UPI VPA has Unknown form type.*/
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE},
- {AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
- PurgeUKM();
- }
-
- // Add another field with an author-specified field type to the form.
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "address-line1";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
{
SCOPED_TRACE("VPA and other autocomplete hint present");
@@ -6665,349 +6316,6 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
}
}
-// Test that we log form events for masked server card nickname.
-// TODO(crbug.com/1059087): Remove histogram logging for server nickname.
-TEST_F(AutofillMetricsTest, LogServerNicknameFormEvents) {
- // 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.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
-
- FormFieldData field;
- std::vector<ServerFieldType> field_types;
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
- test::CreateTestFormField("Year", "card_year", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_NUMBER);
-
- // Creating all kinds of cards. None of them has nicknames.
- RecreateCreditCards(true /* include_local_credit_card */,
- true /* include_masked_server_credit_card */,
- true /* include_full_server_credit_card */);
-
- // Simulate having seen this form on page load.
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- std::string guid("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1);
- // Check that the nickname sub-histogram was not recorded.
- // ExpectBucketCount() can't be used here because it expects the histogram
- // to exist.
- EXPECT_EQ(0, histogram_tester.GetTotalCountsForPrefix(
- "Autofill.FormEvents.CreditCard")
- ["Autofill.FormEvents.CreditCard.WithServerNickname"]);
- }
-
- // Add another masked server card with nickname.
- AddMaskedServerCreditCardWithNickname();
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion. Both general
- // histogram and nickname sub-histogram are logged.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Select the local card, still log to sub-histogram because user has
- // another masked servr card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000001");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- // The general credit card form event historgram is still logged.
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1);
- // Sub-histogratm CreditCard.WithServerNickname is also logged
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown, selecting a masked card server suggestion and
- // submitting the form. Verify that all related form events are correctly
- // logged to nickname sub-histogram.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Select the masked server card without nickname, still log to nickname
- // sub-histogram because user has another masked server card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000002");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- OnDidGetRealPan(AutofillClient::SUCCESS, "6011000990139424");
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_INTERACTED_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 1);
- }
-}
-
-// Test that we log suggestion selection duration for masked server card
-// nickname.
-// TODO(crbug.com/1059087): Remove histogram logging for server nickname.
-TEST_F(AutofillMetricsTest, LogServerNicknameSelectionDuration) {
- base::TimeTicks now = AutofillTickClock::NowTicks();
- TestAutofillTickClock test_clock;
- test_clock.SetNowTicks(now);
-
- // 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.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
-
- FormFieldData field;
- std::vector<ServerFieldType> field_types;
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
- test::CreateTestFormField("Year", "card_year", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_NUMBER);
-
- // Creating all kinds of cards. None of them have nicknames.
- RecreateCreditCards(true /* include_local_credit_card */,
- true /* include_masked_server_credit_card */,
- true /* include_full_server_credit_card */);
-
- // Simulate having seen this form on page load.
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // No masked server card has nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion after 1 second.
- base::TimeDelta selection_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + selection_delta);
- std::string guid("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- // Check that the nickname sub-histogram was not recorded.
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 0);
- }
-
- // Add another masked server card with nickname.
- AddMaskedServerCreditCardWithNickname();
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion after 1 second.
- base::TimeDelta selection_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + selection_delta);
- // Select the local card, log nickname selection duration because user has
- // another masked servr card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000001");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- selection_delta, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and selecting a masked card server suggestion.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion after 1 second.
- base::TimeDelta selection_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + selection_delta);
- // Select the masked server card without nickname, still log select
- // duration, even though GetRealPan fails afterwards, because user has
- // another masked server card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000002");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- OnDidGetRealPan(AutofillClient::PERMANENT_FAILURE, std::string());
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- selection_delta, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating suggestions are shown twice, then choosing a local card.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate the first popup was dismissed and the second popup is shown
- // after 1 second.
- base::TimeDelta suggestion_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + suggestion_delta);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion on the second popup after 2 seconds.
- // The overall selection duration will be 3 seconds, between the first time
- // suggestion was shown and the first card is chosen.
- base::TimeDelta total_selection_delta =
- suggestion_delta + base::TimeDelta::FromSeconds(2);
- test_clock.SetNowTicks(now + total_selection_delta);
- std::string guid("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- total_selection_delta, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating suggestions being shown and selecting masked server card
- // multiple times.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate the first selection happens 1 second after suggestion is shown.
- base::TimeDelta first_suggestion_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + first_suggestion_delta);
- std::string guid1(
- "10000000-0000-0000-0000-000000000002"); // masked server card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid1, std::string()));
- // Simulate choosing another local card 2 seconds after user chooses the
- // server card.
- base::TimeDelta second_selection_delta =
- first_suggestion_delta + base::TimeDelta::FromSeconds(2);
- test_clock.SetNowTicks(now + second_selection_delta);
- std::string guid2("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid2, std::string()));
- // The selection duration should be only logged once.
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- // The logged selection duration should be 1 second, between the suggestion
- // was shown and the first card is chosen.
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- first_suggestion_delta, 1);
- }
-}
-
// Test that we log form events for masked server card with offers.
TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
scoped_feature_list_.InitAndEnableFeature(
@@ -8657,45 +7965,6 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Clear out the third field's value.
form.fields[2].value = base::string16();
forms.front() = form;
-
- // This form is non-fillable if small form support is disabled (min number
- // of fields enforced.)
- {
- base::test::ScopedFeatureList features;
- features.InitWithFeatures(
- // Enabled
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery},
- // Disabled
- {});
- base::HistogramTester histogram_tester;
- base::UserActionTester user_action_tester;
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
- histogram_tester.ExpectUniqueSample(
- "Autofill.FormSubmittedState",
- AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
- EXPECT_EQ(1, user_action_tester.GetActionCount(
- "Autofill_FormSubmitted_NonFillable"));
-
- expected_form_submission_ukm_metrics.push_back(
- {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
- AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
- {UkmFormSubmittedType::kIsForCreditCardName, false},
- {UkmFormSubmittedType::kHasUpiVpaFieldName, false},
- {UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
- {UkmFormSubmittedType::kFormSignatureName,
- Collapse(CalculateFormSignature(form)).value()}});
- VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
- expected_form_submission_ukm_metrics);
-
- AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
- VerifyUkm(test_ukm_recorder_, form, UkmFieldFillStatusType::kEntryName,
- expected_field_fill_status_ukm_metrics);
- }
}
// Verify that we correctly log the submitted form's state with fields
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 267ad01698e..f82bcdf9778 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -48,6 +48,8 @@ VerificationStatus ConvertSpecificsToProfileVerificationStatus(
return VerificationStatus::kObserved;
case sync_pb::AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED:
return VerificationStatus::kUserVerified;
+ case sync_pb::AutofillProfileSpecifics_VerificationStatus_SERVER_PARSED:
+ return VerificationStatus::kServerParsed;
}
}
@@ -67,6 +69,8 @@ ConvertProfileToSpecificsVerificationStatus(VerificationStatus profile_status) {
return sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED;
case (VerificationStatus::kUserVerified):
return sync_pb::AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED;
+ case (VerificationStatus::kServerParsed):
+ return sync_pb::AutofillProfileSpecifics_VerificationStatus_SERVER_PARSED;
}
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.h b/chromium/components/autofill/core/browser/autofill_profile_sync_util.h
index c3078c34aae..a43595262bf 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.h
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.h
@@ -7,8 +7,6 @@
#include <memory>
#include <string>
-// TODO(crbug.com/904390): Remove when the investigation is over.
-#include <vector>
namespace syncer {
struct EntityData;
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.cc b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
index e175fadb0e1..898069ea87f 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_validator.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/check.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/autofill/core/browser/autofill_provider.h b/chromium/components/autofill/core/browser/autofill_provider.h
index 6eae4082e4b..1d9b93d8535 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.h
+++ b/chromium/components/autofill/core/browser/autofill_provider.h
@@ -52,7 +52,8 @@ class AutofillProvider {
bool known_success,
mojom::SubmissionSource source) = 0;
- virtual void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) = 0;
+ virtual void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) = 0;
virtual void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index 97cae9baf26..60997b8bb58 100644
--- a/chromium/components/autofill/core/common/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -6,7 +6,7 @@
// different compilers, we use a script to convert the UTF8 strings into
// numeric literals (\x##).
-#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
namespace autofill {
@@ -31,10 +31,16 @@ const char kCompanyRe[] =
"|شرکت" // fa
"|회사|직장"; // ko-KR
const char kStreetNameRe[] =
- "stra(ss|ß)e" // de
- "|street" // en
- "|rua|avenida"; // br
-const char kHouseNumberRe[] = "(house |^)number|(haus|^)nummer|^número$";
+ "stra(ss|ß)e" // de
+ "|street" // en
+ "|улица|название.?улицы" // ru
+ "|rua|avenida" // pt-PT, pt-BR
+ "|((?<!do |de )endereço)"; // pt-BR
+const char kHouseNumberRe[] =
+ "(house.?|street.?|^)number" // en
+ "|(haus|^)nummer" // de
+ "|^\\*?.?número(.?\\*?$| da residência)" // pt-BR, pt-PT
+ "|дом|номер.?дома"; // ru
const char kAddressLine1Re[] =
"^address$|address[_-]?line(one)?|address1|addr1|street"
"|(?:shipping|billing)address$"
@@ -44,7 +50,7 @@ const char kAddressLine1Re[] =
"|adresse" // fr-FR
"|indirizzo" // it-IT
"|^住所$|住所1" // ja-JP
- "|morada|((?<!identificação do )endereço)" // pt-BR, pt-PT
+ "|morada|((?<!do |de )endereço)" // pt-BR, pt-PT
"|Адрес" // ru
"|地址" // zh-CN
"|(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)" // tr
@@ -121,8 +127,8 @@ const char kCityRe[] =
"|ville|commune" // fr-FR
"|localita" // it-IT
"|市区町村" // ja-JP
- "|cidade" // pt-BR, pt-PT
- "|Город" // ru
+ "|cidade|município" // pt-BR, pt-PT
+ "|Город|Населённый.?пункт" // ru
"|市" // zh-CN
"|分區" // zh-TW
"|شهر" // fa
@@ -241,13 +247,13 @@ const char kExpirationYearRe[] =
// - (optional) Exactly two adjacent m's before the y's.
// - (optional) Separated by white-space and/or a dash or slash.
// - (optional) Prepended with some text similar to "Expiration Date".
-// Tested in components/autofill/core/common/autofill_regexes_unittest.cc
+// Tested in components/autofill/core/browser/autofill_regexes_unittest.cc
const char kExpirationDate2DigitYearRe[] =
"(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)";
// Used to match a expiration date field with a four digit year.
// Same requirements as |kExpirationDate2DigitYearRe| except:
// - Exactly four adjacent y's.
-// Tested in components/autofill/core/common/autofill_regexes_unittest.cc
+// Tested in components/autofill/core/browser/autofill_regexes_unittest.cc
const char kExpirationDate4DigitYearRe[] =
"(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)";
// Used to match expiration date fields that do not specify a year length.
diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.h b/chromium/components/autofill/core/browser/autofill_regex_constants.h
index 407600d571c..de9ef0ecba2 100644
--- a/chromium/components/autofill/core/common/autofill_regex_constants.h
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.h
@@ -2,8 +2,8 @@
// 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_AUTOFILL_REGEX_CONSTANTS_H_
-#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
namespace autofill {
@@ -96,4 +96,4 @@ extern const char kUrlSearchActionRe[];
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/chromium/components/autofill/core/common/autofill_regexes.cc b/chromium/components/autofill/core/browser/autofill_regexes.cc
index 02254fa266a..4875a113f8b 100644
--- a/chromium/components/autofill/core/common/autofill_regexes.cc
+++ b/chromium/components/autofill/core/browser/autofill_regexes.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill/core/common/autofill_regexes.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include <memory>
#include <unordered_map>
@@ -43,7 +43,7 @@ class AutofillRegexes {
icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) {
auto it = matchers_.find(pattern);
if (it == matchers_.end()) {
- const icu::UnicodeString icu_pattern(FALSE, pattern.data(),
+ const icu::UnicodeString icu_pattern(false, pattern.data(),
pattern.length());
UErrorCode status = U_ZERO_ERROR;
@@ -71,21 +71,21 @@ bool MatchesPattern(const base::string16& input,
base::AutoLock lock(*g_lock);
icu::RegexMatcher* matcher = g_autofill_regexes->GetMatcher(pattern);
- icu::UnicodeString icu_input(FALSE, input.data(), input.length());
+ icu::UnicodeString icu_input(false, input.data(), input.length());
matcher->reset(icu_input);
UErrorCode status = U_ZERO_ERROR;
UBool matched = matcher->find(0, status);
DCHECK(U_SUCCESS(status));
- if (matched == TRUE && match) {
+ if (matched && match) {
icu::UnicodeString match_unicode =
matcher->group(group_to_be_captured, status);
DCHECK(U_SUCCESS(status));
*match = base::i18n::UnicodeStringToString16(match_unicode);
}
- return matched == TRUE;
+ return matched;
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_regexes.h b/chromium/components/autofill/core/browser/autofill_regexes.h
index 837130b582c..585e88e20b6 100644
--- a/chromium/components/autofill/core/common/autofill_regexes.h
+++ b/chromium/components/autofill/core/browser/autofill_regexes.h
@@ -2,8 +2,8 @@
// 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_AUTOFILL_REGEXES_H_
-#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
#include "base/strings/string16.h"
@@ -20,4 +20,4 @@ bool MatchesPattern(const base::string16& input,
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
diff --git a/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc b/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc
new file mode 100644
index 00000000000..2adddede044
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc
@@ -0,0 +1,232 @@
+// Copyright 2013 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_regexes.h"
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+namespace autofill {
+
+struct InputPatternTestCase {
+ const char* const input;
+ const char* const pattern;
+};
+
+class PositiveSampleTest : public testing::TestWithParam<InputPatternTestCase> {
+};
+
+TEST_P(PositiveSampleTest, SampleRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(test_case.pattern);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),
+ ASCIIToUTF16(test_case.pattern)));
+}
+
+INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+ PositiveSampleTest,
+ testing::Values(
+ // Empty pattern
+ InputPatternTestCase{"", ""},
+ InputPatternTestCase{
+ "Look, ma' -- a non-empty string!", ""},
+ // Substring
+ InputPatternTestCase{"string", "tri"},
+ // Substring at beginning
+ InputPatternTestCase{"string", "str"},
+ InputPatternTestCase{"string", "^str"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring"},
+ InputPatternTestCase{"string", "ring$"},
+ // Case-insensitive
+ InputPatternTestCase{"StRiNg", "string"}));
+
+class NegativeSampleTest : public testing::TestWithParam<InputPatternTestCase> {
+};
+
+TEST_P(NegativeSampleTest, SampleRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(test_case.pattern);
+ EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input),
+ ASCIIToUTF16(test_case.pattern)));
+}
+
+INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+ NegativeSampleTest,
+ testing::Values(
+ // Empty string
+ InputPatternTestCase{
+ "", "Look, ma' -- a non-empty pattern!"},
+ // Substring
+ InputPatternTestCase{"string", "trn"},
+ // Substring at beginning
+ InputPatternTestCase{"string", " str"},
+ InputPatternTestCase{"string", "^tri"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring "},
+ InputPatternTestCase{"string", "rin$"}));
+
+struct InputTestCase {
+ const char* const input;
+};
+
+class ExpirationDate2DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearPositive,
+ testing::Values(InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
+class ExpirationDate2DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+ EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+class ExpirationDate4DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
+ SCOPED_TRACE(test_case.input);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+ ExpirationDate4DigitYearPositive,
+ testing::Values(
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+class ExpirationDate4DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
+ SCOPED_TRACE(test_case.input);
+ EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillRegexes,
+ ExpirationDate4DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple two year cases
+ InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/address.cc b/chromium/components/autofill/core/browser/data_model/address.cc
index cd7f8e6dd57..284283981ee 100644
--- a/chromium/components/autofill/core/browser/data_model/address.cc
+++ b/chromium/components/autofill/core/browser/data_model/address.cc
@@ -65,7 +65,17 @@ bool Address::FinalizeAfterImport(bool profile_is_verified) {
// fully launched.
if (structured_address::StructuredAddressesEnabled()) {
structured_address_.MigrateLegacyStructure(profile_is_verified);
- return structured_address_.CompleteFullTree();
+ bool result = structured_address_.CompleteFullTree();
+ // If the address could not be completed, it is possible that it contains an
+ // invalid structure.
+ if (!result) {
+ if (structured_address_.WipeInvalidStructure()) {
+ // If the structure was wiped because it is invalid, try to complete the
+ // address again.
+ result = structured_address_.CompleteFullTree();
+ }
+ }
+ return result;
}
return true;
}
@@ -158,6 +168,22 @@ void Address::SetRawInfoWithVerificationStatus(ServerFieldType type,
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled()) {
+ // The street address has a structure that may have already been set before
+ // using the settings dialog. In case the settings dialog was used to change
+ // the address to contain different tokens, the structure must be reset.
+ if (type == ADDRESS_HOME_STREET_ADDRESS) {
+ const base::string16 current_value =
+ structured_address_.GetValueForType(type);
+ if (!current_value.empty()) {
+ bool token_equivalent = structured_address::AreStringTokenEquivalent(
+ value, structured_address_.GetValueForType(type));
+ structured_address_.SetValueForTypeIfPossible(
+ ADDRESS_HOME_STREET_ADDRESS, value, status,
+ /*invalidate_child_nodes=*/!token_equivalent);
+ return;
+ }
+ }
+
structured_address_.SetValueForTypeIfPossible(type, value, status);
return;
}
@@ -366,21 +392,17 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
std::string country_code = base::ToUpperASCII(base::UTF16ToASCII(value));
if (!data_util::IsValidCountryCode(country_code)) {
- // Some popular websites use the HTML_TYPE_COUNTRY_CODE attribute for
- // full text names (e.g. alliedelec.com). Try to convert the value to a
- // country code as a fallback.
- if (base::FeatureList::IsEnabled(
- features::kAutofillAllowHtmlTypeCountryCodesWithFullNames)) {
- CountryNames* country_names =
- !value.empty() ? CountryNames::GetInstance() : nullptr;
- country_code =
- country_names
- ? country_names->GetCountryCodeForLocalizedCountryName(value,
- locale)
- : std::string();
- } else {
- country_code = std::string();
- }
+ // To counteract the misuse of autocomplete=country attribute when used
+ // with full country names, if the supplied country code is not a valid,
+ // it is tested if a country code can be derived from the value when it is
+ // interpreted as a full country name. Otherwise an empty string is
+ // assigned to |country_code|.
+ CountryNames* country_names =
+ !value.empty() ? CountryNames::GetInstance() : nullptr;
+ country_code = country_names
+ ? country_names->GetCountryCodeForLocalizedCountryName(
+ value, locale)
+ : std::string();
}
// TODO(crbug.com/1130194): Clean legacy implementation once structured
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 8a3f79fe3da..ee3aed0d76c 100644
--- a/chromium/components/autofill/core/browser/data_model/address_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/address_unittest.cc
@@ -84,12 +84,6 @@ TEST_P(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
- // Enable the feature that allows for full country names although the
- // field type explicitly set to HTML_TYPE_COUNTRY_CODE.
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(
- features::kAutofillAllowHtmlTypeCountryCodesWithFullNames);
-
// Create an autofill type from HTML_TYPE_COUNTRY_CODE.
AutofillType autofill_type(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE);
@@ -131,18 +125,6 @@ TEST_P(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
AutofillType(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE), "en-US");
EXPECT_EQ(ASCIIToUTF16("DE"), actual_country_code);
EXPECT_EQ(ASCIIToUTF16("Germany"), actual_country);
-
- // By disabling the feature, test that the country name deduction actually
- // uses the path for HTML_TYPE_COUNTRY_CODE.
- feature.Reset();
- feature.InitAndDisableFeature(
- features::kAutofillAllowHtmlTypeCountryCodesWithFullNames);
- address.SetInfo(autofill_type, ASCIIToUTF16("Germany"), "en-US");
- actual_country = address.GetInfo(AutofillType(ADDRESS_HOME_COUNTRY), "en-US");
- actual_country_code = address.GetInfo(
- AutofillType(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE), "en-US");
- EXPECT_EQ(ASCIIToUTF16(""), actual_country);
- EXPECT_EQ(ASCIIToUTF16(""), actual_country_code);
}
// Test that we properly detect country codes appropriate for each country.
@@ -687,6 +669,71 @@ TEST_P(AddressTest, TestGettingTheStructuredAddress) {
base::UTF8ToUTF16("12345"));
}
+// For structured address, test that the structured information is wiped
+// correctly when the unstructured street address changes.
+TEST_P(AddressTest, ResetStructuredTokens) {
+ // This test is only applicable for structured addresses.
+ if (!StructuredAddresses())
+ return;
+
+ Address address;
+ // Set a structured address line and call the finalization routine.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Erika-Mann-Str 12"),
+ structured_address::VerificationStatus::kUserVerified);
+ address.FinalizeAfterImport();
+
+ // Verify that structured tokens have been assigned correctly.
+ EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16("Erika-Mann-Str"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kParsed);
+ ASSERT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16("12"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kParsed);
+
+ // Lift the verification status of the house number to be |kObserved|.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("12"),
+ structured_address::VerificationStatus::kObserved);
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kObserved);
+
+ // Now, set a new unstructured street address that has the same tokens in a
+ // different order.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("12 Erika-Mann-Str"),
+ structured_address::VerificationStatus::kUserVerified);
+
+ // After this operation, the structure should be maintained including the
+ // observed status of the house number.
+ EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16("Erika-Mann-Str"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kParsed);
+ ASSERT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16("12"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kObserved);
+
+ // Now set a different street address.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Marienplatz"),
+ structured_address::VerificationStatus::kUserVerified);
+
+ // The set address is not parsable and the this should unset both the street
+ // name and the house number.
+ EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16(""));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kNoStatus);
+ ASSERT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16(""));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kNoStatus);
+}
+
// Runs the suite with the feature
// |kAutofillSupportForStructuredStructuredNames| enabled and disabled.
// TODO(crbug.com/1130194): Remove parameterized test once structured addresses
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 daf20027c29..7da13d15f85 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
@@ -72,8 +72,8 @@ double AutofillDataModel::GetFrecencyScore(base::Time time) const {
// of the profile and leveraging the properties of the logarithmic function.
// DaysSinceLastUse() and |use_count_| are offset because their minimum values
// are respectively 0 and 1 but the formula requires at least a value of 2.
- // Please update getFrecencyScore in PaymentRequestImpl.java as well if below
- // formula needs update.
+ // Please update getFrecencyScore in ChromePaymentRequestService.java as well
+ // if below formula needs update.
return -log((time - use_date_).InDays() + 2) / log(use_count_ + 1);
}
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 94e43c09ffa..e9668df416b 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -449,15 +449,20 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const {
for (ServerFieldType type : types) {
int comparison = GetRawInfo(type).compare(profile.GetRawInfo(type));
- if (comparison != 0)
+ if (comparison != 0) {
return comparison;
+ }
}
for (ServerFieldType type : types) {
- if (GetVerificationStatus(type) < profile.GetVerificationStatus(type))
+ if (structured_address::IsLessSignificantVerificationStatus(
+ GetVerificationStatus(type), profile.GetVerificationStatus(type))) {
return -1;
- if (GetVerificationStatus(type) > profile.GetVerificationStatus(type))
+ }
+ if (structured_address::IsLessSignificantVerificationStatus(
+ profile.GetVerificationStatus(type), GetVerificationStatus(type))) {
return 1;
+ }
}
// TODO(crbug.com/1130194): Remove feature check once structured addresses are
@@ -474,15 +479,22 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const {
};
for (ServerFieldType type : new_types) {
int comparison = GetRawInfo(type).compare(profile.GetRawInfo(type));
- if (comparison != 0)
+ if (comparison != 0) {
return comparison;
+ }
}
- for (ServerFieldType type : new_types) {
- if (GetVerificationStatus(type) < profile.GetVerificationStatus(type))
+ for (ServerFieldType type : types) {
+ if (structured_address::IsLessSignificantVerificationStatus(
+ GetVerificationStatus(type),
+ profile.GetVerificationStatus(type))) {
return -1;
- if (GetVerificationStatus(type) > profile.GetVerificationStatus(type))
+ }
+ if (structured_address::IsLessSignificantVerificationStatus(
+ profile.GetVerificationStatus(type),
+ GetVerificationStatus(type))) {
return 1;
+ }
}
}
@@ -637,35 +649,47 @@ bool AutofillProfile::MergeStructuredDataFrom(const AutofillProfile& profile,
// Should only be called if the profile is already verified.
DCHECK(IsVerified());
- // Only applicable for structured names.
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames)) {
- return false;
- }
-
AutofillProfileComparator comparator(app_locale);
- NameInfo name;
+
DVLOG(1) << "Merging profile structure information :\nSource = " << profile
<< "\nDest = " << *this;
- // It is already verified upstream that the profiles and therefore also the
- // names are mergeable.
- // However, the structure should only be merged if the full names are token
- // equivalent.
- if (!structured_address::AreStringTokenEquivalent(
- GetRawInfo(NAME_FULL), profile.GetRawInfo(NAME_FULL)))
- return false;
+ bool merged = false;
- if (!comparator.MergeNames(profile, *this, &name)) {
- NOTREACHED();
- return false;
+ // It is already verified upstream that the profiles and therefore also the
+ // names and addresses are mergeable.
+ // However, the structure should only be merged if the full names or addresses
+ // are token equivalent.
+ if (structured_address::StructuredNamesEnabled() &&
+ structured_address::AreStringTokenEquivalent(
+ GetRawInfo(NAME_FULL), profile.GetRawInfo(NAME_FULL))) {
+ NameInfo name;
+ if (!comparator.MergeNames(profile, *this, &name)) {
+ NOTREACHED();
+ return false;
+ }
+ if (name_ != name) {
+ name_ = name;
+ merged = true;
+ }
}
- if (name_ != name) {
- name_ = name;
- return true;
+ if (structured_address::StructuredAddressesEnabled() &&
+ structured_address::AreStringTokenEquivalent(
+ GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
+ profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS))) {
+ Address address;
+ if (!comparator.MergeAddresses(profile, *this, &address)) {
+ NOTREACHED();
+ return false;
+ }
+ if (address_ != address) {
+ address_ = address;
+ merged = true;
+ }
}
- return false;
+
+ return merged;
}
bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile,
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 9c39c693e56..e24375a36eb 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
@@ -122,7 +122,7 @@ NormalizingIterator::NormalizingIterator(
: previous_was_skippable_(false),
collapse_skippable_(whitespace_spec ==
AutofillProfileComparator::RETAIN_WHITESPACE),
- iter_(base::i18n::UTF16CharIterator(text.data(), text.length())) {
+ iter_(text) {
int32_t character = iter_.get();
while (!iter_.end() && IsPunctuationOrWhitespace(u_charType(character))) {
@@ -282,8 +282,7 @@ base::string16 AutofillProfileComparator::NormalizeForComparison(
base::string16 result;
result.reserve(text.length());
bool previous_was_whitespace = (whitespace_spec == RETAIN_WHITESPACE);
- for (base::i18n::UTF16CharIterator iter(text.data(), text.length());
- !iter.end(); iter.Advance()) {
+ for (base::i18n::UTF16CharIterator iter(text); !iter.end(); iter.Advance()) {
if (IsPunctuationOrWhitespace(u_charType(iter.get()))) {
if (!previous_was_whitespace && whitespace_spec == RETAIN_WHITESPACE) {
result.push_back(' ');
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 c745377720b..b5fa1ea03e3 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
@@ -4,7 +4,6 @@
#include "components/autofill/core/browser/data_model/autofill_structured_address.h"
-#include <iostream>
#include <utility>
#include "base/i18n/case_conversion.h"
#include "base/strings/strcat.h"
@@ -136,7 +135,8 @@ void StreetAddress::ParseValueAndAssignSubcomponentsByFallbackMethod() {
bool StreetAddress::HasNewerValuePrecendenceInMerging(
const AddressComponent& newer_component) const {
// If the newer component has a better verification status, use the newer one.
- if (GetVerificationStatus() < newer_component.GetVerificationStatus())
+ if (IsLessSignificantVerificationStatus(
+ GetVerificationStatus(), newer_component.GetVerificationStatus()))
return true;
// If the verification statuses are the same, do not use the newer component
@@ -353,6 +353,13 @@ Address::Address(const Address& other) : Address() {
*this = 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();
+}
+
// Addresses are mergeable when all of their children are mergeable.
// Reformat the address from their children after merge.
Address::Address(AddressComponent* parent)
@@ -367,7 +374,6 @@ Address::~Address() = default;
void Address::MigrateLegacyStructure(bool is_verified_profile) {
// If this component already has a verification status, no profile is regarded
// as already verified.
- std::cout << "APply migration" << std::endl;
if (GetVerificationStatus() != VerificationStatus::kNoStatus)
return;
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 1e2c0201dbd..7e872bfc114 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
@@ -226,6 +226,10 @@ class Address : public AddressComponent {
// a status.
void MigrateLegacyStructure(bool is_verified_profile);
+ // Checks if the street address contains an invalid structure and wipes it if
+ // necessary.
+ bool WipeInvalidStructure() override;
+
private:
StreetAddress street_address_{this};
PostalCode postal_code_{this};
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 fccb0bd9725..50e6e86f2d2 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
@@ -27,6 +27,28 @@ namespace autofill {
namespace structured_address {
+bool IsLessSignificantVerificationStatus(VerificationStatus left,
+ VerificationStatus right) {
+ // Both the KUserVerified and kObserved are larger then kServerParsed although
+ // the underlying integer suggests differently.
+ if (left == VerificationStatus::kServerParsed &&
+ (right == VerificationStatus::kObserved ||
+ right == VerificationStatus::kUserVerified)) {
+ return true;
+ }
+
+ if (right == VerificationStatus::kServerParsed &&
+ (left == VerificationStatus::kObserved ||
+ left == VerificationStatus::kUserVerified)) {
+ return false;
+ }
+
+ // In all other cases, it is sufficient to compare the underlying integer
+ // values.
+ return static_cast<std::underlying_type_t<VerificationStatus>>(left) <
+ static_cast<std::underlying_type_t<VerificationStatus>>(right);
+}
+
AddressComponent::AddressComponent(ServerFieldType storage_type,
AddressComponent* parent,
std::vector<AddressComponent*> subcomponents,
@@ -482,6 +504,27 @@ void AddressComponent::ParseValueAndAssignSubcomponentsByFallbackMethod() {
DCHECK(success);
}
+bool AddressComponent::WipeInvalidStructure() {
+ if (IsAtomic()) {
+ return false;
+ }
+
+ // 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 false;
+}
+
void AddressComponent::FormatValueFromSubcomponents() {
// Get the most suited format string.
base::string16 format_string = GetBestFormatString();
@@ -697,7 +740,7 @@ void AddressComponent::UnsetParsedAndFormattedValuesInEntireTree() {
void AddressComponent::MergeVerificationStatuses(
const AddressComponent& newer_component) {
if (IsValueAssigned() && (GetValue() == newer_component.GetValue()) &&
- (GetVerificationStatus() < newer_component.GetVerificationStatus())) {
+ HasNewerValuePrecendenceInMerging(newer_component)) {
value_verification_status_ = newer_component.GetVerificationStatus();
}
@@ -807,7 +850,7 @@ bool AddressComponent::MergeWithComponent(
// If the normalized values are the same, optimize the verification status.
if ((merge_mode_ & kUseBetterOrNewerForSameValue) && (value == value_newer)) {
- if (newer_component.GetVerificationStatus() >= GetVerificationStatus()) {
+ if (HasNewerValuePrecendenceInMerging(newer_component)) {
*this = newer_component;
}
return true;
@@ -900,7 +943,8 @@ bool AddressComponent::MergeWithComponent(
bool AddressComponent::HasNewerValuePrecendenceInMerging(
const AddressComponent& newer_component) const {
- return newer_component.GetVerificationStatus() >= GetVerificationStatus();
+ return !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus());
}
bool AddressComponent::MergeTokenEquivalentComponent(
@@ -1109,6 +1153,7 @@ int AddressComponent::GetStructureVerificationScore() const {
case VerificationStatus::kNoStatus:
case VerificationStatus::kParsed:
case VerificationStatus::kFormatted:
+ case VerificationStatus::kServerParsed:
break;
case VerificationStatus::kObserved:
result += 1;
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 9cfc4d1c310..7adba19a86e 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
@@ -37,8 +37,15 @@ enum class VerificationStatus {
kObserved = 3,
// The user used the autofill settings to verify and store this token.
kUserVerified = 4,
+ // The token was parsed by the server.
+ kServerParsed = 5,
};
+// Returns true if |left| has a less significant verification status compared to
+// |right|.
+bool IsLessSignificantVerificationStatus(VerificationStatus left,
+ VerificationStatus right);
+
// The merge mode defines if and how two components are merged.
enum MergeMode {
// If one component has an empty value, use the non-empty one.
@@ -57,8 +64,7 @@ enum MergeMode {
kUseNewerIfDifferent = 1 << 5,
// If the newer component contains one token more, apply a recursive strategy
// to merge the tokens.
- kRecursivelyMergeSingleTokenSubset =
- 1 << 6 | kRecursivelyMergeTokenEquivalentValues,
+ kRecursivelyMergeSingleTokenSubset = 1 << 6,
// If one is a substring use the most recent one.
kUseMostRecentSubstring = 1 << 7,
// Merge the child nodes and reformat the node from its children after merge.
@@ -335,6 +341,11 @@ 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.
+ virtual bool WipeInvalidStructure();
+
#ifdef UNIT_TEST
// Initiates the formatting of the values from the subcomponents.
void FormatValueFromSubcomponentsForTesting() {
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 2a4a7fd1c8f..a9356b83cd8 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
@@ -1661,5 +1661,26 @@ TEST(AutofillStructuredAddressAddressComponent, MergeChildsAndReformatRoot) {
VerifyTestValues(&older, older_values);
}
+// Test the comparison of different Verification statuses.
+TEST(AutofillStructuredAddressAddressComponent,
+ TestIsLessSignificantVerificationStatus) {
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kParsed, VerificationStatus::kFormatted));
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kParsed, VerificationStatus::kServerParsed));
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kObserved));
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kUserVerified));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kFormatted));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kParsed));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kObserved, VerificationStatus::kServerParsed));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kUserVerified, VerificationStatus::kServerParsed));
+}
+
} // 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 ed1ffa76558..ea5ba89c845 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
@@ -11,7 +11,6 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/common/autofill_features.h"
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 07f58617c0e..ba400f32f08 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
@@ -267,11 +267,12 @@ std::string ParseFirstMiddleLastNameExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
{CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_FIRST, kSingleWordRe,
- {.quantifier = MATCH_OPTIONAL}),
- CaptureTypeWithPattern(NAME_MIDDLE, kMultipleLazyWordsRe,
- {.quantifier = MATCH_LAZY_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(
+ NAME_MIDDLE, kMultipleLazyWordsRe,
+ CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST,
{kOptionalLastNamePrefixRe, kSingleWordRe}),
kOptionalLastNameSuffixRe});
@@ -288,14 +289,15 @@ std::string ParseLastCommaFirstMiddleExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
{CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST,
{kOptionalLastNamePrefixRe, kSingleWordRe},
{.separator = "\\s*,\\s*"}),
CaptureTypeWithPattern(NAME_FIRST, kSingleWordRe,
- {.quantifier = MATCH_OPTIONAL}),
- CaptureTypeWithPattern(NAME_MIDDLE, kMultipleLazyWordsRe,
- {.quantifier = MATCH_LAZY_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(
+ NAME_MIDDLE, kMultipleLazyWordsRe,
+ CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL})});
}
// Returns an expression to parse an Hispanic/Latinx last name.
@@ -313,7 +315,7 @@ std::string ParseHispanicLastNameExpression() {
{kOptionalLastNamePrefixRe, kSingleWordRe}),
CaptureTypeWithPattern(NAME_LAST_CONJUNCTION,
kHispanicLastNameConjunctionsRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST_SECOND,
{kOptionalLastNamePrefixRe, kSingleWordRe})});
}
@@ -325,9 +327,10 @@ std::string ParseHispanicFullNameExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
{CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- {.quantifier = MATCH_OPTIONAL}),
- CaptureTypeWithPattern(NAME_FIRST, kMultipleLazyWordsRe,
- {.quantifier = MATCH_LAZY_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(
+ NAME_FIRST, kMultipleLazyWordsRe,
+ CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL}),
ParseHispanicLastNameExpression()});
}
@@ -358,14 +361,15 @@ std::string ParseStreetNameHouseNumberExpression() {
CaptureTypeWithPattern(
ADDRESS_HOME_SUBPREMISE,
{
- CaptureTypeWithPrefixedPattern(ADDRESS_HOME_FLOOR, kFloorAffixRe,
- "(?:(\\d{0,3}\\w?))",
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPrefixedPattern(
+ ADDRESS_HOME_FLOOR, kFloorAffixRe, "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))", {.quantifier = MATCH_OPTIONAL}),
+ "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
- {.quantifier = MATCH_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
// Returns an expression to parse a street address into the street name, the
@@ -392,12 +396,13 @@ std::string ParseStreetNameHouseNumberExpressionSuffixedFloor() {
{
CaptureTypeWithSuffixedPattern(
ADDRESS_HOME_FLOOR, "(?:(\\d{0,3}\\w?))", kFloorAffixRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))", {.quantifier = MATCH_OPTIONAL}),
+ "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
- {.quantifier = MATCH_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
// Returns an expression to parse a street address into the street name, the
@@ -417,14 +422,15 @@ std::string ParseHouseNumberStreetNameExpression() {
CaptureTypeWithPattern(
ADDRESS_HOME_SUBPREMISE,
{
- CaptureTypeWithPrefixedPattern(ADDRESS_HOME_FLOOR, kFloorAffixRe,
- "(?:(\\d{0,3}\\w?))",
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPrefixedPattern(
+ ADDRESS_HOME_FLOOR, kFloorAffixRe, "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))", {.quantifier = MATCH_OPTIONAL}),
+ "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
- {.quantifier = MATCH_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
} // namespace
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 1a8bf503d31..c00710a40d4 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
@@ -12,7 +12,6 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -482,6 +481,67 @@ TEST(AutofillStructuredAddress, TestMigrationAndFinalization_AlreadyMigrated) {
// Verify that the address was not changed by the migration.
VerifyTestValues(&address, test_values);
}
+
+// Tests that a valid address structure is not wiped.
+TEST(AutofillStructuredAddress,
+ TestWipingAnInvalidSubstructure_ValidStructure) {
+ Address address;
+ AddressComponentTestValues address_with_valid_structure = {
+ // This structure is valid because all structured components are contained
+ // in the unstructured representation.
+ {.type = ADDRESS_HOME_STREET_ADDRESS,
+ .value = "123 Street name",
+ .status = VerificationStatus::kObserved},
+ {.type = ADDRESS_HOME_STREET_NAME,
+ .value = "Street name",
+ .status = VerificationStatus::kParsed},
+ {.type = ADDRESS_HOME_HOUSE_NUMBER,
+ .value = "123",
+ .status = VerificationStatus::kParsed},
+ };
+
+ SetTestValues(&address, address_with_valid_structure, /*finalize=*/false);
+
+ EXPECT_FALSE(address.WipeInvalidStructure());
+ VerifyTestValues(&address, address_with_valid_structure);
+}
+
+// Tests that an invalid address structure is wiped.
+TEST(AutofillStructuredAddress,
+ TestWipingAnInvalidSubstructure_InValidStructure) {
+ Address address;
+ AddressComponentTestValues address_with_valid_structure = {
+ {.type = ADDRESS_HOME_STREET_ADDRESS,
+ .value = "Some other name",
+ .status = VerificationStatus::kObserved},
+ {.type = ADDRESS_HOME_STREET_NAME,
+ .value = "Street name",
+ .status = VerificationStatus::kParsed},
+ // The structure is invalid, because the house number is not contained in
+ // the unstructured street address.
+ {.type = ADDRESS_HOME_HOUSE_NUMBER,
+ .value = "123",
+ .status = VerificationStatus::kParsed},
+ };
+
+ SetTestValues(&address, address_with_valid_structure, /*finalize=*/false);
+
+ EXPECT_TRUE(address.WipeInvalidStructure());
+
+ AddressComponentTestValues address_with_wiped_structure = {
+ {.type = ADDRESS_HOME_STREET_ADDRESS,
+ .value = "Some other name",
+ .status = VerificationStatus::kObserved},
+ {.type = ADDRESS_HOME_STREET_NAME,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ {.type = ADDRESS_HOME_HOUSE_NUMBER,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ };
+ VerifyTestValues(&address, address_with_wiped_structure);
+}
+
} // namespace
} // namespace structured_address
} // namespace autofill
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 8464c16d6a7..bd31bdcaa3a 100644
--- a/chromium/components/autofill/core/browser/data_model/contact_info.cc
+++ b/chromium/components/autofill/core/browser/data_model/contact_info.cc
@@ -14,12 +14,12 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_regexes.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"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_l10n_util.h"
-#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
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 022464200ad..484b13711c5 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc
@@ -27,6 +27,7 @@
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_metadata.h"
#include "components/autofill/core/browser/data_model/data_model_utils.h"
@@ -35,7 +36,6 @@
#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_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
diff --git a/chromium/components/autofill/core/browser/data_model/data_model_utils.cc b/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
index 518d6a7949d..023b70402cc 100644
--- a/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
+++ b/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
@@ -11,9 +11,9 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "third_party/icu/source/common/unicode/uloc.h"
#include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index 203fbe516ab..37c6daaa7a4 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -19,6 +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/autofill_client.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_type.h"
@@ -102,16 +103,13 @@ bool IsMinimumAddress(const AutofillProfile& profile,
<< "Country entry in form." << CTag{};
}
- if (base::FeatureList::IsEnabled(
- features::kAutofillUseVariationCountryCode)) {
- // As a fallback, use the finch state to get a country code.
- if (country_code.empty() && !variation_country_code.empty()) {
- country_code = variation_country_code;
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormCountrySource
- << "Variations service." << CTag{};
- }
+ // As a fallback, use the finch state to get a country code.
+ if (country_code.empty() && !variation_country_code.empty()) {
+ country_code = variation_country_code;
+ if (import_log_buffer && !country_code.empty()) {
+ *import_log_buffer
+ << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "Variations service." << CTag{};
}
}
@@ -230,6 +228,8 @@ FormDataImporter::FormDataImporter(AutofillClient* client,
payments_client,
app_locale,
personal_data_manager)),
+ address_profile_save_manager_(
+ std::make_unique<AddressProfileSaveManager>(personal_data_manager)),
#if !defined(OS_ANDROID) && !defined(OS_IOS)
local_card_migration_manager_(
std::make_unique<LocalCardMigrationManager>(client,
@@ -470,15 +470,12 @@ bool FormDataImporter::ImportAddressProfiles(const FormStructure& form) {
// And close the div of the section import log.
import_log_buffer << CTag{"div"};
}
- // TODO(crbug.com/1097125): Remove feature test.
// 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) {
AutofillMetrics::LogAddressFormImportStatustMetric(
AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT);
- } else if (base::FeatureList::IsEnabled(
- features::kAutofillProfileImportFromUnifiedSection) &&
- sections.size() > 1) {
+ } else if (sections.size() > 1) {
// Try to import by combining all sections.
if (ImportAddressProfileForSection(form, "", &import_log_buffer)) {
num_saved_profiles++;
@@ -542,14 +539,8 @@ 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, 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())
+ // information into the field, then skip it.
+ if (!field->IsFieldFillable() || value.empty())
continue;
AutofillType field_type = field->Type();
@@ -591,24 +582,20 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Reject profiles with invalid country information.
if (server_field_type == ADDRESS_HOME_COUNTRY &&
candidate_profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty()) {
- // TODO(crbug.com/1075604): Remove branch with disabled feature.
- if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToTranslateCountryNames)) {
- // The country code was not successfully determined from the value in
- // the country field. This can be caused by a localization that does not
- // match the |app_locale|. Try setting the value again using the
- // language of the page. Note, there should be a locale associated with
- // every language code.
- std::string page_language;
- const translate::LanguageState* language_state =
- client_->GetLanguageState();
- if (language_state)
- page_language = language_state->original_language();
- // Retry to set the country of there is known page language.
- if (!page_language.empty()) {
- candidate_profile.SetInfoWithVerificationStatus(
- field_type, value, page_language, VerificationStatus::kObserved);
- }
+ // The country code was not successfully determined from the value in
+ // the country field. This can be caused by a localization that does not
+ // match the |app_locale|. Try setting the value again using the
+ // language of the page. Note, there should be a locale associated with
+ // every language code.
+ std::string page_language;
+ const translate::LanguageState* language_state =
+ client_->GetLanguageState();
+ if (language_state)
+ page_language = language_state->original_language();
+ // Retry to set the country of there is known page language.
+ if (!page_language.empty()) {
+ candidate_profile.SetInfoWithVerificationStatus(
+ field_type, value, page_language, VerificationStatus::kObserved);
}
// Check if the country code was still not determined correctly.
if (candidate_profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty()) {
@@ -687,7 +674,7 @@ bool FormDataImporter::ImportAddressProfileForSection(
return false;
std::string guid =
- personal_data_manager_->SaveImportedProfile(candidate_profile);
+ address_profile_save_manager_->SaveProfile(candidate_profile);
return !guid.empty();
}
diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h
index 38d0b12fd9a..4ef28d575a6 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.h
+++ b/chromium/components/autofill/core/browser/form_data_importer.h
@@ -24,6 +24,8 @@ class SaveCardOfferObserver;
namespace autofill {
+class AddressProfileSaveManager;
+
// Manages logic for importing address profiles and credit card information from
// web forms into the user's Autofill profile via the PersonalDataManager.
// Owned by AutofillManager.
@@ -151,6 +153,9 @@ class FormDataImporter {
// Responsible for managing credit card save flows (local or upload).
std::unique_ptr<CreditCardSaveManager> credit_card_save_manager_;
+ // Responsible for managing address profiles save flows.
+ std::unique_ptr<AddressProfileSaveManager> address_profile_save_manager_;
+
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Responsible for migrating locally saved credit cards to Google Pay.
std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager_;
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 31e772c644a..b15cee9ccae 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -14,7 +14,7 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/guid.h"
@@ -29,8 +29,10 @@
#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_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"
@@ -230,6 +232,7 @@ 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
@@ -580,18 +583,6 @@ TEST_P(FormDataImporterTest, ImportAddressProfileFromUnifiedSection) {
// Assign the address field another section than the other fields.
form_structure.field(3)->section = "another_section";
- base::test::ScopedFeatureList scoped_feature;
- scoped_feature.InitAndDisableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
-
- // Without the feature, the import is expected to fail.
- ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
-
- // After enabled the feature, the import is expected to succeed.
- scoped_feature.Reset();
- scoped_feature.InitAndEnableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
-
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -842,7 +833,9 @@ TEST_P(FormDataImporterTest,
EXPECT_EQ(0, expected.Compare(*results[0]));
}
-TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
+// Test that a form is imported correctly even if some fields are not
+// focusable.
+TEST_P(FormDataImporterTest, ImportAddressProfiles_WithUnFocussableFields) {
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -864,7 +857,8 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
form.fields.push_back(field);
test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
- // Set this field to be unfocusable.
+
+ // Set this field to be not focusable.
field.is_focusable = false;
form.fields.push_back(field);
@@ -877,18 +871,6 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- // 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);
@@ -1605,6 +1587,181 @@ TEST_P(FormDataImporterTest,
EXPECT_EQ(0, profile.Compare(*results2[0]));
}
+TEST_P(FormDataImporterTest,
+ IncorporateStructuredNameInformationInVerifiedProfile) {
+ // This test is only applicable to structured names.
+ if (!structured_address::StructuredNamesEnabled()) {
+ return;
+ }
+
+ // Start with a verified profile.
+ AutofillProfile profile(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ EXPECT_TRUE(profile.IsVerified());
+
+ // Set the verification status for the first and middle name to parsed.
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, base::ASCIIToUTF16("Marion"),
+ structured_address::VerificationStatus::kParsed);
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, base::ASCIIToUTF16("Mitchell"),
+ structured_address::VerificationStatus::kParsed);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ personal_data_manager_->AddProfile(profile);
+ run_loop.Run();
+
+ // Simulate a form submission with conflicting info.
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "Marion Mitchell",
+ "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Morrison", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "johnwayne@me.xyz", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "123 Zoo St.", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "Hollywood", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "CA", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "91601", "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ // The form submission should result in a change of name structure.
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, base::ASCIIToUTF16("Marion Mitchell"),
+ structured_address::VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_MIDDLE, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_LAST, base::ASCIIToUTF16("Morrison"),
+ structured_address::VerificationStatus::kObserved);
+
+ // Expect that no new profile is saved.
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, profile.Compare(*results[0]));
+
+ // Try the same thing, but without "Mitchell". The profiles should still match
+ // because "Marion Morrison" is a variant of the known full name.
+ test::CreateTestFormField("First name:", "first_name", "Marion", "text",
+ &field);
+ form.fields[0] = field;
+
+ FormStructure form_structure2(form);
+ form_structure2.DetermineHeuristicTypes();
+
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
+
+ // Expect that no new profile is saved.
+ const std::vector<AutofillProfile*>& results2 =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results2.size());
+ EXPECT_EQ(0, profile.Compare(*results2[0]));
+}
+
+TEST_P(FormDataImporterTest,
+ IncorporateStructuredAddressInformationInVerififedProfile) {
+ // This test is only applicable to structured addresses.
+ if (!structured_address::StructuredAddressesEnabled()) {
+ return;
+ }
+
+ // Start with a verified profile.
+ AutofillProfile profile(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ EXPECT_TRUE(profile.IsVerified());
+
+ // Reset the structured address to emulate a failed parsing attempt.
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ personal_data_manager_->AddProfile(profile);
+ run_loop.Run();
+
+ // Simulate a form submission with conflicting info.
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "Marion Mitchell",
+ "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Morrison", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "johnwayne@me.xyz", "text",
+ &field);
+ form.fields.push_back(field);
+ // This forms contains structured address information.
+ test::CreateTestFormField("Street Name:", "street_name", "Zoo St.", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("House Number:", "house_number", "123", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "Hollywood", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "CA", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "91601", "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ // The form submission should result in a change of the address structure.
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
+ base::ASCIIToUTF16("Zoo St."),
+ structured_address::VerificationStatus::kFormatted);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16("Zoo St."),
+ structured_address::VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("123"),
+ structured_address::VerificationStatus::kObserved);
+
+ // Expect that no new profile is saved.
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, profile.Compare(*results[0]));
+}
+
// Tests that no profile is inferred if the country is not recognized.
TEST_P(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) {
FormData form;
@@ -1690,37 +1847,6 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_LocalizedCountryName) {
// Set the page language to match the localized country value and try again.
autofill_client_->GetLanguageState()->SetOriginalLanguage("de");
- // TODO(crbug.com/1075604): Remove test with disabled feature.
- // Verify that nothing is changed if using the page language feature is not
- // enabled.
- scoped_feature_list_.Reset();
- if (StructuredNames()) {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableSupportForMoreStructureInNames},
- {features::kAutofillUsePageLanguageToTranslateCountryNames});
- } else {
- scoped_feature_list_.InitWithFeatures(
- {}, {features::kAutofillEnableSupportForMoreStructureInNames,
- features::kAutofillUsePageLanguageToTranslateCountryNames});
- }
- ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
-
- // There should be no imported address profile.
- ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
- ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
-
- // Enable the feature and to test if the profile can now be imported.
- scoped_feature_list_.Reset();
- if (StructuredNames()) {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableSupportForMoreStructureInNames,
- features::kAutofillUsePageLanguageToTranslateCountryNames},
- {});
- } else {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillUsePageLanguageToTranslateCountryNames},
- {features::kAutofillEnableSupportForMoreStructureInNames});
- }
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// There should be one imported address profile.
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 123f7878008..6ed67749e2f 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
@@ -14,10 +14,10 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.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_scanner.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
using base::UTF8ToUTF16;
@@ -58,9 +58,21 @@ std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
base::string16 attention_ignored = UTF8ToUTF16(kAttentionIgnoredRe);
base::string16 region_ignored = UTF8ToUTF16(kRegionIgnoredRe);
- const bool is_enabled_merged_city_state_country_zip =
- base::FeatureList::IsEnabled(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
+ // 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);
// Allow address fields to appear in any order.
size_t begin_trailing_non_labeled_fields = 0;
@@ -68,28 +80,28 @@ 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), nullptr,
- {log_manager, "kAddressLookupRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kAddressNameIgnoredRe), nullptr,
+ if (ParseField(scanner, base::UTF8ToUTF16(kAddressLookupRe), patterns_al,
+ nullptr, {log_manager, "kAddressLookupRe"}) ||
+ ParseField(scanner, base::UTF8ToUTF16(kAddressNameIgnoredRe),
+ patterns_ni, nullptr,
{log_manager, "kAddressNameIgnoreRe"})) {
continue;
// Ignore email addresses.
} else if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
- MATCH_DEFAULT | MATCH_TEXT_AREA, nullptr,
- {log_manager, "kEmailRe"})) {
+ MATCH_DEFAULT | MATCH_TEXT_AREA,
+ patterns_email, nullptr,
+ {log_manager, "kEmailRe"},
+ {.augment_types = MATCH_TEXT_AREA})) {
continue;
- } else if (address_field->ParseAddress(scanner) ||
- (!is_enabled_merged_city_state_country_zip &&
- (address_field->ParseCityStateZipCode(scanner) ||
- address_field->ParseCountry(scanner))) ||
- (is_enabled_merged_city_state_country_zip &&
- address_field->ParseCityStateCountryZipCode(scanner)) ||
- address_field->ParseCompany(scanner)) {
+ } else if (address_field->ParseAddress(scanner, page_language) ||
+ address_field->ParseCityStateCountryZipCode(scanner,
+ page_language) ||
+ address_field->ParseCompany(scanner, page_language)) {
has_trailing_non_labeled_fields = false;
continue;
- } else if (ParseField(scanner, attention_ignored, nullptr,
+ } else if (ParseField(scanner, attention_ignored, patterns_ai, nullptr,
{log_manager, "kAttentionIgnoredRe"}) ||
- ParseField(scanner, region_ignored, nullptr,
+ ParseField(scanner, region_ignored, patterns_ri, nullptr,
{log_manager, "kRegionIgnoredRe"})) {
// We ignore the following:
// * Attention.
@@ -170,15 +182,20 @@ void AddressField::AddClassifications(
kBaseAddressParserScore, field_candidates);
}
-bool AddressField::ParseCompany(AutofillScanner* scanner) {
+bool AddressField::ParseCompany(AutofillScanner* scanner,
+ const std::string& page_language) {
if (company_)
return false;
+ // In JSON : COMPANY
+ auto& patterns_c =
+ PatternProvider::GetInstance().GetMatchPatterns("COMPANY", page_language);
- return ParseField(scanner, UTF8ToUTF16(kCompanyRe), &company_,
+ return ParseField(scanner, UTF8ToUTF16(kCompanyRe), patterns_c, &company_,
{log_manager_, "kCompanyRe"});
}
-bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner) {
+bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner,
+ const std::string& 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.
@@ -190,16 +207,24 @@ 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);
while (!scanner->IsEnd()) {
if (!street_name_ &&
ParseFieldSpecifics(scanner, UTF8ToUTF16(kStreetNameRe), MATCH_DEFAULT,
- &street_name_, {log_manager_, "kStreetNameRe"})) {
+ patterns_s, &street_name_,
+ {log_manager_, "kStreetNameRe"})) {
continue;
}
if (!house_number_ &&
ParseFieldSpecifics(scanner, UTF8ToUTF16(kHouseNumberRe), MATCH_DEFAULT,
- &house_number_, {log_manager_, "kHouseNumberRe"})) {
+ patterns_h, &house_number_,
+ {log_manager_, "kHouseNumberRe"})) {
continue;
}
@@ -218,14 +243,17 @@ bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner) {
return false;
}
-bool AddressField::ParseAddress(AutofillScanner* scanner) {
+bool AddressField::ParseAddress(AutofillScanner* scanner,
+ const std::string& page_language) {
if (street_name_ && house_number_) {
return false;
}
- return ParseAddressFieldSequence(scanner) || ParseAddressLines(scanner);
+ return ParseAddressFieldSequence(scanner, page_language) ||
+ ParseAddressLines(scanner, page_language);
}
-bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
+bool AddressField::ParseAddressLines(AutofillScanner* scanner,
+ const std::string& 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
@@ -239,17 +267,23 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
base::string16 pattern = UTF8ToUTF16(kAddressLine1Re);
base::string16 label_pattern = UTF8ToUTF16(kAddressLine1LabelRe);
- if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, &address1_,
- {log_manager_, "kAddressLine1Re"}) &&
+ // 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"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- &address1_,
+ patterns_l1, &address1_,
{log_manager_, "kAddressLine1LabelRe"}) &&
!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_TEXT_AREA,
- &street_address_,
- {log_manager_, "kAddressLine1Re"}) &&
- !ParseFieldSpecifics(scanner, label_pattern,
- MATCH_LABEL | MATCH_TEXT_AREA, &street_address_,
- {log_manager_, "kAddressLine1LabelRe"}))
+ patterns_l1, &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}))
return false;
if (street_address_)
@@ -260,19 +294,33 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
// discussion on https://codereview.chromium.org/741493003/
pattern = UTF8ToUTF16(kAddressLine2Re);
label_pattern = UTF8ToUTF16(kAddressLine2LabelRe);
- if (!ParseField(scanner, pattern, &address2_,
+ // 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_,
{log_manager_, "kAddressLine2Re"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- &address2_, {log_manager_, "kAddressLine2LabelRe"}))
+ patterns_l2, &address2_,
+ {log_manager_, "kAddressLine2LabelRe"}))
return true;
// Optionally parse address line 3. This uses the same label regexp as
// address 2 above.
pattern = UTF8ToUTF16(kAddressLinesExtraRe);
- if (!ParseField(scanner, pattern, &address3_,
+ if (!ParseField(scanner, pattern, patterns_le, &address3_,
{log_manager_, "kAddressLinesExtraRe"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- &address3_, {log_manager_, "kAddressLine2LabelRe"}))
+ patterns_l2, &address3_,
+ {log_manager_, "kAddressLine2LabelRe"}))
return true;
// Try for surplus lines, which we will promptly discard. Some pages have 4
@@ -281,21 +329,29 @@ 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, nullptr,
+ while (ParseField(scanner, pattern, patterns_le, nullptr,
{log_manager_, "kAddressLinesExtraRe"})) {
// Consumed a surplus line, try for another.
}
return true;
}
-bool AddressField::ParseCountry(AutofillScanner* scanner) {
+bool AddressField::ParseCountry(AutofillScanner* scanner,
+ const std::string& page_language) {
if (country_)
return false;
+ // In JSON : COUNTRY
+ auto& patterns_c =
+ PatternProvider::GetInstance().GetMatchPatterns("COUNTRY", page_language);
+ auto& patterns_cl = PatternProvider::GetInstance().GetMatchPatterns(
+ "COUNTRY_LOCATION", page_language);
+
scanner->SaveCursor();
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kCountryRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- &country_, {log_manager_, "kCountryRe"})) {
+ patterns_c, &country_,
+ {log_manager_, "kCountryRe"})) {
return true;
}
@@ -304,46 +360,67 @@ bool AddressField::ParseCountry(AutofillScanner* scanner) {
scanner->Rewind();
return ParseFieldSpecifics(
scanner, UTF8ToUTF16(kCountryLocationRe),
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, &country_,
- {log_manager_, "kCountryLocationRe"});
+ MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, patterns_cl,
+ &country_, {log_manager_, "kCountryLocationRe"});
}
-bool AddressField::ParseZipCode(AutofillScanner* scanner) {
+bool AddressField::ParseZipCode(AutofillScanner* scanner,
+ const std::string& 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 =
+ PatternProvider::GetInstance().GetMatchPatterns("ZIP_4", page_language);
if (!ParseFieldSpecifics(scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType,
- &zip_, {log_manager_, "kZipCodeRe"})) {
+ patterns_z, &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, &zip4_,
- {log_manager_, "kZip4Re"});
+ ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType,
+ patterns_z4, &zip4_, {log_manager_, "kZip4Re"});
return true;
}
-bool AddressField::ParseCity(AutofillScanner* scanner) {
+bool AddressField::ParseCity(AutofillScanner* scanner,
+ const std::string& page_language) {
if (city_)
return false;
+ // In JSON : CITY
+ auto& patterns_city =
+ PatternProvider::GetInstance().GetMatchPatterns("CITY", page_language);
return ParseFieldSpecifics(scanner, UTF8ToUTF16(kCityRe), kCityMatchType,
- &city_, {log_manager_, "kCityRe"});
+ patterns_city, &city_, {log_manager_, "kCityRe"});
}
-bool AddressField::ParseState(AutofillScanner* scanner) {
+bool AddressField::ParseState(AutofillScanner* scanner,
+ const std::string& page_language) {
if (state_)
return false;
+ // auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ // "ADDRESS_HOME_STATE", page_language);
+ // In JSON : STATE
+ auto& patterns_state =
+ PatternProvider::GetInstance().GetMatchPatterns("STATE", page_language);
return ParseFieldSpecifics(scanner, UTF8ToUTF16(kStateRe), kStateMatchType,
- &state_, {log_manager_, "kStateRe"});
+ patterns_state, &state_,
+ {log_manager_, "kStateRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
AutofillScanner* scanner,
const base::string16& pattern,
int match_type,
+ const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging) {
if (scanner->IsEnd())
@@ -352,10 +429,12 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
AutofillField* cur_match = nullptr;
size_t saved_cursor = scanner->SaveCursor();
bool parsed_name = ParseFieldSpecifics(
- scanner, pattern, match_type & ~MATCH_LABEL, &cur_match, logging);
+ scanner, pattern, match_type & ~MATCH_LABEL, patterns, &cur_match,
+ logging, {.restrict_attributes = MATCH_NAME});
scanner->RewindTo(saved_cursor);
bool parsed_label = ParseFieldSpecifics(
- scanner, pattern, match_type & ~MATCH_NAME, &cur_match, logging);
+ scanner, pattern, match_type & ~MATCH_NAME, patterns, &cur_match, logging,
+ {.restrict_attributes = MATCH_LABEL});
if (parsed_name && parsed_label) {
if (match)
*match = cur_match;
@@ -370,60 +449,9 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
return RESULT_MATCH_NONE;
}
-bool AddressField::ParseCityStateZipCode(AutofillScanner* scanner) {
- // Simple cases.
- if (scanner->IsEnd())
- return false;
- if (city_ && state_ && zip_)
- return false;
- if (state_ && zip_)
- return ParseCity(scanner);
- if (city_ && zip_)
- return ParseState(scanner);
- if (city_ && state_)
- return ParseZipCode(scanner);
-
- // Check for matches to both name and label.
- ParseNameLabelResult city_result = ParseNameAndLabelForCity(scanner);
- if (city_result == RESULT_MATCH_NAME_LABEL)
- return true;
- ParseNameLabelResult state_result = ParseNameAndLabelForState(scanner);
- if (state_result == RESULT_MATCH_NAME_LABEL)
- return true;
- ParseNameLabelResult zip_result = ParseNameAndLabelForZipCode(scanner);
- if (zip_result == RESULT_MATCH_NAME_LABEL)
- return true;
-
- // 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_zip = zip_result != RESULT_MATCH_NONE;
- if (maybe_city && !maybe_state && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (maybe_state && !maybe_city && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (maybe_zip && !maybe_city && !maybe_state)
- return ParseZipCode(scanner);
-
- // Otherwise give name priority over label.
- if (city_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (state_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (zip_result == RESULT_MATCH_NAME)
- return ParseZipCode(scanner);
-
- if (city_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (state_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (zip_result == RESULT_MATCH_LABEL)
- return ParseZipCode(scanner);
-
- return false;
-}
-
-bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
+bool AddressField::ParseCityStateCountryZipCode(
+ AutofillScanner* scanner,
+ const std::string& page_language) {
// The |scanner| is not pointing at a field.
if (scanner->IsEnd())
return false;
@@ -434,25 +462,29 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
// Exactly one field type is missing.
if (state_ && country_ && zip_)
- return ParseCity(scanner);
+ return ParseCity(scanner, page_language);
if (city_ && country_ && zip_)
- return ParseState(scanner);
+ return ParseState(scanner, page_language);
if (city_ && state_ && zip_)
- return ParseCountry(scanner);
+ return ParseCountry(scanner, page_language);
if (city_ && state_ && country_)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
// Check for matches to both the name and the label.
- ParseNameLabelResult city_result = ParseNameAndLabelForCity(scanner);
+ ParseNameLabelResult city_result =
+ ParseNameAndLabelForCity(scanner, page_language);
if (city_result == RESULT_MATCH_NAME_LABEL)
return true;
- ParseNameLabelResult state_result = ParseNameAndLabelForState(scanner);
+ ParseNameLabelResult state_result =
+ ParseNameAndLabelForState(scanner, page_language);
if (state_result == RESULT_MATCH_NAME_LABEL)
return true;
- ParseNameLabelResult country_result = ParseNameAndLabelForCountry(scanner);
+ ParseNameLabelResult country_result =
+ ParseNameAndLabelForCountry(scanner, page_language);
if (country_result == RESULT_MATCH_NAME_LABEL)
return true;
- ParseNameLabelResult zip_result = ParseNameAndLabelForZipCode(scanner);
+ ParseNameLabelResult zip_result =
+ ParseNameAndLabelForZipCode(scanner, page_language);
if (zip_result == RESULT_MATCH_NAME_LABEL)
return true;
@@ -468,7 +500,7 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
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);
+ 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.
@@ -483,7 +515,7 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
if (country_result == RESULT_MATCH_NAME)
return SetFieldAndAdvanceCursor(scanner, &country_);
if (zip_result == RESULT_MATCH_NAME)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
if (city_result == RESULT_MATCH_LABEL)
return SetFieldAndAdvanceCursor(scanner, &city_);
@@ -492,30 +524,38 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
if (country_result == RESULT_MATCH_LABEL)
return SetFieldAndAdvanceCursor(scanner, &country_);
if (zip_result == RESULT_MATCH_LABEL)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
return false;
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForZipCode(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& 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 =
+ PatternProvider::GetInstance().GetMatchPatterns("ZIP_4", page_language);
+
ParseNameLabelResult result = ParseNameAndLabelSeparately(
- scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, &zip_,
+ scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, patterns_z, &zip_,
{log_manager_, "kZipCodeRe"});
if (result != RESULT_MATCH_NAME_LABEL || scanner->IsEnd())
return result;
size_t saved_cursor = scanner->SaveCursor();
- bool found_non_zip4 = ParseCity(scanner);
+ bool found_non_zip4 = ParseCity(scanner, page_language);
if (found_non_zip4)
city_ = nullptr;
scanner->RewindTo(saved_cursor);
if (!found_non_zip4) {
- found_non_zip4 = ParseState(scanner);
+ found_non_zip4 = ParseState(scanner, page_language);
if (found_non_zip4)
state_ = nullptr;
scanner->RewindTo(saved_cursor);
@@ -525,40 +565,55 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForZipCode(
// Look for a zip+4, whose field name will also often contain
// the substring "zip".
ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType,
- &zip4_, {log_manager_, "kZip4Re"});
+ patterns_z4, &zip4_, {log_manager_, "kZip4Re"});
}
return result;
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCity(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (city_)
return RESULT_MATCH_NONE;
+ // In JSON : CITY
+ auto& patterns_city =
+ PatternProvider::GetInstance().GetMatchPatterns("CITY", page_language);
return ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kCityRe),
- kCityMatchType, &city_,
+ kCityMatchType, patterns_city, &city_,
{log_manager_, "kCityRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForState(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (state_)
return RESULT_MATCH_NONE;
+ // In JSON : STATE
+ auto& patterns_state =
+ PatternProvider::GetInstance().GetMatchPatterns("STATE", page_language);
return ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kStateRe),
- kStateMatchType, &state_,
+ kStateMatchType, patterns_state, &state_,
{log_manager_, "kStateRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (country_)
return RESULT_MATCH_NONE;
- ParseNameLabelResult country_result =
- ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kCountryRe),
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- &country_, {log_manager_, "kCountryRe"});
+ // In JSON : COUNTRY
+ auto& patterns_c =
+ PatternProvider::GetInstance().GetMatchPatterns("COUNTRY", page_language);
+ auto& patterns_cl = PatternProvider::GetInstance().GetMatchPatterns(
+ "COUNTRY_LOCATION", page_language);
+
+ ParseNameLabelResult country_result = ParseNameAndLabelSeparately(
+ scanner, UTF8ToUTF16(kCountryRe),
+ MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH, patterns_c, &country_,
+ {log_manager_, "kCountryRe"});
if (country_result != RESULT_MATCH_NONE)
return country_result;
@@ -566,8 +621,8 @@ 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, &country_,
- {log_manager_, "kCountryLocationRe"});
+ MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, patterns_cl,
+ &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 4fb2c6c6758..0ee62ee3853 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.h
@@ -14,6 +14,7 @@
#include "base/strings/string16.h"
#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"
namespace autofill {
@@ -53,45 +54,70 @@ class AddressField : public FormField {
explicit AddressField(LogManager* log_manager);
- bool ParseCompany(AutofillScanner* scanner);
- bool ParseAddress(AutofillScanner* scanner);
- bool ParseAddressFieldSequence(AutofillScanner* scanner);
- bool ParseAddressLines(AutofillScanner* scanner);
- bool ParseCountry(AutofillScanner* scanner);
- bool ParseZipCode(AutofillScanner* scanner);
- bool ParseCity(AutofillScanner* scanner);
- bool ParseState(AutofillScanner* scanner);
+ bool ParseCompany(AutofillScanner* scanner, const std::string& 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, zip, or none of those.
- // TODO(crbug.com/1073555) Delete this once experiment
- // |kAutofillUseParseCityStateCountryZipCodeInHeuristic| has been launched.
- bool ParseCityStateZipCode(AutofillScanner* scanner);
+ bool ParseAddress(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseAddressFieldSequence(AutofillScanner* scanner,
+ const std::string& page_language);
+
+ bool ParseAddressLines(AutofillScanner* scanner,
+ const std::string& page_language);
+
+ bool ParseCountry(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseZipCode(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseCity(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseState(AutofillScanner* scanner, const std::string& 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);
+ bool ParseCityStateCountryZipCode(AutofillScanner* scanner,
+ const std::string& 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,
int match_type,
+ const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging);
// Run matches on the name and label separately. If the return result is
// RESULT_MATCH_NAME_LABEL, then |scanner| advances and the field is set.
// Otherwise |scanner| rewinds and the field is cleared.
- ParseNameLabelResult ParseNameAndLabelForZipCode(AutofillScanner* scanner);
- ParseNameLabelResult ParseNameAndLabelForCity(AutofillScanner* scanner);
- ParseNameLabelResult ParseNameAndLabelForCountry(AutofillScanner* scanner);
- ParseNameLabelResult ParseNameAndLabelForState(AutofillScanner* scanner);
+ ParseNameLabelResult ParseNameAndLabelForZipCode(
+ AutofillScanner* scanner,
+ const std::string& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForCity(
+ AutofillScanner* scanner,
+ const std::string& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForCountry(
+ AutofillScanner* scanner,
+ const std::string& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForState(
+ AutofillScanner* scanner,
+ const std::string& page_language);
LogManager* log_manager_;
AutofillField* company_ = 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 9b59b7c455b..bc6e0908571 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
@@ -14,6 +14,7 @@
#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"
@@ -24,13 +25,11 @@ namespace autofill {
class AddressFieldTest : public testing::Test {
public:
- AddressFieldTest() {}
+ AddressFieldTest() = default;
+ AddressFieldTest(const AddressFieldTest&) = delete;
+ AddressFieldTest& operator=(const AddressFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<AddressField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<AddressField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -41,8 +40,12 @@ class AddressFieldTest : public testing::Test {
static_cast<AddressField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(AddressFieldTest);
+ 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) {
@@ -160,6 +163,104 @@ TEST_F(AddressFieldTest, ParseStreetAddressFromTextArea) {
field_candidates_map_[ASCIIToUTF16("addr")].BestHeuristicType());
}
+// Tests that fields are classified as |ADDRESS_HOME_STREET_NAME| and
+// |ADDRESS_HOME_HOUSE_NUMBER| when they are labeled accordingly and
+// both are present.
+TEST_F(AddressFieldTest, ParseStreetNameAndHouseNumber) {
+ // 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")));
+
+ 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());
+}
+
+// Tests that the field is not classified as |ADDRESS_HOME_STREET_NAME| when
+// it is labeled accordingly but 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());
+}
+
+// Tests that the field is not classified as |ADDRESS_HOME_HOUSE_NUMBER| when
+// it is labeled accordingly but adjacent field classified as
+// |ADDRESS_HOME_STREET_NAME| is absent.
+TEST_F(AddressFieldTest, NotParseHouseNumberWithoutStreetName) {
+ // 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("House number");
+ field.name = ASCIIToUTF16("house-number");
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("house")));
+
+ 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_HOUSE_NUMBER,
+ field_candidates_map_[ASCIIToUTF16("house")].BestHeuristicType());
+}
+
TEST_F(AddressFieldTest, ParseCity) {
FormFieldData field;
field.form_control_type = "text";
@@ -308,10 +409,6 @@ TEST_F(AddressFieldTest, ParseCityStateCountryZipcodeTogether) {
field.name = ASCIIToUTF16("zip");
list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("zip1")));
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
-
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
@@ -350,10 +447,6 @@ TEST_F(AddressFieldTest, ParseCountryLabelRegion) {
list_.push_back(
std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
-
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
@@ -377,10 +470,6 @@ TEST_F(AddressFieldTest, ParseCountryNameRegion) {
list_.push_back(
std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
-
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
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 d9fc85afdce..ddd418eca54 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
@@ -13,31 +13,4 @@ MatchingPattern& MatchingPattern::operator=(const MatchingPattern& mp) =
MatchingPattern::~MatchingPattern() = default;
-autofill::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.negative_pattern = "";
- m_p.match_field_attributes = MATCH_NAME;
- m_p.match_field_input_types = MATCH_TEXT;
- m_p.language = "en";
-
- return m_p;
-}
-
-autofill::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.negative_pattern = "";
- m_p.match_field_attributes = MATCH_LABEL | MATCH_NAME;
- m_p.match_field_input_types = MATCH_TEXT;
- m_p.language = "de";
-
- return m_p;
-}
-
-} // namespace autofill \ No newline at end of file
+} // 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 8335c216c20..b24b5b5a5d7 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
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_AUTOFILL_PARSING_UTILS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_AUTOFILL_PARSING_UTILS_H_
+#include <base/optional.h>
#include <string>
namespace autofill {
@@ -51,17 +52,12 @@ struct MatchingPattern {
std::string pattern_identifier;
std::string positive_pattern;
float positive_score = 1.1f;
- std::string negative_pattern;
+ base::Optional<std::string> negative_pattern;
int match_field_attributes;
int match_field_input_types;
std::string language;
};
-// Use these functions instead of storing "non standats type" constants that
-// bots might complaining over.
-MatchingPattern GetCompanyPatternEn();
-MatchingPattern GetCompanyPatternDe();
-
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_PARSING_UTILS_H_
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 766a9a00fda..27ee112a819 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
@@ -17,13 +17,13 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.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/field_filler.h"
#include "components/autofill/core/browser/field_types.h"
#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_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -92,16 +92,28 @@ std::unique_ptr<FormField> CreditCardField::Parse(
size_t saved_cursor = scanner->SaveCursor();
int nb_unknown_fields = 0;
+ 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);
+
// Credit card fields can appear in many different orders.
// We loop until no more credit card related fields are found, see |break| at
// the bottom of the loop.
for (int fields = 0; !scanner->IsEnd(); ++fields) {
// Ignore gift card fields.
- if (IsGiftCardField(scanner, log_manager))
+ if (IsGiftCardField(scanner, log_manager, page_language))
break;
if (!credit_card_field->cardholder_) {
- if (ParseField(scanner, base::UTF8ToUTF16(kNameOnCardRe),
+ if (ParseField(scanner, base::UTF8ToUTF16(kNameOnCardRe), patterns,
&credit_card_field->cardholder_,
{log_manager, "kNameOnCardRe"})) {
continue;
@@ -113,9 +125,10 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// fields. So we search for "name" only when we've already parsed at
// least one other credit card field and haven't yet parsed the
// expiration date (which usually appears at the end).
+
if (fields > 0 && !credit_card_field->expiration_month_ &&
ParseField(scanner, base::UTF8ToUTF16(kNameOnCardContextualRe),
- &credit_card_field->cardholder_,
+ patterns_cont, &credit_card_field->cardholder_,
{log_manager, "kNameOnCardContextualRe"})) {
continue;
}
@@ -125,7 +138,7 @@ 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),
+ ParseField(scanner, base::UTF8ToUTF16(kLastNameRe), patterns_nl,
&credit_card_field->cardholder_last_,
{log_manager, "kLastNameRe"})) {
continue;
@@ -150,10 +163,12 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// They also sometimes use type="password" for sensitive types.
const int kMatchNumTelAndPwd =
MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_PASSWORD;
+
if (!credit_card_field->verification_ &&
- ParseFieldSpecifics(
- scanner, base::UTF8ToUTF16(kCardCvcRe), kMatchNumTelAndPwd,
- &credit_card_field->verification_, {log_manager, "kCardCvcRe"})) {
+ ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardCvcRe),
+ kMatchNumTelAndPwd, patterns_cvc,
+ &credit_card_field->verification_,
+ {log_manager, "kCardCvcRe"})) {
// A couple of sites have multiple verification codes right after another.
// Allow the classification of these codes one by one.
AutofillField* const saved_cvv = credit_card_field->verification_;
@@ -165,8 +180,9 @@ std::unique_ptr<FormField> CreditCardField::Parse(
!credit_card_field->cardholder_ && scanner->SaveCursor() > 1) {
// Check if the previous field was a verification code.
scanner->RewindTo(scanner->SaveCursor() - 2);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardCvcRe),
- kMatchNumTelAndPwd,
+ kMatchNumTelAndPwd, patterns_cvc,
&credit_card_field->verification_,
{log_manager, "kCardCvcRe"})) {
// Reset the current cvv (The verification parse overwrote it).
@@ -189,8 +205,10 @@ 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);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardNumberRe),
- kMatchNumTelAndPwd, &current_number_field,
+ kMatchNumTelAndPwd, patterns, &current_number_field,
{log_manager, "kCardNumberRe"})) {
// Avoid autofilling any credit card number field having very low or high
// |start_index| on the HTML form.
@@ -215,7 +233,8 @@ std::unique_ptr<FormField> CreditCardField::Parse(
continue;
}
- if (credit_card_field->ParseExpirationDate(scanner, log_manager)) {
+ if (credit_card_field->ParseExpirationDate(scanner, log_manager,
+ page_language)) {
nb_unknown_fields = 0;
continue;
}
@@ -311,8 +330,10 @@ bool CreditCardField::LikelyCardMonthSelectField(AutofillScanner* scanner) {
}
// static
-bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner,
- LogManager* log_manager) {
+bool CreditCardField::LikelyCardYearSelectField(
+ AutofillScanner* scanner,
+ LogManager* log_manager,
+ const std::string& page_language) {
if (scanner->IsEnd())
return false;
@@ -331,9 +352,12 @@ bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner,
}
// Another way to eliminate days - filter out 'day' fields.
+ // In JSON : DAY (only in JSON)
+ auto& patterns_day =
+ PatternProvider::GetInstance().GetMatchPatterns("DAY", page_language);
if (FormField::ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDayRe),
- MATCH_DEFAULT | MATCH_SELECT, nullptr,
- {log_manager, "kDayRe"})) {
+ MATCH_DEFAULT | MATCH_SELECT, patterns_day,
+ nullptr, {log_manager, "kDayRe"})) {
return false;
}
@@ -389,28 +413,40 @@ bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) {
// static
bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
- LogManager* log_manager) {
+ LogManager* log_manager,
+ const std::string& page_language) {
if (scanner->IsEnd())
return false;
const int kMatchFieldTypes =
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);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitCardRe),
- kMatchFieldTypes, nullptr,
+ kMatchFieldTypes, patterns_d, nullptr,
{log_manager, "kDebitCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitGiftCardRe),
- kMatchFieldTypes, nullptr,
+ kMatchFieldTypes, patterns_dg, nullptr,
{log_manager, "kDebitGiftCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kGiftCardRe),
- kMatchFieldTypes, nullptr,
+ kMatchFieldTypes, patterns_g, nullptr,
{log_manager, "kGiftCardRe"});
}
@@ -467,7 +503,8 @@ void CreditCardField::AddClassifications(
}
bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
- LogManager* log_manager) {
+ LogManager* log_manager,
+ const std::string& page_language) {
if (!expiration_date_ && base::LowerCaseEqualsASCII(
scanner->Cursor()->form_control_type, "month")) {
expiration_date_ = scanner->Cursor();
@@ -487,7 +524,7 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
if (LikelyCardMonthSelectField(scanner)) {
expiration_month_ = scanner->Cursor();
scanner->Advance();
- if (LikelyCardYearSelectField(scanner, log_manager)) {
+ if (LikelyCardYearSelectField(scanner, log_manager, page_language)) {
expiration_year_ = scanner->Cursor();
scanner->Advance();
return true;
@@ -500,11 +537,23 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
scanner->RewindTo(month_year_saved_cursor);
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);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationMonthRe),
- kMatchCCType, &expiration_month_,
+ kMatchCCType, patterns_m, &expiration_month_,
{log_manager_, "kExpirationMonthRe"}) &&
ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationYearRe),
- kMatchCCType, &expiration_year_,
+ kMatchCCType, patterns_y, &expiration_year_,
{log_manager_, "kExpirationYearRe"})) {
return true;
}
@@ -512,9 +561,10 @@ 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,
- &expiration_month_, {log_manager_, "^mm$"}) &&
+ patterns_mm, &expiration_month_,
+ {log_manager_, "^mm$"}) &&
ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^(yy|yyyy)$"),
- kMatchCCType, &expiration_year_,
+ kMatchCCType, patterns_yy, &expiration_year_,
{log_manager_, "^(yy|yyyy)$"})) {
return true;
}
@@ -530,17 +580,23 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
return false;
// Try to look for a 2-digit year expiration date.
- if (ParseFieldSpecifics(
- scanner, base::UTF8ToUTF16(kExpirationDate2DigitYearRe), kMatchCCType,
- &expiration_date_, {log_manager_, "kExpirationDate2DigitYearRe"})) {
+ // 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"})) {
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);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationDateRe),
- kMatchCCType, &expiration_date_,
+ kMatchCCType, patterns_exp_d, &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
@@ -554,11 +610,14 @@ 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);
if (FieldCanFitDataForFieldType(current_field_max_length,
CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
- ParseFieldSpecifics(
- scanner, base::UTF8ToUTF16(kExpirationDate4DigitYearRe), kMatchCCType,
- &expiration_date_, {log_manager_, "kExpirationDate4DigitYearRe"})) {
+ ParseFieldSpecifics(scanner,
+ base::UTF8ToUTF16(kExpirationDate4DigitYearRe),
+ kMatchCCType, patterns_4dy, &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 974219ba87e..a3aa409c065 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
@@ -12,6 +12,7 @@
#include "base/macros.h"
#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"
namespace autofill {
@@ -42,7 +43,8 @@ class CreditCardField : public FormField {
// the next few years. |log_manager| is used to log any parsing details
// to chrome://autofill-internals
static bool LikelyCardYearSelectField(AutofillScanner* scanner,
- LogManager* log_manager);
+ LogManager* log_manager,
+ const std::string& page_language);
// Returns true if |scanner| points to a <select> field that contains credit
// card type options.
@@ -53,11 +55,14 @@ class CreditCardField : public FormField {
// Prepaid debit cards do not count as gift cards, since they can be used like
// a credit card.
static bool IsGiftCardField(AutofillScanner* scanner,
- LogManager* log_manager);
+ LogManager* log_manager,
+ const std::string& page_language);
// Parses the expiration month/year/date fields. Returns true if it finds
// something new.
- bool ParseExpirationDate(AutofillScanner* scanner, LogManager* log_manager);
+ bool ParseExpirationDate(AutofillScanner* scanner,
+ LogManager* log_manager,
+ const std::string& 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 f5e0aab5013..9d9815c4269 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
@@ -13,6 +13,7 @@
#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/autofill_clock.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,14 +24,11 @@ namespace autofill {
class CreditCardFieldTestBase {
public:
- CreditCardFieldTestBase() {}
- ~CreditCardFieldTestBase() {}
+ CreditCardFieldTestBase() = default;
+ CreditCardFieldTestBase(const CreditCardFieldTestBase&) = delete;
+ CreditCardFieldTestBase& operator=(const CreditCardFieldTestBase&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<const CreditCardField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Parses the contents of |list_| as a form, and stores the result into
// |field_|.
void Parse() {
@@ -67,17 +65,20 @@ class CreditCardFieldTestBase {
return field_->AddClassifications(&field_candidates_map_);
}
- private:
- DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTestBase);
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<const CreditCardField> field_;
+ FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
class CreditCardFieldTest : public CreditCardFieldTestBase,
public testing::Test {
public:
- CreditCardFieldTest() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTest);
+ CreditCardFieldTest() = default;
+ CreditCardFieldTest(const CreditCardFieldTest&) = delete;
+ CreditCardFieldTest& operator=(const CreditCardFieldTest&) = delete;
};
TEST_F(CreditCardFieldTest, Empty) {
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 ad2b95f68b4..99d87e8fc17 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
@@ -5,8 +5,8 @@
#include "components/autofill/core/browser/form_parsing/email_field.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -15,8 +15,10 @@ std::unique_ptr<FormField> EmailField::Parse(AutofillScanner* scanner,
const std::string& page_language,
LogManager* log_manager) {
AutofillField* field;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ "EMAIL_ADDRESS", page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
- MATCH_DEFAULT | MATCH_EMAIL, &field,
+ MATCH_DEFAULT | MATCH_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 ffcf2dda7a9..3765457f766 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
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 10cbb1f9966..4b5f80e3ca8 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
@@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/address_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
@@ -33,7 +34,6 @@
#include "components/autofill/core/common/autofill_features.h"
#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_regexes.h"
#include "components/autofill/core/common/autofill_util.h"
namespace autofill {
@@ -122,7 +122,7 @@ FieldCandidatesMap FormField::ParseFormFields(
// For <form> tags, make an exception for email fields, which are commonly
// the only recognized field on account registration sites.
const bool accept_parsing =
- fillable_fields >= MinRequiredFieldsForHeuristics() ||
+ fillable_fields >= kMinRequiredFieldsForHeuristics ||
(is_form_tag && email_count > 0);
if (!accept_parsing) {
@@ -168,6 +168,22 @@ bool FormField::ParseField(AutofillScanner* scanner,
return ParseFieldSpecifics(scanner, patterns, match, logging);
}
+bool FormField::ParseField(AutofillScanner* scanner,
+ const base::string16& pattern,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ return ParseField(scanner, patterns, match, logging);
+ } else {
+ return ParseField(scanner, pattern, match, logging);
+ }
+}
+
bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
const base::string16& pattern,
int match_field_attributes,
@@ -207,7 +223,9 @@ bool FormField::ParseFieldSpecifics(
if (base::FeatureList::IsEnabled(
features::
kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
- if (FormField::Match(field, base::UTF8ToUTF16(pattern.negative_pattern),
+ if (pattern.negative_pattern.has_value() &&
+ FormField::Match(field,
+ base::UTF8ToUTF16(pattern.negative_pattern.value()),
pattern.match_field_attributes,
pattern.match_field_input_types, logging)) {
continue;
@@ -220,7 +238,6 @@ bool FormField::ParseFieldSpecifics(
return true;
}
}
-
return false;
}
@@ -237,6 +254,38 @@ bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
match_field_types, match, logging);
}
+bool FormField::ParseFieldSpecifics(
+ AutofillScanner* scanner,
+ const base::string16& pattern,
+ int match_type,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging,
+ MatchFieldBitmasks match_field_bitmasks) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ // 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) {
+ 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, patterns, match, logging);
+ } else {
+ return ParseFieldSpecifics(scanner, pattern, match_type, match, logging);
+ }
+}
+
// static
bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
AutofillField** match) {
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 f2c17a629c5..7eca61ab200 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.h
@@ -72,6 +72,12 @@ class FormField {
AutofillField** match,
const RegExLogging& logging = {});
+ static bool ParseField(AutofillScanner* scanner,
+ const base::string16& pattern,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging = {});
+
// Parses the stream of fields in |scanner| with regular expression |pattern|
// as specified in the |match_type| bit field (see |MatchType|). If |match|
// is non-NULL and the pattern matches, |match| will be set to the matched
@@ -96,6 +102,20 @@ class FormField {
int match_field_input_types,
AutofillField** match,
const RegExLogging& logging = {});
+ struct MatchFieldBitmasks {
+ int restrict_attributes = ~0;
+ int augment_types = 0;
+ };
+
+ static bool ParseFieldSpecifics(AutofillScanner* scanner,
+ const base::string16& pattern,
+ int match_type,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging,
+ MatchFieldBitmasks match_field_bitmasks = {
+ .restrict_attributes = ~0,
+ .augment_types = 0});
// Attempts to parse a field with an empty label. Returns true
// on success and fills |match| with a pointer to the field.
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 771275d5ecf..ed5baa21072 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,10 +10,10 @@
#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/common/autofill_features.h"
#include "testing/gtest/include/gtest/gtest.h"
-using autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics;
using autofill::features::kAutofillFixFillableFieldTypes;
using base::ASCIIToUTF16;
@@ -112,6 +112,8 @@ 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";
@@ -135,66 +137,27 @@ TEST(FormFieldTest, ParseFormFields) {
std::make_unique<AutofillField>(field_data, field_data.label));
// Parse a single address line 1 field.
- {
- base::test::ScopedFeatureList enforce_min_fields;
- enforce_min_fields.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // 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());
- }
- {
- base::test::ScopedFeatureList do_not_enforce_min_fields;
- do_not_enforce_min_fields.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // 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);
- ASSERT_EQ(1u, field_candidates_map.size());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map.find(ASCIIToUTF16("Address line1"))
- ->second.BestHeuristicType());
- }
+ ASSERT_EQ(
+ 0u,
+ FormField::ParseFormFields(fields, /*page_language=*/"", 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));
- {
- base::test::ScopedFeatureList enforce_min_fields;
- enforce_min_fields.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // 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());
- }
- {
- base::test::ScopedFeatureList do_not_enforce_min_fields;
- do_not_enforce_min_fields.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // 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);
- ASSERT_EQ(2u, field_candidates_map.size());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map.find(ASCIIToUTF16("Address line1"))
- ->second.BestHeuristicType());
- EXPECT_EQ(ADDRESS_HOME_LINE2,
- field_candidates_map.find(ASCIIToUTF16("Address line2"))
- ->second.BestHeuristicType());
- }
+ // 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());
}
// 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";
@@ -208,16 +171,11 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
std::make_unique<AutofillField>(field_data, field_data.label));
// Don't parse forms with 2 fields.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // 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());
- }
+ // 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());
field_data.label = ASCIIToUTF16("Search");
fields.push_back(
@@ -227,10 +185,7 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
// now, although a search field is not fillable.
{
base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/
- {kAutofillEnforceMinRequiredFieldsForHeuristics},
- /*disabled_features=*/{kAutofillFixFillableFieldTypes});
+ feature_list.InitAndDisableFeature(kAutofillFixFillableFieldTypes);
// An empty page_language means the language is unknown and patterns of all
// languages are used.
EXPECT_EQ(
@@ -242,11 +197,7 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
// fillable (therefore, the form has only 2 fillable fields).
{
base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillFixFillableFieldTypes},
- /*disabled_features=*/{});
+ feature_list.InitAndEnableFeature(kAutofillFixFillableFieldTypes);
// An empty page_language means the language is unknown and patterns of all
// languages are used.
const FieldCandidatesMap field_candidates_map =
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 0db9bd926fc..0fd65aa87c9 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
@@ -10,10 +10,10 @@
#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
using base::UTF8ToUTF16;
@@ -24,6 +24,7 @@ namespace {
class FullNameField : public NameField {
public:
static std::unique_ptr<FullNameField> Parse(AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
explicit FullNameField(AutofillField* field);
@@ -42,9 +43,12 @@ class FirstTwoLastNamesField : public NameField {
public:
static std::unique_ptr<FirstTwoLastNamesField> ParseComponentNames(
AutofillScanner* scanner,
+ const std::string& page_language,
+ LogManager* log_manager);
+ static std::unique_ptr<FirstTwoLastNamesField> Parse(
+ AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
- static std::unique_ptr<FirstTwoLastNamesField> Parse(AutofillScanner* scanner,
- LogManager* log_manager);
protected:
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
@@ -67,12 +71,16 @@ class FirstLastNameField : public NameField {
public:
static std::unique_ptr<FirstLastNameField> ParseSpecificName(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
static std::unique_ptr<FirstLastNameField> ParseComponentNames(
AutofillScanner* scanner,
+ const std::string& page_language,
+ LogManager* log_manager);
+ static std::unique_ptr<FirstLastNameField> Parse(
+ AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
- static std::unique_ptr<FirstLastNameField> Parse(AutofillScanner* scanner,
- LogManager* log_manager);
protected:
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
@@ -103,11 +111,11 @@ std::unique_ptr<FormField> NameField::Parse(AutofillScanner* scanner,
std::unique_ptr<FormField> field;
if (!field && base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames))
- field = FirstTwoLastNamesField::Parse(scanner, log_manager);
+ field = FirstTwoLastNamesField::Parse(scanner, page_language, log_manager);
if (!field)
- field = FirstLastNameField::Parse(scanner, log_manager);
+ field = FirstLastNameField::Parse(scanner, page_language, log_manager);
if (!field)
- field = FullNameField::Parse(scanner, log_manager);
+ field = FullNameField::Parse(scanner, page_language, log_manager);
return field;
}
@@ -116,12 +124,17 @@ void NameField::AddClassifications(FieldCandidatesMap* field_candidates) const {
}
// static
-std::unique_ptr<FullNameField> FullNameField::Parse(AutofillScanner* scanner,
- LogManager* log_manager) {
+std::unique_ptr<FullNameField> FullNameField::Parse(
+ AutofillScanner* scanner,
+ const std::string& page_language,
+ LogManager* log_manager) {
// Exclude e.g. "username" or "nickname" fields.
scanner->SaveCursor();
- bool should_ignore = ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), nullptr,
- {log_manager, "kNameIgnoredRe"});
+ auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_IGNORED", page_language);
+ bool should_ignore =
+ ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), patterns_ni, nullptr,
+ {log_manager, "kNameIgnoredRe"});
scanner->Rewind();
if (should_ignore)
return nullptr;
@@ -130,7 +143,10 @@ std::unique_ptr<FullNameField> FullNameField::Parse(AutofillScanner* scanner,
// for example, Travelocity_Edit travel profile.html contains a field
// "Travel Profile Name".
AutofillField* field = nullptr;
- if (ParseField(scanner, UTF8ToUTF16(kNameRe), &field,
+ // In JSON : FULL_NAME (closest vatiant)
+ auto& patterns_name = PatternProvider::GetInstance().GetMatchPatterns(
+ "FULL_NAME", page_language);
+ if (ParseField(scanner, UTF8ToUTF16(kNameRe), patterns_name, &field,
{log_manager, "kNameRe"}))
return std::make_unique<FullNameField>(field);
@@ -149,17 +165,32 @@ FirstTwoLastNamesField::FirstTwoLastNamesField() = default;
// static
std::unique_ptr<FirstTwoLastNamesField> FirstTwoLastNamesField::Parse(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
- return ParseComponentNames(scanner, log_manager);
+ return ParseComponentNames(scanner, page_language, log_manager);
}
// static
std::unique_ptr<FirstTwoLastNamesField>
FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
+ const std::string& 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);
+
// Allow name fields to appear in any order.
while (!scanner->IsEnd()) {
// Scan for the honorific prefix before checking for unrelated name fields
@@ -168,7 +199,7 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
// TODO(crbug.com/1098943): Remove check once feature is launched or
// removed.
if (!v->honorific_prefix_ &&
- ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe),
+ ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe), patterns_hp,
&v->honorific_prefix_,
{log_manager, "kHonorificPrefixRe"})) {
continue;
@@ -177,30 +208,31 @@ 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,
- nullptr, {log_manager, "kNameIgnoredRe"})) {
+ patterns_ni, nullptr,
+ {log_manager, "kNameIgnoredRe"})) {
continue;
}
if (!v->first_name_ &&
- ParseField(scanner, UTF8ToUTF16(kFirstNameRe), &v->first_name_,
- {log_manager, "kFirstNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kFirstNameRe), patterns_fn,
+ &v->first_name_, {log_manager, "kFirstNameRe"})) {
continue;
}
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), &v->middle_name_,
- {log_manager, "kMiddleNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), patterns_mn,
+ &v->middle_name_, {log_manager, "kMiddleNameRe"})) {
continue;
}
if (!v->first_last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kNameLastFirstRe), &v->first_last_name_,
- {log_manager, "kNameLastFirstRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kNameLastFirstRe), patterns_ln1,
+ &v->first_last_name_, {log_manager, "kNameLastFirstRe"})) {
continue;
}
if (!v->second_last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kNameLastSecondRe),
+ ParseField(scanner, UTF8ToUTF16(kNameLastSecondRe), patterns_ln2,
&v->second_last_name_,
{log_manager, "kNameLastSecondtRe"})) {
continue;
@@ -235,6 +267,7 @@ void FirstTwoLastNamesField::AddClassifications(
std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
AutofillScanner* scanner,
+ const std::string& 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.
@@ -242,8 +275,11 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
scanner->SaveCursor();
AutofillField* next = nullptr;
- if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), &v->first_name_,
- {log_manager, "kNameSpecificRe"}) &&
+ auto& patterns_ns = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_SPECIFIC", page_language);
+
+ if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), patterns_ns,
+ &v->first_name_, {log_manager, "kNameSpecificRe"}) &&
ParseEmptyLabel(scanner, &next)) {
if (ParseEmptyLabel(scanner, &v->last_name_)) {
// There are three name fields; assume that the middle one is a
@@ -264,6 +300,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
// static
std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstLastNameField> v(new FirstLastNameField);
scanner->SaveCursor();
@@ -279,6 +316,20 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// The ".*last$" matches fields ending in "last" (example in sample8.html).
// 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);
+
while (!scanner->IsEnd()) {
// Scan for the honorific prefix before checking for unrelated fields
// because a honorific prefix field is expected to have very specific labels
@@ -288,7 +339,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames)) {
if (!v->honorific_prefix_ &&
- ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe),
+ ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe), patterns_hp,
&v->honorific_prefix_,
{log_manager, "kHonorificPrefixRe"})) {
continue;
@@ -298,13 +349,14 @@ 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,
- nullptr, {log_manager, "kNameIgnoredRe"})) {
+ patterns_ni, nullptr,
+ {log_manager, "kNameIgnoredRe"})) {
continue;
}
if (!v->first_name_ &&
- ParseField(scanner, UTF8ToUTF16(kFirstNameRe), &v->first_name_,
- {log_manager, "kFirstNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kFirstNameRe), patterns_fn,
+ &v->first_name_, {log_manager, "kFirstNameRe"})) {
continue;
}
@@ -314,21 +366,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), &v->middle_name_,
- {log_manager, "kMiddleInitialRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleInitialRe), patterns_mi,
+ &v->middle_name_, {log_manager, "kMiddleInitialRe"})) {
v->middle_initial_ = true;
continue;
}
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), &v->middle_name_,
- {log_manager, "kMiddleNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), patterns_mn,
+ &v->middle_name_, {log_manager, "kMiddleNameRe"})) {
continue;
}
if (!v->last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kLastNameRe), &v->last_name_,
- {log_manager, "kLastNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kLastNameRe), patterns_ln,
+ &v->last_name_, {log_manager, "kLastNameRe"})) {
continue;
}
@@ -347,11 +399,12 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// static
std::unique_ptr<FirstLastNameField> FirstLastNameField::Parse(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstLastNameField> field =
- ParseSpecificName(scanner, log_manager);
+ ParseSpecificName(scanner, page_language, log_manager);
if (!field)
- field = ParseComponentNames(scanner, log_manager);
+ field = ParseComponentNames(scanner, page_language, log_manager);
return field;
}
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 26048b596bb..7298fbdb7d5 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.h
@@ -13,6 +13,7 @@
#include "base/macros.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/pattern_provider.h"
namespace autofill {
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 2931c9028d5..e83e8187b8c 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
@@ -12,10 +12,11 @@
#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/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,13 +26,11 @@ namespace autofill {
class NameFieldTest : public testing::Test {
public:
- NameFieldTest() {}
+ NameFieldTest() = default;
+ NameFieldTest(const NameFieldTest&) = delete;
+ NameFieldTest& operator=(const NameFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<NameField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<NameField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -41,8 +40,12 @@ class NameFieldTest : public testing::Test {
return std::unique_ptr<NameField>(static_cast<NameField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(NameFieldTest);
+ 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) {
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 82d6294891a..b50388208be 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
@@ -16,10 +16,10 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.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/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
namespace {
@@ -246,7 +246,8 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
scanner, GetRegExp(kPhoneFieldGrammars[i].regex),
&parsed_fields[kPhoneFieldGrammars[i].phone_part],
{log_manager, GetRegExpName(kPhoneFieldGrammars[i].regex)},
- is_country_code_field))
+ is_country_code_field,
+ GetJSONFieldType(kPhoneFieldGrammars[i].regex), page_language))
break;
if (kPhoneFieldGrammars[i].max_size &&
(!parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length ||
@@ -291,11 +292,13 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
if (!ParsePhoneField(scanner, kPhoneSuffixRe,
&phone_field->parsed_phone_fields_[FIELD_SUFFIX],
{log_manager, "kPhoneSuffixRe"},
- /*is_country_code_field=*/false)) {
+ /*is_country_code_field=*/false, "PHONE_SUFFIX",
+ page_language)) {
ParsePhoneField(scanner, kPhoneSuffixSeparatorRe,
&phone_field->parsed_phone_fields_[FIELD_SUFFIX],
{log_manager, "kPhoneSuffixSeparatorRe"},
- /*is_country_code_field=*/false);
+ /*is_country_code_field=*/false, "PHONE_SUFFIX_SEPARATOR",
+ page_language);
}
}
@@ -305,7 +308,8 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
ParsePhoneField(scanner, kPhoneExtensionRe,
&phone_field->parsed_phone_fields_[FIELD_EXTENSION],
{log_manager, "kPhoneExtensionRe"},
- /*is_country_code_field=*/false);
+ /*is_country_code_field=*/false, "PHONE_EXTENSION",
+ page_language);
return std::move(phone_field);
}
@@ -416,19 +420,52 @@ const char* PhoneField::GetRegExpName(RegexType regex_id) {
return "";
}
+//
+std::string PhoneField::GetJSONFieldType(RegexType phonetype_id) {
+ switch (phonetype_id) {
+ case REGEX_COUNTRY:
+ return "PHONE_COUNTRY_CODE";
+ case REGEX_AREA:
+ return "PHONE_AREA_CODE";
+ case REGEX_AREA_NOTEXT:
+ return "PHONE_AREA_CODE_NO_TEXT";
+ case REGEX_PHONE:
+ return "PHONE";
+ case REGEX_PREFIX_SEPARATOR:
+ return "PHONE_PREFIX_SEPARATOR";
+ case REGEX_PREFIX:
+ return "PHONE_PREFIX";
+ case REGEX_SUFFIX_SEPARATOR:
+ return "PHONE_SUFFIX_SEPARATOR";
+ case REGEX_SUFFIX:
+ return "PHONE_SUFFIX";
+ case REGEX_EXTENSION:
+ return "PHONE_EXTENSION";
+ default:
+ NOTREACHED();
+ break;
+ }
+ return std::string();
+}
+
// static
bool PhoneField::ParsePhoneField(AutofillScanner* scanner,
const std::string& regex,
AutofillField** field,
const RegExLogging& logging,
- const bool is_country_code_field) {
+ const bool is_country_code_field,
+ const std::string& json_field_type,
+ const std::string& 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);
+
return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(regex), match_type,
- field, logging);
+ patterns, field, logging);
}
} // namespace autofill
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 f0f39a3928f..6ac25f26693 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
@@ -17,6 +17,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#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"
namespace autofill {
@@ -96,12 +97,18 @@ class PhoneField : public FormField {
// This is useful for logging purposes.
static const char* GetRegExpName(RegexType regex_id);
+ // Returns the name of field type which indicated in JSON corresponding to
+ // |regex_id|.
+ static std::string GetJSONFieldType(RegexType phonetype_id);
+
// Convenient wrapper for ParseFieldSpecifics().
static bool ParsePhoneField(AutofillScanner* scanner,
const std::string& regex,
AutofillField** field,
const RegExLogging& logging,
- const bool is_country_code_field);
+ const bool is_country_code_field,
+ const std::string& json_field_type,
+ const std::string& 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 72469564fd3..71e0cf605c4 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
@@ -16,6 +16,7 @@
#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"
@@ -83,6 +84,9 @@ class PhoneFieldTest : public testing::Test {
std::vector<std::unique_ptr<AutofillField>> list_;
std::unique_ptr<PhoneField> field_;
FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
TEST_F(PhoneFieldTest, Empty) {
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 58079a2800f..595b759ad00 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
@@ -6,8 +6,8 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -16,10 +16,13 @@ std::unique_ptr<FormField> PriceField::Parse(AutofillScanner* scanner,
const std::string& page_language,
LogManager* log_manager) {
AutofillField* field;
+ auto& patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("PRICE", page_language);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kPriceRe),
MATCH_DEFAULT | MATCH_NUMBER | MATCH_SELECT |
MATCH_TEXT_AREA | MATCH_SEARCH,
- &field, {log_manager, kPriceRe})) {
+ 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 b3023982b57..7d05f460dae 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
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 9f6110de258..464830b2852 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
@@ -13,6 +13,7 @@
#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"
@@ -22,13 +23,11 @@ namespace autofill {
class PriceFieldTest : public testing::Test {
public:
- PriceFieldTest() {}
+ PriceFieldTest() = default;
+ PriceFieldTest(const PriceFieldTest&) = delete;
+ PriceFieldTest& operator=(const PriceFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<PriceField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<PriceField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -39,8 +38,12 @@ class PriceFieldTest : public testing::Test {
static_cast<PriceField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(PriceFieldTest);
+ 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) {
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 a2065dc0c30..a7564839f06 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
@@ -6,8 +6,8 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -16,9 +16,12 @@ std::unique_ptr<FormField> SearchField::Parse(AutofillScanner* scanner,
const std::string& page_language,
LogManager* log_manager) {
AutofillField* field;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ SEARCH_TERM, page_language);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kSearchTermRe),
MATCH_DEFAULT | MATCH_SEARCH | MATCH_TEXT_AREA,
- &field, {log_manager, "kSearchTermRe"})) {
+ patterns, &field, {log_manager, "kSearchTermRe"})) {
return std::make_unique<SearchField>(field);
}
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 71b2f70bb48..99e70eb9a2c 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
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 09148d51010..a6be80cc7e0 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
@@ -13,6 +13,7 @@
#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"
@@ -22,13 +23,11 @@ namespace autofill {
class SearchFieldTest : public testing::Test {
public:
- SearchFieldTest() {}
+ SearchFieldTest() = default;
+ SearchFieldTest(const SearchFieldTest&) = delete;
+ SearchFieldTest& operator=(const SearchFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<SearchField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<SearchField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -39,8 +38,12 @@ class SearchFieldTest : public testing::Test {
static_cast<SearchField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(SearchFieldTest);
+ 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) {
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 cf90e229903..2e1dc92a836 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
namespace autofill {
@@ -21,17 +21,25 @@ std::unique_ptr<FormField> TravelField::Parse(AutofillScanner* scanner,
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 =
+ PatternProvider::GetInstance().GetMatchPatterns("FLIGHT", page_language);
auto travel_field = std::make_unique<TravelField>();
- if (ParseField(scanner, base::UTF8ToUTF16(kPassportRe),
+ if (ParseField(scanner, base::UTF8ToUTF16(kPassportRe), patternsP,
&travel_field->passport_, {log_manager, "kPassportRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kTravelOriginRe),
+ ParseField(scanner, base::UTF8ToUTF16(kTravelOriginRe), patternsTO,
&travel_field->origin_, {log_manager, "kTravelOriginRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kTravelDestinationRe),
+ ParseField(scanner, base::UTF8ToUTF16(kTravelDestinationRe), patternsTD,
&travel_field->destination_,
{log_manager, "kTravelDestinationRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kFlightRe), &travel_field->flight_,
- {log_manager, "kFlightRe"})) {
+ ParseField(scanner, base::UTF8ToUTF16(kFlightRe), patternsF,
+ &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 8ac09a00df3..9b2d2e5e891 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
@@ -9,6 +9,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"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index ff7993d82e2..9bd72190efa 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -32,6 +32,8 @@
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/field_candidates.h"
@@ -45,8 +47,6 @@
#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_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.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"
@@ -56,6 +56,7 @@
#include "components/autofill/core/common/logging/log_buffer.h"
#include "components/autofill/core/common/signatures.h"
#include "components/security_state/core/security_state.h"
+#include "components/version_info/version_info.h"
#include "url/origin.h"
namespace autofill {
@@ -64,8 +65,6 @@ using mojom::SubmissionIndicatorEvent;
namespace {
-// Version of the client sent to the server.
-constexpr char kClientVersion[] = "6.1.1715.1442/en (GGLL)";
constexpr char kBillingMode[] = "billing";
constexpr char kShippingMode[] = "shipping";
@@ -705,7 +704,8 @@ bool FormStructure::EncodeUploadRequest(
encoded_signatures->clear();
upload->set_submission(observed_submission);
- upload->set_client_version(kClientVersion);
+ upload->set_client_version(
+ version_info::GetProductNameAndVersionForUserAgent());
upload->set_form_signature(form_signature().value());
upload->set_autofill_used(form_was_autofilled);
upload->set_data_present(EncodeFieldTypes(available_field_types));
@@ -763,7 +763,8 @@ bool FormStructure::EncodeQueryRequest(
queried_form_signatures->clear();
queried_form_signatures->reserve(forms.size());
- query->set_client_version(kClientVersion);
+ query->set_client_version(
+ version_info::GetProductNameAndVersionForUserAgent());
// If a page contains repeated forms, detect that and encode only one form as
// the returned data would be the same for all the repeated forms.
@@ -889,7 +890,6 @@ void FormStructure::ProcessQueryResponse(
form->UpdateAutofillCount();
form->RationalizeRepeatedFields(form_interactions_ukm_logger);
form->RationalizeFieldTypePredictions();
- form->OverrideServerPredictionsWithHeuristics();
form->IdentifySections(false);
}
@@ -956,8 +956,8 @@ std::string FormStructure::FormSignatureAsStr() const {
bool FormStructure::IsAutofillable() const {
size_t min_required_fields =
- std::min({MinRequiredFieldsForHeuristics(), MinRequiredFieldsForQuery(),
- MinRequiredFieldsForUpload()});
+ std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
+ kMinRequiredFieldsForUpload});
if (autofill_count() < min_required_fields)
return false;
@@ -999,8 +999,8 @@ bool FormStructure::ShouldBeParsed(LogManager* log_manager) const {
}
size_t min_required_fields =
- std::min({MinRequiredFieldsForHeuristics(), MinRequiredFieldsForQuery(),
- MinRequiredFieldsForUpload()});
+ std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
+ kMinRequiredFieldsForUpload});
if (active_field_count() < min_required_fields &&
(!all_fields_are_passwords() ||
active_field_count() < kRequiredFieldsForFormsWithOnlyPasswordFields) &&
@@ -1040,7 +1040,7 @@ bool FormStructure::ShouldBeParsed(LogManager* log_manager) const {
}
bool FormStructure::ShouldRunHeuristics() const {
- return active_field_count() >= MinRequiredFieldsForHeuristics() &&
+ return active_field_count() >= kMinRequiredFieldsForHeuristics &&
HasAllowedScheme(source_url_) &&
(is_form_tag_ || is_formless_checkout_ ||
!base::FeatureList::IsEnabled(
@@ -1049,12 +1049,12 @@ bool FormStructure::ShouldRunHeuristics() const {
bool FormStructure::ShouldBeQueried() const {
return (has_password_field_ ||
- active_field_count() >= MinRequiredFieldsForQuery()) &&
+ active_field_count() >= kMinRequiredFieldsForQuery) &&
ShouldBeParsed();
}
bool FormStructure::ShouldBeUploaded() const {
- return active_field_count() >= MinRequiredFieldsForUpload() &&
+ return active_field_count() >= kMinRequiredFieldsForUpload &&
ShouldBeParsed();
}
@@ -1062,37 +1062,21 @@ void FormStructure::RetrieveFromCache(
const FormStructure& cached_form,
const bool should_keep_cached_value,
const bool only_server_and_autofill_state) {
- // TODO(crbug/1101631) Clean up once the experiment is over.
- const bool kUseRendererIds = base::FeatureList::IsEnabled(
- features::kAutofillRetrieveFromCacheWithRendererIds);
- std::map<base::string16, const AutofillField*> cached_fields_by_name;
std::map<FieldRendererId, const AutofillField*> cached_fields_by_id;
for (size_t i = 0; i < cached_form.field_count(); ++i) {
auto* const field = cached_form.field(i);
- if (kUseRendererIds)
- cached_fields_by_id[field->unique_renderer_id] = field;
- else
- cached_fields_by_name[field->unique_name()] = field;
+ cached_fields_by_id[field->unique_renderer_id] = field;
}
for (auto& field : *this) {
const AutofillField* cached_field = nullptr;
- if (kUseRendererIds) {
- const auto& it = cached_fields_by_id.find(field->unique_renderer_id);
- if (it != cached_fields_by_id.end())
- cached_field = it->second;
- } else {
- const auto& it = cached_fields_by_name.find(field->unique_name());
- if (it != cached_fields_by_name.end())
- cached_field = it->second;
- }
+ const auto& it = cached_fields_by_id.find(field->unique_renderer_id);
+ if (it != cached_fields_by_id.end())
+ cached_field = it->second;
// If the unique renderer id (or the name) is not stable due to some Java
// Script magic in the website, use the field signature as a fallback
// solution to find the field in the cached form.
- // TODO(crbug.com/1125624): Remove feature check once trial ended.
- if (!cached_field &&
- base::FeatureList::IsEnabled(
- features::kAutofillRetrieveFromCacheWithFieldSignatureAsFallback)) {
+ if (!cached_field) {
// Iterates over the fields to find the field with the same form
// signature.
for (size_t i = 0; i < cached_form.field_count(); ++i) {
@@ -1125,24 +1109,16 @@ void FormStructure::RetrieveFromCache(
field->is_autofilled = cached_field->is_autofilled;
}
if (field->form_control_type != "select-one") {
- bool is_credit_card_field =
- AutofillType(cached_field->Type().GetStorableType()).group() ==
- CREDIT_CARD;
- if (should_keep_cached_value &&
- (is_credit_card_field ||
- base::FeatureList::IsEnabled(
- features::kAutofillKeepInitialFormValuesInCache))) {
+ if (should_keep_cached_value) {
field->value = cached_field->value;
value_from_dynamic_change_form_ = true;
} else if (field->value == cached_field->value &&
- (!base::FeatureList::IsEnabled(
- features::
- kAutofillImportPrefilledCountryAndStateValues) ||
- (field->server_type() != ADDRESS_HOME_COUNTRY &&
- field->server_type() != ADDRESS_HOME_STATE))) {
- // TODO(crbug.com/1100231): Remove feature check once launched.
+ (field->server_type() != ADDRESS_HOME_COUNTRY &&
+ field->server_type() != ADDRESS_HOME_STATE)) {
// From the perspective of learning user data, text fields containing
// default values are equivalent to empty fields.
+ // Since a website can prefill country and state values basedw on
+ // GeoIp, the mechanism is deactivated for state and country fields.
field->value = base::string16();
}
}
@@ -1242,8 +1218,8 @@ void FormStructure::LogQualityMetrics(
// submission event.
if (observed_submission) {
AutofillMetrics::AutofillFormSubmittedState state;
- if (num_detected_field_types < MinRequiredFieldsForHeuristics() &&
- num_detected_field_types < MinRequiredFieldsForQuery()) {
+ if (num_detected_field_types < kMinRequiredFieldsForHeuristics &&
+ num_detected_field_types < kMinRequiredFieldsForQuery) {
state = AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA;
} else {
if (did_autofill_all_possible_fields) {
@@ -1871,27 +1847,6 @@ void FormStructure::RationalizeAddressStateCountry(
}
}
-void FormStructure::OverrideServerPredictionsWithHeuristics() {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames) &&
- !base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInAddresses)) {
- return;
- }
- for (const auto& field : fields_) {
- switch (field->heuristic_type()) {
- case NAME_LAST_SECOND:
- case NAME_LAST_FIRST:
- case ADDRESS_HOME_STREET_NAME:
- case ADDRESS_HOME_HOUSE_NUMBER:
- field->SetTypeTo(AutofillType(field->heuristic_type()));
- break;
- default: {
- };
- }
- }
-}
-
void FormStructure::RationalizeRepeatedFields(
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
// The type of every field whose index is in
@@ -2090,9 +2045,21 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
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();
+ }
+ };
+
if (!has_author_specified_sections || is_enabled_autofill_new_sectioning) {
- // Name sections after the first field in the section.
- base::string16 current_section = fields_.front()->unique_name();
+ 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;
@@ -2214,7 +2181,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
}
// The end of a section, so start a new section.
- current_section = field->unique_name();
+ current_section = get_section_name(*field);
if (is_enabled_autofill_new_sectioning) {
// The section described in the autocomplete section attribute
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index a18c4d9b581..58a8a8d48dc 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -25,7 +25,6 @@
#include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/renderer_id.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -399,11 +398,12 @@ class FormStructure {
private:
friend class AutofillMergeTest;
friend class FormStructureTestImpl;
+ friend class ParameterizedFormStructureTest;
FRIEND_TEST_ALL_PREFIXES(AutofillDownloadTest, QueryAndUploadTest);
FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl, FindLongestCommonPrefix);
FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl, FindLongestCommonAffixLength);
FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl, IsValidParseableName);
- FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl,
+ FRIEND_TEST_ALL_PREFIXES(ParameterizedFormStructureTest,
RationalizePhoneNumber_RunsOncePerSection);
class SectionedFieldsIndexes {
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 6125363ecb2..4e894075277 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -19,27 +19,26 @@
#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"
#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/autofill/core/common/password_form.h"
#include "components/autofill/core/common/signatures.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/version_info/version_info.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using base::ASCIIToUTF16;
+using version_info::GetProductNameAndVersionForUserAgent;
namespace autofill {
-using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
-using features::kAutofillEnforceMinRequiredFieldsForQuery;
-using features::kAutofillEnforceMinRequiredFieldsForUpload;
using features::kAutofillLabelAffixRemoval;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
@@ -90,74 +89,22 @@ class FormStructureTestImpl : public test::FormStructureTest {
feature_list->InitAndDisableFeature(feature);
}
- // Single field forms are not parseable iff all of the minimum required field
- // values are enforced.
- void CheckFormShouldBeParsed(const char* trace_message,
- const FormData form,
- bool expected_if_all_enforced,
- bool expected_if_not_all_enforced) {
- SCOPED_TRACE(trace_message);
- for (bool enforce_min_for_heuristics : {true, false}) {
- base::test::ScopedFeatureList heuristics, query, upload;
- InitFeature(&heuristics, kAutofillEnforceMinRequiredFieldsForHeuristics,
- enforce_min_for_heuristics);
- for (bool enforce_min_for_query : {true, false}) {
- base::test::ScopedFeatureList heuristics, query, upload;
- InitFeature(&query, kAutofillEnforceMinRequiredFieldsForQuery,
- enforce_min_for_query);
- for (bool enforce_min_for_upload : {true, false}) {
- base::test::ScopedFeatureList heuristics, query, upload;
- InitFeature(&upload, kAutofillEnforceMinRequiredFieldsForUpload,
- enforce_min_for_upload);
- bool all_enforced = enforce_min_for_heuristics &&
- enforce_min_for_query && enforce_min_for_upload;
- FormStructure form_structure(form);
- if (all_enforced) {
- EXPECT_EQ(expected_if_all_enforced,
- form_structure.ShouldBeParsed());
- } else {
- EXPECT_EQ(expected_if_not_all_enforced,
- form_structure.ShouldBeParsed())
- << "heuristics:" << enforce_min_for_heuristics << "; "
- << "query:" << enforce_min_for_query << "; "
- << "upload:" << enforce_min_for_upload;
- }
- }
- }
- }
+ bool FormShouldBeParsed(const FormData form) {
+ return FormStructure(form).ShouldBeParsed();
}
- bool FormIsAutofillable(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForHeuristics,
- enforce_min_fields);
+ bool FormIsAutofillable(const FormData& form) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
return form_structure.IsAutofillable();
}
- bool FormShouldRunHeuristics(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForHeuristics,
- enforce_min_fields);
- FormStructure form_structure(form);
- return form_structure.ShouldRunHeuristics();
+ bool FormShouldRunHeuristics(const FormData& form) {
+ return FormStructure(form).ShouldRunHeuristics();
}
- bool FormShouldBeQueried(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForQuery,
- enforce_min_fields);
- FormStructure form_structure(form);
- return form_structure.ShouldBeQueried();
- }
-
- bool FormShouldBeUploaded(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForUpload,
- enforce_min_fields);
- FormStructure form_structure(form);
- return form_structure.ShouldBeUploaded();
+ bool FormShouldBeQueried(const FormData& form) {
+ return FormStructure(form).ShouldBeQueried();
}
void DisableAutofillMetadataFieldTrial() {
@@ -175,6 +122,13 @@ class FormStructureTestImpl : public test::FormStructureTest {
{});
}
+ FieldRendererId MakeFieldRendererId() {
+ return FieldRendererId(++id_counter_);
+ }
+
+ protected:
+ TestPatternProvider test_pattern_provider_;
+
private:
void EnableAutofillMetadataFieldTrial() {
scoped_feature_list_.Reset();
@@ -184,6 +138,7 @@ class FormStructureTestImpl : public test::FormStructureTest {
field_trial_->group();
}
+ uint32_t id_counter_ = 10;
base::test::ScopedFeatureList scoped_feature_list_;
scoped_refptr<base::FieldTrial> field_trial_;
};
@@ -277,62 +232,60 @@ TEST_F(FormStructureTestImpl, IsAutofillable) {
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// With min required fields enabled.
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_FALSE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// Add a password field. The form should be picked up by the password but
// not by autofill.
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_FALSE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// Add an auto-fillable fields. With just one auto-fillable field, this should
// be picked up by autofill only if there is no minimum field enforcement.
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullname");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// Add an auto-fillable fields. With just one auto-fillable field, this should
// be picked up by autofill only if there is no minimum field enforcement.
field.label = ASCIIToUTF16("Address Line 1");
field.name = ASCIIToUTF16("address1");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// We now have three auto-fillable fields. It's always autofillable.
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_TRUE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_TRUE(FormIsAutofillable(form));
// The target cannot include http(s)://*/search...
form.action = GURL("http://google.com/search?q=hello");
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_FALSE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// But search can be in the URL.
form.action = GURL("http://search.com/?q=hello");
- EXPECT_TRUE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_TRUE(FormIsAutofillable(form));
}
TEST_F(FormStructureTestImpl, ShouldBeParsed) {
@@ -345,51 +298,56 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed) {
FormFieldData::CheckStatus::kCheckableButUnchecked;
checkable_field.name = ASCIIToUTF16("radiobtn");
checkable_field.form_control_type = "radio";
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
// A form with a single checkable field isn't interesting.
- CheckFormShouldBeParsed("one checkable", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "one checkable";
// Add a second checkable field.
checkable_field.name = ASCIIToUTF16("checkbox");
checkable_field.form_control_type = "checkbox";
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
// A form with a only checkable fields isn't interesting.
- CheckFormShouldBeParsed("two checkable", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "two checkable";
// Add a text field.
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);
// Single text field forms shouldn't be parsed if all of the minimums are
// enforced but should be parsed if ANY of the minimums is not enforced.
- CheckFormShouldBeParsed("username", form, false, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "username";
// We now have three text fields, though only two are auto-fillable.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Three text field forms should always be parsed.
- CheckFormShouldBeParsed("three field", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "three field";
// The target cannot include http(s)://*/search...
form.action = GURL("http://google.com/search?q=hello");
- CheckFormShouldBeParsed("search path", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "search path";
// But search can be in the URL.
form.action = GURL("http://search.com/?q=hello");
- CheckFormShouldBeParsed("search domain", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "search domain";
// The form need only have three fields, but at least one must be a text
// field.
@@ -398,38 +356,43 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed) {
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
field.form_control_type = "select-one";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.form_control_type = "select-one";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- CheckFormShouldBeParsed("text + selects", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "text + selects";
// Now, no text fields.
form.fields[0].form_control_type = "select-one";
- CheckFormShouldBeParsed("only selects", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "only selects";
// We have only one field, which is password.
form.fields.clear();
field.label = ASCIIToUTF16("Password");
field.name = ASCIIToUTF16("pw");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- CheckFormShouldBeParsed("password", form, false, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "password";
// We have two fields, which are passwords, should be parsed.
field.label = ASCIIToUTF16("New password");
field.name = ASCIIToUTF16("new_pw");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- CheckFormShouldBeParsed("new password", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "new password";
}
TEST_F(FormStructureTestImpl, ShouldBeParsed_BadScheme) {
@@ -441,18 +404,21 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed_BadScheme) {
field.name = ASCIIToUTF16("name");
field.form_control_type = "text";
field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
field.autocomplete_attribute = "address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Baseline, HTTP should work.
@@ -522,12 +488,14 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed_TwoFields_HasAutocomplete) {
field.name = ASCIIToUTF16("name");
field.form_control_type = "name";
field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("Address");
field.form_control_type = "select-one";
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1115,39 +1083,20 @@ TEST_F(FormStructureTestImpl,
FormFieldData field;
field.form_control_type = "text";
+
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormShouldRunHeuristics(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldRunHeuristics(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormShouldRunHeuristics(form));
- EXPECT_FALSE(FormShouldBeQueried(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldBeQueried(form, false)); // Min not enforced.
-
- // Status Quo (Q3/2017) - Small forms not supported.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload},
- // Disabled.
- {});
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(0U, form_structure.autofill_count());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_FALSE(form_structure.IsAutofillable());
- }
+ EXPECT_TRUE(FormShouldBeQueried(form));
// Default configuration.
{
@@ -1161,22 +1110,6 @@ TEST_F(FormStructureTestImpl,
EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_FALSE(form_structure.IsAutofillable());
}
-
- // Enable small form heuristics.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(2U, form_structure.autofill_count());
- EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(NAME_LAST, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_TRUE(form_structure.IsAutofillable());
- }
}
// Tests the heuristics and server predictions are not run for forms with less
@@ -1194,65 +1127,23 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.autocomplete_attribute = "given-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormShouldRunHeuristics(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldRunHeuristics(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormShouldRunHeuristics(form));
- EXPECT_FALSE(FormShouldBeQueried(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldBeQueried(form, false)); // Min not enforced.
-
- // Status Quo (Q3/2017) - Small forms not supported.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload},
- // Disabled.
- {});
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(1U, form_structure.autofill_count());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_FALSE(form_structure.IsAutofillable());
- }
-
- // Enable small form heuristics.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(2U, form_structure.autofill_count());
- EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(NAME_LAST, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_EQ(NAME_FIRST, form_structure.field(0)->Type().GetStorableType());
- EXPECT_EQ(NAME_LAST, form_structure.field(1)->Type().GetStorableType());
- EXPECT_TRUE(form_structure.IsAutofillable());
- }
+ EXPECT_TRUE(FormShouldBeQueried(form));
// As a side effect of parsing small forms (if any of the heuristics, query,
// or upload minimmums are disabled, we'll autofill fields with an
// autocomplete attribute, even if its the only field in the form.
{
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForUpload);
FormData form_copy = form;
form_copy.fields.pop_back();
FormStructure form_structure(form_copy);
@@ -1280,20 +1171,24 @@ TEST_F(FormStructureTestImpl, PasswordFormShouldBeQueried) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.autocomplete_attribute = "username";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Password");
field.name = ASCIIToUTF16("Password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1315,28 +1210,37 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributeWithSections) {
// Some fields will have no section specified. These fall into the default
// section.
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// We allow arbitrary section names.
field.autocomplete_attribute = "section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// "shipping" and "billing" are special section tokens that don't require the
// "section-" prefix.
field.autocomplete_attribute = "shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "billing email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// "shipping" and "billing" can be combined with other section names.
field.autocomplete_attribute = "section-foo shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "section-foo billing email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// We don't do anything clever to try to coalesce sections; it's up to site
// authors to avoid typos.
field.autocomplete_attribute = "section--foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// "shipping email" and "section--shipping" email should be parsed as
@@ -1344,10 +1248,12 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributeWithSections) {
// implement implicit section names from attributes like "shipping email"; see
// the implementation for more details.
field.autocomplete_attribute = "section--shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Credit card fields are implicitly in a separate section from other fields.
field.autocomplete_attribute = "section-foo cc-number";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1380,20 +1286,29 @@ TEST_F(FormStructureTestImpl,
// Some fields will have no section specified. These fall into the default
// section.
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Specifying "section-" is equivalent to not specifying a section.
field.autocomplete_attribute = "section- email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Invalid tokens should prevent us from setting a section name.
field.autocomplete_attribute = "garbage section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "garbage section-bar email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "garbage shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "garbage billing email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1423,8 +1338,11 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "text";
field.autocomplete_attribute = "section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "section-foo address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1455,15 +1373,22 @@ TEST_F(FormStructureTestImpl,
field.name = ASCIIToUTF16("one");
field.autocomplete_attribute = "address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.name = base::string16();
field.autocomplete_attribute = "section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.name = base::string16();
field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.name = ASCIIToUTF16("two");
field.autocomplete_attribute = "address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1491,43 +1416,53 @@ TEST_F(FormStructureTestImpl, HeuristicsSample8) {
field.label = ASCIIToUTF16("Your First Name:");
field.name = ASCIIToUTF16("bill.first");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Your Last Name:");
field.name = ASCIIToUTF16("bill.last");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Street Address Line 1:");
field.name = ASCIIToUTF16("bill.street1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Street Address Line 2:");
field.name = ASCIIToUTF16("bill.street2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("bill.city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State (U.S.):");
field.name = ASCIIToUTF16("bill.state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Zip/Postal Code:");
field.name = ASCIIToUTF16("BillTo.PostalCode");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country:");
field.name = ASCIIToUTF16("bill.country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone Number:");
field.name = ASCIIToUTF16("BillTo.Phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1569,32 +1504,39 @@ TEST_F(FormStructureTestImpl, HeuristicsSample6) {
field.label = ASCIIToUTF16("E-mail address");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full name");
field.name = ASCIIToUTF16("name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Company");
field.name = ASCIIToUTF16("company");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Zip Code");
field.name = ASCIIToUTF16("Home.PostalCode");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.value = ASCIIToUTF16("continue");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1632,35 +1574,43 @@ TEST_F(FormStructureTestImpl, HeuristicsLabelsOnly) {
field.label = ASCIIToUTF16("First Name");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Zip code");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1698,27 +1648,33 @@ TEST_F(FormStructureTestImpl, HeuristicsCreditCardInfo) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Month");
field.name = ASCIIToUTF16("ccmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Year");
field.name = ASCIIToUTF16("ccyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Verification");
field.name = ASCIIToUTF16("verification");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1753,33 +1709,40 @@ TEST_F(FormStructureTestImpl, HeuristicsCreditCardInfoWithUnknownCardField) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// This is not a field we know how to process. But we should skip over it
// and process the other fields in the card block.
field.label = ASCIIToUTF16("Card image");
field.name = ASCIIToUTF16("card_image");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Month");
field.name = ASCIIToUTF16("ccmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Year");
field.name = ASCIIToUTF16("ccyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Verification");
field.name = ASCIIToUTF16("verification");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1816,18 +1779,22 @@ TEST_F(FormStructureTestImpl, ThreeAddressLines) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line2");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line3");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1857,18 +1824,22 @@ TEST_F(FormStructureTestImpl, SurplusAddressLinesIgnored) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("shipping.address.addressLine1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line2");
field.name = ASCIIToUTF16("shipping.address.addressLine2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line3");
field.name = ASCIIToUTF16("billing.address.addressLine3");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line4");
field.name = ASCIIToUTF16("billing.address.addressLine4");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1901,18 +1872,22 @@ TEST_F(FormStructureTestImpl, ThreeAddressLinesExpedia) {
field.label = ASCIIToUTF16("Street:");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Suite or Apt:");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adap");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Street address second line");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City:");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adct");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1944,14 +1919,17 @@ TEST_F(FormStructureTestImpl, TwoAddressLinesEbay) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("address1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Floor number, suite number, etc");
field.name = ASCIIToUTF16("address2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City:");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1978,14 +1956,17 @@ TEST_F(FormStructureTestImpl, HeuristicsStateWithProvince) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line2");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State/Province/Region");
field.name = ASCIIToUTF16("State");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2013,46 +1994,57 @@ TEST_F(FormStructureTestImpl, HeuristicsWithBilling) {
field.label = ASCIIToUTF16("First Name*:");
field.name = ASCIIToUTF16("editBillingAddress$firstNameBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name*:");
field.name = ASCIIToUTF16("editBillingAddress$lastNameBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Company Name:");
field.name = ASCIIToUTF16("editBillingAddress$companyBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address*:");
field.name = ASCIIToUTF16("editBillingAddress$addressLine1Box");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Apt/Suite :");
field.name = ASCIIToUTF16("editBillingAddress$addressLine2Box");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City*:");
field.name = ASCIIToUTF16("editBillingAddress$cityBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State/Province*:");
field.name = ASCIIToUTF16("editBillingAddress$stateDropDown");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country*:");
field.name = ASCIIToUTF16("editBillingAddress$countryDropDown");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Postal Code*:");
field.name = ASCIIToUTF16("editBillingAddress$zipCodeBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone*:");
field.name = ASCIIToUTF16("editBillingAddress$phoneBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email Address*:");
field.name = ASCIIToUTF16("email$emailBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2086,11 +2078,13 @@ TEST_F(FormStructureTestImpl, ThreePartPhoneNumber) {
field.label = ASCIIToUTF16("Phone:");
field.name = ASCIIToUTF16("dayphone1");
field.max_length = 0;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("-");
field.name = ASCIIToUTF16("dayphone2");
field.max_length = 3; // Size of prefix is 3.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("-");
@@ -2098,11 +2092,13 @@ TEST_F(FormStructureTestImpl, ThreePartPhoneNumber) {
field.max_length = 4; // Size of suffix is 4. If unlimited size is
// passed, phone will be parsed as
// <country code> - <area code> - <phone>.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("ext.:");
field.name = ASCIIToUTF16("dayphone4");
field.max_length = 0;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2131,22 +2127,27 @@ TEST_F(FormStructureTestImpl, HeuristicsInfernoCC) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("billing_address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("expiration_month");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Year");
field.name = ASCIIToUTF16("expiration_year");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2182,26 +2183,32 @@ TEST_F(FormStructureTestImpl, HeuristicsInferCCNames_NamesNotFirst) {
field.label = ASCIIToUTF16("Card number");
field.name = ASCIIToUTF16("ccnumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("First name");
field.name = ASCIIToUTF16("first_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last name");
field.name = ASCIIToUTF16("last_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration date");
field.name = ASCIIToUTF16("ccexpiresmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("ccexpiresyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("cvc number");
field.name = ASCIIToUTF16("csc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2241,26 +2248,32 @@ TEST_F(FormStructureTestImpl, HeuristicsInferCCNames_NamesFirst) {
field.label = ASCIIToUTF16("Cardholder Name");
field.name = ASCIIToUTF16("cc_first_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last name");
field.name = ASCIIToUTF16("last_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card number");
field.name = ASCIIToUTF16("ccnumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration date");
field.name = ASCIIToUTF16("ccexpiresmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("ccexpiresyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("cvc number");
field.name = ASCIIToUTF16("csc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2296,22 +2309,27 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("billing_address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("expiration_month");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Year");
field.name = ASCIIToUTF16("expiration_year");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2320,7 +2338,9 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
FormFieldData::CheckStatus::kCheckableButUnchecked;
checkable_field.label = ASCIIToUTF16("Checkable1");
checkable_field.name = ASCIIToUTF16("Checkable1");
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
+
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
@@ -2331,7 +2351,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
// Prepare the expected proto string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -2379,6 +2399,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
for (size_t i = 0; i < 5; ++i) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
@@ -2441,6 +2462,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
for (size_t i = 0; i < 300; ++i) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
malformed_form.fields.push_back(field);
}
@@ -2568,6 +2590,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
@@ -2575,6 +2598,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -2583,6 +2607,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS},
{AutofillProfile::INVALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -2591,6 +2616,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER}, {AutofillProfile::EMPTY});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -2599,6 +2625,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2610,6 +2637,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2640,7 +2668,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -2699,6 +2727,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
@@ -2767,6 +2796,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
@@ -2774,6 +2804,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -2782,6 +2813,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS},
{AutofillProfile::INVALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -2790,6 +2822,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER}, {AutofillProfile::EMPTY});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -2798,6 +2831,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2809,6 +2843,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2839,7 +2874,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -2899,6 +2934,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST},
{AutofillProfile::UNVALIDATED, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
@@ -2906,6 +2942,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST},
{AutofillProfile::UNVALIDATED, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -2914,6 +2951,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS},
{AutofillProfile::INVALID, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -2923,6 +2961,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
possible_field_types, possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER},
{AutofillProfile::EMPTY, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -2931,6 +2970,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2942,6 +2982,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID, AutofillProfile::VALID});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2972,7 +3013,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -3030,12 +3071,14 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.name = ASCIIToUTF16("firstname");
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -3043,6 +3086,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.form_control_type = "email";
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -3051,6 +3095,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -3059,6 +3104,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{ADDRESS_HOME_COUNTRY});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -3070,6 +3116,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{ADDRESS_HOME_COUNTRY});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -3106,7 +3153,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
AutofillUploadContents upload;
upload.set_submission(true);
upload.set_submission_event(AutofillUploadContents::HTML_FORM_SUBMISSION);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -3159,6 +3206,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
@@ -3216,6 +3264,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
@@ -3254,35 +3303,45 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.autocomplete_attribute = "given-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.autocomplete_attribute = "family-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {USERNAME});
+
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{ACCOUNT_CREATION_PASSWORD});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3316,7 +3375,7 @@ TEST_F(FormStructureTestImpl,
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440000000000000000802");
@@ -3383,22 +3442,28 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.autocomplete_attribute = "given-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.autocomplete_attribute = "family-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3419,7 +3484,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3473,9 +3538,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
field.autocomplete_attribute = "given-name";
field.css_classes = ASCIIToUTF16("class1 class2");
field.properties_mask = FieldPropertiesFlags::kHadFocus;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
@@ -3484,9 +3551,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
field.css_classes = ASCIIToUTF16("class1 class2");
field.properties_mask =
FieldPropertiesFlags::kHadFocus | FieldPropertiesFlags::kUserTyped;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
@@ -3496,9 +3565,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
field.css_classes = ASCIIToUTF16("class1 class2");
field.properties_mask =
FieldPropertiesFlags::kHadFocus | FieldPropertiesFlags::kUserTyped;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3519,7 +3590,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3571,22 +3642,28 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
field.form_control_type = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3607,7 +3684,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(false);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3653,17 +3730,23 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
field.form_control_type = "text";
// No label for the first field.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3684,7 +3767,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3725,19 +3808,25 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithCssClassesAndIds) {
FormFieldData field;
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.css_classes = ASCIIToUTF16("last_name_field");
field.id_attribute = ASCIIToUTF16("lastname_id");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.css_classes = ASCIIToUTF16("email_field required_field");
field.id_attribute = ASCIIToUTF16("email_id");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3758,7 +3847,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithCssClassesAndIds) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3814,12 +3903,17 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
FormFieldData field;
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
@@ -3845,7 +3939,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3894,22 +3988,28 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
// Some fields don't have "name" or "autocomplete" attributes, and some have
// neither.
// No label.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
field.autocomplete_attribute = "family-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.form_control_type = "email";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3930,7 +4030,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3984,18 +4084,22 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
field.id_attribute = ASCIIToUTF16("first_name");
field.autocomplete_attribute = "given-name";
field.css_classes = ASCIIToUTF16("class1 class2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
field.id_attribute = ASCIIToUTF16("last_name");
field.autocomplete_attribute = "family-name";
field.css_classes = ASCIIToUTF16("class1 class2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
@@ -4003,9 +4107,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
field.form_control_type = "email";
field.autocomplete_attribute = "email";
field.css_classes = ASCIIToUTF16("class1 class2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -4026,7 +4132,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -4069,16 +4175,19 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("first");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("last");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4103,7 +4212,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure.form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("");
@@ -4355,6 +4464,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
@@ -4362,6 +4472,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("first");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
@@ -4369,6 +4480,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("last");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
@@ -4376,6 +4488,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
@@ -4392,7 +4505,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("1440000360000008");
@@ -4500,14 +4613,17 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_PasswordsRevealed) {
FormFieldData field;
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.name = ASCIIToUTF16("first");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.name = ASCIIToUTF16("last");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4529,6 +4645,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_IsFormTag) {
form.url = GURL("http://www.foo.com/");
FormFieldData field;
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form.is_form_tag = is_form_tag;
@@ -4581,6 +4698,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) {
field.aria_label = ASCIIToUTF16(f.aria_label);
field.aria_description = ASCIIToUTF16(f.aria_description);
field.css_classes = ASCIIToUTF16(f.css_classes);
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
RandomizedEncoder encoder("seed for testing",
@@ -4722,6 +4840,7 @@ TEST_F(FormStructureTestImpl, Metadata_OnlySendFullUrlWithUserConsent) {
field.form_control_type = "text";
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
TestingPrefServiceSimple prefs;
@@ -4755,10 +4874,12 @@ TEST_F(FormStructureTestImpl, CheckFormSignature) {
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("first");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Checkable fields shouldn't affect the signature.
@@ -4766,6 +4887,7 @@ TEST_F(FormStructureTestImpl, CheckFormSignature) {
field.name = ASCIIToUTF16("Select");
field.form_control_type = "checkbox";
field.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -4796,16 +4918,24 @@ TEST_F(FormStructureTestImpl, CheckFormSignature) {
field.label = ASCIIToUTF16("Random Field label");
field.name = ASCIIToUTF16("random1234");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Random Field label2");
field.name = ASCIIToUTF16("random12345");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Random Field label3");
field.name = ASCIIToUTF16("1ran12dom12345678");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Random Field label3");
field.name = ASCIIToUTF16("12345ran123456dom123");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
form_structure = std::make_unique<FormStructure>(form);
EXPECT_EQ(FormStructureTestImpl::Hash64Bit(
std::string("https://login.facebook.com&login_form&email&first&"
@@ -4823,16 +4953,19 @@ TEST_F(FormStructureTestImpl, ToFormData) {
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 = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
EXPECT_TRUE(form.SameFormAs(FormStructure(form).ToFormData()));
@@ -4848,18 +4981,21 @@ TEST_F(FormStructureTestImpl, SkipFieldTest) {
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 = ASCIIToUTF16("select");
field.name = ASCIIToUTF16("select");
field.form_control_type = "checkbox";
field.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("email");
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);
@@ -4870,7 +5006,7 @@ TEST_F(FormStructureTestImpl, SkipFieldTest) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -4903,16 +5039,19 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLabels) {
// No label on the first field.
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Enter your Email address");
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Enter your Password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
std::vector<FormStructure*> forms;
@@ -4923,7 +5062,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLabels) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -4954,6 +5093,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
// No label on the first field.
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// This label will be truncated in the XML request.
@@ -4964,11 +5104,13 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
"Exceeding A Certain Number Of Characters...");
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Enter your Password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4979,7 +5121,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -5011,6 +5153,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
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();
@@ -5018,6 +5161,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
field.name = ASCIIToUTF16("");
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);
@@ -5029,7 +5173,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -5065,12 +5209,14 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_DisabledMetadataTrial) {
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);
@@ -5081,7 +5227,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_DisabledMetadataTrial) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -5115,7 +5261,9 @@ TEST_F(FormStructureTestImpl, PossibleValues) {
field.option_values.push_back(ASCIIToUTF16(""));
field.option_contents.push_back(ASCIIToUTF16("Germany"));
field.option_values.push_back(ASCIIToUTF16("GRMNY"));
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
+
FormStructure form_structure(form_data);
form_structure.ParseFieldTypesFromAutocompleteAttributes();
@@ -5138,7 +5286,9 @@ TEST_F(FormStructureTestImpl, PossibleValues) {
// A freeform input (<input>) allows any value (overriding other <select>s).
FormFieldData freeform_field;
freeform_field.autocomplete_attribute = "billing country";
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(freeform_field);
+
FormStructure form_structure2(form_data);
form_structure2.ParseFieldTypesFromAutocompleteAttributes();
EXPECT_EQ(0U, form_structure2.PossibleValues(ADDRESS_BILLING_COUNTRY).size());
@@ -5395,15 +5545,18 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_UnknownType) {
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);
@@ -5454,10 +5607,12 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
field.label = ASCIIToUTF16("fullname");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Checkable fields should be ignored in parsing
@@ -5466,6 +5621,7 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
checkable_field.form_control_type = "radio";
checkable_field.check_status =
FormFieldData::CheckStatus::kCheckableButUnchecked;
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
FormStructure form_structure(form);
@@ -5476,11 +5632,13 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
FormData form2;
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form2.fields.push_back(field);
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form2.fields.push_back(field);
FormStructure form_structure2(form2);
@@ -5545,6 +5703,7 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "email";
field.label = ASCIIToUTF16("emailaddress");
field.name = ASCIIToUTF16("emailaddress");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add form to the vector needed by the response parsing function.
@@ -5574,6 +5733,7 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponseWhenPayloadNotBase64) {
field.form_control_type = "email";
field.label = ASCIIToUTF16("emailaddress");
field.name = ASCIIToUTF16("emailaddress");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add form to the vector needed by the response parsing function.
@@ -5615,12 +5775,14 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_AuthorDefinedTypes) {
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
field.autocomplete_attribute = "new-password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5656,18 +5818,22 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeLoneField) {
field.label = ASCIIToUTF16("fullname");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("height");
field.name = ASCIIToUTF16("height");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5703,14 +5869,17 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeCCName) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("fname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5745,22 +5914,27 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeMultiMonth_1) {
field.label = ASCIIToUTF16("Cardholder");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Month)");
field.name = ASCIIToUTF16("expiry_month");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Year");
field.name = ASCIIToUTF16("expiry_year");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Quantity");
field.name = ASCIIToUTF16("quantity");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5804,18 +5978,22 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeMultiMonth_2) {
field.label = ASCIIToUTF16("Cardholder");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiry Date (MMYY)");
field.name = ASCIIToUTF16("expiry");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Quantity");
field.name = ASCIIToUTF16("quantity");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5981,7 +6159,16 @@ TEST_F(FormStructureTestImpl, FindLongestCommonPrefix) {
EXPECT_EQ(ASCIIToUTF16(""), prefix);
}
-TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
+TEST_P(ParameterizedFormStructureTest,
+ RationalizePhoneNumber_RunsOncePerSection) {
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
+
FormData form;
form.url = GURL("http://foo.com");
FormFieldData field;
@@ -5990,18 +6177,22 @@ TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Home Phone");
field.name = ASCIIToUTF16("homePhoneNumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Cell Phone");
field.name = ASCIIToUTF16("cellPhoneNumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6022,9 +6213,15 @@ TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
FormStructure::ParseApiQueryResponse(
response_string, forms, test::GetEncodedSignatures(forms), nullptr);
- EXPECT_FALSE(form_structure.phone_rationalized_["fullName_1-default"]);
- form_structure.RationalizePhoneNumbersInSection("fullName_1-default");
- EXPECT_TRUE(form_structure.phone_rationalized_["fullName_1-default"]);
+ if (section_with_renderer_ids) {
+ EXPECT_FALSE(form_structure.phone_rationalized_["fullName_11-default"]);
+ form_structure.RationalizePhoneNumbersInSection("fullName_11-default");
+ EXPECT_TRUE(form_structure.phone_rationalized_["fullName_11-default"]);
+ } else {
+ EXPECT_FALSE(form_structure.phone_rationalized_["fullName_1-default"]);
+ form_structure.RationalizePhoneNumbersInSection("fullName_1-default");
+ EXPECT_TRUE(form_structure.phone_rationalized_["fullName_1-default"]);
+ }
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
@@ -6048,14 +6245,17 @@ TEST_F(FormStructureTestImpl, RationalizeRepeatedFields_OneAddress) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6095,18 +6295,22 @@ TEST_F(FormStructureTestImpl, RationalizeRepreatedFields_TwoAddresses) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6148,22 +6352,27 @@ TEST_F(FormStructureTestImpl, RationalizeRepreatedFields_ThreeAddresses) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6209,26 +6418,32 @@ TEST_F(FormStructureTestImpl, RationalizeRepreatedFields_FourAddresses) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6281,31 +6496,37 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6361,78 +6582,93 @@ TEST_F(
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Billing
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Work address (not realistic)
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6513,26 +6749,32 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6588,39 +6830,48 @@ TEST_F(
// Shipping
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Billing
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6677,45 +6928,55 @@ TEST_F(FormStructureTestImpl,
// First Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Second Section
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Third Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Fourth Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6779,18 +7040,22 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.section = "billing";
@@ -6799,54 +7064,64 @@ TEST_F(FormStructureTestImpl,
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.section = "billing-2";
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6912,74 +7187,88 @@ TEST_F(FormStructureTestImpl,
// First Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("city");
field.name = ASCIIToUTF16("City");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state2");
field.form_control_type = "select-one";
field.role = FormFieldData::RoleAttribute::kPresentation; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.role = FormFieldData::RoleAttribute::kOther; // visible
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Second Section
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("city");
field.name = ASCIIToUTF16("City");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Third Section
field.label = ASCIIToUTF16("city");
field.name = ASCIIToUTF16("City");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state2");
field.form_control_type = "select-one";
field.role = FormFieldData::RoleAttribute::kPresentation; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.role = FormFieldData::RoleAttribute::kOther; // visible
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7057,28 +7346,33 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country3");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7121,34 +7415,40 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country3");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state2");
field.is_focusable = true; // visible
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7208,22 +7508,26 @@ TEST_P(ParameterizedFormStructureTest,
// Autocomplete Off, with server data.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Autocomplete Off, without server data.
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Autocomplete On, with server data.
field.should_autocomplete = true;
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Autocomplete On, without server data.
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7277,18 +7581,22 @@ TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
// All fields with autocomplete off and no server data.
field.label = ASCIIToUTF16("Cardholder Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Credit Card Number");
field.name = ASCIIToUTF16("cc-number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("exp-date");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("CVC");
field.name = ASCIIToUTF16("cvc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7352,18 +7660,22 @@ TEST_P(ParameterizedFormStructureTest, WithServerDataCCFields_CVC_NoOverwrite) {
// All fields with autocomplete off and no server data.
field.label = ASCIIToUTF16("Cardholder Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Credit Card Number");
field.name = ASCIIToUTF16("cc-number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("exp-date");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("CVC");
field.name = ASCIIToUTF16("cvc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7443,16 +7755,22 @@ TEST_P(RationalizationFieldTypeFilterTest, Rationalization_Rules_Filter_Out) {
// Just adding >=3 random fields to trigger rationalization.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Something under test");
field.name = ASCIIToUTF16("tested-thing");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7503,17 +7821,22 @@ TEST_P(RationalizationFieldTypeRelationshipsTest,
// Just adding >=3 random fields to trigger rationalization.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Some field with required type");
field.name = ASCIIToUTF16("some-name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Something under test");
field.name = ASCIIToUTF16("tested-thing");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7560,6 +7883,7 @@ TEST_F(FormStructureTestImpl, AllowBigForms) {
for (size_t i = 0; i < 250; ++i) {
field.form_control_type = "text";
field.name = ASCIIToUTF16("text") + base::NumberToString16(i);
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
@@ -7578,14 +7902,11 @@ TEST_F(FormStructureTestImpl, AllowBigForms) {
// Tests that an Autofill upload for password form with 1 field should not be
// uploaded.
TEST_F(FormStructureTestImpl, OneFieldPasswordFormShouldNotBeUpload) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /* enabled features */ {kAutofillEnforceMinRequiredFieldsForUpload},
- /* disabled features */ {kAutofillEnforceMinRequiredFieldsForQuery});
FormData form;
FormFieldData field;
field.name = ASCIIToUTF16("Password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
EXPECT_FALSE(FormStructure(form).ShouldBeUploaded());
@@ -7611,9 +7932,15 @@ TEST_F(FormStructureTestImpl, CreateForPasswordManagerUpload) {
// Tests if a new logical form is started with the second appearance of a field
// of type |NAME|.
-TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
+TEST_P(ParameterizedFormStructureTest, NoAutocompleteSectionNames) {
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(features::kAutofillUseNewSectioningMethod);
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
FormData form;
form.url = GURL("http://foo.com");
@@ -7623,26 +7950,32 @@ TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7661,12 +7994,21 @@ TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
// Assert the correct number of fields.
ASSERT_EQ(6U, form_structure.field_count());
- EXPECT_EQ("fullName_1-default", form_structure.field(0)->section);
- EXPECT_EQ("fullName_1-default", form_structure.field(1)->section);
- EXPECT_EQ("fullName_1-default", form_structure.field(2)->section);
- EXPECT_EQ("fullName_2-default", form_structure.field(3)->section);
- EXPECT_EQ("fullName_2-default", form_structure.field(4)->section);
- EXPECT_EQ("fullName_2-default", form_structure.field(5)->section);
+ if (section_with_renderer_ids) {
+ EXPECT_EQ("fullName_11-default", form_structure.field(0)->section);
+ EXPECT_EQ("fullName_11-default", form_structure.field(1)->section);
+ EXPECT_EQ("fullName_11-default", form_structure.field(2)->section);
+ EXPECT_EQ("fullName_14-default", form_structure.field(3)->section);
+ EXPECT_EQ("fullName_14-default", form_structure.field(4)->section);
+ EXPECT_EQ("fullName_14-default", form_structure.field(5)->section);
+ } else {
+ EXPECT_EQ("fullName_1-default", form_structure.field(0)->section);
+ EXPECT_EQ("fullName_1-default", form_structure.field(1)->section);
+ EXPECT_EQ("fullName_1-default", form_structure.field(2)->section);
+ EXPECT_EQ("fullName_2-default", form_structure.field(3)->section);
+ EXPECT_EQ("fullName_2-default", form_structure.field(4)->section);
+ EXPECT_EQ("fullName_2-default", form_structure.field(5)->section);
+ }
}
// Tests that the immediate recurrence of the |PHONE_HOME_NUMBER| type does not
@@ -7683,33 +8025,40 @@ TEST_F(FormStructureTestImpl, NoSplitByRecurringPhoneFieldType) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Mobile Number");
field.name = ASCIIToUTF16("mobileNumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue billing name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
field.autocomplete_attribute = "section-blue billing tel";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Mobile Number");
field.name = ASCIIToUTF16("mobileNumber");
field.autocomplete_attribute = "section-blue billing tel";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7740,9 +8089,15 @@ TEST_F(FormStructureTestImpl, NoSplitByRecurringPhoneFieldType) {
// Tests if a new logical form is started with the second appearance of a field
// of type |ADDRESS_HOME_COUNTRY|.
-TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
+TEST_P(ParameterizedFormStructureTest, SplitByRecurringFieldType) {
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(features::kAutofillUseNewSectioningMethod);
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
FormData form;
form.url = GURL("http://foo.com");
@@ -7753,21 +8108,25 @@ TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7787,16 +8146,26 @@ TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
EXPECT_EQ("blue-shipping-default", form_structure.field(2)->section);
- EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ if (section_with_renderer_ids) {
+ EXPECT_EQ("country_14-default", form_structure.field(3)->section);
+ } else {
+ EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ }
}
// Tests if a new logical form is started with the second appearance of a field
// of type |NAME_FULL| and another with the second appearance of a field of
// type |ADDRESS_HOME_COUNTRY|.
-TEST_F(FormStructureTestImpl,
+TEST_P(ParameterizedFormStructureTest,
SplitByNewAutocompleteSectionNameAndRecurringType) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(features::kAutofillUseNewSectioningMethod);
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
FormData form;
form.url = GURL("http://foo.com");
@@ -7807,21 +8176,25 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue billing country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7842,7 +8215,11 @@ TEST_F(FormStructureTestImpl,
EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
EXPECT_EQ("blue-billing-default", form_structure.field(1)->section);
EXPECT_EQ("blue-billing-default", form_structure.field(2)->section);
- EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ if (section_with_renderer_ids) {
+ EXPECT_EQ("country_14-default", form_structure.field(3)->section);
+ } else {
+ EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ }
}
// Tests if a new logical form is started with the second appearance of a field
@@ -7860,21 +8237,25 @@ TEST_F(FormStructureTestImpl, SplitByNewAutocompleteSectionName) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue billing name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7914,21 +8295,25 @@ TEST_F(
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue billing name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7966,11 +8351,13 @@ TEST_F(FormStructureTestImpl, FromEmptyAutocompleteSectionToDefinedOne) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -8005,17 +8392,20 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("FullName");
field.name = ASCIIToUTF16("fullName");
field.is_focusable = true; // visible
field.autocomplete_attribute = "shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -8052,11 +8442,13 @@ TEST_F(FormStructureTestImpl, IgnoreAribtraryAutocompleteSectionName) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-red ship name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
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
new file mode 100644
index 00000000000..1e5ed929936
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
@@ -0,0 +1,156 @@
+// 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/geo/alternative_state_name_map.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace autofill {
+
+namespace {
+
+// Assuming a user can have maximum 500 profiles each containing a different
+// state string in the worst case scenario.
+constexpr int kMaxMapSize = 500;
+
+// The characters to be removed from the state strings before the comparison.
+constexpr char kCharsToStrip[] = ".- ";
+
+} // namespace
+
+// static
+AlternativeStateNameMap* AlternativeStateNameMap::GetInstance() {
+ static base::NoDestructor<AlternativeStateNameMap>
+ g_alternative_state_name_map;
+ return g_alternative_state_name_map.get();
+}
+
+AlternativeStateNameMap::AlternativeStateNameMap() = default;
+
+// static
+AlternativeStateNameMap::StateName AlternativeStateNameMap::NormalizeStateName(
+ const StateName& text) {
+ base::string16 normalized_text;
+ base::RemoveChars(text.value(), base::ASCIIToUTF16(kCharsToStrip),
+ &normalized_text);
+ return StateName(normalized_text);
+}
+
+base::Optional<AlternativeStateNameMap::CanonicalStateName>
+AlternativeStateNameMap::GetCanonicalStateName(
+ const CountryCode& country_code,
+ const StateName& state_name,
+ bool is_state_name_normalized) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+ // Example:
+ // Entries in |localized_state_names_map_| are:
+ // ("DE", "Bavaria") -> {
+ // "canonical_name": "Bayern",
+ // "abbreviations": "BY",
+ // "alternative_names": "Bavaria"
+ // }
+ // Entries in |localized_state_names_reverse_lookup_map_| are:
+ // ("DE", "Bayern") -> "Bayern"
+ // ("DE", "BY") -> "Bayern"
+ // ("DE", "Bavaria") -> "Bayern"
+ // then, AlternativeStateNameMap::GetCanonicalStateName("DE", "Bayern") =
+ // AlternativeStateNameMap::GetCanonicalStateName("DE", "BY") =
+ // AlternativeStateNameMap::GetCanonicalStateName("DE", "Bavaria") =
+ // CanonicalStateName("Bayern")
+ StateName normalized_state_name = state_name;
+ if (!is_state_name_normalized)
+ normalized_state_name = NormalizeStateName(state_name);
+
+ auto it = localized_state_names_reverse_lookup_map_.find(
+ {country_code, normalized_state_name});
+ if (it != localized_state_names_reverse_lookup_map_.end())
+ return it->second;
+
+ return base::nullopt;
+}
+
+base::Optional<StateEntry> AlternativeStateNameMap::GetEntry(
+ const CountryCode& country_code,
+ const StateName& state_string_from_profile) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+
+ StateName normalized_state_string_from_profile =
+ NormalizeStateName(state_string_from_profile);
+ base::Optional<CanonicalStateName> canonical_state_name =
+ 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());
+ }
+
+ 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;
+}
+
+void AlternativeStateNameMap::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) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+
+ // Example:
+ // AddEntry("DE", "Bavaria", {
+ // "canonical_name": "Bayern",
+ // "abbreviations": "BY",
+ // "alternative_names": "Bavaria"
+ // }, {"Bavaria", "BY", "Bayern"}, "Bayern")
+ // Then entry added to |localized_state_names_map_| is:
+ // ("DE", "Bayern") -> {
+ // "canonical_name": "Bayern",
+ // "abbreviations": "BY",
+ // "alternative_names": "Bavaria"
+ // }
+ // Entries added to |localized_state_names_reverse_lookup_map_| are:
+ // ("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;
+ }
+}
+
+bool AlternativeStateNameMap::IsLocalisedStateNamesMapEmpty() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+ return localized_state_names_map_.empty();
+}
+
+void AlternativeStateNameMap::ClearAlternativeStateNameMap() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+ localized_state_names_map_.clear();
+ localized_state_names_reverse_lookup_map_.clear();
+}
+
+} // namespace autofill
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
new file mode 100644
index 00000000000..1ed11eaa6c6
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h
@@ -0,0 +1,181 @@
+// 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_GEO_ALTERNATIVE_STATE_NAME_MAP_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_H_
+
+#include "components/autofill/core/browser/proto/states.pb.h"
+
+#include "base/i18n/case_conversion.h"
+#include "base/no_destructor.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string16.h"
+#include "base/util/type_safety/strong_alias.h"
+
+namespace autofill {
+// AlternativeStateNameMap encapsulates mappings from state names in the
+// profiles to their localized and the abbreviated names.
+//
+// AlternativeStateNameMap is used for the filling of state fields, comparison
+// of profiles, determining mergeability of the address profiles and required
+// |ADDRESS_HOME_STATE| votes to be sent to the server.
+//
+// AlternativeStateNameMap can provide the following data for the states:
+// 1. The state string stored in the address profile denoted by
+// state_string_from_profile in this class.
+// 2. The canonical state name (StateEntry::canonical_name) which acts as the
+// unique identifier representing the state (unique within a country).
+// 3. The abbreviations of the state (StateEntry::abbreviations).
+// 4. The alternative names of the state (StateEntry::alternative_names).
+//
+// StateEntry holds the information about the abbreviations and the
+// alternative names of the state which is determined after comparison with the
+// state values saved in the address profiles if they match.
+//
+// The main map |localized_state_names_map_| maps the tuple
+// (country_code, canonical state name) as the key to the corresponding
+// StateEntry object (with the information about the abbreviations and the
+// alternative names) as the value.
+//
+// The |localized_state_names_reverse_lookup_map_| takes in the
+// country_code and StateEntry::name, StateEntry::abbreviations or
+// ::alternative_names as the key and the canonical state name as the value.
+//
+// Example: Considering "California" as the state_string_from_profile and
+// the corresponding StateEntry object:
+// {
+// 'canonical_name': 'California',
+// 'abbreviations': ['CA'],
+// 'alternate_names': ['The Golden State']
+// }
+//
+// 1. StateEntry::canonical_name (i.e "California" in this case) acts
+// as the canonical state name.
+// 2. ("US", "California") acts as the key and the above StateEntry
+// object is added as the value in the
+// |localized_state_names_map_|.
+// 3. Entries added to |localized_state_names_reverse_lookup_map_|
+// are:
+// a. ("US", "California") -> "California"
+// 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
+class AlternativeStateNameMap {
+ public:
+ // Represents ISO 3166-1 alpha-2 codes (always uppercase ASCII).
+ using CountryCode = util::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>;
+
+ // 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>;
+
+ static AlternativeStateNameMap* GetInstance();
+
+ ~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|).
+ base::Optional<CanonicalStateName> GetCanonicalStateName(
+ const CountryCode& country_code,
+ const StateName& state_name,
+ bool is_state_name_normalized = false) const;
+
+ // Returns the value present in |localized_state_names_map_| corresponding
+ // to (|country_code|, |state_string_from_profile|). In case, the entry does
+ // not exist in the map, base::nullopt is returned.
+ base::Optional<StateEntry> GetEntry(
+ const CountryCode& country_code,
+ const StateName& state_string_from_profile) const;
+
+ // 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
+ // |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);
+
+ // Returns true if the |localized_state_names_map_| is empty.
+ bool IsLocalisedStateNamesMapEmpty() const;
+
+#if defined(UNIT_TEST)
+ // Clears the map for testing purposes.
+ void ClearAlternativeStateNameMapForTesting() {
+ ClearAlternativeStateNameMap();
+ }
+#endif
+
+ private:
+ AlternativeStateNameMap();
+
+ // Clears the |localized_state_names_map_| and
+ // |localized_state_names_reverse_lookup_map_|.
+ // Used only for testing purposes.
+ void ClearAlternativeStateNameMap();
+
+ // A custom comparator for the
+ // |localized_state_names_reverse_lookup_map_| that ignores the case
+ // of the string on comparisons.
+ struct CaseInsensitiveLessComparator {
+ bool operator()(const std::pair<CountryCode, StateName>& lhs,
+ const std::pair<CountryCode, StateName>& rhs) const {
+ // Compares the country codes that are always uppercase ASCII.
+ if (lhs.first != rhs.first)
+ return lhs.first.value() < rhs.first.value();
+
+ return base::i18n::ToLower(lhs.second.value()) <
+ base::i18n::ToLower(rhs.second.value());
+ }
+ };
+
+ // Since the constructor is private, |base::NoDestructor| must be friend to be
+ // allowed to construct the class.
+ friend class base::NoDestructor<AlternativeStateNameMap>;
+
+ // A map that stores the alternative state names. The map is keyed
+ // by the country_code and the canonical state name (or
+ // normalized_state_value_from_profile in case no canonical state name is
+ // known) while the value is the StateEntry object.
+ std::map<std::pair<CountryCode, CanonicalStateName>, StateEntry>
+ localized_state_names_map_;
+
+ // The map is keyed by the country_code and the abbreviation or
+ // canonical name or the alternative name of the state.
+ std::map<std::pair<CountryCode, StateName>,
+ CanonicalStateName,
+ CaseInsensitiveLessComparator>
+ localized_state_names_reverse_lookup_map_;
+
+ SEQUENCE_CHECKER(alternative_state_name_map_sequence_checker_);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_H_
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
new file mode 100644
index 00000000000..9435c583dbf
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc
@@ -0,0 +1,69 @@
+// 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/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 {
+
+namespace test {
+
+void PopulateStateEntry(const TestStateEntry& test_state_entry,
+ StateEntry* state_entry) {
+ state_entry->set_canonical_name(test_state_entry.canonical_name);
+ for (const auto& abbr : test_state_entry.abbreviations)
+ state_entry->add_abbreviations(abbr);
+ for (const auto& alternative_name : test_state_entry.alternative_names)
+ state_entry->add_alternative_names(alternative_name);
+}
+
+void ClearAlternativeStateNameMapForTesting() {
+ AlternativeStateNameMap::GetInstance()
+ ->ClearAlternativeStateNameMapForTesting();
+}
+
+void PopulateAlternativeStateNameMapForTesting(
+ const std::string& country_code,
+ const std::string& key,
+ const std::vector<TestStateEntry>& test_state_entries) {
+ for (const auto& test_state_entry : test_state_entries) {
+ 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()));
+ 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)));
+
+ AlternativeStateNameMap::GetInstance()->AddEntry(
+ AlternativeStateNameMap::CountryCode(country_code),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16(key)),
+ state_entry, alternatives, &canonical_state_name);
+ }
+}
+
+std::string CreateStatesProtoAsString(const std::string& country_code,
+ const TestStateEntry& test_state_entry) {
+ StatesInCountry states_data;
+ states_data.set_country_code(std::move(country_code));
+ StateEntry* entry = states_data.add_states();
+ PopulateStateEntry(test_state_entry, entry);
+
+ std::string serialized_output;
+ bool proto_is_serialized = states_data.SerializeToString(&serialized_output);
+ DCHECK(proto_is_serialized);
+ return serialized_output;
+}
+
+} // namespace test
+} // namespace autofill
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
new file mode 100644
index 00000000000..0c86be629a8
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h
@@ -0,0 +1,47 @@
+// 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_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
+
+#include "base/optional.h"
+#include "components/autofill/core/browser/proto/states.pb.h"
+
+namespace autofill {
+
+namespace test {
+
+namespace internal {
+template <typename = void>
+struct TestStateEntry {
+ std::string canonical_name = "Bavaria";
+ std::vector<std::string> abbreviations = {"BY"};
+ std::vector<std::string> alternative_names = {"Bayern"};
+};
+} // namespace internal
+
+using TestStateEntry = internal::TestStateEntry<>;
+
+// Populates |state_entry| with the data in |test_state_entry|.
+void PopulateStateEntry(const TestStateEntry& test_state_entry,
+ StateEntry* state_entry);
+
+// Clears the map for testing purposes.
+void ClearAlternativeStateNameMapForTesting();
+
+// Inserts a StateEntry instance into AlternativeStateNameMap for testing.
+void PopulateAlternativeStateNameMapForTesting(
+ const std::string& country_code = "DE",
+ const std::string& key = "Bavaria",
+ const std::vector<TestStateEntry>& test_state_entries = {TestStateEntry()});
+
+// Returns a StateEntry instance serialized as string.
+std::string CreateStatesProtoAsString(
+ const std::string& country_code = "DE",
+ const TestStateEntry& test_state_entry = TestStateEntry());
+
+} // namespace test
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
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
new file mode 100644
index 00000000000..268b41cec02
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc
@@ -0,0 +1,119 @@
+// 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/geo/alternative_state_name_map.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace test {
+
+// Tests that map is not empty when an entry has been added to it.
+TEST(AlternativeStateNameMapTest, IsEntryAddedToMap) {
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ EXPECT_FALSE(
+ AlternativeStateNameMap::GetInstance()->IsLocalisedStateNamesMapEmpty());
+}
+
+// Tests that the state canonical name is present when an entry is added to
+// the map.
+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))),
+ 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(""))),
+ base::nullopt);
+ EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode(""),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16(""))),
+ base::nullopt);
+}
+
+// Tests that the separate entries are created in the map for the different
+// country codes.
+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);
+}
+
+// Tests that |AlternativeStateNameMap::NormalizeStateName()| removes "-", " "
+// and "." from the text.
+TEST(AlternativeStateNameMapTest, StripText) {
+ struct {
+ const char* test_string;
+ const char* expected;
+ } test_cases[] = {{"B.Y", "BY"},
+ {"The Golden Sun", "TheGoldenSun"},
+ {"Bavaria - BY", "BavariaBY"}};
+ for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(testing::Message() << "test_string: " << test_case.test_string
+ << " | expected: " << test_case.expected);
+ AlternativeStateNameMap::StateName text =
+ AlternativeStateNameMap::StateName(
+ base::ASCIIToUTF16(test_case.test_string));
+ EXPECT_EQ(AlternativeStateNameMap::NormalizeStateName(text).value(),
+ base::ASCIIToUTF16(test_case.expected));
+ }
+}
+
+// Tests that the correct entries are returned when the maps in
+// AlternativeStateNameMap are queried.
+TEST(AlternativeStateNameMapTest, GetEntry) {
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ AlternativeStateNameMap* alternative_state_name_map =
+ AlternativeStateNameMap::GetInstance();
+ EXPECT_EQ(
+ alternative_state_name_map->GetEntry(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Random"))),
+ base::nullopt);
+ auto entry = alternative_state_name_map->GetEntry(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")));
+ EXPECT_NE(entry, base::nullopt);
+ ASSERT_TRUE(entry->has_canonical_name());
+ EXPECT_EQ(entry->canonical_name(), "Bavaria");
+ EXPECT_THAT(entry->abbreviations(),
+ testing::UnorderedElementsAreArray({"BY"}));
+ EXPECT_THAT(entry->alternative_names(),
+ testing::UnorderedElementsAreArray({"Bayern"}));
+}
+
+} // namespace test
+} // namespace autofill
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
new file mode 100644
index 00000000000..3c85158b61e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc
@@ -0,0 +1,226 @@
+// 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/geo/alternative_state_name_map_updater.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/ranges/algorithm.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#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/common/autofill_l10n_util.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/prefs/pref_service.h"
+
+namespace autofill {
+
+namespace {
+
+// Returns data read from the file specified in |file|.
+std::string LoadDataFromFile(const base::FilePath& file) {
+ DCHECK(!file.empty());
+
+ std::string data;
+ if (!base::PathExists(file)) {
+ VLOG(1) << "File does not exist: " << file;
+ return std::string();
+ }
+
+ if (!base::ReadFileToString(file, &data)) {
+ VLOG(1) << "Failed reading from file: " << file;
+ return std::string();
+ }
+
+ return data;
+}
+
+} // namespace
+
+AlternativeStateNameMapUpdater::AlternativeStateNameMapUpdater()
+ : task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {}
+
+AlternativeStateNameMapUpdater::~AlternativeStateNameMapUpdater() = default;
+
+// static
+bool AlternativeStateNameMapUpdater::ContainsState(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_alternative_state_names,
+ const AlternativeStateNameMap::StateName&
+ stripped_state_values_from_profile) {
+ l10n::CaseInsensitiveCompare compare;
+
+ // Returns true if |str1| is same as |str2| in a case-insensitive comparison.
+ return base::ranges::any_of(
+ stripped_alternative_state_names,
+ [&](const AlternativeStateNameMap::StateName& text) {
+ return compare.StringsEqual(text.value(),
+ stripped_state_values_from_profile.value());
+ });
+}
+
+void AlternativeStateNameMapUpdater::LoadStatesData(
+ const 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);
+
+ // If the installed directory path is empty, it means that the component is
+ // not ready for use yet.
+ if (data_download_path.empty()) {
+ std::move(done_callback).Run();
+ return;
+ }
+
+ const std::vector<std::string>& country_codes =
+ CountryDataMap::GetInstance()->country_codes();
+
+ // 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) {
+ const AlternativeStateNameMap::CountryCode& country_code = entry.first;
+ const std::vector<AlternativeStateNameMap::StateName>& states =
+ entry.second;
+
+ // This is a security check to ensure that we only attempt to read files
+ // that match to known countries.
+ 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),
+ base::BindOnce(
+ &AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent,
+ weak_ptr_factory_.GetWeakPtr(), states));
+ }
+}
+
+void AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_state_values_from_profiles,
+ const std::string& data) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ DCHECK_GT(number_pending_init_tasks_, 0);
+ --number_pending_init_tasks_;
+
+ StatesInCountry states_data;
+
+ if (!data.empty() && states_data.ParseFromString(data)) {
+ DCHECK(states_data.has_country_code());
+ AlternativeStateNameMap::CountryCode country_code =
+ AlternativeStateNameMap::CountryCode(states_data.country_code());
+
+ // Boolean flags that denote in |match_found[i]| whether the match has been
+ // found for |stripped_state_values_from_profiles[i]|.
+ std::vector<bool> match_found(stripped_state_values_from_profiles.size(),
+ false);
+
+ // 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
+ // the above created states list (if a match is not found for v yet). If the
+ // 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);
+
+ 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
+ // the state under consideration, add it to the AlternativeStateNameMap.
+ if (ContainsState(state_names,
+ stripped_state_values_from_profiles[i])) {
+ AlternativeStateNameMap::GetInstance()->AddEntry(
+ country_code, stripped_state_values_from_profiles[i], state_entry,
+ state_names, &state_canonical_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) {
+ for (auto& callback : std::exchange(pending_init_done_callbacks_, {}))
+ std::move(callback).Run();
+ }
+}
+
+std::vector<AlternativeStateNameMap::StateName>
+AlternativeStateNameMapUpdater::ExtractAllStateNames(
+ const StateEntry& state_entry) {
+ DCHECK(state_entry.has_canonical_name());
+
+ std::vector<AlternativeStateNameMap::StateName> state_names;
+ state_names.reserve(1u + state_entry.abbreviations_size() +
+ state_entry.alternative_names_size());
+
+ state_names.emplace_back(AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(
+ base::UTF8ToUTF16(state_entry.canonical_name()))));
+ for (const auto& abbr : state_entry.abbreviations()) {
+ state_names.emplace_back(AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16(abbr))));
+ }
+ for (const auto& alternative_name : state_entry.alternative_names()) {
+ state_names.emplace_back(AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(
+ base::UTF8ToUTF16(alternative_name))));
+ }
+
+ return state_names;
+}
+
+} // 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
new file mode 100644
index 00000000000..ab1caabaf66
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h
@@ -0,0 +1,113 @@
+// 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_GEO_ALTERNATIVE_STATE_NAME_MAP_UPDATER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_UPDATER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+
+class PrefService;
+
+namespace autofill {
+
+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 {
+ public:
+ AlternativeStateNameMapUpdater();
+ ~AlternativeStateNameMapUpdater();
+ 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);
+
+#if defined(UNIT_TEST)
+ // A wrapper around |ProcessLoadedStateFileContent| used for testing purposes.
+ void ProcessLoadedStateFileContentForTesting(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ state_values_from_profiles,
+ const std::string& data,
+ base::OnceClosure callback) {
+ ++number_pending_init_tasks_;
+ pending_init_done_callbacks_.push_back(std::move(callback));
+ ProcessLoadedStateFileContent(state_values_from_profiles, data);
+ }
+
+ // A wrapper around |ContainsState| used for testing purposes.
+ static bool ContainsStateForTesting(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_alternative_state_names,
+ const AlternativeStateNameMap::StateName&
+ stripped_state_values_from_profile) {
+ return ContainsState(stripped_alternative_state_names,
+ stripped_state_values_from_profile);
+ }
+#endif
+
+ private:
+ // Compares |stripped_state_value_from_profile| with the entries in
+ // |stripped_state_alternative_names| and returns true if a match is found.
+ static bool ContainsState(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_alternative_state_names,
+ const AlternativeStateNameMap::StateName&
+ stripped_state_values_from_profile);
+
+ // Each entry in |state_values_from_profiles| is compared with the states
+ // |data| read from the files and then inserted into the
+ // AlternativeStateNameMap.
+ void ProcessLoadedStateFileContent(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ state_values_from_profiles,
+ const std::string& data);
+
+ // Builds and returns a list of all the names of the state (including its
+ // abbreviations) from the |state_entry| into |state_names|.
+ std::vector<AlternativeStateNameMap::StateName> ExtractAllStateNames(
+ const StateEntry& state_entry);
+
+ // TaskRunner for reading files from disk.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ // 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;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // base::WeakPtr ensures that the callback bound to the object is canceled
+ // when that object is destroyed.
+ base::WeakPtrFactory<AlternativeStateNameMapUpdater> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_UPDATER_H_
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
new file mode 100644
index 00000000000..97a6eb1038a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
@@ -0,0 +1,159 @@
+// 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/geo/alternative_state_name_map_updater.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/optional.h"
+#include "base/strings/utf_string_conversions.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/common/autofill_prefs.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+
+namespace autofill {
+
+class AlternativeStateNameMapUpdaterTest : public ::testing::Test {
+ public:
+ AlternativeStateNameMapUpdaterTest()
+ : pref_service_(test::PrefServiceForTesting()) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(data_install_dir_.CreateUniqueTempDir());
+ }
+
+ 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);
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ AlternativeStateNameMapUpdater alternative_state_name_map_updater;
+ std::unique_ptr<PrefService> pref_service_;
+ base::ScopedTempDir data_install_dir_;
+};
+
+// Tests that the states data is added to AlternativeStateNameMap.
+TEST_F(AlternativeStateNameMapUpdaterTest, EntryAddedToStateMap) {
+ test::ClearAlternativeStateNameMapForTesting();
+ std::string states_data = test::CreateStatesProtoAsString();
+ std::vector<AlternativeStateNameMap::StateName> test_strings = {
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("B.Y")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bav-aria")),
+ AlternativeStateNameMap::StateName(UTF8ToUTF16("amapá")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Broen")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria is in Germany")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("BA is in Germany"))};
+ std::vector<bool> state_data_present = {true, true, true, true,
+ false, false, false, false};
+
+ 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,
+ state_data_present[i]);
+ }
+}
+
+// Tests that the AlternativeStateNameMap is populated when
+// |StateNameMapUpdater::LoadStatesData()| is called.
+TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesData) {
+ test::ClearAlternativeStateNameMapForTesting();
+
+ base::WriteFile(GetPath().AppendASCII("DE"),
+ test::CreateStatesProtoAsString());
+ WritePathToPref(GetPath());
+
+ base::RunLoop run_loop;
+ alternative_state_name_map_updater.LoadStatesData(
+ {{AlternativeStateNameMap::CountryCode("DE"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))}}},
+ pref_service_.get(), run_loop.QuitClosure());
+ run_loop.Run();
+
+ EXPECT_NE(
+ AlternativeStateNameMap::GetInstance()->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
+ base::nullopt);
+}
+
+// Tests that the AlternativeStateNameMap is populated when
+// |StateNameMapUpdater::LoadStatesData()| is called and there are UTF8 strings.
+TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesDataUTF8) {
+ test::ClearAlternativeStateNameMapForTesting();
+
+ base::WriteFile(
+ GetPath().AppendASCII("ES"),
+ test::CreateStatesProtoAsString(
+ "ES", {.canonical_name = "Paraná",
+ .abbreviations = {"PR"},
+ .alternative_names = {"Parana", "State of Parana"}}));
+ WritePathToPref(GetPath());
+
+ base::RunLoop run_loop;
+ alternative_state_name_map_updater.LoadStatesData(
+ {{AlternativeStateNameMap::CountryCode("ES"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Parana"))}}},
+ pref_service_.get(), run_loop.QuitClosure());
+ run_loop.Run();
+
+ base::Optional<StateEntry> entry1 =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode("ES"),
+ AlternativeStateNameMap::StateName(base::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("ES"),
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16("Parana")));
+ EXPECT_NE(entry2, base::nullopt);
+ EXPECT_EQ(entry2->canonical_name(), "Paraná");
+ EXPECT_THAT(entry2->abbreviations(),
+ testing::UnorderedElementsAreArray({"PR"}));
+ EXPECT_THAT(entry2->alternative_names(), testing::UnorderedElementsAreArray(
+ {"Parana", "State of Parana"}));
+}
+
+// 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"))));
+ EXPECT_FALSE(AlternativeStateNameMapUpdater::ContainsStateForTesting(
+ {AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("BY"))},
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("California"))));
+}
+
+} // 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 43a02de277f..121868e521a 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.cc
@@ -37,20 +37,16 @@ AutofillCountry::AutofillCountry(const std::string& country_code,
// If there is no entry in the |CountryDataMap| for the
// |country_code_for_country_data| use the country code derived from the
// locale. This reverts to US.
- country_data_map->HasCountryData(country_code_)
+ country_data_map->HasRequiredFieldsForAddressImport(country_code_)
? country_code_
: CountryCodeForLocale(locale);
// Acquire the country address data.
- const CountryData& data = country_data_map->GetCountryData(country_code_);
+ required_fields_for_address_import_ =
+ country_data_map->GetRequiredFieldsForAddressImport(country_code_);
// Translate the country name by the supplied local.
name_ = l10n_util::GetDisplayNameForCountry(country_code_, locale);
-
- // Get the localized strings associate with the address fields.
- postal_code_label_ = l10n_util::GetStringUTF16(data.postal_code_label_id);
- state_label_ = l10n_util::GetStringUTF16(data.state_label_id);
- address_required_fields_ = data.address_required_fields;
}
AutofillCountry::~AutofillCountry() {}
@@ -82,10 +78,7 @@ AutofillCountry::AutofillCountry(const std::string& country_code,
const base::string16& name,
const base::string16& postal_code_label,
const base::string16& state_label)
- : country_code_(country_code),
- name_(name),
- postal_code_label_(postal_code_label),
- state_label_(state_label) {}
+ : country_code_(country_code), name_(name) {}
// Prints a formatted log of a |AutofillCountry| to a |LogBuffer|.
LogBuffer& operator<<(LogBuffer& buffer, const AutofillCountry& country) {
@@ -97,8 +90,6 @@ LogBuffer& operator<<(LogBuffer& buffer, const AutofillCountry& country) {
buffer << Tr{} << "State required:" << country.requires_state();
buffer << Tr{} << "Zip required:" << country.requires_zip();
buffer << Tr{} << "City required:" << country.requires_city();
- buffer << Tr{} << "State label:" << country.state_label();
- buffer << Tr{} << "Postal code label:" << country.postal_code_label();
buffer << CTag{"table"};
buffer << CTag{"div"};
buffer << CTag{};
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.h b/chromium/components/autofill/core/browser/geo/autofill_country.h
index fc16ef008d3..c1d3a3eb1b7 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.h
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.h
@@ -31,33 +31,32 @@ class AutofillCountry {
const std::string& country_code() const { return country_code_; }
const base::string16& name() const { return name_; }
- const base::string16& postal_code_label() const { return postal_code_label_; }
- const base::string16& state_label() const { return state_label_; }
// City is expected in a complete address for this country.
bool requires_city() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_CITY) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_CITY) != 0;
}
// State is expected in a complete address for this country.
bool requires_state() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_STATE) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_STATE) != 0;
}
// Zip is expected in a complete address for this country.
bool requires_zip() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_ZIP) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_ZIP) != 0;
}
// An address line1 is expected in a complete address for this country.
bool requires_line1() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_LINE1) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_LINE1) != 0;
}
// True if a complete address is expected to either contain a state or a ZIP
// code. Not true if the address explicitly needs both.
bool requires_zip_or_state() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_ZIP_OR_STATE) != 0;
+ return (required_fields_for_address_import_ &
+ ADDRESS_REQUIRES_ZIP_OR_STATE) != 0;
}
private:
@@ -72,14 +71,8 @@ class AutofillCountry {
// The country's name, localized to the app locale.
base::string16 name_;
- // The localized label for the postal code (or zip code) field.
- base::string16 postal_code_label_;
-
- // The localized label for the state (or province, district, etc.) field.
- base::string16 state_label_;
-
- // Address requirement field codes for the country.
- AddressRequiredFields address_required_fields_;
+ // Required fields for an address import for the country.
+ RequiredFieldsForAddressImport required_fields_for_address_import_;
DISALLOW_COPY_AND_ASSIGN(AutofillCountry);
};
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 655c9e1777a..487d46e1990 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
@@ -24,8 +24,6 @@ TEST(AutofillCountryTest, AutofillCountry) {
AutofillCountry united_states_en("US", "en_US");
EXPECT_EQ("US", united_states_en.country_code());
EXPECT_EQ(ASCIIToUTF16("United States"), united_states_en.name());
- EXPECT_EQ(ASCIIToUTF16("ZIP code"), united_states_en.postal_code_label());
- EXPECT_EQ(ASCIIToUTF16("State"), united_states_en.state_label());
AutofillCountry united_states_es("US", "es");
EXPECT_EQ("US", united_states_es.country_code());
@@ -39,8 +37,6 @@ TEST(AutofillCountryTest, AutofillCountry) {
AutofillCountry canada_en("CA", "en_US");
EXPECT_EQ("CA", canada_en.country_code());
EXPECT_EQ(ASCIIToUTF16("Canada"), canada_en.name());
- EXPECT_EQ(ASCIIToUTF16("Postal code"), canada_en.postal_code_label());
- EXPECT_EQ(ASCIIToUTF16("Province"), canada_en.state_label());
AutofillCountry canada_hu("CA", "hu");
EXPECT_EQ("CA", canada_hu.country_code());
@@ -124,7 +120,7 @@ TEST(AutofillCountryTest, AliasMappingsForCountryData) {
CountryDataMap* country_data_map = CountryDataMap::GetInstance();
// There should be country data for the "GB".
- EXPECT_TRUE(country_data_map->HasCountryData("GB"));
+ EXPECT_TRUE(country_data_map->HasRequiredFieldsForAddressImport("GB"));
// Check the correctness of the alias definitions.
EXPECT_TRUE(country_data_map->HasCountryCodeAlias("UK"));
diff --git a/chromium/components/autofill/core/browser/geo/country_data.cc b/chromium/components/autofill/core/browser/geo/country_data.cc
index a85fba5a745..545179c09d8 100644
--- a/chromium/components/autofill/core/browser/geo/country_data.cc
+++ b/chromium/components/autofill/core/browser/geo/country_data.cc
@@ -14,9 +14,9 @@
namespace autofill {
namespace {
-struct StaticCountryData {
+struct StaticCountryAddressImportRequirementsData {
char country_code[3];
- CountryData country_data;
+ RequiredFieldsForAddressImport address_import_field_requirements;
};
// Alias definitions record for CountryData requests. A request for
@@ -30,783 +30,284 @@ struct StaticCountryCodeAliasData {
// Alias definitions.
const StaticCountryCodeAliasData kCountryCodeAliases[] = {{"UK", "GB"}};
-// Maps country codes to localized label string identifiers. Keep this sorted
+// Maps country codes to address import requirements. Keep this sorted
// by country code.
// This list is comprized of countries appearing in both
// //third_party/icu/source/data/region/en.txt and
// //third_party/libaddressinput/src/cpp/src/region_data_constants.cc.
-const StaticCountryData kCountryData[] = {
- // clang-format off
- {"AC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PARISH,
- ADDRESS_REQUIRES_LINE1 } },
- {"AE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_EMIRATE,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"AF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"AI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AS", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PARISH,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"BD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"BS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"BT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"BZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"CI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"CV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"CZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"DK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"DO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"EC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"EE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"EG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"EH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ER", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"ES", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"ET", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"FK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FM", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"FO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_COUNTY,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"GL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GU", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"HK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_AREA,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"HM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"HN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"HR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"HT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"HU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ID", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_COUNTY,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"IR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"JE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"JM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PARISH,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"JO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"JP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PREFECTURE,
- ADDRESS_REQUIRES_LINE1_STATE_ZIP } },
- {"KE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"KM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"KN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"KP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"KR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"KW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"KZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"LA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"LI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ME", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MH", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"MK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ML", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"MO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"MP", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"MQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_DEPARTMENT,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_DISTRICT,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"NU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"NZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"OM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"PE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"PF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"PG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"PH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"PK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PR", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"PT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PW", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"PY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"QA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"RE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_ZIP } },
- {"SH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_ZIP } },
- {"SN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"ST", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"TJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"TT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"TW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_COUNTY,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"TZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"UA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"UG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"UM", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"US", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"UY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"UZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"VA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"VC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"VE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"VG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"VI", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"VN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"VU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"WF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"WS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"XK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"YE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"YT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ZA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ZM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"ZW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- // clang-format on
+const StaticCountryAddressImportRequirementsData
+ kCountryAddressImportRequirementsData[] = {
+ {"AC", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AD", ADDRESS_REQUIRES_LINE1},
+ {"AE", ADDRESS_REQUIRES_LINE1_STATE},
+ {"AF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AG", ADDRESS_REQUIRES_LINE1},
+ {"AI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AM", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AO", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AQ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AS", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AU", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AX", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BB", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"BD", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BF", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BI", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BJ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BO", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BQ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"BS", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"BT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BV", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BY", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BZ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CA", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CC", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CD", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CF", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"CI", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CK", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CL", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CN", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CO", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CS", ADDRESS_REQUIRES_LINE1},
+ {"CV", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CX", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CY", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"CZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DJ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"DK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"DO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"EC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"EE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"EG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"EH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ER", ADDRESS_REQUIRES_LINE1_CITY},
+ {"ES", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"ET", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FJ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"FK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FM", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"FO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GB", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GD", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GH", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GI", ADDRESS_REQUIRES_LINE1},
+ {"GL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GP", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GQ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GW", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GY", ADDRESS_REQUIRES_LINE1_CITY},
+ {"HK", ADDRESS_REQUIRES_LINE1_STATE},
+ {"HM", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"HN", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"HR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"HT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"HU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ID", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IE", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IN", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IQ", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"IR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IT", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"JE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"JM", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"JO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"JP", ADDRESS_REQUIRES_LINE1_STATE_ZIP},
+ {"KE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KI", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"KM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"KN", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"KP", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"KR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"KW", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KY", ADDRESS_REQUIRES_LINE1_STATE},
+ {"KZ", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"LA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LB", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LC", ADDRESS_REQUIRES_LINE1_CITY},
+ {"LI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LV", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LY", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MD", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ME", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MH", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"MK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ML", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MN", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"MO", ADDRESS_REQUIRES_LINE1},
+ {"MP", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"MQ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MR", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MV", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MX", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MY", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MZ", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NF", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NG", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NI", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NP", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NR", ADDRESS_REQUIRES_LINE1_STATE},
+ {"NU", ADDRESS_REQUIRES_LINE1_CITY},
+ {"NZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"OM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PA", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"PE", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"PF", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"PG", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"PH", ADDRESS_REQUIRES_LINE1_CITY},
+ {"PK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"PT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PW", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"PY", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"QA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"RE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"RO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"RS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"RU", ADDRESS_REQUIRES_LINE1_CITY},
+ {"RW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SB", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SC", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SG", ADDRESS_REQUIRES_LINE1_ZIP},
+ {"SH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SJ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SL", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SM", ADDRESS_REQUIRES_LINE1_ZIP},
+ {"SN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SO", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SR", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"ST", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SV", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SX", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TD", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TF", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TH", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"TJ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TK", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TL", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TO", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TR", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"TT", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TV", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"TW", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"TZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"UA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"UG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"UM", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"US", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"UY", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"UZ", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"VA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"VC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"VE", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"VG", ADDRESS_REQUIRES_LINE1},
+ {"VI", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"VN", ADDRESS_REQUIRES_LINE1_CITY},
+ {"VU", ADDRESS_REQUIRES_LINE1_CITY},
+ {"WF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"WS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"XK", ADDRESS_REQUIRES_LINE1_CITY},
+ {"YE", ADDRESS_REQUIRES_LINE1_CITY},
+ {"YT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ZA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ZM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"ZW", ADDRESS_REQUIRES_LINE1_CITY},
};
// GetCountryCodes and GetCountryData compute the data for CountryDataMap
-// based on |kCountryData|.
+// based on |kCountryAddressImportRequirementsData|.
std::vector<std::string> GetCountryCodes() {
std::vector<std::string> country_codes;
- country_codes.reserve(base::size(kCountryData));
- for (const auto& static_data : kCountryData) {
+ country_codes.reserve(base::size(kCountryAddressImportRequirementsData));
+ for (const auto& static_data : kCountryAddressImportRequirementsData) {
country_codes.push_back(static_data.country_code);
}
return country_codes;
}
-std::map<std::string, CountryData> GetCountryDataMap() {
- std::map<std::string, CountryData> country_data;
+std::map<std::string, RequiredFieldsForAddressImport> GetCountryDataMap() {
+ std::map<std::string, RequiredFieldsForAddressImport> import_requirements;
// Add all the countries we have explicit data for.
- for (const auto& static_data : kCountryData) {
- country_data.insert(
- std::make_pair(static_data.country_code, static_data.country_data));
+ for (const auto& static_data : kCountryAddressImportRequirementsData) {
+ import_requirements.insert(
+ import_requirements.end(),
+ std::make_pair(static_data.country_code,
+ static_data.address_import_field_requirements));
}
// Add any other countries that ICU knows about, falling back to default data
@@ -814,14 +315,13 @@ std::map<std::string, CountryData> GetCountryDataMap() {
for (const char* const* country_pointer = icu::Locale::getISOCountries();
*country_pointer; ++country_pointer) {
std::string country_code = *country_pointer;
- if (!country_data.count(country_code)) {
- CountryData data = {IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE};
- country_data.insert(
- std::make_pair(std::move(country_code), std::move(data)));
+ if (!import_requirements.count(country_code)) {
+ import_requirements.insert(std::make_pair(
+ std::move(country_code),
+ RequiredFieldsForAddressImport::ADDRESS_REQUIREMENTS_UNKNOWN));
}
}
- return country_data;
+ return import_requirements;
}
std::map<std::string, std::string> GetCountryCodeAliasMap() {
@@ -844,23 +344,25 @@ CountryDataMap* CountryDataMap::GetInstance() {
}
CountryDataMap::CountryDataMap()
- : country_data_(GetCountryDataMap()),
+ : required_fields_for_address_import_map_(GetCountryDataMap()),
country_code_aliases_(GetCountryCodeAliasMap()),
country_codes_(GetCountryCodes()) {}
CountryDataMap::~CountryDataMap() = default;
-bool CountryDataMap::HasCountryData(const std::string& country_code) const {
- return country_data_.count(country_code) > 0;
+bool CountryDataMap::HasRequiredFieldsForAddressImport(
+ const std::string& country_code) const {
+ return required_fields_for_address_import_map_.count(country_code) > 0;
}
-const CountryData& CountryDataMap::GetCountryData(
+RequiredFieldsForAddressImport
+CountryDataMap::GetRequiredFieldsForAddressImport(
const std::string& country_code) const {
- auto lookup = country_data_.find(country_code);
- if (lookup != country_data_.end())
+ auto lookup = required_fields_for_address_import_map_.find(country_code);
+ if (lookup != required_fields_for_address_import_map_.end())
return lookup->second;
// If there is no entry for country_code return the entry for the US.
- return country_data_.find("US")->second;
+ return required_fields_for_address_import_map_.find("US")->second;
}
bool CountryDataMap::HasCountryCodeAlias(
@@ -872,7 +374,7 @@ const std::string CountryDataMap::GetCountryCodeForAlias(
const std::string& country_code_alias) const {
auto lookup = country_code_aliases_.find(country_code_alias);
if (lookup != country_code_aliases_.end()) {
- DCHECK(HasCountryData(lookup->second));
+ DCHECK(HasRequiredFieldsForAddressImport(lookup->second));
return lookup->second;
}
return std::string();
diff --git a/chromium/components/autofill/core/browser/geo/country_data.h b/chromium/components/autofill/core/browser/geo/country_data.h
index d30783a6276..12ae5f8cf17 100644
--- a/chromium/components/autofill/core/browser/geo/country_data.h
+++ b/chromium/components/autofill/core/browser/geo/country_data.h
@@ -20,7 +20,7 @@ namespace autofill {
// The minimal required fields for an address to be complete for a given
// country.
-enum AddressRequiredFields {
+enum RequiredFieldsForAddressImport {
ADDRESS_REQUIRES_CITY = 1 << 0,
ADDRESS_REQUIRES_STATE = 1 << 1,
ADDRESS_REQUIRES_ZIP = 1 << 2,
@@ -52,19 +52,6 @@ enum AddressRequiredFields {
ADDRESS_REQUIREMENTS_UNKNOWN = ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP,
};
-// This struct describes the address format typical for a particular country.
-struct CountryData {
- // Resource identifier for the string used to denote postal codes.
- int postal_code_label_id;
-
- // Resource identifier for the string used to denote the major subdivision
- // below the "country" level.
- int state_label_id;
-
- // The required parts of the address.
- AddressRequiredFields address_required_fields;
-};
-
// A singleton class that encapsulates a map from country codes to country data.
class CountryDataMap {
public:
@@ -72,7 +59,7 @@ class CountryDataMap {
// Returns true if a |CountryData| entry for the supplied |country_code|
// exists.
- bool HasCountryData(const std::string& country_code) const;
+ bool HasRequiredFieldsForAddressImport(const std::string& country_code) const;
// Returns true if there is a country code alias for |country_code|.
bool HasCountryCodeAlias(const std::string& country_code_alias) const;
@@ -82,9 +69,10 @@ class CountryDataMap {
const std::string GetCountryCodeForAlias(
const std::string& country_code_alias) const;
- // Lookup the |CountryData| for the supplied |country_code|. If no entry
- // exists, return the data for the US as a best guess.
- const CountryData& GetCountryData(const std::string& country_code) const;
+ // Lookup the |RequiredFieldForAddressImport| for the supplied |country_code|.
+ // If no entry exists, return requirements for the US as a best guess.
+ RequiredFieldsForAddressImport GetRequiredFieldsForAddressImport(
+ const std::string& country_code) const;
// Return a constant reference to a vector of all country codes.
const std::vector<std::string>& country_codes() { return country_codes_; }
@@ -94,7 +82,8 @@ class CountryDataMap {
~CountryDataMap();
friend struct base::DefaultSingletonTraits<CountryDataMap>;
- const std::map<std::string, CountryData> country_data_;
+ const std::map<std::string, RequiredFieldsForAddressImport>
+ required_fields_for_address_import_map_;
const std::map<std::string, std::string> country_code_aliases_;
const std::vector<std::string> country_codes_;
diff --git a/chromium/components/autofill/core/browser/geo/subkey_requester.cc b/chromium/components/autofill/core/browser/geo/subkey_requester.cc
index 5bbc0dda70f..0eb5da274bc 100644
--- a/chromium/components/autofill/core/browser/geo/subkey_requester.cc
+++ b/chromium/components/autofill/core/browser/geo/subkey_requester.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
index b167d01018f..506fadb82f0 100644
--- a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
@@ -4,8 +4,8 @@
#include "components/autofill/core/browser/logging/log_buffer_submitter.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/values.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/logging/log_receiver.h"
diff --git a/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc b/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
index e9c2ab752f4..19806be5c00 100644
--- a/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
@@ -5,7 +5,7 @@
#include "components/autofill/core/browser/logging/log_manager.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "components/autofill/core/browser/logging/log_receiver.h"
#include "components/autofill/core/browser/logging/log_router.h"
diff --git a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
index 95e479a4740..ecae251fd12 100644
--- a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
+++ b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
@@ -13,7 +13,6 @@
#include "components/autofill/core/browser/form_data_importer.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/autofill_tick_clock.h"
namespace autofill {
@@ -50,19 +49,6 @@ void CreditCardFormEventLogger::OnDidSelectCardSuggestion(
AutofillSyncSigninState sync_state) {
sync_state_ = sync_state;
- // When server nicknames are available, if any card is selected, log the
- // selection duration.
- if (has_server_nickname_ && !has_logged_suggestion_selected_timestamp_) {
- has_logged_suggestion_selected_timestamp_ = true;
- base::TimeTicks now = AutofillTickClock::NowTicks();
- // Suggestion selection should always chronologically follow suggestion
- // shown.
- DCHECK(now > first_suggestion_shown_timestamp_);
- base::UmaHistogramMediumTimes(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- now - first_suggestion_shown_timestamp_);
- }
-
if (has_eligible_offer_) {
card_selected_has_offer_ = DoesCardHaveOffer(credit_card);
base::UmaHistogramBoolean("Autofill.Offer.SelectedCardHasOffer",
@@ -189,8 +175,6 @@ void CreditCardFormEventLogger::LogUkmInteractedWithForm(
}
void CreditCardFormEventLogger::OnSuggestionsShownOnce() {
- // Record the timestamp of the first suggestion shown.
- first_suggestion_shown_timestamp_ = AutofillTickClock::NowTicks();
base::UmaHistogramBoolean("Autofill.Offer.SuggestedCardsHaveOffer",
has_eligible_offer_);
}
@@ -214,14 +198,6 @@ void CreditCardFormEventLogger::OnLog(const std::string& name,
NUM_FORM_EVENTS);
}
- // Log a different histogram for credit card forms with server nickname
- // available so that selection rate with server nickname can be compared on
- // their own.
- if (has_server_nickname_) {
- base::UmaHistogramEnumeration(name + ".WithServerNickname", event,
- NUM_FORM_EVENTS);
- }
-
// Log a different histogram for credit card forms with credit card offers
// available so that selection rate with offers and rewards can be compared on
// their own.
diff --git a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
index a84566a1b3f..4fb93962afc 100644
--- a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
+++ b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
@@ -46,10 +46,6 @@ class CreditCardFormEventLogger : public FormEventLoggerBase {
is_context_secure_ = is_context_secure;
}
- void set_has_server_nickname(bool has_server_nickname) {
- has_server_nickname_ = has_server_nickname;
- }
-
void set_suggestions(std::vector<Suggestion> suggestions);
void OnDidSelectCardSuggestion(const CreditCard& credit_card,
@@ -97,18 +93,11 @@ class CreditCardFormEventLogger : public FormEventLoggerBase {
bool is_context_secure_ = false;
UnmaskAuthFlowType current_authentication_flow_;
bool has_logged_masked_server_card_suggestion_selected_ = false;
- bool has_logged_suggestion_selected_timestamp_ = false;
bool logged_suggestion_filled_was_masked_server_card_ = false;
- base::TimeTicks first_suggestion_shown_timestamp_;
std::vector<Suggestion> suggestions_;
bool has_eligible_offer_ = false;
bool card_selected_has_offer_ = false;
- // True when ANY of the masked server cards has a nickname. Note that,
- // depending on the experimental setup, the user may not be shown the
- // nickname.
- bool has_server_nickname_ = false;
-
// Weak references.
PersonalDataManager* personal_data_manager_;
AutofillClient* client_;
diff --git a/chromium/components/autofill/core/browser/pattern_provider/DEPS b/chromium/components/autofill/core/browser/pattern_provider/DEPS
new file mode 100644
index 00000000000..89e4cd8553f
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/grit/components_resources.h",
+ "+services/data_decoder/public/cpp:cpp",
+ "+services/data_decoder/public",
+]
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
new file mode 100644
index 00000000000..3aaeb3d97a9
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
@@ -0,0 +1,228 @@
+// 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/pattern_configuration_parser.h"
+
+#include "base/bind.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/grit/components_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace autofill {
+
+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";
+const char kMatchFieldAttributesKey[] = "match_field_attributes";
+const char kMatchFieldInputTypesKey[] = "match_field_input_types";
+const char kVersionKey[] = "version";
+
+bool ParseMatchingPattern(PatternProvider::Map& patterns,
+ const std::string& field_type,
+ const std::string& 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 =
+ value.FindStringKey(kNegativePatternKey);
+ base::Optional<double> positive_score =
+ value.FindDoubleKey(kPositiveScoreKey);
+ base::Optional<int> match_field_attributes =
+ value.FindIntKey(kMatchFieldAttributesKey);
+ base::Optional<int> match_field_input_types =
+ value.FindIntKey(kMatchFieldInputTypesKey);
+
+ if (!pattern_identifier || !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.match_field_attributes = match_field_attributes.value();
+ new_pattern.match_field_input_types = match_field_input_types.value();
+ new_pattern.language = language;
+
+ // Shift to the right to match the MatchFieldTypes enum, which temporarily
+ // starts at 1<<2 instead of 1<<0.
+ new_pattern.match_field_input_types <<= 2;
+
+ 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 << "|.";
+
+ 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
+// 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.
+ if (!result.value) {
+ DVLOG(1) << "Failed to parse PatternProvider configuration JSON string.";
+ std::move(done_callback).Run();
+ return;
+ }
+
+ base::Version version = ExtractVersionFromJsonObject(result.value.value());
+ base::Optional<PatternProvider::Map> patterns =
+ GetConfigurationFromJsonObject(result.value.value());
+
+ 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);
+ } else {
+ DVLOG(1) << "Failed to parse PatternProvider configuration JSON object.";
+ }
+
+ std::move(done_callback).Run();
+}
+
+} // namespace
+
+base::Optional<PatternProvider::Map> GetConfigurationFromJsonObject(
+ const base::Value& root) {
+ PatternProvider::Map patterns;
+
+ if (!root.is_dict()) {
+ DVLOG(1) << "JSON object is not a dictionary.";
+ return base::nullopt;
+ }
+
+ for (const auto& kv : root.DictItems()) {
+ const std::string& field_type = kv.first;
+ const base::Value* field_type_dict = &kv.second;
+
+ if (!field_type_dict->is_dict()) {
+ DVLOG(1) << "|" << field_type << "| does not contain a dictionary.";
+ return base::nullopt;
+ }
+
+ for (const auto& value : field_type_dict->DictItems()) {
+ const std::string& language = value.first;
+ const base::Value* inner_list = &value.second;
+
+ if (!inner_list->is_list()) {
+ DVLOG(1) << "Language |" << language << "| in |" << field_type
+ << "| does not contain a list.";
+ return base::nullopt;
+ }
+
+ for (const auto& matchingPatternObj : inner_list->GetList()) {
+ bool success = ParseMatchingPattern(patterns, field_type, language,
+ matchingPatternObj);
+ if (!success) {
+ DVLOG(1) << "Found incorrect |MatchingPattern| object in list |"
+ << field_type << "|, language |" << language << "|.";
+ return base::nullopt;
+ }
+ }
+ }
+ }
+
+ return base::make_optional(patterns);
+}
+
+base::Version ExtractVersionFromJsonObject(base::Value& root) {
+ if (!root.is_dict())
+ return base::Version("0");
+
+ base::Optional<base::Value> version_str = root.ExtractKey(kVersionKey);
+ if (!version_str || !version_str.value().is_string())
+ return base::Version("0");
+
+ base::Version version = base::Version(version_str.value().GetString());
+ if (!version.IsValid())
+ return base::Version("0");
+
+ return version;
+}
+
+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)));
+}
+
+base::Optional<PatternProvider::Map>
+GetPatternsFromResourceBundleSynchronously() {
+ if (!ui::ResourceBundle::HasSharedInstance()) {
+ VLOG(1) << "Resource Bundle unavailable to load Autofill Matching Pattern "
+ "definitions.";
+ return base::nullopt;
+ }
+
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ std::string resource_string =
+ bundle.LoadDataResourceString(IDR_AUTOFILL_REGEX_JSON);
+ base::Optional<base::Value> json_object =
+ base::JSONReader::Read(resource_string);
+
+ // Discard version, since this is the only getter used in unit tests.
+ base::Version version = ExtractVersionFromJsonObject(json_object.value());
+ base::Optional<PatternProvider::Map> configuration_map =
+ GetConfigurationFromJsonObject(json_object.value());
+
+ return configuration_map;
+}
+
+} // namespace field_type_parsing
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h
new file mode 100644
index 00000000000..8f72b18bf31
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h
@@ -0,0 +1,60 @@
+// 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_PATTERN_CONFIGURATION_PARSER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_PATTERN_CONFIGURATION_PARSER_H_
+
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/version.h"
+#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+
+namespace autofill {
+
+namespace field_type_parsing {
+
+// Tries to extract the configuration version from the JSON base::Value tree.
+// This removes the key if found, so that validation is easier later on.
+// If not found, default to version 0.
+base::Version ExtractVersionFromJsonObject(base::Value& root);
+
+// Transforms the parsed JSON base::Value tree into the map used in
+// |PatternProvider|. Requires the version key to already be extracted.
+// The root is expected to be a dictionary with keys corresponding to
+// strings representing |ServerFieldType|. Then there should be
+// second level dictionaries with keys describing the language. These
+// should point to a list of objects representing |MatchingPattern|.
+// {
+// "FIELD_NAME": {
+// "language":[
+// {MatchingPatternFields}
+// ]
+// }
+// }
+// An example can be found in the relative resources folder.
+base::Optional<PatternProvider::Map> GetConfigurationFromJsonObject(
+ const base::Value& root);
+
+// Tries to get and parse the default configuration in the resource bundle
+// into a valid map used in |PatternProvider| and swap it in for further use.
+// The callback is used as a signal for testing.
+void PopulateFromResourceBundle(
+ base::OnceClosure done_callback = base::DoNothing::Once());
+
+// Tries to parse the given JSON string into a valid map used in the
+// |PatternProvider| and swap it in for further use.
+void PopulateFromJsonString(std::string json_string);
+
+// Synchronous getter used to set up a test fixture.
+base::Optional<PatternProvider::Map>
+GetPatternsFromResourceBundleSynchronously();
+
+} // namespace field_type_parsing
+
+} // namespace autofill
+
+#endif
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
new file mode 100644
index 00000000000..a9cd570a644
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
@@ -0,0 +1,196 @@
+// 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/pattern_configuration_parser.h"
+
+#include <stddef.h>
+
+#include "base/json/json_reader.h"
+#include "base/test/gtest_util.h"
+#include "base/version.h"
+#include "components/grit/components_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace autofill {
+
+namespace field_type_parsing {
+
+// Test that the |base::Value| object of the configuration is
+// parsed to the map structure used by |PatternProvider| as
+// expected, given the input is valid.
+TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
+ std::string JSON_message = R"(
+ {
+ "version": "1.0",
+ "FULL_NAME": {
+ "en_us": [
+ {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "Name_fr",
+ "positive_pattern": "nom|prenom",
+ "positive_score": 2.0,
+ "negative_pattern": "compagne",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ]
+ },
+ "ADDRESS": {
+ "en_us": [
+ {
+ "pattern_identifier": "Address",
+ "positive_pattern": "address",
+ "positive_score": 2.0,
+ "negative_pattern": "email",
+ "match_field_attributes": 4,
+ "match_field_input_types": 3
+ }
+ ]
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Version version = ExtractVersionFromJsonObject(JSON_object.value());
+ base::Optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(JSON_object.value());
+
+ ASSERT_TRUE(version.IsValid());
+ ASSERT_TRUE(optional_patterns);
+
+ ASSERT_EQ(base::Version("1.0"), version);
+
+ PatternProvider::Map patterns = optional_patterns.value();
+
+ 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.count("ADDRESS"));
+ ASSERT_EQ(1U, patterns["ADDRESS"].size());
+ ASSERT_TRUE(patterns["ADDRESS"].count("en_us"));
+
+ // Test one |MatchingPattern| to check that they are parsed correctly.
+ MatchingPattern* pattern = &patterns["FULL_NAME"]["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_NEAR(2.0, pattern->positive_score, 1e-6);
+ ASSERT_EQ(2, pattern->match_field_attributes);
+ ASSERT_EQ(3 << 2, pattern->match_field_input_types);
+}
+
+// Test that the parser does not return anything if some |MatchingPattern|
+// object is missing a property.
+TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
+ std::string JSON_message = R"(
+ {
+ "version": "1.0",
+ "FULL_NAME": {
+ "en_us": [
+ {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "Name_fr",
+ "positive_pattern": "nom|prenom",
+ "negative_pattern": "compagne",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ]
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(JSON_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+// 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"(
+ {
+ "FULL_NAME": {
+ "en_us": [
+ {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ]
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Version version = ExtractVersionFromJsonObject(JSON_object.value());
+
+ ASSERT_EQ(base::Version("0"), version);
+}
+
+// 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"(
+ {
+ "FULL_NAME": {
+ "en_us": {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(JSON_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+} // namespace field_type_parsing
+
+} // namespace autofill
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 04a2d48bac1..349c0d8c39a 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
@@ -8,42 +8,171 @@
#include <iostream>
#include <string>
+#include "base/bind.h"
+#include "base/feature_list.h"
+#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/pattern_configuration_parser.h"
+#include "components/autofill/core/common/autofill_features.h"
namespace autofill {
-PatternProvider::PatternProvider() {
- auto& company_patterns = patterns_[AutofillType(COMPANY_NAME).ToString()];
- company_patterns["EN"].push_back(GetCompanyPatternEn());
- company_patterns["DE"].push_back(GetCompanyPatternDe());
+
+namespace {
+const char* kSourceCodeLanguage = "en";
+
+// Adds the English patterns, restricted to MatchFieldType MATCH_NAME, to
+// every other language.
+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 =
+ p.second;
+
+ auto it = lang_to_patterns.find(kSourceCodeLanguage);
+ if (it == lang_to_patterns.end())
+ continue;
+ std::vector<MatchingPattern> en_patterns = it->second;
+ for (MatchingPattern& en_pattern : en_patterns) {
+ en_pattern.match_field_attributes = MATCH_NAME;
+ }
+
+ for (auto& q : lang_to_patterns) {
+ const std::string& page_language = q.first;
+ std::vector<MatchingPattern>& patterns = q.second;
+
+ if (page_language != kSourceCodeLanguage) {
+ patterns.insert(patterns.end(), en_patterns.begin(), en_patterns.end());
+ }
+ }
+ }
}
-PatternProvider::~PatternProvider() {
- patterns_.clear();
+// 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 =
+ p.second;
+ for (auto& q : lang_to_patterns) {
+ std::vector<MatchingPattern>& patterns = q.second;
+ std::sort(patterns.begin(), patterns.end(),
+ [](const MatchingPattern& mp1, const MatchingPattern& mp2) {
+ return mp1.positive_score > mp2.positive_score;
+ });
+ }
+ }
+}
+}
+
+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();
+ }
+ }
+ return *g_pattern_provider;
}
-void PatternProvider::SetPatterns(
- const std::map<std::string,
- std::map<std::string, std::vector<MatchingPattern>>>&
- patterns) {
- patterns_ = patterns;
+// static
+void PatternProvider::ResetPatternProvider() {
+ g_pattern_provider = nullptr;
}
-const std::vector<MatchingPattern>& PatternProvider::GetMatchPatterns(
+PatternProvider::PatternProvider() = default;
+PatternProvider::~PatternProvider() = default;
+
+void PatternProvider::SetPatterns(PatternProvider::Map patterns,
+ const base::Version version,
+ const bool overwrite_equal_version) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!pattern_version_.IsValid() || pattern_version_ < version ||
+ (overwrite_equal_version && pattern_version_ == version)) {
+ patterns_ = patterns;
+ pattern_version_ = version;
+ EnrichPatternsWithEnVersion(&patterns_);
+ SortPatternsByScore(&patterns_);
+ }
+}
+
+const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
const std::string& pattern_name,
- const std::string& page_language) {
- return patterns_[pattern_name][page_language];
+ const std::string& 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)) {
+ auto outer_it = patterns_.find(pattern_name);
+ if (outer_it != patterns_.end()) {
+ const std::map<std::string, 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()) {
+ const std::vector<MatchingPattern>& patterns = inner_it->second;
+ if (!patterns.empty()) {
+ return patterns;
+ }
+ }
+ }
+ return GetAllPatternsByType(pattern_name);
+ } else if (
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ return GetAllPatternsByType(pattern_name);
+ } else {
+ return {};
+ }
}
-const std::vector<MatchingPattern>& PatternProvider::GetMatchPatterns(
+const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
ServerFieldType type,
- const std::string& page_language) {
+ const std::string& page_language) const {
std::string pattern_name = AutofillType(type).ToString();
return GetMatchPatterns(pattern_name, page_language);
}
-PatternProvider* PatternProvider::getInstance() {
- static base::NoDestructor<PatternProvider> instance;
- return instance.get();
+const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
+ ServerFieldType type) const {
+ std::string type_str = AutofillType(type).ToString();
+ return GetAllPatternsByType(type_str);
+}
+
+const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
+ const std::string& type) const {
+ auto it = patterns_.find(type);
+ if (it == patterns_.end())
+ return {};
+ const std::map<std::string, 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 std::vector<MatchingPattern>& language_patterns = p.second;
+ for (const MatchingPattern& mp : language_patterns) {
+ if (page_language == kSourceCodeLanguage ||
+ mp.language != kSourceCodeLanguage) {
+ all_language_patterns.push_back(mp);
+ }
+ }
+ }
+ return all_language_patterns;
}
} // namespace autofill
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 2cb7422023b..4ddd9cf6469 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
@@ -7,52 +7,91 @@
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/no_destructor.h"
+#include "base/sequence_checker.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/autofill_regex_constants.h"
-#include "third_party/re2/src/re2/re2.h"
namespace autofill {
+// Base class for the Pattern Provider. This class contains the implementation
+// for providing the matching patterns. Different subclasses provide different
+// ways to load the data in for further use.
class PatternProvider {
public:
- static PatternProvider* getInstance();
+ // 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>>>;
- // Setter for loaded patterns from external storage.
- void SetPatterns(
- const std::map<std::string,
- std::map<std::string, std::vector<MatchingPattern>>>&
- patterns);
+ // Returns a reference to the global Pattern Provider.
+ static PatternProvider& GetInstance();
- // Provides us with all patterns that can match our field type and page
- // language.
- const std::vector<MatchingPattern>& GetMatchPatterns(
+ // Setter for loading patterns from external storage.
+ void SetPatterns(const Map patterns,
+ const base::Version version,
+ const bool overwrite_equal_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 std::string& page_language) const;
- const std::vector<MatchingPattern>& GetMatchPatterns(
+ // 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 std::string& page_language) const;
- // Provides us with all patterns that can match our field type.
- const std::vector<MatchingPattern>& GetAllPatternsBaseOnType(
- ServerFieldType type);
+ // Find all patterns, across all languages, for a given server field |type|.
+ const std::vector<MatchingPattern> GetAllPatternsByType(
+ ServerFieldType type) const;
+
+ // Find all patterns, across all languages, for a given server field |type|.
+ const std::vector<MatchingPattern> GetAllPatternsByType(
+ 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();
- private:
PatternProvider();
~PatternProvider();
- // Func to sort the incoming map by score.
- void SortPatternsByScore(std::vector<MatchingPattern>& patterns);
+ const Map& patterns() const { return patterns_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderPipelineTest,
+ TestParsingEquivalent);
+ FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderPipelineTest,
+ DefaultPatternProviderLoads);
+
+ 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.
+ SEQUENCE_CHECKER(sequence_checker_);
// Local map to store a vector of patterns keyed by field type and
// page language.
- std::map<std::string, std::map<std::string, std::vector<MatchingPattern>>>
- patterns_;
+ Map patterns_;
- friend class base::NoDestructor<PatternProvider>;
+ // Version for keeping track which pattern set is currently used.
+ base::Version pattern_version_;
};
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_PATTERN_PROVIDER_H_ \ No newline at end of file
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_PATTERN_PROVIDER_H_
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 7259a75d56e..5222b67d903 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
@@ -2,8 +2,6 @@
// 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/pattern_provider.h"
-
#include <stddef.h>
#include <map>
@@ -11,10 +9,83 @@
#include <vector>
#include "base/test/gtest_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_types.h"
+#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 "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
+namespace {
+
+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.negative_pattern = "";
+ m_p.match_field_attributes = MATCH_NAME;
+ m_p.match_field_input_types = MATCH_TEXT;
+ m_p.language = "en";
+ 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.negative_pattern = "";
+ m_p.match_field_attributes = MATCH_LABEL | MATCH_NAME;
+ m_p.match_field_input_types = MATCH_TEXT;
+ m_p.language = "de";
+ return m_p;
+}
+
+// Pattern Provider with custom values set for testing.
+class UnitTestPatternProvider : public PatternProvider {
+ public:
+ UnitTestPatternProvider();
+ UnitTestPatternProvider(const std::vector<MatchingPattern>& de_patterns,
+ const std::vector<MatchingPattern>& en_patterns);
+ ~UnitTestPatternProvider();
+};
+
+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);
+}
+
+UnitTestPatternProvider::~UnitTestPatternProvider() {
+ PatternProvider::ResetPatternProvider();
+}
+
+} // 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 &&
@@ -26,14 +97,165 @@ bool operator==(const MatchingPattern& mp1, const MatchingPattern& mp2) {
}
TEST(AutofillPatternProvider, Single_Match) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
+
MatchingPattern kCompanyPatternEn = GetCompanyPatternEn();
MatchingPattern kCompanyPatternDe = GetCompanyPatternDe();
- PatternProvider* pattern_provider = PatternProvider::getInstance();
+ 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);
+}
+
+// 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 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);
+
+ 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();
+
+ TestPatternProvider test_pattern_provider;
+
+ EXPECT_EQ(default_pattern_provider.patterns(),
+ test_pattern_provider.patterns());
+}
+
+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);
+}
+
+TEST(AutofillPatternProvider, UnknownLanguages) {
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+ // disabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", ""),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "blabla"),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ }
+
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ // disabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", ""),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "blabla"),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ }
+}
+
+TEST(AutofillPatternProvider, EnrichPatternsWithEnVersion) {
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+ // disabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "en"),
+ std::vector<MatchingPattern>{GetCompanyPatternEn()});
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "de"),
+ std::vector<MatchingPattern>(
+ {GetCompanyPatternDe(), GetCompanyPatternEn()}));
+ }
+
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ // disabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+ 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()}));
+ }
+}
- ASSERT_TRUE(pattern_provider->GetMatchPatterns("COMPANY_NAME", "EN").size() >
- 0);
- EXPECT_EQ(pattern_provider->GetMatchPatterns("COMPANY_NAME", "EN")[0],
- kCompanyPatternEn);
+TEST(AutofillPatternProvider, SortPatternsByScore) {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns,
+ features::kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ // disabled
+ {});
+ std::vector<MatchingPattern> de_input_patterns;
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns[0].positive_score = 3.0;
+ de_input_patterns[1].positive_score = 1.0;
+ de_input_patterns[2].positive_score = 5.0;
+ de_input_patterns[3].positive_score = 3.0;
+ UnitTestPatternProvider p(de_input_patterns, {});
+ const std::vector<MatchingPattern>& de_patterns =
+ p.GetMatchPatterns(COMPANY_NAME, "de");
+ 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);
+ EXPECT_EQ(de_patterns[2].positive_score, 3.0);
+ EXPECT_EQ(de_patterns[3].positive_score, 1.0);
}
-} // namespace autofill \ No newline at end of file
+} // namespace autofill
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
new file mode 100644
index 00000000000..16778eac24e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
@@ -0,0 +1,2947 @@
+{
+ "ADDRESS_HOME_STREET_NAME": {
+ "en" : [
+ {
+ "pattern_identifier": "en_street_name",
+ "positive_pattern": "street",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de" : [
+ {
+ "pattern_identifier": "de_street_name",
+ "positive_pattern": "stra(ss|ß)e",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru" : [
+ {
+ "pattern_identifier": "ru_street_name",
+ "positive_pattern": "улица|название.?улицы",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt" : [
+ {
+ "pattern_identifier": "pt_street_name",
+ "positive_pattern": "rua|avenida|((?<!do |de )endereço)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_HOME_HOUSE_NUMBER":{
+ "en": [
+ {
+ "pattern_identifier": "en_house_number",
+ "positive_pattern": "(house.?|street.?|^)number",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_house_number",
+ "positive_pattern": "(haus|^)nummer",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_house_number",
+ "positive_pattern": "^\\*?.?número(.?\\*?$| da residência)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_house_number",
+ "positive_pattern": "дом|номер.?дома",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ATTENTION_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_attention_ignored_preserving",
+ "positive_pattern": "attention|attn",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "REGION_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_region_ignored_preserving",
+ "positive_pattern": "province|region|other",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_region_ignored_preserving",
+ "positive_pattern": "provincia",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_region_ignored_preserving",
+ "positive_pattern": "bairro|suburb",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_NAME_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_name_ignored_preserving",
+ "positive_pattern": "address.*nickname|address.*label",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "COMPANY": {
+ "en": [
+ {
+ "pattern_identifier": "en_company_preserving",
+ "positive_pattern": "company|business|organization|organisation",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_company_preserving",
+ "positive_pattern": "(?<!con)firma|firmenname",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_company_preserving",
+ "positive_pattern": "empresa",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_company_preserving",
+ "positive_pattern": "societe|société",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_company_preserving",
+ "positive_pattern": "ragione.?sociale",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_company_preserving",
+ "positive_pattern": "会社",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_company_preserving",
+ "positive_pattern": "название.?компании",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_company_preserving",
+ "positive_pattern": "单位|公司",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_company_preserving",
+ "positive_pattern": "شرکت",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_company_preserving",
+ "positive_pattern": "회사|직장",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LINE_1": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_line_1_preserving",
+ "positive_pattern": "^address$|address[_-]?line(one)?|address1|addr1|street|(?:shipping|billing)address$|house.?name",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "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_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_address_line_1_preserving",
+ "positive_pattern": "strasse|straße",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_address_line_1_preserving",
+ "positive_pattern": "direccion|dirección",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_address_line_1_preserving",
+ "positive_pattern": "adresse",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "fr_address_line_1_label_preserving",
+ "positive_pattern": "adresse",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_address_line_1_preserving",
+ "positive_pattern": "indirizzo",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "it_address_line_1_label_preserving",
+ "positive_pattern": "indirizzo",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_address_line_1_preserving",
+ "positive_pattern": "^住所$|住所1",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "ja_address_line_1_label_preserving",
+ "positive_pattern": "住所",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_address_line_1_preserving",
+ "positive_pattern": "morada|((?<!do |de )endereço)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_address_line_1_preserving",
+ "positive_pattern": "Адрес",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_address_line_1_preserving",
+ "positive_pattern": "地址",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "zh_address_line_1_label_preserving",
+ "positive_pattern": "地址",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_address_line_1_preserving",
+ "positive_pattern": "(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "tr_address_line_1_label_preserving",
+ "positive_pattern": "(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_address_line_1_preserving",
+ "positive_pattern": "^주소.?$|주소.?1",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ,
+ {
+ "pattern_identifier": "ko_address_line_1_label_preserving",
+ "positive_pattern": "주소",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LINE_2": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_line_2_preserving",
+ "positive_pattern": "address[_-]?line(2|two)|address2|addr2|street|suite|unit",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "en_address_line_2_label_preserving",
+ "positive_pattern": "address|line",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_address_line_2_preserving",
+ "positive_pattern": "adresszusatz|ergänzende.?angaben",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_address_line_2_preserving",
+ "positive_pattern": "direccion2|colonia|adicional",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_address_line_2_preserving",
+ "positive_pattern": "addresssuppl|complementnom|appartement",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "fr_address_line_2_label_preserving",
+ "positive_pattern": "adresse",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_address_line_2_preserving",
+ "positive_pattern": "indirizzo2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "it_address_line_2_label_preserving",
+ "positive_pattern": "indirizzo",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_address_line_2_preserving",
+ "positive_pattern": "住所2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_address_line_2_preserving",
+ "positive_pattern": "complemento|addrcomplement",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_address_line_2_preserving",
+ "positive_pattern": "Улица",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_address_line_2_preserving",
+ "positive_pattern": "地址2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "zh_address_line_2_label_preserving",
+ "positive_pattern": "地址",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_address_line_2_preserving",
+ "positive_pattern": "주소.?2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "ko_address_line_2_label_preserving",
+ "positive_pattern": "주소",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LINE_EXTRA": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_line_extra_preserving",
+ "positive_pattern": "address.*line[3-9]|address[3-9]|addr[3-9]|street|line[3-9]",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_address_line_extra_preserving",
+ "positive_pattern": "municipio",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_address_line_extra_preserving",
+ "positive_pattern": "batiment|residence",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_address_line_extra_preserving",
+ "positive_pattern": "indirizzo[3-9]",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LOOKUP": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_lookup_preserving",
+ "positive_pattern": "lookup",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "COUNTRY": {
+ "en": [
+ {
+ "pattern_identifier": "en_country_preserving",
+ "positive_pattern": "country|countries",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_country_preserving",
+ "positive_pattern": "país|pais",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_country_preserving",
+ "positive_pattern": "(\\b|_)land(\\b|_)(?!.*(mark.*))",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_country_preserving",
+ "positive_pattern": "(?<!(入|出))国",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_country_preserving",
+ "positive_pattern": "国家",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_country_preserving",
+ "positive_pattern": "국가|나라",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_country_preserving",
+ "positive_pattern": "(\\b|_)(ülke|ulce|ulke)(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_country_preserving",
+ "positive_pattern": "کشور",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "COUNTRY_LOCATION": {
+ "en": [
+ {
+ "pattern_identifier": "en_country_location_preserving",
+ "positive_pattern": "location",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 136
+ }
+ ]
+ },
+ "ZIP_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_zip_code_preserving",
+ "positive_pattern": "zip|postal|post.*code|pcode|pin.?code",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_zip_code_preserving",
+ "positive_pattern": "postleitzahl",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_zip_code_preserving",
+ "positive_pattern": "\\bcp\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_zip_code_preserving",
+ "positive_pattern": "\\bcdp\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_zip_code_preserving",
+ "positive_pattern": "\\bcap\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_zip_code_preserving",
+ "positive_pattern": "郵便番号",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_zip_code_preserving",
+ "positive_pattern": "codigo|codpos|\\bcep\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_zip_code_preserving",
+ "positive_pattern": "Почтовый.?Индекс",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_zip_code_preserving",
+ "positive_pattern": "पिन.?कोड",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_zip_code_preserving",
+ "positive_pattern": "പിന്‍കോഡ്",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_zip_code_preserving",
+ "positive_pattern": "邮政编码|邮编|郵遞區號",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_zip_code_preserving",
+ "positive_pattern": "(\\b|_)posta kodu(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_zip_code_preserving",
+ "positive_pattern": "우편.?번호",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "ZIP_4": {
+ "en": [
+ {
+ "pattern_identifier": "en_zip_4_preserving",
+ "positive_pattern": "zip|^-$|post2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_zip_4_preserving",
+ "positive_pattern": "codpos2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "CITY": {
+ "en": [
+ {
+ "pattern_identifier": "en_city_preserving",
+ "positive_pattern": "city|town|suburb",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_city_preserving",
+ "positive_pattern": "\\bort\\b|stadt",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_city_preserving",
+ "positive_pattern": "ciudad|provincia|localidad|poblacion",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_city_preserving",
+ "positive_pattern": "ville|commune",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_city_preserving",
+ "positive_pattern": "localita",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_city_preserving",
+ "positive_pattern": "市区町村",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_city_preserving",
+ "positive_pattern": "cidade|município",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_city_preserving",
+ "positive_pattern": "Город|Населённый.?пункт",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_city_preserving",
+ "positive_pattern": "市|分區",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_city_preserving",
+ "positive_pattern": "شهر",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_city_preserving",
+ "positive_pattern": "शहर|ग्राम|गाँव",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_city_preserving",
+ "positive_pattern": "നഗരം|ഗ്രാമം",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_city_preserving",
+ "positive_pattern": "((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_city_preserving",
+ "positive_pattern": "^시[^도·・]|시[·・]?군[·・]?구",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "STATE": {
+ "en": [
+ {
+ "pattern_identifier": "en_state_preserving",
+ "positive_pattern": "(?<!(united|hist|history).?)state|county|region|province|county|principality",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_state_preserving",
+ "positive_pattern": "都道府県",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_state_preserving",
+ "positive_pattern": "estado|provincia",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_state_preserving",
+ "positive_pattern": "область",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_state_preserving",
+ "positive_pattern": "省|地區",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_state_preserving",
+ "positive_pattern": "സംസ്ഥാനം",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_state_preserving",
+ "positive_pattern": "استان",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_state_preserving",
+ "positive_pattern": "राज्य",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_state_preserving",
+ "positive_pattern": "((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_state_preserving",
+ "positive_pattern": "^시[·・]?도",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "SEARCH_TERM": {
+ "en": [
+ {
+ "pattern_identifier": "en_search_term_preserving",
+ "positive_pattern": "^q$|search|query|qry",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_search_term_preserving",
+ "positive_pattern": "suche.*",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_search_term_preserving",
+ "positive_pattern": "搜索",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_search_term_preserving",
+ "positive_pattern": "探す|検索",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_search_term_preserving",
+ "positive_pattern": "recherch.*",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_search_term_preserving",
+ "positive_pattern": "busca",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_search_term_preserving",
+ "positive_pattern": "جستجو",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_search_term_preserving",
+ "positive_pattern": "искать|найти|поиск",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ]
+ },
+ "PRICE": {
+ "en": [
+ {
+ "pattern_identifier": "en_price_preserving",
+ "positive_pattern": "\\bprice\\b|\\brate\\b|\\bcost\\b",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ],
+ "ar": [
+ {
+ "pattern_identifier": "ar_price_preserving",
+ "positive_pattern": "قیمة‎|سعر‎",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_price_preserving",
+ "positive_pattern": "قیمت",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_price_preserving",
+ "positive_pattern": "\\bprix\\b|\\bcoût\\b|\\bcout\\b|\\btarif\\b",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ]
+ },
+ "NAME_ON_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_on_card_preserving",
+ "positive_pattern": "card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card|(?:card|cc).?name|cc.?full.?name",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_name_on_card_preserving",
+ "positive_pattern": "karteninhaber",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_name_on_card_preserving",
+ "positive_pattern": "nombre.*tarjeta",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_name_on_card_preserving",
+ "positive_pattern": "nom.*carte",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_name_on_card_preserving",
+ "positive_pattern": "nome.*cart",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_name_on_card_preserving",
+ "positive_pattern": "名前",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_name_on_card_preserving",
+ "positive_pattern": "Имя.*карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_name_on_card_preserving",
+ "positive_pattern": "信用卡开户名|开户名|持卡人姓名|持卡人姓名",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "NAME_ON_CARD_CONTEXTUAL": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_on_card_contextual_preserving",
+ "positive_pattern": "name",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "CREDIT_CARD_NUMBER": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_number_preserving",
+ "positive_pattern": "(add)?(?:card|cc|acct).?(?:number|#|no|num|field)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_number_preserving",
+ "positive_pattern": "(?<!telefon|haus|person|fødsels)nummer",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_number_preserving",
+ "positive_pattern": "カード番号",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_number_preserving",
+ "positive_pattern": "Номер.*карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_card_number_preserving",
+ "positive_pattern": "信用卡号|信用卡号码|信用卡卡號",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_card_number_preserving",
+ "positive_pattern": "카드",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_number_preserving",
+ "positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_number_preserving",
+ "positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_card_number_preserving",
+ "positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ]
+ },
+ "CREDIT_CARD_VERIFICATION_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_cvc_preserving",
+ "positive_pattern": "verification|card.?identification|security.?code|card.?code|security.?value|security.?number|card.?pin|c-v-v|(cvn|cvv|cvc|csc|cvd|cid|ccv)(field)?|\\bcid\\b",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_MONTH": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_month_preserving",
+ "positive_pattern": "expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_exp_month_preserving",
+ "positive_pattern": "gueltig|gültig|monat",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_exp_month_preserving",
+ "positive_pattern": "fecha",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_card_exp_month_preserving",
+ "positive_pattern": "date.*exp",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_card_exp_month_preserving",
+ "positive_pattern": "scadenza",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_exp_month_preserving",
+ "positive_pattern": "有効期限",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_exp_month_preserving",
+ "positive_pattern": "validade",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_exp_month_preserving",
+ "positive_pattern": "Срок действия карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_card_exp_month_preserving",
+ "positive_pattern": "月",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_year_preserving",
+ "positive_pattern": "exp|^/|(add)?year",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_exp_year_preserving",
+ "positive_pattern": "ablaufdatum|gueltig|gültig|jahr",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_exp_year_preserving",
+ "positive_pattern": "fecha",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_card_exp_year_preserving",
+ "positive_pattern": "scadenza",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_exp_year_preserving",
+ "positive_pattern": "有効期限",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_exp_year_preserving",
+ "positive_pattern": "validade",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_exp_year_preserving",
+ "positive_pattern": "Срок действия карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_card_exp_year_preserving",
+ "positive_pattern": "年|有效期",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_date_2_digit_year_preserving",
+ "positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_date_4_digit_year_preserving",
+ "positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_DATE": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_date_preserving",
+ "positive_pattern": "expir|exp.*date|^expfield$",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_exp_date_preserving",
+ "positive_pattern": "gueltig|gültig",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_exp_date_preserving",
+ "positive_pattern": "fecha",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_card_exp_date_preserving",
+ "positive_pattern": "date.*exp",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_card_exp_date_preserving",
+ "positive_pattern": "scadenza",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_exp_date_preserving",
+ "positive_pattern": "有効期限",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_exp_date_preserving",
+ "positive_pattern": "validade",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_exp_date_preserving",
+ "positive_pattern": "Срок действия карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_MONTH_BEFORE_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_month_before_year_preserving",
+ "positive_pattern": "^mm$",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_YEAR_AFTER_MONTH": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_year_after_month_preserving",
+ "positive_pattern": "^(yy|yyyy)$",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "GIFT_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_gift_card_preserving",
+ "positive_pattern": "gift.?(card|cert)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 197
+ }
+ ]
+ },
+ "DEBIT_GIFT_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_debit_gift_card_preserving",
+ "positive_pattern": "(?:visa|mastercard|discover|amex|american express).*gift.?card",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 197
+ }
+ ]
+ },
+ "DEBIT_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_debit_card_preserving",
+ "positive_pattern": "debit.*card",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 197
+ }
+ ]
+ },
+ "DAY": {
+ "en": [
+ {
+ "pattern_identifier": "en_day_preserving",
+ "positive_pattern": "day",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 9
+ }
+ ]
+ },
+ "EMAIL_ADDRESS": {
+ "en": [
+ {
+ "pattern_identifier": "en_email_preserving",
+ "positive_pattern": "e.?mail",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_email_preserving",
+ "positive_pattern": "courriel",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_email_preserving",
+ "positive_pattern": "correo.*electr(o|ó)nico",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_email_preserving",
+ "positive_pattern": "メールアドレス",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_email_preserving",
+ "positive_pattern": "Электронной.?Почты",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_email_preserving",
+ "positive_pattern": "邮件|邮箱|電郵地址",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_email_preserving",
+ "positive_pattern": "ഇ-മെയില്‍|ഇലക്ട്രോണിക്.?മെയിൽ",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_email_preserving",
+ "positive_pattern": "ایمیل|پست.*الکترونیک",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_email_preserving",
+ "positive_pattern": "ईमेल|इलॅक्ट्रॉनिक.?मेल",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_email_preserving",
+ "positive_pattern": "(\\b|_)eposta(\\b|_)",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_email_preserving",
+ "positive_pattern": "(?:이메일|전자.?우편|[Ee]-?mail)(.?주소)?",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ]
+ },
+ "NAME_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_ignored_preserving",
+ "positive_pattern": "user.?name|user.?id|nickname|maiden name|title|prefix|suffix",
+ "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
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_name_ignored_preserving",
+ "positive_pattern": "vollständiger.?name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_name_ignored_preserving",
+ "positive_pattern": "用户名",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_name_ignored_preserving",
+ "positive_pattern": "(?:사용자.?)?아이디|사용자.?ID",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "FULL_NAME": {
+ "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_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_full_name_preserving",
+ "positive_pattern": "nombre.*y.*apellidos",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_full_name_preserving",
+ "positive_pattern": "^nom(?!bre)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_full_name_preserving",
+ "positive_pattern": "お名前|氏名",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_full_name_preserving",
+ "positive_pattern": "^nome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_full_name_preserving",
+ "positive_pattern": "نام.*نام.*خانوادگی",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_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",
+ "positive_pattern": "(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_full_name_preserving",
+ "positive_pattern": "성명",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "NAME_SPECIFIC": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_specific_preserving",
+ "positive_pattern": "^name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_name_specific_preserving",
+ "positive_pattern": "^nom",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_name_specific_preserving",
+ "positive_pattern": "^nome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "FIRST_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_first_name_preserving",
+ "positive_pattern": "first.*name|initials|fname|first$|given.*name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_first_name_preserving",
+ "positive_pattern": "vorname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_first_name_preserving",
+ "positive_pattern": "nombre",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_first_name_preserving",
+ "positive_pattern": "forename|prénom|prenom",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_first_name_preserving",
+ "positive_pattern": "名",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_first_name_preserving",
+ "positive_pattern": "nome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_first_name_preserving",
+ "positive_pattern": "Имя",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_first_name_preserving",
+ "positive_pattern": "نام",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_first_name_preserving",
+ "positive_pattern": "이름",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_first_name_preserving",
+ "positive_pattern": "പേര്",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_first_name_preserving",
+ "positive_pattern": "(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_first_name_preserving",
+ "positive_pattern": "नाम",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "MIDDLE_INITIAL": {
+ "en": [
+ {
+ "pattern_identifier": "en_middle_initial_preserving",
+ "positive_pattern": "middle.*initial|m\\.i\\.|mi$|\\bmi\\b",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "MIDDLE_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_middle_name_preserving",
+ "positive_pattern": "middle.*name|mname|middle$",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "LAST_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_last_name_preserving",
+ "positive_pattern": "last.*name|lname|surname(?!\\d)|last$|secondname|family.*name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_last_name_preserving",
+ "positive_pattern": "nachname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_last_name_preserving",
+ "positive_pattern": "apellidos?",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_last_name_preserving",
+ "positive_pattern": "famille|^nom(?!bre)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_last_name_preserving",
+ "positive_pattern": "cognome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_last_name_preserving",
+ "positive_pattern": "姓",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_last_name_preserving",
+ "positive_pattern": "apelidos|surename|sobrenome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_last_name_preserving",
+ "positive_pattern": "Фамилия",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_last_name_preserving",
+ "positive_pattern": "نام.*خانوادگی",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_last_name_preserving",
+ "positive_pattern": "उपनाम",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_last_name_preserving",
+ "positive_pattern": "മറുപേര്",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_last_name_preserving",
+ "positive_pattern": "(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_last_name_preserving",
+ "positive_pattern": "\\b성(?:[^명]|\\b)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "LAST_NAME_FIRST": {
+ "es": [
+ {
+ "pattern_identifier": "es_last_name_first_preserving",
+ "positive_pattern": "(primer.*apellido)|(apellido1)|(apellido.*paterno)|surname_?1|first(\\s|_)?surname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "LAST_NAME_SECOND": {
+ "es": [
+ {
+ "pattern_identifier": "es_last_name_second_preserving",
+ "positive_pattern": "(segund.*apellido)|(apellido2)|(apellido.*materno)|surname_?2|second(\\s|_)?surname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "HONORIFIC_PREFIX": {
+ "en": [
+ {
+ "pattern_identifier": "en_honorific_prefix_preserving",
+ "positive_pattern": "^title:?$|(salutation(?! and given name))",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_honorific_prefix_preserving",
+ "positive_pattern": "anrede|titel",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_honorific_prefix_preserving",
+ "positive_pattern": "tratamiento|encabezamiento",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_honorific_prefix_preserving",
+ "positive_pattern": "titolo",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_honorific_prefix_preserving",
+ "positive_pattern": "titre",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_honorific_prefix_preserving",
+ "positive_pattern": "обраще́ние|зва́ние",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "el": [
+ {
+ "pattern_identifier": "el_honorific_prefix_preserving",
+ "positive_pattern": "προσφώνηση",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_honorific_prefix_preserving",
+ "positive_pattern": "hitap",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "PHONE": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_preserving",
+ "positive_pattern": "phone|mobile|contact.?number",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_phone_preserving",
+ "positive_pattern": "telefonnummer",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_phone_preserving",
+ "positive_pattern": "telefono|teléfono",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_phone_preserving",
+ "positive_pattern": "telfixe",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_phone_preserving",
+ "positive_pattern": "電話",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_phone_preserving",
+ "positive_pattern": "telefone|telemovel",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_phone_preserving",
+ "positive_pattern": "телефон",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_phone_preserving",
+ "positive_pattern": "मोबाइल",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_phone_preserving",
+ "positive_pattern": "(\\b|_|\\*)telefon(\\b|_|\\*)",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_phone_preserving",
+ "positive_pattern": "电话",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_phone_preserving",
+ "positive_pattern": "മൊബൈല്‍",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_phone_preserving",
+ "positive_pattern": "(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "AUGMENTED_PHONE_COUNTRY_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_augmented_phone_country_code_preserving",
+ "positive_pattern": "^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "PHONE_COUNTRY_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_country_code_preserving",
+ "positive_pattern": "country.*code|ccode|_cc|phone.*code|user.*phone.*code",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 77
+ }
+ ]
+ },
+ "PHONE_AREA_CODE_NO_TEXT": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_area_code_no_text_preserving",
+ "positive_pattern": "^\\($",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_AREA_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_area_code_preserving",
+ "positive_pattern": "area.*code|acode|area",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_phone_area_code_preserving",
+ "positive_pattern": "지역.?번호",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_PREFIX_SEPARATOR": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_prefix_separator_preserving",
+ "positive_pattern": "^-$|^\\)$",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_SUFFIX_SEPARATOR": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_suffix_separator_preserving",
+ "positive_pattern": "^-$",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_PREFIX": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_prefix_preserving",
+ "positive_pattern": "prefix|exchange",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_phone_prefix_preserving",
+ "positive_pattern": "preselection",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_phone_prefix_preserving",
+ "positive_pattern": "ddd",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_SUFFIX": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_suffix_preserving",
+ "positive_pattern": "suffix",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_EXTENSION": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_extension_preserving",
+ "positive_pattern": "\\bext|ext\\b|extension",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_phone_extension_preserving",
+ "positive_pattern": "ramal",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PASSPORT": {
+ "en": [
+ {
+ "pattern_identifier": "en_passport_preserving",
+ "positive_pattern": "document.*number|passport",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_passport_preserving",
+ "positive_pattern": "passeport",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_passport_preserving",
+ "positive_pattern": "numero.*documento|pasaporte",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_passport_preserving",
+ "positive_pattern": "書類",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "TRAVEL_ORIGIN": {
+ "en": [
+ {
+ "pattern_identifier": "en_travel_origin_preserving",
+ "positive_pattern": "point.*of.*entry|arrival",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_travel_origin_preserving",
+ "positive_pattern": "punto.*internaci(o|ó)n|fecha.*llegada",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_travel_origin_preserving",
+ "positive_pattern": "入国",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "TRAVEL_DESTINATION": {
+ "en": [
+ {
+ "pattern_identifier": "en_travel_destination_preserving",
+ "positive_pattern": "departure",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_travel_destination_preserving",
+ "positive_pattern": "fecha.*salida|destino",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_travel_destination_preserving",
+ "positive_pattern": "出国",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "FLIGHT": {
+ "en": [
+ {
+ "pattern_identifier": "en_flight_preserving",
+ "positive_pattern": "airline|flight",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_flight_preserving",
+ "positive_pattern": "aerol(i|í)nea|n(u|ú)mero.*vuelo",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_flight_preserving",
+ "positive_pattern": "便名|航空会社",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "UPI_VIRTUAL_PAYMENT_ADDRESS": {
+ "en": [
+ {
+ "pattern_identifier": "en_upi_virtual_payment_address_user@(IFSC/Aadhaar/Mobile/RuPay)_preserving",
+ "positive_pattern": "^[\\w.+-_]+@(\\w+\\.ifsc\\.npci|aadhaar\\.npci|mobile\\.npci|rupay\\.npci)$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "en_upi_virtual_payment_address_user@(bank_list)_preserving",
+ "positive_pattern": "^[\\w.+-_]+@(airtel|airtelpaymentsbank|albk|allahabadbank|allbank|andb|apb|apl|axis|axisbank|axisgo|bandhan|barodampay|birla|boi|cbin|cboi|centralbank|cmsidfc|cnrb|csbcash|csbpay|cub|dbs|dcb|dcbbank|denabank|dlb|eazypay|equitas|ezeepay|fbl|federal|finobank|hdfcbank|hsbc|icici|idbi|idbibank|idfc|idfcbank|idfcnetc|ikwik|imobile|indbank|indianbank|indianbk|indus|iob|jkb|jsb|jsbp|karb|karurvysyabank|kaypay|kbl|kbl052|kmb|kmbl|kotak|kvb|kvbank|lime|lvb|lvbank|mahb|obc|okaxis|okbizaxis|okhdfcbank|okicici|oksbi|paytm|payzapp|pingpay|pnb|pockets|psb|purz|rajgovhdfcbank|rbl|sbi|sc|scb|scbl|scmobile|sib|srcb|synd|syndbank|syndicate|tjsb|tjsp|ubi|uboi|uco|unionbank|unionbankofindia|united|upi|utbi|vijayabank|vijb|vjb|ybl|yesbank|yesbankltd)$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "INTERNATIONAL_BANK_ACCOUNT_NUMBER": {
+ "en": [
+ {
+ "pattern_identifier": "en_international_bank_account_number_preserving",
+ "positive_pattern": "^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "VALIDATION_CREDIT_CARD_VERIFICATION_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_credit_card_cvc_preserving",
+ "positive_pattern": "^\\d{3,4}$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "VALIDATION_CREDIT_CARD_EXP_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_credit_card_exp_year_preserving",
+ "positive_pattern": "^[2][0][1-9][0-9]$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "URL_SEARCH_ACTION": {
+ "en": [
+ {
+ "pattern_identifier": "en_url_search_action_preserving",
+ "positive_pattern": "/search(/|((\\w*\\.\\w+)?$))",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "SOCIAL_SECURITY": {
+ "en": [
+ {
+ "pattern_identifier": "en_social_security_preserving",
+ "positive_pattern": "ssn|social.?security.?(num(ber)?|#)*",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ONE_TIME_PASSWORD": {
+ "en": [
+ {
+ "pattern_identifier": "en_one_time_password_preserving",
+ "positive_pattern": "one.?time|sms.?(code|token|password|pwd|pass)",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ }
+}
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
new file mode 100644
index 00000000000..e6e1a075863
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc
@@ -0,0 +1,36 @@
+// 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
new file mode 100644
index 00000000000..dc923237777
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h
@@ -0,0 +1,23 @@
+// 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/payments/autofill_save_card_infobar_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h
index 969131b3a1e..99d93d80d3e 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h
@@ -7,6 +7,8 @@
#include <memory>
+#include "components/signin/public/identity_manager/account_info.h"
+
namespace infobars {
class InfoBar;
}
@@ -15,9 +17,12 @@ namespace autofill {
class AutofillSaveCardInfoBarDelegateMobile;
-// Creates an infobar for saving a credit card on a mobile device.
+// Creates an Infobar for saving a credit card on a mobile device. If
+// AccountInfo contains the user's data, an account indication footer will be
+// shown at the bottom of the Infobar.
std::unique_ptr<infobars::InfoBar> CreateSaveCardInfoBarMobile(
- std::unique_ptr<AutofillSaveCardInfoBarDelegateMobile> delegate);
+ std::unique_ptr<AutofillSaveCardInfoBarDelegateMobile> delegate,
+ base::Optional<AccountInfo> accountInfo);
} // namespace autofill
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 7267cfdfd1a..25ea9af5ec7 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
@@ -7,25 +7,18 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "build/build_config.h"
+#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"
#include "google_apis/gaia/google_service_auth_error.h"
-namespace {
-
-#if defined(OS_ANDROID)
-constexpr base::Feature kWalletRequiresFirstSyncSetupComplete{
- "WalletRequiresFirstSyncSetupComplete", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
-
-} // namespace
-
namespace browser_sync {
AutofillWalletModelTypeController::AutofillWalletModelTypeController(
@@ -102,7 +95,8 @@ AutofillWalletModelTypeController::GetPreconditionState() const {
pref_service_->GetBoolean(autofill::prefs::kAutofillCreditCardEnabled) &&
!sync_service_->GetAuthError().IsPersistentError();
#if defined(OS_ANDROID)
- if (base::FeatureList::IsEnabled(kWalletRequiresFirstSyncSetupComplete)) {
+ if (base::FeatureList::IsEnabled(
+ autofill::features::kWalletRequiresFirstSyncSetupComplete)) {
// On Android, it's also required that the initial Sync setup is complete
// (i.e. the user has previously opted in to Sync-the-feature, even if it's
// not enabled right now).
@@ -114,6 +108,22 @@ AutofillWalletModelTypeController::GetPreconditionState() const {
: PreconditionState::kMustStopAndClearData;
}
+bool AutofillWalletModelTypeController::ShouldRunInTransportOnlyMode() const {
+ if (type() != syncer::AUTOFILL_WALLET_DATA) {
+ return false;
+ }
+ if (!base::FeatureList::IsEnabled(
+ autofill::features::kAutofillEnableAccountWalletStorage)) {
+ return false;
+ }
+ if (sync_service_->GetUserSettings()->IsUsingSecondaryPassphrase() &&
+ !base::FeatureList::IsEnabled(
+ switches::kSyncAllowWalletDataInTransportModeWithCustomPassphrase)) {
+ return false;
+ }
+ return true;
+}
+
void AutofillWalletModelTypeController::OnUserPrefChanged() {
DCHECK(CalledOnValidThread());
sync_service_->DataTypePreconditionChanged(type());
diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
index 03d0312c094..8a016e00805 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
@@ -47,6 +47,7 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController,
void Stop(syncer::ShutdownReason shutdown_reason,
StopCallback callback) override;
PreconditionState GetPreconditionState() const override;
+ bool ShouldRunInTransportOnlyMode() const override;
// syncer::SyncServiceObserver implementation.
void OnStateChanged(syncer::SyncService* sync) override;
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 cbd1018b3dd..9b38d40a594 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
@@ -79,21 +79,12 @@ void CreditCardAccessManager::UpdateCreditCardFormEventLogger() {
size_t server_record_type_count = 0;
size_t local_record_type_count = 0;
- bool has_server_nickname = false;
for (CreditCard* credit_card : credit_cards) {
- // If any masked server card has valid nickname, we will set to true no
- // matter the flag is enabled or not.
- if (credit_card->record_type() == CreditCard::MASKED_SERVER_CARD &&
- credit_card->HasNonEmptyValidNickname()) {
- has_server_nickname = true;
- }
-
if (credit_card->record_type() == CreditCard::LOCAL_CARD)
local_record_type_count++;
else
server_record_type_count++;
}
- form_event_logger_->set_has_server_nickname(has_server_nickname);
form_event_logger_->set_server_record_type_count(server_record_type_count);
form_event_logger_->set_local_record_type_count(local_record_type_count);
form_event_logger_->set_is_context_secure(client_->IsContextSecure());
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 e9e8c203a20..2addf2ad08f 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
@@ -15,7 +15,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string16.h"
@@ -486,6 +486,8 @@ void CreditCardSaveManager::OfferCardUploadSave() {
// should not display the offer-to-save infobar at all.
if (!is_mobile_build || show_save_prompt_.value_or(true)) {
user_did_accept_upload_prompt_ = false;
+ if (observer_for_testing_)
+ observer_for_testing_->OnOfferUploadSave();
client_->ConfirmSaveCreditCardToCloud(
upload_request_.card, legal_message_lines_,
AutofillClient::SaveCreditCardOptions()
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
index cc5131c2956..a1e77140599 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
@@ -84,6 +84,7 @@ class CreditCardSaveManager {
public:
virtual ~ObserverForTest() {}
virtual void OnOfferLocalSave() {}
+ virtual void OnOfferUploadSave() {}
virtual void OnDecideToRequestUploadSave() {}
virtual void OnReceivedGetUploadDetailsResponse() {}
virtual void OnSentUploadCardRequest() {}
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 d6dbaf29876..1868db7fc2b 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,6 +31,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/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"
@@ -349,6 +350,7 @@ class CreditCardSaveManagerTest : 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 TestFormDataImporter:
TestCreditCardSaveManager* credit_card_save_manager_;
// Ends up getting owned (and destroyed) by TestAutofillClient:
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 5843d193507..a7286883894 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,6 +28,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/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"
@@ -313,6 +314,7 @@ 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/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
index 1faf3fad213..d96c2f31f4b 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/autofill/core/browser/payments/strike_database.cc b/chromium/components/autofill/core/browser/payments/strike_database.cc
index d373314931e..a4acdfcbdb8 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database.cc
+++ b/chromium/components/autofill/core/browser/payments/strike_database.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
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 1d0f11324dd..039ea214d05 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
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/post_task.h"
#include "base/time/time.h"
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 0a6960bbd43..11d891b1282 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -1523,12 +1523,9 @@ const std::string& PersonalDataManager::GetDefaultCountryCodeForNewAddress()
if (default_country_code_.empty())
default_country_code_ = MostCommonCountryCodeFromProfiles();
- if (base::FeatureList::IsEnabled(
- features::kAutofillUseVariationCountryCode)) {
- // Failing that, use the country code from variations service.
- if (default_country_code_.empty())
- default_country_code_ = variations_country_code_;
- }
+ // Failing that, use the country code from variations service.
+ if (default_country_code_.empty())
+ default_country_code_ = variations_country_code_;
// Failing that, guess based on system timezone.
if (default_country_code_.empty())
@@ -1984,7 +1981,7 @@ bool PersonalDataManager::ShouldShowCardsFromAccountOption() const {
return !is_opted_in;
#else
return false;
-#endif // #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) || \
+#endif // #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) || \
// defined(OS_APPLE)
}
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 c930dbc16a4..99b095478df 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -15,7 +15,7 @@
#include <vector>
#include "base/base64.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/guid.h"
#include "base/i18n/time_formatting.h"
@@ -2035,7 +2035,6 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) {
TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromVariations) {
base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseVariationCountryCode);
const std::string expected_country_code = "DE";
const std::string unepected_country_code = "FR";
diff --git a/chromium/components/autofill/core/browser/proto/BUILD.gn b/chromium/components/autofill/core/browser/proto/BUILD.gn
index eb779aaae07..0aac1b74f7f 100644
--- a/chromium/components/autofill/core/browser/proto/BUILD.gn
+++ b/chromium/components/autofill/core/browser/proto/BUILD.gn
@@ -11,6 +11,7 @@ fuzzable_proto_library("proto") {
"password_requirements.proto",
"password_requirements_shard.proto",
"server.proto",
+ "states.proto",
"strike_data.proto",
]
}
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index 1bc923e9f25..ea2d2a5f4b8 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -407,6 +407,7 @@ message AutofillUploadContents {
DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD = 8; // unused
DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD = 9; // unused
PROBABLE_FORM_SUBMISSION = 10;
+ CHANGE_PASSWORD_FORM_CLEARED = 11;
}
// The type of the event that was taken as an indication that the form has
diff --git a/chromium/components/autofill/core/browser/proto/states.proto b/chromium/components/autofill/core/browser/proto/states.proto
new file mode 100644
index 00000000000..3253823616b
--- /dev/null
+++ b/chromium/components/autofill/core/browser/proto/states.proto
@@ -0,0 +1,31 @@
+// 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.
+
+syntax = "proto2";
+
+package autofill;
+
+option optimize_for = LITE_RUNTIME;
+
+message StateEntry {
+ // Full name representing the state entry unique within a country.
+ // Example:
+ // "California" for "CA", "California", "The Golden State".
+ // "Bavaria" for "BY", "Bavaria", "Bayern".
+ optional string canonical_name = 1;
+
+ // Abbreviations corresponding to the state entry.
+ repeated string abbreviations = 2;
+
+ // Alternative names of the state.
+ repeated string alternative_names = 3;
+}
+
+message StatesInCountry {
+ // Two digit country code.
+ optional string country_code = 1;
+
+ // All the states belonging to the country.
+ repeated StateEntry states = 2;
+}
diff --git a/chromium/components/autofill/core/browser/rationalization_util_unittest.cc b/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
index 67ebfbe0af9..8ec974c7a65 100644
--- a/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_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_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.h b/chromium/components/autofill/core/browser/test_autofill_manager.h
index 51989ace0e5..2a5b103953c 100644
--- a/chromium/components/autofill/core/browser/test_autofill_manager.h
+++ b/chromium/components/autofill/core/browser/test_autofill_manager.h
@@ -72,6 +72,7 @@ class TestAutofillManager : public AutofillManager {
void SetCallParentUploadFormData(bool value);
using AutofillManager::is_rich_query_enabled;
+ using AutofillManager::pending_form_data;
private:
TestPersonalDataManager* personal_data_; // Weak reference.
diff --git a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc b/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
index ed92eae2fcf..7bdb471b44a 100644
--- a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
@@ -5,7 +5,7 @@
#include "components/autofill/core/browser/test_autofill_profile_validator_delayed.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.cc b/chromium/components/autofill/core/browser/test_autofill_provider.cc
index 2102a1974f9..ac9248b8d08 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.cc
@@ -33,8 +33,8 @@ void TestAutofillProvider::OnSelectControlDidChange(
const FormFieldData& field,
const gfx::RectF& bounding_box) {}
-void TestAutofillProvider::OnFocusNoLongerOnForm(
- AutofillHandlerProxy* handler) {}
+void TestAutofillProvider::OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) {}
void TestAutofillProvider::OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.h b/chromium/components/autofill/core/browser/test_autofill_provider.h
index 7a21e59c6bb..db7234195fa 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.h
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.h
@@ -37,7 +37,8 @@ class TestAutofillProvider : public AutofillProvider {
const FormData& form,
bool known_success,
mojom::SubmissionSource source) override {}
- void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override;
+ void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) override;
void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc
index 03455605c04..49a051467f7 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.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/credit_card.h"
diff --git a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
index 4779ab5f6c5..144e523b838 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/geo/region_data_loader.h"
#include "components/strings/grit/components_strings.h"
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index 33f0aa6dbde..deee50f2db7 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -14,12 +14,12 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/geo/state_names.h"
#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
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 557cbac1485..9cda0484f05 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/proto/autofill_sync.pb.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -287,7 +288,7 @@ void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutocompleteSyncBridge>(
web_data_backend,
std::make_unique<ClientTagBasedModelTypeProcessor>(
- syncer::AUTOFILL, /*dump_stack=*/base::RepeatingClosure())));
+ syncer::AUTOFILL, /*dump_stack=*/base::DoNothing())));
}
// static
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 d559076a9a4..4c580c90dc0 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
@@ -10,13 +10,13 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -27,9 +27,9 @@
#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/mock_model_type_change_processor.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/webdata/common/web_database.h"
#include "testing/gmock/include/gmock/gmock.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 627a0aac521..d6f098f58b0 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
@@ -9,6 +9,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -60,7 +61,7 @@ void AutofillProfileSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillProfileSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_PROFILE,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
app_locale, web_data_backend));
}
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 f977b702cad..171f079d9f8 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
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
@@ -18,7 +18,7 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
@@ -35,12 +35,12 @@
#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/mock_model_type_change_processor.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/model/sync_error_factory_mock.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"
#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_difference_tracker_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
index 403f270afec..03f8b7baef7 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
@@ -4,7 +4,7 @@
#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/mock_callback.h"
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 4f639a23d22..aa3324298db 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1044,9 +1044,10 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
AutofillProfile profile;
profile.set_origin(std::string());
- profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("Street Address"),
- VerificationStatus::kUserVerified);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS,
+ ASCIIToUTF16("Street Name House Number Premise Subpremise"),
+ VerificationStatus::kUserVerified);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_NAME,
ASCIIToUTF16("Street Name"),
VerificationStatus::kFormatted);
@@ -1070,9 +1071,9 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
profile.SetRawInfoWithVerificationStatus(
ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"), VerificationStatus::kObserved);
- profile.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_DEPENDENT_STREET_NAME, ASCIIToUTF16("Dependent Street Name"),
- VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_DEPENDENT_STREET_NAME,
+ ASCIIToUTF16(""),
+ VerificationStatus::kObserved);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER,
ASCIIToUTF16("House Number"),
@@ -1131,7 +1132,7 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_STREET_NAME),
ASCIIToUTF16("Street Name"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
- ASCIIToUTF16("Dependent Street Name"));
+ ASCIIToUTF16(""));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
ASCIIToUTF16("House Number"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_SUBPREMISE),
@@ -1162,15 +1163,16 @@ TEST_F(AutofillTableTest,
AutofillProfile profile;
profile.set_origin(std::string());
- profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("Street Address"),
- VerificationStatus::kUserVerified);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS,
+ ASCIIToUTF16("Street Name House Number Premise Subpremise"),
+ VerificationStatus::kUserVerified);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_NAME,
ASCIIToUTF16("Street Name"),
VerificationStatus::kFormatted);
- profile.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_DEPENDENT_STREET_NAME, ASCIIToUTF16("Dependent Street Name"),
- VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_DEPENDENT_STREET_NAME,
+ ASCIIToUTF16(""),
+ VerificationStatus::kObserved);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER,
ASCIIToUTF16("House Number"),
VerificationStatus::kUserVerified);
@@ -1196,7 +1198,7 @@ TEST_F(AutofillTableTest,
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_STREET_NAME),
ASCIIToUTF16("Street Name"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
- ASCIIToUTF16("Dependent Street Name"));
+ ASCIIToUTF16(""));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
ASCIIToUTF16("House Number"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_SUBPREMISE),
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 e43c36f6c40..c89d012e159 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
@@ -10,6 +10,7 @@
#include <vector>
#include "base/base64.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/optional.h"
@@ -310,7 +311,7 @@ void AutofillWalletMetadataSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillWalletMetadataSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_WALLET_METADATA,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
web_data_backend));
}
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 0cae0cf6b6d..f646c276c19 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
@@ -13,10 +13,10 @@
#include "base/base64.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/data_model/autofill_metadata.h"
@@ -32,9 +32,9 @@
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/entity_data.h"
-#include "components/sync/model/mock_model_type_change_processor.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"
#include "testing/gtest/include/gtest/gtest.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 c95389dba6d..bc4c93b79ba 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
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
@@ -47,7 +48,7 @@ void AutofillWalletOfferSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillWalletOfferSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_WALLET_OFFER,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
web_data_backend));
}
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 3132670cb95..5658421d159 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
@@ -12,7 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
@@ -26,12 +26,12 @@
#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/model/mock_model_type_change_processor.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/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.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 8cafefa1abb..47f257894e1 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
@@ -7,6 +7,7 @@
#include <utility>
#include "base/base64.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
@@ -146,7 +147,7 @@ void AutofillWalletSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillWalletSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_WALLET_DATA,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
web_data_backend));
}
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 540f2b9376b..ce186b41372 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
@@ -10,13 +10,12 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.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"
@@ -36,12 +35,12 @@
#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/model/mock_model_type_change_processor.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/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
index 6487f6bb507..de0083a0599 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -5,7 +5,7 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
index dce7abdaf4a..b637f09bf1d 100644
--- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
@@ -7,7 +7,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index 44d8b901795..948b48e1485 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -22,16 +22,13 @@ static_library("common") {
"autofill_payments_features.h",
"autofill_prefs.cc",
"autofill_prefs.h",
- "autofill_regex_constants.cc",
- "autofill_regex_constants.h",
- "autofill_regexes.cc",
- "autofill_regexes.h",
"autofill_switches.cc",
"autofill_switches.h",
"autofill_tick_clock.cc",
"autofill_tick_clock.h",
"autofill_util.cc",
"autofill_util.h",
+ "dense_set.h",
"field_data_manager.cc",
"field_data_manager.h",
"form_data.cc",
@@ -46,11 +43,8 @@ static_library("common") {
"gaia_id_hash.h",
"logging/log_buffer.cc",
"logging/log_buffer.h",
- "password_form.cc",
- "password_form.h",
"password_form_fill_data.cc",
"password_form_fill_data.h",
- "password_form_generation_data.cc",
"password_form_generation_data.h",
"password_generation_util.cc",
"password_generation_util.h",
@@ -87,8 +81,8 @@ source_set("unit_tests") {
"autofill_internals/logging_scope_unittest.cc",
"autofill_l10n_util_unittest.cc",
"autofill_prefs_unittest.cc",
- "autofill_regexes_unittest.cc",
"autofill_util_unittest.cc",
+ "dense_set_unittest.cc",
"field_data_manager_unittest.cc",
"form_data_unittest.cc",
"form_field_data_unittest.cc",
diff --git a/chromium/components/autofill/core/common/OWNERS b/chromium/components/autofill/core/common/OWNERS
index 219017c1704..04e7201eab4 100644
--- a/chromium/components/autofill/core/common/OWNERS
+++ b/chromium/components/autofill/core/common/OWNERS
@@ -1,5 +1,3 @@
-per-file *password*=dvadym@chromium.org
-per-file *password*=kolos@chromium.org
-per-file *password*=vasilii@chromium.org
+per-file *password*=file://components/password_manager/OWNERS
per-file autofill_payments_features.*=file://components/autofill/core/browser/payments/OWNERS
diff --git a/chromium/components/autofill/core/common/autofill_constants.cc b/chromium/components/autofill/core/common/autofill_constants.cc
index f67d797bed9..5f9f040624a 100644
--- a/chromium/components/autofill/core/common/autofill_constants.cc
+++ b/chromium/components/autofill/core/common/autofill_constants.cc
@@ -12,25 +12,6 @@ namespace autofill {
const char kSettingsOrigin[] = "Chrome settings";
-size_t MinRequiredFieldsForHeuristics() {
- return base::FeatureList::IsEnabled(
- autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics)
- ? 3
- : 1;
-}
-size_t MinRequiredFieldsForQuery() {
- return base::FeatureList::IsEnabled(
- autofill::features::kAutofillEnforceMinRequiredFieldsForQuery)
- ? 3
- : 1;
-}
-size_t MinRequiredFieldsForUpload() {
- return base::FeatureList::IsEnabled(
- autofill::features::kAutofillEnforceMinRequiredFieldsForUpload)
- ? 3
- : 1;
-}
-
bool IsAutofillEntryWithUseDateDeletable(const base::Time& use_date) {
return use_date < AutofillClock::Now() - kDisusedDataModelDeletionTimeDelta;
}
diff --git a/chromium/components/autofill/core/common/autofill_constants.h b/chromium/components/autofill/core/common/autofill_constants.h
index 84c5b916b03..07428810cc3 100644
--- a/chromium/components/autofill/core/common/autofill_constants.h
+++ b/chromium/components/autofill/core/common/autofill_constants.h
@@ -18,9 +18,9 @@ extern const char kSettingsOrigin[];
// The number of fields required by Autofill to execute its heuristic and
// crowd-sourcing query/upload routines.
-size_t MinRequiredFieldsForHeuristics();
-size_t MinRequiredFieldsForQuery();
-size_t MinRequiredFieldsForUpload();
+constexpr size_t kMinRequiredFieldsForHeuristics = 3;
+constexpr size_t kMinRequiredFieldsForQuery = 1;
+constexpr size_t kMinRequiredFieldsForUpload = 1;
// The maximum number of form fields we are willing to parse, due to
// computational costs. Several examples of forms with lots of fields that are
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index 50444cf12c2..349361c1c7b 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -24,6 +24,13 @@ namespace features {
const base::Feature kAutofillAddressEnhancementVotes{
"kAutofillAddressEnhancementVotes", base::FEATURE_DISABLED_BY_DEFAULT};
+// TODO(crbug.com/1135188): Remove this feature flag after the explicit save
+// prompts for address profiles is complete.
+// When enabled, a save prompt will be shown to user upon form submission before
+// storing any detected address profile.
+const base::Feature kAutofillAddressProfileSavePrompt{
+ "AutofillAddressProfileSavePrompt", base::FEATURE_DISABLED_BY_DEFAULT};
+
// By default, AutofillAgent and, if |kAutofillProbableFormSubmissionInBrowser|
// is enabled, also ContentAutofillDriver omit duplicate form submissions, even
// though the form's data may have changed substantially. If enabled, the
@@ -32,13 +39,6 @@ const base::Feature kAutofillAddressEnhancementVotes{
const base::Feature kAutofillAllowDuplicateFormSubmissions{
"AutofillAllowDuplicateFormSubmissions", base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls if a full country name instead of a country code in a field with a
-// type derived from HTML_TYPE_COUNTRY_CODE can be used to set the profile
-// country.
-const base::Feature kAutofillAllowHtmlTypeCountryCodesWithFullNames{
- "AutofillAllowHtmlTypeCountryCodesWithFullNames",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls whether autofill activates on non-HTTP(S) pages. Useful for
// automated with data URLS in cases where it's too difficult to use the
// embedded test server. Generally avoid using.
@@ -86,6 +86,28 @@ const base::Feature kAutofillEnableAugmentedPhoneCountryCode{
const base::Feature kAutofillEnableHideSuggestionsUI{
"AutofillEnableHideSuggestionsUI", 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.
+const base::Feature
+ kAutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers{
+ "AutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled and user is syncing, 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.
+const base::Feature kAutofillEnableInfoBarAccountIndicationFooterForSyncUsers{
+ "AutofillEnableInfoBarAccountIndicationFooterForSyncUsers",
+ 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.
+const base::Feature kAutofillEnablePasswordInfoBarAccountIndicationFooter{
+ "AutofillEnablePasswordInfoBarAccountIndicationFooter",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls if Autofill supports new structure in names.
// TODO(crbug.com/1098943): Remove once launched.
const base::Feature kAutofillEnableSupportForMoreStructureInNames{
@@ -104,23 +126,12 @@ const base::Feature kAutofillEnableSupportForMergingSubsetNames{
"AutofillEnableSupportForMergingSubsetNames",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls whether or not a minimum number of fields is required before
-// heuristic field type prediction is run for a form.
-const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics{
- "AutofillEnforceMinRequiredFieldsForHeuristics",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether or not a minimum number of fields is required before
-// crowd-sourced field type predictions are queried for a form.
-const base::Feature kAutofillEnforceMinRequiredFieldsForQuery{
- "AutofillEnforceMinRequiredFieldsForQuery",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Controls whether or not a minimum number of fields is required before
-// field type votes are uploaded to the crowd-sourcing server.
-const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{
- "AutofillEnforceMinRequiredFieldsForUpload",
- base::FEATURE_DISABLED_BY_DEFAULT};
+// 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};
// Controls whether or not all datalist shall be extracted into FormFieldData.
// This feature is enabled in both WebView and WebLayer where all datalists
@@ -137,30 +148,17 @@ const base::Feature kAutofillExtractAllDatalists{
const base::Feature kAutofillFixFillableFieldTypes{
"AutofillFixFillableFieldTypes", base::FEATURE_DISABLED_BY_DEFAULT};
-// If enabled, prefilled country and state values are not reset before
-// an address profile import.
-// TODO(crbug.com/1100231): Remove once fix is tested.
-const base::Feature kAutofillImportPrefilledCountryAndStateValues{
- "AutofillImportPrefilledCountryAndStateValues",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// When enabled, Autofill keeps the initial field values in the |FormStructure|
-// cache for all field types.
-const base::Feature kAutofillKeepInitialFormValuesInCache{
- "AutofillKeepCachedFormValues", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// When enabled, Autofill will use FieldRendererIds instead of unique_names
-// to align forms in FormStructure::RetrieveFromCache().
-const base::Feature kAutofillRetrieveFromCacheWithRendererIds{
- "AutofillRetrieveFromCacheWithRendererIds",
- 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.
+const base::Feature kAutofillRefillWithRendererIds{
+ "AutofillRefillWithRendererIds", base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, Autofill will try to retrieve cached fields by signatures as a
-// fallback that is useful if unique renderer ids are unstable.
-// TODO(crbug.com/1125624): Remove experiment once trial ended.
-const base::Feature kAutofillRetrieveFromCacheWithFieldSignatureAsFallback{
- "AutofillRetrieveFromCacheWithFieldSignatureAsFallback",
- base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will use FormRendererIds instead of
+// unique_name() to create unique section names.
+// TODO(crbug/896689): Remove once experiment is finished.
+const base::Feature kAutofillNameSectionsWithRendererIds{
+ "AutofillNameSectionsWithRendererIds", base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, autofill suggestions are displayed in the keyboard accessory
// instead of the regular popup.
@@ -196,15 +194,6 @@ const base::Feature kAutofillProbableFormSubmissionInBrowser{
const base::Feature kAutofillProfileClientValidation{
"AutofillProfileClientValidation", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillProfileImportFromUnifiedSection{
- "AutofillProfileImportFromUnifiedSection",
- 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{
@@ -263,14 +252,17 @@ const base::Feature kAutofillSkipFillingFieldsWithChangedValues{
const base::Feature kAutofillTokenPrefixMatching{
"AutofillTokenPrefixMatching", base::FEATURE_DISABLED_BY_DEFAULT};
-// Enables the touch to fill feature for Android.
-const base::Feature kAutofillTouchToFill = {"TouchToFillAndroid",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// Autofill upload throttling is used for testing.
const base::Feature kAutofillUploadThrottling{"AutofillUploadThrottling",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether to use the AutofillUseAlternativeStateNameMap for filling
+// of state selection fields, comparison of profiles and sending state votes to
+// the server.
+// TODO(crbug.com/1143516): Remove the feature when the experiment is completed.
+const base::Feature kAutofillUseAlternativeStateNameMap{
+ "AutofillUseAlternativeStateNameMap", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether suggestions' labels use the improved label disambiguation
// format.
const base::Feature kAutofillUseImprovedLabelDisambiguation{
@@ -282,31 +274,12 @@ const base::Feature kAutofillUseImprovedLabelDisambiguation{
const base::Feature kAutofillUseNewSectioningMethod{
"AutofillUseNewSectioningMethod", base::FEATURE_DISABLED_BY_DEFAULT};
-// TODO(crbug.com/1075604): Remove once launched.
-// Controls whether the page language is used as a fall-back locale to translate
-// the country name when a profile is imported from a form.
-const base::Feature kAutofillUsePageLanguageToTranslateCountryNames{
- "AutofillUsePageLanguageToTranslateCountryNames",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether to use the |ParseCityStateCountryZipCode| or not for
-// predicting the heuristic type.
-// |ParseCityStateCountryZipCode| is intended to prevent the misclassification
-// of the country field into |ADDRESS_HOME_STATE| while determining the
-// heuristic type. The misclassification happens sometimes because the regular
-// expression for |ADDRESS_HOME_STATE| contains the term "region" which is also
-// used for country selectors.
-const base::Feature kAutofillUseParseCityStateCountryZipCodeInHeuristic{
- "AutofillUseParseCityStateCountryZipCodeInHeuristic",
+// 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};
-// Controls whether or not autofill utilizes the country code from the Chrome
-// variation service. The country code is used for determining the address
-// requirements for address profile creation and as source for a default country
-// used in a new address profile.
-const base::Feature kAutofillUseVariationCountryCode{
- "AutofillUseVariationCountryCode", base::FEATURE_DISABLED_BY_DEFAULT};
-
#if defined(OS_ANDROID)
// Controls whether the Autofill manual fallback for Addresses and Payments is
// present on Android.
@@ -335,5 +308,13 @@ const base::Feature kAutofillUseUniqueRendererIDsOnIOS{
"AutofillUseUniqueRendererIDsOnIOS", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
+#if defined(OS_ANDROID)
+// Controls whether the Wallet (GPay) integration requires first-sync-setup to
+// be complete.
+// TODO(crbug.com/1134564): Clean up after launch.
+const base::Feature kWalletRequiresFirstSyncSetupComplete{
+ "WalletRequiresFirstSyncSetupComplete", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
} // namespace features
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index 1bbf23972e7..8209085714b 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -22,8 +22,8 @@ namespace features {
// All features in alphabetical order.
extern const base::Feature kAutofillAddressEnhancementVotes;
+extern const base::Feature kAutofillAddressProfileSavePrompt;
extern const base::Feature kAutofillAllowDuplicateFormSubmissions;
-extern const base::Feature kAutofillAllowHtmlTypeCountryCodesWithFullNames;
extern const base::Feature kAutofillAllowNonHttpActivation;
extern const base::Feature kAutofillAlwaysFillAddresses;
extern const base::Feature
@@ -33,20 +33,20 @@ extern const base::Feature kAutofillCreateDataForTest;
extern const base::Feature kAutofillEnableAccountWalletStorage;
extern const base::Feature kAutofillEnableAugmentedPhoneCountryCode;
extern const base::Feature kAutofillEnableHideSuggestionsUI;
+extern const base::Feature
+ kAutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers;
+extern const base::Feature
+ kAutofillEnableInfoBarAccountIndicationFooterForSyncUsers;
+extern const base::Feature
+ kAutofillEnablePasswordInfoBarAccountIndicationFooter;
extern const base::Feature kAutofillEnableSupportForMoreStructureInNames;
extern const base::Feature kAutofillEnableSupportForMoreStructureInAddresses;
extern const base::Feature kAutofillEnableSupportForMergingSubsetNames;
-extern const base::Feature kAutofillEnableSupportForHouseNumbers;
-extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics;
-extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery;
-extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
+extern const base::Feature kAutofillEnableUIForHonorificPrefixesInSettings;
extern const base::Feature kAutofillExtractAllDatalists;
extern const base::Feature kAutofillFixFillableFieldTypes;
-extern const base::Feature kAutofillImportPrefilledCountryAndStateValues;
-extern const base::Feature kAutofillKeepInitialFormValuesInCache;
-extern const base::Feature kAutofillRetrieveFromCacheWithRendererIds;
-extern const base::Feature
- kAutofillRetrieveFromCacheWithFieldSignatureAsFallback;
+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;
@@ -55,8 +55,6 @@ extern const base::Feature kAutofillOffNoServerData;
extern const base::Feature kAutofillPreventMixedFormsFilling;
extern const base::Feature kAutofillProbableFormSubmissionInBrowser;
extern const base::Feature kAutofillProfileClientValidation;
-extern const base::Feature kAutofillProfileImportFromUnfocusableFields;
-extern const base::Feature kAutofillProfileImportFromUnifiedSection;
extern const base::Feature kAutofillProfileServerValidation;
extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout;
extern const base::Feature kAutofillRichMetadataQueries;
@@ -67,13 +65,11 @@ extern const base::Feature kAutofillShowTypePredictions;
extern const base::Feature kAutofillSkipComparingInferredLabels;
extern const base::Feature kAutofillSkipFillingFieldsWithChangedValues;
extern const base::Feature kAutofillTokenPrefixMatching;
-extern const base::Feature kAutofillTouchToFill;
extern const base::Feature kAutofillUploadThrottling;
+extern const base::Feature kAutofillUseAlternativeStateNameMap;
extern const base::Feature kAutofillUseImprovedLabelDisambiguation;
extern const base::Feature kAutofillUseNewSectioningMethod;
-extern const base::Feature kAutofillUsePageLanguageToTranslateCountryNames;
-extern const base::Feature kAutofillUseParseCityStateCountryZipCodeInHeuristic;
-extern const base::Feature kAutofillUseVariationCountryCode;
+extern const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns;
#if defined(OS_ANDROID)
extern const base::Feature kAutofillManualFallbackAndroid;
@@ -97,6 +93,10 @@ bool IsMacViewsAutofillPopupExperimentEnabled();
extern const base::Feature kAutofillUseUniqueRendererIDsOnIOS;
#endif // OS_IOS
+#if defined(OS_ANDROID)
+extern const base::Feature kWalletRequiresFirstSyncSetupComplete;
+#endif
+
} // namespace features
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc
index 5d89d6e7431..8d74f541c6c 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.cc
+++ b/chromium/components/autofill/core/common/autofill_payments_features.cc
@@ -84,6 +84,12 @@ const base::Feature kAutofillEnableGoogleIssuedCard{
const base::Feature kAutofillEnableOffersInDownstream{
"kAutofillEnableOffersInDownstream", 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 SaveCardInfoBar.
+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{
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h
index 29ab241633c..4cadf5421ad 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.h
+++ b/chromium/components/autofill/core/common/autofill_payments_features.h
@@ -30,6 +30,8 @@ extern const base::Feature kAutofillEnableCardNicknameUpstream;
extern const base::Feature kAutofillEnableFixedPaymentsBubbleLogging;
extern const base::Feature kAutofillEnableGoogleIssuedCard;
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;
diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc
index c31f2e3c56b..23a0ce36f01 100644
--- a/chromium/components/autofill/core/common/autofill_prefs.cc
+++ b/chromium/components/autofill/core/common/autofill_prefs.cc
@@ -185,11 +185,12 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterTimePref(prefs::kAutofillUploadEventsLastResetTimestamp,
base::Time());
registry->RegisterDictionaryPref(prefs::kAutofillSyncTransportOptIn);
- registry->RegisterStringPref(prefs::kAutofillStatesDataDir, "");
// Deprecated prefs registered for migration.
registry->RegisterBooleanPref(kAutofillJapanCityFieldMigratedDeprecated,
false);
+ // Deprecated in profile prefs.
+ registry->RegisterStringPref(prefs::kAutofillStatesDataDir, "");
}
void MigrateDeprecatedAutofillPrefs(PrefService* prefs) {
@@ -223,6 +224,11 @@ void MigrateDeprecatedAutofillPrefs(PrefService* prefs) {
// Added 10/2019.
prefs->ClearPref(kAutofillJapanCityFieldMigratedDeprecated);
+
+ // Added 11/2020
+ // TODO(crbug.com/1147852): Remove deprecated kAutofillStatesDataDir from
+ // autofill profile prefs.
+ prefs->ClearPref(kAutofillStatesDataDir);
}
bool IsAutocompleteEnabled(const PrefService* prefs) {
diff --git a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
deleted file mode 100644
index 4201bceef30..00000000000
--- a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2013 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/common/autofill_regexes.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ASCIIToUTF16;
-
-namespace autofill {
-
-struct InputPatternTestCase {
- const char* const input;
- const char* const pattern;
- };
-
- class PositiveSampleTest
- : public testing::TestWithParam<InputPatternTestCase> {};
-
- TEST_P(PositiveSampleTest, SampleRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- SCOPED_TRACE(test_case.pattern);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),
- ASCIIToUTF16(test_case.pattern)));
- }
-
- INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
- PositiveSampleTest,
- testing::Values(
- // Empty pattern
- InputPatternTestCase{"", ""},
- InputPatternTestCase{
- "Look, ma' -- a non-empty string!", ""},
- // Substring
- InputPatternTestCase{"string", "tri"},
- // Substring at beginning
- InputPatternTestCase{"string", "str"},
- InputPatternTestCase{"string", "^str"},
- // Substring at end
- InputPatternTestCase{"string", "ring"},
- InputPatternTestCase{"string", "ring$"},
- // Case-insensitive
- InputPatternTestCase{"StRiNg", "string"}));
-
- class NegativeSampleTest
- : public testing::TestWithParam<InputPatternTestCase> {};
-
- TEST_P(NegativeSampleTest, SampleRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- SCOPED_TRACE(test_case.pattern);
- EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input),
- ASCIIToUTF16(test_case.pattern)));
-}
-
-INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
- NegativeSampleTest,
- testing::Values(
- // Empty string
- InputPatternTestCase{
- "", "Look, ma' -- a non-empty pattern!"},
- // Substring
- InputPatternTestCase{"string", "trn"},
- // Substring at beginning
- InputPatternTestCase{"string", " str"},
- InputPatternTestCase{"string", "^tri"},
- // Substring at end
- InputPatternTestCase{"string", "ring "},
- InputPatternTestCase{"string", "rin$"}));
-
-struct InputTestCase {
- const char* const input;
- };
-
- class ExpirationDate2DigitYearPositive
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
-
- INSTANTIATE_TEST_SUITE_P(
- AutofillRegexes,
- ExpirationDate2DigitYearPositive,
- testing::Values(InputTestCase{"mm / yy"},
- InputTestCase{"mm/ yy"},
- InputTestCase{"mm /yy"},
- InputTestCase{"mm/yy"},
- InputTestCase{"mm - yy"},
- InputTestCase{"mm- yy"},
- InputTestCase{"mm -yy"},
- InputTestCase{"mm-yy"},
- InputTestCase{"mmyy"},
- // Complex two year cases
- InputTestCase{"Expiration Date (MM / YY)"},
- InputTestCase{"Expiration Date (MM/YY)"},
- InputTestCase{"Expiration Date (MM - YY)"},
- InputTestCase{"Expiration Date (MM-YY)"},
- InputTestCase{"Expiration Date MM / YY"},
- InputTestCase{"Expiration Date MM/YY"},
- InputTestCase{"Expiration Date MM - YY"},
- InputTestCase{"Expiration Date MM-YY"},
- InputTestCase{"expiration date yy"},
- InputTestCase{"Exp Date (MM / YY)"}));
-
- class ExpirationDate2DigitYearNegative
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
- EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
-
- INSTANTIATE_TEST_SUITE_P(
- AutofillRegexes,
- ExpirationDate2DigitYearNegative,
- testing::Values(InputTestCase{""},
- InputTestCase{"Look, ma' -- an invalid string!"},
- InputTestCase{"mmfavouritewordyy"},
- InputTestCase{"mm a yy"},
- InputTestCase{"mm a yyyy"},
- // Simple four year cases
- InputTestCase{"mm / yyyy"},
- InputTestCase{"mm/ yyyy"},
- InputTestCase{"mm /yyyy"},
- InputTestCase{"mm/yyyy"},
- InputTestCase{"mm - yyyy"},
- InputTestCase{"mm- yyyy"},
- InputTestCase{"mm -yyyy"},
- InputTestCase{"mm-yyyy"},
- InputTestCase{"mmyyyy"},
- // Complex four year cases
- InputTestCase{"Expiration Date (MM / YYYY)"},
- InputTestCase{"Expiration Date (MM/YYYY)"},
- InputTestCase{"Expiration Date (MM - YYYY)"},
- InputTestCase{"Expiration Date (MM-YYYY)"},
- InputTestCase{"Expiration Date MM / YYYY"},
- InputTestCase{"Expiration Date MM/YYYY"},
- InputTestCase{"Expiration Date MM - YYYY"},
- InputTestCase{"Expiration Date MM-YYYY"},
- InputTestCase{"expiration date yyyy"},
- InputTestCase{"Exp Date (MM / YYYY)"}));
-
- class ExpirationDate4DigitYearPositive
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
- auto test_case = GetParam();
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
- SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
-
- INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
- ExpirationDate4DigitYearPositive,
- testing::Values(
- // Simple four year cases
- InputTestCase{"mm / yyyy"},
- InputTestCase{"mm/ yyyy"},
- InputTestCase{"mm /yyyy"},
- InputTestCase{"mm/yyyy"},
- InputTestCase{"mm - yyyy"},
- InputTestCase{"mm- yyyy"},
- InputTestCase{"mm -yyyy"},
- InputTestCase{"mm-yyyy"},
- InputTestCase{"mmyyyy"},
- // Complex four year cases
- InputTestCase{"Expiration Date (MM / YYYY)"},
- InputTestCase{"Expiration Date (MM/YYYY)"},
- InputTestCase{"Expiration Date (MM - YYYY)"},
- InputTestCase{"Expiration Date (MM-YYYY)"},
- InputTestCase{"Expiration Date MM / YYYY"},
- InputTestCase{"Expiration Date MM/YYYY"},
- InputTestCase{"Expiration Date MM - YYYY"},
- InputTestCase{"Expiration Date MM-YYYY"},
- InputTestCase{"expiration date yyyy"},
- InputTestCase{"Exp Date (MM / YYYY)"}));
-
- class ExpirationDate4DigitYearNegative
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
- auto test_case = GetParam();
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
- SCOPED_TRACE(test_case.input);
- EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- AutofillRegexes,
- ExpirationDate4DigitYearNegative,
- testing::Values(InputTestCase{""},
- InputTestCase{"Look, ma' -- an invalid string!"},
- InputTestCase{"mmfavouritewordyy"},
- InputTestCase{"mm a yy"},
- InputTestCase{"mm a yyyy"},
- // Simple two year cases
- InputTestCase{"mm / yy"},
- InputTestCase{"mm/ yy"},
- InputTestCase{"mm /yy"},
- InputTestCase{"mm/yy"},
- InputTestCase{"mm - yy"},
- InputTestCase{"mm- yy"},
- InputTestCase{"mm -yy"},
- InputTestCase{"mm-yy"},
- InputTestCase{"mmyy"},
- // Complex two year cases
- InputTestCase{"Expiration Date (MM / YY)"},
- InputTestCase{"Expiration Date (MM/YY)"},
- InputTestCase{"Expiration Date (MM - YY)"},
- InputTestCase{"Expiration Date (MM-YY)"},
- InputTestCase{"Expiration Date MM / YY"},
- InputTestCase{"Expiration Date MM/YY"},
- InputTestCase{"Expiration Date MM - YY"},
- InputTestCase{"Expiration Date MM-YY"},
- InputTestCase{"expiration date yy"},
- InputTestCase{"Exp Date (MM / YY)"}));
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_util.cc b/chromium/components/autofill/core/common/autofill_util.cc
index f738895aa7f..d9a17f403a6 100644
--- a/chromium/components/autofill/core/common/autofill_util.cc
+++ b/chromium/components/autofill/core/common/autofill_util.cc
@@ -65,7 +65,7 @@ bool IsKeyboardAccessoryEnabled() {
bool IsTouchToFillEnabled() {
#if defined(OS_ANDROID)
- return base::FeatureList::IsEnabled(features::kAutofillTouchToFill);
+ return true;
#else // !defined(OS_ANDROID)
return false;
#endif
diff --git a/chromium/components/autofill/core/common/dense_set.h b/chromium/components/autofill/core/common/dense_set.h
new file mode 100644
index 00000000000..cd52b04a025
--- /dev/null
+++ b/chromium/components/autofill/core/common/dense_set.h
@@ -0,0 +1,278 @@
+// 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_DENSE_SET_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_DENSE_SET_H_
+
+#include <bitset>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/numerics/safe_conversions.h"
+
+namespace autofill {
+
+// A set container with a std::set<T>-like interface for integral or enum types
+// T that have a dense and small representation as unsigned integers.
+//
+// The order of the elements in the container corresponds to their integer
+// representation.
+//
+// The lower and upper bounds of elements storable in a container are
+// [T(0), kEnd).
+//
+// 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.
+//
+// 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>
+class DenseSet {
+ private:
+ using Index = std::make_unsigned_t<T>;
+
+ public:
+ // A bidirectional iterator for the DenseSet.
+ class Iterator {
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = T;
+ using difference_type = std::ptrdiff_t;
+ using pointer = void;
+ using reference = T;
+
+ constexpr Iterator() = default;
+
+ friend bool operator==(const Iterator& a, const Iterator& b) {
+ DCHECK(a.owner_);
+ DCHECK_EQ(a.owner_, b.owner_);
+ return a.index_ == b.index_;
+ }
+
+ friend bool operator!=(const Iterator& a, const Iterator& b) {
+ return !(a == b);
+ }
+
+ T operator*() const {
+ DCHECK(derefenceable());
+ return index_to_value(index_);
+ }
+
+ Iterator& operator++() {
+ ++index_;
+ Skip(kForward);
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ auto that = *this;
+ operator++();
+ return that;
+ }
+
+ Iterator& operator--() {
+ --index_;
+ Skip(kBackward);
+ return *this;
+ }
+
+ Iterator operator--(int) {
+ auto that = *this;
+ operator--();
+ return that;
+ }
+
+ private:
+ friend DenseSet;
+
+ enum Direction { kBackward = -1, kForward = 1 };
+
+ constexpr Iterator(const DenseSet* owner, Index index)
+ : owner_(owner), index_(index) {}
+
+ // Advances the index, starting from the current position, to the next
+ // non-empty one. std::bitset does not offer a find-next-set operation.
+ void Skip(Direction direction) {
+ DCHECK_LE(index_, owner_->max_size());
+ while (index_ < owner_->max_size() && !derefenceable()) {
+ index_ += direction;
+ }
+ }
+
+ bool derefenceable() const {
+ DCHECK_LT(index_, owner_->max_size());
+ return owner_->bitset_.test(index_);
+ }
+
+ const DenseSet* owner_ = nullptr;
+
+ // The current index is in the interval [0, owner_->max_size()].
+ Index index_ = 0;
+ };
+
+ using value_type = T;
+ using iterator = Iterator;
+ using const_iterator = Iterator;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ constexpr DenseSet() = default;
+
+ DenseSet(std::initializer_list<T> init) {
+ for (const auto& x : init) {
+ insert(x);
+ }
+ }
+
+ template <typename InputIt>
+ DenseSet(InputIt first, InputIt last) {
+ for (auto it = first; it != last; ++it) {
+ insert(*it);
+ }
+ }
+
+ friend bool operator==(const DenseSet& a, const DenseSet& b) {
+ return a.bitset_ == b.bitset_;
+ }
+
+ friend bool operator!=(const DenseSet& a, const DenseSet& b) {
+ return !(a == b);
+ }
+
+ // Iterators.
+
+ // Returns an iterator to the beginning.
+ iterator begin() const {
+ const_iterator it(this, 0);
+ it.Skip(Iterator::kForward);
+ return it;
+ }
+ const_iterator cbegin() const { return begin(); }
+
+ // Returns an iterator to the end.
+ iterator end() const { return iterator(this, max_size()); }
+ const_iterator cend() const { return end(); }
+
+ // Returns a reverse iterator to the beginning.
+ reverse_iterator rbegin() const { return reverse_iterator(end()); }
+ const_reverse_iterator crbegin() const { return rbegin(); }
+
+ // Returns a reverse iterator to the end.
+ reverse_iterator rend() const { return reverse_iterator(begin()); }
+ const_reverse_iterator crend() const { return rend(); }
+
+ // Capacity.
+
+ // Returns true if the set is empty, otherwise false.
+ bool empty() const { return bitset_.none(); }
+
+ // Returns the number of elements the set has.
+ size_t size() const { return bitset_.count(); }
+
+ // Returns the maximum number of elements the set can have.
+ size_t max_size() const { return bitset_.size(); }
+
+ // Modifiers.
+
+ // Clears the contents.
+ void clear() { bitset_.reset(); }
+
+ // Inserts value |x| if it is not present yet, and returns an iterator to the
+ // inserted or existing element and a boolean that indicates whether the
+ // insertion took place.
+ std::pair<iterator, bool> insert(T x) {
+ bool contained = contains(x);
+ bitset_.set(value_to_index(x));
+ return {find(x), !contained};
+ }
+
+ // 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) {
+ bool contained = contains(x);
+ bitset_.reset(value_to_index(x));
+ return contained ? 1 : 0;
+ }
+
+ // Erases the element |*it| and returns an iterator to its successor.
+ iterator erase(const_iterator it) {
+ DCHECK(it.owner_ == this && it.derefenceable());
+ bitset_.reset(it.index_);
+ it.Skip(const_iterator::kForward);
+ return it;
+ }
+
+ // Erases the elements [first,last) and returns |last|.
+ iterator erase(const_iterator first, const_iterator last) {
+ DCHECK(first.owner_ == this && last.owner_ == this);
+ while (first != last) {
+ bitset_.reset(first.index_);
+ ++first;
+ }
+ return last;
+ }
+
+ // Lookup.
+
+ // Returns 1 if |x| is an element, otherwise 0.
+ size_t count(T x) const { return contains(x) ? 1 : 0; }
+
+ // Returns an iterator to the element |x| if it exists, otherwise end().
+ const_iterator find(T x) const {
+ return contains(x) ? const_iterator(this, value_to_index(x)) : cend();
+ }
+
+ // Returns true if |x| is an element, else |false|.
+ bool contains(T x) const { return bitset_.test(value_to_index(x)); }
+
+ // 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));
+ it.Skip(Iterator::kForward);
+ return it;
+ }
+
+ // Returns an iterator to the first element greater than |x|, or end().
+ const_iterator upper_bound(T x) const {
+ const_iterator it(this, value_to_index(x) + 1);
+ it.Skip(Iterator::kForward);
+ return it;
+ }
+
+ private:
+ friend Iterator;
+
+ struct Wrapper {
+ using type = T;
+ };
+
+ static constexpr Index value_to_index(T x) {
+ DCHECK(index_to_value(0) <= x && x < kEnd);
+ return base::checked_cast<Index>(x);
+ }
+
+ static constexpr T index_to_value(Index i) {
+ DCHECK_LT(i, base::checked_cast<Index>(kEnd));
+ using UnderlyingType =
+ typename std::conditional_t<std::is_enum<T>::value,
+ std::underlying_type<T>, Wrapper>::type;
+ return static_cast<T>(base::checked_cast<UnderlyingType>(i));
+ }
+
+ static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
+ static_assert(index_to_value(0) <= kEnd, "");
+
+ std::bitset<base::checked_cast<Index>(kEnd)> bitset_{};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_BITSET_H_
diff --git a/chromium/components/autofill/core/common/dense_set_unittest.cc b/chromium/components/autofill/core/common/dense_set_unittest.cc
new file mode 100644
index 00000000000..c6df3972962
--- /dev/null
+++ b/chromium/components/autofill/core/common/dense_set_unittest.cc
@@ -0,0 +1,484 @@
+// 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/common/dense_set.h"
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+TEST(DenseSet, initialization) {
+ enum class T : size_t {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kEnd = 6
+ };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQ(s.size(), 0u);
+ EXPECT_EQ(DS(s.begin(), s.end()), s);
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(DS(s.begin(), s.end()), s);
+ EXPECT_EQ(DS(s.cbegin(), s.cend()), s);
+ EXPECT_EQ(DS(s.rbegin(), s.rend()), s);
+ EXPECT_EQ(DS(s.crbegin(), s.crend()), s);
+ EXPECT_EQ(DS({T::Four, T::Two, T::One}), s);
+}
+
+TEST(DenseSet, iterators_begin_end) {
+ enum class T : int {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kEnd = 6
+ };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(std::distance(s.begin(), s.end()), 3);
+
+ {
+ auto it = s.begin();
+ auto x1 = *it++;
+ auto x2 = *it++;
+ auto x3 = *it++;
+ EXPECT_EQ(it, s.end());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.begin();
+ auto x1 = *it;
+ auto x2 = *++it;
+ auto x3 = *++it;
+ EXPECT_NE(it, s.end());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ EXPECT_THAT(s, ::testing::ElementsAre(T::One, T::Two, T::Four));
+}
+
+TEST(DenseSet, iterators_begin_end_reverse) {
+ enum class T : char {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kEnd = 6
+ };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+
+ {
+ auto it = s.end();
+ it--;
+ auto x3 = *it--;
+ auto x2 = *it--;
+ auto x1 = *it;
+ EXPECT_EQ(it, s.begin());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.end();
+ auto x3 = *--it;
+ auto x2 = *--it;
+ auto x1 = *--it;
+ EXPECT_EQ(it, s.begin());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+}
+
+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>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(std::distance(s.rbegin(), s.rend()), 3);
+
+ {
+ auto it = s.rbegin();
+ auto x3 = *it++;
+ auto x2 = *it++;
+ auto x1 = *it++;
+ EXPECT_EQ(it, s.rend());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.rbegin();
+ auto x3 = *it;
+ auto x2 = *++it;
+ auto x1 = *++it;
+ EXPECT_NE(it, s.rend());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ EXPECT_THAT(std::vector<T>(s.rbegin(), s.rend()),
+ ::testing::ElementsAre(T::Four, T::Two, T::One));
+}
+
+TEST(DenseSet, lookup) {
+ enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+
+ EXPECT_FALSE(s.contains(static_cast<T>(0)));
+ EXPECT_TRUE(s.contains(T::One));
+ EXPECT_TRUE(s.contains(T::Two));
+ EXPECT_FALSE(s.contains(T::Three));
+ EXPECT_TRUE(s.contains(T::Four));
+ EXPECT_FALSE(s.contains(T::Five));
+
+ EXPECT_EQ(s.contains(static_cast<T>(0)), 0u);
+ EXPECT_EQ(s.contains(T::One), 1u);
+ EXPECT_EQ(s.contains(T::Two), 1u);
+ EXPECT_EQ(s.contains(T::Three), 0u);
+ EXPECT_EQ(s.contains(T::Four), 1u);
+ EXPECT_EQ(s.contains(T::Five), 0u);
+
+ EXPECT_EQ(s.find(static_cast<T>(0)), s.end());
+ EXPECT_NE(s.find(T::One), s.end());
+ EXPECT_NE(s.find(T::Two), s.end());
+ EXPECT_EQ(s.find(T::Three), s.end());
+ EXPECT_NE(s.find(T::Four), s.end());
+ EXPECT_EQ(s.find(T::Five), s.end());
+
+ EXPECT_EQ(*s.find(T::One), T::One);
+ EXPECT_EQ(*s.find(T::Two), T::Two);
+ EXPECT_EQ(*s.find(T::Four), T::Four);
+
+ EXPECT_NE(s.find(static_cast<T>(0)), s.lower_bound(static_cast<T>(0)));
+ EXPECT_EQ(s.find(T::One), s.lower_bound(T::One));
+ EXPECT_EQ(s.find(T::Two), s.lower_bound(T::Two));
+ 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));
+}
+
+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>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+
+ EXPECT_EQ(s.lower_bound(static_cast<T>(0)), s.begin());
+ EXPECT_EQ(s.lower_bound(T::One), s.begin());
+
+ EXPECT_EQ(s.upper_bound(T::Four), s.end());
+ EXPECT_EQ(s.upper_bound(T::Five), s.end());
+
+ {
+ auto it = s.lower_bound(static_cast<T>(0));
+ auto jt = s.upper_bound(static_cast<T>(0));
+ EXPECT_EQ(it, jt);
+ }
+
+ {
+ auto it = s.lower_bound(T::One);
+ auto jt = s.upper_bound(T::One);
+ auto x1 = *it++;
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x1, T::One);
+ }
+
+ {
+ auto it = s.lower_bound(T::Four);
+ auto jt = s.upper_bound(T::Four);
+ auto x3 = *it++;
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.lower_bound(T::Five);
+ auto jt = s.upper_bound(T::Five);
+ EXPECT_EQ(it, jt);
+ }
+
+ {
+ auto it = s.lower_bound(T::One);
+ auto jt = s.upper_bound(T::Five);
+ auto x1 = *it++;
+ auto x2 = *it++;
+ auto x3 = *it++;
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.lower_bound(T::Three);
+ auto jt = s.upper_bound(T::Four);
+ auto x3 = *it++;
+ EXPECT_EQ(jt, s.end());
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ EXPECT_EQ(static_cast<size_t>(std::distance(s.begin(), s.end())), s.size());
+ EXPECT_EQ(std::next(std::next(std::next(s.begin()))), s.end());
+}
+
+TEST(DenseSet, max_size) {
+ const int One = 1;
+ const int Two = 2;
+ // const int Three = 3;
+ const int Four = 4;
+ // const int Five = 5;
+ const int kEnd = 6;
+ using DS = DenseSet<int, kEnd>;
+
+ DS s;
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQ(s.size(), 0u);
+ EXPECT_EQ(s.max_size(), 6u);
+ s.insert(Two);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), 1u);
+ s.insert(Four);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), 2u);
+ s.insert(One);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(s.max_size(), 6u);
+}
+
+TEST(DenseSet, modifiers) {
+ const size_t One = 1;
+ const size_t Two = 2;
+ 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>;
+
+ DS s;
+ s.insert(Two);
+ s.insert(Four);
+ s.insert(One);
+ EXPECT_EQ(s.size(), 3u);
+
+ auto EXPECT_INSERTION = [](auto& set, auto value, bool took_place) {
+ auto it = set.insert(value);
+ EXPECT_EQ(it, std::make_pair(set.find(value), took_place));
+ };
+
+ DS t;
+ EXPECT_NE(s, t);
+ EXPECT_INSERTION(t, Two, true);
+ EXPECT_INSERTION(t, Two, false);
+ EXPECT_INSERTION(t, Four, true);
+ EXPECT_INSERTION(t, Four, false);
+ EXPECT_INSERTION(t, One, true);
+ EXPECT_INSERTION(t, One, false);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_INSERTION(t, Three, true);
+ EXPECT_INSERTION(t, Three, false);
+ EXPECT_EQ(t.erase(Three), 1u);
+ EXPECT_EQ(t.erase(Three), 0u);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_EQ(s.erase(One), 1u);
+ EXPECT_EQ(t.erase(Four), 1u);
+ EXPECT_NE(s, t);
+ EXPECT_EQ(s.size(), 2u);
+ EXPECT_EQ(t.size(), 2u);
+
+ EXPECT_INSERTION(s, One, true);
+ EXPECT_INSERTION(t, Four, true);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_EQ(s.erase(s.find(One)), s.find(Two));
+ EXPECT_EQ(t.erase(t.lower_bound(One), t.upper_bound(One)), t.find(Two));
+ EXPECT_FALSE(s.contains(One));
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 2u);
+ EXPECT_EQ(t.size(), 2u);
+
+ EXPECT_INSERTION(s, One, true);
+ EXPECT_INSERTION(t, One, true);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_EQ(s.erase(s.find(Two), s.end()), s.end());
+ EXPECT_EQ(t.erase(t.lower_bound(Two), t.upper_bound(Four)), t.end());
+ EXPECT_TRUE(s.contains(One));
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 1u);
+ EXPECT_EQ(t.size(), 1u);
+
+ EXPECT_INSERTION(s, Two, true);
+ EXPECT_INSERTION(t, Two, true);
+ EXPECT_INSERTION(s, Four, true);
+ EXPECT_INSERTION(t, Four, true);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+
+ s.clear();
+ EXPECT_EQ(s, DS());
+ EXPECT_EQ(s.size(), 0u);
+
+ EXPECT_INSERTION(s, *t.begin(), true);
+ EXPECT_TRUE(s.contains(One));
+ EXPECT_INSERTION(s, *std::next(t.begin()), true);
+ EXPECT_TRUE(s.contains(Two));
+ EXPECT_INSERTION(s, *std::prev(t.end()), true);
+ EXPECT_TRUE(s.contains(Four));
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+}
+
+TEST(DenseSet, std_set) {
+ constexpr size_t kEnd = 50;
+ DenseSet<size_t, kEnd> dense_set;
+ std::set<size_t> std_set;
+
+ auto expect_equivalence = [&] {
+ EXPECT_EQ(dense_set.empty(), std_set.empty());
+ EXPECT_EQ(dense_set.size(), std_set.size());
+ EXPECT_TRUE(base::ranges::equal(dense_set, std_set));
+ };
+
+ auto random_insert = [&] {
+ expect_equivalence();
+ size_t value = base::RandUint64() % kEnd;
+ auto p = dense_set.insert(value);
+ auto q = std_set.insert(value);
+ EXPECT_EQ(p.second, q.second);
+ EXPECT_EQ(p.first == dense_set.end(), q.first == std_set.end());
+ EXPECT_TRUE(!p.second || p.first == dense_set.find(value));
+ EXPECT_TRUE(!q.second || q.first == std_set.find(value));
+ };
+
+ auto random_erase = [&] {
+ expect_equivalence();
+ size_t value = base::RandUint64() % kEnd;
+ EXPECT_EQ(dense_set.erase(value), std_set.erase(value));
+ };
+
+ auto random_erase_iterator = [&] {
+ expect_equivalence();
+ size_t value = base::RandUint64() % kEnd;
+ auto it = dense_set.find(value);
+ auto jt = std_set.find(value);
+ EXPECT_EQ(it == dense_set.end(), jt == std_set.end());
+ if (it == dense_set.end() || jt == std_set.end())
+ return;
+ auto succ_it = dense_set.erase(it);
+ auto succ_jt = std_set.erase(jt);
+ EXPECT_EQ(succ_it == dense_set.end(), succ_jt == std_set.end());
+ EXPECT_TRUE(succ_it == dense_set.upper_bound(value));
+ EXPECT_TRUE(succ_jt == std_set.upper_bound(value));
+ EXPECT_TRUE(succ_it == dense_set.end() || *succ_it == *succ_jt);
+ };
+
+ auto random_erase_range = [&] {
+ expect_equivalence();
+ size_t min_value = base::RandUint64() % kEnd;
+ size_t max_value = base::RandUint64() % kEnd;
+ 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),
+ dense_set.upper_bound(max_value));
+ std_set.erase(std_set.lower_bound(min_value),
+ std_set.upper_bound(max_value));
+ };
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_insert();
+ }
+
+ for (size_t i = 0; i < kEnd / 2; ++i) {
+ random_erase();
+ }
+
+ expect_equivalence();
+ dense_set.clear();
+ std_set.clear();
+ expect_equivalence();
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_insert();
+ }
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_erase_iterator();
+ }
+
+ expect_equivalence();
+ dense_set.clear();
+ std_set.clear();
+ expect_equivalence();
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_insert();
+ }
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_erase_range();
+ }
+
+ expect_equivalence();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/logging/log_buffer.cc b/chromium/components/autofill/core/common/logging/log_buffer.cc
index 0f9e6c349d5..961e66e457b 100644
--- a/chromium/components/autofill/core/common/logging/log_buffer.cc
+++ b/chromium/components/autofill/core/common/logging/log_buffer.cc
@@ -76,7 +76,7 @@ bool TryCoalesceString(std::vector<base::Value>* buffer,
base::Value CreateEmptyFragment() {
base::Value::DictStorage storage;
- storage.try_emplace("type", std::make_unique<base::Value>("fragment"));
+ storage.try_emplace("type", "fragment");
return base::Value(storage);
}
@@ -115,9 +115,8 @@ LogBuffer& operator<<(LogBuffer& buf, Tag&& tag) {
return buf;
base::Value::DictStorage storage;
- storage.try_emplace("type", std::make_unique<base::Value>("element"));
- storage.try_emplace("value",
- std::make_unique<base::Value>(std::move(tag.name)));
+ storage.try_emplace("type", "element");
+ storage.try_emplace("value", std::move(tag.name));
buf.buffer_.emplace_back(std::move(storage));
return buf;
}
@@ -148,8 +147,7 @@ LogBuffer& operator<<(LogBuffer& buf, Attrib&& attrib) {
base::Value(std::move(attrib.value)));
} else {
base::Value::DictStorage dict;
- dict.try_emplace(std::move(attrib.name),
- std::make_unique<base::Value>(std::move(attrib.value)));
+ dict.try_emplace(std::move(attrib.name), std::move(attrib.value));
node.SetKey("attributes", base::Value(std::move(dict)));
}
@@ -173,10 +171,10 @@ LogBuffer& operator<<(LogBuffer& buf, base::StringPiece text) {
return buf;
base::Value::DictStorage storage;
- storage.try_emplace("type", std::make_unique<base::Value>("text"));
+ storage.try_emplace("type", "text");
// This text is not HTML escaped because the rest of the frame work takes care
// of that and it must not be escaped twice.
- storage.try_emplace("value", std::make_unique<base::Value>(text));
+ storage.try_emplace("value", text);
base::Value node_to_add(std::move(storage));
AppendChildToLastNode(&buf.buffer_, std::move(node_to_add));
return buf;
diff --git a/chromium/components/autofill/core/common/mojom/BUILD.gn b/chromium/components/autofill/core/common/mojom/BUILD.gn
index 4c3ab8abd86..12cc7be0213 100644
--- a/chromium/components/autofill/core/common/mojom/BUILD.gn
+++ b/chromium/components/autofill/core/common/mojom/BUILD.gn
@@ -72,10 +72,6 @@ mojom("mojo_types") {
mojom = "autofill.mojom.PasswordGenerationUIData"
cpp = "::autofill::password_generation::PasswordGenerationUIData"
},
- {
- mojom = "autofill.mojom.ValueElementPair"
- cpp = "::autofill::ValueElementPair"
- },
]
traits_headers = [ "autofill_types_mojom_traits.h" ]
traits_sources = [ "autofill_types_mojom_traits.cc" ]
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
index 6ad1a8fc233..4c35cd75787 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
@@ -27,19 +27,7 @@ enum SubmissionIndicatorEvent {
// DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD,
// DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD,
PROBABLE_FORM_SUBMISSION = 10,
-};
-
-// This enum lists form field types as understood by the password manager,
-// essentially a digest of |autofill::ServerFieldType|. Note that we cannot
-// simply reuse |autofill::ServerFieldType| as it is defined in the browser,
-// while this enum will be used by both the browser and renderer.
-// TODO(https://crbug.com/1067347): move this enum to browser code. It is not
-// used in Mojo anymore.
-enum PasswordFormFieldPredictionType {
- kUsername,
- kCurrentPassword,
- kNewPassword,
- kNotPassword,
+ CHANGE_PASSWORD_FORM_CLEARED = 11,
};
enum SubmissionSource {
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 bc85d1db9f7..5b9b8780e67 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
@@ -23,8 +23,6 @@
namespace autofill {
-using mojom::PasswordFormFieldPredictionType;
-
const std::vector<const char*> kOptions = {"Option1", "Option2", "Option3",
"Option4"};
namespace {
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc
deleted file mode 100644
index 6585faa88e8..00000000000
--- a/chromium/components/autofill/core/common/password_form.cc
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright 2013 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/common/password_form.h"
-
-#include <algorithm>
-#include <ostream>
-#include <sstream>
-
-#include "base/json/json_writer.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-
-namespace autofill {
-
-namespace {
-
-std::string ToString(PasswordForm::Store in_store) {
- switch (in_store) {
- case PasswordForm::Store::kNotSet:
- return "Not Set";
- case PasswordForm::Store::kProfileStore:
- return "Profile Store";
- case PasswordForm::Store::kAccountStore:
- return "Account Store";
- }
-}
-
-std::string ToString(PasswordForm::Scheme scheme) {
- switch (scheme) {
- case PasswordForm::Scheme::kHtml:
- return "HTML";
- case PasswordForm::Scheme::kBasic:
- return "Basic";
- case PasswordForm::Scheme::kDigest:
- return "Digest";
- case PasswordForm::Scheme::kOther:
- return "Other";
- case PasswordForm::Scheme::kUsernameOnly:
- return "UsernameOnly";
- }
-
- NOTREACHED();
- return std::string();
-}
-
-std::string ToString(PasswordForm::Type type) {
- switch (type) {
- case PasswordForm::Type::kManual:
- return "Manual";
- case PasswordForm::Type::kGenerated:
- return "Generated";
- case PasswordForm::Type::kApi:
- return "API";
- }
-
- NOTREACHED();
- return std::string();
-}
-
-std::string ToString(PasswordForm::GenerationUploadStatus status) {
- switch (status) {
- case PasswordForm::GenerationUploadStatus::kNoSignalSent:
- return "No Signal Sent";
- case PasswordForm::GenerationUploadStatus::kPositiveSignalSent:
- return "Positive Signal Sent";
- case PasswordForm::GenerationUploadStatus::kNegativeSignalSent:
- return "Negative Signal Sent";
- }
-
- NOTREACHED();
- return std::string();
-}
-
-// Utility function that creates a std::string from an object supporting the
-// ostream operator<<.
-template <typename T>
-std::string ToString(const T& obj) {
- std::ostringstream ostream;
- ostream << obj;
- return ostream.str();
-}
-
-base::string16 ValueElementVectorToString(
- const ValueElementVector& value_element_pairs) {
- std::vector<base::string16> pairs(value_element_pairs.size());
- std::transform(value_element_pairs.begin(), value_element_pairs.end(),
- pairs.begin(), [](const ValueElementPair& p) {
- return p.first + base::ASCIIToUTF16("+") + p.second;
- });
- return base::JoinString(pairs, base::ASCIIToUTF16(", "));
-}
-
-// Serializes a PasswordForm to a JSON object. Used only for logging in tests.
-void PasswordFormToJSON(const PasswordForm& form,
- base::DictionaryValue* target) {
- target->SetString("scheme", ToString(form.scheme));
- target->SetString("signon_realm", form.signon_realm);
- target->SetBoolean("is_public_suffix_match", form.is_public_suffix_match);
- target->SetBoolean("is_affiliation_based_match",
- form.is_affiliation_based_match);
- target->SetString("url", form.url.possibly_invalid_spec());
- target->SetString("action", form.action.possibly_invalid_spec());
- target->SetString("submit_element", form.submit_element);
- target->SetString("username_element", form.username_element);
- target->SetInteger("username_element_renderer_id",
- form.username_element_renderer_id.value());
- target->SetString("username_value", form.username_value);
- target->SetString("password_element", form.password_element);
- target->SetString("password_value", form.password_value);
- target->SetInteger("password_element_renderer_id",
- form.password_element_renderer_id.value());
- target->SetString("new_password_element", form.new_password_element);
- target->SetInteger("password_element_renderer_id",
- form.password_element_renderer_id.value());
- target->SetString("new_password_value", form.new_password_value);
- target->SetString("confirmation_password_element",
- form.confirmation_password_element);
- target->SetInteger("confirmation_password_element_renderer_id",
- form.confirmation_password_element_renderer_id.value());
- target->SetString("all_possible_usernames",
- ValueElementVectorToString(form.all_possible_usernames));
- target->SetString("all_possible_passwords",
- ValueElementVectorToString(form.all_possible_passwords));
- target->SetBoolean("blocked_by_user", form.blocked_by_user);
- target->SetDouble("date_last_used", form.date_last_used.ToDoubleT());
- target->SetDouble("date_created", form.date_created.ToDoubleT());
- target->SetDouble("date_synced", form.date_synced.ToDoubleT());
- target->SetString("type", ToString(form.type));
- target->SetInteger("times_used", form.times_used);
- target->SetString("form_data", ToString(form.form_data));
- target->SetString("generation_upload_status",
- ToString(form.generation_upload_status));
- target->SetString("display_name", form.display_name);
- target->SetString("icon_url", form.icon_url.possibly_invalid_spec());
- target->SetString("federation_origin", form.federation_origin.Serialize());
- target->SetBoolean("skip_next_zero_click", form.skip_zero_click);
- target->SetBoolean("was_parsed_using_autofill_predictions",
- form.was_parsed_using_autofill_predictions);
- target->SetString("affiliated_web_realm", form.affiliated_web_realm);
- target->SetString("app_display_name", form.app_display_name);
- target->SetString("app_icon_url", form.app_icon_url.possibly_invalid_spec());
- target->SetString("submission_event", ToString(form.submission_event));
- target->SetBoolean("only_for_fallback", form.only_for_fallback);
- target->SetBoolean("is_gaia_with_skip_save_password_form",
- form.form_data.is_gaia_with_skip_save_password_form);
- target->SetBoolean("is_new_password_reliable", form.is_new_password_reliable);
- target->SetString("in_store", ToString(form.in_store));
-
- std::vector<std::string> hashes;
- hashes.reserve(form.moving_blocked_for_list.size());
- for (const auto& gaia_id_hash : form.moving_blocked_for_list) {
- hashes.push_back(gaia_id_hash.ToBase64());
- }
- target->SetString("moving_blocked_for_list", base::JoinString(hashes, ", "));
-}
-
-} // namespace
-
-PasswordForm::PasswordForm() = default;
-
-PasswordForm::PasswordForm(const PasswordForm& other) = default;
-
-PasswordForm::PasswordForm(PasswordForm&& other) = default;
-
-PasswordForm::~PasswordForm() = default;
-
-PasswordForm& PasswordForm::operator=(const PasswordForm& form) = default;
-
-PasswordForm& PasswordForm::operator=(PasswordForm&& form) = default;
-
-bool PasswordForm::IsPossibleChangePasswordForm() const {
- return !new_password_element.empty();
-}
-
-bool PasswordForm::IsPossibleChangePasswordFormWithoutUsername() const {
- return IsPossibleChangePasswordForm() && username_element.empty();
-}
-
-bool PasswordForm::HasUsernameElement() const {
- return !username_element_renderer_id.is_null();
-}
-
-bool PasswordForm::HasPasswordElement() const {
- return !password_element_renderer_id.is_null();
-}
-
-bool PasswordForm::HasNewPasswordElement() const {
- return !new_password_element_renderer_id.is_null();
-}
-
-bool PasswordForm::IsFederatedCredential() const {
- return !federation_origin.opaque();
-}
-
-bool PasswordForm::IsSingleUsername() const {
- return HasUsernameElement() && !HasPasswordElement() &&
- !HasNewPasswordElement();
-}
-
-bool PasswordForm::IsUsingAccountStore() const {
- return in_store == Store::kAccountStore;
-}
-
-bool PasswordForm::HasNonEmptyPasswordValue() const {
- return !password_value.empty() || !new_password_value.empty();
-}
-
-bool PasswordForm::operator==(const PasswordForm& form) const {
- return scheme == form.scheme && signon_realm == form.signon_realm &&
- url == form.url && action == form.action &&
- submit_element == form.submit_element &&
- username_element == form.username_element &&
- username_element_renderer_id == form.username_element_renderer_id &&
- username_value == form.username_value &&
- all_possible_usernames == form.all_possible_usernames &&
- all_possible_passwords == form.all_possible_passwords &&
- form_has_autofilled_value == form.form_has_autofilled_value &&
- password_element == form.password_element &&
- password_element_renderer_id == form.password_element_renderer_id &&
- password_value == form.password_value &&
- new_password_element == form.new_password_element &&
- confirmation_password_element_renderer_id ==
- form.confirmation_password_element_renderer_id &&
- confirmation_password_element == form.confirmation_password_element &&
- confirmation_password_element_renderer_id ==
- form.confirmation_password_element_renderer_id &&
- new_password_value == form.new_password_value &&
- date_created == form.date_created && date_synced == form.date_synced &&
- date_last_used == form.date_last_used &&
- blocked_by_user == form.blocked_by_user && type == form.type &&
- times_used == form.times_used &&
- form_data.SameFormAs(form.form_data) &&
- generation_upload_status == form.generation_upload_status &&
- display_name == form.display_name && icon_url == form.icon_url &&
- // We compare the serialization of the origins here, as we want unique
- // origins to compare as '=='.
- federation_origin.Serialize() == form.federation_origin.Serialize() &&
- skip_zero_click == form.skip_zero_click &&
- was_parsed_using_autofill_predictions ==
- form.was_parsed_using_autofill_predictions &&
- is_public_suffix_match == form.is_public_suffix_match &&
- is_affiliation_based_match == form.is_affiliation_based_match &&
- affiliated_web_realm == form.affiliated_web_realm &&
- app_display_name == form.app_display_name &&
- app_icon_url == form.app_icon_url &&
- submission_event == form.submission_event &&
- only_for_fallback == form.only_for_fallback &&
- is_new_password_reliable == form.is_new_password_reliable &&
- in_store == form.in_store &&
- moving_blocked_for_list == form.moving_blocked_for_list;
-}
-
-bool PasswordForm::operator!=(const PasswordForm& form) const {
- return !operator==(form);
-}
-
-bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
- const PasswordForm& right) {
- return (left.signon_realm == right.signon_realm && left.url == right.url &&
- left.username_element == right.username_element &&
- left.username_value == right.username_value &&
- left.password_element == right.password_element);
-}
-
-std::ostream& operator<<(std::ostream& os, PasswordForm::Scheme scheme) {
- return os << ToString(scheme);
-}
-
-std::ostream& operator<<(std::ostream& os, const PasswordForm& form) {
- base::DictionaryValue form_json;
- PasswordFormToJSON(form, &form_json);
-
- // Serialize the default PasswordForm, and remove values from the result that
- // are equal to this to make the results more concise.
- base::DictionaryValue default_form_json;
- PasswordFormToJSON(PasswordForm(), &default_form_json);
- for (base::DictionaryValue::Iterator it_default_key_values(default_form_json);
- !it_default_key_values.IsAtEnd(); it_default_key_values.Advance()) {
- const base::Value* actual_value;
- if (form_json.Get(it_default_key_values.key(), &actual_value) &&
- it_default_key_values.value().Equals(actual_value)) {
- form_json.Remove(it_default_key_values.key(), nullptr);
- }
- }
-
- std::string form_as_string;
- base::JSONWriter::WriteWithOptions(
- form_json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &form_as_string);
- base::TrimWhitespaceASCII(form_as_string, base::TRIM_ALL, &form_as_string);
- return os << "PasswordForm(" << form_as_string << ")";
-}
-
-std::ostream& operator<<(std::ostream& os, PasswordForm* form) {
- return os << "&" << *form;
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
deleted file mode 100644
index 3d3e786a73a..00000000000
--- a/chromium/components/autofill/core/common/password_form.h
+++ /dev/null
@@ -1,388 +0,0 @@
-// Copyright 2013 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_PASSWORD_FORM_H__
-#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/time/time.h"
-#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/gaia_id_hash.h"
-#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
-#include "components/autofill/core/common/renderer_id.h"
-#include "url/gurl.h"
-#include "url/origin.h"
-
-namespace autofill {
-
-// Pair of a value and the name of the element that contained this value.
-using ValueElementPair = std::pair<base::string16, base::string16>;
-
-// Vector of possible username values and corresponding field names.
-using ValueElementVector = std::vector<ValueElementPair>;
-
-// The PasswordForm struct encapsulates information about a login form,
-// which can be an HTML form or a dialog with username/password text fields.
-//
-// The Web Data database stores saved username/passwords and associated form
-// metdata using a PasswordForm struct, typically one that was created from
-// a parsed HTMLFormElement or LoginDialog, but the saved entries could have
-// also been created by imported data from another browser.
-//
-// The PasswordManager implements a fuzzy-matching algorithm to compare saved
-// PasswordForm entries against PasswordForms that were created from a parsed
-// HTML or dialog form. As one might expect, the more data contained in one
-// of the saved PasswordForms, the better the job the PasswordManager can do
-// in matching it against the actual form it was saved on, and autofill
-// accurately. But it is not always possible, especially when importing from
-// other browsers with different data models, to copy over all the information
-// about a particular "saved password entry" to our PasswordForm
-// representation.
-//
-// The field descriptions in the struct specification below are intended to
-// describe which fields are not strictly required when adding a saved password
-// entry to the database and how they can affect the matching process.
-//
-// TODO(crbug.com/1067347): Move complete class to password_manager namespace.
-struct PasswordForm {
- // Enum to differentiate between HTML form based authentication, and dialogs
- // using basic or digest schemes. Default is kHtml. Only PasswordForms of the
- // same Scheme will be matched/autofilled against each other.
- enum class Scheme {
- kHtml,
- kBasic,
- kDigest,
- kOther,
- kUsernameOnly,
- kMinValue = kHtml,
- kMaxValue = kUsernameOnly,
- };
-
- // Enum to differentiate between manually filled forms, forms with auto-
- // generated passwords, and forms generated from the DOM API.
- //
- // Always append new types at the end. This enum is converted to int and
- // stored in password store backends, so it is important to keep each
- // value assigned to the same integer.
- enum class Type {
- kManual,
- kGenerated,
- kApi,
- kMinValue = kManual,
- kMaxValue = kApi,
- };
-
- // Enum to keep track of what information has been sent to the server about
- // this form regarding password generation.
- enum class GenerationUploadStatus {
- kNoSignalSent,
- kPositiveSignalSent,
- kNegativeSignalSent,
- kMinValue = kNoSignalSent,
- kMaxValue = kNegativeSignalSent,
- };
-
- Scheme scheme = Scheme::kHtml;
-
- // The "Realm" for the sign-on. This is scheme, host, port for SCHEME_HTML.
- // Dialog based forms also contain the HTTP realm. Android based forms will
- // contain a string of the form "android://<hash of cert>@<package name>"
- //
- // The signon_realm is effectively the primary key used for retrieving
- // data from the database, so it must not be empty.
- std::string signon_realm;
-
- // An URL consists of the scheme, host, port and path; the rest is stripped.
- // This is the primary data used by the PasswordManager to decide (in longest
- // matching prefix fashion) whether or not a given PasswordForm result from
- // the database is a good fit for a particular form on a page.
- //
- // This should not be empty except for Android based credentials.
- GURL url;
-
- // The action target of the form; like |origin| URL consists of the scheme,
- // host, port and path; the rest is stripped. This is the primary data used by
- // the PasswordManager for form autofill; that is, the action of the saved
- // credentials must match the action of the form on the page to be autofilled.
- // If this is empty / not available, it will result in a "restricted" IE-like
- // autofill policy, where we wait for the user to type in their username
- // before autofilling the password. In these cases, after successful login the
- // action URL will automatically be assigned by the PasswordManager.
- //
- // When parsing an HTML form, this must always be set.
- GURL action;
-
- // The web realm affiliated with the Android application, if the form is an
- // Android credential. Otherwise, the string is empty. If there are several
- // realms affiliated with the application, an arbitrary realm is chosen. The
- // field is filled out when the PasswordStore injects affiliation and branding
- // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
- // no prior call to this method, the string is empty.
- std::string affiliated_web_realm;
-
- // The display name (e.g. Play Store name) of the Android application if the
- // form is an Android credential. Otherwise, the string is empty. The field is
- // filled out when the PasswordStore injects affiliation and branding
- // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
- // no prior call to this method, the string is empty.
- std::string app_display_name;
-
- // The icon URL (e.g. Play Store icon URL) of the Android application if the
- // form is an Android credential. Otherwise, the URL is empty. The field is
- // filled out when the PasswordStore injects affiliation and branding
- // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
- // no prior call to this method, the URL is empty.
- GURL app_icon_url;
-
- // The name of the submit button used. Optional; only used in scoring
- // of PasswordForm results from the database to make matches as tight as
- // possible.
- base::string16 submit_element;
-
- // The name of the username input element.
- base::string16 username_element;
-
- // The renderer id of the username input element. It is set during the new
- // form parsing and not persisted.
- FieldRendererId username_element_renderer_id;
-
- // True if the server-side classification was successful.
- bool server_side_classification_successful = false;
-
- // True if the server-side classification believes that the field may be
- // pre-filled with a placeholder in the value attribute. It is set during
- // form parsing and not persisted.
- bool username_may_use_prefilled_placeholder = false;
-
- // When parsing an HTML form, this is typically empty unless the site
- // has implemented some form of autofill.
- base::string16 username_value;
-
- // This member is populated in cases where we there are multiple input
- // elements that could possibly be the username. Used when our heuristics for
- // determining the username are incorrect. Optional.
- ValueElementVector all_possible_usernames;
-
- // This member is populated in cases where we there are multiple possible
- // password values. Used in pending password state, to populate a dropdown
- // for possible passwords. Contains all possible passwords. Optional.
- ValueElementVector all_possible_passwords;
-
- // True if |all_possible_passwords| have autofilled value or its part.
- bool form_has_autofilled_value = false;
-
- // The name of the input element corresponding to the current password.
- // Optional (improves scoring).
- //
- // When parsing an HTML form, this will always be set, unless it is a sign-up
- // form or a change password form that does not ask for the current password.
- // In these two cases the |new_password_element| will always be set.
- base::string16 password_element;
-
- // The renderer id of the password input element. It is set during the new
- // form parsing and not persisted.
- FieldRendererId password_element_renderer_id;
-
- // The current password. Must be non-empty for PasswordForm instances that are
- // meant to be persisted to the password store.
- //
- // When parsing an HTML form, this is typically empty.
- base::string16 password_value;
-
- // The current encrypted password. Must be non-empty for PasswordForm
- // instances retrieved from the password store or coming in a
- // PasswordStoreChange that is not of type REMOVE.
- std::string encrypted_password;
-
- // If the form was a sign-up or a change password form, the name of the input
- // element corresponding to the new password. Optional, and not persisted.
- base::string16 new_password_element;
-
- // The renderer id of the new password input element. It is set during the new
- // form parsing and not persisted.
- FieldRendererId new_password_element_renderer_id;
-
- // The confirmation password element. Optional, only set on form parsing, and
- // not persisted.
- base::string16 confirmation_password_element;
-
- // The renderer id of the confirmation password input element. It is set
- // during the new form parsing and not persisted.
- FieldRendererId confirmation_password_element_renderer_id;
-
- // The new password. Optional, and not persisted.
- base::string16 new_password_value;
-
- // When the login was last used by the user to login to the site. Defaults to
- // |date_created|, except for passwords that were migrated from the now
- // deprecated |preferred| flag. Their default is set when migrating the login
- // database to have the "date_last_used" column.
- //
- // When parsing an HTML form, this is not used.
- base::Time date_last_used;
-
- // When the login was saved (by chrome).
- //
- // When parsing an HTML form, this is not used.
- base::Time date_created;
-
- // When the login was downloaded from the sync server. For local passwords is
- // not used.
- //
- // When parsing an HTML form, this is not used.
- base::Time date_synced;
-
- // Tracks if the user opted to never remember passwords for this form. Default
- // to false.
- //
- // When parsing an HTML form, this is not used.
- bool blocked_by_user = false;
-
- // The form type.
- Type type = Type::kManual;
-
- // The number of times that this username/password has been used to
- // authenticate the user.
- //
- // When parsing an HTML form, this is not used.
- int times_used = 0;
-
- // Autofill representation of this form. Used to communicate with the
- // Autofill servers if necessary. Currently this is only used to help
- // determine forms where we can trigger password generation.
- //
- // When parsing an HTML form, this is normally set.
- FormData form_data;
-
- // What information has been sent to the Autofill server about this form.
- GenerationUploadStatus generation_upload_status =
- GenerationUploadStatus::kNoSignalSent;
-
- // These following fields are set by a website using the Credential Manager
- // API. They will be empty and remain unused for sites which do not use that
- // API.
- //
- // User friendly name to show in the UI.
- base::string16 display_name;
-
- // The URL of this credential's icon, such as the user's avatar, to display
- // in the UI.
- GURL icon_url;
-
- // The origin of identity provider used for federated login.
- url::Origin federation_origin;
-
- // If true, Chrome will not return this credential to a site in response to
- // 'navigator.credentials.request()' without user interaction.
- // Once user selects this credential the flag is reseted.
- bool skip_zero_click = false;
-
- // If true, this form was parsed using Autofill predictions.
- bool was_parsed_using_autofill_predictions = false;
-
- // If true, this match was found using public suffix matching.
- bool is_public_suffix_match = false;
-
- // If true, this is a credential saved through an Android application, and
- // found using affiliation-based match.
- bool is_affiliation_based_match = false;
-
- // The type of the event that was taken as an indication that this form is
- // being or has already been submitted. This field is not persisted and filled
- // out only for submitted forms.
- mojom::SubmissionIndicatorEvent submission_event =
- mojom::SubmissionIndicatorEvent::NONE;
-
- // True iff heuristics declined this form for normal saving or filling (e.g.
- // only credit card fields were found). But this form can be saved or filled
- // only with the fallback.
- bool only_for_fallback = false;
-
- // True iff the new password field was found with server hints or autocomplete
- // attributes. Only set on form parsing for filling, and not persisted. Used
- // as signal for password generation eligibility.
- bool is_new_password_reliable = false;
-
- // Serialized to prefs, so don't change numeric values!
- // These values are persisted to logs. Entries should not be renumbered and
- // numeric values should never be reused.
- enum class Store {
- // Default value.
- kNotSet = 0,
- // Credential came from the profile (i.e. local) storage.
- kProfileStore = 1,
- // Credential came from the Gaia-account-scoped storage.
- kAccountStore = 2,
- kMaxValue = kAccountStore
- };
- Store in_store = Store::kNotSet;
-
- // Vector of hashes of the gaia id for users who prefer not to move this
- // password form to their account. This list is used to suppress the move
- // prompt for those users.
- std::vector<GaiaIdHash> moving_blocked_for_list;
-
- // Return true if we consider this form to be a change password form.
- // We use only client heuristics, so it could include signup forms.
- bool IsPossibleChangePasswordForm() const;
-
- // Return true if we consider this form to be a change password form
- // without username field. We use only client heuristics, so it could
- // include signup forms.
- bool IsPossibleChangePasswordFormWithoutUsername() const;
-
- // Returns true if current password element is set.
- bool HasUsernameElement() const;
-
- // Returns true if current password element is set.
- bool HasPasswordElement() const;
-
- // Returns true if current password element is set.
- bool HasNewPasswordElement() const;
-
- // True iff |federation_origin| isn't empty.
- bool IsFederatedCredential() const;
-
- // True if username element is set and password and new password elements are
- // not set.
- bool IsSingleUsername() const;
-
- // Returns whether this form is stored in the account-scoped store, i.e.
- // whether |in_store == Store::kAccountStore|.
- bool IsUsingAccountStore() const;
-
- // Returns true when |password_value| or |new_password_value| are non-empty.
- bool HasNonEmptyPasswordValue() const;
-
- // Equality operators for testing.
- bool operator==(const PasswordForm& form) const;
- bool operator!=(const PasswordForm& form) const;
-
- PasswordForm();
- PasswordForm(const PasswordForm& other);
- PasswordForm(PasswordForm&& other);
- ~PasswordForm();
-
- PasswordForm& operator=(const PasswordForm& form);
- PasswordForm& operator=(PasswordForm&& form);
-};
-
-// True if the unique keys for the forms are the same. The unique key is
-// (origin, username_element, username_value, password_element, signon_realm).
-bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
- const PasswordForm& right);
-
-// For testing.
-std::ostream& operator<<(std::ostream& os, PasswordForm::Scheme scheme);
-std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
-std::ostream& operator<<(std::ostream& os, PasswordForm* form);
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h
index 36f83ca6b03..93081879d5d 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -9,7 +9,6 @@
#include <vector>
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/renderer_id.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.cc b/chromium/components/autofill/core/common/password_form_generation_data.cc
deleted file mode 100644
index 04cccb19fbb..00000000000
--- a/chromium/components/autofill/core/common/password_form_generation_data.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 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/common/password_form_generation_data.h"
-
-#include <utility>
-
-namespace autofill {
-
-PasswordFormGenerationData::PasswordFormGenerationData() = default;
-
-PasswordFormGenerationData::PasswordFormGenerationData(
- FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id)
- : new_password_renderer_id(new_password_renderer_id),
- confirmation_password_renderer_id(confirmation_password_renderer_id) {}
-
-#if defined(OS_IOS)
-PasswordFormGenerationData::PasswordFormGenerationData(
- FormRendererId form_renderer_id,
- FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id)
- : form_renderer_id(form_renderer_id),
- new_password_renderer_id(new_password_renderer_id),
- confirmation_password_renderer_id(confirmation_password_renderer_id) {}
-
-PasswordFormGenerationData::PasswordFormGenerationData(
- const PasswordFormGenerationData&) = default;
-
-PasswordFormGenerationData& PasswordFormGenerationData::operator=(
- const PasswordFormGenerationData&) = default;
-
-PasswordFormGenerationData::PasswordFormGenerationData(
- PasswordFormGenerationData&&) = default;
-
-PasswordFormGenerationData& PasswordFormGenerationData::operator=(
- PasswordFormGenerationData&&) = default;
-
-PasswordFormGenerationData::~PasswordFormGenerationData() = default;
-
-#endif
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.h b/chromium/components/autofill/core/common/password_form_generation_data.h
index 2618629d47a..7c22909ac82 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -5,32 +5,15 @@
#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_
-#include <stdint.h>
-
-#include "base/optional.h"
#include "build/build_config.h"
#include "components/autofill/core/common/renderer_id.h"
-#include "url/gurl.h"
namespace autofill {
// Structure used for sending information from browser to renderer about on
// which fields password should be generated.
struct PasswordFormGenerationData {
- PasswordFormGenerationData();
- PasswordFormGenerationData(FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id);
#if defined(OS_IOS)
- PasswordFormGenerationData(FormRendererId form_renderer_id,
- FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id);
-
- PasswordFormGenerationData(const PasswordFormGenerationData&);
- PasswordFormGenerationData& operator=(const PasswordFormGenerationData&);
- PasswordFormGenerationData(PasswordFormGenerationData&&);
- PasswordFormGenerationData& operator=(PasswordFormGenerationData&&);
- ~PasswordFormGenerationData();
-
FormRendererId form_renderer_id;
#endif
FieldRendererId new_password_renderer_id;
diff --git a/chromium/components/autofill/core/common/password_generation_util.h b/chromium/components/autofill/core/common/password_generation_util.h
index 43115bfaae3..abcee73daae 100644
--- a/chromium/components/autofill/core/common/password_generation_util.h
+++ b/chromium/components/autofill/core/common/password_generation_util.h
@@ -5,7 +5,9 @@
#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_GENERATION_UTIL_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_GENERATION_UTIL_H_
-#include "components/autofill/core/common/password_form.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "ui/gfx/geometry/rect_f.h"
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc
index cc87fcd332e..4890a9be31a 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc
@@ -353,8 +353,8 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Generation disabled: no sync";
case STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE:
return "Generation: automatic generation is available";
- case STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP:
- return "Show generation popup triggered manually";
+ case STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP:
+ return "Show generation popup triggered";
case STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED:
return "Generated password accepted";
case STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT:
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h
index 2c23c2e54f4..aea961ea912 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.h
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.h
@@ -120,7 +120,7 @@ class SavePasswordProgressLogger {
STRING_GENERATION_DISABLED_SAVING_DISABLED,
STRING_GENERATION_DISABLED_NO_SYNC,
STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE,
- STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP,
+ STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP,
STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED,
STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT,
STRING_MAIN_FRAME_ORIGIN,
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
index bce8f456d66..550f2e9479a 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/password_form.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm
index 1fcafb96c9f..c33daac5902 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent.mm
@@ -15,6 +15,7 @@
#include "base/mac/foundation_util.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
@@ -107,7 +108,8 @@ void GetFormField(autofill::FormFieldData* field,
void UpdateFieldManagerWithFillingResults(
scoped_refptr<FieldDataManager> fieldDataManager,
- NSString* jsonString) {
+ NSString* jsonString,
+ size_t numFieldsInFormData) {
std::map<uint32_t, base::string16> fillingResults;
if (autofill::ExtractFillingResults(jsonString, &fillingResults)) {
for (auto& fillData : fillingResults) {
@@ -116,6 +118,8 @@ void UpdateFieldManagerWithFillingResults(
kAutofilledOnUserTrigger);
}
}
+ // TODO(crbug/1131038): Remove once the experiment is over.
+ UMA_HISTOGRAM_BOOLEAN("Autofill.FormFillSuccessIOS", !fillingResults.empty());
}
void UpdateFieldManagerForClearedIDs(
@@ -759,9 +763,9 @@ autofillManagerFromWebState:(web::WebState*)webState
};
// The document has now been fully loaded. Scan for forms to be extracted.
size_t min_required_fields =
- MIN(autofill::MinRequiredFieldsForUpload(),
- MIN(autofill::MinRequiredFieldsForHeuristics(),
- autofill::MinRequiredFieldsForQuery()));
+ MIN(autofill::kMinRequiredFieldsForUpload,
+ MIN(autofill::kMinRequiredFieldsForHeuristics,
+ autofill::kMinRequiredFieldsForQuery));
[self fetchFormsFiltered:NO
withName:base::string16()
minimumRequiredFieldsCount:min_required_fields
@@ -944,6 +948,7 @@ 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
@@ -953,7 +958,8 @@ autofillManagerFromWebState:(web::WebState*)webState
if (!strongSelf)
return;
UpdateFieldManagerWithFillingResults(
- strongSelf->_fieldDataManager, jsonString);
+ strongSelf->_fieldDataManager, jsonString,
+ numFieldsInFormData);
// 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_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
index 9948c219d46..f72958bede1 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -175,7 +175,7 @@ net::IsolationInfo AutofillDriverIOS::IsolationInfo() {
return net::IsolationInfo();
return net::IsolationInfo::Create(
- net::IsolationInfo::RedirectMode::kUpdateNothing,
+ net::IsolationInfo::RequestType::kOther,
url::Origin::Create(main_web_frame->GetSecurityOrigin()),
url::Origin::Create(web_frame->GetSecurityOrigin()),
net::SiteForCookies());