summaryrefslogtreecommitdiff
path: root/chromium/components/autofill
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/autofill
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/autofill')
-rw-r--r--chromium/components/autofill/android/BUILD.gn47
-rw-r--r--chromium/components/autofill/android/OWNERS6
-rw-r--r--chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java157
-rw-r--r--chromium/components/autofill/android/provider/BUILD.gn53
-rw-r--r--chromium/components/autofill/android/provider/OWNERS (renamed from chromium/components/autofill/android/junit/OWNERS)0
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.cc (renamed from chromium/components/autofill/android/autofill_provider_android.cc)61
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.h (renamed from chromium/components/autofill/android/autofill_provider_android.h)16
-rw-r--r--chromium/components/autofill/android/provider/form_data_android.cc (renamed from chromium/components/autofill/android/form_data_android.cc)6
-rw-r--r--chromium/components/autofill/android/provider/form_data_android.h (renamed from chromium/components/autofill/android/form_data_android.h)6
-rw-r--r--chromium/components/autofill/android/provider/form_field_data_android.cc (renamed from chromium/components/autofill/android/form_field_data_android.cc)11
-rw-r--r--chromium/components/autofill/android/provider/form_field_data_android.h (renamed from chromium/components/autofill/android/form_field_data_android.h)6
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java (renamed from chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java)0
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java (renamed from chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java)0
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java (renamed from chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProviderImpl.java)340
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java (renamed from chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProviderUMA.java)0
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormData.java (renamed from chromium/components/autofill/android/java/src/org/chromium/components/autofill/FormData.java)0
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java (renamed from chromium/components/autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java)20
-rw-r--r--chromium/components/autofill/android/provider/junit/BUILD.gn (renamed from chromium/components/autofill/android/junit/BUILD.gn)8
-rw-r--r--chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java (renamed from chromium/components/autofill/android/junit/src/org/chromium/components/autofill/AutofillProviderImplTest.java)13
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc8
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h8
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory.cc17
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc4
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc3
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_agent.mojom2
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_driver.mojom4
-rw-r--r--chromium/components/autofill/content/renderer/BUILD.gn1
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc131
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h3
-rw-r--r--chromium/components/autofill/content/renderer/focus_test_utils.h4
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc90
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.h32
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc160
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc44
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.cc11
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.h4
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.cc11
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc345
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc106
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h34
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc16
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.h7
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc3
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.h3
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn5
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css4
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant_unittest.cc36
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.cc23
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h45
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc73
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.h16
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc30
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc8
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc271
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.cc121
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.h52
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.cc8
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc176
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h37
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc97
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc253
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h90
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc815
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.cc8
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.h7
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc60
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h19
-rw-r--r--chromium/components/autofill/core/browser/autofill_type.cc18
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.cc39
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.h13
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc45
-rw-r--r--chromium/components/autofill/core/browser/data_model/data_model_utils.cc14
-rw-r--r--chromium/components/autofill/core/browser/data_model/data_model_utils.h4
-rw-r--r--chromium/components/autofill/core/browser/data_model/phone_number.cc14
-rw-r--r--chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc76
-rw-r--r--chromium/components/autofill/core/browser/data_model/test_data_creator.cc1
-rw-r--r--chromium/components/autofill/core/browser/field_filler.cc41
-rw-r--r--chromium/components/autofill/core/browser/field_filler_unittest.cc128
-rw-r--r--chromium/components/autofill/core/browser/field_types.cc4
-rw-r--r--chromium/components/autofill/core/browser/field_types.h11
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc51
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.h3
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc248
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc66
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.h8
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc68
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.cc94
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.h7
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc331
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc305
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h90
-rw-r--r--chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc7
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc494
-rw-r--r--chromium/components/autofill/core/browser/geo/country_names.cc3
-rw-r--r--chromium/components/autofill/core/browser/geo/country_names_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc7
-rw-r--r--chromium/components/autofill/core/browser/metrics/form_event_logger_base.h2
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc13
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager.h42
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc11
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h13
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc7
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc22
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc69
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc52
-rw-r--r--chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc3
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc13
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc79
-rw-r--r--chromium/components/autofill/core/browser/payments/test_internal_authenticator.cc15
-rw-r--r--chromium/components/autofill/core/browser/payments/test_internal_authenticator.h2
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc47
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h6
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc455
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto46
-rw-r--r--chromium/components/autofill/core/browser/randomized_encoder.cc1
-rw-r--r--chromium/components/autofill/core/browser/randomized_encoder.h1
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc10
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h7
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_download_manager.cc3
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager.cc5
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.h1
-rw-r--r--chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc1
-rw-r--r--chromium/components/autofill/core/browser/ui/accessory_sheet_enums.h10
-rw-r--r--chromium/components/autofill/core/browser/ui/address_combobox_model.cc4
-rw-r--r--chromium/components/autofill/core/browser/ui/address_combobox_model.h4
-rw-r--r--chromium/components/autofill/core/browser/ui/country_combobox_model.cc4
-rw-r--r--chromium/components/autofill/core/browser/ui/country_combobox_model.h4
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl.cc2
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc43
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h1
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc57
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h5
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/ui/popup_types.h3
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model.cc8
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model.h4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_change.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc24
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc9
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc5
-rw-r--r--chromium/components/autofill/core/common/autofill_data_validation.cc2
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc42
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h7
-rw-r--r--chromium/components/autofill/core/common/autofill_internals/log_message.cc1
-rw-r--r--chromium/components/autofill/core/common/autofill_internals/logging_scope.cc1
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.cc29
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.h4
-rw-r--r--chromium/components/autofill/core/common/autofill_regex_constants.cc3
-rw-r--r--chromium/components/autofill/core/common/autofill_regex_constants.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes.cc6
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes.h5
-rw-r--r--chromium/components/autofill/core/common/form_data.h4
-rw-r--r--chromium/components/autofill/core/common/form_field_data.cc1
-rw-r--r--chromium/components/autofill/core/common/form_field_data.h8
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types.mojom7
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc10
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h18
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc36
-rw-r--r--chromium/components/autofill/core/common/password_form.cc7
-rw-r--r--chromium/components/autofill/core/common/password_form.h18
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h7
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.cc2
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h4
-rw-r--r--chromium/components/autofill/core/common/renderer_id.h2
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm3
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.h1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.mm32
-rw-r--r--chromium/components/autofill/ios/browser/js_autofill_manager.h7
-rw-r--r--chromium/components/autofill/ios/browser/js_autofill_manager.mm33
-rw-r--r--chromium/components/autofill/ios/browser/js_suggestion_manager.mm12
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm1
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm39
-rw-r--r--chromium/components/autofill/ios/form_util/form_unittest.mm54
-rw-r--r--chromium/components/autofill/ios/form_util/resources/fill.js58
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form.js2
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form_handlers.js57
183 files changed, 5673 insertions, 2250 deletions
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
index f246baeb159..e29c613e982 100644
--- a/chromium/components/autofill/android/BUILD.gn
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -41,6 +41,7 @@ android_library("autofill_java") {
"//base:base_java",
"//content/public/android:content_java",
"//third_party/android_deps:android_support_v7_appcompat_java",
+ "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
"//ui/android:ui_java",
]
sources = [
@@ -54,49 +55,3 @@ android_library("autofill_java") {
]
srcjar_deps = [ ":autofill_core_browser_java_enums" ]
}
-
-android_library("provider_java") {
- deps = [
- "//base:base_java",
- "//base:jni_java",
- "//components/autofill/core/common/mojom:mojo_types_java",
- "//components/version_info/android:version_constants_java",
- "//content/public/android:content_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
- "//ui/android:ui_java",
- ]
- annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
- sources = [
- "java/src/org/chromium/components/autofill/AutofillActionModeCallback.java",
- "java/src/org/chromium/components/autofill/AutofillManagerWrapper.java",
- "java/src/org/chromium/components/autofill/AutofillProvider.java",
- "java/src/org/chromium/components/autofill/AutofillProviderImpl.java",
- "java/src/org/chromium/components/autofill/AutofillProviderUMA.java",
- "java/src/org/chromium/components/autofill/FormData.java",
- "java/src/org/chromium/components/autofill/FormFieldData.java",
- ]
-}
-
-generate_jni("jni_headers") {
- sources = [
- "java/src/org/chromium/components/autofill/AutofillProvider.java",
- "java/src/org/chromium/components/autofill/FormData.java",
- "java/src/org/chromium/components/autofill/FormFieldData.java",
- ]
-}
-
-static_library("provider") {
- sources = [
- "autofill_provider_android.cc",
- "autofill_provider_android.h",
- "form_data_android.cc",
- "form_data_android.h",
- "form_field_data_android.cc",
- "form_field_data_android.h",
- ]
- deps = [
- ":jni_headers",
- "//components/autofill/core/browser:browser",
- "//content/public/browser",
- ]
-}
diff --git a/chromium/components/autofill/android/OWNERS b/chromium/components/autofill/android/OWNERS
index 7f956d082c5..475b1659fb0 100644
--- a/chromium/components/autofill/android/OWNERS
+++ b/chromium/components/autofill/android/OWNERS
@@ -1,8 +1,2 @@
file://ui/android/OWNERS
-# Files related to integration with system autofill
-per-file *autofill_provider*=michaelbai@chromium.org
-per-file *AutofillProvider*=michaelbai@chromium.org
-per-file *AutofillManagerWrapper*=michaelbai@chromium.org
-per-file *form*=michaelbai@chromium.org
-per-file *Form*=michaelbai@chromium.org
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java b/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
deleted file mode 100644
index a7d05d359a4..00000000000
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.autofill;
-
-import android.util.SparseArray;
-import android.view.ViewGroup;
-import android.view.ViewStructure;
-import android.view.autofill.AutofillValue;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.annotations.NativeMethods;
-import org.chromium.content_public.browser.WebContents;
-
-/**
- * This class defines interface of AutofillProvider, it doesn't use chrome's
- * autofill service or suggestion UI, instead, uses third party autofill service
- * by knowing of format structure and user's input.
- *
- * AutofillProvider handles one autofill session at time, each call of
- * queryFormFieldAutofill cancels previous session and starts a new one, the
- * calling of other methods shall associate with current session.
- *
- */
-@JNINamespace("autofill")
-public abstract class AutofillProvider {
- public AutofillProvider() {}
-
- /**
- * Invoked when container view is changed.
- *
- * @param containerView new container view.
- */
- public abstract void onContainerViewChanged(ViewGroup containerView);
-
- public abstract void setWebContents(WebContents webContents);
-
- /**
- * Invoked when autofill value is available, AutofillProvider shall fill the
- * form with the provided values.
- *
- * @param values the array of autofill values, the key is virtual id of form
- * field.
- */
- public abstract void autofill(final SparseArray<AutofillValue> values);
-
- /**
- * Invoked when autofill service needs the form structure.
- *
- * @param structure see View.onProvideAutofillVirtualStructure()
- * @param flags see View.onProvideAutofillVirtualStructure()
- */
- public abstract void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags);
-
- /**
- * @return whether query autofill suggestion.
- */
- public abstract boolean shouldQueryAutofillSuggestion();
-
- public abstract void queryAutofillSuggestion();
-
- /**
- * Invoked when filling form is need. AutofillProvider shall ask autofill
- * service for the values with which to fill the form.
- *
- * @param formData the form needs to fill.
- * @param focus the index of focus field in formData
- * @param x the boundary of focus field.
- * @param y the boundary of focus field.
- * @param width the boundary of focus field.
- * @param height the boundary of focus field.
- */
- @CalledByNative
- protected abstract void startAutofillSession(
- FormData formData, int focus, float x, float y, float width, float height);
-
- /**
- * Invoked when form field's value is changed.
- *
- * @param index index of field in current form.
- * @param x the boundary of focus field.
- * @param y the boundary of focus field.
- * @param width the boundary of focus field.
- * @param height the boundary of focus field.
- *
- */
- @CalledByNative
- protected abstract void onFormFieldDidChange(
- int index, float x, float y, float width, float height);
-
- /**
- * Invoked when text field is scrolled.
- *
- * @param index index of field in current form.
- * @param x the boundary of focus field.
- * @param y the boundary of focus field.
- * @param width the boundary of focus field.
- * @param height the boundary of focus field.
- *
- */
- @CalledByNative
- protected abstract void onTextFieldDidScroll(
- int index, float x, float y, float width, float height);
-
- /**
- * Invoked when current form will be submitted.
- * @param submissionSource the submission source, could be any member defined in
- * SubmissionSource.java
- */
- @CalledByNative
- protected abstract void onFormSubmitted(int submissionSource);
-
- /**
- * Invoked when focus field changed.
- *
- * @param focusOnForm whether focus is still on form.
- * @param focusItem the index of field has focus
- * @param x the boundary of focus field.
- * @param y the boundary of focus field.
- * @param width the boundary of focus field.
- * @param height the boundary of focus field.
- */
- @CalledByNative
- protected abstract void onFocusChanged(
- boolean focusOnForm, int focusItem, float x, float y, float width, float height);
-
- /**
- * Send form to renderer for filling.
- *
- * @param nativeAutofillProvider the native autofill provider.
- * @param formData the form to fill.
- */
- protected void autofill(long nativeAutofillProvider, FormData formData) {
- AutofillProviderJni.get().onAutofillAvailable(
- nativeAutofillProvider, AutofillProvider.this, formData);
- }
-
- /**
- * Invoked when current query need to be reset.
- */
- @CalledByNative
- protected abstract void reset();
-
- @CalledByNative
- protected abstract void setNativeAutofillProvider(long nativeAutofillProvider);
-
- @CalledByNative
- protected abstract void onDidFillAutofillFormData();
-
- @NativeMethods
- interface Natives {
- void onAutofillAvailable(
- long nativeAutofillProviderAndroid, AutofillProvider caller, FormData formData);
- }
-}
diff --git a/chromium/components/autofill/android/provider/BUILD.gn b/chromium/components/autofill/android/provider/BUILD.gn
new file mode 100644
index 00000000000..263b88afd5e
--- /dev/null
+++ b/chromium/components/autofill/android/provider/BUILD.gn
@@ -0,0 +1,53 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+import("//build/config/locales.gni")
+
+android_library("java") {
+ deps = [
+ "//base:base_java",
+ "//base:jni_java",
+ "//components/autofill/android:autofill_java",
+ "//components/autofill/core/common/mojom:mojo_types_java",
+ "//components/version_info/android:version_constants_java",
+ "//content/public/android:content_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//ui/android:ui_java",
+ ]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+ sources = [
+ "java/src/org/chromium/components/autofill/AutofillActionModeCallback.java",
+ "java/src/org/chromium/components/autofill/AutofillManagerWrapper.java",
+ "java/src/org/chromium/components/autofill/AutofillProvider.java",
+ "java/src/org/chromium/components/autofill/AutofillProviderUMA.java",
+ "java/src/org/chromium/components/autofill/FormData.java",
+ "java/src/org/chromium/components/autofill/FormFieldData.java",
+ ]
+}
+
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/autofill/AutofillProvider.java",
+ "java/src/org/chromium/components/autofill/FormData.java",
+ "java/src/org/chromium/components/autofill/FormFieldData.java",
+ ]
+}
+
+static_library("provider") {
+ sources = [
+ "autofill_provider_android.cc",
+ "autofill_provider_android.h",
+ "form_data_android.cc",
+ "form_data_android.h",
+ "form_field_data_android.cc",
+ "form_field_data_android.h",
+ ]
+ deps = [
+ ":jni_headers",
+ "//components/autofill/core/browser:browser",
+ "//content/public/browser",
+ "//ui/android",
+ ]
+}
diff --git a/chromium/components/autofill/android/junit/OWNERS b/chromium/components/autofill/android/provider/OWNERS
index 44a22b15980..44a22b15980 100644
--- a/chromium/components/autofill/android/junit/OWNERS
+++ b/chromium/components/autofill/android/provider/OWNERS
diff --git a/chromium/components/autofill/android/autofill_provider_android.cc b/chromium/components/autofill/android/provider/autofill_provider_android.cc
index 76129371d95..408ff96c130 100644
--- a/chromium/components/autofill/android/autofill_provider_android.cc
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.cc
@@ -2,27 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill/android/autofill_provider_android.h"
+#include "components/autofill/android/provider/autofill_provider_android.h"
#include <memory>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
-#include "components/autofill/android/form_data_android.h"
-#include "components/autofill/android/jni_headers/AutofillProvider_jni.h"
+#include "components/autofill/android/provider/form_data_android.h"
+#include "components/autofill/android/provider/jni_headers/AutofillProvider_jni.h"
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_handler_proxy.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
+#include "ui/android/window_android.h"
#include "ui/gfx/geometry/rect_f.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF16;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
+using base::android::ToJavaArrayOfStrings;
using content::BrowserThread;
using content::WebContents;
using gfx::RectF;
@@ -85,6 +88,21 @@ void AutofillProviderAndroid::OnQueryFormFieldAutofill(
// ignored if the form is same.
if (ShouldStartNewSession(handler, form))
StartNewSession(handler, form, field, bounding_box);
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ if (!field.datalist_values.empty()) {
+ ScopedJavaLocalRef<jobjectArray> jdatalist_values =
+ ToJavaArrayOfStrings(env, field.datalist_values);
+ ScopedJavaLocalRef<jobjectArray> jdatalist_labels =
+ ToJavaArrayOfStrings(env, field.datalist_labels);
+ Java_AutofillProvider_showDatalistPopup(
+ env, obj, jdatalist_values, jdatalist_labels,
+ field.text_direction == base::i18n::RIGHT_TO_LEFT);
+ }
}
bool AutofillProviderAndroid::ShouldStartNewSession(
@@ -141,6 +159,31 @@ void AutofillProviderAndroid::OnAutofillAvailable(JNIEnv* env,
}
}
+void AutofillProviderAndroid::OnAcceptDataListSuggestion(JNIEnv* env,
+ jobject jcaller,
+ jstring value) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (auto* handler = handler_.get()) {
+ RendererShouldAcceptDataListSuggestion(
+ handler, ConvertJavaStringToUTF16(env, value));
+ }
+}
+
+void AutofillProviderAndroid::SetAnchorViewRect(JNIEnv* env,
+ jobject jcaller,
+ jobject anchor_view,
+ jfloat x,
+ jfloat y,
+ jfloat width,
+ jfloat height) {
+ ui::ViewAndroid* view_android = web_contents_->GetNativeView();
+ if (!view_android)
+ return;
+
+ view_android->SetAnchorRect(ScopedJavaLocalRef<jobject>(env, anchor_view),
+ gfx::RectF(x, y, width, height));
+}
+
void AutofillProviderAndroid::OnTextFieldDidChange(
AutofillHandlerProxy* handler,
const FormData& form,
@@ -314,6 +357,18 @@ void AutofillProviderAndroid::OnFormsSeen(AutofillHandlerProxy* handler,
FireSuccessfulSubmission(pending_submission_source_);
}
+void AutofillProviderAndroid::OnHidePopup(AutofillHandlerProxy* handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (handler == handler_.get()) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_AutofillProvider_hidePopup(env, obj);
+ }
+}
+
void AutofillProviderAndroid::Reset(AutofillHandlerProxy* handler) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (handler == handler_.get()) {
diff --git a/chromium/components/autofill/android/autofill_provider_android.h b/chromium/components/autofill/android/provider/autofill_provider_android.h
index 270a05eea00..b0830e2338e 100644
--- a/chromium/components/autofill/android/autofill_provider_android.h
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.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_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
-#define COMPONENTS_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
+#ifndef COMPONENTS_AUTOFILL_ANDROID_PROVIDER_AUTOFILL_PROVIDER_ANDROID_H_
+#define COMPONENTS_AUTOFILL_ANDROID_PROVIDER_AUTOFILL_PROVIDER_ANDROID_H_
#include "base/android/jni_weak_ref.h"
#include "base/memory/weak_ptr.h"
@@ -67,11 +67,21 @@ class AutofillProviderAndroid : public AutofillProvider {
void OnFormsSeen(AutofillHandlerProxy* handler,
const std::vector<FormData>& forms,
const base::TimeTicks timestamp) override;
+ void OnHidePopup(AutofillHandlerProxy* handler) override;
void Reset(AutofillHandlerProxy* handler) override;
// Methods called by Java.
void OnAutofillAvailable(JNIEnv* env, jobject jcaller, jobject form_data);
+ void OnAcceptDataListSuggestion(JNIEnv* env, jobject jcaller, jstring value);
+
+ void SetAnchorViewRect(JNIEnv* env,
+ jobject jcaller,
+ jobject anchor_view,
+ jfloat x,
+ jfloat y,
+ jfloat width,
+ jfloat height);
private:
void FireSuccessfulSubmission(mojom::SubmissionSource source);
@@ -114,4 +124,4 @@ class AutofillProviderAndroid : public AutofillProvider {
};
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
+#endif // COMPONENTS_AUTOFILL_ANDROID_PROVIDER_AUTOFILL_PROVIDER_ANDROID_H_
diff --git a/chromium/components/autofill/android/form_data_android.cc b/chromium/components/autofill/android/provider/form_data_android.cc
index c91a0c62472..7f24f8967c5 100644
--- a/chromium/components/autofill/android/form_data_android.cc
+++ b/chromium/components/autofill/android/provider/form_data_android.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill/android/form_data_android.h"
+#include "components/autofill/android/provider/form_data_android.h"
#include "base/android/jni_string.h"
-#include "components/autofill/android/form_field_data_android.h"
-#include "components/autofill/android/jni_headers/FormData_jni.h"
+#include "components/autofill/android/provider/form_field_data_android.h"
+#include "components/autofill/android/provider/jni_headers/FormData_jni.h"
#include "components/autofill/core/browser/form_structure.h"
using base::android::AttachCurrentThread;
diff --git a/chromium/components/autofill/android/form_data_android.h b/chromium/components/autofill/android/provider/form_data_android.h
index a2b33c8d917..8882a788673 100644
--- a/chromium/components/autofill/android/form_data_android.h
+++ b/chromium/components/autofill/android/provider/form_data_android.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_ANDROID_FORM_DATA_ANDROID_H_
-#define COMPONENTS_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_
+#ifndef COMPONENTS_AUTOFILL_ANDROID_PROVIDER_FORM_DATA_ANDROID_H_
+#define COMPONENTS_AUTOFILL_ANDROID_PROVIDER_FORM_DATA_ANDROID_H_
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
@@ -70,4 +70,4 @@ class FormDataAndroid {
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_
+#endif // COMPONENTS_AUTOFILL_ANDROID_PROVIDER_FORM_DATA_ANDROID_H_
diff --git a/chromium/components/autofill/android/form_field_data_android.cc b/chromium/components/autofill/android/provider/form_field_data_android.cc
index da134267220..ee5471f5239 100644
--- a/chromium/components/autofill/android/form_field_data_android.cc
+++ b/chromium/components/autofill/android/provider/form_field_data_android.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill/android/form_field_data_android.h"
+#include "components/autofill/android/provider/form_field_data_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
-#include "components/autofill/android/jni_headers/FormFieldData_jni.h"
+#include "components/autofill/android/provider/jni_headers/FormFieldData_jni.h"
#include "components/autofill/core/common/autofill_util.h"
using base::android::AttachCurrentThread;
@@ -50,6 +50,10 @@ ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
if (!heuristic_type_.IsUnknown())
jheuristic_type =
ConvertUTF8ToJavaString(env, heuristic_type_.ToString());
+ ScopedJavaLocalRef<jobjectArray> jdatalist_values =
+ ToJavaArrayOfStrings(env, field_ptr_->datalist_values);
+ ScopedJavaLocalRef<jobjectArray> jdatalist_labels =
+ ToJavaArrayOfStrings(env, field_ptr_->datalist_labels);
obj = Java_FormFieldData_createFormFieldData(
env, jname, jlabel, jvalue, jautocomplete_attr,
@@ -57,7 +61,8 @@ ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
joption_values, joption_contents, IsCheckable(field_ptr_->check_status),
IsChecked(field_ptr_->check_status), field_ptr_->max_length,
jheuristic_type, field_ptr_->bounds.x(), field_ptr_->bounds.y(),
- field_ptr_->bounds.right(), field_ptr_->bounds.bottom());
+ field_ptr_->bounds.right(), field_ptr_->bounds.bottom(),
+ jdatalist_values, jdatalist_labels);
java_ref_ = JavaObjectWeakGlobalRef(env, obj);
}
return obj;
diff --git a/chromium/components/autofill/android/form_field_data_android.h b/chromium/components/autofill/android/provider/form_field_data_android.h
index e882bb49704..a12ad979bfe 100644
--- a/chromium/components/autofill/android/form_field_data_android.h
+++ b/chromium/components/autofill/android/provider/form_field_data_android.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_ANDROID_FORM_FIELD_DATA_ANDROID_H_
-#define COMPONENTS_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_
+#ifndef COMPONENTS_AUTOFILL_ANDROID_PROVIDER_FORM_FIELD_DATA_ANDROID_H_
+#define COMPONENTS_AUTOFILL_ANDROID_PROVIDER_FORM_FIELD_DATA_ANDROID_H_
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
@@ -39,4 +39,4 @@ class FormFieldDataAndroid {
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_
+#endif // COMPONENTS_AUTOFILL_ANDROID_PROVIDER_FORM_FIELD_DATA_ANDROID_H_
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java
index 6921fcab52c..6921fcab52c 100644
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
index 0287ac38f97..0287ac38f97 100644
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProviderImpl.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
index e53188067c3..acbf7a61a22 100644
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProviderImpl.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -19,18 +19,30 @@ import android.view.autofill.AutofillValue;
import androidx.annotation.VisibleForTesting;
+import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
+import org.chromium.base.StrictModeContext;
import org.chromium.base.ThreadUtils;
-import org.chromium.base.annotations.DoNotInline;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.annotations.VerifiesOnO;
import org.chromium.base.metrics.ScopedSysTraceEvent;
import org.chromium.components.version_info.VersionConstants;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContentsAccessibility;
+import org.chromium.ui.DropdownItem;
+import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.display.DisplayAndroid;
/**
- * This class uses Android autofill service to fill web form. All methods are
- * supposed to be called in UI thread.
+ * This class works with Android autofill service to fill web form, it doesn't use chrome's
+ * autofill service or suggestion UI. All methods are supposed to be called in UI thread.
+ *
+ * AutofillProvider handles one autofill session at time, each call of
+ * queryFormFieldAutofill cancels previous session and starts a new one, the
+ * calling of other methods shall associate with current session.
*
* This class doesn't have 1:1 mapping to native AutofillProviderAndroid; the
* normal ownership model is that this object is owned by the embedder-specific
@@ -38,12 +50,13 @@ import org.chromium.ui.display.DisplayAndroid;
* AutofillProviderAndroid is owned by the embedder-specific C++ WebContents
* wrapper (e.g., native AwContents in //android_webview).
*
- * DoNotInline since it causes class verification errors, see crbug.com/991851.
+ * VerifiesOnO since it causes class verification errors, see crbug.com/991851.
*/
-@DoNotInline
+@VerifiesOnO
@TargetApi(Build.VERSION_CODES.O)
-public class AutofillProviderImpl extends AutofillProvider {
- private static final String TAG = "AutofillProviderImpl";
+@JNINamespace("autofill")
+public class AutofillProvider {
+ private static final String TAG = "AutofillProvider";
private static class FocusField {
public final short fieldIndex;
public final Rect absBound;
@@ -117,11 +130,15 @@ public class AutofillProviderImpl extends AutofillProvider {
child.setAutofillValue(AutofillValue.forToggle(field.isChecked()));
break;
case FormFieldData.ControlType.TEXT:
+ case FormFieldData.ControlType.DATALIST:
child.setAutofillType(View.AUTOFILL_TYPE_TEXT);
child.setAutofillValue(AutofillValue.forText(field.getValue()));
if (field.mMaxLength != 0) {
builder.addAttribute("maxlength", String.valueOf(field.mMaxLength));
}
+ if (field.getControlType() == FormFieldData.ControlType.DATALIST) {
+ child.setAutofillOptions(field.mDatalistValues);
+ }
break;
default:
break;
@@ -151,6 +168,7 @@ public class AutofillProviderImpl extends AutofillProvider {
field.setChecked(value.getToggleValue());
break;
case FormFieldData.ControlType.TEXT:
+ case FormFieldData.ControlType.DATALIST:
field.setAutofillValue((String) value.getTextValue());
break;
default:
@@ -188,6 +206,7 @@ public class AutofillProviderImpl extends AutofillProvider {
case FormFieldData.ControlType.TOGGLE:
return AutofillValue.forToggle(field.isChecked());
case FormFieldData.ControlType.TEXT:
+ case FormFieldData.ControlType.DATALIST:
return AutofillValue.forText(field.getValue());
default:
return null;
@@ -240,17 +259,20 @@ public class AutofillProviderImpl extends AutofillProvider {
private AutofillProviderUMA mAutofillUMA;
private AutofillManagerWrapper.InputUIObserver mInputUIObserver;
private long mAutofillTriggeredTimeMillis;
+ private Context mContext;
+ private AutofillPopup mDatalistPopup;
+ private WebContentsAccessibility mWebContentsAccessibility;
+ private View mAnchorView;
- public AutofillProviderImpl(Context context, ViewGroup containerView, String providerName) {
+ public AutofillProvider(Context context, ViewGroup containerView, String providerName) {
this(containerView, new AutofillManagerWrapper(context), context, providerName);
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public AutofillProviderImpl(ViewGroup containerView, AutofillManagerWrapper manager,
+ public AutofillProvider(ViewGroup containerView, AutofillManagerWrapper manager,
Context context, String providerName) {
mProviderName = providerName;
- try (ScopedSysTraceEvent e =
- ScopedSysTraceEvent.scoped("AutofillProviderImpl.constructor")) {
+ try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped("AutofillProvider.constructor")) {
assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
mAutofillManager = manager;
mContainerView = containerView;
@@ -266,15 +288,25 @@ public class AutofillProviderImpl extends AutofillProvider {
}
};
mAutofillManager.addInputUIObserver(mInputUIObserver);
+ mContext = context;
}
}
- @Override
+ /**
+ * Invoked when container view is changed.
+ *
+ * @param containerView new container view.
+ */
public void onContainerViewChanged(ViewGroup containerView) {
mContainerView = containerView;
}
- @Override
+ /**
+ * Invoked when autofill service needs the form structure.
+ *
+ * @param structure see View.onProvideAutofillVirtualStructure()
+ * @param flags see View.onProvideAutofillVirtualStructure()
+ */
public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
// This method could be called for the session started by the native
// control outside of the scope of autofill, e.g. the URL bar, in this case, we simply
@@ -295,7 +327,13 @@ public class AutofillProviderImpl extends AutofillProvider {
mAutofillUMA.onVirtualStructureProvided();
}
- @Override
+ /**
+ * Invoked when autofill value is available, AutofillProvider shall fill the
+ * form with the provided values.
+ *
+ * @param values the array of autofill values, the key is virtual id of form
+ * field.
+ */
public void autofill(final SparseArray<AutofillValue> values) {
if (mNativeAutofillProvider != 0 && mRequest != null && mRequest.autofill((values))) {
autofill(mNativeAutofillProvider, mRequest.mFormData);
@@ -306,13 +344,14 @@ public class AutofillProviderImpl extends AutofillProvider {
}
}
- @Override
+ /**
+ * @return whether query autofill suggestion.
+ */
public boolean shouldQueryAutofillSuggestion() {
return mRequest != null && mRequest.getFocusField() != null
&& !mAutofillManager.isAutofillInputUIShowing();
}
- @Override
public void queryAutofillSuggestion() {
if (shouldQueryAutofillSuggestion()) {
FocusField focusField = mRequest.getFocusField();
@@ -321,27 +360,50 @@ public class AutofillProviderImpl extends AutofillProvider {
}
}
- @Override
+ /**
+ * Invoked when filling form is need. AutofillProvider shall ask autofill
+ * service for the values with which to fill the form.
+ *
+ * @param formData the form needs to fill.
+ * @param focus the index of focus field in formData
+ * @param x the boundary of focus field.
+ * @param y the boundary of focus field.
+ * @param width the boundary of focus field.
+ * @param height the boundary of focus field.
+ */
+ @CalledByNative
public void startAutofillSession(
FormData formData, int focus, float x, float y, float width, float height) {
// Check focusField inside short value?
- // Autofill Manager might have session that wasn't started by AutofillProviderImpl,
+ // Autofill Manager might have session that wasn't started by AutofillProvider,
// we just always cancel existing session here.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
mAutofillManager.cancel();
}
- mAutofillManager.notifyNewSessionStarted();
+
Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
- if (mRequest != null) notifyViewExitBeforeDestoryRequest();
+ if (mRequest != null) notifyViewExitBeforeDestroyRequest();
transformFormFieldToContainViewCoordinates(formData);
mRequest = new AutofillRequest(formData, new FocusField((short) focus, absBound));
int virtualId = mRequest.getVirtualId((short) focus);
- mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
+ notifyVirtualViewEntered(mContainerView, virtualId, absBound);
mAutofillUMA.onSessionStarted(mAutofillManager.isDisabled());
mAutofillTriggeredTimeMillis = System.currentTimeMillis();
+
+ mAutofillManager.notifyNewSessionStarted();
}
- @Override
+ /**
+ * Invoked when form field's value is changed.
+ *
+ * @param index index of field in current form.
+ * @param x the boundary of focus field.
+ * @param y the boundary of focus field.
+ * @param width the boundary of focus field.
+ * @param height the boundary of focus field.
+ *
+ */
+ @CalledByNative
public void onFormFieldDidChange(int index, float x, float y, float width, float height) {
// Check index inside short value?
if (mRequest == null) return;
@@ -358,17 +420,27 @@ public class AutofillProviderImpl extends AutofillProvider {
int virtualId = mRequest.getVirtualId(sIndex);
Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
if (!focusField.absBound.equals(absBound)) {
- mAutofillManager.notifyVirtualViewExited(mContainerView, virtualId);
- mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
+ notifyVirtualViewExited(mContainerView, virtualId);
+ notifyVirtualViewEntered(mContainerView, virtualId, absBound);
// Update focus field position.
mRequest.setFocusField(new FocusField(focusField.fieldIndex, absBound));
}
}
- notifyVirtualValueChanged(index);
+ notifyVirtualValueChanged(index, /* forceNotify = */ false);
mAutofillUMA.onUserChangeFieldValue(mRequest.getField(sIndex).hasPreviouslyAutofilled());
}
- @Override
+ /**
+ * Invoked when text field is scrolled.
+ *
+ * @param index index of field in current form.
+ * @param x the boundary of focus field.
+ * @param y the boundary of focus field.
+ * @param width the boundary of focus field.
+ * @param height the boundary of focus field.
+ *
+ */
+ @CalledByNative
public void onTextFieldDidScroll(int index, float x, float y, float width, float height) {
// crbug.com/730764 - from P and above, Android framework listens to the onScrollChanged()
// and repositions the autofill UI automatically.
@@ -383,42 +455,94 @@ public class AutofillProviderImpl extends AutofillProvider {
Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
// Notify the new position to the Android framework. Note that we do not call
// notifyVirtualViewExited() here intentionally to avoid flickering.
- mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
+ notifyVirtualViewEntered(mContainerView, virtualId, absBound);
// Update focus field position.
mRequest.setFocusField(new FocusField(focusField.fieldIndex, absBound));
}
- private void notifyVirtualValueChanged(int index) {
+ private boolean isDatalistField(int childId) {
+ FormFieldData field = mRequest.getField((short) childId);
+ return field.mControlType == FormFieldData.ControlType.DATALIST;
+ }
+
+ private void notifyVirtualValueChanged(int index, boolean forceNotify) {
+ // The ValueChanged, ViewEntered and ViewExited aren't notified to the autofill service for
+ // the focused datalist to avoid the potential UI conflict.
+ // The datalist support was added later and the option list is displayed by WebView, the
+ // autofill service might also show its suggestions when the datalist (associated the input
+ // field) is focused, the two UI overlap, the solution is to completely hide the fact that
+ // the datalist is being focused to the autofill service to prevent it from displaying the
+ // suggestion.
+ // The ValueChange will still be sent to autofill service when the form
+ // submitted or autofilled.
+ if (!forceNotify && isDatalistField(index)) return;
AutofillValue autofillValue = mRequest.getFieldNewValue(index);
if (autofillValue == null) return;
mAutofillManager.notifyVirtualValueChanged(
mContainerView, mRequest.getVirtualId((short) index), autofillValue);
}
- @Override
+ private void notifyVirtualViewEntered(View parent, int childId, Rect absBounds) {
+ // Refer to notifyVirtualValueChanged() for the reason of the datalist's special handling.
+ if (isDatalistField(childId)) return;
+ mAutofillManager.notifyVirtualViewEntered(parent, childId, absBounds);
+ }
+
+ private void notifyVirtualViewExited(View parent, int childId) {
+ // Refer to notifyVirtualValueChanged() for the reason of the datalist's special handling.
+ if (isDatalistField(childId)) return;
+ mAutofillManager.notifyVirtualViewExited(parent, childId);
+ }
+
+ /**
+ * Invoked when current form will be submitted.
+ * @param submissionSource the submission source, could be any member defined in
+ * SubmissionSource.java
+ */
+ @CalledByNative
public void onFormSubmitted(int submissionSource) {
// The changes could be missing, like those made by Javascript, we'd better to notify
// AutofillManager current values. also see crbug.com/353001 and crbug.com/732856.
- notifyFormValues();
+ forceNotifyFormValues();
mAutofillManager.commit(submissionSource);
mRequest = null;
mAutofillUMA.onFormSubmitted(submissionSource);
}
- @Override
+ /**
+ * Invoked when focus field changed.
+ *
+ * @param focusOnForm whether focus is still on form.
+ * @param focusItem the index of field has focus
+ * @param x the boundary of focus field.
+ * @param y the boundary of focus field.
+ * @param width the boundary of focus field.
+ * @param height the boundary of focus field.
+ */
+ @CalledByNative
public void onFocusChanged(
boolean focusOnForm, int focusField, float x, float y, float width, float height) {
onFocusChangedImpl(
focusOnForm, focusField, x, y, width, height, false /*causedByValueChange*/);
}
- private void notifyViewExitBeforeDestoryRequest() {
+ @CalledByNative
+ public void hidePopup() {
+ if (mDatalistPopup != null) {
+ mDatalistPopup.dismiss();
+ mDatalistPopup = null;
+ }
+ if (mWebContentsAccessibility != null) {
+ mWebContentsAccessibility.onAutofillPopupDismissed();
+ }
+ }
+
+ private void notifyViewExitBeforeDestroyRequest() {
if (mRequest == null) return;
FocusField focusField = mRequest.getFocusField();
if (focusField == null) return;
- mAutofillManager.notifyVirtualViewExited(
- mContainerView, mRequest.getVirtualId(focusField.fieldIndex));
+ notifyVirtualViewExited(mContainerView, mRequest.getVirtualId(focusField.fieldIndex));
mRequest.setFocusField(null);
}
@@ -436,37 +560,118 @@ public class AutofillProviderImpl extends AutofillProvider {
// Notify focus changed.
if (prev != null) {
- mAutofillManager.notifyVirtualViewExited(
- mContainerView, mRequest.getVirtualId(prev.fieldIndex));
+ notifyVirtualViewExited(mContainerView, mRequest.getVirtualId(prev.fieldIndex));
}
- mAutofillManager.notifyVirtualViewEntered(
+ notifyVirtualViewEntered(
mContainerView, mRequest.getVirtualId((short) focusField), absBound);
if (!causedByValueChange) {
// The focus field value might not sync with platform's
// AutofillManager, just notify it value changed.
- notifyVirtualValueChanged(focusField);
+ notifyVirtualValueChanged(focusField, /* forceNotify = */ false);
mAutofillTriggeredTimeMillis = System.currentTimeMillis();
}
mRequest.setFocusField(new FocusField((short) focusField, absBound));
} else {
if (prev == null) return;
// Notify focus changed.
- mAutofillManager.notifyVirtualViewExited(
- mContainerView, mRequest.getVirtualId(prev.fieldIndex));
+ notifyVirtualViewExited(mContainerView, mRequest.getVirtualId(prev.fieldIndex));
mRequest.setFocusField(null);
}
}
- @Override
+ @CalledByNative
+ protected void showDatalistPopup(
+ String[] datalistValues, String[] datalistLabels, boolean isRtl) {
+ if (mRequest == null) return;
+ FocusField focusField = mRequest.getFocusField();
+ if (focusField != null) {
+ showDatalistPopup(datalistValues, datalistLabels,
+ mRequest.getField(focusField.fieldIndex).getBounds(), isRtl);
+ }
+ }
+
+ /**
+ * Display the simplest popup for the datalist. This is same as WebView's datalist popup in
+ * Android pre-o. No suggestion from the autofill service will be presented, No advance
+ * features of AutofillPopup are used.
+ */
+ private void showDatalistPopup(
+ String[] datalistValues, String[] datalistLabels, RectF bounds, boolean isRtl) {
+ final AutofillSuggestion[] suggestions = new AutofillSuggestion[datalistValues.length];
+ for (int i = 0; i < suggestions.length; i++) {
+ suggestions[i] = new AutofillSuggestion(datalistValues[i], datalistLabels[i],
+ DropdownItem.NO_ICON, false /* isIconAtLeft */, i, false /* isDeletable */,
+ false /* isMultilineLabel */, false /* isBoldLabel */);
+ }
+ if (mWebContentsAccessibility == null) {
+ mWebContentsAccessibility = WebContentsAccessibility.fromWebContents(mWebContents);
+ }
+ if (mDatalistPopup == null) {
+ if (ContextUtils.activityFromContext(mContext) == null) return;
+ ViewAndroidDelegate delegate = mWebContents.getViewAndroidDelegate();
+ if (mAnchorView == null) mAnchorView = delegate.acquireView();
+ setAnchorViewRect(bounds);
+ try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
+ mDatalistPopup = new AutofillPopup(mContext, mAnchorView, new AutofillDelegate() {
+ @Override
+ public void dismissed() {
+ onDatalistPopupDismissed();
+ }
+
+ @Override
+ public void suggestionSelected(int listIndex) {
+ onSuggestionSelected(suggestions[listIndex].getLabel());
+ }
+
+ @Override
+ public void deleteSuggestion(int listIndex) {}
+
+ @Override
+ public void accessibilityFocusCleared() {
+ mWebContentsAccessibility.onAutofillPopupAccessibilityFocusCleared();
+ }
+ });
+ } catch (RuntimeException e) {
+ // Deliberately swallowing exception because bad framework implementation can
+ // throw exceptions in ListPopupWindow constructor.
+ onDatalistPopupDismissed();
+ return;
+ }
+ }
+ mDatalistPopup.filterAndShow(suggestions, isRtl, false);
+ if (mWebContentsAccessibility != null) {
+ mWebContentsAccessibility.onAutofillPopupDisplayed(mDatalistPopup.getListView());
+ }
+ }
+
+ private void onDatalistPopupDismissed() {
+ ViewAndroidDelegate delegate = mWebContents.getViewAndroidDelegate();
+ delegate.removeView(mAnchorView);
+ mAnchorView = null;
+ }
+
+ private void onSuggestionSelected(String value) {
+ acceptDataListSuggestion(mNativeAutofillProvider, value);
+ hidePopup();
+ }
+
+ private void setAnchorViewRect(RectF rect) {
+ setAnchorViewRect(mNativeAutofillProvider, mAnchorView, rect);
+ }
+
+ /**
+ * Invoked when current query need to be reset.
+ */
+ @CalledByNative
protected void reset() {
// We don't need to reset anything here, it should be safe to cancel
// current autofill session when new one starts in
// startAutofillSession().
}
- @Override
+ @CalledByNative
protected void setNativeAutofillProvider(long nativeAutofillProvider) {
if (nativeAutofillProvider == mNativeAutofillProvider) return;
// Setting the mNativeAutofillProvider to 0 may occur as a
@@ -482,21 +687,29 @@ public class AutofillProviderImpl extends AutofillProvider {
if (nativeAutofillProvider == 0) mAutofillManager.destroy();
}
- @Override
public void setWebContents(WebContents webContents) {
if (webContents == mWebContents) return;
if (mWebContents != null) mRequest = null;
mWebContents = webContents;
}
- @Override
+ @CalledByNative
protected void onDidFillAutofillFormData() {
- notifyFormValues();
+ // The changes were caused by the autofill service autofill form,
+ // notified it about the result.
+ forceNotifyFormValues();
}
- private void notifyFormValues() {
+ private void forceNotifyFormValues() {
if (mRequest == null) return;
- for (int i = 0; i < mRequest.getFieldCount(); ++i) notifyVirtualValueChanged(i);
+ for (int i = 0; i < mRequest.getFieldCount(); ++i) {
+ notifyVirtualValueChanged(i, /* forceNotify = */ true);
+ }
+ }
+
+ @VisibleForTesting
+ public AutofillPopup getDatalistPopupForTesting() {
+ return mDatalistPopup;
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
@@ -537,4 +750,37 @@ public class AutofillProviderImpl extends AutofillProvider {
field.setBoundsInContainerViewCoordinates(bounds);
}
}
+
+ /**
+ * Send form to renderer for filling.
+ *
+ * @param nativeAutofillProvider the native autofill provider.
+ * @param formData the form to fill.
+ */
+ private void autofill(long nativeAutofillProvider, FormData formData) {
+ AutofillProviderJni.get().onAutofillAvailable(
+ nativeAutofillProvider, AutofillProvider.this, formData);
+ }
+
+ private void acceptDataListSuggestion(long nativeAutofillProvider, String value) {
+ AutofillProviderJni.get().onAcceptDataListSuggestion(
+ nativeAutofillProvider, AutofillProvider.this, value);
+ }
+
+ private void setAnchorViewRect(long nativeAutofillProvider, View anchorView, RectF rect) {
+ AutofillProviderJni.get().setAnchorViewRect(nativeAutofillProvider, AutofillProvider.this,
+ anchorView, rect.left, rect.top, rect.width(), rect.height());
+ }
+
+ @NativeMethods
+ interface Natives {
+ void onAutofillAvailable(
+ long nativeAutofillProviderAndroid, AutofillProvider caller, FormData formData);
+
+ void onAcceptDataListSuggestion(
+ long nativeAutofillProviderAndroid, AutofillProvider caller, String value);
+
+ void setAnchorViewRect(long nativeAutofillProviderAndroid, AutofillProvider caller,
+ View anchorView, float x, float y, float width, float height);
+ }
}
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProviderUMA.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
index 394cd849c95..394cd849c95 100644
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/FormData.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormData.java
index 8069aa887b6..8069aa887b6 100644
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/FormData.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormData.java
diff --git a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
index 964c73206c7..eb0a94a6bce 100644
--- a/chromium/components/autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
@@ -22,13 +22,17 @@ import java.lang.annotation.RetentionPolicy;
public class FormFieldData {
/**
* Define the control types supported by android.view.autofill.AutofillValue.
+ *
+ * Android doesn't have DATALIST control, it is sent to the Autofill service as
+ * View.AUTOFILL_TYPE_TEXT with AutofillOptions.
*/
- @IntDef({ControlType.TEXT, ControlType.TOGGLE, ControlType.LIST})
+ @IntDef({ControlType.TEXT, ControlType.TOGGLE, ControlType.LIST, ControlType.DATALIST})
@Retention(RetentionPolicy.SOURCE)
public @interface ControlType {
int TEXT = 0;
int TOGGLE = 1;
int LIST = 2;
+ int DATALIST = 3;
}
public final String mLabel;
@@ -43,6 +47,9 @@ public class FormFieldData {
public final @ControlType int mControlType;
public final int mMaxLength;
public final String mHeuristicType;
+ public final String[] mDatalistValues;
+ public final String[] mDatalistLabels;
+
// The bounds in the viewport's coordinates
private final RectF mBounds;
// The bounds in the container view's coordinates.
@@ -58,7 +65,8 @@ public class FormFieldData {
private FormFieldData(String name, String label, String value, String autocompleteAttr,
boolean shouldAutocomplete, String placeholder, String type, String id,
String[] optionValues, String[] optionContents, boolean isCheckField, boolean isChecked,
- int maxLength, String heuristicType, float left, float top, float right, float bottom) {
+ int maxLength, String heuristicType, float left, float top, float right, float bottom,
+ String[] datalistValues, String[] datalistLabels) {
mName = name;
mLabel = label;
mValue = value;
@@ -70,8 +78,12 @@ public class FormFieldData {
mOptionValues = optionValues;
mOptionContents = optionContents;
mIsChecked = isChecked;
+ mDatalistLabels = datalistLabels;
+ mDatalistValues = datalistValues;
if (mOptionValues != null && mOptionValues.length != 0) {
mControlType = ControlType.LIST;
+ } else if (mDatalistValues != null && mDatalistValues.length != 0) {
+ mControlType = ControlType.DATALIST;
} else if (isCheckField) {
mControlType = ControlType.TOGGLE;
} else {
@@ -142,9 +154,9 @@ public class FormFieldData {
String autocompleteAttr, boolean shouldAutocomplete, String placeholder, String type,
String id, String[] optionValues, String[] optionContents, boolean isCheckField,
boolean isChecked, int maxLength, String heuristicType, float left, float top,
- float right, float bottom) {
+ float right, float bottom, String[] datalistValues, String[] datalistLabels) {
return new FormFieldData(name, label, value, autocompleteAttr, shouldAutocomplete,
placeholder, type, id, optionValues, optionContents, isCheckField, isChecked,
- maxLength, heuristicType, left, top, right, bottom);
+ maxLength, heuristicType, left, top, right, bottom, datalistValues, datalistLabels);
}
}
diff --git a/chromium/components/autofill/android/junit/BUILD.gn b/chromium/components/autofill/android/provider/junit/BUILD.gn
index 0f58b8ac6fa..95cea50bf90 100644
--- a/chromium/components/autofill/android/junit/BUILD.gn
+++ b/chromium/components/autofill/android/provider/junit/BUILD.gn
@@ -9,13 +9,15 @@ java_library("components_autofill_junit_tests") {
# Platform checks are broken for Robolectric. See https://crbug.com/1071638.
bypass_platform_checks = true
testonly = true
- sources =
- [ "src/org/chromium/components/autofill/AutofillProviderImplTest.java" ]
+ sources = [ "src/org/chromium/components/autofill/AutofillProviderTest.java" ]
deps = [
"//base:base_java_test_support",
"//base:base_junit_test_support",
- "//components/autofill/android:provider_java",
+ "//components/autofill/android/provider:java",
"//content/public/android:content_java",
+ "//third_party/android_deps:robolectric_all_java",
+ "//third_party/junit",
+ "//third_party/mockito:mockito_java",
"//ui/android:ui_java",
]
}
diff --git a/chromium/components/autofill/android/junit/src/org/chromium/components/autofill/AutofillProviderImplTest.java b/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
index d8c8c2bfd3d..e4b12cec808 100644
--- a/chromium/components/autofill/android/junit/src/org/chromium/components/autofill/AutofillProviderImplTest.java
+++ b/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
@@ -31,11 +31,11 @@ import org.chromium.ui.display.DisplayAndroid;
import java.util.ArrayList;
/**
- * The unit tests for AutofillProviderImpl.
+ * The unit tests for AutofillProvider.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
-public class AutofillProviderImplTest {
+public class AutofillProviderTest {
private static final float EXPECTED_DIP_SCALE = 2;
private static final int SCROLL_X = 15;
private static final int SCROLL_Y = 155;
@@ -46,7 +46,7 @@ public class AutofillProviderImplTest {
private WindowAndroid mWindowAndroid;
private WebContents mWebContents;
private ViewGroup mContainerView;
- private AutofillProviderImpl mAutofillProvider;
+ private AutofillProvider mAutofillProvider;
private DisplayAndroid mDisplayAndroid;
@Before
@@ -57,8 +57,7 @@ public class AutofillProviderImplTest {
mDisplayAndroid = Mockito.mock(DisplayAndroid.class);
mWebContents = Mockito.mock(WebContents.class);
mContainerView = Mockito.mock(ViewGroup.class);
- mAutofillProvider =
- new AutofillProviderImpl(mContext, mContainerView, "AutofillProviderImplTest");
+ mAutofillProvider = new AutofillProvider(mContext, mContainerView, "AutofillProviderTest");
mAutofillProvider.setWebContents(mWebContents);
when(mWebContents.getTopLevelNativeWindow()).thenReturn(mWindowAndroid);
@@ -85,10 +84,10 @@ public class AutofillProviderImplTest {
ArrayList<FormFieldData> fields = new ArrayList<FormFieldData>(1);
fields.add(FormFieldData.createFormFieldData(null, null, null, null, false, null, null,
null, null, null, false, false, 0, null, 10 /* left */, 20 /* top */,
- 300 /* right */, 60 /*bottom*/));
+ 300 /* right */, 60 /*bottom*/, null, null));
fields.add(FormFieldData.createFormFieldData(null, null, null, null, false, null, null,
null, null, null, false, false, 0, null, 20 /* left */, 100 /* top */,
- 400 /* right */, 200 /*bottom*/));
+ 400 /* right */, 200 /*bottom*/, null, null));
FormData formData = new FormData(null, null, fields);
mAutofillProvider.transformFormFieldToContainViewCoordinates(formData);
RectF result = formData.mFields.get(0).getBoundsInContainerViewCoordinates();
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 7cf16fc27ea..ed248d98c85 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -288,17 +288,11 @@ void ContentAutofillDriver::DidEndTextFieldEditing() {
autofill_handler_->OnDidEndTextFieldEditing();
}
-void ContentAutofillDriver::SetDataList(
- const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) {
- autofill_handler_->OnSetDataList(values, labels);
-}
-
void ContentAutofillDriver::SelectFieldOptionsDidChange(const FormData& form) {
autofill_handler_->SelectFieldOptionsDidChange(form);
}
-void ContentAutofillDriver::DidNavigateMainFrame(
+void ContentAutofillDriver::DidNavigateFrame(
content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsSameDocument())
return;
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index 587b09f7e65..7d201fe0deb 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -115,13 +115,11 @@ class ContentAutofillDriver : public AutofillDriver,
base::TimeTicks timestamp) override;
void DidPreviewAutofillFormData() override;
void DidEndTextFieldEditing() override;
- void SetDataList(const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) override;
void SelectFieldOptionsDidChange(const FormData& form) override;
- // Called when the main frame has navigated. Explicitely will not trigger for
- // subframe navigations. See navigation_handle.h for details.
- void DidNavigateMainFrame(content::NavigationHandle* navigation_handle);
+ // DidNavigateFrame() is called on the frame's driver, respectively, when a
+ // navigation occurs in that specific frame.
+ void DidNavigateFrame(content::NavigationHandle* navigation_handle);
AutofillManager* autofill_manager() { return autofill_manager_; }
AutofillHandler* autofill_handler() { return autofill_handler_.get(); }
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
index 35e691af47c..2738209f51c 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -132,18 +132,13 @@ void ContentAutofillDriverFactory::RenderFrameDeleted(
void ContentAutofillDriverFactory::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
- // For the purposes of this code, a navigation is not important if it has not
- // committed yet or if it's in a subframe.
- if (!navigation_handle->HasCommitted() ||
- !navigation_handle->IsInMainFrame()) {
- return;
+ if (navigation_handle->HasCommitted() &&
+ (navigation_handle->IsInMainFrame() ||
+ navigation_handle->HasSubframeNavigationEntryCommitted())) {
+ NavigationFinished();
+ DriverForFrame(navigation_handle->GetRenderFrameHost())
+ ->DidNavigateFrame(navigation_handle);
}
-
- // A main frame navigation has occured. We suppress the autofill popup and
- // tell the autofill driver.
- NavigationFinished();
- DriverForFrame(navigation_handle->GetRenderFrameHost())
- ->DidNavigateMainFrame(navigation_handle);
}
void ContentAutofillDriverFactory::OnVisibilityChanged(
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 cc75354a844..335cde6bf11 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -282,7 +282,7 @@ class TestContentAutofillDriver : public ContentAutofillDriver {
return static_cast<MockAutofillManager*>(autofill_manager());
}
- using ContentAutofillDriver::DidNavigateMainFrame;
+ using ContentAutofillDriver::DidNavigateFrame;
};
class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
@@ -316,7 +316,7 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
content::MockNavigationHandle navigation_handle(GURL(), main_rfh());
navigation_handle.set_has_committed(true);
navigation_handle.set_is_same_document(same_document);
- driver_->DidNavigateMainFrame(&navigation_handle);
+ driver_->DidNavigateFrame(&navigation_handle);
}
protected:
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index 35475b3d8a0..b7aa9f45bb9 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -51,6 +51,7 @@
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
+#include "url/gurl.h"
#if BUILDFLAG(ENABLE_PLUGINS)
#include "content/public/browser/plugin_service.h"
@@ -316,7 +317,7 @@ FingerprintDataLoader::FingerprintDataLoader(
content::GetDeviceService().BindGeolocationContext(
geolocation_context_.BindNewPipeAndPassReceiver());
geolocation_context_->BindGeolocation(
- geolocation_.BindNewPipeAndPassReceiver());
+ geolocation_.BindNewPipeAndPassReceiver(), GURL::EmptyGURL());
geolocation_->SetHighAccuracy(false);
geolocation_->QueryNextPosition(
base::BindOnce(&FingerprintDataLoader::OnGotGeoposition,
diff --git a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
index 3e7e9c944a5..28b90f991f2 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
@@ -90,7 +90,7 @@ interface PasswordAutofillAgent {
// Lets the renderer know that there are no saved credentials for filling.
// This is the "no results" equivalent of FillPasswordForm.
- InformNoSavedCredentials();
+ InformNoSavedCredentials(bool should_show_popup_without_passwords);
// Fills the given |credential| into the last focused text input.
FillIntoFocusedField(bool is_password, mojo_base.mojom.String16 credential);
diff --git a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
index 96fcfbf363b..1c9d27910e0 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
@@ -71,10 +71,6 @@ interface AutofillDriver {
// Sent when a text field is done editing.
DidEndTextFieldEditing();
-
- // Informs browser of data list values for the current field.
- SetDataList(array<mojo_base.mojom.String16> values,
- array<mojo_base.mojom.String16> labels);
};
// There is one instance of this interface per web contents in the browser
diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn
index 82ce0f34d5a..6ee2bee980b 100644
--- a/chromium/components/autofill/content/renderer/BUILD.gn
+++ b/chromium/components/autofill/content/renderer/BUILD.gn
@@ -80,6 +80,7 @@ jumbo_static_library("test_support") {
"//components/autofill/content/renderer",
"//services/service_manager/public/cpp",
"//skia",
+ "//testing/gmock",
"//testing/gtest",
"//third_party/blink/public:blink",
]
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 307fa136447..39e65c63370 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -86,6 +86,7 @@ using blink::WebVector;
namespace autofill {
+using form_util::ExtractMask;
using form_util::FindFormAndFieldForFormControlElement;
using form_util::UnownedCheckoutFormElementsAndFieldSetsToFormData;
using mojom::SubmissionSource;
@@ -98,32 +99,12 @@ namespace {
// upon, instead of multiple in close succession (debounce time).
size_t kWaitTimeForSelectOptionsChangesMs = 50;
-// Gets all the data list values (with corresponding label) for the given
-// element.
-void GetDataListSuggestions(const WebInputElement& element,
- std::vector<base::string16>* values,
- std::vector<base::string16>* labels) {
- for (const auto& option : element.FilteredDataListOptions()) {
- values->push_back(option.Value().Utf16());
- if (option.Value() != option.Label())
- labels->push_back(option.Label().Utf16());
- else
- labels->push_back(base::string16());
- }
-}
-
-// Trim the vector before sending it to the browser process to ensure we
-// don't send too much data through the IPC.
-void TrimStringVectorForIPC(std::vector<base::string16>* strings) {
- // Limit the size of the vector.
- if (strings->size() > kMaxListSize)
- strings->resize(kMaxListSize);
-
- // Limit the size of the strings in the vector.
- for (size_t i = 0; i < strings->size(); ++i) {
- if ((*strings)[i].length() > kMaxDataLength)
- (*strings)[i].resize(kMaxDataLength);
- }
+// Helper function to return EXTRACT_DATALIST if kAutofillExtractAllDatalist is
+// enabled, otherwise EXTRACT_NONE is returned.
+ExtractMask GetExtractDatalistMask() {
+ return base::FeatureList::IsEnabled(features::kAutofillExtractAllDatalists)
+ ? form_util::EXTRACT_DATALIST
+ : form_util::EXTRACT_NONE;
}
} // namespace
@@ -160,6 +141,9 @@ AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
&AutofillAgent::BindPendingReceiver, base::Unretained(this)));
}
+// The destructor is not guaranteed to be called. Destruction happens (only)
+// through the OnDestruct() event, which posts a task to delete this object.
+// The process may be killed before this deletion can happen.
AutofillAgent::~AutofillAgent() {
RemoveFormObserver(this);
}
@@ -175,17 +159,13 @@ bool AutofillAgent::FormDataCompare::operator()(const FormData& lhs,
std::tie(rhs.name, rhs.url, rhs.action, rhs.is_form_tag);
}
-void AutofillAgent::DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) {
+void AutofillAgent::DidCommitProvisionalLoad(ui::PageTransition transition) {
blink::WebFrame* frame = render_frame()->GetWebFrame();
// TODO(dvadym): check if we need to check if it is main frame navigation
// http://crbug.com/443155
if (frame->Parent())
return; // Not a top-level navigation.
- if (is_same_document_navigation)
- return;
-
// Navigation to a new page or a page refresh.
element_.Reset();
@@ -225,9 +205,11 @@ void AutofillAgent::DidChangeScrollOffsetImpl(
FormData form;
FormFieldData field;
- if (FindFormAndFieldForFormControlElement(element_, field_data_manager_.get(),
- form_util::EXTRACT_BOUNDS, &form,
- &field)) {
+ if (FindFormAndFieldForFormControlElement(
+ element_, field_data_manager_.get(),
+ static_cast<ExtractMask>(form_util::EXTRACT_BOUNDS |
+ GetExtractDatalistMask()),
+ &form, &field)) {
GetAutofillDriver()->TextFieldDidScroll(form, field, field.bounds);
}
@@ -237,14 +219,6 @@ void AutofillAgent::DidChangeScrollOffsetImpl(
void AutofillAgent::FocusedElementChanged(const WebElement& element) {
was_focused_before_now_ = false;
-
- if ((IsKeyboardAccessoryEnabled() || !focus_requires_scroll_) &&
- !element.IsNull() &&
- element.GetDocument().GetFrame()->HasTransientUserActivation()) {
- focused_node_was_last_clicked_ = true;
- HandleFocusChangeComplete();
- }
-
HidePopup();
if (element.IsNull()) {
@@ -258,14 +232,30 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
const WebInputElement* input = ToWebInputElement(&element);
+ bool focus_moved_to_new_form = false;
if (!last_interacted_form_.IsNull() &&
(!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();
- return;
+ focus_moved_to_new_form = true;
+ }
+
+ // Calls HandleFocusChangeComplete() after notifying the focus is no longer on
+ // the previous form, then early return. No need to notify the newly focused
+ // element because that will be done by HandleFocusChangeComplete() which
+ // triggers FormControlElementClicked().
+ // Refer to http://crbug.com/1105254
+ if ((IsKeyboardAccessoryEnabled() || !focus_requires_scroll_) &&
+ !element.IsNull() &&
+ element.GetDocument().GetFrame()->HasTransientUserActivation()) {
+ focused_node_was_last_clicked_ = true;
+ HandleFocusChangeComplete();
}
+ if (focus_moved_to_new_form)
+ return;
+
if (!input || !input->IsEnabled() || input->IsReadOnly() ||
!input->IsTextField())
return;
@@ -274,9 +264,11 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
FormData form;
FormFieldData field;
- if (FindFormAndFieldForFormControlElement(element_, field_data_manager_.get(),
- form_util::EXTRACT_BOUNDS, &form,
- &field)) {
+ if (FindFormAndFieldForFormControlElement(
+ element_, field_data_manager_.get(),
+ static_cast<ExtractMask>(form_util::EXTRACT_BOUNDS |
+ GetExtractDatalistMask()),
+ &form, &field)) {
GetAutofillDriver()->FocusOnFormField(form, field, field.bounds);
}
}
@@ -355,9 +347,11 @@ void AutofillAgent::OnTextFieldDidChange(const WebInputElement& element) {
FormData form;
FormFieldData field;
- if (FindFormAndFieldForFormControlElement(element, field_data_manager_.get(),
- form_util::EXTRACT_BOUNDS, &form,
- &field)) {
+ if (FindFormAndFieldForFormControlElement(
+ element, field_data_manager_.get(),
+ static_cast<ExtractMask>(form_util::EXTRACT_BOUNDS |
+ GetExtractDatalistMask()),
+ &form, &field)) {
GetAutofillDriver()->TextFieldDidChange(form, field, field.bounds,
AutofillTickClock::NowTicks());
}
@@ -616,9 +610,8 @@ bool AutofillAgent::CollectFormlessElements(FormData* output) {
if (control_elements.size() > kMaxParseableFields)
return false;
- const form_util::ExtractMask extract_mask =
- static_cast<form_util::ExtractMask>(form_util::EXTRACT_VALUE |
- form_util::EXTRACT_OPTIONS);
+ const ExtractMask extract_mask = static_cast<ExtractMask>(
+ form_util::EXTRACT_VALUE | form_util::EXTRACT_OPTIONS);
return UnownedCheckoutFormElementsAndFieldSetsToFormData(
fieldsets, control_elements, nullptr, document, field_data_manager_.get(),
@@ -784,15 +777,18 @@ void AutofillAgent::QueryAutofillSuggestions(
FormData form;
FormFieldData field;
- if (!FindFormAndFieldForFormControlElement(element, field_data_manager_.get(),
- form_util::EXTRACT_BOUNDS, &form,
- &field)) {
+ if (!FindFormAndFieldForFormControlElement(
+ element, field_data_manager_.get(),
+ static_cast<ExtractMask>(form_util::EXTRACT_BOUNDS |
+ GetExtractDatalistMask()),
+ &form, &field)) {
// If we didn't find the cached form, at least let autocomplete have a shot
// at providing suggestions.
WebFormControlElementToFormField(
element, nullptr,
- static_cast<form_util::ExtractMask>(form_util::EXTRACT_VALUE |
- form_util::EXTRACT_BOUNDS),
+ static_cast<ExtractMask>(form_util::EXTRACT_VALUE |
+ form_util::EXTRACT_BOUNDS |
+ GetExtractDatalistMask()),
&field);
}
@@ -803,20 +799,15 @@ void AutofillAgent::QueryAutofillSuggestions(
return;
}
- std::vector<base::string16> data_list_values;
- std::vector<base::string16> data_list_labels;
- const WebInputElement* input_element = ToWebInputElement(&element);
- if (input_element) {
- // Find the datalist values and send them to the browser process.
- GetDataListSuggestions(*input_element, &data_list_values,
- &data_list_labels);
- TrimStringVectorForIPC(&data_list_values);
- TrimStringVectorForIPC(&data_list_labels);
+ if (!base::FeatureList::IsEnabled(features::kAutofillExtractAllDatalists)) {
+ if (const WebInputElement* input_element = ToWebInputElement(&element)) {
+ // Find the datalist values and send them to the browser process.
+ form_util::GetDataListSuggestions(*input_element, &field.datalist_values,
+ &field.datalist_labels);
+ }
}
is_popup_possibly_visible_ = true;
-
- GetAutofillDriver()->SetDataList(data_list_values, data_list_labels);
GetAutofillDriver()->QueryFormFieldAutofill(autofill_query_id_, form, field,
field.bounds,
autoselect_first_suggestion);
@@ -1041,7 +1032,9 @@ void AutofillAgent::OnProvisionallySaveForm(
FormData form;
FormFieldData field;
if (FindFormAndFieldForFormControlElement(
- element, field_data_manager_.get(), form_util::EXTRACT_BOUNDS,
+ element, field_data_manager_.get(),
+ static_cast<ExtractMask>(form_util::EXTRACT_BOUNDS |
+ GetExtractDatalistMask()),
&form, &field)) {
GetAutofillDriver()->SelectControlDidChange(form, field, field.bounds);
}
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index b0e7943afb2..be2b158814f 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -168,8 +168,7 @@ class AutofillAgent : public content::RenderFrameObserver,
};
// content::RenderFrameObserver:
- void DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) override;
+ void DidCommitProvisionalLoad(ui::PageTransition transition) override;
void DidFinishDocumentLoad() override;
void DidChangeScrollOffset() override;
void FocusedElementChanged(const blink::WebElement& element) override;
diff --git a/chromium/components/autofill/content/renderer/focus_test_utils.h b/chromium/components/autofill/content/renderer/focus_test_utils.h
index a20563153b8..038e8fcedb0 100644
--- a/chromium/components/autofill/content/renderer/focus_test_utils.h
+++ b/chromium/components/autofill/content/renderer/focus_test_utils.h
@@ -5,9 +5,9 @@
#ifndef COMPONENTS_AUTOFILL_CONTENT_RENDERER_FOCUS_TEST_UTILS_H_
#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_FOCUS_TEST_UTILS_H_
-#include "base/callback.h"
-#include "string"
+#include <string>
+#include "base/callback.h"
#include "third_party/blink/public/web/web_document.h"
namespace autofill {
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index c1f47cb9575..35f247f215c 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -1470,11 +1470,6 @@ bool UnownedFormElementsAndFieldSetsToFormData(
FormData* form,
FormFieldData* field) {
form->url = GetCanonicalOriginForDocument(document);
- if (IsAutofillFieldMetadataEnabled() && !document.Body().IsNull()) {
- SCOPED_UMA_HISTOGRAM_TIMER(
- "PasswordManager.ButtonTitlePerformance.NoFormTag");
- form->button_titles = InferButtonTitlesForForm(document.Body());
- }
if (document.GetFrame() && document.GetFrame()->Top()) {
form->main_frame_origin = document.GetFrame()->Top()->GetSecurityOrigin();
} else {
@@ -1514,6 +1509,20 @@ bool ScriptModifiedUsernameAcceptable(
return field_data_manager->FindMachedValue(value);
}
+// Trim the vector before sending it to the browser process to ensure we
+// don't send too much data through the IPC.
+void TrimStringVectorForIPC(std::vector<base::string16>* strings) {
+ // Limit the size of the vector.
+ if (strings->size() > kMaxListSize)
+ strings->resize(kMaxListSize);
+
+ // Limit the size of the strings in the vector.
+ for (auto& string : *strings) {
+ if (string.length() > kMaxDataLength)
+ string.resize(kMaxDataLength);
+ }
+}
+
// Helper function that strips any authentication data, as well as query and
// ref portions of URL.
GURL StripAuthAndParams(const GURL& gurl) {
@@ -1527,6 +1536,20 @@ GURL StripAuthAndParams(const GURL& gurl) {
} // namespace
+void GetDataListSuggestions(const WebInputElement& element,
+ std::vector<base::string16>* values,
+ std::vector<base::string16>* labels) {
+ for (const auto& option : element.FilteredDataListOptions()) {
+ values->push_back(option.Value().Utf16());
+ if (option.Value() != option.Label())
+ labels->push_back(option.Label().Utf16());
+ else
+ labels->push_back(base::string16());
+ }
+ TrimStringVectorForIPC(values);
+ TrimStringVectorForIPC(labels);
+}
+
bool ExtractFormData(const WebFormElement& form_element,
const FieldDataManager& field_data_manager,
FormData* data) {
@@ -1583,7 +1606,7 @@ GURL GetCanonicalOriginForDocument(const WebDocument& document) {
return StripAuthAndParams(full_origin);
}
-GURL GetOriginWithoutAuthForDocument(const WebDocument& document) {
+GURL GetDocumentUrlWithoutAuth(const WebDocument& document) {
GURL::Replacements rep;
rep.ClearUsername();
rep.ClearPassword();
@@ -1647,6 +1670,11 @@ base::string16 GetFormIdentifier(const WebFormElement& form) {
return identifier;
}
+FormRendererId GetFormRendererId(const blink::WebFormElement& form) {
+ return form.IsNull() ? FormRendererId()
+ : FormRendererId(form.UniqueRendererFormId());
+}
+
base::i18n::TextDirection GetTextDirectionForElement(
const blink::WebFormControlElement& element) {
// Use 'text-align: left|right' if set or 'direction' otherwise.
@@ -1766,6 +1794,12 @@ void WebFormControlElementToFormField(
}
}
}
+ if (extract_mask & EXTRACT_DATALIST) {
+ if (auto* input = blink::ToWebInputElement(&element)) {
+ GetDataListSuggestions(*input, &field->datalist_values,
+ &field->datalist_labels);
+ }
+ }
if (!(extract_mask & EXTRACT_VALUE))
return;
@@ -1834,11 +1868,6 @@ bool WebFormElementToFormData(
form->action = GetCanonicalActionForForm(form_element);
form->is_action_empty =
form_element.Action().IsNull() || form_element.Action().IsEmpty();
- if (IsAutofillFieldMetadataEnabled()) {
- SCOPED_UMA_HISTOGRAM_TIMER(
- "PasswordManager.ButtonTitlePerformance.HasFormTag");
- form->button_titles = InferButtonTitlesForForm(form_element);
- }
if (frame->Top()) {
form->main_frame_origin = frame->Top()->GetSecurityOrigin();
} else {
@@ -2179,6 +2208,41 @@ base::string16 FindChildText(const WebNode& node) {
return FindChildTextWithIgnoreList(node, std::set<WebNode>());
}
+ButtonTitleList GetButtonTitles(const WebFormElement& web_form,
+ const WebDocument& document,
+ ButtonTitlesCache* button_titles_cache) {
+ DCHECK(button_titles_cache);
+ if (!IsAutofillFieldMetadataEnabled() && web_form.IsNull())
+ return ButtonTitleList();
+
+ // True if the cache has no entry for |web_form|.
+ bool cache_miss = true;
+ // Iterator pointing to the entry for |web_form| if the entry for |web_form|
+ // is found.
+ ButtonTitlesCache::iterator form_position;
+ std::tie(form_position, cache_miss) = button_titles_cache->emplace(
+ GetFormRendererId(web_form), ButtonTitleList());
+ if (!cache_miss)
+ return form_position->second;
+
+ ButtonTitleList button_titles;
+ DCHECK(!web_form.IsNull() || !document.IsNull());
+ if (web_form.IsNull()) {
+ const WebElement& body = document.Body();
+ if (!body.IsNull()) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "PasswordManager.ButtonTitlePerformance.NoFormTag");
+ button_titles = InferButtonTitlesForForm(body);
+ }
+ } else {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "PasswordManager.ButtonTitlePerformance.HasFormTag");
+ button_titles = InferButtonTitlesForForm(web_form);
+ }
+ form_position->second = std::move(button_titles);
+ return form_position->second;
+}
+
base::string16 FindChildTextWithIgnoreListForTesting(
const WebNode& node,
const std::set<WebNode>& divs_to_skip) {
@@ -2192,10 +2256,6 @@ bool InferLabelForElementForTesting(const WebFormControlElement& element,
return InferLabelForElement(element, stop_words, label, label_source);
}
-ButtonTitleList InferButtonTitlesForTesting(const WebElement& form_element) {
- return InferButtonTitlesForForm(form_element);
-}
-
WebFormElement FindFormByUniqueRendererId(WebDocument doc,
FormRendererId form_renderer_id) {
for (const auto& form : doc.Forms()) {
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h
index 877d8aa285b..1a33e640255 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.h
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.h
@@ -10,6 +10,7 @@
#include <set>
#include <vector>
+#include "base/containers/flat_map.h"
#include "base/i18n/rtl.h"
#include "base/macros.h"
#include "base/strings/string16.h"
@@ -45,6 +46,10 @@ class FieldDataManager;
namespace form_util {
+// Mapping from a form element's render id to results of button titles
+// heuristics for a given form element.
+using ButtonTitlesCache = base::flat_map<FormRendererId, ButtonTitleList>;
+
// A bit field mask to extract data from WebFormControlElement.
// Copied to components/autofill/ios/browser/resources/autofill_controller.js.
enum ExtractMask {
@@ -59,8 +64,18 @@ enum ExtractMask {
// WebFormControlElement.
EXTRACT_BOUNDS = 1 << 3, // Extract bounds from WebFormControlElement,
// could trigger layout if needed.
+ EXTRACT_DATALIST = 1 << 4, // Extract datalist from WebFormControlElement,
+ // the total number of options is up to
+ // kMaxListSize and each option has as far as
+ // kMaxDataLength.
};
+// Gets up to kMaxListSize data list values (with corresponding label) for the
+// given element, each value and label have as far as kMaxDataLength.
+void GetDataListSuggestions(const blink::WebInputElement& element,
+ std::vector<base::string16>* values,
+ std::vector<base::string16>* labels);
+
// Extract FormData from the form element and return whether the operation was
// successful.
bool ExtractFormData(const blink::WebFormElement& form_element,
@@ -89,7 +104,7 @@ bool AreFormContentsVisible(const blink::WebFormElement& form);
// strip unnecessary data (e.g. query params and HTTP credentials).
GURL GetCanonicalActionForForm(const blink::WebFormElement& form);
GURL GetCanonicalOriginForDocument(const blink::WebDocument& document);
-GURL GetOriginWithoutAuthForDocument(const blink::WebDocument& document);
+GURL GetDocumentUrlWithoutAuth(const blink::WebDocument& document);
// Returns true if |element| is a month input element.
bool IsMonthInput(const blink::WebInputElement* element);
@@ -123,6 +138,10 @@ bool IsWebElementVisible(const blink::WebElement& element);
// attribute.
base::string16 GetFormIdentifier(const blink::WebFormElement& form);
+// Returns the |unique_renderer_id| of a given |WebFormElement|. If
+// |WebFormElement::IsNull()|, returns a null renderer ID.
+FormRendererId GetFormRendererId(const blink::WebFormElement& form);
+
// Returns text alignment for |element|.
base::i18n::TextDirection GetTextDirectionForElement(
const blink::WebFormControlElement& element);
@@ -273,6 +292,15 @@ void PreviewSuggestion(const base::string16& suggestion,
// Whitespace is trimmed from text accumulated at descendant nodes.
base::string16 FindChildText(const blink::WebNode& node);
+// Returns the button titles for |web_form| (or unowned buttons in |document| if
+// |web_form| is null). |button_titles_cache| can be used to spare recomputation
+// if called multiple times for the same form. Button titles computation for
+// unowned buttons is enabled only in Dev and Canary (crbug.com/1086446),
+// otherwise the method returns an empty list.
+ButtonTitleList GetButtonTitles(const blink::WebFormElement& web_form,
+ const blink::WebDocument& document,
+ ButtonTitlesCache* button_titles_cache);
+
// Exposed for testing purpose
base::string16 FindChildTextWithIgnoreListForTesting(
const blink::WebNode& node,
@@ -281,8 +309,6 @@ bool InferLabelForElementForTesting(const blink::WebFormControlElement& element,
const std::vector<base::char16>& stop_words,
base::string16* label,
FormFieldData::LabelSource* label_source);
-ButtonTitleList InferButtonTitlesForTesting(
- const blink::WebElement& form_element);
// Returns form by unique renderer id. Return null element if there is no form
// with given form renderer id.
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 9693e877d2f..34575e77b47 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -4,12 +4,15 @@
#include "components/autofill/content/renderer/form_autofill_util.h"
+#include "base/metrics/field_trial.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/renderer_id.h"
#include "content/public/test/render_view_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
@@ -138,6 +141,14 @@ const char kDivTableExample6[] =
// TODO(crbug.com/796918): Should be "label" or "label-"
const char kDivTableExample6Expected[] = "";
+void VerifyButtonTitleCache(const WebFormElement& form_target,
+ const ButtonTitleList& expected_button_titles,
+ const ButtonTitlesCache& actual_cache) {
+ EXPECT_THAT(actual_cache,
+ testing::ElementsAre(testing::Pair(GetFormRendererId(form_target),
+ expected_button_titles)));
+}
+
class FormAutofillUtilsTest : public content::RenderViewTest {
public:
FormAutofillUtilsTest() {}
@@ -272,8 +283,8 @@ TEST_F(FormAutofillUtilsTest, InferLabelSourceTest) {
}
}
-TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest) {
- const char kHtml[] =
+TEST_F(FormAutofillUtilsTest, GetButtonTitles) {
+ constexpr char kHtml[] =
"<form id='target'>"
" <input type='button' value='Clear field'>"
" <input type='button' value='Clear field'>"
@@ -294,8 +305,11 @@ TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest) {
ASSERT_FALSE(target.IsNull());
const WebFormElement& form_target = target.ToConst<WebFormElement>();
ASSERT_FALSE(form_target.IsNull());
+ ButtonTitlesCache cache;
+
+ autofill::ButtonTitleList actual =
+ GetButtonTitles(form_target, web_frame->GetDocument(), &cache);
- autofill::ButtonTitleList actual = InferButtonTitlesForTesting(form_target);
autofill::ButtonTitleList expected = {
{base::UTF8ToUTF16("Clear field"),
ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE},
@@ -309,9 +323,11 @@ TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest) {
{base::UTF8ToUTF16("Join"), ButtonTitleType::DIV},
{base::UTF8ToUTF16("Start"), ButtonTitleType::SPAN}};
EXPECT_EQ(expected, actual);
+
+ VerifyButtonTitleCache(form_target, expected, cache);
}
-TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest_TooLongTitle) {
+TEST_F(FormAutofillUtilsTest, GetButtonTitles_TooLongTitle) {
std::string title;
for (int i = 0; i < 300; ++i)
title += "a";
@@ -330,8 +346,10 @@ TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest_TooLongTitle) {
ASSERT_FALSE(target.IsNull());
const WebFormElement& form_target = target.ToConst<WebFormElement>();
ASSERT_FALSE(form_target.IsNull());
+ ButtonTitlesCache cache;
- autofill::ButtonTitleList actual = InferButtonTitlesForTesting(form_target);
+ autofill::ButtonTitleList actual =
+ GetButtonTitles(form_target, web_frame->GetDocument(), &cache);
int total_length = 0;
for (auto title : actual) {
@@ -341,8 +359,14 @@ TEST_F(FormAutofillUtilsTest, InferButtonTitleForFormTest_TooLongTitle) {
EXPECT_EQ(200, total_length);
}
-TEST_F(FormAutofillUtilsTest, InferButtonTitle_Formless) {
- const char kNoFormHtml[] =
+TEST_F(FormAutofillUtilsTest, GetButtonTitles_Formless) {
+ // Button titles computation and crowdsourcing for <form>less forms are
+ // enabled only if |AutofillFieldMetadata| (Dev and Canary) is enabled.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.Init();
+ base::FieldTrialList::CreateFieldTrial("AutofillFieldMetadata", "Enabled");
+
+ constexpr char kNoFormHtml[] =
"<div class='reg-form'>"
" <input type='button' value='\n Show\t password '>"
" <button>Sign Up</button>"
@@ -358,10 +382,12 @@ TEST_F(FormAutofillUtilsTest, InferButtonTitle_Formless) {
LoadHTML(kNoFormHtml);
WebLocalFrame* web_frame = GetMainFrame();
ASSERT_NE(nullptr, web_frame);
- const WebElement& body = web_frame->GetDocument().Body();
- ASSERT_FALSE(body.IsNull());
+ WebFormElement form_target;
+ ASSERT_FALSE(web_frame->GetDocument().Body().IsNull());
+ ButtonTitlesCache cache;
- autofill::ButtonTitleList actual = InferButtonTitlesForTesting(body);
+ autofill::ButtonTitleList actual =
+ GetButtonTitles(form_target, web_frame->GetDocument(), &cache);
autofill::ButtonTitleList expected = {
{base::UTF8ToUTF16("Show password"),
ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE},
@@ -370,6 +396,42 @@ TEST_F(FormAutofillUtilsTest, InferButtonTitle_Formless) {
{base::UTF8ToUTF16("Register"),
ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE}};
EXPECT_EQ(expected, actual);
+
+ VerifyButtonTitleCache(form_target, expected, cache);
+}
+
+TEST_F(FormAutofillUtilsTest, GetButtonTitles_Formless_DisabledByDefault) {
+ // Button titles computation and crowdsourcing for <form>less forms should be
+ // disabled if |AutofillFieldMetadata| is disabled.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.Init();
+ base::FieldTrialList::CreateFieldTrial("AutofillFieldMetadata", "Disabled");
+
+ constexpr char kNoFormHtml[] =
+ "<div class='reg-form'>"
+ " <input type='button' value='\n Show\t password '>"
+ " <button>Sign Up</button>"
+ " <button type='button'>Register</button>"
+ "</div>"
+ "<form id='ignored-form'>"
+ " <input type='button' value='Ignore this'>"
+ " <button>Ignore this</button>"
+ " <a id='Submit' value='Ignore this'>"
+ " <div name='BTN'>Ignore this</div>"
+ "</form>";
+
+ LoadHTML(kNoFormHtml);
+ WebLocalFrame* web_frame = GetMainFrame();
+ ASSERT_NE(nullptr, web_frame);
+ WebFormElement form_target;
+ ASSERT_FALSE(web_frame->GetDocument().Body().IsNull());
+ ButtonTitlesCache cache;
+
+ autofill::ButtonTitleList actual =
+ GetButtonTitles(form_target, web_frame->GetDocument(), &cache);
+
+ EXPECT_TRUE(actual.empty());
+ EXPECT_TRUE(cache.empty());
}
TEST_F(FormAutofillUtilsTest, IsEnabled) {
@@ -788,6 +850,84 @@ TEST_F(FormAutofillUtilsTest, ExtractUnownedBounds) {
EXPECT_FALSE(form_data.fields.back().bounds.IsEmpty());
}
+TEST_F(FormAutofillUtilsTest, GetDataListSuggestions) {
+ LoadHTML(
+ "<body><input list='datalist_id' name='count' id='i1'><datalist "
+ "id='datalist_id'><option value='1'><option "
+ "value='2'></datalist></body>");
+ WebDocument doc = GetMainFrame()->GetDocument();
+ auto web_control = doc.GetElementById("i1").To<WebInputElement>();
+ std::vector<base::string16> values;
+ std::vector<base::string16> labels;
+ GetDataListSuggestions(web_control, &values, &labels);
+ ASSERT_EQ(values.size(), 2u);
+ ASSERT_EQ(labels.size(), 2u);
+ EXPECT_EQ(values[0], base::UTF8ToUTF16("1"));
+ EXPECT_EQ(values[1], base::UTF8ToUTF16("2"));
+ EXPECT_EQ(labels[0], base::UTF8ToUTF16(""));
+ EXPECT_EQ(labels[1], base::UTF8ToUTF16(""));
+}
+
+TEST_F(FormAutofillUtilsTest, GetDataListSuggestionsWithLabels) {
+ LoadHTML(
+ "<body><input list='datalist_id' name='count' id='i1'><datalist "
+ "id='datalist_id'><option value='1'>one</option><option "
+ "value='2'>two</option></datalist></body>");
+ WebDocument doc = GetMainFrame()->GetDocument();
+ auto web_control = doc.GetElementById("i1").To<WebInputElement>();
+ std::vector<base::string16> values;
+ std::vector<base::string16> labels;
+ GetDataListSuggestions(web_control, &values, &labels);
+ ASSERT_EQ(values.size(), 2u);
+ ASSERT_EQ(labels.size(), 2u);
+ EXPECT_EQ(values[0], base::UTF8ToUTF16("1"));
+ EXPECT_EQ(values[1], base::UTF8ToUTF16("2"));
+ EXPECT_EQ(labels[0], base::UTF8ToUTF16("one"));
+ EXPECT_EQ(labels[1], base::UTF8ToUTF16("two"));
+}
+
+TEST_F(FormAutofillUtilsTest, ExtractDataList) {
+ LoadHTML(
+ "<body><input list='datalist_id' name='count' id='i1'><datalist "
+ "id='datalist_id'><option value='1'>one</option><option "
+ "value='2'>two</option></datalist></body>");
+ WebDocument doc = GetMainFrame()->GetDocument();
+ auto web_control = doc.GetElementById("i1").To<WebInputElement>();
+ FormData form_data;
+ FormFieldData form_field_data;
+ ASSERT_TRUE(FindFormAndFieldForFormControlElement(
+ web_control, nullptr /*field_data_manager*/, EXTRACT_DATALIST, &form_data,
+ &form_field_data));
+
+ auto& values = form_data.fields.back().datalist_values;
+ auto& labels = form_data.fields.back().datalist_labels;
+ ASSERT_EQ(values.size(), 2u);
+ ASSERT_EQ(labels.size(), 2u);
+ EXPECT_EQ(values[0], base::UTF8ToUTF16("1"));
+ EXPECT_EQ(values[1], base::UTF8ToUTF16("2"));
+ EXPECT_EQ(labels[0], base::UTF8ToUTF16("one"));
+ EXPECT_EQ(labels[1], base::UTF8ToUTF16("two"));
+ EXPECT_EQ(form_field_data.datalist_values, values);
+ EXPECT_EQ(form_field_data.datalist_labels, labels);
+}
+
+TEST_F(FormAutofillUtilsTest, NotExtractDataList) {
+ LoadHTML(
+ "<body><input list='datalist_id' name='count' id='i1'><datalist "
+ "id='datalist_id'><option value='1'>one</option><option "
+ "value='2'>two</option></datalist></body>");
+ WebDocument doc = GetMainFrame()->GetDocument();
+ auto web_control = doc.GetElementById("i1").To<WebInputElement>();
+ FormData form_data;
+ FormFieldData form_field_data;
+ ASSERT_TRUE(FindFormAndFieldForFormControlElement(
+ web_control, nullptr /*field_data_manager*/, &form_data,
+ &form_field_data));
+
+ EXPECT_TRUE(form_data.fields.back().datalist_values.empty());
+ EXPECT_TRUE(form_data.fields.back().datalist_labels.empty());
+}
+
} // namespace
} // namespace form_util
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index 1bde0197a15..fe638091f41 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -18,6 +18,7 @@
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/strings/string_number_conversions.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/page_form_analyser_logger.h"
#include "components/autofill/core/common/autofill_constants.h"
@@ -420,37 +421,19 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
std::vector<WebFormControlElement> control_elements;
- // First check the synthetic form.
- bool found_synthetic_form = false;
- if (form.data.SameFormAs(synthetic_form_)) {
- found_synthetic_form = true;
+ if (form.data.unique_renderer_id.is_null()) { // Form is synthetic.
WebDocument document = frame_->GetDocument();
control_elements = form_util::GetUnownedAutofillableFormFieldElements(
document.All(), nullptr);
- }
-
- if (!found_synthetic_form) {
- // Find the real form by searching through the WebDocuments.
- bool found_form = false;
-
+ } else {
for (const WebFormElement& form_element : frame_->GetDocument().Forms()) {
- // To match two forms, we look for the form's name and the number of
- // fields on that form. (Form names may not be unique.)
- // Note: WebString() == WebString(string16()) does not evaluate to |true|
- // -- WebKit distinguishes between a "null" string (lhs) and an "empty"
- // string (rhs). We don't want that distinction, so forcing to string16.
- base::string16 element_name = form_util::GetFormIdentifier(form_element);
- if (element_name == form.data.name) {
- found_form = true;
+ FormRendererId form_id(form_element.UniqueRendererFormId());
+ if (form_id == form.data.unique_renderer_id) {
control_elements =
form_util::ExtractAutofillableElementsInForm(form_element);
- if (control_elements.size() == form.fields.size())
- break;
+ break;
}
}
-
- if (!found_form)
- return false;
}
if (control_elements.size() != form.fields.size()) {
@@ -464,11 +447,9 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
WebFormControlElement& element = control_elements[i];
const FormFieldData& field_data = form.data.fields[i];
- if (element.NameForAutofill().Utf16() != field_data.name) {
- // Keep things simple. Don't show predictions for elements whose names
- // were modified between page load and the server's response to our query.
+ FieldRendererId field_id(element.UniqueRendererFormControlId());
+ if (field_id != field_data.unique_renderer_id)
continue;
- }
const FormFieldDataPredictions& field = form.fields[i];
// Possibly add a console warning for this field regarding the usage of
@@ -492,6 +473,11 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
const base::string16 truncated_label = field_data.label.substr(
0, std::min(field_data.label.length(), kMaxLabelSize));
+ std::string form_id =
+ base::NumberToString(form.data.unique_renderer_id.value());
+ std::string field_id =
+ base::NumberToString(field.field.unique_renderer_id.value());
+
std::string title =
base::StrCat({"overall type: ", field.overall_type, //
"\nserver type: ", field.server_type, //
@@ -500,7 +486,9 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
"\nparseable name: ", field.parseable_name, //
"\nsection: ", field.section, //
"\nfield signature: ", field.signature, //
- "\nform signature: ", form.signature});
+ "\nform signature: ", form.signature, //
+ "\nform renderer id: ", form_id, //
+ "\nfield renderer id: ", field_id});
// Set this debug string to the title so that a developer can easily debug
// by hovering the mouse over the input field.
diff --git a/chromium/components/autofill/content/renderer/form_tracker.cc b/chromium/components/autofill/content/renderer/form_tracker.cc
index e077f40a8b7..8613e8d3938 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.cc
+++ b/chromium/components/autofill/content/renderer/form_tracker.cc
@@ -126,14 +126,13 @@ void FormTracker::FormControlDidChangeImpl(
}
}
-void FormTracker::DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) {
+void FormTracker::DidCommitProvisionalLoad(ui::PageTransition transition) {
DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
- if (!is_same_document_navigation) {
- ResetLastInteractedElements();
- return;
- }
+ ResetLastInteractedElements();
+}
+void FormTracker::DidFinishSameDocumentNavigation() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
FireSubmissionIfFormDisappear(SubmissionSource::SAME_DOCUMENT_NAVIGATION);
}
diff --git a/chromium/components/autofill/content/renderer/form_tracker.h b/chromium/components/autofill/content/renderer/form_tracker.h
index ed4e403ff26..1ac3a8a1272 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.h
+++ b/chromium/components/autofill/content/renderer/form_tracker.h
@@ -87,8 +87,8 @@ class FormTracker : public content::RenderFrameObserver {
FormSubmittedBySameDocumentNavigation);
// content::RenderFrameObserver:
- void DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) override;
+ void DidCommitProvisionalLoad(ui::PageTransition transition) override;
+ void DidFinishSameDocumentNavigation() override;
void DidStartNavigation(
const GURL& url,
base::Optional<blink::WebNavigationType> navigation_type) override;
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.cc b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
index 9929ea02fd1..1006ccd24ab 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.cc
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
@@ -284,13 +284,6 @@ void FindUsernameFieldInternal(
}
}
-// Returns the |unique_renderer_id| of a given |WebFormElement|. If
-// |WebFormElement::IsNull()| return a null renderer ID.
-FormRendererId GetFormRendererId(WebFormElement form) {
- return form.IsNull() ? FormRendererId()
- : FormRendererId(form.UniqueRendererFormId());
-}
-
} // namespace
const std::vector<FieldRendererId>& GetPredictionsFieldBasedOnHtmlAttributes(
@@ -311,8 +304,8 @@ const std::vector<FieldRendererId>& GetPredictionsFieldBasedOnHtmlAttributes(
bool cache_miss = true;
// Iterator pointing to the entry for |form| if the entry for |form| is found.
UsernameDetectorCache::iterator form_position;
- std::tie(form_position, cache_miss) = username_detector_cache->insert(
- std::make_pair(GetFormRendererId(form), std::vector<FieldRendererId>()));
+ std::tie(form_position, cache_miss) = username_detector_cache->emplace(
+ form_util::GetFormRendererId(form), std::vector<FieldRendererId>());
if (cache_miss) {
std::vector<FieldRendererId> username_predictions;
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc b/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
new file mode 100644
index 00000000000..d39bca5d8cd
--- /dev/null
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
@@ -0,0 +1,345 @@
+// 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 "base/strings/stringprintf.h"
+#include "components/autofill/content/renderer/form_autofill_util.h"
+#include "components/autofill/content/renderer/html_based_username_detector.h"
+#include "content/public/test/render_view_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+
+using blink::WebElement;
+using blink::WebFormControlElement;
+using blink::WebFormElement;
+using blink::WebLocalFrame;
+using blink::WebString;
+
+namespace autofill {
+
+namespace {
+
+struct TextField {
+ const char* name;
+ const char* id;
+ const char* value;
+ const char* label;
+};
+
+constexpr char kTestForm[] = R"(
+ <FORM name="Test" id="userform">
+ <label for="%s">%s</label>
+ <input type="text" name="%s" id="%s" value="%s" />
+
+ <label for="%s">%s</label>
+ <input type="text" name="%s" id="%s" value="%s" />
+
+ <input type="password" id="password" value="v" />
+ <input type="submit" value="submit" />
+ </FORM>
+)";
+
+std::string GetFormHTML(const TextField& first_field,
+ const TextField& second_field) {
+ return base::StringPrintf(
+ kTestForm, first_field.id, first_field.label, first_field.name,
+ first_field.id, first_field.value, second_field.id, second_field.label,
+ second_field.name, second_field.id, second_field.value);
+}
+
+class HtmlBasedUsernameDetectorTest : public content::RenderViewTest {
+ protected:
+ struct TestCase {
+ const TextField first_text_field_parameter;
+ const TextField second_text_field_parameter;
+ const WebString expected_username_id;
+ };
+
+ FormData LoadFormDataFromHtml(const std::string& html) {
+ LoadHTML(html.data());
+ const WebFormElement& form = GetFormElement();
+ return GetFormDataFromForm(form);
+ }
+
+ FormData GetFormDataFromForm(const WebFormElement& form) {
+ FormData form_data;
+ EXPECT_TRUE(form_util::WebFormElementToFormData(
+ form, WebFormControlElement(), nullptr, form_util::EXTRACT_NONE,
+ &form_data, nullptr));
+
+ return form_data;
+ }
+
+ FieldRendererId GetRendererIdFromWebElementId(const WebString& id) {
+ const WebLocalFrame* frame = GetMainFrame();
+ const WebElement& element = frame->GetDocument().GetElementById(id);
+ EXPECT_FALSE(element.IsNull());
+ return FieldRendererId(element.ToConst<blink::WebInputElement>()
+ .UniqueRendererFormControlId());
+ }
+
+ WebFormElement GetFormElement() {
+ const WebLocalFrame* frame = GetMainFrame();
+ const blink::WebVector<WebFormElement>& forms =
+ frame->GetDocument().Forms();
+ EXPECT_EQ(1U, forms.size());
+ EXPECT_FALSE(forms[0].IsNull());
+
+ return forms[0];
+ }
+
+ std::vector<WebFormControlElement> GetFormControlElements() {
+ const WebFormElement& form = GetFormElement();
+ blink::WebVector<WebFormControlElement> control_elements =
+ form.GetFormControlElements();
+ return control_elements.ReleaseVector();
+ }
+
+ void PredictAndCheckUsernameId(const std::string& html,
+ const WebString& expected_username_id) {
+ const FormData& form_data = LoadFormDataFromHtml(html);
+ const std::vector<WebFormControlElement>& control_elements =
+ GetFormControlElements();
+
+ // Get the expected renderer id from the expected username id.
+ const FieldRendererId expected_renderer_id =
+ GetRendererIdFromWebElementId(expected_username_id);
+
+ // Run predictions and test the result.
+ UsernameDetectorCache cache;
+ const std::vector<FieldRendererId>& renderer_ids =
+ GetPredictionsFieldBasedOnHtmlAttributes(control_elements, form_data,
+ &cache);
+
+ ASSERT_EQ(1u, cache.size());
+ ASSERT_FALSE(cache.begin()->second.empty());
+ EXPECT_EQ(expected_renderer_id, cache.begin()->second[0]);
+ ASSERT_FALSE(renderer_ids.empty());
+ EXPECT_EQ(expected_renderer_id, renderer_ids[0]);
+ }
+};
+
+} // namespace
+
+TEST_F(HtmlBasedUsernameDetectorTest, DeveloperGroupAttributes) {
+ // Each test case consists of a set of parameters to be plugged into
+ // the TestCase struct, plus the corresponding expectations. The test data
+ // contains cases that are identified by HTML detector, and not by
+ // base heuristic. Thus, username field does not necessarely have to
+ // be right before password field. These tests basically check
+ // searching in developer group (i.e. name and id attribute,
+ // concatenated, with "$" guard in between).
+ const TestCase test_cases[] = {
+ // There are both field name and id.
+ {{"username", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "x1d"},
+ // there is no field id.
+ {{"username", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "x1d"},
+ // Upper or mixed case shouldn't matter.
+ {{"uSeRnAmE", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "x1d"},
+ // Check removal of special characters.
+ {{"u1_s2-e3~r4/n5(a)6m#e", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "x1d"},
+ // Check guard between field name and field id.
+ {{"us", "ername", "johnsmith"}, {"email", "id", "js@google.com"}, "id"},
+ // Check removal of fields with latin negative words in developer group.
+ {{"email", "x", "js@google.com"},
+ {"fake_username", "y", "johnsmith"},
+ "x"},
+ {{"email", "mail", "js@google.com"},
+ {"user_name", "fullname", "johnsmith"},
+ "mail"},
+ // Identify latin translations of "username".
+ {{"benutzername", "x", "johnsmith"},
+ {"email", "y", "js@google.com"},
+ "x"},
+ // Identify latin translations of "user".
+ {{"utilizator", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "x1d"},
+ // Identify technical words.
+ {{"loginid", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "x1d"},
+ // Identify weak words.
+ {{"usrname", "x1d", "johnsmith"},
+ {"email", "y1d", "js@google.com"},
+ "y1d"},
+ // If a word matches in maximum 2 fields, it is accepted.
+ // First encounter is selected as username.
+ {{"username", "x1d", "johnsmith"},
+ {"repeat_username", "y1d", "johnsmith"},
+ "x1d"},
+ // A short word should be enclosed between delimiters. Otherwise, an
+ // Occurrence doesn't count.
+ {{"identity_name", "idn", "johnsmith"}, {"id", "xid", "123"}, "xid"}};
+
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Iteration " << i);
+
+ const std::string& form_html =
+ GetFormHTML(test_cases[i].first_text_field_parameter,
+ test_cases[i].second_text_field_parameter);
+
+ PredictAndCheckUsernameId(form_html, test_cases[i].expected_username_id);
+ }
+}
+
+TEST_F(HtmlBasedUsernameDetectorTest, UserGroupAttributes) {
+ // Each test case consists of a set of parameters to be plugged into
+ // the TestCase struct, plus the corresponding expectations. The test data
+ // contains cases that are identified by HTML detector, and not by
+ // base heuristic. Thus, username field does not necessarely have to
+ // be right before password field. These tests basically check
+ // searching in user group
+ const TestCase test_cases[] = {
+ // Label information will decide username.
+ {{"name1", "id1", "johnsmith", "Username:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id1"},
+ // Placeholder information will decide username.
+ {{"name1", "id1", "js@google.com", "Email:"},
+ {"name2", "id2", "johnsmith", "Username:"},
+ "id2"},
+ // Check removal of special characters.
+ {{"name1", "id1", "johnsmith", "U s er n a m e:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id1"},
+ // Check removal of fields with latin negative words in user group.
+ {{"name1", "id1", "johnsmith", "Username password:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id2"},
+ // Check removal of fields with non-latin negative words in user group.
+ {{"name1", "id1", "js@google.com", "Email:"},
+ {"name2", "id2", "johnsmith", "የይለፍቃልየይለፍቃል:"},
+ "id1"},
+ // Identify latin translations of "username".
+ {{"name1", "id1", "johnsmith", "Username:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id1"},
+ // Identify non-latin translations of "username".
+ {{"name1", "id1", "johnsmith", "用户名:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id1"},
+ // Identify latin translations of "user".
+ {{"name1", "id1", "johnsmith", "Wosuta:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id1"},
+ // Identify non-latin translations of "user".
+ {{"name1", "id1", "johnsmith", "истифода:"},
+ {"name2", "id2", "js@google.com", "Email:"},
+ "id1"},
+ // Identify weak words.
+ {{"name1", "id1", "johnsmith", "Insert your login details:"},
+ {"name2", "id2", "js@google.com", "Insert your email:"},
+ "id1"},
+ // Check user group priority, compared to developer group.
+ // User group should have higher priority than developer group.
+ {{"email", "id1", "js@google.com", "Username:"},
+ {"username", "id2", "johnsmith", "Email:"},
+ "id1"},
+ // Check treatment for short dictionary words. "uid" has higher priority,
+ // but its occurrence is ignored because it is a part of another word.
+ {
+ {"name1", "noword", "johnsmith", "Insert your id:"},
+ {"name2", "uidentical", "js@google.com", "Insert something:"},
+ "noword",
+ }};
+
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Iteration " << i);
+
+ const std::string& form_html =
+ GetFormHTML(test_cases[i].first_text_field_parameter,
+ test_cases[i].second_text_field_parameter);
+
+ PredictAndCheckUsernameId(form_html, test_cases[i].expected_username_id);
+ }
+}
+
+TEST_F(HtmlBasedUsernameDetectorTest, SeveralDetections) {
+ // If word matches in more than 2 fields, we don't match on it.
+ // We search for match with another word.
+ const std::string& test_form = R"(
+ <form>
+ <input type="text" name="address" id="xuser" value="addr" />
+ <input type="text" name="loginid" id="yuser" value="johnsmith" />
+ <input type="text" name="tel" id="zuser" value="sometel" />
+ <input type="password" id="password" value="v" />
+ <input type="submit" value="submit" />
+ </form>
+ )";
+ PredictAndCheckUsernameId(test_form, "yuser");
+}
+
+TEST_F(HtmlBasedUsernameDetectorTest, HTMLDetectorCache) {
+ const TextField text_fields[] = {
+ {"unknown", "12345"},
+ {"something", "smith"},
+ };
+
+ const std::string& form_html = GetFormHTML(text_fields[0], text_fields[1]);
+
+ FormData form_data = LoadFormDataFromHtml(form_html);
+ std::vector<WebFormControlElement> control_elements =
+ GetFormControlElements();
+
+ UsernameDetectorCache cache;
+ std::vector<FieldRendererId> field_ids =
+ GetPredictionsFieldBasedOnHtmlAttributes(control_elements, form_data,
+ &cache);
+
+ // No signals from HTML attributes. The classifier found nothing and cached
+ // it.
+ ASSERT_EQ(1u, cache.size());
+ EXPECT_TRUE(field_ids.empty());
+ const WebFormElement& form = GetFormElement();
+ EXPECT_EQ(FormRendererId(form.UniqueRendererFormId()), cache.begin()->first);
+ EXPECT_TRUE(cache.begin()->second.empty());
+
+ // Changing attributes would change the classifier's output. But the output
+ // will be the same because it was cached in |username_detector_cache|.
+ control_elements[0].SetAttribute("name", "id");
+ form_data = GetFormDataFromForm(GetFormElement());
+ field_ids = GetPredictionsFieldBasedOnHtmlAttributes(control_elements,
+ form_data, &cache);
+ ASSERT_EQ(1u, cache.size());
+ EXPECT_TRUE(field_ids.empty());
+ EXPECT_EQ(FormRendererId(form.UniqueRendererFormId()), cache.begin()->first);
+ EXPECT_TRUE(cache.begin()->second.empty());
+
+ // Clear the cache. The classifier will find username field and cache it.
+ cache.clear();
+ ASSERT_EQ(4u, control_elements.size());
+ field_ids = GetPredictionsFieldBasedOnHtmlAttributes(control_elements,
+ form_data, &cache);
+ ASSERT_EQ(1u, cache.size());
+ EXPECT_EQ(1u, field_ids.size());
+ EXPECT_EQ(FormRendererId(form.UniqueRendererFormId()), cache.begin()->first);
+ ASSERT_EQ(1u, cache.begin()->second.size());
+ EXPECT_EQ(FieldRendererId(control_elements[0].UniqueRendererFormControlId()),
+ cache.begin()->second[0]);
+
+ // Change the attributes again ("username" is stronger signal than "id"),
+ // but keep the cache. The classifier's output should be the same.
+ control_elements[1].SetAttribute("name", "username");
+ form_data = GetFormDataFromForm(GetFormElement());
+ field_ids = GetPredictionsFieldBasedOnHtmlAttributes(control_elements,
+ form_data, &cache);
+
+ ASSERT_EQ(1u, cache.size());
+ EXPECT_EQ(1u, field_ids.size());
+ EXPECT_EQ(FormRendererId(form.UniqueRendererFormId()), cache.begin()->first);
+ ASSERT_EQ(1u, cache.begin()->second.size());
+ EXPECT_EQ(FieldRendererId(control_elements[0].UniqueRendererFormControlId()),
+ cache.begin()->second[0]);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index d85705681a9..4d283f72a0f 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -24,7 +24,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
#include "components/autofill/content/renderer/prefilled_values_detector.h"
@@ -36,7 +35,6 @@
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/signatures.h"
-#include "components/password_manager/core/common/password_manager_features.h"
#include "components/safe_browsing/buildflags.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/render_frame.h"
@@ -257,9 +255,9 @@ WebString GetFormSignatureAsWebString(const FormData& form_data) {
// Annotate |fields| with field signatures and form signature as HTML
// attributes.
void AnnotateFieldsWithSignatures(
- std::vector<blink::WebFormControlElement>* fields,
+ std::vector<blink::WebFormControlElement>& fields,
const blink::WebString& form_signature) {
- for (blink::WebFormControlElement& control_element : *fields) {
+ for (blink::WebFormControlElement& control_element : fields) {
FieldSignature field_signature = CalculateFieldSignatureByNameAndType(
control_element.NameForAutofill().Utf16(),
control_element.FormControlTypeForAutofill().Utf8());
@@ -272,37 +270,6 @@ void AnnotateFieldsWithSignatures(
}
}
-// Annotate |forms| and all fields in the |frame| with form and field signatures
-// as HTML attributes.
-void AnnotateFormsAndFieldsWithSignatures(WebLocalFrame* frame,
- WebVector<WebFormElement>* forms) {
- for (WebFormElement& form : *forms) {
- std::unique_ptr<FormData> form_data(
- CreateFormDataFromWebForm(form, /*field_data_manager=*/nullptr,
- /*username_detector_cache=*/nullptr));
- WebString form_signature;
- if (form_data) {
- form_signature = GetFormSignatureAsWebString(*form_data);
- form.SetAttribute(WebString::FromASCII(kDebugAttributeForFormSignature),
- form_signature);
- }
- std::vector<WebFormControlElement> form_fields =
- form_util::ExtractAutofillableElementsInForm(form);
- AnnotateFieldsWithSignatures(&form_fields, form_signature);
- }
-
- std::vector<WebFormControlElement> unowned_elements =
- form_util::GetUnownedAutofillableFormFieldElements(
- frame->GetDocument().All(), nullptr);
- std::unique_ptr<FormData> form_data(CreateFormDataFromUnownedInputElements(
- *frame, /*field_data_manager=*/nullptr,
- /*username_detector_cache=*/nullptr));
- WebString form_signature;
- if (form_data)
- form_signature = GetFormSignatureAsWebString(*form_data);
- AnnotateFieldsWithSignatures(&unowned_elements, form_signature);
-}
-
// Returns true iff there is a password field in |frame|.
bool HasPasswordField(const WebLocalFrame& frame) {
static base::NoDestructor<WebString> kPassword("password");
@@ -416,14 +383,6 @@ bool HasDocumentWithValidFrame(const WebInputElement& element) {
return frame && frame->View();
}
-bool ShowPopupWithoutPasswords(const WebInputElement& password_element) {
- if (!base::FeatureList::IsEnabled(
- password_manager::features::kEnablePasswordsAccountStorage)) {
- return false;
- }
- return !password_element.IsNull() && IsElementEditable(password_element);
-}
-
// This method tries to fix `fields` with empty typed or filled properties by
// matching them against previously filled or typed in fields with the same
// value and copying their filled or typed mask.
@@ -905,9 +864,10 @@ bool PasswordAutofillAgent::ShowSuggestions(
FindPasswordInfoForElement(element, UseFallbackData(true), &username_element,
&password_element, &password_info);
- if (!password_info && !ShowPopupWithoutPasswords(password_element)) {
+ if (!password_info) {
MaybeCheckSafeBrowsingReputation(element);
- return false;
+ if (!CanShowPopupWithoutPasswords(password_element))
+ return false;
}
// Check that all fillable elements are editable.
@@ -1015,6 +975,31 @@ void PasswordAutofillAgent::UserGestureObserved() {
gatekeeper_.OnUserGesture();
}
+void PasswordAutofillAgent::AnnotateFormsAndFieldsWithSignatures(
+ WebVector<WebFormElement>& forms) {
+ for (WebFormElement& form : forms) {
+ std::unique_ptr<FormData> form_data = GetFormDataFromWebForm(form);
+ WebString form_signature;
+ if (form_data) {
+ form_signature = GetFormSignatureAsWebString(*form_data);
+ form.SetAttribute(WebString::FromASCII(kDebugAttributeForFormSignature),
+ form_signature);
+ }
+ std::vector<WebFormControlElement> form_fields =
+ form_util::ExtractAutofillableElementsInForm(form);
+ AnnotateFieldsWithSignatures(form_fields, form_signature);
+ }
+
+ std::vector<WebFormControlElement> unowned_elements =
+ form_util::GetUnownedAutofillableFormFieldElements(
+ render_frame()->GetWebFrame()->GetDocument().All(), nullptr);
+ std::unique_ptr<FormData> form_data = GetFormDataFromUnownedInputElements();
+ WebString form_signature;
+ if (form_data)
+ form_signature = GetFormSignatureAsWebString(*form_data);
+ AnnotateFieldsWithSignatures(unowned_elements, form_signature);
+}
+
void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (logging_state_active_) {
@@ -1046,7 +1031,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
WebVector<WebFormElement> forms = frame->GetDocument().Forms();
if (IsShowAutofillSignaturesEnabled())
- AnnotateFormsAndFieldsWithSignatures(frame, &forms);
+ AnnotateFormsAndFieldsWithSignatures(forms);
if (logger)
logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size());
@@ -1131,7 +1116,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
password_forms_data.back().url =
form_util::GetCanonicalOriginForDocument(frame->GetDocument());
password_forms_data.back().full_url =
- form_util::GetOriginWithoutAuthForDocument(frame->GetDocument());
+ form_util::GetDocumentUrlWithoutAuth(frame->GetDocument());
}
if (!password_forms_data.empty()) {
sent_request_to_store_ = true;
@@ -1161,12 +1146,9 @@ void PasswordAutofillAgent::DidFinishLoad() {
}
void PasswordAutofillAgent::DidCommitProvisionalLoad(
- bool is_same_document_navigation,
ui::PageTransition transition) {
- if (!is_same_document_navigation) {
- checked_safe_browsing_reputation_ = false;
- recorded_first_filling_result_ = false;
- }
+ checked_safe_browsing_reputation_ = false;
+ recorded_first_filling_result_ = false;
}
void PasswordAutofillAgent::OnFrameDetached() {
@@ -1312,7 +1294,10 @@ void PasswordAutofillAgent::AnnotateFieldsWithParsingResult(
"confirmation_password_element");
}
-void PasswordAutofillAgent::InformNoSavedCredentials() {
+void PasswordAutofillAgent::InformNoSavedCredentials(
+ bool should_show_popup_without_passwords) {
+ should_show_popup_without_passwords_ = should_show_popup_without_passwords;
+
autofilled_elements_cache_.clear();
// Clear the actual field values.
@@ -1382,7 +1367,8 @@ void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
std::unique_ptr<FormData> PasswordAutofillAgent::GetFormDataFromWebForm(
const WebFormElement& web_form) {
return CreateFormDataFromWebForm(web_form, field_data_manager_.get(),
- &username_detector_cache_);
+ &username_detector_cache_,
+ &button_titles_cache_);
}
std::unique_ptr<FormData>
@@ -1398,7 +1384,8 @@ PasswordAutofillAgent::GetFormDataFromUnownedInputElements() {
if (!web_frame)
return nullptr;
return CreateFormDataFromUnownedInputElements(
- *web_frame, field_data_manager_.get(), &username_detector_cache_);
+ *web_frame, field_data_manager_.get(), &username_detector_cache_,
+ &button_titles_cache_);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1430,6 +1417,7 @@ void PasswordAutofillAgent::CleanupOnDocumentShutdown() {
web_input_to_password_info_.clear();
password_to_username_.clear();
last_supplied_password_info_iter_ = web_input_to_password_info_.end();
+ should_show_popup_without_passwords_ = false;
browser_has_form_to_process_ = false;
field_data_manager_.get()->ClearData();
username_autofill_state_ = WebAutofillState::kNotFilled;
@@ -1535,7 +1523,7 @@ bool PasswordAutofillAgent::FillUserNameAndPassword(
// This is a heuristic guess. If the credential is stored for
// www.example.com, the username may be prefilled with "@example.com".
std::string possible_email_domain =
- GetRegistryControlledDomain(fill_data.origin);
+ GetRegistryControlledDomain(fill_data.url);
prefilled_placeholder_username =
!username_element.Value().IsEmpty() &&
@@ -1886,4 +1874,10 @@ void PasswordAutofillAgent::SetLastUpdatedFormAndField(
: FieldRendererId(input.UniqueRendererFormControlId());
}
+bool PasswordAutofillAgent::CanShowPopupWithoutPasswords(
+ const WebInputElement& password_element) const {
+ return should_show_popup_without_passwords_ && !password_element.IsNull() &&
+ IsElementEditable(password_element);
+}
+
} // 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 011425f9186..4852ec2a3b8 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -20,6 +20,7 @@
#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/autofill_agent.h"
#include "components/autofill/content/renderer/field_data_manager.h"
+#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/form_tracker.h"
#include "components/autofill/content/renderer/html_based_username_detector.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
@@ -99,10 +100,6 @@ enum class FillingResult {
kMaxValue = kNoFillableElementsFound,
};
-// Names of HTML attributes to show form and field signatures for debugging.
-extern const char kDebugAttributeForFormSignature[];
-extern const char kDebugAttributeForFieldSignature[];
-
class FieldDataManager;
class RendererSavePasswordProgressLogger;
class PasswordGenerationAgent;
@@ -133,7 +130,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// mojom::PasswordAutofillAgent:
void FillPasswordForm(const PasswordFormFillData& form_data) override;
- void InformNoSavedCredentials() override;
+ void InformNoSavedCredentials(
+ bool should_show_popup_without_passwords) override;
void FillIntoFocusedField(bool is_password,
const base::string16& credential) override;
void SetLoggingState(bool active) override;
@@ -235,8 +233,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void DidFinishLoad() override;
void ReadyToCommitNavigation(
blink::WebDocumentLoader* document_loader) override;
- void DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) override;
+ void DidCommitProvisionalLoad(ui::PageTransition transition) override;
void OnDestruct() override;
const scoped_refptr<FieldDataManager> GetFieldDataManager() {
@@ -345,6 +342,12 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
DISALLOW_COPY_AND_ASSIGN(PasswordValueGatekeeper);
};
+ // Annotate |forms| and all fields in the current frame with form and field
+ // signatures as HTML attributes. Used by
+ // chrome://flags/#enable-show-autofill-signatures only.
+ void AnnotateFormsAndFieldsWithSignatures(
+ blink::WebVector<blink::WebFormElement>& forms);
+
// Scans the given frame for password forms and sends them up to the browser.
// If |only_visible| is true, only forms visible in the layout are sent.
void SendPasswordForms(bool only_visible);
@@ -467,6 +470,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void SetLastUpdatedFormAndField(const blink::WebFormElement& form,
const blink::WebFormControlElement& input);
+ bool CanShowPopupWithoutPasswords(
+ const blink::WebInputElement& password_element) const;
+
// 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_|.
@@ -474,6 +480,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// The chronologically last insertion into |web_input_to_password_info_|.
WebInputToPasswordInfoMap::iterator last_supplied_password_info_iter_;
+ bool should_show_popup_without_passwords_ = false;
+
// Map WebFormControlElement to the pair of:
// 1) The most recent text that user typed or PasswordManager autofilled in
// input elements. Used for storing username/password before JavaScript
@@ -513,10 +521,6 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// Records the username typed before suggestions preview.
base::string16 username_query_prefix_;
- // The HTML based username detector's cache which maps form elements to
- // username predictions.
- UsernameDetectorCache username_detector_cache_;
-
// This notifier is used to avoid sending redundant messages to the password
// manager driver mojo interface.
FocusStateNotifier focus_state_notifier_;
@@ -543,6 +547,14 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// structure. Replace FormData with a smaller structure.
std::map<FormRendererId, FormStructureInfo> forms_structure_cache_;
+ // The HTML based username detector's cache which maps form elements to
+ // username predictions.
+ UsernameDetectorCache username_detector_cache_;
+
+ // Stores the mapping from a form element's ID to results of button titles
+ // heuristics for that form.
+ form_util::ButtonTitlesCache button_titles_cache_;
+
// Flag to prevent that multiple PasswordManager.FirstRendererFillingResult
// UMA metrics are recorded per page load. This is reset on
// DidCommitProvisionalLoad() but only for non-same-document-navigations.
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 a216162bcfd..93824cae0bd 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -9,7 +9,6 @@
#include "base/no_destructor.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.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 "components/autofill/core/common/renderer_id.h"
@@ -128,7 +127,8 @@ bool IsGaiaWithSkipSavePasswordForm(const blink::WebFormElement& form) {
std::unique_ptr<FormData> CreateFormDataFromWebForm(
const WebFormElement& web_form,
const FieldDataManager* field_data_manager,
- UsernameDetectorCache* username_detector_cache) {
+ UsernameDetectorCache* username_detector_cache,
+ form_util::ButtonTitlesCache* button_titles_cache) {
if (web_form.IsNull())
return nullptr;
@@ -136,7 +136,7 @@ std::unique_ptr<FormData> CreateFormDataFromWebForm(
form_data->url =
form_util::GetCanonicalOriginForDocument(web_form.GetDocument());
form_data->full_url =
- form_util::GetOriginWithoutAuthForDocument(web_form.GetDocument());
+ form_util::GetDocumentUrlWithoutAuth(web_form.GetDocument());
form_data->is_gaia_with_skip_save_password_form =
IsGaiaWithSkipSavePasswordForm(web_form) ||
IsGaiaReauthenticationForm(web_form);
@@ -153,6 +153,8 @@ std::unique_ptr<FormData> CreateFormDataFromWebForm(
}
form_data->username_predictions = GetUsernamePredictions(
control_elements.ReleaseVector(), *form_data, username_detector_cache);
+ form_data->button_titles = form_util::GetButtonTitles(
+ web_form, web_form.GetDocument(), button_titles_cache);
return form_data;
}
@@ -160,7 +162,8 @@ std::unique_ptr<FormData> CreateFormDataFromWebForm(
std::unique_ptr<FormData> CreateFormDataFromUnownedInputElements(
const WebLocalFrame& frame,
const FieldDataManager* field_data_manager,
- UsernameDetectorCache* username_detector_cache) {
+ UsernameDetectorCache* username_detector_cache,
+ form_util::ButtonTitlesCache* button_titles_cache) {
std::vector<WebElement> fieldsets;
std::vector<WebFormControlElement> control_elements =
form_util::GetUnownedFormFieldElements(frame.GetDocument().All(),
@@ -179,9 +182,12 @@ std::unique_ptr<FormData> CreateFormDataFromUnownedInputElements(
form_data->url =
form_util::GetCanonicalOriginForDocument(frame.GetDocument());
form_data->full_url =
- form_util::GetOriginWithoutAuthForDocument(frame.GetDocument());
+ form_util::GetDocumentUrlWithoutAuth(frame.GetDocument());
form_data->username_predictions = GetUsernamePredictions(
control_elements, *form_data, username_detector_cache);
+ form_data->button_titles = form_util::GetButtonTitles(
+ WebFormElement(), frame.GetDocument(), button_titles_cache);
+
return form_data;
}
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 8701d51e57e..07a2ad05095 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -12,6 +12,7 @@
#include <vector>
#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"
@@ -42,14 +43,16 @@ bool IsGaiaWithSkipSavePasswordForm(const blink::WebFormElement& form);
std::unique_ptr<FormData> CreateFormDataFromWebForm(
const blink::WebFormElement& web_form,
const FieldDataManager* field_data_manager,
- UsernameDetectorCache* username_detector_cache);
+ UsernameDetectorCache* username_detector_cache,
+ form_util::ButtonTitlesCache* button_titles_cache);
// Same as CreateFormDataFromWebForm() but for input elements that are
// not enclosed in <form> element.
std::unique_ptr<FormData> CreateFormDataFromUnownedInputElements(
const blink::WebLocalFrame& frame,
const FieldDataManager* field_data_manager,
- UsernameDetectorCache* username_detector_cache);
+ UsernameDetectorCache* username_detector_cache,
+ form_util::ButtonTitlesCache* button_titles_cache);
// The "Realm" for the sign-on. This is scheme, host, port.
std::string GetSignOnRealm(const GURL& origin);
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index 959fa2d7388..a87d298ca38 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -160,10 +160,7 @@ void PasswordGenerationAgent::BindPendingReceiver(
}
void PasswordGenerationAgent::DidCommitProvisionalLoad(
- bool is_same_document_navigation,
ui::PageTransition transition) {
- if (is_same_document_navigation)
- return;
// Update stats for main frame navigation.
if (!render_frame()->GetWebFrame()->Parent()) {
if (current_generation_item_) {
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h
index 6baf4393658..2eeb0e3044e 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.h
@@ -97,8 +97,7 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
struct GenerationItemInfo;
// RenderFrameObserver:
- void DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) override;
+ void DidCommitProvisionalLoad(ui::PageTransition transition) override;
void DidChangeScrollOffset() override;
void OnDestruct() override;
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index d8de972ccdb..3696ebea775 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -169,6 +169,8 @@ jumbo_static_library("browser") {
"metrics/form_event_logger_base.h",
"metrics/form_events.h",
"payments/account_info_getter.h",
+ "payments/autofill_offer_manager.cc",
+ "payments/autofill_offer_manager.h",
"payments/autofill_wallet_model_type_controller.cc",
"payments/autofill_wallet_model_type_controller.h",
"payments/card_unmask_delegate.cc",
@@ -501,6 +503,7 @@ jumbo_static_library("test_support") {
sources += [
"payments/test_credit_card_fido_authenticator.cc",
"payments/test_credit_card_fido_authenticator.h",
+ "payments/test_internal_authenticator.cc",
"payments/test_internal_authenticator.h",
]
@@ -718,6 +721,8 @@ if (use_libfuzzer) {
# TODO(crbug.com/896313): Reduce the dependency on "browser".
":browser",
"//base:base",
+ "//components/autofill/core/browser",
+ "//components/autofill/core/browser:test_support",
"//components/autofill/core/browser/proto",
"//components/autofill/core/common",
"//third_party/libprotobuf-mutator",
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
index 4d4b7509401..36b5c68b20a 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
@@ -175,8 +175,8 @@ html {
display: none;
}
-.hide-AddressProfileFormImport.log-entry[scope='AddressProfileFormImport'],
-.hide-AddressProfileFormImport.log-entry[scope='AddressProfileFormImport'] + hr {
+.hide-AddressProfileFormImport .log-entry[scope='AddressProfileFormImport'],
+.hide-AddressProfileFormImport .log-entry[scope='AddressProfileFormImport'] + hr {
display: none;
}
diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
index a47451ca2e5..a5b7a87d286 100644
--- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
@@ -168,8 +168,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOff) {
std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_FALSE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -183,8 +183,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn) {
// With valid input, the function extracts the credit card form properly.
std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -199,8 +199,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Secure) {
form_structure->DetermineHeuristicTypes();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -217,8 +217,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_NotSecure) {
form_structure->DetermineHeuristicTypes();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_FALSE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -233,8 +233,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Javascript) {
form_structure->DetermineHeuristicTypes();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -249,8 +249,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_WeirdJs) {
form_structure->DetermineHeuristicTypes();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -264,8 +264,8 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_EmptyAction) {
form_structure->DetermineHeuristicTypes();
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
}
@@ -275,8 +275,8 @@ TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_CancelCvc) {
// Will extract the credit card form data.
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
// Create a valid card for the assist.
@@ -297,8 +297,8 @@ TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_SubmitCvc) {
// Will extract the credit card form data.
auto& form_structures = *autofill_manager_->mutable_form_structures();
- auto signature = form_structure->form_signature();
- form_structures[signature] = std::move(form_structure);
+ auto renderer_id = form_structure->unique_renderer_id();
+ form_structures[renderer_id] = std::move(form_structure);
EXPECT_TRUE(autofill_assistant_->CanShowCreditCardAssist());
// Create a valid card for the assist.
diff --git a/chromium/components/autofill/core/browser/autofill_client.cc b/chromium/components/autofill/core/browser/autofill_client.cc
index 3e56a59c33e..ac6e1eae560 100644
--- a/chromium/components/autofill/core/browser/autofill_client.cc
+++ b/chromium/components/autofill/core/browser/autofill_client.cc
@@ -4,10 +4,33 @@
#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/version_info/channel.h"
namespace autofill {
+AutofillClient::PopupOpenArgs::PopupOpenArgs() = default;
+AutofillClient::PopupOpenArgs::PopupOpenArgs(
+ const gfx::RectF& element_bounds,
+ base::i18n::TextDirection text_direction,
+ std::vector<autofill::Suggestion> suggestions,
+ AutoselectFirstSuggestion autoselect_first_suggestion,
+ PopupType popup_type)
+ : element_bounds(element_bounds),
+ text_direction(text_direction),
+ suggestions(std::move(suggestions)),
+ autoselect_first_suggestion(autoselect_first_suggestion),
+ popup_type(popup_type) {}
+AutofillClient::PopupOpenArgs::PopupOpenArgs(
+ const AutofillClient::PopupOpenArgs&) = default;
+AutofillClient::PopupOpenArgs::PopupOpenArgs(AutofillClient::PopupOpenArgs&&) =
+ default;
+AutofillClient::PopupOpenArgs::~PopupOpenArgs() = default;
+AutofillClient::PopupOpenArgs& AutofillClient::PopupOpenArgs::operator=(
+ const AutofillClient::PopupOpenArgs&) = default;
+AutofillClient::PopupOpenArgs& AutofillClient::PopupOpenArgs::operator=(
+ AutofillClient::PopupOpenArgs&&) = default;
+
version_info::Channel AutofillClient::GetChannel() const {
return version_info::Channel::UNKNOWN;
}
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index b1cd8283f70..be85907d853 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -15,6 +15,7 @@
#include "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
+#include "base/util/type_safety/strong_alias.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/payments/legal_message_line.h"
@@ -24,6 +25,7 @@
#include "components/security_state/core/security_state.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/base/window_open_disposition.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "url/gurl.h"
#if !defined(OS_IOS)
@@ -36,10 +38,6 @@ namespace content {
class RenderFrameHost;
}
-namespace gfx {
-class RectF;
-}
-
namespace signin {
class IdentityManager;
}
@@ -177,6 +175,31 @@ class AutofillClient : public RiskDataLoader {
bool show_prompt = false;
};
+ // Required arguments to create a dropdown showing autofill suggestions.
+ struct PopupOpenArgs {
+ using AutoselectFirstSuggestion =
+ ::util::StrongAlias<class AutoSelectFirstSuggestionTag, bool>;
+
+ PopupOpenArgs();
+ PopupOpenArgs(const gfx::RectF& element_bounds,
+ base::i18n::TextDirection text_direction,
+ std::vector<autofill::Suggestion> suggestions,
+ AutoselectFirstSuggestion autoselect_first_suggestion,
+ PopupType popup_type);
+ PopupOpenArgs(const PopupOpenArgs&);
+ PopupOpenArgs(PopupOpenArgs&&);
+ ~PopupOpenArgs();
+ PopupOpenArgs& operator=(const PopupOpenArgs&);
+ PopupOpenArgs& operator=(PopupOpenArgs&&);
+
+ gfx::RectF element_bounds;
+ base::i18n::TextDirection text_direction =
+ base::i18n::TextDirection::UNKNOWN_DIRECTION;
+ std::vector<autofill::Suggestion> suggestions;
+ AutoselectFirstSuggestion autoselect_first_suggestion{false};
+ PopupType popup_type = PopupType::kUnspecified;
+ };
+
// Callback to run after local credit card save is offered. Sends whether the
// prompt was accepted, declined, or ignored in |user_decision|.
typedef base::OnceCallback<void(SaveCardOfferUserDecision user_decision)>
@@ -210,7 +233,7 @@ class AutofillClient : public RiskDataLoader {
typedef base::RepeatingCallback<void(WebauthnDialogCallbackType)>
WebauthnDialogCallback;
- ~AutofillClient() override {}
+ ~AutofillClient() override = default;
// Returns the channel for the installation. In branded builds, this will be
// version_info::Channel::{STABLE,BETA,DEV,CANARY}. In unbranded builds, or
@@ -414,11 +437,7 @@ class AutofillClient : public RiskDataLoader {
// |identifiers| for the element at |element_bounds|. |delegate| will be
// notified of popup events.
virtual void ShowAutofillPopup(
- const gfx::RectF& element_bounds,
- base::i18n::TextDirection text_direction,
- const std::vector<Suggestion>& suggestions,
- bool autoselect_first_suggestion,
- PopupType popup_type,
+ const PopupOpenArgs& open_args,
base::WeakPtr<AutofillPopupDelegate> delegate) = 0;
// Update the data list values shown by the Autofill popup, if visible.
@@ -430,6 +449,12 @@ class AutofillClient : public RiskDataLoader {
// |UpdatePopup| to update the open popup in-place.
virtual void PinPopupView() = 0;
+ // The returned arguments allow to reopen the dropdown with
+ // |ShowAutofillPopup| even if the controller is destroyed temporarily.
+ // This function ensures that the element's bounds are transformed back to the
+ // screen space-independent bounds.
+ virtual PopupOpenArgs GetReopenPopupArgs() const = 0;
+
// Returns (not elided) suggestions currently held by the UI.
virtual base::span<const Suggestion> GetPopupSuggestions() const = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 92847181730..1fe15d7faeb 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -27,7 +27,6 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_metrics.h"
-#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/logging/log_protobufs.h"
#include "components/autofill/core/browser/proto/legacy_proto_bridge.h"
@@ -587,7 +586,7 @@ bool GetAPIQueryPayload(const AutofillQueryContents& query,
} // namespace
struct AutofillDownloadManager::FormRequestData {
- std::vector<std::string> form_signatures;
+ FormAndFieldSignatures signatures;
RequestType request_type;
std::string payload;
int num_attempts = 0;
@@ -640,9 +639,8 @@ bool AutofillDownloadManager::StartQueryRequest(
// Encode the query for the requested forms.
AutofillQueryContents query;
- FormRequestData request_data;
- if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures,
- &query)) {
+ FormAndFieldSignatures signatures;
+ if (!FormStructure::EncodeQueryRequest(forms, &query, &signatures)) {
return false;
}
@@ -665,17 +663,27 @@ bool AutofillDownloadManager::StartQueryRequest(
return false;
}
+ FormRequestData request_data;
+ request_data.signatures = std::move(signatures);
request_data.request_type = AutofillDownloadManager::REQUEST_QUERY;
request_data.payload = std::move(payload);
AutofillMetrics::LogServerQueryMetric(AutofillMetrics::QUERY_SENT);
std::string query_data;
- if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) {
+ if (CheckCacheForQueryRequest(request_data.signatures, &query_data)) {
DVLOG(1) << "AutofillDownloadManager: query request has been retrieved "
- << "from the cache, form signatures: "
- << GetCombinedSignature(request_data.form_signatures);
+ << "from the cache, form signatures:" <<
+ [&request_data] {
+ std::string form_sigs;
+ for (const auto& form_and_fields : request_data.signatures) {
+ base::StrAppend(
+ &form_sigs,
+ {" ", base::NumberToString(form_and_fields.first.value())});
+ }
+ return form_sigs;
+ }();
observer_->OnLoadedServerPredictions(std::move(query_data),
- request_data.form_signatures);
+ request_data.signatures);
return true;
}
@@ -710,9 +718,10 @@ bool AutofillDownloadManager::StartUploadRequest(
return false;
AutofillUploadContents upload;
+ FormAndFieldSignatures signatures;
if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled,
login_form_signature, observed_submission,
- &upload)) {
+ &upload, &signatures)) {
return false;
}
@@ -743,7 +752,7 @@ bool AutofillDownloadManager::StartUploadRequest(
}
FormRequestData request_data;
- request_data.form_signatures.push_back(form.FormSignatureAsStr());
+ request_data.signatures = std::move(signatures);
request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD;
request_data.payload = std::move(payload);
@@ -925,32 +934,27 @@ bool AutofillDownloadManager::StartRequest(FormRequestData request_data) {
}
void AutofillDownloadManager::CacheQueryRequest(
- const std::vector<std::string>& forms_in_query,
+ const FormAndFieldSignatures& forms_in_query,
const std::string& query_data) {
- std::string signature = GetCombinedSignature(forms_in_query);
for (auto it = cached_forms_.begin(); it != cached_forms_.end(); ++it) {
- if (it->first == signature) {
+ if (it->first == forms_in_query) {
// We hit the cache, move to the first position and return.
- std::pair<std::string, std::string> data = *it;
+ auto data = *it;
cached_forms_.erase(it);
cached_forms_.push_front(data);
return;
}
}
- std::pair<std::string, std::string> data;
- data.first = signature;
- data.second = query_data;
- cached_forms_.push_front(data);
+ cached_forms_.emplace_front(forms_in_query, query_data);
while (cached_forms_.size() > max_form_cache_size_)
cached_forms_.pop_back();
}
bool AutofillDownloadManager::CheckCacheForQueryRequest(
- const std::vector<std::string>& forms_in_query,
+ const FormAndFieldSignatures& forms_in_query,
std::string* query_data) const {
- std::string signature = GetCombinedSignature(forms_in_query);
for (const auto& it : cached_forms_) {
- if (it.first == signature) {
+ if (it.first == forms_in_query) {
// We hit the cache, fill the data and return.
*query_data = it.second;
return true;
@@ -959,23 +963,6 @@ bool AutofillDownloadManager::CheckCacheForQueryRequest(
return false;
}
-std::string AutofillDownloadManager::GetCombinedSignature(
- const std::vector<std::string>& forms_in_query) const {
- size_t total_size = forms_in_query.size();
- for (size_t i = 0; i < forms_in_query.size(); ++i)
- total_size += forms_in_query[i].length();
- std::string signature;
-
- signature.reserve(total_size);
-
- for (size_t i = 0; i < forms_in_query.size(); ++i) {
- if (i)
- signature.append(",");
- signature.append(forms_in_query[i]);
- }
- return signature;
-}
-
// static
int AutofillDownloadManager::GetMaxServerAttempts() {
// This value is constant for the life of the browser, so we cache it
@@ -995,7 +982,7 @@ void AutofillDownloadManager::OnSimpleLoaderComplete(
std::unique_ptr<network::SimpleURLLoader> simple_loader = std::move(*it);
url_loaders_.erase(it);
- CHECK(request_data.form_signatures.size());
+ CHECK(request_data.signatures.size() > 0);
int response_code = -1; // Invalid response code.
if (simple_loader->ResponseInfo() && simple_loader->ResponseInfo()->headers) {
response_code = simple_loader->ResponseInfo()->headers->response_code();
@@ -1024,7 +1011,7 @@ void AutofillDownloadManager::OnSimpleLoaderComplete(
<< response_code << " and error message from the server "
<< error_message;
- observer_->OnServerRequestError(request_data.form_signatures[0],
+ observer_->OnServerRequestError(request_data.signatures.front().first,
request_data.request_type, response_code);
LogFailingPayloadSize(request_data.request_type,
@@ -1053,11 +1040,11 @@ void AutofillDownloadManager::OnSimpleLoaderComplete(
}
if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) {
- CacheQueryRequest(request_data.form_signatures, *response_body);
+ CacheQueryRequest(request_data.signatures, *response_body);
UMA_HISTOGRAM_BOOLEAN("Autofill.Query.WasInCache",
simple_loader->LoadedFromCache());
observer_->OnLoadedServerPredictions(std::move(*response_body),
- request_data.form_signatures);
+ request_data.signatures);
return;
}
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.h b/chromium/components/autofill/core/browser/autofill_download_manager.h
index 88ce53237a5..4531f498907 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.h
@@ -20,6 +20,8 @@
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/common/signatures.h"
#include "components/variations/variations_http_header_provider.h"
#include "net/base/backoff_entry.h"
#include "services/network/public/cpp/simple_url_loader.h"
@@ -30,7 +32,6 @@ class PrefService;
namespace autofill {
class AutofillDriver;
-class FormStructure;
class LogManager;
const size_t kMaxAPIQueryGetSize = 10240; // 10 KiB
@@ -52,10 +53,10 @@ class AutofillDownloadManager {
public:
// Called when field type predictions are successfully received from the
// server. |response| contains the server response for the forms
- // represented by |form_signatures|.
+ // represented by |signatures|.
virtual void OnLoadedServerPredictions(
std::string response,
- const std::vector<std::string>& form_signatures) = 0;
+ const FormAndFieldSignatures& signatures) = 0;
// These notifications are used to help with testing.
// Called when heuristic either successfully considered for upload and
@@ -65,7 +66,7 @@ class AutofillDownloadManager {
// |form_signature| - the signature of the requesting form.
// |request_type| - type of request that failed.
// |http_error| - HTTP error code.
- virtual void OnServerRequestError(const std::string& form_signature,
+ virtual void OnServerRequestError(FormSignature form_signature,
RequestType request_type,
int http_error) {}
@@ -135,7 +136,8 @@ class AutofillDownloadManager {
FRIEND_TEST_ALL_PREFIXES(AutofillDownloadManagerTest, RetryLimit_Query);
struct FormRequestData;
- typedef std::list<std::pair<std::string, std::string> > QueryRequestCache;
+ typedef std::list<std::pair<FormAndFieldSignatures, std::string>>
+ QueryRequestCache;
// Returns the URL and request method to use when issuing the request
// described by |request_data|. If the returned method is GET, the URL
@@ -163,11 +165,11 @@ class AutofillDownloadManager {
// Caches query request. |forms_in_query| is a vector of form signatures in
// the query. |query_data| is the successful data returned over the wire.
- void CacheQueryRequest(const std::vector<std::string>& forms_in_query,
+ void CacheQueryRequest(const FormAndFieldSignatures& forms_in_query,
const std::string& query_data);
// Returns true if query is in the cache, while filling |query_data|, false
// otherwise. |forms_in_query| is a vector of form signatures in the query.
- bool CheckCacheForQueryRequest(const std::vector<std::string>& forms_in_query,
+ bool CheckCacheForQueryRequest(const FormAndFieldSignatures& forms_in_query,
std::string* query_data) const;
// Concatenates |forms_in_query| into one signature.
std::string GetCombinedSignature(
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 6b31dc6ef00..22fd6ac32b1 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -211,7 +211,7 @@ class AutofillDownloadManagerTest : public AutofillDownloadManager::Observer,
// AutofillDownloadManager::Observer implementation.
void OnLoadedServerPredictions(
std::string response_xml,
- const std::vector<std::string>& form_signatures) override {
+ const FormAndFieldSignatures& form_signatures) override {
ResponseData response;
response.response = std::move(response_xml);
response.type_of_response = QUERY_SUCCESSFULL;
@@ -224,11 +224,11 @@ class AutofillDownloadManagerTest : public AutofillDownloadManager::Observer,
responses_.push_back(response);
}
- void OnServerRequestError(const std::string& form_signature,
+ void OnServerRequestError(FormSignature form_signature,
AutofillDownloadManager::RequestType request_type,
int http_error) override {
ResponseData response;
- response.signature = form_signature;
+ response.signature = base::NumberToString(form_signature.value());
response.error = http_error;
response.type_of_response =
request_type == AutofillDownloadManager::REQUEST_QUERY
@@ -1401,7 +1401,7 @@ class AutofillServerCommunicationTest
// AutofillDownloadManager::Observer implementation.
void OnLoadedServerPredictions(
std::string /* response_xml */,
- const std::vector<std::string>& /*form_signatures */) override {
+ const FormAndFieldSignatures& /*form_signatures */) override {
ASSERT_TRUE(run_loop_);
run_loop_->QuitWhenIdle();
}
@@ -2007,6 +2007,8 @@ TEST_P(AutofillUploadTest, RichMetadata) {
EXPECT_TRUE(upload.randomized_form_metadata().has_id());
EXPECT_TRUE(upload.randomized_form_metadata().has_name());
EXPECT_TRUE(upload.randomized_form_metadata().has_url());
+ ASSERT_TRUE(upload.randomized_form_metadata().has_checksum_for_url());
+ EXPECT_EQ(upload.randomized_form_metadata().checksum_for_url(), 3608731642);
EXPECT_EQ(3, upload.field_size());
for (const auto& f : upload.field()) {
ASSERT_TRUE(f.has_randomized_field_metadata());
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index ef21685dbc3..86f1fbca419 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -225,34 +225,4 @@ bool IsInAutofillSuggestionsDisabledExperiment() {
return group_name == "Disabled";
}
-bool OfferStoreUnmaskedCards(bool is_off_the_record) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- // The checkbox can be forced on with a flag, but by default we don't store
- // on Linux due to lack of system keychain integration. See crbug.com/162735
- return base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableOfferStoreUnmaskedWalletCards);
-#else
- // Never offer to store unmasked cards when off the record.
- if (is_off_the_record) {
- return false;
- }
-
- // Query the field trial before checking command line flags to ensure UMA
- // reports the correct group.
- std::string group_name =
- base::FieldTrialList::FindFullName("OfferStoreUnmaskedWalletCards");
-
- // The checkbox can be forced on or off with flags.
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableOfferStoreUnmaskedWalletCards))
- return true;
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOfferStoreUnmaskedWalletCards))
- return false;
-
- // Otherwise use the field trial to show the checkbox or not.
- return group_name != "Disabled";
-#endif
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h
index d291ce0af08..d5b92be5822 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.h
+++ b/chromium/components/autofill/core/browser/autofill_experiments.h
@@ -44,11 +44,6 @@ bool IsCreditCardMigrationEnabled(PersonalDataManager* personal_data_manager,
// disables providing suggestions.
bool IsInAutofillSuggestionsDisabledExperiment();
-// Returns true if the user should be offered to locally store unmasked cards.
-// This controls whether the option is presented at all rather than the default
-// response of the option.
-bool OfferStoreUnmaskedCards(bool is_off_the_record);
-
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index 6cc56740ad1..ca64c2ca325 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -39,6 +39,9 @@ namespace autofill {
namespace {
+using AutoselectFirstSuggestion =
+ AutofillClient::PopupOpenArgs::AutoselectFirstSuggestion;
+
// Returns true if the suggestion entry is an Autofill warning message.
// Warning messages should display on top of suggestion list.
bool IsAutofillWarningEntry(int frontend_id) {
@@ -162,9 +165,10 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
// Send to display.
if (query_field_.is_focusable && GetAutofillDriver()->CanShowAutofillUi()) {
- manager_->client()->ShowAutofillPopup(
+ autofill::AutofillClient::PopupOpenArgs open_args(
element_bounds_, query_field_.text_direction, suggestions,
- autoselect_first_suggestion, popup_type_, GetWeakPtr());
+ AutoselectFirstSuggestion(autoselect_first_suggestion), popup_type_);
+ manager_->client()->ShowAutofillPopup(open_args, GetWeakPtr());
}
}
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 b70b30a792f..fd2f179f617 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/i18n/rtl.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
@@ -35,6 +36,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
using base::ASCIIToUTF16;
using testing::_;
@@ -51,15 +53,22 @@ const int kAutofillProfileId = 1;
class MockAutofillDriver : public TestAutofillDriver {
public:
- MockAutofillDriver() {}
+ MockAutofillDriver() = default;
// Mock methods to enable testability.
- MOCK_METHOD1(RendererShouldAcceptDataListSuggestion,
- void(const base::string16&));
- MOCK_METHOD0(RendererShouldClearFilledSection, void());
- MOCK_METHOD0(RendererShouldClearPreviewedForm, void());
- MOCK_METHOD1(RendererShouldFillFieldWithValue, void(const base::string16&));
- MOCK_METHOD1(RendererShouldPreviewFieldWithValue,
- void(const base::string16&));
+ MOCK_METHOD(void,
+ RendererShouldAcceptDataListSuggestion,
+ (const base::string16&),
+ (override));
+ MOCK_METHOD(void, RendererShouldClearFilledSection, (), (override));
+ MOCK_METHOD(void, RendererShouldClearPreviewedForm, (), (override));
+ MOCK_METHOD(void,
+ RendererShouldFillFieldWithValue,
+ (const base::string16&),
+ (override));
+ MOCK_METHOD(void,
+ RendererShouldPreviewFieldWithValue,
+ (const base::string16&),
+ (override));
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillDriver);
@@ -67,25 +76,23 @@ class MockAutofillDriver : public TestAutofillDriver {
class MockAutofillClient : public TestAutofillClient {
public:
- MockAutofillClient() {}
-
- MOCK_METHOD1(ScanCreditCard, void(CreditCardScanCallback callbacK));
-
- MOCK_METHOD6(ShowAutofillPopup,
- void(const gfx::RectF& element_bounds,
- base::i18n::TextDirection text_direction,
- const std::vector<Suggestion>& suggestions,
- bool autoselect_first_suggestion,
- PopupType popup_type,
- base::WeakPtr<AutofillPopupDelegate> delegate));
-
- MOCK_METHOD2(UpdateAutofillPopupDataListValues,
- void(const std::vector<base::string16>& values,
- const std::vector<base::string16>& lables));
-
- MOCK_METHOD1(HideAutofillPopup, void(PopupHidingReason));
-
- MOCK_METHOD1(ExecuteCommand, void(int));
+ MockAutofillClient() = default;
+ MOCK_METHOD(void,
+ ScanCreditCard,
+ (CreditCardScanCallback callbacK),
+ (override));
+ MOCK_METHOD(void,
+ ShowAutofillPopup,
+ (const autofill::AutofillClient::PopupOpenArgs& open_args,
+ base::WeakPtr<AutofillPopupDelegate> delegate),
+ (override));
+ MOCK_METHOD(void,
+ UpdateAutofillPopupDataListValues,
+ (const std::vector<base::string16>& values,
+ const std::vector<base::string16>& lables),
+ (override));
+ MOCK_METHOD(void, HideAutofillPopup, (PopupHidingReason), (override));
+ MOCK_METHOD(void, ExecuteCommand, (int), (override));
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
@@ -99,21 +106,24 @@ class MockAutofillManager : public AutofillManager {
client,
client->GetPersonalDataManager(),
client->GetAutocompleteHistoryManager()) {}
- ~MockAutofillManager() override {}
PopupType GetPopupType(const FormData& form,
const FormFieldData& field) override {
return PopupType::kPersonalInformation;
}
- MOCK_METHOD2(ShouldShowScanCreditCard,
- bool(const FormData& form, const FormFieldData& field));
-
- MOCK_METHOD2(ShouldShowCreditCardSigninPromo,
- bool(const FormData& form, const FormFieldData& field));
-
- MOCK_METHOD2(OnUserHideSuggestions,
- void(const FormData& form, const FormFieldData& field));
+ MOCK_METHOD(bool,
+ ShouldShowScanCreditCard,
+ (const FormData& form, const FormFieldData& field),
+ (override));
+ MOCK_METHOD(bool,
+ ShouldShowCreditCardSigninPromo,
+ (const FormData& form, const FormFieldData& field),
+ (override));
+ MOCK_METHOD(void,
+ OnUserHideSuggestions,
+ (const FormData& form, const FormFieldData& field),
+ (override));
bool ShouldShowCardsFromAccountOption(const FormData& form,
const FormFieldData& field) {
@@ -124,19 +134,22 @@ class MockAutofillManager : public AutofillManager {
should_show_cards_from_account_option_ = true;
}
- MOCK_METHOD5(FillOrPreviewForm,
- void(AutofillDriver::RendererFormDataAction action,
- int query_id,
- const FormData& form,
- const FormFieldData& field,
- int unique_id));
-
- MOCK_METHOD5(FillCreditCardForm,
- void(int query_id,
- const FormData& form,
- const FormFieldData& field,
- const CreditCard& credit_card,
- const base::string16& cvc));
+ MOCK_METHOD(void,
+ FillOrPreviewForm,
+ (AutofillDriver::RendererFormDataAction action,
+ int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ int unique_id),
+ (override));
+ MOCK_METHOD(void,
+ FillCreditCardForm,
+ (int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const base::string16& cvc),
+ (override));
private:
bool should_show_cards_from_account_option_ = false;
@@ -208,9 +221,9 @@ TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) {
// The enums must be cast to ints to prevent compile errors on linux_rel.
auto element_ids = testing::ElementsAre(
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// This should call ShowAutofillPopup.
std::vector<Suggestion> autofill_item;
@@ -218,6 +231,9 @@ TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) {
autofill_item[0].frontend_id = kAutofillProfileId;
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
EXPECT_CALL(
*autofill_manager_,
@@ -243,10 +259,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
// The enums must be cast to ints to prevent compile errors on linux_rel.
auto element_ids = testing::ElementsAre(
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
-
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
base::UserActionTester user_action_tester;
@@ -258,6 +273,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
EXPECT_EQ(0, user_action_tester.GetActionCount(
"Signin_Impression_FromAutofillDropdown"));
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
EXPECT_CALL(
*autofill_manager_,
@@ -284,9 +302,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
auto element_ids = testing::ElementsAre(
static_cast<int>(POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
base::UserActionTester user_action_tester;
@@ -296,6 +314,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
kQueryId, items, /*autoselect_first_suggestion=*/false);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Signin_Impression_FromAutofillDropdown"));
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
EXPECT_CALL(autofill_client_,
ExecuteCommand(autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
@@ -328,9 +349,9 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateDataList) {
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// This should call ShowAutofillPopup.
std::vector<Suggestion> autofill_item;
@@ -338,20 +359,25 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateDataList) {
autofill_item[0].frontend_id = kAutofillProfileId;
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
// Try calling OnSuggestionsReturned with no Autofill values and ensure
// the datalist items are still shown.
// The enum must be cast to an int to prevent compile errors on linux_rel.
- EXPECT_CALL(
- autofill_client_,
- ShowAutofillPopup(_, _,
- SuggestionVectorIdsAre(testing::ElementsAre(
- static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY))),
- false, PopupType::kPersonalInformation, _));
+
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
autofill_item.clear();
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(testing::ElementsAre(
+ static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY))));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Test that datalist values can get updated while a popup is showing.
@@ -378,9 +404,9 @@ TEST_F(AutofillExternalDelegateUnitTest, UpdateDataListWhileShowingPopup) {
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// Ensure the popup is displayed.
std::vector<Suggestion> autofill_item;
@@ -388,6 +414,9 @@ TEST_F(AutofillExternalDelegateUnitTest, UpdateDataListWhileShowingPopup) {
autofill_item[0].frontend_id = kAutofillProfileId;
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
// This would normally get called from ShowAutofillPopup, but it is mocked so
// we need to call OnPopupShown ourselves.
@@ -428,9 +457,9 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutofillDatalistValues) {
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// Have an Autofill item that is identical to one of the datalist entries.
std::vector<Suggestion> autofill_item;
@@ -440,6 +469,9 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutofillDatalistValues) {
autofill_item[0].frontend_id = kAutofillProfileId;
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Test that we de-dupe autocomplete values against datalist values, keeping the
@@ -467,9 +499,9 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutocompleteDatalistValues) {
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
static_cast<int>(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// Have an Autocomplete item that is identical to one of the datalist entries
// and one that is distinct.
@@ -482,6 +514,9 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutocompleteDatalistValues) {
autocomplete_items[1].frontend_id = POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY;
external_delegate_->OnSuggestionsReturned(
kQueryId, autocomplete_items, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIdsAre(element_ids));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Test that the Autofill popup is able to display warnings explaining why
@@ -490,14 +525,9 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutocompleteDatalistValues) {
TEST_F(AutofillExternalDelegateUnitTest, AutofillWarnings) {
IssueOnQuery(kQueryId);
- // The enums must be cast to ints to prevent compile errors on linux_rel.
- EXPECT_CALL(
- autofill_client_,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(testing::ElementsAre(static_cast<int>(
- POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE))),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// This should call ShowAutofillPopup.
std::vector<Suggestion> autofill_item;
@@ -506,6 +536,15 @@ TEST_F(AutofillExternalDelegateUnitTest, AutofillWarnings) {
POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE;
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+
+ // The enums must be cast to ints to prevent compile errors on linux_rel.
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(testing::ElementsAre(static_cast<int>(
+ POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE))));
+ EXPECT_EQ(open_args.element_bounds, gfx::RectF());
+ EXPECT_EQ(open_args.text_direction, base::i18n::UNKNOWN_DIRECTION);
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Test that Autofill warnings are removed if there are also autocomplete
@@ -514,13 +553,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
AutofillWarningsNotShown_WithSuggestions) {
IssueOnQuery(kQueryId);
- // The enums must be cast to ints to prevent compile errors on linux_rel.
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(testing::ElementsAre(
- static_cast<int>(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY))),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
// This should call ShowAutofillPopup.
std::vector<Suggestion> suggestions;
@@ -532,6 +567,13 @@ TEST_F(AutofillExternalDelegateUnitTest,
suggestions[1].frontend_id = POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY;
external_delegate_->OnSuggestionsReturned(
kQueryId, suggestions, /*autoselect_first_suggestion=*/false);
+
+ // The enums must be cast to ints to prevent compile errors on linux_rel.
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(testing::ElementsAre(
+ static_cast<int>(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY))));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Test that the Autofill delegate doesn't try and fill a form with a
@@ -768,9 +810,9 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldShowGooglePayIcon) {
auto element_icons =
testing::ElementsAre(std::string(), testing::StartsWith("googlePay"));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
std::vector<Suggestion> autofill_item;
autofill_item.push_back(Suggestion());
@@ -779,6 +821,9 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldShowGooglePayIcon) {
// This should call ShowAutofillPopup.
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false, true);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIconsAre(element_icons));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
TEST_F(AutofillExternalDelegateUnitTest,
@@ -788,9 +833,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
auto element_icons = testing::ElementsAre(
std::string(),
std::string() /* Autofill setting item does not have icon. */);
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
std::vector<Suggestion> autofill_item;
autofill_item.push_back(Suggestion());
@@ -799,6 +844,9 @@ TEST_F(AutofillExternalDelegateUnitTest,
// This should call ShowAutofillPopup.
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false, false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIconsAre(element_icons));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
TEST_F(AutofillExternalDelegateUnitTest, ShouldUseNewSettingName) {
@@ -806,9 +854,9 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldUseNewSettingName) {
auto element_values = testing::ElementsAre(
base::string16(), l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorValuesAre(element_values),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
std::vector<Suggestion> autofill_item;
autofill_item.push_back(Suggestion());
@@ -817,6 +865,9 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldUseNewSettingName) {
// This should call ShowAutofillPopup.
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorValuesAre(element_values));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Tests that the prompt to show account cards shows up when the corresponding
@@ -830,9 +881,9 @@ TEST_F(AutofillExternalDelegateCardsFromAccountTest,
base::string16(),
l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ACCOUNT_CARDS),
l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorValuesAre(element_values),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
std::vector<Suggestion> autofill_item;
autofill_item.push_back(Suggestion());
@@ -840,6 +891,9 @@ TEST_F(AutofillExternalDelegateCardsFromAccountTest,
external_delegate_->OnSuggestionsReturned(
kQueryId, autofill_item, /*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorValuesAre(element_values));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
// Tests that the prompt to show account cards shows up when the corresponding
@@ -851,13 +905,16 @@ TEST_F(AutofillExternalDelegateCardsFromAccountTest,
auto element_values = testing::ElementsAre(
l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ACCOUNT_CARDS));
- EXPECT_CALL(autofill_client_,
- ShowAutofillPopup(_, _, SuggestionVectorValuesAre(element_values),
- false, PopupType::kPersonalInformation, _));
+ AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client_, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
external_delegate_->OnSuggestionsReturned(
kQueryId, std::vector<Suggestion>(),
/*autoselect_first_suggestion=*/false);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorValuesAre(element_values));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc
index 60c09c74bf0..ddb4f6816d3 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler.cc
@@ -5,13 +5,16 @@
#include "components/autofill/core/browser/autofill_handler.h"
#include "base/containers/adapters.h"
+#include "base/feature_list.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/autofill_data_validation.h"
+#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_payments_features.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
+#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -79,46 +82,62 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
if (forms.empty())
return;
- // Parse each of the forms. Because parsing a given FormData may invalidate
- // and replace a form parsed before it (invalidating any pointers we might
- // hold) we track the newly created form signatures instead of remembering
- // the pointer values.
- std::set<FormSignature> new_form_signatures;
+ std::set<FormRendererId> new_form_renderer_ids;
for (const FormData& form : forms) {
const auto parse_form_start_time = AutofillTickClock::NowTicks();
- FormStructure* cached_form_structure = nullptr;
- FormStructure* form_structure = nullptr;
- // Try to find the FormStructure that corresponds to |form| if the form
- // contains credit card fields only.
- // |cached_form_structure| may still be nullptr after this call.
- ignore_result(FindCachedForm(form, &cached_form_structure));
+ FormStructure* cached_form_structure =
+ FindCachedFormByRendererId(form.unique_renderer_id);
+ // Autofill used to ignore cache hits for non-credit-card forms. The
+ // motivation behind this is probably to have credit-card forms preserve
+ // their original signature, whereas non-credit-card forms would use the
+ // most recent form signature. Ignoring cache hits however appears to be
+ // part of breaking profile imports and voting for dynamic forms. See
+ // crbug/1091401#c15 for details.
+ //
+ // Therefore, if the kAutofillKeepInitialFormValuesInCache experiment is
+ // enabled, we do not ignore cache hits, but in those cases where the old
+ // code would have ignored the cache hit we update the FormStructure's
+ // FormSignature.
+ // Otherwise, if the experiment disabled, we just ignore the cache hit.
+ //
+ // 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) {
- cached_form_structure = nullptr;
+ update_form_signature = true;
+ if (kOldBehavior)
+ cached_form_structure = nullptr;
break;
}
}
}
- if (!ParseForm(form, cached_form_structure, &form_structure))
+ FormStructure* form_structure = ParseForm(form, cached_form_structure);
+ if (!form_structure)
continue;
DCHECK(form_structure);
- new_form_signatures.insert(form_structure->form_signature());
+
+ if (update_form_signature && !kOldBehavior)
+ form_structure->set_form_signature(CalculateFormSignature(form));
+
+ new_form_renderer_ids.insert(form_structure->unique_renderer_id());
AutofillMetrics::LogParseFormTiming(AutofillTickClock::NowTicks() -
parse_form_start_time);
}
- if (new_form_signatures.empty())
+ if (new_form_renderer_ids.empty())
return;
// Populate the set of newly created form structures and call the
// OnFormsParsed handler.
std::vector<FormStructure*> new_form_structures;
- new_form_structures.reserve(new_form_signatures.size());
- for (auto signature : new_form_signatures) {
- FormStructure* form_structure = nullptr;
- if (FindCachedForm(signature, &form_structure) && form_structure) {
+ new_form_structures.reserve(new_form_renderer_ids.size());
+ for (auto renderer_id : new_form_renderer_ids) {
+ FormStructure* form_structure = FindCachedFormByRendererId(renderer_id);
+ if (form_structure) {
new_form_structures.push_back(form_structure);
} else {
NOTREACHED();
@@ -204,8 +223,9 @@ bool AutofillHandler::GetCachedFormAndField(const FormData& form,
FormStructure** form_structure,
AutofillField** autofill_field) {
// Maybe find an existing FormStructure that corresponds to |form|.
- FormStructure* cached_form = nullptr;
- if (FindCachedForm(form, &cached_form)) {
+ FormStructure* cached_form =
+ FindCachedFormByRendererId(form.unique_renderer_id);
+ if (cached_form) {
DCHECK(cached_form);
if (!CachedFormNeedsUpdate(form, *cached_form)) {
// There is no data to return if there are no auto-fillable fields.
@@ -221,7 +241,8 @@ bool AutofillHandler::GetCachedFormAndField(const FormData& form,
// The form is new or updated, parse it and discard |cached_form|.
// i.e., |cached_form| is no longer valid after this call.
- if (!ParseForm(form, std::move(cached_form), form_structure))
+ *form_structure = ParseForm(form, cached_form);
+ if (!*form_structure)
return false;
// Annotate the updated form with its predicted types.
@@ -236,52 +257,40 @@ bool AutofillHandler::GetCachedFormAndField(const FormData& form,
return *autofill_field != nullptr;
}
-bool AutofillHandler::FindCachedForm(FormSignature form_signature,
- FormStructure** form_structure) const {
- auto it = form_structures_.find(form_signature);
- if (it != form_structures_.end()) {
- *form_structure = it->second.get();
- return true;
- }
- return false;
-}
-
-bool AutofillHandler::FindCachedForm(const FormData& form,
- FormStructure** form_structure) const {
- // Find the FormStructure that corresponds to |form|.
- if (FindCachedForm(autofill::CalculateFormSignature(form), form_structure))
- return true;
-
- // The form might have been modified by JavaScript which resulted in a change
- // of form signature. Compare it to all the forms in the cache to look for a
- // match.
- for (const auto& it : form_structures_) {
- if (*it.second == form) {
- *form_structure = it.second.get();
- return true;
+size_t AutofillHandler::FindCachedFormsBySignature(
+ FormSignature form_signature,
+ std::vector<FormStructure*>* form_structures) const {
+ size_t hits_num = 0;
+ for (const auto& p : form_structures_) {
+ if (p.second->form_signature() == form_signature) {
+ ++hits_num;
+ if (form_structures)
+ form_structures->push_back(p.second.get());
}
}
+ return hits_num;
+}
- *form_structure = nullptr;
- return false;
+FormStructure* AutofillHandler::FindCachedFormByRendererId(
+ FormRendererId form_renderer_id) const {
+ auto it = form_structures_.find(form_renderer_id);
+ return it != form_structures_.end() ? it->second.get() : nullptr;
}
-bool AutofillHandler::ParseForm(const FormData& form,
- const FormStructure* cached_form,
- FormStructure** parsed_form_structure) {
- DCHECK(parsed_form_structure);
+FormStructure* AutofillHandler::ParseForm(const FormData& form,
+ const FormStructure* cached_form) {
if (form_structures_.size() >= kAutofillHandlerMaxFormCacheSize) {
if (log_manager_) {
log_manager_->Log() << LoggingScope::kAbortParsing
<< LogMessage::kAbortParsingTooManyForms << form;
}
- return false;
+ return nullptr;
}
auto form_structure = std::make_unique<FormStructure>(form);
form_structure->ParseFieldTypesFromAutocompleteAttributes();
if (!form_structure->ShouldBeParsed(log_manager_))
- return false;
+ return nullptr;
if (cached_form) {
// We need to keep the server data if available. We need to use them while
@@ -300,17 +309,17 @@ bool AutofillHandler::ParseForm(const FormData& form,
// Hold the parsed_form_structure we intend to return. We can use this to
// reference the form_signature when transferring ownership below.
- *parsed_form_structure = form_structure.get();
+ FormStructure* parsed_form_structure = form_structure.get();
// Ownership is transferred to |form_structures_| which maintains it until
// the form is parsed again or the AutofillHandler is destroyed.
//
// Note that this insert/update takes ownership of the new form structure
// and also destroys the previously cached form structure.
- form_structures_[(*parsed_form_structure)->form_signature()] =
+ form_structures_[parsed_form_structure->unique_renderer_id()] =
std::move(form_structure);
- return true;
+ return parsed_form_structure;
}
void AutofillHandler::Reset() {
diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h
index 942d74de177..a7965f77308 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.h
+++ b/chromium/components/autofill/core/browser/autofill_handler.h
@@ -16,6 +16,7 @@
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
+#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
namespace gfx {
@@ -46,9 +47,6 @@ class AutofillHandler {
virtual void OnFormParsed() = 0;
};
- using FormStructureMap =
- std::map<FormSignature, std::unique_ptr<FormStructure>>;
-
virtual ~AutofillHandler();
// Invoked when the value of textfield is changed.
@@ -108,10 +106,6 @@ class AutofillHandler {
// Invoked when popup window should be hidden.
virtual void OnHidePopup() = 0;
- // Invoked when data list need to be set.
- virtual void OnSetDataList(const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) = 0;
-
// Invoked when the options of a select element in the |form| changed.
virtual void SelectFieldOptionsDidChange(const FormData& form) = 0;
@@ -140,14 +134,18 @@ class AutofillHandler {
}
// Returns the present form structures seen by Autofill handler.
- const FormStructureMap& form_structures() const { return form_structures_; }
+ const std::map<FormRendererId, std::unique_ptr<FormStructure>>&
+ form_structures() const {
+ return form_structures_;
+ }
AutofillDriver* driver() { return driver_; }
#if defined(UNIT_TEST)
// A public wrapper that calls |mutable_form_structures| for testing purposes
// only.
- FormStructureMap* mutable_form_structures_for_test() {
+ std::map<FormRendererId, std::unique_ptr<FormStructure>>*
+ mutable_form_structures_for_test() {
return mutable_form_structures();
}
#endif
@@ -192,30 +190,28 @@ class AutofillHandler {
virtual void OnFormsParsed(const std::vector<FormStructure*>& form_structures,
const base::TimeTicks timestamp) = 0;
- // Fills |form_structure| with a pointer to the cached form structure
- // corresponding to |form_signature|. Returns false if no cached form
- // structure is found with a matching signature.
- bool FindCachedForm(FormSignature form_signature,
- FormStructure** form_structure) const WARN_UNUSED_RESULT;
+ // Returns the number of FormStructures with the given |form_signature| and
+ // appends them to |form_structures|. Runs in linear time.
+ size_t FindCachedFormsBySignature(
+ FormSignature form_signature,
+ std::vector<FormStructure*>* form_structures) const;
- // Fills |form_structure| with a pointer to the cached form structure
- // corresponding to |form|. This will do a direct match of the form's
- // signature as well as fuzzy match of the forms structure if no directly
- // matching form signature is found. Returns false if no match is found.
- bool FindCachedForm(const FormData& form,
- FormStructure** form_structure) const WARN_UNUSED_RESULT;
+ // Returns nullptr if no cached form structure is found with a matching
+ // |renderer_id|. Runs in logarithmic time.
+ FormStructure* FindCachedFormByRendererId(FormRendererId renderer_id) const;
// Parses the |form| with the server data retrieved from the |cached_form|
- // (if any), and writes it to the |parse_form_structure|. Adds the
- // |parse_form_structure| to the |form_structures_|. Returns true if the form
- // is parsed.
- bool ParseForm(const FormData& form,
- const FormStructure* cached_form,
- FormStructure** parsed_form_structure);
+ // (if any). Returns nullptr if the form should not be parsed. Otherwise, adds
+ // the returned form structure to the |form_structures_|.
+ FormStructure* ParseForm(const FormData& form,
+ const FormStructure* cached_form);
bool value_from_dynamic_change_form_ = false;
- FormStructureMap* mutable_form_structures() { return &form_structures_; }
+ std::map<FormRendererId, std::unique_ptr<FormStructure>>*
+ mutable_form_structures() {
+ return &form_structures_;
+ }
private:
// Provides driver-level context to the shared code of the component. Must
@@ -225,7 +221,7 @@ class AutofillHandler {
LogManager* const log_manager_;
// Our copy of the form data.
- FormStructureMap form_structures_;
+ std::map<FormRendererId, std::unique_ptr<FormStructure>> form_structures_;
// Will be not null only for |SaveCardBubbleViewsFullFormBrowserTest|.
ObserverForTest* observer_for_testing_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
index 8a9fcaf4558..a246c8c8d72 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -88,11 +88,9 @@ void AutofillHandlerProxy::OnDidPreviewAutofillFormData() {}
void AutofillHandlerProxy::OnDidEndTextFieldEditing() {}
-void AutofillHandlerProxy::OnHidePopup() {}
-
-void AutofillHandlerProxy::OnSetDataList(
- const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) {}
+void AutofillHandlerProxy::OnHidePopup() {
+ provider_->OnHidePopup(this);
+}
void AutofillHandlerProxy::SelectFieldOptionsDidChange(const FormData& form) {}
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.h b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
index 152292c21ab..2abce2fdb02 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.h
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
@@ -28,8 +28,6 @@ class AutofillHandlerProxy : public AutofillHandler {
void OnDidPreviewAutofillFormData() override;
void OnDidEndTextFieldEditing() override;
void OnHidePopup() override;
- void OnSetDataList(const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) override;
void SelectFieldOptionsDidChange(const FormData& form) override;
void Reset() override;
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 1513e981190..4e8321b85e3 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -248,6 +248,12 @@ bool IsAddressForm(FieldTypeGroup field_type_group) {
void LogAutofillTypePredictionsAvailable(
LogManager* log_manager,
const std::vector<FormStructure*>& forms) {
+ if (VLOG_IS_ON(1)) {
+ VLOG(1) << "Parsed forms:";
+ for (FormStructure* form : forms)
+ VLOG(1) << *form;
+ }
+
if (!log_manager || !log_manager->IsLoggingActive())
return;
@@ -425,7 +431,24 @@ int TypeValueFormFillingLimit(ServerFieldType field_type) {
} // namespace
-AutofillManager::FillingContext::FillingContext() = default;
+AutofillManager::FillingContext::FillingContext(
+ const AutofillField& field,
+ const AutofillProfile* optional_profile,
+ const CreditCard* optional_credit_card,
+ const base::string16* optional_cvc)
+ : profile(optional_profile ? base::make_optional(*optional_profile)
+ : base::nullopt),
+ credit_card(optional_credit_card
+ ? base::make_optional(std::make_pair(
+ *optional_credit_card,
+ optional_cvc ? *optional_cvc : base::string16()))
+ : base::nullopt),
+ filled_field_name(field.unique_name()),
+ original_fill_time(AutofillTickClock::NowTicks()) {
+ DCHECK(optional_profile || optional_credit_card);
+ DCHECK(optional_credit_card || !optional_cvc);
+ DCHECK(profile || credit_card);
+}
AutofillManager::FillingContext::~FillingContext() = default;
@@ -892,6 +915,7 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
const FormFieldData& field,
const gfx::RectF& transformed_box,
bool autoselect_first_suggestion) {
+ SetDataList(field.datalist_values, field.datalist_labels);
external_delegate_->OnQuery(query_id, form, field, transformed_box);
std::vector<Suggestion> suggestions;
@@ -1022,9 +1046,9 @@ void AutofillManager::FillOrPreviewCreditCardForm(
credit_card_, *form_structure, *autofill_field, sync_state_);
}
- FillOrPreviewDataModelForm(
- action, query_id, form, field, credit_card_, /*is_credit_card=*/true,
- /*cvc=*/base::string16(), form_structure, autofill_field);
+ FillOrPreviewDataModelForm(action, query_id, form, field, /*profile=*/nullptr,
+ &credit_card_, /*cvc=*/nullptr, form_structure,
+ autofill_field);
}
void AutofillManager::FillOrPreviewProfileForm(
@@ -1040,22 +1064,11 @@ void AutofillManager::FillOrPreviewProfileForm(
if (action == AutofillDriver::FORM_DATA_ACTION_FILL) {
address_form_event_logger_->OnDidFillSuggestion(
profile, *form_structure, *autofill_field, sync_state_);
-
- // Set up the information needed for an eventual refill of this form.
- if (!form_structure->GetIdentifierForRefill().empty()) {
- auto& entry =
- filling_contexts_map_[form_structure->GetIdentifierForRefill()];
- auto filling_context = std::make_unique<FillingContext>();
- filling_context->temp_data_model = profile;
- filling_context->filled_field_name = autofill_field->unique_name();
- filling_context->original_fill_time = AutofillTickClock::NowTicks();
- entry = std::move(filling_context);
- }
}
- FillOrPreviewDataModelForm(
- action, query_id, form, field, profile, /*is_credit_card=*/false,
- /*cvc=*/base::string16(), form_structure, autofill_field);
+ FillOrPreviewDataModelForm(action, query_id, form, field, &profile,
+ /*credit_card=*/nullptr,
+ /*cvc=*/nullptr, form_structure, autofill_field);
}
void AutofillManager::FillOrPreviewForm(
@@ -1096,9 +1109,9 @@ void AutofillManager::FillCreditCardForm(int query_id,
if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
return;
- FillOrPreviewDataModelForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, query_id, form, field, credit_card,
- /*is_credit_card=*/true, cvc, form_structure, autofill_field);
+ FillOrPreviewDataModelForm(AutofillDriver::FORM_DATA_ACTION_FILL, query_id,
+ form, field, /*profile=*/nullptr, &credit_card,
+ &cvc, form_structure, autofill_field);
}
void AutofillManager::FillProfileForm(const autofill::AutofillProfile& profile,
@@ -1167,11 +1180,13 @@ void AutofillManager::OnDidFillAutofillFormData(const FormData& form,
UpdatePendingForm(form);
- FormStructure* form_structure = nullptr;
std::set<FormType> form_types;
// Find the FormStructure that corresponds to |form|. Use default form type if
// form is not present in our cache, which will happen rarely.
- if (FindCachedForm(form, &form_structure)) {
+
+ FormStructure* form_structure =
+ FindCachedFormByRendererId(form.unique_renderer_id);
+ if (form_structure) {
form_types = form_structure->GetFormTypes();
}
@@ -1354,8 +1369,8 @@ void AutofillManager::SetTestDelegate(AutofillManagerTestDelegate* delegate) {
test_delegate_ = delegate;
}
-void AutofillManager::OnSetDataList(const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) {
+void AutofillManager::SetDataList(const std::vector<base::string16>& values,
+ const std::vector<base::string16>& labels) {
if (!IsValidString16Vector(values) || !IsValidString16Vector(labels) ||
values.size() != labels.size())
return;
@@ -1364,14 +1379,13 @@ void AutofillManager::OnSetDataList(const std::vector<base::string16>& values,
}
void AutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
- FormStructure* form_structure = nullptr;
-
// Look for a cached version of the form. It will be a null pointer if none is
// found, which is fine.
- FormStructure* cached_form = nullptr;
- ignore_result(FindCachedForm(form, &cached_form));
+ FormStructure* cached_form =
+ FindCachedFormByRendererId(form.unique_renderer_id);
- if (!ParseForm(form, cached_form, &form_structure))
+ FormStructure* form_structure = ParseForm(form, cached_form);
+ if (!form_structure)
return;
if (ShouldTriggerRefill(*form_structure))
@@ -1380,21 +1394,23 @@ void AutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
void AutofillManager::OnLoadedServerPredictions(
std::string response,
- const std::vector<std::string>& form_signatures) {
- // Get the current valid FormStructures represented by |form_signatures|.
+ const FormAndFieldSignatures& signatures) {
+ // Get the current valid FormStructures represented by |signatures|.
std::vector<FormStructure*> queried_forms;
- queried_forms.reserve(form_signatures.size());
- for (const std::string& signature : form_signatures) {
- // The |signature| is the direct string representation of the FormSignature.
- // Convert it to a uint64_t to do the lookup.
- FormSignature form_signature;
- FormStructure* form_structure;
- if (base::StringToUint64(signature, &form_signature.value()) &&
- FindCachedForm(form_signature, &form_structure)) {
- queried_forms.push_back(form_structure);
- }
+ queried_forms.reserve(signatures.size());
+ for (const auto& p : signatures) {
+ FindCachedFormsBySignature(p.first, &queried_forms);
}
+ // Each form signature in |signatures| is supposed to be unique, and therefore
+ // appear only once. This ensures that FindCachedFormsBySignature() produces
+ // an output without duplicates in the forms.
+ // TODO(crbug/1064709): |queried_forms| could be a set data structure; their
+ // order should be irrelevant.
+ DCHECK_EQ(queried_forms.size(),
+ std::set<FormStructure*>(queried_forms.begin(), queried_forms.end())
+ .size());
+
// If there are no current forms corresponding to the queried signatures, drop
// the query response.
if (queried_forms.empty())
@@ -1404,10 +1420,12 @@ void AutofillManager::OnLoadedServerPredictions(
if (base::FeatureList::IsEnabled(features::kAutofillUseApi)) {
// Parse response from API.
FormStructure::ParseApiQueryResponse(std::move(response), queried_forms,
+ signatures,
form_interactions_ukm_logger_.get());
} else {
// Parse response from legacy server.
FormStructure::ParseQueryResponse(std::move(response), queried_forms,
+ signatures,
form_interactions_ukm_logger_.get());
}
@@ -1687,15 +1705,25 @@ void AutofillManager::FillOrPreviewDataModelForm(
int query_id,
const FormData& form,
const FormFieldData& field,
- const AutofillDataModel& data_model,
- bool is_credit_card,
- const base::string16& cvc,
+ const AutofillProfile* optional_profile,
+ const CreditCard* optional_credit_card,
+ const base::string16* optional_cvc,
FormStructure* form_structure,
AutofillField* autofill_field,
bool is_refill) {
+ DCHECK(optional_profile || optional_credit_card);
+ DCHECK(optional_credit_card || !optional_cvc);
DCHECK(form_structure);
DCHECK(autofill_field);
+ const AutofillDataModel& data_model = [&]() -> const AutofillDataModel& {
+ if (optional_profile)
+ return *optional_profile;
+ else
+ return *optional_credit_card;
+ }();
+ bool is_credit_card = !!optional_credit_card;
+
LogBuffer buffer;
buffer << "is credit card section: " << is_credit_card << Br{};
buffer << "is refill: " << is_refill << Br{};
@@ -1707,21 +1735,25 @@ void AutofillManager::FillOrPreviewDataModelForm(
FormData result = form;
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);
+ }
+
// Only record the types that are filled for an eventual refill if all the
// following are satisfied:
// The refilling feature is enabled.
// 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.
- // This is not a credit card fill.
FillingContext* filling_context = nullptr;
auto itr =
filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
if (itr != filling_contexts_map_.end())
filling_context = itr->second.get();
bool could_attempt_refill = filling_context != nullptr &&
- !filling_context->attempted_refill &&
- !is_refill && !is_credit_card;
+ !filling_context->attempted_refill && !is_refill;
// Count the number of times the value of a specific type was filled into the
// form.
@@ -1796,11 +1828,12 @@ void AutofillManager::FillOrPreviewDataModelForm(
continue;
}
+ ServerFieldType field_type = cached_field->Type().GetStorableType();
+
// Don't fill expired cards expiration date.
- if (data_util::IsCreditCardExpirationType(
- cached_field->Type().GetStorableType()) &&
- static_cast<const CreditCard*>(&data_model)
- ->IsExpired(AutofillClock::Now())) {
+ if (data_util::IsCreditCardExpirationType(field_type) &&
+ (!optional_credit_card ||
+ optional_credit_card->IsExpired(AutofillClock::Now()))) {
buffer << Tr{} << field_number
<< "Skipped: don't fill expiration date of expired cards";
continue;
@@ -1808,7 +1841,6 @@ void AutofillManager::FillOrPreviewDataModelForm(
// A field with a specific type is only allowed to be filled a limited
// number of times given by |TypeValueFormFillingLimit(field_type)|.
- const auto field_type = cached_field->Type().GetStorableType();
if (type_filling_count[field_type] >=
TypeValueFormFillingLimit(field_type)) {
buffer << Tr{} << field_number
@@ -1831,12 +1863,14 @@ void AutofillManager::FillOrPreviewDataModelForm(
bool has_value_before = !result.fields[i].value.empty();
bool is_autofilled_before = result.fields[i].is_autofilled;
+ const base::string16 kEmptyCvc{};
std::string failure_to_fill; // Reason for failing to fill.
// Fill the non-empty value from |data_model| into the result vector, which
// will be sent to the renderer.
FillFieldWithValue(
- cached_field, data_model, &result.fields[i], should_notify, cvc,
+ cached_field, data_model, &result.fields[i], should_notify,
+ optional_cvc ? *optional_cvc : kEmptyCvc,
data_util::DetermineGroups(form_structure->GetServerFieldTypes()),
&failure_to_fill);
@@ -1880,9 +1914,9 @@ std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
const FormData& form) {
// Ignore forms not present in our cache. These are typically forms with
// wonky JavaScript that also makes them not auto-fillable.
- FormStructure* cached_submitted_form;
- if (!FindCachedForm(form, &cached_submitted_form) ||
- !ShouldUploadForm(*cached_submitted_form)) {
+ FormStructure* cached_submitted_form =
+ FindCachedFormByRendererId(form.unique_renderer_id);
+ if (!cached_submitted_form || !ShouldUploadForm(*cached_submitted_form)) {
return nullptr;
}
@@ -2425,8 +2459,9 @@ bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) {
}
void AutofillManager::TriggerRefill(const FormData& form) {
- FormStructure* form_structure = nullptr;
- if (!FindCachedForm(form, &form_structure))
+ FormStructure* form_structure =
+ FindCachedFormByRendererId(form.unique_renderer_id);
+ if (!form_structure)
return;
DCHECK(form_structure);
@@ -2460,12 +2495,23 @@ void AutofillManager::TriggerRefill(const FormData& form) {
return;
FormFieldData field = *autofill_field;
- base::string16 cvc;
- FillOrPreviewDataModelForm(
- AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
- /*query_id=*/-1, form, field, filling_context->temp_data_model,
- /*is_credit_card=*/false, cvc, form_structure, autofill_field,
- /*is_refill=*/true);
+ if (filling_context->credit_card) {
+ FillOrPreviewDataModelForm(
+ AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
+ /*query_id=*/-1, form, field,
+ /*profile=*/nullptr, &filling_context->credit_card.value().first,
+ &filling_context->credit_card.value().second, form_structure,
+ autofill_field,
+ /*is_refill=*/true);
+ }
+ if (filling_context->profile) {
+ FillOrPreviewDataModelForm(
+ AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
+ /*query_id=*/-1, form, field, &filling_context->profile.value(),
+ /*credic_card=*/nullptr, /*cvc=*/nullptr, form_structure,
+ autofill_field,
+ /*is_refill=*/true);
+ }
}
void AutofillManager::GetAvailableSuggestions(
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index ec2e22519c7..71fb7e85857 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -17,6 +17,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -228,8 +229,6 @@ class AutofillManager : public AutofillHandler,
void OnDidPreviewAutofillFormData() override;
void OnDidEndTextFieldEditing() override;
void OnHidePopup() override;
- void OnSetDataList(const std::vector<base::string16>& values,
- const std::vector<base::string16>& labels) override;
void SelectFieldOptionsDidChange(const FormData& form) override;
void Reset() override;
@@ -280,8 +279,8 @@ class AutofillManager : public AutofillHandler,
// purposes only.
void OnLoadedServerPredictionsForTest(
std::string response,
- const std::vector<std::string>& form_signatures) {
- OnLoadedServerPredictions(response, form_signatures);
+ const FormAndFieldSignatures& signatures) {
+ OnLoadedServerPredictions(response, signatures);
}
// A public wrapper that calls |MakeFrontendID| for testing purposes only.
@@ -386,17 +385,25 @@ class AutofillManager : public AutofillHandler,
private:
// Keeps track of the filling context for a form, used to make refill attemps.
struct FillingContext {
- FillingContext();
+ // |optional_profile| or |optional_credit_card| must be non-null.
+ // If |optional_credit_card| is non-null, |optional_cvc| may be non-null.
+ FillingContext(const AutofillField& field,
+ const AutofillProfile* optional_profile,
+ const CreditCard* optional_credit_card,
+ const base::string16* optional_cvc);
~FillingContext();
// Whether a refill attempt was made.
bool attempted_refill = false;
- // The profile that was used for the initial fill.
- AutofillProfile temp_data_model;
+ // The profile or credit card that was used for the initial fill.
+ // The std::string associated with the credit card is the CVC, which may be
+ // empty.
+ const base::Optional<AutofillProfile> profile;
+ const base::Optional<std::pair<CreditCard, base::string16>> credit_card;
// The name of the field that was initially filled.
- base::string16 filled_field_name;
- // The time at which the initial fill occured.
- base::TimeTicks original_fill_time;
+ const base::string16 filled_field_name;
+ // The time at which the initial fill occurred.
+ const base::TimeTicks original_fill_time;
// The timer used to trigger a refill.
base::OneShotTimer on_refill_timer;
// The field type groups that were initially filled.
@@ -430,7 +437,7 @@ class AutofillManager : public AutofillHandler,
// AutofillDownloadManager::Observer:
void OnLoadedServerPredictions(
std::string response,
- const std::vector<std::string>& form_signatures) override;
+ const FormAndFieldSignatures& signatures) override;
// CreditCardAccessManager::Accessor
void OnCreditCardFetched(
@@ -477,9 +484,9 @@ class AutofillManager : public AutofillHandler,
int query_id,
const FormData& form,
const FormFieldData& field,
- const AutofillDataModel& data_model,
- bool is_credit_card,
- const base::string16& cvc,
+ const AutofillProfile* optional_profile,
+ const CreditCard* optional_credit_card,
+ const base::string16* optional_cvc,
FormStructure* form_structure,
AutofillField* autofill_field,
bool is_refill = false);
@@ -596,6 +603,8 @@ class AutofillManager : public AutofillHandler,
FormEventLoggerBase* GetEventFormLogger(
FieldTypeGroup field_type_group) const;
+ void SetDataList(const std::vector<base::string16>& values,
+ const std::vector<base::string16>& labels);
AutofillClient* const client_;
LogManager* log_manager_;
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index ec5ccdf8e0e..79f827e5c8e 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -96,7 +96,6 @@ using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
using features::kAutofillEnforceMinRequiredFieldsForQuery;
using features::kAutofillEnforceMinRequiredFieldsForUpload;
using features::kAutofillRestrictUnownedFieldsToFormlessCheckout;
-using mojom::ButtonTitleType;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
@@ -832,6 +831,7 @@ TEST_F(AutofillManagerTest, OnFormsSeen_DifferentFormStructures) {
// Different form structure.
FormData form2;
+ form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("MyForm");
form2.url = GURL("https://myform.com/form.html");
form2.action = GURL("https://myform.com/submit.html");
@@ -862,6 +862,7 @@ TEST_F(AutofillManagerTest, OnFormsSeen_SendAutofillTypePredictionsToRenderer) {
FormData form2;
FormFieldData field;
test::CreateTestFormField("Querty", "qwerty", "", "text", &field);
+ form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("NonQueryable");
form2.url = form1.url;
form2.action = GURL("https://myform.com/submit.html");
@@ -4716,6 +4717,9 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillDisabled) {
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
+ external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ autofill_manager_.get(), autofill_driver_.get(),
+ /*call_parent_methods=*/false);
autofill_manager_->SetExternalDelegate(external_delegate_.get());
// Set up our form data.
@@ -4742,6 +4746,9 @@ TEST_F(AutofillManagerTest,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
+ external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ autofill_manager_.get(), autofill_driver_.get(),
+ /*call_parent_methods=*/false);
autofill_manager_->SetExternalDelegate(external_delegate_.get());
// Set up our form data.
@@ -4812,6 +4819,9 @@ TEST_F(AutofillManagerTest,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
+ external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ autofill_manager_.get(), autofill_driver_.get(),
+ /*call_parent_methods=*/false);
autofill_manager_->SetExternalDelegate(external_delegate_.get());
// Set up our form data.
@@ -4840,6 +4850,9 @@ TEST_F(AutofillManagerTest,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
+ external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ autofill_manager_.get(), autofill_driver_.get(),
+ /*call_parent_methods=*/false);
autofill_manager_->SetExternalDelegate(external_delegate_.get());
// Set up our form data.
@@ -4890,6 +4903,9 @@ TEST_F(AutofillManagerTest, AutocompleteOffRespectedForAutocomplete) {
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
+ external_delegate_ = std::make_unique<TestAutofillExternalDelegate>(
+ autofill_manager_.get(), autofill_driver_.get(),
+ /*call_parent_methods=*/false);
autofill_manager_->SetExternalDelegate(external_delegate_.get());
EXPECT_CALL(*(autocomplete_history_manager_.get()),
@@ -4947,6 +4963,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromLegacyServer) {
// Similarly, a second form.
FormData form2;
+ form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("MyForm");
form2.url = GURL("http://myform.com/form.html");
form2.action = GURL("http://myform.com/submit.html");
@@ -4981,9 +4998,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromLegacyServer) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- std::vector<std::string> signatures;
- signatures.push_back(form_structure->FormSignatureAsStr());
- signatures.push_back(form_structure2->FormSignatureAsStr());
+ FormAndFieldSignatures signatures =
+ test::GetEncodedSignatures({form_structure, form_structure2});
base::HistogramTester histogram_tester;
autofill_manager_->OnLoadedServerPredictionsForTest(response_string,
@@ -5022,6 +5038,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromApi) {
// First form on the page.
FormData form;
+ form.unique_renderer_id.value() = 1;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
@@ -5045,6 +5062,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromApi) {
// Second form on the page.
FormData form2;
+ form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("MyForm2");
form2.url = GURL("http://myform.com/form.html");
form2.action = GURL("http://myform.com/submit.html");
@@ -5084,8 +5102,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromApi) {
std::string encoded_response_string;
base::Base64Encode(response_string, &encoded_response_string);
- std::vector<std::string> signatures = {form_structure->FormSignatureAsStr(),
- form_structure2->FormSignatureAsStr()};
+ FormAndFieldSignatures signatures =
+ test::GetEncodedSignatures({form_structure, form_structure2});
// Run method under test.
base::HistogramTester histogram_tester;
@@ -5127,6 +5145,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) {
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
form_structure->DetermineHeuristicTypes();
+ FormAndFieldSignatures signatures =
+ test::GetEncodedSignatures(*form_structure);
autofill_manager_->AddSeenFormStructure(
std::unique_ptr<TestFormStructure>(form_structure));
@@ -5146,9 +5166,6 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) {
std::string response_string_base64;
base::Base64Encode(response_string, &response_string_base64);
- std::vector<std::string> signatures;
- signatures.push_back(form_structure->FormSignatureAsStr());
-
// Reset the manager (such as during a navigation).
autofill_manager_->Reset();
@@ -5209,12 +5226,9 @@ TEST_F(AutofillManagerTest, DetermineHeuristicsWithOverallPrediction) {
std::string response_string_base64;
base::Base64Encode(response_string, &response_string_base64);
- std::vector<std::string> signatures;
- signatures.push_back(form_structure->FormSignatureAsStr());
-
base::HistogramTester histogram_tester;
- autofill_manager_->OnLoadedServerPredictionsForTest(response_string_base64,
- signatures);
+ autofill_manager_->OnLoadedServerPredictionsForTest(
+ response_string_base64, test::GetEncodedSignatures(*form_structure));
// Verify that FormStructure::ParseQueryResponse was called (here and below).
histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_RESPONSE_RECEIVED,
@@ -7641,8 +7655,9 @@ TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressOnly) {
// Create a form with name and address fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7684,8 +7699,9 @@ TEST_F(AutofillManagerTest,
// Create a form with address fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7726,8 +7742,9 @@ TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_ContactOnly) {
// Create a form with name and contact fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7768,8 +7785,9 @@ TEST_F(AutofillManagerTest,
// Create a form with contact fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7809,8 +7827,9 @@ TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_Other) {
// Create a form with name fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7850,8 +7869,9 @@ TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressPlusEmail) {
// Create a form with name, address, and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7901,8 +7921,9 @@ TEST_F(AutofillManagerTest,
// Create a form with address and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -7949,8 +7970,9 @@ TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressPlusPhone) {
// Create a form with name fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -8000,8 +8022,9 @@ TEST_F(AutofillManagerTest,
// Create a form with name, address, and phone fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -8049,8 +8072,9 @@ TEST_F(AutofillManagerTest,
// Create a form with name, address, phone, and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
@@ -8101,8 +8125,9 @@ TEST_F(AutofillManagerTest,
// Create a form with address, phone, and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
- form.button_titles = {std::make_pair(
- ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
form.main_frame_origin =
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index ee304fed0c1..9cdccda5142 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -20,6 +20,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
@@ -110,8 +111,9 @@ std::string PreviousSaveCreditCardPromptUserDecisionToString(
// accessed from the unit test file. It is not exposed in the header file,
// however, because it is not intended for consumption outside of the metrics
// implementation.
-int GetFieldTypeGroupMetric(ServerFieldType field_type,
- AutofillMetrics::FieldTypeQualityMetric metric) {
+int GetFieldTypeGroupPredictionQualityMetric(
+ ServerFieldType field_type,
+ AutofillMetrics::FieldTypeQualityMetric metric) {
DCHECK_LT(metric, AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
FieldTypeGroupForMetrics group = GROUP_AMBIGUOUS;
@@ -227,6 +229,26 @@ int GetFieldTypeGroupMetric(ServerFieldType field_type,
return (group << 8) | metric;
}
+// This function encodes the integer value of a |ServerFieldType| and the
+// metric value of an |AutofilledFieldUserEdtingStatus| into a 16 bit integer.
+// The lower four bits are used to encode the editing status and the higher
+// 12 bits are used to encode the field type.
+int GetFieldTypeUserEditStatusMetric(
+ ServerFieldType server_type,
+ AutofillMetrics::AutofilledFieldUserEditingStatusMetric metric) {
+ static_assert(ServerFieldType::MAX_VALID_FIELD_TYPE <= (UINT16_MAX >> 4),
+ "Autofill::ServerTypes value needs more than 12 bits.");
+
+ static_assert(
+ static_cast<int>(
+ AutofillMetrics::AutofilledFieldUserEditingStatusMetric::kMaxValue) <=
+ (UINT16_MAX >> 12),
+ "AutofillMetrics::AutofilledFieldUserEditingStatusMetric value needs "
+ "more than 4 bits");
+
+ return (server_type << 4) | static_cast<int>(metric);
+}
+
namespace {
const char* GetQualityMetricPredictionSource(
@@ -355,9 +377,9 @@ void LogPredictionQualityMetricsForFieldsOnlyFilledWhenFocused(
DVLOG(2) << "TRUE POSITIVE";
base::UmaHistogramSparse(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE);
- base::UmaHistogramSparse(
- type_specific_histogram,
- GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE));
+ base::UmaHistogramSparse(type_specific_histogram,
+ GetFieldTypeGroupPredictionQualityMetric(
+ actual_type, AutofillMetrics::TRUE_POSITIVE));
if (log_rationalization_metrics) {
bool duplicated_filling = DuplicatedFilling(form, field);
base::UmaHistogramSparse(
@@ -378,8 +400,8 @@ void LogPredictionQualityMetricsForFieldsOnlyFilledWhenFocused(
if (predicted_type != UNKNOWN_TYPE)
base::UmaHistogramSparse(
type_specific_histogram,
- GetFieldTypeGroupMetric(predicted_type,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH));
+ GetFieldTypeGroupPredictionQualityMetric(
+ predicted_type, AutofillMetrics::FALSE_NEGATIVE_MISMATCH));
if (log_rationalization_metrics) {
// Logging RATIONALIZATION_OK despite of type mismatch here because autofill
// would have got it wrong with or without rationalization. Rationalization
@@ -418,9 +440,9 @@ void LogPredictionQualityMetricsForCommonFields(
// predict that type with which the field was filled.
base::UmaHistogramSparse(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE);
- base::UmaHistogramSparse(
- type_specific_histogram,
- GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE));
+ base::UmaHistogramSparse(type_specific_histogram,
+ GetFieldTypeGroupPredictionQualityMetric(
+ actual_type, AutofillMetrics::TRUE_POSITIVE));
return;
}
@@ -435,8 +457,9 @@ void LogPredictionQualityMetricsForCommonFields(
: (is_ambiguous ? AutofillMetrics::FALSE_POSITIVE_AMBIGUOUS
: AutofillMetrics::FALSE_POSITIVE_UNKNOWN));
base::UmaHistogramSparse(aggregate_histogram, metric);
- base::UmaHistogramSparse(type_specific_histogram,
- GetFieldTypeGroupMetric(predicted_type, metric));
+ base::UmaHistogramSparse(
+ type_specific_histogram,
+ GetFieldTypeGroupPredictionQualityMetric(predicted_type, metric));
return;
}
@@ -449,8 +472,8 @@ void LogPredictionQualityMetricsForCommonFields(
AutofillMetrics::FALSE_NEGATIVE_UNKNOWN);
base::UmaHistogramSparse(
type_specific_histogram,
- GetFieldTypeGroupMetric(actual_type,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN));
+ GetFieldTypeGroupPredictionQualityMetric(
+ actual_type, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN));
return;
}
@@ -465,12 +488,12 @@ void LogPredictionQualityMetricsForCommonFields(
AutofillMetrics::FALSE_NEGATIVE_MISMATCH);
base::UmaHistogramSparse(
type_specific_histogram,
- GetFieldTypeGroupMetric(actual_type,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH));
+ GetFieldTypeGroupPredictionQualityMetric(
+ actual_type, AutofillMetrics::FALSE_NEGATIVE_MISMATCH));
base::UmaHistogramSparse(
type_specific_histogram,
- GetFieldTypeGroupMetric(predicted_type,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH));
+ GetFieldTypeGroupPredictionQualityMetric(
+ predicted_type, AutofillMetrics::FALSE_POSITIVE_MISMATCH));
}
// Logs field type prediction quality metrics. The primary histogram name is
@@ -690,6 +713,121 @@ void AutofillMetrics::LogSaveCardRequestExpirationDateReasonMetric(
}
// static
+void AutofillMetrics::LogSaveCardPromptOfferMetric(
+ SaveCardPromptOfferMetric metric,
+ bool is_uploading,
+ bool is_reshow,
+ AutofillClient::SaveCreditCardOptions options,
+ int previous_save_credit_card_prompt_user_decision,
+ security_state::SecurityLevel security_level,
+ AutofillSyncSigninState sync_state) {
+ DCHECK_LT(metric, NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+ std::string base_histogram_name = "Autofill.SaveCreditCardPromptOffer";
+ std::string destination = is_uploading ? ".Upload" : ".Local";
+ std::string show = is_reshow ? ".Reshows" : ".FirstShow";
+ std::string metric_with_destination_and_show =
+ base_histogram_name + destination + show;
+ base::UmaHistogramEnumeration(metric_with_destination_and_show, metric,
+ NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + GetMetricsSyncStateSuffix(sync_state),
+ metric, NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+
+ if (options.should_request_name_from_user) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".RequestingCardholderName", metric,
+ NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+ }
+ if (options.should_request_expiration_date_from_user) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".RequestingExpirationDate", metric,
+ NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+ }
+ if (options.has_non_focusable_field) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".FromNonFocusableForm", metric,
+ NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+ }
+ if (options.from_dynamic_change_form) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".FromDynamicChangeForm", metric,
+ NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+ }
+
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show +
+ PreviousSaveCreditCardPromptUserDecisionToString(
+ previous_save_credit_card_prompt_user_decision),
+ metric, NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+
+ if (security_level != security_state::SecurityLevel::SECURITY_LEVEL_COUNT) {
+ base::UmaHistogramEnumeration(
+ security_state::GetSecurityLevelHistogramName(
+ base_histogram_name + destination, security_level),
+ metric, NUM_SAVE_CARD_PROMPT_OFFER_METRICS);
+ }
+}
+
+// static
+void AutofillMetrics::LogSaveCardPromptResultMetric(
+ SaveCardPromptResultMetric metric,
+ bool is_uploading,
+ bool is_reshow,
+ AutofillClient::SaveCreditCardOptions options,
+ int previous_save_credit_card_prompt_user_decision,
+ security_state::SecurityLevel security_level,
+ AutofillSyncSigninState sync_state) {
+ DCHECK_LT(metric, NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+ std::string base_histogram_name = "Autofill.SaveCreditCardPromptResult";
+ std::string destination = is_uploading ? ".Upload" : ".Local";
+ std::string show = is_reshow ? ".Reshows" : ".FirstShow";
+ std::string metric_with_destination_and_show =
+ base_histogram_name + destination + show;
+
+ base::UmaHistogramEnumeration(metric_with_destination_and_show, metric,
+ NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + GetMetricsSyncStateSuffix(sync_state),
+ metric, NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+
+ if (options.should_request_name_from_user) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".RequestingCardholderName", metric,
+ NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+ }
+ if (options.should_request_expiration_date_from_user) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".RequestingExpirationDate", metric,
+ NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+ }
+ if (options.has_non_focusable_field) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".FromNonFocusableForm", metric,
+ NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+ }
+ if (options.from_dynamic_change_form) {
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show + ".FromDynamicChangeForm", metric,
+ NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+ }
+
+ base::UmaHistogramEnumeration(
+ metric_with_destination_and_show +
+ PreviousSaveCreditCardPromptUserDecisionToString(
+ previous_save_credit_card_prompt_user_decision),
+ metric, NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+
+ if (security_level != security_state::SecurityLevel::SECURITY_LEVEL_COUNT) {
+ base::UmaHistogramEnumeration(
+ security_state::GetSecurityLevelHistogramName(
+ base_histogram_name + destination, security_level),
+ metric, NUM_SAVE_CARD_PROMPT_RESULT_METRICS);
+ }
+}
+
+// static
void AutofillMetrics::LogSaveCardPromptMetric(
SaveCardPromptMetric metric,
bool is_uploading,
@@ -761,6 +899,12 @@ void AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
}
// static
+void AutofillMetrics::LogCreditCardUploadLegalMessageLinkClicked() {
+ base::RecordAction(base::UserMetricsAction(
+ "Autofill_CreditCardUpload_LegalMessageLinkClicked"));
+}
+
+// static
void AutofillMetrics::LogCreditCardUploadFeedbackMetric(
CreditCardUploadFeedbackMetric metric) {
DCHECK_LT(metric, NUM_CREDIT_CARD_UPLOAD_FEEDBACK_METRICS);
@@ -1262,6 +1406,49 @@ void AutofillMetrics::LogOverallPredictionQualityMetrics(
true /*log_rationalization_metrics*/);
}
+void AutofillMetrics::LogEditedAutofilledFieldAtSubmission(
+ FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ const FormStructure& form,
+ const AutofillField& field) {
+ const std::string aggregate_histogram =
+ "Autofill.EditedAutofilledFieldAtSubmission.Aggregate";
+ const std::string type_specific_histogram =
+ "Autofill.EditedAutofilledFieldAtSubmission.ByFieldType";
+
+ AutofilledFieldUserEditingStatusMetric editing_metric =
+ field.previously_autofilled()
+ ? AutofilledFieldUserEditingStatusMetric::AUTOFILLED_FIELD_WAS_EDITED
+ : AutofilledFieldUserEditingStatusMetric::
+ AUTOFILLED_FIELD_WAS_NOT_EDITED;
+
+ // Record the aggregated UMA statistics.
+ base::UmaHistogramEnumeration(aggregate_histogram, editing_metric);
+
+ // Record the type specific UMA statistics.
+ base::UmaHistogramSparse(type_specific_histogram,
+ GetFieldTypeUserEditStatusMetric(
+ field.Type().GetStorableType(), editing_metric));
+
+ // Record the UMA statistics spliced by the autocomplete attribute value.
+ FormType form_type =
+ FormTypes::FieldTypeGroupToFormType(field.Type().group());
+ if (form_type == ADDRESS_FORM || form_type == CREDIT_CARD_FORM) {
+ bool autocomplete_off = field.autocomplete_attribute == "off";
+ const std::string autocomplete_histogram = base::StrCat(
+ {"Autofill.Autocomplete.", autocomplete_off ? "Off" : "NotOff",
+ ".EditedAutofilledFieldAtSubmission.",
+ form_type == ADDRESS_FORM ? "Address" : "CreditCard"});
+ base::UmaHistogramEnumeration(autocomplete_histogram, editing_metric);
+ }
+
+ // If the field was edited, record the event to UKM.
+ if (editing_metric ==
+ AutofilledFieldUserEditingStatusMetric::AUTOFILLED_FIELD_WAS_EDITED) {
+ form_interactions_ukm_logger->LogEditedAutofilledFieldAtSubmission(form,
+ field);
+ }
+}
+
// static
void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) {
DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS);
@@ -1481,7 +1668,9 @@ void AutofillMetrics::LogStoredCreditCardMetrics(
const std::vector<std::unique_ptr<CreditCard>>& server_cards,
base::TimeDelta disused_data_threshold) {
size_t num_local_cards = 0;
+ size_t num_local_cards_with_nickname = 0;
size_t num_masked_cards = 0;
+ size_t num_masked_cards_with_nickname = 0;
size_t num_unmasked_cards = 0;
size_t num_disused_local_cards = 0;
size_t num_disused_masked_cards = 0;
@@ -1513,6 +1702,8 @@ void AutofillMetrics::LogStoredCreditCardMetrics(
days_since_last_use);
num_local_cards += 1;
num_disused_local_cards += disused_delta;
+ if (card->HasValidNickname())
+ num_local_cards_with_nickname += 1;
break;
case CreditCard::MASKED_SERVER_CARD:
UMA_HISTOGRAM_COUNTS_1000(
@@ -1523,6 +1714,8 @@ void AutofillMetrics::LogStoredCreditCardMetrics(
days_since_last_use);
num_masked_cards += 1;
num_disused_masked_cards += disused_delta;
+ if (card->HasValidNickname())
+ num_masked_cards_with_nickname += 1;
break;
case CreditCard::FULL_SERVER_CARD:
UMA_HISTOGRAM_COUNTS_1000(
@@ -1549,10 +1742,15 @@ void AutofillMetrics::LogStoredCreditCardMetrics(
UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount", num_cards);
UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Local",
num_local_cards);
+ UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Local.WithNickname",
+ num_local_cards_with_nickname);
UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Server",
num_server_cards);
UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Server.Masked",
num_masked_cards);
+ UMA_HISTOGRAM_COUNTS_1000(
+ "Autofill.StoredCreditCardCount.Server.Masked.WithNickname",
+ num_masked_cards_with_nickname);
UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Server.Unmasked",
num_unmasked_cards);
@@ -1953,6 +2151,19 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogDidFillSuggestion(
.Record(ukm_recorder_);
}
+void AutofillMetrics::FormInteractionsUkmLogger::
+ LogEditedAutofilledFieldAtSubmission(const FormStructure& form,
+ const AutofillField& field) {
+ if (!CanLog())
+ return;
+
+ ukm::builders::Autofill_EditedAutofilledFieldAtSubmission(source_id_)
+ .SetFieldSignature(HashFieldSignature(field.GetFieldSignature()))
+ .SetFormSignature(HashFormSignature(form.form_signature()))
+ .SetOverallType(static_cast<int64_t>(field.Type().GetStorableType()))
+ .Record(ukm_recorder_);
+}
+
void AutofillMetrics::FormInteractionsUkmLogger::LogTextFieldDidChange(
const FormStructure& form,
const AutofillField& field) {
@@ -2211,4 +2422,10 @@ void AutofillMetrics::
"Autofill.AddressProfileImportCountrySpecificFieldRequirements", metric);
}
+// static
+void AutofillMetrics::LogAddressFormImportStatustMetric(
+ AutofillMetrics::AddressProfileImportStatusMetric metric) {
+ base::UmaHistogramEnumeration("Autofill.AddressProfileImportStatus", metric);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index 124cac7c810..68dcd8aebd3 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -135,14 +135,14 @@ class AutofillMetrics {
enum InfoBarMetric {
INFOBAR_SHOWN = 0, // We showed an infobar, e.g. prompting to save credit
- // card info.
- INFOBAR_ACCEPTED, // The user explicitly accepted the infobar.
- INFOBAR_DENIED, // The user explicitly denied the infobar.
- INFOBAR_IGNORED, // The user completely ignored the infobar (logged on
- // tab close).
+ // card info.
+ INFOBAR_ACCEPTED, // The user explicitly accepted the infobar.
+ INFOBAR_DENIED, // The user explicitly denied the infobar.
+ INFOBAR_IGNORED, // The user completely ignored the infobar (logged on
+ // tab close).
INFOBAR_NOT_SHOWN_INVALID_LEGAL_MESSAGE, // We didn't show the infobar
- // because the provided legal
- // message was invalid.
+ // because the provided legal
+ // message was invalid.
NUM_INFO_BAR_METRICS,
};
@@ -233,6 +233,30 @@ class AutofillMetrics {
kMaxValue = kExpirationDatePresentButExpired,
};
+ // Metrics to track event when the save card prompt is offered.
+ enum SaveCardPromptOfferMetric {
+ // The prompt is actually shown.
+ SAVE_CARD_PROMPT_SHOWN,
+ // The prompt is not shown because the prompt has been declined by the user
+ // too many times.
+ SAVE_CARD_PROMPT_NOT_SHOWN_MAX_STRIKES_REACHED,
+ NUM_SAVE_CARD_PROMPT_OFFER_METRICS,
+ };
+
+ enum SaveCardPromptResultMetric {
+ // The user explicitly accepted the prompt by clicking the ok button.
+ SAVE_CARD_PROMPT_ACCEPTED,
+ // The user explicitly cancelled the prompt by clicking the cancel button.
+ SAVE_CARD_PROMPT_CANCELLED,
+ // The user explicitly closed the prompt with the close button or ESC.
+ SAVE_CARD_PROMPT_CLOSED,
+ // The user did not interact with the prompt.
+ SAVE_CARD_PROMPT_NOT_INTERACTED,
+ // The prompt lost focus and was deactivated.
+ SAVE_CARD_PROMPT_LOST_FOCUS,
+ NUM_SAVE_CARD_PROMPT_RESULT_METRICS,
+ };
+
// Metrics to measure user interaction with the save credit card prompt.
//
// SAVE_CARD_PROMPT_DISMISS_FOCUS is not stored explicitly, but can be
@@ -244,7 +268,7 @@ class AutofillMetrics {
// location bar icon being clicked while bubble is hidden (reshows).
SAVE_CARD_PROMPT_SHOW_REQUESTED,
// The prompt was shown successfully.
- SAVE_CARD_PROMPT_SHOWN,
+ SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
// The prompt was not shown because the legal message was invalid.
SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE,
// The user explicitly accepted the prompt.
@@ -966,6 +990,21 @@ class AutofillMetrics {
kMaxValue = LINE1_ZIP_STATE_CITY_REQUIREMENT_VIOLATED,
};
+ // To record if the value in an autofilled field was edited by the user.
+ enum class AutofilledFieldUserEditingStatusMetric {
+ AUTOFILLED_FIELD_WAS_EDITED = 0,
+ AUTOFILLED_FIELD_WAS_NOT_EDITED = 1,
+ kMaxValue = AUTOFILLED_FIELD_WAS_NOT_EDITED,
+ };
+
+ // Represent the overall status of a profile import.
+ enum class AddressProfileImportStatusMetric {
+ NO_IMPORT = 0,
+ REGULAR_IMPORT = 1,
+ SECTION_UNION_IMPORT = 2,
+ kMaxValue = SECTION_UNION_IMPORT,
+ };
+
// Utility to log URL keyed form interaction events.
class FormInteractionsUkmLogger {
public:
@@ -999,6 +1038,8 @@ class AutofillMetrics {
const AutofillField& field);
void LogTextFieldDidChange(const FormStructure& form,
const AutofillField& field);
+ void LogEditedAutofilledFieldAtSubmission(const FormStructure& form,
+ const AutofillField& field);
void LogFieldFillStatus(const FormStructure& form,
const AutofillField& field,
QualityMetricType metric_type);
@@ -1107,6 +1148,22 @@ class AutofillMetrics {
static void LogCreditCardFillingInfoBarMetric(InfoBarMetric metric);
static void LogSaveCardRequestExpirationDateReasonMetric(
SaveCardRequestExpirationDateReasonMetric metric);
+ static void LogSaveCardPromptOfferMetric(
+ SaveCardPromptOfferMetric metric,
+ bool is_uploading,
+ bool is_reshow,
+ AutofillClient::SaveCreditCardOptions options,
+ int previous_save_credit_card_prompt_user_decision,
+ security_state::SecurityLevel security_level,
+ AutofillSyncSigninState sync_state);
+ static void LogSaveCardPromptResultMetric(
+ SaveCardPromptResultMetric metric,
+ bool is_uploading,
+ bool is_reshow,
+ AutofillClient::SaveCreditCardOptions options,
+ int previous_save_credit_card_prompt_user_decision,
+ security_state::SecurityLevel security_level,
+ AutofillSyncSigninState sync_state);
static void LogSaveCardPromptMetric(
SaveCardPromptMetric metric,
bool is_uploading,
@@ -1119,6 +1176,7 @@ class AutofillMetrics {
SaveCardPromptMetric metric,
bool is_uploading,
security_state::SecurityLevel security_level);
+ static void LogCreditCardUploadLegalMessageLinkClicked();
static void LogCreditCardUploadFeedbackMetric(
CreditCardUploadFeedbackMetric metric);
static void LogManageCardsPromptMetric(ManageCardsPromptMetric metric,
@@ -1534,6 +1592,15 @@ class AutofillMetrics {
bool is_city_missing,
bool is_line1_missing);
+ // Records if an autofilled field of a specific type was edited by the user.
+ static void LogEditedAutofilledFieldAtSubmission(
+ FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ const FormStructure& form,
+ const AutofillField& field);
+
+ static void LogAddressFormImportStatustMetric(
+ AddressProfileImportStatusMetric metric);
+
static const char* GetMetricsSyncStateSuffix(
AutofillSyncSigninState sync_state);
@@ -1545,6 +1612,11 @@ class AutofillMetrics {
DISALLOW_IMPLICIT_CONSTRUCTORS(AutofillMetrics);
};
-} // namespace autofill
+#if defined(UNIT_TEST)
+int GetFieldTypeUserEditStatusMetric(
+ ServerFieldType server_type,
+ AutofillMetrics::AutofilledFieldUserEditingStatusMetric metric);
+#endif
+} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METRICS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index 5fad6416589..f5c0ffec08d 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -51,6 +51,7 @@
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/test_sync_service.h"
@@ -100,6 +101,8 @@ using UkmFormSubmittedType = ukm::builders::Autofill_FormSubmitted;
using UkmFieldTypeValidationType = ukm::builders::Autofill_FieldTypeValidation;
using UkmFieldFillStatusType = ukm::builders::Autofill_FieldFillStatus;
using UkmFormEventType = ukm::builders::Autofill_FormEvent;
+using UkmEditedAutofilledFieldAtSubmission =
+ ukm::builders::Autofill_EditedAutofilledFieldAtSubmission;
using ExpectedUkmMetricsRecord = std::vector<std::pair<const char*, int64_t>>;
using ExpectedUkmMetrics = std::vector<ExpectedUkmMetricsRecord>;
@@ -117,6 +120,13 @@ FieldSignature Collapse(FieldSignature sig) {
return FieldSignature(sig.value() % 1021);
}
+// Returns numbers which are distinct from each other within the scope of one
+// test.
+FormRendererId MakeFormRendererId() {
+ static uint32_t counter = 10;
+ return FormRendererId(counter++);
+}
+
struct AddressProfileImportRequirementExpectations {
AddressImportRequirements requirement;
bool fulfilled;
@@ -295,8 +305,9 @@ class MockAutofillClient : public TestAutofillClient {
} // namespace
// This is defined in the autofill_metrics.cc implementation file.
-int GetFieldTypeGroupMetric(ServerFieldType field_type,
- AutofillMetrics::FieldTypeQualityMetric metric);
+int GetFieldTypeGroupPredictionQualityMetric(
+ ServerFieldType field_type,
+ AutofillMetrics::FieldTypeQualityMetric metric);
class AutofillMetricsTest : public testing::Test {
public:
@@ -615,6 +626,7 @@ INSTANTIATE_TEST_SUITE_P(AutofillMetricsTest,
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");
@@ -681,48 +693,50 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
// Match:
histogram_tester.ExpectBucketCount(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE, 2);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1);
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::TRUE_POSITIVE),
+ 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_CITY_AND_NUMBER,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_CITY_AND_NUMBER, AutofillMetrics::TRUE_POSITIVE),
1);
// Mismatch:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_NUMBER,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
1);
// False Positive Unknown:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_NUMBER,
- AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
1);
// False Positive Empty:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL,
- AutofillMetrics::FALSE_POSITIVE_EMPTY),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::FALSE_POSITIVE_EMPTY),
1);
// Sanity Check:
@@ -744,33 +758,34 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
// Match:
histogram_tester.ExpectBucketCount(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE, 2);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE),
1);
// Mismatch:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FIRST,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
1);
// False Positive Unknown:
@@ -778,16 +793,16 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS,
- AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
1);
// False Positive Empty:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FIRST,
- AutofillMetrics::FALSE_POSITIVE_EMPTY),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_EMPTY),
1);
// Sanity Check:
@@ -796,6 +811,253 @@ 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);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+ std::string guid(kTestGuid);
+ autofill_manager_->FillOrPreviewForm(
+ AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
+ autofill_manager_->MakeFrontendIDForTest(std::string(), guid));
+
+ // Simulate form submission.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION);
+
+ std::string histogram = "Autofill.AddressProfileImportStatus";
+ 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);
+}
+
+// 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);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+ std::string guid(kTestGuid);
+ autofill_manager_->FillOrPreviewForm(
+ AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
+ autofill_manager_->MakeFrontendIDForTest(std::string(), guid));
+
+ // Simulate form submission.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION);
+
+ std::string histogram = "Autofill.AddressProfileImportStatus";
+ histogram_tester.ExpectBucketCount(
+ histogram,
+ AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT, 1);
+ histogram_tester.ExpectBucketCount(
+ histogram, AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ histogram,
+ AutofillMetrics::AddressProfileImportStatusMetric::SECTION_UNION_IMPORT,
+ 0);
+}
+
+// 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);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+ std::string guid(kTestGuid);
+ autofill_manager_->FillOrPreviewForm(
+ AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
+ autofill_manager_->MakeFrontendIDForTest(std::string(), guid));
+
+ 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);
+
+ 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,
+ 1);
+}
+
// Test that the ProfileImportRequirements are all counted as fulfilled for a
// 'perfect' profile import.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_AllFulfilled) {
@@ -1427,6 +1689,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForRationalizationOk) {
// 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");
@@ -1507,6 +1770,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForRationalizationGood) {
// 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");
@@ -1574,6 +1838,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
// 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");
@@ -1716,6 +1981,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
// 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");
@@ -1765,7 +2031,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
ASSERT_TRUE(response.SerializeToString(&response_string));
FormStructure::ParseQueryResponse(
- response_string, forms,
+ response_string, forms, test::GetEncodedSignatures(forms),
autofill_manager_->form_interactions_ukm_logger_for_test());
ASSERT_EQ(test_ukm_recorder_
@@ -1823,6 +2089,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
// 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");
@@ -1880,7 +2147,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
ASSERT_TRUE(response.SerializeToString(&response_string));
FormStructure::ParseQueryResponse(
- response_string, forms,
+ response_string, forms, test::GetEncodedSignatures(forms),
autofill_manager_->form_interactions_ukm_logger_for_test());
ASSERT_EQ(test_ukm_recorder_
@@ -1960,6 +2227,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForRationalizationBad) {
// 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");
@@ -2026,6 +2294,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForOnlyFillWhenFocusedField) {
// 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");
@@ -2115,16 +2384,18 @@ TEST_F(AutofillMetricsTest,
AutofillMetrics::TRUE_POSITIVE, 4);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1);
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::TRUE_POSITIVE),
+ 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_LINE1,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_LINE1, AutofillMetrics::TRUE_POSITIVE),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_CITY_AND_NUMBER,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_CITY_AND_NUMBER, AutofillMetrics::TRUE_POSITIVE),
2);
// TRUE_NEGATIVE_EMPTY
histogram_tester.ExpectBucketCount(aggregate_histogram,
@@ -2134,8 +2405,8 @@ TEST_F(AutofillMetricsTest,
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
// Sanity Check:
histogram_tester.ExpectTotalCount(aggregate_histogram, 6);
@@ -2156,16 +2427,18 @@ TEST_F(AutofillMetricsTest,
AutofillMetrics::TRUE_POSITIVE, 4);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1);
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::TRUE_POSITIVE),
+ 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_LINE1,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_LINE1, AutofillMetrics::TRUE_POSITIVE),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_CITY_AND_NUMBER,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_CITY_AND_NUMBER, AutofillMetrics::TRUE_POSITIVE),
2);
// TRUE_NEGATIVE_EMPTY
histogram_tester.ExpectBucketCount(aggregate_histogram,
@@ -2175,8 +2448,9 @@ TEST_F(AutofillMetricsTest,
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_CITY_AND_NUMBER,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_CITY_AND_NUMBER,
+ AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
// Sanity Check:
histogram_tester.ExpectTotalCount(aggregate_histogram, 6);
@@ -2327,6 +2601,7 @@ TEST_P(QualityMetricsTest, Classification) {
// 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");
@@ -2466,11 +2741,11 @@ TEST_P(QualityMetricsTest, Classification) {
aggregate_expected_count);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(actual_field_type, metric),
+ GetFieldTypeGroupPredictionQualityMetric(actual_field_type, metric),
expected_count_for_actual_type);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(predicted_type, metric),
+ GetFieldTypeGroupPredictionQualityMetric(predicted_type, metric),
expected_count_for_predicted_type);
}
}
@@ -2502,6 +2777,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
base::HistogramTester histogram_tester;
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");
@@ -2543,6 +2819,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
// 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");
@@ -2612,47 +2889,49 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
// Match:
histogram_tester.ExpectBucketCount(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE, 2);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1);
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::TRUE_POSITIVE),
+ 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE),
1);
// Mismatch:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_NUMBER,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
1);
// False Positives:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL,
- AutofillMetrics::FALSE_POSITIVE_EMPTY),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::FALSE_POSITIVE_EMPTY),
1);
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_NUMBER,
- AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
1);
// Sanity Check:
@@ -2674,33 +2953,34 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
// Match:
histogram_tester.ExpectBucketCount(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE, 2);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER,
- AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE),
1);
// Mismatch:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FIRST,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
1);
// False Positives:
@@ -2708,15 +2988,15 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FIRST,
- AutofillMetrics::FALSE_POSITIVE_EMPTY),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_EMPTY),
1);
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS,
- AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
1);
// Sanity Check:
@@ -2729,6 +3009,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
// on autocomplete attributes present on the fields.
TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
FormData form;
+ form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
@@ -2761,7 +3042,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
TestFormStructure* form_structure_ptr = form_structure.get();
form_structure->DetermineHeuristicTypes();
ASSERT_TRUE(autofill_manager_->mutable_form_structures_for_test()
- ->emplace(form_structure_ptr->form_signature(),
+ ->emplace(form_structure_ptr->unique_renderer_id(),
std::move(form_structure))
.second);
@@ -2785,12 +3066,9 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
std::string encoded_response_string;
base::Base64Encode(response_string, &encoded_response_string);
- std::vector<std::string> signatures;
- signatures.push_back(form_structure_ptr->FormSignatureAsStr());
-
base::HistogramTester histogram_tester;
- autofill_manager_->OnLoadedServerPredictionsForTest(encoded_response_string,
- signatures);
+ autofill_manager_->OnLoadedServerPredictionsForTest(
+ encoded_response_string, test::GetEncodedSignatures(*form_structure_ptr));
// Verify that FormStructure::ParseQueryResponse was called (here and below).
histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
@@ -2819,27 +3097,29 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_ZIP, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
// Match:
histogram_tester.ExpectBucketCount(aggregate_histogram,
AutofillMetrics::TRUE_POSITIVE, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_LAST, AutofillMetrics::TRUE_POSITIVE), 1);
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_LAST, AutofillMetrics::TRUE_POSITIVE),
+ 1);
// Mismatch:
histogram_tester.ExpectBucketCount(
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FIRST,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_MIDDLE,
- AutofillMetrics::FALSE_POSITIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_MIDDLE, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
1);
// Sanity check.
@@ -2852,6 +3132,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
// 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");
@@ -2911,6 +3192,7 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
// 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");
@@ -2948,7 +3230,7 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
SCOPED_TRACE("ADDRESS_HOME_COUNTRY");
histogram_tester.ExpectBucketCount(
histogram_name,
- GetFieldTypeGroupMetric(
+ GetFieldTypeGroupPredictionQualityMetric(
ADDRESS_HOME_COUNTRY,
source == "Overall" ? AutofillMetrics::TRUE_POSITIVE
: AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
@@ -2961,8 +3243,8 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
SCOPED_TRACE("ADDRESS_HOME_ZIP");
histogram_tester.ExpectBucketCount(
histogram_name,
- GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_ZIP, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
}
@@ -2971,10 +3253,10 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
SCOPED_TRACE("PHONE_HOME_WHOLE_NUMBER");
histogram_tester.ExpectBucketCount(
histogram_name,
- GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER,
- source == "Server"
- ? AutofillMetrics::FALSE_NEGATIVE_UNKNOWN
- : AutofillMetrics::TRUE_POSITIVE),
+ GetFieldTypeGroupPredictionQualityMetric(
+ PHONE_HOME_WHOLE_NUMBER,
+ source == "Server" ? AutofillMetrics::FALSE_NEGATIVE_UNKNOWN
+ : AutofillMetrics::TRUE_POSITIVE),
1);
}
@@ -2988,6 +3270,7 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
// 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");
@@ -3052,8 +3335,8 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_STATE,
- AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_STATE, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
1);
// Match:
histogram_tester.ExpectBucketCount(aggregate_histogram,
@@ -3061,23 +3344,25 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
source == "Heuristic" ? 2 : 1);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1);
+ GetFieldTypeGroupPredictionQualityMetric(
+ NAME_FULL, AutofillMetrics::TRUE_POSITIVE),
+ 1);
// Mismatch:
histogram_tester.ExpectBucketCount(aggregate_histogram,
AutofillMetrics::FALSE_NEGATIVE_MISMATCH,
source == "Heuristic" ? 1 : 2);
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(EMAIL_ADDRESS,
- AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ EMAIL_ADDRESS, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
// Source dependent:
histogram_tester.ExpectBucketCount(
by_field_type_histogram,
- GetFieldTypeGroupMetric(ADDRESS_HOME_CITY,
- source == "Heuristic"
- ? AutofillMetrics::TRUE_POSITIVE
- : AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
+ GetFieldTypeGroupPredictionQualityMetric(
+ ADDRESS_HOME_CITY, source == "Heuristic"
+ ? AutofillMetrics::TRUE_POSITIVE
+ : AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
1);
}
}
@@ -3087,6 +3372,7 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
// Construct a fillable form.
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");
@@ -3123,6 +3409,7 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForHeuristics);
// Construct a non-fillable form.
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");
@@ -3150,11 +3437,150 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
"Autofill.StoredProfileCountAtAutofillableFormSubmission", 0);
}
+// Verify that when submitting an autofillable form, the proper tppe of
+// the edited fields is correctly logged to UKM.
+TEST_F(AutofillMetricsTest, TypeOfEditedAutofilledFieldsUkmLogging) {
+ // Construct a fillable form.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.url = GURL("https://example.test/form.html");
+ form.action = GURL("https://example.test/submit.html");
+ form.main_frame_origin =
+ url::Origin::Create(GURL("https://example.test/form.html"));
+
+ 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_FULL);
+
+ test::CreateTestFormField("Autofill Failed", "autofillfailed",
+ "buddy@gmail.com", "text", &field);
+ field.is_autofilled = true;
+ form.fields.push_back(field);
+ heuristic_types.push_back(EMAIL_ADDRESS);
+ server_types.push_back(EMAIL_ADDRESS);
+
+ 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);
+
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ // Verify that there are no counts before form submission.
+
+ EXPECT_EQ(0U, test_ukm_recorder_->entries_count());
+
+ base::HistogramTester histogram_tester;
+ // Simulate text input in the first and second fields.
+ autofill_manager_->OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
+ TimeTicks());
+
+ // Simulate form submission.
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION);
+ ExpectedUkmMetricsRecord name_field_ukm_record{
+ {UkmEditedAutofilledFieldAtSubmission::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[0])).value()},
+ {UkmEditedAutofilledFieldAtSubmission::kFormSignatureName,
+ Collapse(CalculateFormSignature(form)).value()},
+ {UkmEditedAutofilledFieldAtSubmission::kOverallTypeName,
+ static_cast<int64_t>(NAME_FULL)}};
+
+ VerifyUkm(test_ukm_recorder_, form,
+ UkmEditedAutofilledFieldAtSubmission::kEntryName,
+ {name_field_ukm_record});
+}
+
+// Verify that when submitting an autofillable form, the proper tppe of
+// the edited fields is correctly logged to UMA.
+TEST_F(AutofillMetricsTest, TypeOfEditedAutofilledFieldsUmaLogging) {
+ // Construct a fillable form.
+ 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(GURL("http://example_root.com/form.html"));
+
+ 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_FULL);
+
+ test::CreateTestFormField("Autofill Failed", "autofillfailed",
+ "buddy@gmail.com", "text", &field);
+ field.is_autofilled = true;
+ form.fields.push_back(field);
+ heuristic_types.push_back(EMAIL_ADDRESS);
+ server_types.push_back(EMAIL_ADDRESS);
+
+ 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);
+
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ base::HistogramTester histogram_tester;
+ // Simulate text input in the first and second fields.
+ autofill_manager_->OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
+ TimeTicks());
+ autofill_manager_->OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
+ TimeTicks());
+
+ // Simulate form submission.
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION);
+
+ // The |NAME_FULL| field was edited (bucket 112).
+ histogram_tester.ExpectBucketCount(
+ "Autofill.EditedAutofilledFieldAtSubmission.ByFieldType", 112, 1);
+
+ // The |NAME_FULL| field was edited (bucket 144).
+ histogram_tester.ExpectBucketCount(
+ "Autofill.EditedAutofilledFieldAtSubmission.ByFieldType", 144, 1);
+
+ // The |PHONE_HOME_CITY_AND_NUMBER| field was not edited (bucket 209).
+ histogram_tester.ExpectBucketCount(
+ "Autofill.EditedAutofilledFieldAtSubmission.ByFieldType", 209, 1);
+
+ // The aggregated histogram should have two counts on edited fields.
+ histogram_tester.ExpectBucketCount(
+ "Autofill.EditedAutofilledFieldAtSubmission.Aggregate", 0, 2);
+
+ // The aggregated histogram should have one count on accepted fields.
+ histogram_tester.ExpectBucketCount(
+ "Autofill.EditedAutofilledFieldAtSubmission.Aggregate", 1, 1);
+
+ // The autocomplete!=off histogram should have one count on accepted fields.
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Autocomplete.NotOff.EditedAutofilledFieldAtSubmission.Address",
+ 1, 1);
+
+ // The autocomplete!=off histogram should have no count on accepted fields.
+ histogram_tester.ExpectTotalCount(
+ "Autofill.Autocomplete.Off.EditedAutofilledFieldAtSubmission.Address", 0);
+}
+
// Verify that when submitting an autofillable form, the proper number of edited
// fields is logged.
TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
// Construct a fillable form.
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");
@@ -3209,6 +3635,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
// Construct a fillable form.
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");
@@ -3258,6 +3685,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// Start with a non-fillable form.
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");
@@ -3362,6 +3790,7 @@ TEST_F(AutofillMetricsTest,
UkmDeveloperEngagement_LogFillableFormParsedWithoutTypeHints) {
// Start with a non-fillable form.
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");
@@ -3408,6 +3837,7 @@ TEST_F(AutofillMetricsTest,
TEST_F(AutofillMetricsTest,
UkmDeveloperEngagement_LogFillableFormParsedWithTypeHints) {
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");
@@ -3465,6 +3895,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
// Disabled.
{});
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");
@@ -3634,6 +4065,67 @@ TEST_F(AutofillMetricsTest, LogStoredCreditCardMetrics) {
"Autofill.DaysSinceLastUse.StoredCreditCard.Server.Unmasked", 200, 3);
}
+TEST_F(AutofillMetricsTest, LogStoredCreditCardWithNicknameMetrics) {
+ std::vector<std::unique_ptr<CreditCard>> local_cards;
+ std::vector<std::unique_ptr<CreditCard>> server_cards;
+ local_cards.reserve(2);
+ server_cards.reserve(4);
+
+ // Create cards with and without nickname of each record type: 1 of each for
+ // local, 2 of each for masked.
+ const std::vector<CreditCard::RecordType> record_types{
+ CreditCard::LOCAL_CARD, CreditCard::MASKED_SERVER_CARD};
+ int num_cards_of_type = 0;
+ for (auto record_type : record_types) {
+ num_cards_of_type += 1;
+ for (int i = 0; i < num_cards_of_type; ++i) {
+ // Create a card with a nickname.
+ CreditCard card_with_nickname = test::GetRandomCreditCard(record_type);
+ card_with_nickname.SetNickname(ASCIIToUTF16("Valid nickname"));
+
+ // Create a card that doesn't have a nickname.
+ CreditCard card_without_nickname = test::GetRandomCreditCard(record_type);
+ // Set nickname to empty.
+ card_without_nickname.SetNickname(ASCIIToUTF16(""));
+
+ // Add the cards to the personal data manager in the appropriate way.
+ auto& repo =
+ (record_type == CreditCard::LOCAL_CARD) ? local_cards : server_cards;
+ repo.push_back(
+ std::make_unique<CreditCard>(std::move(card_with_nickname)));
+ repo.push_back(
+ std::make_unique<CreditCard>(std::move(card_without_nickname)));
+ }
+ }
+
+ // Log the stored credit card metrics for the cards configured above.
+ base::HistogramTester histogram_tester;
+ AutofillMetrics::LogStoredCreditCardMetrics(local_cards, server_cards,
+ base::TimeDelta::FromDays(180));
+
+ // Validate the count metrics.
+ histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount", 1);
+ histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount.Local", 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.StoredCreditCardCount.Local.WithNickname", 1);
+ histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount.Server", 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.StoredCreditCardCount.Server.Masked", 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.StoredCreditCardCount.Server.Masked.WithNickname", 1);
+ histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount", 6, 1);
+ histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount.Local", 2,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.StoredCreditCardCount.Local.WithNickname", 1, 1);
+ histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount.Server", 4,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.StoredCreditCardCount.Server.Masked", 4, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.StoredCreditCardCount.Server.Masked.WithNickname", 2, 1);
+}
+
// Test that we correctly log when Profile Autofill is enabled at startup.
TEST_F(AutofillMetricsTest, AutofillProfileIsEnabledAtStartup) {
base::HistogramTester histogram_tester;
@@ -3698,6 +4190,7 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsDisabledAtStartup) {
TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
// 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");
@@ -3770,6 +4263,7 @@ TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
TEST_P(AutofillMetricsCompanyTest, CompanyNameSuggestions) {
// 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");
@@ -3814,6 +4308,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
// 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");
@@ -3999,6 +4494,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
// Test that the UPI Checkout flow form submit is correctly logged
TEST_F(AutofillMetricsTest, UpiVpaUkmTest) {
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");
@@ -4030,6 +4526,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
// 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");
@@ -4171,6 +4668,7 @@ TEST_F(AutofillMetricsTest, PolledCreditCardSuggestions_DebounceLogs) {
// Set up the form data.
FormData form;
+ form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
form.url = GURL("http://www.foo.com/");
@@ -4231,6 +4729,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
// Set up the 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");
@@ -4250,6 +4749,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
{
// Simulate having seen this insecure form on page load.
+ form.unique_renderer_id = MakeFormRendererId();
form.url = GURL("http://example.com/form.html");
form.action = GURL("http://example.com/submit.html");
form.main_frame_origin =
@@ -4269,6 +4769,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
{
// Simulate having seen this secure form on page load.
autofill_manager_->Reset();
+ form.unique_renderer_id = MakeFormRendererId();
form.url = GURL("https://example.com/form.html");
form.action = GURL("https://example.com/submit.html");
form.main_frame_origin =
@@ -4292,6 +4793,7 @@ TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) {
// Set up the 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");
@@ -4349,6 +4851,7 @@ TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) {
TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) {
// 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");
@@ -4381,6 +4884,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) {
TEST_P(AutofillMetricsIFrameTest, CreditCardInteractedFormEvents) {
// 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");
@@ -4437,6 +4941,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardInteractedFormEvents) {
TEST_P(AutofillMetricsIFrameTest, CreditCardPopupSuppressedFormEvents) {
// 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");
@@ -4495,6 +5000,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardPopupSuppressedFormEvents) {
TEST_P(AutofillMetricsIFrameTest, CreditCardShownFormEvents) {
// 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");
@@ -4577,6 +5083,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSelectedFormEvents) {
true /* include_full_server_credit_card */);
// 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");
@@ -4658,6 +5165,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) {
true /* include_full_server_credit_card */);
// 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");
@@ -4910,6 +5418,7 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) {
false /* include_full_server_credit_card */);
// 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");
@@ -4979,6 +5488,7 @@ TEST_F(AutofillMetricsTest,
// 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");
@@ -5021,6 +5531,7 @@ TEST_P(AutofillMetricsIFrameTest,
// 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");
@@ -5065,6 +5576,7 @@ TEST_P(AutofillMetricsIFrameTest,
// 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");
@@ -5110,6 +5622,7 @@ TEST_P(AutofillMetricsIFrameTest,
// 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");
@@ -5156,6 +5669,7 @@ TEST_P(AutofillMetricsIFrameTest,
// 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");
@@ -5202,6 +5716,7 @@ TEST_P(AutofillMetricsIFrameTest,
// 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");
@@ -5261,6 +5776,7 @@ TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) {
RecreateProfile(/*is_server=*/false);
// 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");
@@ -5302,6 +5818,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
true /* include_full_server_credit_card */);
// 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");
@@ -5796,6 +6313,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
true /* include_full_server_credit_card */);
// 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");
@@ -6456,6 +6974,7 @@ TEST_P(AutofillMetricsServerNicknameTest, LogServerNicknameSelectionDuration) {
TEST_F(AutofillMetricsTest, MixedParsedFormEvents) {
// 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");
@@ -6499,6 +7018,7 @@ TEST_F(AutofillMetricsTest, MixedParsedFormEvents) {
TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
// 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");
@@ -6541,6 +7061,7 @@ TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
TEST_F(AutofillMetricsTest, AddressInteractedFormEvents) {
// 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");
@@ -6617,6 +7138,7 @@ TEST_F(AutofillMetricsTest, AddressSuppressedFormEvents) {
RecreateProfile(/*is_server=*/false);
// 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");
@@ -6710,6 +7232,7 @@ TEST_F(AutofillMetricsTest, AddressShownFormEvents) {
RecreateProfile(/*is_server=*/false);
// 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");
@@ -6821,6 +7344,7 @@ TEST_F(AutofillMetricsTest, AddressFilledFormEvents) {
RecreateProfile(/*is_server=*/false);
// 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");
@@ -6940,6 +7464,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
RecreateProfile(/*is_server=*/false);
// 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");
@@ -7152,6 +7677,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
RecreateProfile(/*is_server=*/false);
// 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");
@@ -7336,6 +7862,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
TEST_F(AutofillMetricsTest, CreditCardFormEventsAreSegmented) {
// 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");
@@ -7447,6 +7974,7 @@ TEST_F(AutofillMetricsTest, CreditCardFormEventsAreSegmented) {
TEST_F(AutofillMetricsTest, AddressFormEventsAreSegmented) {
// 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");
@@ -7556,6 +8084,7 @@ TEST_F(AutofillMetricsTest, DaysSinceLastUse_Profile) {
TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Start with a form with insufficiently many fields.
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");
@@ -7859,6 +8388,7 @@ TEST_F(
AutofillMetricsTest,
AutofillFormSubmittedState_DontCountUnfilledFieldsWithOnlyFillWhenFocused) {
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");
@@ -7994,6 +8524,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessMetric_UnknownForm) {
TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_EmptyForm) {
// Load a fillable form.
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");
@@ -8020,6 +8551,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
// Load a fillable form.
FormData form;
+ form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
form.url = GURL("https://example.com/form.html");
form.action = GURL("https://example.com/submit.html");
@@ -8189,6 +8721,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Load a fillable form.
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");
@@ -8443,6 +8976,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
// Load a fillable form.
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");
@@ -8460,6 +8994,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
// Fill additional form.
FormData second_form = form;
+ second_form.unique_renderer_id = MakeFormRendererId();
test::CreateTestFormField("Second Phone", "second_phone", "", "text", &field);
second_form.fields.push_back(field);
@@ -8864,6 +9399,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Load a fillable form.
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");
@@ -8990,6 +9526,7 @@ class AutofillMetricsParseQueryResponseTest : public testing::Test {
public:
void SetUp() override {
FormData form;
+ form.unique_renderer_id = MakeFormRendererId();
form.url = GURL("http://foo.com");
form.main_frame_origin = url::Origin::Create(GURL("http://foo_root.com"));
FormFieldData field;
@@ -9043,7 +9580,8 @@ TEST_F(AutofillMetricsParseQueryResponseTest, ServerHasData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, nullptr);
+ FormStructure::ParseQueryResponse(
+ response_string, forms_, test::GetEncodedSignatures(forms_), nullptr);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(true, 2)));
@@ -9062,7 +9600,8 @@ TEST_F(AutofillMetricsParseQueryResponseTest, OneFormNoServerData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, nullptr);
+ FormStructure::ParseQueryResponse(
+ response_string, forms_, test::GetEncodedSignatures(forms_), nullptr);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(false, 1), Bucket(true, 1)));
@@ -9080,7 +9619,8 @@ TEST_F(AutofillMetricsParseQueryResponseTest, AllFormsNoServerData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, nullptr);
+ FormStructure::ParseQueryResponse(
+ response_string, forms_, test::GetEncodedSignatures(forms_), nullptr);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(false, 2)));
@@ -9099,7 +9639,8 @@ TEST_F(AutofillMetricsParseQueryResponseTest, PartialNoServerData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, nullptr);
+ FormStructure::ParseQueryResponse(
+ response_string, forms_, test::GetEncodedSignatures(forms_), nullptr);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(true, 2)));
@@ -9114,6 +9655,7 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) {
// 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");
@@ -9172,6 +9714,7 @@ TEST_F(AutofillMetricsTest,
// Set up our form data.
FormData form;
+ form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
form.url = GURL("https://example.com/form.html");
form.action = GURL("http://example.com/submit.html");
@@ -9296,6 +9839,7 @@ TEST_F(AutofillMetricsTest, DISABLED_AutofillSuggestionShownTest) {
false /* include_masked_server_credit_card */,
false /* include_full_server_credit_card */);
FormData form;
+ form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
form.url = GURL("http://example_cc.com/form.html");
form.action = GURL("http://example_cc.com/submit.html");
@@ -9335,6 +9879,7 @@ TEST_F(AutofillMetricsTest, DynamicFormMetrics) {
// 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");
@@ -9434,10 +9979,10 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogUserHappinessBySecurityLevel(
AutofillMetrics::USER_DID_AUTOFILL_ONCE, UNKNOWN_FORM_TYPE,
- security_state::SecurityLevel::EV_SECURE);
- histogram_tester.ExpectBucketCount(
- "Autofill.UserHappiness.Unknown.EV_SECURE",
- AutofillMetrics::USER_DID_AUTOFILL_ONCE, 1);
+ security_state::SecurityLevel::SECURE);
+ histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Unknown.SECURE",
+ AutofillMetrics::USER_DID_AUTOFILL_ONCE,
+ 1);
}
{
@@ -9457,6 +10002,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) {
// Load a fillable form.
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");
@@ -9718,11 +10264,11 @@ TEST_F(AutofillMetricsTest, LogSaveCardPromptMetricBySecurityLevel) {
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, /*is_uploading=*/true,
- security_state::SecurityLevel::SECURE);
+ AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
+ /*is_uploading=*/true, security_state::SecurityLevel::SECURE);
histogram_tester.ExpectBucketCount(
"Autofill.SaveCreditCardPrompt.Upload.SECURE",
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1);
+ AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED, 1);
}
{
@@ -9749,9 +10295,9 @@ TEST_F(AutofillMetricsTest, LogSaveCardPromptMetricBySecurityLevel) {
base::HistogramTester histogram_tester;
AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING,
- /*is_uploading=*/false, security_state::SecurityLevel::EV_SECURE);
+ /*is_uploading=*/false, security_state::SecurityLevel::SECURE);
histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Local.EV_SECURE",
+ "Autofill.SaveCreditCardPrompt.Local.SECURE",
AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, 1);
}
@@ -9779,22 +10325,23 @@ TEST_F(AutofillMetricsTest,
/*is_uploading=*/true, /*is_reshow=*/false,
AutofillClient::SaveCreditCardOptions(),
/*previous_save_credit_card_prompt_user_decision=*/1,
- security_state::SecurityLevel::EV_SECURE, SyncSigninState::kSignedOut);
+ security_state::SecurityLevel::SECURE, SyncSigninState::kSignedOut);
histogram_tester.ExpectBucketCount(
- "Autofill.SaveCreditCardPrompt.Upload.EV_SECURE",
+ "Autofill.SaveCreditCardPrompt.Upload.SECURE",
AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, 1);
}
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogSaveCardPromptMetric(
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, /*is_uploading=*/false,
+ AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
+ /*is_uploading=*/false,
/*is_reshow=*/true, AutofillClient::SaveCreditCardOptions(),
/*previous_save_credit_card_prompt_user_decision=*/0,
security_state::SecurityLevel::SECURE, SyncSigninState::kSignedOut);
histogram_tester.ExpectBucketCount(
"Autofill.SaveCreditCardPrompt.Local.SECURE",
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1);
+ AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED, 1);
}
}
@@ -9963,15 +10510,17 @@ TEST_F(AutofillMetricsTest, LogSaveCardPromptMetric_BySyncState) {
/*is_uploading=*/true, /*is_reshow=*/false,
AutofillClient::SaveCreditCardOptions(),
/*previous_save_credit_card_prompt_user_decision=*/1,
- security_state::SecurityLevel::EV_SECURE, SyncSigninState::kSignedIn);
+ security_state::SecurityLevel::SECURE, SyncSigninState::kSignedIn);
histogram_tester.ExpectBucketCount(
"Autofill.SaveCreditCardPrompt.Upload.FirstShow.SignedIn",
AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, 1);
}
+
{
base::HistogramTester histogram_tester;
AutofillMetrics::LogSaveCardPromptMetric(
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, /*is_uploading=*/false,
+ AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED,
+ /*is_uploading=*/false,
/*is_reshow=*/true, AutofillClient::SaveCreditCardOptions(),
/*previous_save_credit_card_prompt_user_decision=*/0,
security_state::SecurityLevel::SECURE,
@@ -9979,7 +10528,7 @@ TEST_F(AutofillMetricsTest, LogSaveCardPromptMetric_BySyncState) {
histogram_tester.ExpectBucketCount(
"Autofill.SaveCreditCardPrompt.Local.Reshows."
"SignedInAndSyncFeatureEnabled",
- AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1);
+ AutofillMetrics::SAVE_CARD_PROMPT_SHOWN_DEPRECATED, 1);
}
}
@@ -10026,6 +10575,7 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
// Load a fillable form.
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");
@@ -10136,6 +10686,10 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
"Autofill.KeyMetrics.FillingCorrectness.Address", 1, 1);
histogram_tester.ExpectBucketCount(
"Autofill.KeyMetrics.FillingAssistance.Address", 1, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Autocomplete.NotOff.FillingAcceptance.Address", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.Autocomplete.Off.FillingAcceptance.Address", 0);
} else {
histogram_tester.ExpectTotalCount(
"Autofill.KeyMetrics.FillingReadiness.Address", 0);
@@ -10145,6 +10699,10 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
"Autofill.KeyMetrics.FillingCorrectness.Address", 0);
histogram_tester.ExpectTotalCount(
"Autofill.KeyMetrics.FillingAssistance.Address", 0);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.Autocomplete.NotOff.FillingAcceptance.Address", 0);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.Autocomplete.Off.FillingAcceptance.Address", 0);
}
if (user_accepted_suggestion) {
histogram_tester.ExpectBucketCount(
@@ -10172,6 +10730,7 @@ void AutofillMetricsKeyMetricsTest::SetUp() {
RecreateProfile(/*is_server=*/false);
// Load a fillable 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");
@@ -10373,4 +10932,18 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledDataButDoesNotSubmit) {
"Autofill.KeyMetrics.FormSubmission.Autofilled.Address", 0, 1);
}
+TEST_F(AutofillMetricsTest, GetFieldTypeUserEditStatusMetric) {
+ // The id of ADDRESS_HOME_COUNTRY is 36 = 0b10'0100.
+ ServerFieldType server_type = ADDRESS_HOME_COUNTRY;
+ // The id of AUTOFILL_FIELD_WAS_NOT_EDITED is 1.
+ AutofillMetrics::AutofilledFieldUserEditingStatusMetric metric =
+ AutofillMetrics::AutofilledFieldUserEditingStatusMetric::
+ AUTOFILLED_FIELD_WAS_NOT_EDITED;
+
+ int expected_result = 0b10'0100'0001;
+ int actual_result =
+ autofill::GetFieldTypeUserEditStatusMetric(server_type, metric);
+ EXPECT_EQ(expected_result, actual_result);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_provider.cc b/chromium/components/autofill/core/browser/autofill_provider.cc
index 9fc3b8c0f43..8cea5630a05 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.cc
+++ b/chromium/components/autofill/core/browser/autofill_provider.cc
@@ -19,4 +19,10 @@ void AutofillProvider::SendFormDataToRenderer(AutofillHandlerProxy* handler,
requestId, AutofillDriver::FORM_DATA_ACTION_FILL, formData);
}
-} // namespace autofil
+void AutofillProvider::RendererShouldAcceptDataListSuggestion(
+ AutofillHandlerProxy* handler,
+ const base::string16& value) {
+ handler->driver()->RendererShouldAcceptDataListSuggestion(value);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_provider.h b/chromium/components/autofill/core/browser/autofill_provider.h
index 09f87a90ab9..6eae4082e4b 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.h
+++ b/chromium/components/autofill/core/browser/autofill_provider.h
@@ -67,11 +67,18 @@ class AutofillProvider {
const std::vector<FormData>& forms,
const base::TimeTicks timestamp) = 0;
+ virtual void OnHidePopup(AutofillHandlerProxy* handler) = 0;
+
virtual void Reset(AutofillHandlerProxy* handler) = 0;
void SendFormDataToRenderer(AutofillHandlerProxy* handler,
int requestId,
const FormData& formData);
+
+ // Notifies the renderer should accept the datalist suggestion given by
+ // |value| and fill the associated input field.
+ void RendererShouldAcceptDataListSuggestion(AutofillHandlerProxy* handler,
+ const base::string16& value);
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index bf871432b31..82b3b06f3b4 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -22,8 +22,10 @@
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/renderer_id.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
@@ -50,6 +52,16 @@ std::string GetRandomCardNumber() {
return value;
}
+FormRendererId MakeFormRendererId() {
+ static uint32_t counter = 10;
+ return FormRendererId(counter++);
+}
+
+FieldRendererId MakeFieldRendererId() {
+ static uint32_t counter = 10;
+ return FieldRendererId(counter++);
+}
+
} // namespace
std::unique_ptr<PrefService> PrefServiceForTesting() {
@@ -74,6 +86,7 @@ void CreateTestFormField(const char* label,
const char* value,
const char* type,
FormFieldData* field) {
+ field->unique_renderer_id = MakeFieldRendererId();
field->label = ASCIIToUTF16(label);
field->name = ASCIIToUTF16(name);
field->value = ASCIIToUTF16(value);
@@ -108,6 +121,27 @@ void CreateTestSelectField(const std::vector<const char*>& values,
CreateTestSelectField("", "", "", values, values, values.size(), field);
}
+void CreateTestDatalistField(const char* label,
+ const char* name,
+ const char* value,
+ const std::vector<const char*>& values,
+ const std::vector<const char*>& labels,
+ FormFieldData* field) {
+ // Fill the base attributes.
+ CreateTestFormField(label, name, value, "text", field);
+
+ std::vector<base::string16> values16(values.size());
+ for (size_t i = 0; i < values.size(); ++i)
+ values16[i] = base::UTF8ToUTF16(values[i]);
+
+ std::vector<base::string16> label16(labels.size());
+ for (size_t i = 0; i < labels.size(); ++i)
+ label16[i] = base::UTF8ToUTF16(labels[i]);
+
+ field->datalist_values = values16;
+ field->datalist_labels = label16;
+}
+
void CreateTestAddressFormData(FormData* form, const char* unique_id) {
std::vector<ServerFieldTypeSet> types;
CreateTestAddressFormData(form, &types, unique_id);
@@ -116,6 +150,7 @@ void CreateTestAddressFormData(FormData* form, const char* unique_id) {
void CreateTestAddressFormData(FormData* form,
std::vector<ServerFieldTypeSet>* types,
const char* unique_id) {
+ form->unique_renderer_id = MakeFormRendererId();
form->name =
ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : "");
form->button_titles = {
@@ -192,6 +227,7 @@ void CreateTestAddressFormData(FormData* form,
void CreateTestPersonalInformationFormData(FormData* form,
const char* unique_id) {
+ form->unique_renderer_id = MakeFormRendererId();
form->name =
ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : "");
form->url = GURL("http://myform.com/form.html");
@@ -216,6 +252,7 @@ void CreateTestCreditCardFormData(FormData* form,
bool use_month_type,
bool split_names,
const char* unique_id) {
+ form->unique_renderer_id = MakeFormRendererId();
form->name =
ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : "");
if (is_https) {
@@ -796,5 +833,28 @@ std::string TenYearsFromNow() {
return base::NumberToString(now.year + 10);
}
+FormAndFieldSignatures GetEncodedSignatures(const FormStructure& form) {
+ FormAndFieldSignatures signatures;
+ signatures.emplace_back(form.form_signature(),
+ std::vector<autofill::FieldSignature>{});
+ for (const auto& field : form) {
+ if (form.ShouldSkipFieldVisibleForTesting(*field))
+ continue;
+ signatures.back().second.push_back(field->GetFieldSignature());
+ }
+ return signatures;
+}
+
+FormAndFieldSignatures GetEncodedSignatures(
+ const std::vector<FormStructure*>& forms) {
+ FormAndFieldSignatures all_signatures;
+ for (const FormStructure* form : forms) {
+ FormAndFieldSignatures form_signatures = GetEncodedSignatures(*form);
+ std::move(form_signatures.begin(), form_signatures.end(),
+ std::back_inserter(all_signatures));
+ }
+ return all_signatures;
+}
+
} // namespace test
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index 900e51fcdb7..f51ea475c9f 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -14,6 +14,7 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
#include "components/autofill/core/browser/proto/server.pb.h"
@@ -64,6 +65,14 @@ void CreateTestSelectField(const char* label,
void CreateTestSelectField(const std::vector<const char*>& values,
FormFieldData* field);
+// Provides a quick way to populate a datalist field.
+void CreateTestDatalistField(const char* label,
+ const char* name,
+ const char* value,
+ const std::vector<const char*>& values,
+ const std::vector<const char*>& labels,
+ FormFieldData* field);
+
// Populates |form| with data corresponding to a simple address form.
// Note that this actually appends fields to the form data, which can be useful
// for building up more complex test forms. Another version of the function is
@@ -274,6 +283,16 @@ void FillQueryField(AutofillPageQueryRequest_Form_Field* field,
const char* name,
const char* control_type);
+// Creates the structure of signatures that would be encoded by
+// FormStructure::EncodeUploadRequest() and FormStructure::EncodeQueryRequest()
+// and consumed by FormStructure::ParseQueryResponse() and
+// FormStructure::ParseApiQueryResponse().
+//
+// Perhaps a neater way would be to move this to TestFormStructure.
+FormAndFieldSignatures GetEncodedSignatures(const FormStructure& form);
+FormAndFieldSignatures GetEncodedSignatures(
+ const std::vector<FormStructure*>& forms);
+
// Calls the required functions on the given external delegate to cause the
// delegate to display a popup.
void GenerateTestAutofillPopup(
diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc
index 19e9cbf009f..31428cacab9 100644
--- a/chromium/components/autofill/core/browser/autofill_type.cc
+++ b/chromium/components/autofill/core/browser/autofill_type.cc
@@ -10,9 +10,13 @@ namespace autofill {
FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
switch (field_type) {
+ case NAME_HONORIFIC_PREFIX:
case NAME_FIRST:
case NAME_MIDDLE:
case NAME_LAST:
+ case NAME_LAST_FIRST:
+ case NAME_LAST_SECOND:
+ case NAME_LAST_CONJUNCTION:
case NAME_MIDDLE_INITIAL:
case NAME_FULL:
case NAME_SUFFIX:
@@ -139,6 +143,7 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
HtmlFieldMode field_mode) {
switch (field_type) {
case HTML_TYPE_NAME:
+ case HTML_TYPE_HONORIFIC_PREFIX:
case HTML_TYPE_GIVEN_NAME:
case HTML_TYPE_ADDITIONAL_NAME:
case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
@@ -318,6 +323,9 @@ ServerFieldType AutofillType::GetStorableType() const {
case HTML_TYPE_NAME:
return NAME_FULL;
+ case HTML_TYPE_HONORIFIC_PREFIX:
+ return NAME_HONORIFIC_PREFIX;
+
case HTML_TYPE_GIVEN_NAME:
return NAME_FIRST;
@@ -456,6 +464,8 @@ std::string AutofillType::ToString() const {
break;
case HTML_TYPE_NAME:
return "HTML_TYPE_NAME";
+ case HTML_TYPE_HONORIFIC_PREFIX:
+ return "HTML_TYPE_HONORIFIC_PREFIX";
case HTML_TYPE_GIVEN_NAME:
return "HTML_TYPE_GIVEN_NAME";
case HTML_TYPE_ADDITIONAL_NAME:
@@ -558,12 +568,20 @@ std::string AutofillType::ServerFieldTypeToString(ServerFieldType type) {
return "UNKNOWN_TYPE";
case EMPTY_TYPE:
return "EMPTY_TYPE";
+ case NAME_HONORIFIC_PREFIX:
+ return "NAME_HONORIFIC_PREFIX";
case NAME_FIRST:
return "NAME_FIRST";
case NAME_MIDDLE:
return "NAME_MIDDLE";
case NAME_LAST:
return "NAME_LAST";
+ case NAME_LAST_FIRST:
+ return "NAME_LAST_FIRST";
+ case NAME_LAST_CONJUNCTION:
+ return "NAME_LAST_CONJUNCTION";
+ case NAME_LAST_SECOND:
+ return "NAME_LAST_SECOND";
case NAME_MIDDLE_INITIAL:
return "NAME_MIDDLE_INITIAL";
case NAME_FULL:
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 4b42be5216b..8e2fffe9ddb 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc
@@ -760,9 +760,16 @@ void CreditCard::SetExpirationDateFromString(const base::string16& text) {
const std::pair<base::string16, base::string16> CreditCard::LabelPieces()
const {
base::string16 label;
- // No CC number, return name only.
- if (number().empty())
+ if (number().empty()) {
+ // No CC number, if valid nickname is present, return nickname only.
+ // Otherwise, return cardholder name only.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableCardNicknameManagement) &&
+ HasValidNickname()) {
+ return std::make_pair(nickname_, base::string16());
+ }
return std::make_pair(name_on_card_, base::string16());
+ }
base::string16 obfuscated_cc_number =
CardIdentifierStringForAutofillDisplay();
@@ -817,11 +824,12 @@ base::string16 CreditCard::NetworkAndLastFourDigits() const {
: network + ASCIIToUTF16(" ") + obfuscated_string;
}
-base::string16 CreditCard::CardIdentifierStringForAutofillDisplay() const {
+base::string16 CreditCard::CardIdentifierStringForAutofillDisplay(
+ base::string16 customized_nickname) const {
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSurfacingServerCardNickname) &&
- HasValidNickname()) {
- return NicknameAndLastFourDigits();
+ (HasValidNickname() || !customized_nickname.empty())) {
+ return NicknameAndLastFourDigits(customized_nickname);
}
// Return a Google-specific string for Google-issued cards.
if (base::FeatureList::IsEnabled(features::kAutofillEnableGoogleIssuedCard) &&
@@ -832,10 +840,11 @@ base::string16 CreditCard::CardIdentifierStringForAutofillDisplay() const {
}
base::string16 CreditCard::CardIdentifierStringAndDescriptiveExpiration(
- const std::string& app_locale) const {
+ const std::string& app_locale,
+ base::string16 customized_nickname) const {
return l10n_util::GetStringFUTF16(
IDS_AUTOFILL_CREDIT_CARD_TWO_LINE_LABEL_FROM_NAME,
- CardIdentifierStringForAutofillDisplay(),
+ CardIdentifierStringForAutofillDisplay(customized_nickname),
GetInfo(AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR), app_locale));
}
@@ -897,13 +906,17 @@ bool CreditCard::HasValidNickname() const {
return false;
}
// Must not contain digits.
- for (char c : nickname_) {
+ for (base::char16 c : nickname_) {
if (base::IsAsciiDigit(c))
return false;
}
return true;
}
+base::string16 CreditCard::NicknameAndLastFourDigitsForTesting() const {
+ return NicknameAndLastFourDigits();
+}
+
base::string16 CreditCard::Expiration2DigitYearAsString() const {
return data_util::Expiration2DigitYearAsString(expiration_year_);
}
@@ -954,15 +967,17 @@ base::string16 CreditCard::NetworkForFill() const {
return ::autofill::NetworkForFill(network_);
}
-base::string16 CreditCard::NicknameAndLastFourDigits() const {
+base::string16 CreditCard::NicknameAndLastFourDigits(
+ base::string16 customized_nickname) const {
// Should call HasValidNickname() to check valid nickname before calling this.
- DCHECK(HasValidNickname());
+ DCHECK(HasValidNickname() || !customized_nickname.empty());
const base::string16 digits = LastFourDigits();
// If digits are empty, return nickname.
if (digits.empty())
- return nickname_;
+ return customized_nickname.empty() ? nickname_ : customized_nickname;
- return nickname_ + ASCIIToUTF16(" ") +
+ return (customized_nickname.empty() ? nickname_ : customized_nickname) +
+ ASCIIToUTF16(" ") +
internal::GetObfuscatedStringForCardDigits(digits);
}
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.h b/chromium/components/autofill/core/browser/data_model/credit_card.h
index 555dc938a99..e74ced42b14 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.h
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.h
@@ -260,14 +260,16 @@ class CreditCard : public AutofillDataModel {
// available and valid; otherwise, formatted as 'IssuerNetwork - ****2345'.
// Google-issued cards have their own specific identifier, instead of
// displaying the issuer network name.
- base::string16 CardIdentifierStringForAutofillDisplay() const;
+ base::string16 CardIdentifierStringForAutofillDisplay(
+ base::string16 customized_nickname = base::string16()) const;
// A label for this card formatted as 'Nickname - ****2345, expires on MM/YY'
// if nickname experiment is turned on and nickname is available; otherwise,
// formatted as 'IssuerNetwork - ****2345, expires on MM/YY'.
// This label is used as a second line label when the cardholder
// name/expiration date field is selected.
base::string16 CardIdentifierStringAndDescriptiveExpiration(
- const std::string& app_locale) const;
+ const std::string& app_locale,
+ base::string16 customized_nickname = base::string16()) const;
// A label for this card formatted as 'Expires on MM/YY'.
// This label is used as a second line label when the autofill dropdown
// uses a two line layout and the credit card number is selected.
@@ -292,10 +294,12 @@ class CreditCard : public AutofillDataModel {
// Returns whether the card has a valid nickname.
bool HasValidNickname() const;
+ // Should be used ONLY by tests.
+ base::string16 NicknameAndLastFourDigitsForTesting() const;
+
private:
FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationDateFromString);
FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationYearFromString);
- FRIEND_TEST_ALL_PREFIXES(CreditCardTest, NicknameAndLastFourDigitsStrings);
base::string16 Expiration2DigitYearAsString() const;
@@ -312,7 +316,8 @@ class CreditCard : public AutofillDataModel {
// A label for this card formatted as 'Nickname - ****2345'. Always call
// HasValidNickname() before calling this.
- base::string16 NicknameAndLastFourDigits() const;
+ base::string16 NicknameAndLastFourDigits(
+ base::string16 customized_nickname = base::string16()) const;
// Sets the name_on_card_ value based on the saved name parts.
void SetNameOnCardFromSeparateParts();
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
index 01c06a494c8..56a5c11ec45 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
@@ -61,8 +61,11 @@ const char* const kInvalidNumbers[] = {
};
const char* const kValidNicknames[] = {
- "Grocery Card", "Two percent Cashback",
+ "Grocery Card",
+ "Two percent Cashback",
"Mastercard \xF0\x9F\x92\xB3", /* Nickname with UTF-8 hex encoded emoji */
+ "\u0634\u063a\u0645\u0688", /* arbitrary Arabic script in unicode */
+ "\u0434\u0444\u0431\u044A", /* arbitrary Cyrillic script in unicode */
};
const char* const kInvalidNicknames[] = {
@@ -98,9 +101,11 @@ TEST(CreditCardTest, GetObfuscatedStringForCardDigits) {
TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
base::test::ScopedFeatureList scoped_feature_list;
base::string16 valid_nickname = ASCIIToUTF16("My Visa Card");
- // Enable the flag.
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillEnableSurfacingServerCardNickname);
+ // Enable the flags.
+ scoped_feature_list.InitWithFeatures(
+ /*enable_features=*/{features::kAutofillEnableSurfacingServerCardNickname,
+ features::kAutofillEnableCardNicknameManagement},
+ /*disable_features=*/{});
// Case 0: empty credit card.
CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com/");
@@ -126,6 +131,16 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
base::string16 obfuscated1 = credit_card1.NetworkAndLastFourDigits();
EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated1);
+ // Case 1.1: No credit card number, but has nickname.
+ CreditCard credit_card11(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card11, "John Dillinger", "", "01", "2010",
+ "1");
+ credit_card11.SetNickname(valid_nickname);
+ base::string16 summary11 = credit_card11.Label();
+ EXPECT_EQ(valid_nickname, summary11);
+ base::string16 obfuscated11 = credit_card11.NetworkAndLastFourDigits();
+ EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated11);
+
// Case 2: No month.
CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card2, "John Dillinger",
@@ -193,10 +208,12 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
summary6);
// Case 7: Have everything including nickname but flag is off.
- // Reset and disable the feature flag.
+ // Reset and disable the nickname feature flags.
scoped_feature_list.Reset();
- scoped_feature_list.InitAndDisableFeature(
- features::kAutofillEnableSurfacingServerCardNickname);
+ scoped_feature_list.InitWithFeatures(
+ /*enable_features=*/{}, /*disable_features=*/{
+ features::kAutofillEnableSurfacingServerCardNickname,
+ features::kAutofillEnableCardNicknameManagement});
CreditCard credit_card7(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card7, "John Dillinger",
"5105 1051 0510 5100" /* Mastercard */, "01", "2010",
@@ -206,6 +223,16 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
summary7);
+
+ // Case 8: No credit card number, has valid nickname, but flag is off.
+ CreditCard credit_card8(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card8, "John Dillinger", "", "01", "2010",
+ "1");
+ credit_card8.SetNickname(valid_nickname);
+ base::string16 summary8 = credit_card11.Label();
+ EXPECT_EQ(base::string16(ASCIIToUTF16("John Dillinger")), summary8);
+ base::string16 obfuscated8 = credit_card8.NetworkAndLastFourDigits();
+ EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated8);
}
TEST(CreditCardTest, NicknameAndLastFourDigitsStrings) {
@@ -216,7 +243,7 @@ TEST(CreditCardTest, NicknameAndLastFourDigitsStrings) {
test::SetCreditCardInfo(&credit_card1, "John Dillinger", "", "01", "2020",
"1");
credit_card1.SetNickname(valid_nickname);
- EXPECT_EQ(valid_nickname, credit_card1.NicknameAndLastFourDigits());
+ EXPECT_EQ(valid_nickname, credit_card1.NicknameAndLastFourDigitsForTesting());
// Case 2: Have everything.
CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com/");
@@ -226,7 +253,7 @@ TEST(CreditCardTest, NicknameAndLastFourDigitsStrings) {
EXPECT_EQ(
valid_nickname + UTF8ToUTF16(std::string(" ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- credit_card2.NicknameAndLastFourDigits());
+ credit_card2.NicknameAndLastFourDigitsForTesting());
}
TEST(CreditCardTest, CardIdentifierStringsForAutofillDisplay) {
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 67391ee4b1f..518d6a7949d 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
@@ -12,6 +12,8 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.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"
@@ -141,6 +143,18 @@ bool SetExpirationYear(int value, int* expiration_year) {
return true;
}
+base::string16 FindPossiblePhoneCountryCode(const base::string16& text) {
+ base::string16 candidate;
+ if (text.find(base::ASCIIToUTF16("00")) != base::string16::npos ||
+ text.find('+') != base::string16::npos) {
+ if (MatchesPattern(text, base::ASCIIToUTF16(kAugmentedPhoneCountryCodeRe),
+ &candidate, 1))
+ return candidate;
+ }
+
+ return base::string16();
+}
+
} // namespace data_util
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/data_model_utils.h b/chromium/components/autofill/core/browser/data_model/data_model_utils.h
index 59a75c3ce54..f1324537936 100644
--- a/chromium/components/autofill/core/browser/data_model/data_model_utils.h
+++ b/chromium/components/autofill/core/browser/data_model/data_model_utils.h
@@ -47,6 +47,10 @@ bool SetExpirationMonth(int value, int* expiration_month);
// made to |*expiration_year|.
bool SetExpirationYear(int value, int* expiration_year);
+// Finds possible country code in |text| by fetching the first sub-group when
+// matched with |kAugmentedPhoneCountryCodeRe| regex.
+base::string16 FindPossiblePhoneCountryCode(const base::string16& text);
+
} // namespace data_util
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/phone_number.cc b/chromium/components/autofill/core/browser/data_model/phone_number.cc
index 4327531281e..96a2b0b62f1 100644
--- a/chromium/components/autofill/core/browser/data_model/phone_number.cc
+++ b/chromium/components/autofill/core/browser/data_model/phone_number.cc
@@ -13,9 +13,11 @@
#include "base/strings/utf_string_conversions.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/data_model_utils.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
+#include "components/autofill/core/common/autofill_features.h"
namespace autofill {
namespace {
@@ -134,6 +136,18 @@ void PhoneNumber::GetMatchingTypes(const base::string16& text,
matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
}
}
+
+ // |PHONE_HOME_COUNTRY_CODE| is added to the set of the |matching_types| when
+ // the digits extracted from the |stripped_text| match the |country_code|.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableAugmentedPhoneCountryCode)) {
+ base::string16 candidate =
+ data_util::FindPossiblePhoneCountryCode(stripped_text);
+ base::string16 country_code =
+ GetInfo(AutofillType(PHONE_HOME_COUNTRY_CODE), app_locale);
+ if (candidate.size() > 0 && candidate == country_code)
+ matching_types->insert(PHONE_HOME_COUNTRY_CODE);
+ }
}
// Normalize phones if |type| is a whole number:
diff --git a/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc b/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc
index 29456dcf536..2a28625d1d9 100644
--- a/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc
@@ -6,10 +6,12 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -289,4 +291,78 @@ TEST(PhoneNumberTest, InternationalPhoneHomeCityAndNumber_DE) {
phone_number.GetInfo(PHONE_HOME_CITY_AND_NUMBER, "en-US"));
}
+// Tests whether the |PHONE_HOME_COUNTRY_CODE| is added to the set of matching
+// types.
+TEST(PhoneNumberTest, CountryCodeInMatchingTypes) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ AutofillProfile profile;
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ // Set the phone number such that country_code == 1, city_code = 650,
+ // number = 2345678.
+ base::string16 phone(ASCIIToUTF16("1 [650] 234-5678"));
+ PhoneNumber phone_number(&profile);
+ phone_number.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), phone, "US");
+
+ std::vector<const char*> test_cases = {"+1", "1", "(+1) United States",
+ "US (+1)"};
+
+ for (size_t i = 0; i < test_cases.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "i(US) = " << i);
+
+ ServerFieldTypeSet matching_types;
+ phone_number.GetMatchingTypes(ASCIIToUTF16(test_cases[i]), "US",
+ &matching_types);
+
+ EXPECT_THAT(matching_types, testing::ElementsAre(PHONE_HOME_COUNTRY_CODE));
+ }
+
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
+ base::string16 de_phone(ASCIIToUTF16("+49 0151 6679586"));
+ PhoneNumber phone_number_de(&profile);
+ phone_number_de.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), de_phone,
+ "DE");
+
+ test_cases = {"49", "+49", "(+49) DE", "(0049) DE", "0049"};
+ for (size_t i = 0; i < test_cases.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "i(DE) = " << i);
+
+ ServerFieldTypeSet matching_types;
+ phone_number_de.GetMatchingTypes(ASCIIToUTF16(test_cases[i]), "DE",
+ &matching_types);
+
+ EXPECT_THAT(matching_types, testing::ElementsAre(PHONE_HOME_COUNTRY_CODE));
+ }
+}
+
+// Tests that the |PHONE_HOME_COUNTRY_CODE| should not be added to the set of
+// matching types.
+TEST(PhoneNumberTest, CountryCodeNotInMatchingTypes) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ AutofillProfile profile;
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ // Set phone number so country_code == 1, city_code = 650, number = 2345678.
+ base::string16 phone(ASCIIToUTF16("1 [650] 234-5678"));
+ PhoneNumber phone_number(&profile);
+ phone_number.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), phone, "US");
+
+ std::vector<const char*> test_cases = {
+ "01", "+16502", "11", "211", "0001", "++1", "+1abc2", "001abc2", "01"};
+
+ for (size_t i = 0; i < test_cases.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+
+ ServerFieldTypeSet matching_types;
+ phone_number.GetMatchingTypes(ASCIIToUTF16(test_cases[i]), "US",
+ &matching_types);
+
+ EXPECT_THAT(matching_types, testing::IsEmpty());
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/test_data_creator.cc b/chromium/components/autofill/core/browser/data_model/test_data_creator.cc
index 41bdcd75669..edb610199dc 100644
--- a/chromium/components/autofill/core/browser/data_model/test_data_creator.cc
+++ b/chromium/components/autofill/core/browser/data_model/test_data_creator.cc
@@ -6,6 +6,7 @@
#include <inttypes.h>
+#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
diff --git a/chromium/components/autofill/core/browser/field_filler.cc b/chromium/components/autofill/core/browser/field_filler.cc
index 34766959c5e..16ada9dbb6c 100644
--- a/chromium/components/autofill/core/browser/field_filler.cc
+++ b/chromium/components/autofill/core/browser/field_filler.cc
@@ -705,6 +705,36 @@ base::string16 RemoveWhitespace(const base::string16& value) {
return stripped_value;
}
+// Finds the best suitable option in the |field| that corresponds to the
+// |country_code|.
+// If the exact match is not found, extracts the digits (ignoring leading '00'
+// or '+') from each option and compares them with the |country_code|.
+void FillPhoneCountryCodeSelectControl(const base::string16& country_code,
+ FormFieldData* field,
+ std::string* failure_to_fill) {
+ if (country_code.empty())
+ return;
+
+ // Find the option that exactly matches the |country_code|.
+ if (SetSelectControlValue(country_code, field, /*best_match_index=*/nullptr,
+ failure_to_fill))
+ return;
+
+ for (size_t i = 0; i < field->option_contents.size(); i++) {
+ base::string16 cc_candidate_in_value =
+ data_util::FindPossiblePhoneCountryCode(
+ RemoveWhitespace(field->option_values[i]));
+ base::string16 cc_candidate_in_content =
+ data_util::FindPossiblePhoneCountryCode(
+ RemoveWhitespace(field->option_contents[i]));
+ if (cc_candidate_in_value == country_code ||
+ cc_candidate_in_content == country_code) {
+ field->value = field->option_values[i];
+ return;
+ }
+ }
+}
+
} // namespace
FieldFiller::FieldFiller(const std::string& app_locale,
@@ -748,7 +778,16 @@ bool FieldFiller::FillFormField(const AutofillField& field,
}
if (type.group() == PHONE_HOME) {
- FillPhoneNumberField(field, value, field_data);
+ // If the |field_data| is a selection box and having the type
+ // |PHONE_HOME_COUNTRY_CODE|, call |FillPhoneCountryCodeSelectControl|.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableAugmentedPhoneCountryCode) &&
+ field_data->form_control_type == "select-one" &&
+ type.GetStorableType() == PHONE_HOME_COUNTRY_CODE) {
+ FillPhoneCountryCodeSelectControl(value, field_data, failure_to_fill);
+ } else {
+ FillPhoneNumberField(field, value, field_data);
+ }
return true;
}
if (field_data->form_control_type == "select-one") {
diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc
index f5c2e8f6b08..02f1c95c11f 100644
--- a/chromium/components/autofill/core/browser/field_filler_unittest.cc
+++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc
@@ -1495,4 +1495,132 @@ INSTANTIATE_TEST_SUITE_P(
FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 3, "Quebec", "",
false}));
+// Tests that the correct option is chosen in the selection box when one of the
+// options exactly matches the phone country code.
+TEST_F(AutofillFieldFillerTest,
+ FillSelectControlPhoneCountryCodeWithExactMatch) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ std::vector<const char*> kPhoneCountryCode = {"91", "1", "20", "49"};
+ AutofillField field;
+ test::CreateTestSelectField(kPhoneCountryCode, &field);
+ field.set_heuristic_type(PHONE_HOME_COUNTRY_CODE);
+
+ AutofillProfile address;
+ address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+15145554578"));
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("1"), field.value);
+}
+
+// Tests that the correct option is chosen in the selection box when the options
+// are preceded by a plus sign and the field is of |PHONE_HOME_COUNTRY_CODE|
+// type.
+TEST_F(AutofillFieldFillerTest,
+ FillSelectControlPhoneCountryCodePrecededByPlus) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ std::vector<const char*> kPhoneCountryCode = {"+91", "+1", "+20", "+49"};
+ AutofillField field;
+ test::CreateTestSelectField(kPhoneCountryCode, &field);
+ field.set_heuristic_type(PHONE_HOME_COUNTRY_CODE);
+
+ AutofillProfile address;
+ address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+918890888888"));
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("+91"), field.value);
+}
+
+// Tests that the correct option is chosen in the selection box when the options
+// are preceded by a '00' and the field is of |PHONE_HOME_COUNTRY_CODE|
+// type.
+TEST_F(AutofillFieldFillerTest,
+ FillSelectControlPhoneCountryCodePrecededByDoubleZeros) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ std::vector<const char*> kPhoneCountryCode = {"0091", "001", "0020", "0049"};
+ AutofillField field;
+ test::CreateTestSelectField(kPhoneCountryCode, &field);
+ field.set_heuristic_type(PHONE_HOME_COUNTRY_CODE);
+
+ AutofillProfile address;
+ address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+918890888888"));
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("0091"), field.value);
+}
+
+// Tests that the correct option is chosen in the selection box when the options
+// are composed of the country code and the country name.
+TEST_F(AutofillFieldFillerTest, FillSelectControlAugmentedPhoneCountryCode) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ std::vector<const char*> kPhoneCountryCode = {
+ "Please select an option", "+91 (India)", "+1 (United States)",
+ "+20 (Egypt)", "+49 (Germany)"};
+ AutofillField field;
+ test::CreateTestSelectField(kPhoneCountryCode, &field);
+ field.set_heuristic_type(PHONE_HOME_COUNTRY_CODE);
+
+ AutofillProfile address;
+ address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("+49 (Germany)"), field.value);
+}
+
+// Tests that the correct option is chosen in the selection box when the options
+// are composed of the country code having whitespace and the country name.
+TEST_F(AutofillFieldFillerTest,
+ FillSelectControlAugmentedPhoneCountryCodeWithWhiteSpaces) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ std::vector<const char*> kPhoneCountryCode = {
+ "Please select an option", "(00 91) India", "(00 1) United States",
+ "(00 20) Egypt", "(00 49) Germany"};
+ AutofillField field;
+ test::CreateTestSelectField(kPhoneCountryCode, &field);
+ field.set_heuristic_type(PHONE_HOME_COUNTRY_CODE);
+
+ AutofillProfile address;
+ address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("(00 49) Germany"), field.value);
+}
+
+// Tests that the correct option is chosen in the selection box when the options
+// are composed of the country code that is preceded by '00' and the country
+// name.
+TEST_F(AutofillFieldFillerTest,
+ FillSelectControlAugmentedPhoneCountryCodeHavingDoubleZeros) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ std::vector<const char*> kPhoneCountryCode = {
+ "Please select an option", "(0091) India", "(001) United States",
+ "(0020) Egypt", "(0049) Germany"};
+ AutofillField field;
+ test::CreateTestSelectField(kPhoneCountryCode, &field);
+ field.set_heuristic_type(PHONE_HOME_COUNTRY_CODE);
+
+ AutofillProfile address;
+ address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+ EXPECT_EQ(ASCIIToUTF16("(0049) Germany"), field.value);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/field_types.cc b/chromium/components/autofill/core/browser/field_types.cc
index d734b327ab2..d5f7ede4a7d 100644
--- a/chromium/components/autofill/core/browser/field_types.cc
+++ b/chromium/components/autofill/core/browser/field_types.cc
@@ -11,9 +11,13 @@ namespace autofill {
bool IsFillableFieldType(ServerFieldType field_type) {
switch (field_type) {
+ case NAME_HONORIFIC_PREFIX:
case NAME_FIRST:
case NAME_MIDDLE:
case NAME_LAST:
+ case NAME_LAST_FIRST:
+ case NAME_LAST_CONJUNCTION:
+ case NAME_LAST_SECOND:
case NAME_MIDDLE_INITIAL:
case NAME_FULL:
case NAME_SUFFIX:
diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h
index b8964f24f76..24e11f2b469 100644
--- a/chromium/components/autofill/core/browser/field_types.h
+++ b/chromium/components/autofill/core/browser/field_types.h
@@ -206,9 +206,17 @@ enum ServerFieldType {
// Currently not used by Chrome.
ADDRESS_HOME_OTHER_SUBUNIT = 106,
+ // Types to represent the structure of a Hispanic/Latinx last name.
+ NAME_LAST_FIRST = 107,
+ NAME_LAST_CONJUNCTION = 108,
+ NAME_LAST_SECOND = 109,
+
+ // Type to catch name additions like "Mr.", "Ms." or "Dr.".
+ NAME_HONORIFIC_PREFIX = 110,
+
// No new types can be added without a corresponding change to the Autofill
// server.
- MAX_VALID_FIELD_TYPE = 107,
+ MAX_VALID_FIELD_TYPE = 111,
};
// The list of all HTML autocomplete field type hints supported by Chrome.
@@ -219,6 +227,7 @@ enum HtmlFieldType {
// Name types.
HTML_TYPE_NAME,
+ HTML_TYPE_HONORIFIC_PREFIX,
HTML_TYPE_GIVEN_NAME,
HTML_TYPE_ADDITIONAL_NAME,
HTML_TYPE_FAMILY_NAME,
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index b243b7aa61f..1009591614b 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -466,6 +466,27 @@ 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) {
+ // Try to import by combining all sections.
+ if (ImportAddressProfileForSection(form, "", &import_log_buffer)) {
+ num_saved_profiles++;
+ AutofillMetrics::LogAddressFormImportStatustMetric(
+ AutofillMetrics::AddressProfileImportStatusMetric::
+ SECTION_UNION_IMPORT);
+ }
+ }
+ if (num_saved_profiles == 0) {
+ AutofillMetrics::LogAddressFormImportStatustMetric(
+ AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT);
+ }
}
import_log_buffer << LogMessage::kImportAddressProfileFromFormNumberOfImports
<< num_saved_profiles << CTag{};
@@ -509,7 +530,8 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Go through each |form| field and attempt to constitute a valid profile.
for (const auto& field : form) {
// Reject fields that are not within the specified |section|.
- if (field->section != section)
+ // If section is empty, use all fields.
+ if (field->section != section && !section.empty())
continue;
base::string16 value;
@@ -518,7 +540,12 @@ bool FormDataImporter::ImportAddressProfileForSection(
// 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.
- if (!field->IsFieldFillable() || !field->is_focusable || value.empty())
+ // TODO(crbug.com/1101280): Remove |skip_unfocussable_field|
+ bool skip_unfocussable_field =
+ !field->is_focusable &&
+ !base::FeatureList::IsEnabled(
+ features::kAutofillProfileImportFromUnfocusableFields);
+ if (!field->IsFieldFillable() || skip_unfocussable_field || value.empty())
continue;
AutofillType field_type = field->Type();
@@ -679,17 +706,12 @@ bool FormDataImporter::ImportCreditCard(
}
}
- // If editable expiration date experiment is enabled, the card with invalid
- // expiration date can be uploaded. However, the card with invalid card number
- // must be ignored.
+ // Cards with invalid expiration dates can be uploaded due to the existence of
+ // the expiration date fix flow. However, cards with invalid card numbers must
+ // still be ignored.
if (!candidate_credit_card.HasValidCardNumber()) {
return false;
}
- if (!candidate_credit_card.HasValidExpirationDate() &&
- !base::FeatureList::IsEnabled(
- features::kAutofillUpstreamEditableExpirationDate)) {
- return false;
- }
// Can import one valid card per form. Start by treating it as NEW_CARD, but
// overwrite this type if we discover it is already a local or server card.
@@ -711,6 +733,15 @@ bool FormDataImporter::ImportCreditCard(
// already a local card.
imported_credit_card_record_type_ =
ImportedCreditCardRecordType::LOCAL_CARD;
+
+ // If the card is a local card and it has a nickname stored in the local
+ // database, copy the nickname to the |candidate_credit_card| so that the
+ // nickname also shows in the Upstream bubble.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableSurfacingServerCardNickname)) {
+ candidate_credit_card.SetNickname(card_copy.nickname());
+ }
+
// If we should not return the local card, return that we merged it,
// without setting |imported_credit_card|.
if (!should_return_local_card)
diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h
index d255cbd8625..38d0b12fd9a 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.h
+++ b/chromium/components/autofill/core/browser/form_data_importer.h
@@ -114,7 +114,8 @@ class FormDataImporter {
bool ImportAddressProfiles(const FormStructure& form);
// Helper method for ImportAddressProfiles which only considers the fields for
- // a specified |section|.
+ // a specified |section|. If |section| is the empty string, the import is
+ // performed on the union of all sections.
bool ImportAddressProfileForSection(const FormStructure& form,
const std::string& section,
LogBuffer* import_log_buffer);
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 ca166dfaea8..1487f0ff2e2 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -306,7 +306,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -319,6 +319,60 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) {
EXPECT_EQ(0, expected.Compare(*results[0]));
}
+TEST_F(FormDataImporterTest, ImportAddressProfileFromUnifiedSection) {
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+
+ // 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);
+ test::SetProfileInfo(&expected, "George", nullptr, "Washington",
+ "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
+ "San Francisco", "California", "94102", nullptr,
+ nullptr);
+ const std::vector<AutofillProfile*>& results2 =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results2.size());
+ EXPECT_EQ(0, expected.Compare(*results2[0]));
+}
+
TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) {
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -343,7 +397,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
}
@@ -374,7 +428,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoEmails) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
}
@@ -405,7 +459,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
}
@@ -427,7 +481,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
@@ -455,7 +509,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressUSA) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
}
@@ -482,7 +536,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGB) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
}
@@ -504,7 +558,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGI) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
}
@@ -544,7 +598,7 @@ TEST_F(FormDataImporterTest,
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
@@ -556,6 +610,64 @@ TEST_F(FormDataImporterTest,
EXPECT_EQ(0, expected.Compare(*results[0]));
}
+TEST_F(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Phone:", "phone", "1234554321", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ // Set this field to be unfocusable.
+ field.is_focusable = false;
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+
+ // 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_.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);
+ test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
+ nullptr, "21 Laussat St", nullptr, "San Francisco",
+ "California", "94102", nullptr, "1234554321");
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, expected.Compare(*results[0]));
+}
+
TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) {
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -583,7 +695,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -623,7 +735,7 @@ TEST_F(FormDataImporterTest,
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure1);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -659,7 +771,7 @@ TEST_F(FormDataImporterTest,
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure2);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
@@ -716,7 +828,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -790,7 +902,7 @@ TEST_F(FormDataImporterTest,
// Still able to do the import.
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -872,7 +984,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// Only two are saved.
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -926,7 +1038,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure1);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -972,7 +1084,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure2);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
const std::vector<AutofillProfile*>& results2 =
personal_data_manager_->GetProfiles();
@@ -1009,7 +1121,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure1);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
@@ -1045,7 +1157,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure2);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
const std::vector<AutofillProfile*>& results2 =
personal_data_manager_->GetProfiles();
@@ -1089,7 +1201,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure1);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure1);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -1127,7 +1239,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure2);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
const std::vector<AutofillProfile*>& results2 =
personal_data_manager_->GetProfiles();
@@ -1163,7 +1275,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_InsufficientAddress) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure1);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure1);
// Since no refresh is expected, reload the data from the database to make
// sure no changes were written out.
@@ -1219,7 +1331,7 @@ TEST_F(FormDataImporterTest,
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// Expect that no new profile is saved.
const std::vector<AutofillProfile*>& results =
@@ -1237,7 +1349,7 @@ TEST_F(FormDataImporterTest,
FormStructure form_structure2(form);
form_structure2.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure2);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
// Expect that no new profile is saved.
const std::vector<AutofillProfile*>& results2 =
@@ -1276,7 +1388,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
// Since no refresh is expected, reload the data from the database to make
// sure no changes were written out.
@@ -1320,7 +1432,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_LocalizedCountryName) {
// the page language is not set.
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
@@ -1334,7 +1446,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_LocalizedCountryName) {
// enabled.
scoped_feature_list_.InitAndDisableFeature(
features::kAutofillUsePageLanguageToTranslateCountryNames);
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
// There should be no imported address profile.
ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
@@ -1345,7 +1457,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_LocalizedCountryName) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillUsePageLanguageToTranslateCountryNames);
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// There should be one imported address profile.
ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size());
@@ -1392,7 +1504,7 @@ TEST_F(FormDataImporterTest,
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/true, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -1439,7 +1551,7 @@ TEST_F(FormDataImporterTest,
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- ImportAddressProfiles(/*extraction_success=*/false, form_structure);
+ ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
// Since no refresh is expected, reload the data from the database to make
// sure no changes were written out.
@@ -1507,39 +1619,10 @@ TEST_F(FormDataImporterTest, ImportCreditCard_InvalidCardNumber) {
ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
}
-// Tests that an invalid credit card expiration is not extracted when the
-// expiration date fix flow experiment is disabled.
-TEST_F(FormDataImporterTest, ImportCreditCard_InvalidExpiryDate) {
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
- FormData form;
- form.url = GURL("https://wwww.foo.com");
-
- AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "0",
- "2999");
-
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- std::unique_ptr<CreditCard> imported_credit_card;
- base::HistogramTester histogram_tester;
- EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
- ASSERT_FALSE(imported_credit_card);
- histogram_tester.ExpectUniqueSample("Autofill.SubmittedCardState",
- AutofillMetrics::HAS_CARD_NUMBER_ONLY, 1);
-
- // Since no refresh is expected, reload the data from the database to make
- // sure no changes were written out.
- ResetPersonalDataManager(USER_MODE_NORMAL);
-
- ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
-}
-
-// Tests that an empty credit card expiration is extracted when editable
-// expiration date experiment on.
+// Tests that a credit card with an empty expiration can be extracted due to the
+// expiration date fix flow.
TEST_F(FormDataImporterTest,
ImportCreditCard_InvalidExpiryDate_EditableExpirationExpOn) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -1555,12 +1638,10 @@ TEST_F(FormDataImporterTest,
AutofillMetrics::HAS_CARD_NUMBER_ONLY, 1);
}
-// Tests that an expired credit card is extracted when editable expiration date
-// experiment on.
+// Tests that an expired credit card can be extracted due to the expiration date
+// fix flow.
TEST_F(FormDataImporterTest,
ImportCreditCard_ExpiredExpiryDate_EditableExpirationExpOn) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -2458,38 +2539,7 @@ TEST_F(FormDataImporterTest,
// Ensures that |imported_credit_card_record_type_| is set correctly.
TEST_F(
FormDataImporterTest,
- ImportFormData_ImportCreditCardRecordType_NoCard_ExpiredCard_EditableExpDateOff) {
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
- // Simulate a form submission with an expired credit card.
- FormData form;
- form.url = GURL("https://wwww.foo.com");
-
- AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01",
- "1999");
-
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- std::unique_ptr<CreditCard> imported_credit_card;
- base::Optional<std::string> imported_upi_id;
- EXPECT_FALSE(form_data_importer_->ImportFormData(
- form_structure, /*profile_autofill_enabled=*/true,
- /*credit_card_autofill_enabled=*/true,
- /*should_return_local_card=*/true, &imported_credit_card,
- &imported_upi_id));
- ASSERT_FALSE(imported_credit_card);
- // |imported_credit_card_record_type_| should be NO_CARD because no valid card
- // was successfully imported from the form.
- ASSERT_TRUE(form_data_importer_->imported_credit_card_record_type_ ==
- FormDataImporter::ImportedCreditCardRecordType::NO_CARD);
-}
-
-// Ensures that |imported_credit_card_record_type_| is set correctly.
-TEST_F(
- FormDataImporterTest,
ImportFormData_ImportCreditCardRecordType_NewCard_ExpiredCard_WithExpDateFixFlow) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
// Simulate a form submission with an expired credit card.
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -3110,8 +3160,6 @@ TEST_F(FormDataImporterTest,
// server card and user submitted an invalid expiration date month.
TEST_F(FormDataImporterTest,
Metrics_SubmittedServerCardExpirationStatus_EmptyExpirationMonth) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
EnableWalletCardImport();
std::vector<CreditCard> server_cards;
@@ -3160,8 +3208,6 @@ TEST_F(FormDataImporterTest,
// server card and user submitted an invalid expiration date year.
TEST_F(FormDataImporterTest,
Metrics_SubmittedServerCardExpirationStatus_EmptyExpirationYear) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
EnableWalletCardImport();
std::vector<CreditCard> server_cards;
@@ -3211,8 +3257,6 @@ TEST_F(FormDataImporterTest,
TEST_F(
FormDataImporterTest,
Metrics_SubmittedDifferentServerCardExpirationStatus_EmptyExpirationYear) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
EnableWalletCardImport();
std::vector<CreditCard> server_cards;
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 36e09498599..3495f488b98 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
@@ -20,6 +20,7 @@
#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"
@@ -212,7 +213,7 @@ std::unique_ptr<FormField> CreditCardField::Parse(AutofillScanner* scanner,
continue;
}
- if (credit_card_field->ParseExpirationDate(scanner)) {
+ if (credit_card_field->ParseExpirationDate(scanner, log_manager)) {
nb_unknown_fields = 0;
continue;
}
@@ -308,7 +309,8 @@ bool CreditCardField::LikelyCardMonthSelectField(AutofillScanner* scanner) {
}
// static
-bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) {
+bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner,
+ LogManager* log_manager) {
if (scanner->IsEnd())
return false;
@@ -317,18 +319,48 @@ bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) {
MATCH_SELECT | MATCH_SEARCH))
return false;
+ // Filter out days - elements for date entries would have
+ // numbers 1 to 9 as well in them, which we can filter on.
+ const base::string16 kSingleDigitDateRe = base::ASCIIToUTF16("\\b[1-9]\\b");
+ for (const auto& value : field->option_contents) {
+ if (MatchesPattern(value, kSingleDigitDateRe)) {
+ return false;
+ }
+ }
+
+ // Another way to eliminate days - filter out 'day' fields.
+ if (FormField::ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDayRe),
+ MATCH_DEFAULT | MATCH_SELECT, nullptr,
+ {log_manager, "kDayRe"})) {
+ return false;
+ }
+
+ // Filter out birth years - a website would not offer 1999 as a credit card
+ // expiration year, but show it in the context of a birth year selector.
+ const base::string16 kBirthYearRe = base::ASCIIToUTF16("(1999|99)");
+ for (const auto& value : field->option_contents) {
+ if (MatchesPattern(value, kBirthYearRe)) {
+ return false;
+ }
+ }
+
const base::Time time_now = AutofillClock::Now();
base::Time::Exploded time_exploded;
time_now.UTCExplode(&time_exploded);
const int kYearsToMatch = 3;
- std::vector<base::string16> years_to_check;
+ std::vector<base::string16> years_to_check_4_digit;
+ std::vector<base::string16> years_to_check_2_digit;
for (int year = time_exploded.year; year < time_exploded.year + kYearsToMatch;
++year) {
- years_to_check.push_back(base::NumberToString16(year));
+ years_to_check_4_digit.push_back(base::NumberToString16(year));
+ years_to_check_2_digit.push_back(base::NumberToString16(year).substr(2));
}
- return (FindConsecutiveStrings(years_to_check, field->option_values) ||
- FindConsecutiveStrings(years_to_check, field->option_contents));
+ return (
+ FindConsecutiveStrings(years_to_check_4_digit, field->option_values) ||
+ FindConsecutiveStrings(years_to_check_4_digit, field->option_contents) ||
+ FindConsecutiveStrings(years_to_check_2_digit, field->option_values) ||
+ FindConsecutiveStrings(years_to_check_2_digit, field->option_contents));
}
// static
@@ -359,20 +391,25 @@ bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
if (scanner->IsEnd())
return false;
+ const int kMatchFieldTypes =
+ MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_SEARCH;
size_t saved_cursor = scanner->SaveCursor();
- if (ParseField(scanner, base::UTF8ToUTF16(kDebitCardRe), nullptr,
- {log_manager, "kDebitCardRe"})) {
+ if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitCardRe),
+ kMatchFieldTypes, nullptr,
+ {log_manager, "kDebitCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
- if (ParseField(scanner, base::UTF8ToUTF16(kDebitGiftCardRe), nullptr,
- {log_manager, "kDebitGiftCardRe"})) {
+ if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitGiftCardRe),
+ kMatchFieldTypes, nullptr,
+ {log_manager, "kDebitGiftCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
- return ParseField(scanner, base::UTF8ToUTF16(kGiftCardRe), nullptr,
- {log_manager, "kGiftCardRe"});
+ return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kGiftCardRe),
+ kMatchFieldTypes, nullptr,
+ {log_manager, "kGiftCardRe"});
}
CreditCardField::CreditCardField(LogManager* log_manager)
@@ -427,7 +464,8 @@ void CreditCardField::AddClassifications(
}
}
-bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) {
+bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
+ LogManager* log_manager) {
if (!expiration_date_ && base::LowerCaseEqualsASCII(
scanner->Cursor()->form_control_type, "month")) {
expiration_date_ = scanner->Cursor();
@@ -447,7 +485,7 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) {
if (LikelyCardMonthSelectField(scanner)) {
expiration_month_ = scanner->Cursor();
scanner->Advance();
- if (LikelyCardYearSelectField(scanner)) {
+ if (LikelyCardYearSelectField(scanner, log_manager)) {
expiration_year_ = scanner->Cursor();
scanner->Advance();
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 9db7aec100f..abd4eb9a961 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
@@ -38,8 +38,10 @@ class CreditCardField : public FormField {
// Returns true if |scanner| points to a field that looks like a year
// <select> for a credit card. i.e. it contains the current year and
- // the next few years.
- static bool LikelyCardYearSelectField(AutofillScanner* scanner);
+ // 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);
// Returns true if |scanner| points to a <select> field that contains credit
// card type options.
@@ -54,7 +56,7 @@ class CreditCardField : public FormField {
// Parses the expiration month/year/date fields. Returns true if it finds
// something new.
- bool ParseExpirationDate(AutofillScanner* scanner);
+ bool ParseExpirationDate(AutofillScanner* scanner, LogManager* log_manager);
// 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 865e1893f21..e876c72ec64 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
@@ -9,9 +9,11 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -152,6 +154,72 @@ TEST_F(CreditCardFieldTest, ParseMiniumCreditCard) {
field_candidates_map_[ASCIIToUTF16("year3")].BestHeuristicType());
}
+TEST_F(CreditCardFieldTest, ParseMinimumCreditCardWithExpiryDateOptions) {
+ FormFieldData cc_number_field;
+ FormFieldData month_field;
+ FormFieldData year_field;
+
+ cc_number_field.form_control_type = "text";
+ cc_number_field.label = ASCIIToUTF16("Card Number");
+ cc_number_field.name = ASCIIToUTF16("card_number");
+ list_.push_back(
+ std::make_unique<AutofillField>(cc_number_field, ASCIIToUTF16("number")));
+
+ // For month field, set the label and name to something which won't match
+ // any regex, so we can test matching of the options themselves.
+ month_field.form_control_type = "select-one";
+ month_field.label = ASCIIToUTF16("Random label");
+ month_field.name = ASCIIToUTF16("Random name");
+ const std::vector<std::string> kMonths{"MM", "01", "02", "03", "04",
+ "05", "06", "07", "08", "09",
+ "10", "11", "12"};
+ for (auto month : kMonths) {
+ month_field.option_contents.push_back(base::UTF8ToUTF16(month));
+ month_field.option_values.push_back(base::UTF8ToUTF16(month));
+ }
+ list_.push_back(
+ std::make_unique<AutofillField>(month_field, ASCIIToUTF16("month")));
+
+ // For year, keep the label and name to something which doesn't match regex
+ // so we can test matching of the options themselves.
+ year_field.form_control_type = "select-one";
+ year_field.label = ASCIIToUTF16("Random label");
+ year_field.name = ASCIIToUTF16("Random name");
+ year_field.max_length = 2;
+ year_field.option_contents.push_back(base::ASCIIToUTF16("YY"));
+ year_field.option_values.push_back(base::ASCIIToUTF16("YY"));
+
+ const base::Time time_now = AutofillClock::Now();
+ base::Time::Exploded time_exploded;
+ time_now.UTCExplode(&time_exploded);
+ const int kYearsToAdd = 10;
+
+ for (auto year = time_exploded.year; year < time_exploded.year + kYearsToAdd;
+ year++) {
+ year_field.option_contents.push_back(
+ base::NumberToString16(year).substr(2));
+ year_field.option_values.push_back(base::NumberToString16(year).substr(2));
+ }
+ list_.push_back(
+ std::make_unique<AutofillField>(year_field, ASCIIToUTF16("year")));
+
+ Parse();
+ ASSERT_NE(nullptr, field_.get());
+ AddClassifications();
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NUMBER,
+ field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+ field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
+ field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
+}
+
TEST_F(CreditCardFieldTest, ParseFullCreditCard) {
FormFieldData field;
field.form_control_type = "text";
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 a067e9ca0ba..d7079bfd751 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
@@ -17,11 +17,33 @@
#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/common/autofill_features.h"
#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
namespace {
+// Minimum limit on the number of the options of the select field for
+// determining the field to be of |PHONE_HOME_COUNTRY_CODE| type.
+constexpr int kMinSelectOptionsForCountryCode = 5;
+
+// Maximum limit on the number of the options of the select field for
+// determining the field to be of |PHONE_HOME_COUNTRY_CODE| type.
+// Currently, there are approximately 250 countries that have been assigned a
+// phone country code, therefore, 275 is taken as the upper bound.
+constexpr int kMaxSelectOptionsForCountryCode = 275;
+
+// Minimum percentage of options in select field that should look like a
+// country code in order to classify the field as a |PHONE_HOME_COUNTRY_CODE|.
+constexpr int kMinCandidatePercentageForCountryCode = 90;
+
+// If a <select> element has <= |kHeuristicThresholdForCountryCode| options,
+// all or all-but-one need to look like country code options. Otherwise,
+// |kMinCandidatePercentageForCountryCode| is used to check for a fraction
+// of country code like options.
+constexpr int kHeuristicThresholdForCountryCode = 10;
+
// This string includes all area code separators, including NoText.
std::string GetAreaRegex() {
std::string area_code = kAreaCodeRe;
@@ -131,6 +153,65 @@ const PhoneField::Parser PhoneField::kPhoneFieldGrammars[] = {
};
// static
+bool PhoneField::LikelyAugmentedPhoneCountryCode(
+ AutofillScanner* scanner,
+ AutofillField** matched_field) {
+ // If the experiment |kAutofillEnableAugmentedPhoneCountryCode| is not
+ // enabled, return false.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableAugmentedPhoneCountryCode))
+ return false;
+
+ AutofillField* field = scanner->Cursor();
+
+ // Return false if the field is not a selection box.
+ if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
+ return false;
+
+ // If the number of the options is less than the minimum limit or more than
+ // the maximum limit, return false.
+ if (field->option_contents.size() < kMinSelectOptionsForCountryCode ||
+ field->option_contents.size() >= kMaxSelectOptionsForCountryCode)
+ return false;
+
+ // |total_covered_options| stores the count of the options that are
+ // compared with the regex.
+ int total_num_options = static_cast<int>(field->option_contents.size());
+
+ // |total_positive_options| stores the count of the options that match the
+ // regex.
+ int total_positive_options = 0;
+
+ for (const auto& option : field->option_contents) {
+ if (MatchesPattern(option,
+ base::ASCIIToUTF16(kAugmentedPhoneCountryCodeRe)))
+ total_positive_options++;
+ }
+
+ // If the number of the options compared is less or equal to
+ // |kHeuristicThresholdForCountryCode|, then either all the options or all
+ // options but one should match the regex.
+ if (total_num_options <= kHeuristicThresholdForCountryCode &&
+ total_positive_options + 1 < total_num_options)
+ return false;
+
+ // If the number of the options compared is more than
+ // |kHeuristicThresholdForCountryCode|,
+ // |kMinCandidatePercentageForCountryCode|% of the options should match the
+ // regex.
+ if (total_num_options > kHeuristicThresholdForCountryCode &&
+ total_positive_options * 100 <
+ total_num_options * kMinCandidatePercentageForCountryCode)
+ return false;
+
+ // Assign the |matched_field| and advance the cursor.
+ if (matched_field)
+ *matched_field = field;
+ scanner->Advance();
+ return true;
+}
+
+// static
std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
LogManager* log_manager) {
if (scanner->IsEnd())
@@ -149,11 +230,22 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
for (; i < base::size(kPhoneFieldGrammars) &&
kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR;
++i) {
+ const bool is_country_code_field =
+ kPhoneFieldGrammars[i].phone_part == FIELD_COUNTRY_CODE;
+
+ // The field length comparison with |kPhoneFieldGrammars[i].max_size| is
+ // not required in case of the selection boxes that are of phone country
+ // code type.
+ if (is_country_code_field &&
+ LikelyAugmentedPhoneCountryCode(scanner,
+ &parsed_fields[FIELD_COUNTRY_CODE]))
+ continue;
+
if (!ParsePhoneField(
scanner, GetRegExp(kPhoneFieldGrammars[i].regex),
&parsed_fields[kPhoneFieldGrammars[i].phone_part],
{log_manager, GetRegExpName(kPhoneFieldGrammars[i].regex)},
- (kPhoneFieldGrammars[i].phone_part == FIELD_COUNTRY_CODE)))
+ is_country_code_field))
break;
if (kPhoneFieldGrammars[i].max_size &&
(!parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length ||
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 b9067d7a250..96c38133568 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
@@ -102,6 +102,13 @@ class PhoneField : public FormField {
const RegExLogging& logging,
const bool is_country_code_field);
+ // Returns true if |scanner| points to a <select> field that appears to be the
+ // phone country code by looking at its option contents.
+ // "Augmented" refers to the fact that we are looking for select options that
+ // contain not only a country code but also further text like "Germany (+49)".
+ static bool LikelyAugmentedPhoneCountryCode(AutofillScanner* scanner,
+ AutofillField** match);
+
// FIELD_PHONE is always present; holds suffix if prefix is present.
// The rest could be NULL.
AutofillField* parsed_phone_fields_[FIELD_MAX];
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 22754b699a2..f5a2d7cb76e 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
@@ -13,8 +13,10 @@
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -59,6 +61,22 @@ class PhoneFieldTest : public testing::Test {
EXPECT_EQ(expected_type, it->second.BestHeuristicType()) << name;
}
+ // Populates a select |field| with the |label|, the |name| and the |contents|.
+ void CreateTestSelectField(const char* label,
+ const char* name,
+ const std::vector<const char*>& contents,
+ FormFieldData* field) {
+ field->label = ASCIIToUTF16(label);
+ field->name = ASCIIToUTF16(name);
+ field->form_control_type = "select-one";
+
+ std::vector<base::string16> contents16;
+ for (auto* const element : contents)
+ contents16.push_back(base::UTF8ToUTF16(element));
+
+ field->option_contents = contents16;
+ }
+
std::vector<std::unique_ptr<AutofillField>> list_;
std::unique_ptr<PhoneField> field_;
FieldCandidatesMap field_candidates_map_;
@@ -335,4 +353,317 @@ TEST_F(PhoneFieldTest, CountryCodeIsSelectElement) {
CheckField("phoneNumber", PHONE_HOME_NUMBER);
}
+// Tests if the country code, city code and phone number fields are correctly
+// classified by the heuristic when the phone code field is a select element
+// consisting of valid options.
+TEST_F(PhoneFieldTest, CountryCodeWithOptions) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ FormFieldData field;
+
+ // Options consisting of the country code followed by the country names.
+ std::vector<const char*> augmented_field_options_list = {
+ "(+91) India", "(+49) Germany", "(+1) United States", "(+20) Egypt",
+ "(+1242) Bahamas", "(+593) Ecuador", "(+7) Russia"};
+ CreateTestSelectField("PC", "PC", augmented_field_options_list, &field);
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("countryCode")));
+
+ field.label = ASCIIToUTF16("Phone City Code");
+ field.name = ASCIIToUTF16("areacode");
+ field.form_control_type = "text";
+ field.max_length = 3;
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("cityCode")));
+
+ field.label = ASCIIToUTF16("Phone Number");
+ field.name = ASCIIToUTF16("phonenumber");
+ field.max_length = 0;
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_NE(nullptr, field_.get());
+ field_->AddClassificationsForTesting(&field_candidates_map_);
+ CheckField("countryCode", PHONE_HOME_COUNTRY_CODE);
+ CheckField("cityCode", PHONE_HOME_CITY_CODE);
+ CheckField("phoneNumber", PHONE_HOME_NUMBER);
+}
+
+// Tests if the country code field is correctly classified by the heuristic when
+// the phone code is a select element and consists of valid options.
+TEST_F(PhoneFieldTest, IsPhoneCountryCodeField) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ FormFieldData field;
+ std::vector<std::vector<const char*>> augmented_field_options_list = {
+ // Options with the country name followed by the country code in brackets.
+ {"India(+91) ", "Germany(+49)", "United States(+1)", "Egypt(+20)",
+ "Bahamas(+1242)", "Ecuador(+593)", "Russia(+7)"},
+
+ // Options consisting of the country code totaling more than 20.
+ {"+91", "+49", "+1", "+20", "+1242", "+593", "+7",
+ "+1441", "+211", "+212", "+30", "+31", "+32", "+33",
+ "+34", "+51", "52", "+673", "+674", "+81", "+82"},
+
+ // Options consisting of the country code totaling more than 20 with an
+ // additional placeholder option.
+ {"+91", "+49",
+ "+1", "+20",
+ "+1242", "+593",
+ "+7", "+1441",
+ "+211", "+212",
+ "+30", "+31",
+ "+32", "+33",
+ "+34", "+51",
+ "52", "+673",
+ "+674", "+81",
+ "+82", "Please select an option"},
+
+ // Options with the country name followed by the country code in brackets
+ // along with a placeholder option.
+ {"Please select an option", "(+91) India", "(+49) Germany",
+ "(+1) United States", "(+20) Egypt", "(+1242) Bahamas", "(+593) Ecuador",
+ "(+7) Russia"},
+
+ // Options with the phone country code followed by the country
+ // abbreviation.
+ {"91 IN", "49 DE", "1 US", "20 E", "1242 B", "593 EQ", "7 R"},
+
+ // Options with the phone country code that are preceded by '00' and
+ // followed by the country abbreviation.
+ {"(0091) IN", "(0049) DE", "(001) US", "(0020) E", "(001242) B",
+ "(00593) EQ", "(007) R"},
+
+ // Options with the phone country code that are preceded by '00' and
+ // followed by the country abbreviation with single space in between.
+ {"(00 91) IN", "(00 49) DE", "(00 1) US", "(00 20) E", "(00 1242) B",
+ "(00 593) EQ", "(00 7) R"},
+
+ // Options with the phone country code preceded by '00' with multiple
+ // spaces in between to align them.
+ {"00 91", "00 49", "00 1", "00 20", "001242", "00 593", "00 7"},
+
+ // Options with the phone country code preceded by '00'.
+ {"0091", "0049", "001", "0020", "001242", "00593", "007"}};
+
+ for (size_t i = 0; i < augmented_field_options_list.size(); ++i) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+ const auto& options_list = augmented_field_options_list[i];
+ CreateTestSelectField("PC", "PC", options_list, &field);
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("countryCode")));
+
+ field.label = ASCIIToUTF16("Phone Number");
+ field.name = ASCIIToUTF16("phonenumber");
+ field.max_length = 14;
+ field.form_control_type = "text";
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_NE(nullptr, field_.get());
+ field_->AddClassificationsForTesting(&field_candidates_map_);
+ CheckField("countryCode", PHONE_HOME_COUNTRY_CODE);
+ }
+} // namespace autofill
+
+// Tests that the month field is not classified as |PHONE_HOME_COUNTRY_CODE|.
+TEST_F(PhoneFieldTest, IsMonthField) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ FormFieldData field;
+ std::vector<std::vector<const char*>> augmented_field_options_list = {
+ // Month options in numeric.
+ {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"},
+
+ // Month options in numeric followed by the respective text.
+ {"(01) Jan", "(02) Feb", "(03) March", "(04) April", "(05) May",
+ "(06) June", "(07) July", "(08) August", "(09) Sept", "(10) Oct",
+ "(11) Nov", "(12) Dec"}};
+
+ for (size_t i = 0; i < augmented_field_options_list.size(); ++i) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+ const auto& options_list = augmented_field_options_list[i];
+ CreateTestSelectField("Month", "Month", options_list, &field);
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("months")));
+
+ field.label = ASCIIToUTF16("Phone Number");
+ field.name = ASCIIToUTF16("phonenumber");
+ field.max_length = 14;
+ field.form_control_type = "text";
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_EQ(nullptr, field_.get());
+ }
+}
+
+// Tests that the day field is not classified as |PHONE_HOME_COUNTRY_CODE|.
+TEST_F(PhoneFieldTest, IsDayField) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ FormFieldData field;
+ std::vector<std::vector<const char*>> augmented_field_options_list = {
+ // Numeric day options.
+ {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
+ "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
+ "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"},
+
+ // Numeric day options with a select option placeholder.
+ {"Please select an option",
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ "08",
+ "09",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "20",
+ "21",
+ "22",
+ "23",
+ "24",
+ "25",
+ "26",
+ "27",
+ "28",
+ "29",
+ "30"}};
+
+ for (size_t i = 0; i < augmented_field_options_list.size(); ++i) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+ const auto& options_list = augmented_field_options_list[i];
+ CreateTestSelectField("Field", "Field", options_list, &field);
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("day")));
+
+ field.label = ASCIIToUTF16("Phone Number");
+ field.name = ASCIIToUTF16("phonenumber");
+ field.max_length = 14;
+ field.form_control_type = "text";
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_EQ(nullptr, field_.get());
+ }
+}
+
+// Tests that the field is not classified as |PHONE_HOME_COUNTRY_CODE|.
+TEST_F(PhoneFieldTest, IsYearField) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ FormFieldData field;
+ std::vector<std::vector<const char*>> augmented_field_options_list = {
+ // Numeric four digit year options.
+ {"1990", "1991", "1992", "1993", "1994", "1995", "1996",
+ "1997", "1998", "1999", "2000", "2001", "2002", "2003",
+ "2004", "2005", "2006", "2007", "2008", "2009", "2010"},
+
+ // Numeric four digit year options less than 10 in total.
+ {"1990", "1991", "1992", "1993", "1994"},
+
+ // Numeric four digit year options in decreasing order.
+ {"2025", "2024", "2023", "2022", "2021", "2020"},
+
+ // Numeric two digit year options.
+ {"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "00", "01",
+ "02", "03", "04", "05", "06"},
+
+ // Numeric two digit year options along with an additional placeholder
+ // option.
+ {"Please select an option", "90", "91", "92", "93", "94", "95", "96",
+ "97", "98", "99", "00", "01", "02", "03", "04", "05", "06"},
+
+ // Numeric two digit year options along with an additional placeholder
+ // option less than 10 in total.
+ {"Please select an option", "90", "91", "92", "93", "94"}};
+
+ for (size_t i = 0; i < augmented_field_options_list.size(); ++i) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+ const auto& options_list = augmented_field_options_list[i];
+ CreateTestSelectField("Field", "Field", options_list, &field);
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("year")));
+
+ field.label = ASCIIToUTF16("Phone Number");
+ field.name = ASCIIToUTF16("phonenumber");
+ field.max_length = 14;
+ field.form_control_type = "text";
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_EQ(nullptr, field_.get());
+ }
+}
+
+// Tests that the timezone field is not classified as |PHONE_HOME_COUNTRY_CODE|.
+TEST_F(PhoneFieldTest, IsTimeZoneField) {
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableAugmentedPhoneCountryCode);
+
+ FormFieldData field;
+ std::vector<std::vector<const char*>> augmented_field_options_list = {
+ // Time Zone options.
+ {"Yemen (UTC+03:00)", "Uruguay (UTC−03:00)", "UAE (UTC+04:00)",
+ "Uganda (UTC+03:00)", "Turkey (UTC+03:00)", "Taiwan (UTC+08:00)",
+ "Sweden (UTC+01:00)"},
+
+ // Time Zone options with a placeholder select element.
+ {"Please select an option", "Yemen (UTC+03:00)", "Uruguay (UTC−03:00)",
+ "UAE (UTC+04:00)", "Uganda (UTC+03:00)", "Turkey (UTC+03:00)",
+ "Taiwan (UTC+08:00)", "Sweden (UTC+01:00)"}};
+
+ for (size_t i = 0; i < augmented_field_options_list.size(); ++i) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+ const auto& options_list = augmented_field_options_list[i];
+ CreateTestSelectField("Time Zone", "TimeZone", options_list, &field);
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("timeZone")));
+
+ field.label = ASCIIToUTF16("Phone Number");
+ field.name = ASCIIToUTF16("phonenumber");
+ field.max_length = 14;
+ field.form_control_type = "text";
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("phoneNumber")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_EQ(nullptr, field_.get());
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index 8001381efa8..66e954488ec 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -61,7 +61,6 @@
namespace autofill {
-using mojom::ButtonTitleType;
using mojom::SubmissionIndicatorEvent;
namespace {
@@ -169,6 +168,9 @@ HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
if (autocomplete_attribute_value == "name")
return HTML_TYPE_NAME;
+ if (autocomplete_attribute_value == "honorific-prefix")
+ return HTML_TYPE_HONORIFIC_PREFIX;
+
if (autocomplete_attribute_value == "given-name" ||
autocomplete_attribute_value == "given_name" ||
autocomplete_attribute_value == "first-name" ||
@@ -359,32 +361,6 @@ HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
return HTML_TYPE_UNRECOGNIZED;
}
-// Helper function for explicit conversion between |ButtonTitleType| defined in
-// "autofill_types.mojom.h" and "server.proto".
-AutofillUploadContents_ButtonTitle_ButtonTitleType ToServerButtonTitleType(
- ButtonTitleType input) {
- switch (input) {
- case ButtonTitleType::NONE:
- return AutofillUploadContents::ButtonTitle::NONE;
- case ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE:
- return AutofillUploadContents::ButtonTitle::BUTTON_ELEMENT_SUBMIT_TYPE;
- case ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE:
- return AutofillUploadContents::ButtonTitle::BUTTON_ELEMENT_BUTTON_TYPE;
- case ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE:
- return AutofillUploadContents::ButtonTitle::INPUT_ELEMENT_SUBMIT_TYPE;
- case ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE:
- return AutofillUploadContents::ButtonTitle::INPUT_ELEMENT_BUTTON_TYPE;
- case ButtonTitleType::HYPERLINK:
- return AutofillUploadContents::ButtonTitle::HYPERLINK;
- case ButtonTitleType::DIV:
- return AutofillUploadContents::ButtonTitle::DIV;
- case ButtonTitleType::SPAN:
- return AutofillUploadContents::ButtonTitle::SPAN;
- }
- NOTREACHED();
- return AutofillUploadContents::ButtonTitle::NONE;
-}
-
std::ostream& operator<<(
std::ostream& out,
const autofill::AutofillQueryResponseContents& response) {
@@ -394,6 +370,22 @@ std::ostream& operator<<(
return out;
}
+std::ostream& operator<<(std::ostream& out,
+ const autofill::AutofillQueryResponse& response) {
+ for (const auto& form : response.form_suggestions()) {
+ out << "\nForm";
+ for (const auto& field : form.field_suggestions()) {
+ out << "\n Field\n signature: " << field.field_signature();
+ if (field.has_primary_type_prediction())
+ out << "\n primary_type_prediction: "
+ << field.primary_type_prediction();
+ for (const auto& prediction : field.predictions())
+ out << "\n prediction: " << prediction.type();
+ }
+ }
+ return out;
+}
+
// Returns true iff all form fields autofill types are in |contained_types|.
bool AllTypesCaptured(const FormStructure& form,
const ServerFieldTypeSet& contained_types) {
@@ -467,11 +459,21 @@ void PopulateRandomizedFormMetadata(const RandomizedEncoder& encoder,
RandomizedEncoder::FORM_NAME, form.name_attribute(),
metadata->mutable_name());
}
+
+ for (const ButtonTitleInfo& e : form.button_titles()) {
+ auto* button_title = metadata->add_button_title();
+ DCHECK(!e.first.empty());
+ EncodeRandomizedValue(encoder, form_signature, kNullFieldSignature,
+ RandomizedEncoder::FORM_BUTTON_TITLES, e.first,
+ button_title->mutable_title());
+ button_title->set_type(static_cast<ButtonTitleType>(e.second));
+ }
auto full_source_url = form.full_source_url().spec();
if (encoder.AnonymousUrlCollectionIsEnabled() && !full_source_url.empty()) {
EncodeRandomizedValue(encoder, form_signature, kNullFieldSignature,
RandomizedEncoder::FORM_URL, full_source_url,
metadata->mutable_url());
+ metadata->set_checksum_for_url(StrToHash32Bit(full_source_url));
}
}
@@ -677,8 +679,11 @@ bool FormStructure::EncodeUploadRequest(
bool form_was_autofilled,
const std::string& login_form_signature,
bool observed_submission,
- AutofillUploadContents* upload) const {
+ AutofillUploadContents* upload,
+ FormAndFieldSignatures* encoded_signatures) const {
DCHECK(AllTypesCaptured(*this, available_field_types));
+ encoded_signatures->clear();
+
upload->set_submission(observed_submission);
upload->set_client_version(kClientVersion);
upload->set_form_signature(form_signature().value());
@@ -712,7 +717,7 @@ bool FormStructure::EncodeUploadRequest(
for (const ButtonTitleInfo& e : button_titles_) {
auto* button_title = upload->add_button_title();
button_title->set_title(base::UTF16ToUTF8(e.first));
- button_title->set_type(ToServerButtonTitleType(e.second));
+ button_title->set_type(static_cast<ButtonTitleType>(e.second));
}
}
@@ -725,36 +730,38 @@ bool FormStructure::EncodeUploadRequest(
if (IsMalformed())
return false; // Malformed form, skip it.
- EncodeFormForUpload(upload);
+ EncodeFormForUpload(upload, encoded_signatures);
return true;
}
// static
bool FormStructure::EncodeQueryRequest(
const std::vector<FormStructure*>& forms,
- std::vector<std::string>* encoded_signatures,
- AutofillQueryContents* query) {
+ AutofillQueryContents* query,
+ FormAndFieldSignatures* encoded_signatures) {
DCHECK(encoded_signatures);
encoded_signatures->clear();
encoded_signatures->reserve(forms.size());
query->set_client_version(kClientVersion);
- // Some badly formatted web sites repeat forms - detect that and encode only
- // one form as returned data would be the same for all the repeated forms.
- std::set<std::string> processed_forms;
+ // 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.
+ // TODO(crbug/1064709#c11): the statement is not entirely correct because
+ // (1) distinct forms can have identical form signatures because we truncate
+ // (large) numbers in the form signature calculation while these are
+ // considered for field signatures; (2) for dynamic forms we will hold on to
+ // the original form signature.
+ std::set<FormSignature> processed_forms;
for (const auto* form : forms) {
- std::string signature(form->FormSignatureAsStr());
- if (processed_forms.find(signature) != processed_forms.end())
+ if (processed_forms.find(form->form_signature()) != processed_forms.end())
continue;
- processed_forms.insert(signature);
+ processed_forms.insert(form->form_signature());
UMA_HISTOGRAM_COUNTS_1000("Autofill.FieldCount", form->field_count());
if (form->IsMalformed())
continue;
- form->EncodeFormForQuery(query->add_form());
-
- encoded_signatures->push_back(signature);
+ form->EncodeFormForQuery(query->add_form(), encoded_signatures);
}
return !encoded_signatures->empty();
@@ -764,6 +771,7 @@ bool FormStructure::EncodeQueryRequest(
void FormStructure::ParseQueryResponse(
std::string payload,
const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
AutofillMetrics::LogServerQueryMetric(
AutofillMetrics::QUERY_RESPONSE_RECEIVED);
@@ -775,12 +783,14 @@ void FormStructure::ParseQueryResponse(
VLOG(1) << "Autofill query response was successfully parsed:\n" << response;
- ProcessQueryResponse(response, forms, form_interactions_ukm_logger);
+ ProcessQueryResponse(response, forms, encoded_signatures,
+ form_interactions_ukm_logger);
}
void FormStructure::ParseApiQueryResponse(
base::StringPiece payload,
const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
AutofillMetrics::LogServerQueryMetric(
AutofillMetrics::QUERY_RESPONSE_RECEIVED);
@@ -796,38 +806,56 @@ void FormStructure::ParseApiQueryResponse(
if (!response.ParseFromString(decoded_payload))
return;
- // TODO(vincb): Make an ostream overloaded function for this.
- VLOG(1) << "Autofill query response from API was successfully parsed";
+ VLOG(1) << "Autofill query response from API was successfully parsed: "
+ << response;
ProcessQueryResponse(CreateLegacyResponseFromApiResponse(response), forms,
- form_interactions_ukm_logger);
+ encoded_signatures, form_interactions_ukm_logger);
}
// static
void FormStructure::ProcessQueryResponse(
const AutofillQueryResponseContents& response,
const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
AutofillMetrics::LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED);
bool heuristics_detected_fillable_field = false;
bool query_response_overrode_heuristics = false;
+ // Align the server response to the |encoded_signatures|.
+ auto field_types = [&response, &encoded_signatures] {
+ std::map<std::pair<FormSignature, FieldSignature>,
+ ::autofill::AutofillQueryResponseContents_Field>
+ field_types;
+ auto current_field = response.field().begin();
+ for (const auto& form_and_fields : encoded_signatures) {
+ FormSignature form = form_and_fields.first;
+ for (const auto& field : form_and_fields.second) {
+ // In some cases *successful* response does not return all the
+ // fields.
+ if (current_field == response.field().end())
+ return field_types;
+ field_types[std::make_pair(form, field)] = *current_field++;
+ }
+ }
+ return field_types;
+ }();
+
// Copy the field types into the actual form.
- auto current_field = response.field().begin();
for (FormStructure* form : forms) {
bool query_response_has_no_server_data = true;
for (auto& field : form->fields_) {
- if (form->ShouldSkipField(*field))
+ auto it = field_types.find(
+ std::make_pair(form->form_signature(), field->GetFieldSignature()));
+ if (it == field_types.end())
continue;
- // In some cases *successful* response does not return all the fields.
- // Quit the update of the types then.
- if (current_field == response.field().end())
- break;
+ const auto& current_field = it->second;
- ServerFieldType field_type = static_cast<ServerFieldType>(
- current_field->overall_type_prediction());
+ ServerFieldType field_type =
+ static_cast<ServerFieldType>(current_field.overall_type_prediction());
query_response_has_no_server_data &= field_type == NO_SERVER_DATA;
ServerFieldType heuristic_type = field->heuristic_type();
@@ -837,23 +865,21 @@ void FormStructure::ProcessQueryResponse(
field->set_server_type(field_type);
std::vector<AutofillQueryResponseContents::Field::FieldPrediction>
server_predictions;
- if (current_field->predictions_size() == 0) {
+ if (current_field.predictions_size() == 0) {
AutofillQueryResponseContents::Field::FieldPrediction field_prediction;
field_prediction.set_type(field_type);
server_predictions.push_back(field_prediction);
} else {
- server_predictions.assign(current_field->predictions().begin(),
- current_field->predictions().end());
+ server_predictions.assign(current_field.predictions().begin(),
+ current_field.predictions().end());
}
field->set_server_predictions(std::move(server_predictions));
if (heuristic_type != field->Type().GetStorableType())
query_response_overrode_heuristics = true;
- if (current_field->has_password_requirements())
- field->SetPasswordRequirements(current_field->password_requirements());
-
- ++current_field;
+ if (current_field.has_password_requirements())
+ field->SetPasswordRequirements(current_field.password_requirements());
}
AutofillMetrics::LogServerResponseHasDataForForm(
@@ -885,18 +911,12 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions(
forms.reserve(form_structures.size());
for (const FormStructure* form_structure : form_structures) {
FormDataPredictions form;
- form.data.name = form_structure->form_name_;
- form.data.url = form_structure->source_url_;
- form.data.action = form_structure->target_url_;
- form.data.main_frame_origin = form_structure->main_frame_origin_;
- form.data.is_form_tag = form_structure->is_form_tag_;
- form.data.is_formless_checkout = form_structure->is_formless_checkout_;
+ form.data = form_structure->ToFormData();
form.signature = form_structure->FormSignatureAsStr();
for (const auto& field : form_structure->fields_) {
- form.data.fields.push_back(FormFieldData(*field));
-
FormFieldDataPredictions annotated_field;
+ annotated_field.field = *field;
annotated_field.signature = field->FieldSignatureAsStr();
annotated_field.heuristic_type =
AutofillType(field->heuristic_type()).ToString();
@@ -1041,44 +1061,68 @@ void FormStructure::RetrieveFromCache(
const FormStructure& cached_form,
const bool should_keep_cached_value,
const bool only_server_and_autofill_state) {
- // Map from field signatures to cached fields.
- std::map<base::string16, const AutofillField*> cached_fields;
+ // 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);
- cached_fields[field->unique_name()] = field;
+ if (kUseRendererIds)
+ cached_fields_by_id[field->unique_renderer_id] = field;
+ else
+ cached_fields_by_name[field->unique_name()] = field;
}
for (auto& field : *this) {
- const auto& cached_field = cached_fields.find(field->unique_name());
- if (cached_field != cached_fields.end()) {
+ 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;
+ }
+
+ if (cached_field) {
if (!only_server_and_autofill_state) {
// Transfer attributes of the cached AutofillField to the newly created
// AutofillField.
- field->set_heuristic_type(cached_field->second->heuristic_type());
- field->SetHtmlType(cached_field->second->html_type(),
- cached_field->second->html_mode());
- field->section = cached_field->second->section;
+ field->set_heuristic_type(cached_field->heuristic_type());
+ field->SetHtmlType(cached_field->html_type(),
+ cached_field->html_mode());
+ field->section = cached_field->section;
field->set_only_fill_when_focused(
- cached_field->second->only_fill_when_focused());
+ cached_field->only_fill_when_focused());
}
if (should_keep_cached_value) {
- field->is_autofilled = cached_field->second->is_autofilled;
+ field->is_autofilled = cached_field->is_autofilled;
}
if (field->form_control_type != "select-one") {
bool is_credit_card_field =
- AutofillType(cached_field->second->Type().GetStorableType())
- .group() == CREDIT_CARD;
- if (should_keep_cached_value && is_credit_card_field) {
- field->value = cached_field->second->value;
+ AutofillType(cached_field->Type().GetStorableType()).group() ==
+ CREDIT_CARD;
+ if (should_keep_cached_value &&
+ (is_credit_card_field ||
+ base::FeatureList::IsEnabled(
+ features::kAutofillKeepInitialFormValuesInCache))) {
+ field->value = cached_field->value;
value_from_dynamic_change_form_ = true;
- } else if (field->value == cached_field->second->value) {
+ } 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.
// From the perspective of learning user data, text fields containing
// default values are equivalent to empty fields.
field->value = base::string16();
}
}
- field->set_server_type(cached_field->second->server_type());
- field->set_previously_autofilled(
- cached_field->second->previously_autofilled());
+ field->set_server_type(cached_field->server_type());
+ field->set_previously_autofilled(cached_field->previously_autofilled());
}
}
@@ -1155,6 +1199,15 @@ void FormStructure::LogQualityMetrics(
did_autofill_some_possible_fields = true;
else if (!field->only_fill_when_focused())
did_autofill_all_possible_fields = false;
+
+ // If the form was submitted, record if field types have been filled and
+ // subsequently edited by the user.
+ if (observed_submission) {
+ if (field->is_autofilled || field->previously_autofilled()) {
+ AutofillMetrics::LogEditedAutofilledFieldAtSubmission(
+ form_interactions_ukm_logger, *this, *field);
+ }
+ }
}
AutofillMetrics::LogNumberOfEditedAutofilledFields(
@@ -1390,11 +1443,16 @@ size_t FormStructure::active_field_count() const {
FormData FormStructure::ToFormData() const {
FormData data;
+ data.id_attribute = id_attribute_;
+ data.name_attribute = name_attribute_;
data.name = form_name_;
+ data.button_titles = button_titles_;
data.url = source_url_;
data.full_url = full_source_url_;
data.action = target_url_;
data.main_frame_origin = main_frame_origin_;
+ data.is_form_tag = is_form_tag_;
+ data.is_formless_checkout = is_formless_checkout_;
data.unique_renderer_id = unique_renderer_id_;
for (size_t i = 0; i < fields_.size(); ++i) {
@@ -1404,23 +1462,6 @@ FormData FormStructure::ToFormData() const {
return data;
}
-bool FormStructure::operator==(const FormData& form) const {
- // TODO(jhawkins): Is this enough to differentiate a form?
- if (form_name_ == form.name && source_url_ == form.url &&
- target_url_ == form.action) {
- return true;
- }
-
- // TODO(jhawkins): Compare field names, IDs and labels once we have labels
- // set up.
-
- return false;
-}
-
-bool FormStructure::operator!=(const FormData& form) const {
- return !operator==(form);
-}
-
FormStructure::SectionedFieldsIndexes::SectionedFieldsIndexes() {}
FormStructure::SectionedFieldsIndexes::~SectionedFieldsIndexes() {}
@@ -1866,10 +1907,13 @@ void FormStructure::RationalizeFieldTypePredictions() {
}
void FormStructure::EncodeFormForQuery(
- AutofillQueryContents::Form* query_form) const {
+ AutofillQueryContents::Form* query_form,
+ FormAndFieldSignatures* encoded_signatures) const {
DCHECK(!IsMalformed());
query_form->set_signature(form_signature().value());
+ encoded_signatures->emplace_back();
+ encoded_signatures->back().first = form_signature();
if (is_rich_query_enabled_) {
EncodeFormMetadataForQuery(*this, query_form->mutable_form_metadata());
@@ -1880,8 +1924,8 @@ void FormStructure::EncodeFormForQuery(
continue;
AutofillQueryContents::Form::Field* added_field = query_form->add_field();
-
added_field->set_signature(field->GetFieldSignature().value());
+ encoded_signatures->back().second.push_back(field->GetFieldSignature());
if (is_rich_query_enabled_) {
EncodeFieldMetadataForQuery(*field,
@@ -1897,9 +1941,14 @@ void FormStructure::EncodeFormForQuery(
}
}
-void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const {
+void FormStructure::EncodeFormForUpload(
+ AutofillUploadContents* upload,
+ FormAndFieldSignatures* encoded_signatures) const {
DCHECK(!IsMalformed());
+ encoded_signatures->emplace_back();
+ encoded_signatures->back().first = form_signature();
+
if (randomized_encoder_) {
PopulateRandomizedFormMetadata(*randomized_encoder_, *this,
upload->mutable_randomized_form_metadata());
@@ -1915,6 +1964,7 @@ void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const {
continue;
auto* added_field = upload->add_field();
+ encoded_signatures->back().second.push_back(field->GetFieldSignature());
for (const auto& field_type : field->possible_types()) {
added_field->add_autofill_type(field_type);
@@ -2280,6 +2330,45 @@ void FormStructure::RationalizeTypeRelationships() {
}
}
+std::ostream& operator<<(std::ostream& buffer, const FormStructure& form) {
+ buffer << "\nForm signature: "
+ << base::StrCat({base::NumberToString(form.form_signature().value()),
+ " - ",
+ base::NumberToString(
+ HashFormSignature(form.form_signature()))});
+ buffer << "\n Form name: " << form.form_name();
+ buffer << "\n Unique renderer Id: " << form.unique_renderer_id().value();
+ buffer << "\n Target URL:" << form.target_url();
+ for (size_t i = 0; i < form.field_count(); ++i) {
+ buffer << "\n Field " << i << ": ";
+ const AutofillField* field = form.field(i);
+ buffer << "\n Signature: "
+ << base::StrCat(
+ {base::NumberToString(field->GetFieldSignature().value()),
+ " - ",
+ base::NumberToString(
+ HashFieldSignature(field->GetFieldSignature()))});
+ buffer << "\n Name: " << field->parseable_name();
+
+ auto type = field->Type().ToString();
+ auto heuristic_type = AutofillType(field->heuristic_type()).ToString();
+ auto server_type = AutofillType(field->server_type()).ToString();
+
+ buffer << "\n Type: "
+ << base::StrCat({type, " (heuristic: ", heuristic_type,
+ ", server: ", server_type, ")"});
+ buffer << "\n Section: " << field->section;
+
+ constexpr size_t kMaxLabelSize = 100;
+ const base::string16 truncated_label =
+ field->label.substr(0, std::min(field->label.length(), kMaxLabelSize));
+ buffer << "\n Label: " << truncated_label;
+
+ buffer << "\n Is empty: " << (field->IsEmpty() ? "Yes" : "No");
+ }
+ return buffer;
+}
+
LogBuffer& operator<<(LogBuffer& buffer, const FormStructure& form) {
buffer << Tag{"div"} << Attrib{"class", "form"};
buffer << Tag{"table"};
@@ -2320,6 +2409,8 @@ LogBuffer& operator<<(LogBuffer& buffer, const FormStructure& form) {
const base::string16 truncated_label =
field->label.substr(0, std::min(field->label.length(), kMaxLabelSize));
buffer << Tr{} << "Label:" << truncated_label;
+
+ buffer << Tr{} << "Is empty:" << (field->IsEmpty() ? "Yes" : "No");
buffer << CTag{"table"};
buffer << CTag{"td"};
buffer << CTag{"tr"};
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index 9890750a9f8..7e0ceef0fe8 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -49,6 +49,11 @@ enum class PasswordAttribute {
kPasswordAttributesCount
};
+// The structure of forms and fields, represented by their signatures, on a
+// page. These are sequence containers to reflect their order in the DOM.
+using FormAndFieldSignatures =
+ std::vector<std::pair<FormSignature, std::vector<FieldSignature>>>;
+
struct FormData;
struct FormDataPredictions;
@@ -65,43 +70,41 @@ class FormStructure {
// types.
void DetermineHeuristicTypes(LogManager* log_manager = nullptr);
- // Encodes the proto |upload| request from this FormStructure.
+ // Encodes the proto |upload| request from this FormStructure, and stores
+ // the (single) FormSignature and the signatures of the fields to be uploaded
+ // in |encoded_signatures|.
// In some cases, a |login_form_signature| is included as part of the upload.
// This field is empty when sending upload requests for non-login forms.
bool EncodeUploadRequest(const ServerFieldTypeSet& available_field_types,
bool form_was_autofilled,
const std::string& login_form_signature,
bool observed_submission,
- autofill::AutofillUploadContents* upload) const;
-
- // Encodes the proto |query| request for the set of |forms| that are valid
- // (see implementation for details on which forms are not included in the
- // query). The form signatures used in the Query request are output in
- // |encoded_signatures|. All valid fields are encoded in |query|.
+ autofill::AutofillUploadContents* upload,
+ FormAndFieldSignatures* encoded_signatures) const;
+
+ // Encodes the proto |query| request for the list of |forms| and their fields
+ // that are valid. The queried FormSignatures and FieldSignatures are stored
+ // in |encoded_signatures| in the same order as in |query|. In case multiple
+ // FormStructures have the same FormSignature, only the first one is included
+ // in |query| and |encoded_signatures|.
static bool EncodeQueryRequest(const std::vector<FormStructure*>& forms,
- std::vector<std::string>* encoded_signatures,
- autofill::AutofillQueryContents* query);
+ autofill::AutofillQueryContents* query,
+ FormAndFieldSignatures* encoded_signatures);
// Parses response as AutofillQueryResponseContents proto and calls
// ProcessQueryResponse.
- static void ParseQueryResponse(std::string response,
- const std::vector<FormStructure*>& forms,
- AutofillMetrics::FormInteractionsUkmLogger*);
+ static void ParseQueryResponse(
+ std::string response,
+ const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
+ AutofillMetrics::FormInteractionsUkmLogger*);
static void ParseApiQueryResponse(
base::StringPiece payload,
const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
AutofillMetrics::FormInteractionsUkmLogger*);
- // Parses the field types from the server query response. |forms| must be the
- // same as the one passed to EncodeQueryRequest when constructing the query.
- // |form_interactions_ukm_logger| is used to provide logs to UKM and can be
- // null in tests.
- static void ProcessQueryResponse(
- const AutofillQueryResponseContents& response,
- const std::vector<FormStructure*>& forms,
- AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger);
-
// Returns predictions using the details from the given |form_structures| and
// their fields' predicted types.
static std::vector<FormDataPredictions> GetFieldTypePredictions(
@@ -241,6 +244,8 @@ class FormStructure {
const url::Origin& main_frame_origin() const { return main_frame_origin_; }
+ const ButtonTitleList& button_titles() const { return button_titles_; }
+
bool has_author_specified_types() const {
return has_author_specified_types_;
}
@@ -268,7 +273,11 @@ class FormStructure {
bool all_fields_are_passwords() const { return all_fields_are_passwords_; }
- FormSignature form_signature() const { return form_signature_; }
+ const FormSignature form_signature() const { return form_signature_; }
+
+ void set_form_signature(FormSignature signature) {
+ form_signature_ = signature;
+ }
// Returns a FormData containing the data this form structure knows about.
FormData ToFormData() const;
@@ -349,8 +358,6 @@ class FormStructure {
void set_submission_source(mojom::SubmissionSource submission_source) {
submission_source_ = submission_source;
}
- bool operator==(const FormData& form) const;
- bool operator!=(const FormData& form) const;
// Returns an identifier that is used by the refill logic. Takes the first non
// empty of these or returns an empty string:
@@ -380,6 +387,20 @@ class FormStructure {
FormRendererId unique_renderer_id() const { return unique_renderer_id_; }
+ bool ShouldSkipFieldVisibleForTesting(const FormFieldData& field) const {
+ return ShouldSkipField(field);
+ }
+
+ static void ProcessQueryResponseForTesting(
+ const AutofillQueryResponseContents& response,
+ const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
+ AutofillMetrics::FormInteractionsUkmLogger*
+ form_interactions_ukm_logger) {
+ ProcessQueryResponse(response, forms, encoded_signatures,
+ form_interactions_ukm_logger);
+ }
+
private:
friend class AutofillMergeTest;
friend class FormStructureTest;
@@ -434,6 +455,16 @@ class FormStructure {
size_t current_section_ptr = 0;
};
+ // Parses the field types from the server query response. |forms| must be the
+ // same as the one passed to EncodeQueryRequest when constructing the query.
+ // |form_interactions_ukm_logger| is used to provide logs to UKM and can be
+ // null in tests.
+ static void ProcessQueryResponse(
+ const AutofillQueryResponseContents& response,
+ const std::vector<FormStructure*>& forms,
+ const FormAndFieldSignatures& encoded_signatures,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger);
+
FormStructure(FormSignature form_signature,
const std::vector<FieldSignature>& field_signatures);
@@ -498,12 +529,11 @@ class FormStructure {
// when it considers necessary.
void RationalizeFieldTypePredictions();
- // Encodes information about this form and its fields into |query_form|.
- void EncodeFormForQuery(
- autofill::AutofillQueryContents::Form* query_form) const;
+ void EncodeFormForQuery(autofill::AutofillQueryContents::Form* query_form,
+ FormAndFieldSignatures* encoded_signatures) const;
- // Encodes information about this form and its fields into |upload|.
- void EncodeFormForUpload(autofill::AutofillUploadContents* upload) const;
+ void EncodeFormForUpload(autofill::AutofillUploadContents* upload,
+ FormAndFieldSignatures* encoded_signatures) const;
// Returns true if the form has no fields, or too many.
bool IsMalformed() const;
@@ -663,6 +693,8 @@ class FormStructure {
};
LogBuffer& operator<<(LogBuffer& buffer, const FormStructure& form);
+std::ostream& operator<<(std::ostream& buffer, const FormStructure& form);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_STRUCTURE_H_
diff --git a/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc b/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc
index b684f2f6ed2..8e3870a008c 100644
--- a/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc
+++ b/chromium/components/autofill/core/browser/form_structure_process_query_response_fuzzer.cc
@@ -7,6 +7,7 @@
#include <iostream>
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
@@ -35,7 +36,8 @@ void AddField(const std::string& label,
// forms vectors, so it can be changed if needed.
DEFINE_BINARY_PROTO_FUZZER(const AutofillQueryResponseContents& response) {
std::vector<FormStructure*> forms;
- FormStructure::ProcessQueryResponse(response, forms, nullptr);
+ FormStructure::ProcessQueryResponseForTesting(
+ response, forms, test::GetEncodedSignatures(forms), nullptr);
FormData form_data;
AddField("username", "username", "text", &form_data);
@@ -43,7 +45,8 @@ DEFINE_BINARY_PROTO_FUZZER(const AutofillQueryResponseContents& response) {
FormStructure form(form_data);
forms.push_back(&form);
- FormStructure::ProcessQueryResponse(response, forms, nullptr);
+ FormStructure::ProcessQueryResponseForTesting(
+ response, forms, test::GetEncodedSignatures(forms), nullptr);
}
} // namespace
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 0e23ab24aea..f5e7a3ae4bb 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -39,7 +39,6 @@ namespace autofill {
using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
using features::kAutofillEnforceMinRequiredFieldsForQuery;
using features::kAutofillEnforceMinRequiredFieldsForUpload;
-using mojom::ButtonTitleType;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
@@ -2349,7 +2348,18 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+
+ FormAndFieldSignatures expected_signatures;
+ expected_signatures.push_back(
+ {form_structure.form_signature(),
+ {
+ form_structure.field(0)->GetFieldSignature(),
+ form_structure.field(1)->GetFieldSignature(),
+ form_structure.field(2)->GetFieldSignature(),
+ form_structure.field(3)->GetFieldSignature(),
+ form_structure.field(4)->GetFieldSignature()
+ // field 5 is checkable, and hence skipped.
+ }});
// Prepare the expected proto string.
AutofillQueryContents query;
@@ -2371,13 +2381,11 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
- const std::string kSignature1 = form_structure.FormSignatureAsStr();
-
AutofillQueryContents encoded_query;
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
- ASSERT_EQ(1U, encoded_signatures.size());
- EXPECT_EQ(kSignature1, encoded_signatures[0]);
+ FormAndFieldSignatures encoded_signatures;
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
+ EXPECT_EQ(encoded_signatures, expected_signatures);
std::string encoded_query_string;
encoded_query.SerializeToString(&encoded_query_string);
@@ -2388,11 +2396,13 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
FormStructure form_structure2(form);
forms.push_back(&form_structure2);
+ FormAndFieldSignatures expected_signatures2 = expected_signatures;
+
AutofillQueryContents encoded_query2;
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query2));
- ASSERT_EQ(1U, encoded_signatures.size());
- EXPECT_EQ(kSignature1, encoded_signatures[0]);
+ FormAndFieldSignatures encoded_signatures2;
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query2,
+ &encoded_signatures2));
+ EXPECT_EQ(encoded_signatures2, expected_signatures2);
encoded_query2.SerializeToString(&encoded_query_string);
EXPECT_EQ(expected_query_string, encoded_query_string);
@@ -2407,6 +2417,21 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
FormStructure form_structure3(form);
forms.push_back(&form_structure3);
+ FormAndFieldSignatures expected_signatures3 = expected_signatures2;
+ expected_signatures3.push_back(
+ {form_structure3.form_signature(),
+ {form_structure3.field(0)->GetFieldSignature(),
+ form_structure3.field(1)->GetFieldSignature(),
+ form_structure3.field(2)->GetFieldSignature(),
+ form_structure3.field(3)->GetFieldSignature(),
+ form_structure3.field(4)->GetFieldSignature(),
+ // field 5 is checkable, and hence skipped.
+ form_structure3.field(6)->GetFieldSignature(),
+ form_structure3.field(7)->GetFieldSignature(),
+ form_structure3.field(8)->GetFieldSignature(),
+ form_structure3.field(9)->GetFieldSignature(),
+ form_structure3.field(10)->GetFieldSignature()}});
+
// Add the second form to the expected proto.
query_form = query.add_form();
query_form->set_signature(form_structure3.form_signature().value());
@@ -2429,16 +2454,31 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
AutofillQueryContents encoded_query3;
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query3));
- ASSERT_EQ(2U, encoded_signatures.size());
- EXPECT_EQ(kSignature1, encoded_signatures[0]);
- const std::string kSignature2 = form_structure3.FormSignatureAsStr();
- EXPECT_EQ(kSignature2, encoded_signatures[1]);
+ FormAndFieldSignatures encoded_signatures3;
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query3,
+ &encoded_signatures3));
+ EXPECT_EQ(encoded_signatures3, expected_signatures3);
encoded_query3.SerializeToString(&encoded_query_string);
EXPECT_EQ(expected_query_string, encoded_query_string);
+ // |form_structures4| will have the same signature as |form_structure3|.
+ form.fields.back().name = ASCIIToUTF16("address123456789");
+
+ FormStructure form_structure4(form);
+ forms.push_back(&form_structure4);
+
+ FormAndFieldSignatures expected_signatures4 = expected_signatures3;
+
+ AutofillQueryContents encoded_query4;
+ FormAndFieldSignatures encoded_signatures4;
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query4,
+ &encoded_signatures4));
+ EXPECT_EQ(encoded_signatures4, expected_signatures4);
+
+ encoded_query4.SerializeToString(&encoded_query_string);
+ EXPECT_EQ(expected_query_string, encoded_query_string);
+
FormData malformed_form(form);
// Add 300 address fields - the form is not valid anymore, but previous ones
// are. The result should be the same as in previous test.
@@ -2450,22 +2490,25 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
FormStructure malformed_form_structure(malformed_form);
forms.push_back(&malformed_form_structure);
- AutofillQueryContents encoded_query4;
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query4));
- ASSERT_EQ(2U, encoded_signatures.size());
- EXPECT_EQ(kSignature1, encoded_signatures[0]);
- EXPECT_EQ(kSignature2, encoded_signatures[1]);
- encoded_query4.SerializeToString(&encoded_query_string);
+ FormAndFieldSignatures expected_signatures5 = expected_signatures4;
+
+ AutofillQueryContents encoded_query5;
+ FormAndFieldSignatures encoded_signatures5;
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query5,
+ &encoded_signatures5));
+ EXPECT_EQ(encoded_signatures5, expected_signatures5);
+
+ encoded_query5.SerializeToString(&encoded_query_string);
EXPECT_EQ(expected_query_string, encoded_query_string);
// Check that we fail if there are only bad form(s).
std::vector<FormStructure*> bad_forms;
bad_forms.push_back(&malformed_form_structure);
- AutofillQueryContents encoded_query5;
- EXPECT_FALSE(FormStructure::EncodeQueryRequest(bad_forms, &encoded_signatures,
- &encoded_query5));
+ AutofillQueryContents encoded_query6;
+ FormAndFieldSignatures encoded_signatures6;
+ EXPECT_FALSE(FormStructure::EncodeQueryRequest(bad_forms, &encoded_query6,
+ &encoded_signatures6));
}
TEST_F(FormStructureTest, EncodeUploadRequest_SubmissionIndicatorEvents_Match) {
@@ -2507,44 +2550,43 @@ TEST_F(FormStructureTest, EncodeUploadRequest_SubmissionIndicatorEvents_Match) {
}
TEST_F(FormStructureTest, ButtonTitleType_Match) {
- // Statically assert that the mojo ButtonTitleType enum matches the
- // corresponding entries the in proto AutofillUploadContents::ButtonTitle
- // ButtonTitleType enum.
- static_assert(AutofillUploadContents::ButtonTitle::NONE ==
- static_cast<int>(ButtonTitleType::NONE),
- "NONE enumerator does not match!");
+ // Statically assert that the mojom::ButtonTitleType enum matches the
+ // corresponding entries in the proto - ButtonTitleType enum.
+ static_assert(
+ ButtonTitleType::NONE == static_cast<int>(mojom::ButtonTitleType::NONE),
+ "NONE enumerator does not match!");
static_assert(
- AutofillUploadContents::ButtonTitle::BUTTON_ELEMENT_SUBMIT_TYPE ==
- static_cast<int>(ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE),
+ ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE ==
+ static_cast<int>(mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE),
"BUTTON_ELEMENT_SUBMIT_TYPE enumerator does not match!");
static_assert(
- AutofillUploadContents::ButtonTitle::BUTTON_ELEMENT_BUTTON_TYPE ==
- static_cast<int>(ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE),
+ ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE ==
+ static_cast<int>(mojom::ButtonTitleType::BUTTON_ELEMENT_BUTTON_TYPE),
"BUTTON_ELEMENT_BUTTON_TYPE enumerator does not match!");
static_assert(
- AutofillUploadContents::ButtonTitle::INPUT_ELEMENT_SUBMIT_TYPE ==
- static_cast<int>(ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE),
+ ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE ==
+ static_cast<int>(mojom::ButtonTitleType::INPUT_ELEMENT_SUBMIT_TYPE),
"INPUT_ELEMENT_SUBMIT_TYPE enumerator does not match!");
static_assert(
- AutofillUploadContents::ButtonTitle::INPUT_ELEMENT_BUTTON_TYPE ==
- static_cast<int>(ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE),
+ ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE ==
+ static_cast<int>(mojom::ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE),
"INPUT_ELEMENT_BUTTON_TYPE enumerator does not match!");
- static_assert(AutofillUploadContents::ButtonTitle::HYPERLINK ==
- static_cast<int>(ButtonTitleType::HYPERLINK),
+ static_assert(ButtonTitleType::HYPERLINK ==
+ static_cast<int>(mojom::ButtonTitleType::HYPERLINK),
"HYPERLINK enumerator does not match!");
- static_assert(AutofillUploadContents::ButtonTitle::DIV ==
- static_cast<int>(ButtonTitleType::DIV),
- "DIV enumerator does not match!");
+ static_assert(
+ ButtonTitleType::DIV == static_cast<int>(mojom::ButtonTitleType::DIV),
+ "DIV enumerator does not match!");
- static_assert(AutofillUploadContents::ButtonTitle::SPAN ==
- static_cast<int>(ButtonTitleType::SPAN),
- "SPAN enumerator does not match!");
+ static_assert(
+ ButtonTitleType::SPAN == static_cast<int>(mojom::ButtonTitleType::SPAN),
+ "SPAN enumerator does not match!");
}
TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) {
@@ -2669,10 +2711,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) {
////////////////
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload));
+ available_field_types, false, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -2684,7 +2728,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload2));
+ available_field_types, true, std::string(), true, &encoded_upload2,
+ &signatures));
encoded_upload2.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -2737,7 +2782,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3));
+ available_field_types, false, std::string(), true, &encoded_upload3,
+ &signatures));
encoded_upload3.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -2862,10 +2908,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithNonMatchingValidities) {
////////////////
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload));
+ available_field_types, false, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -2995,10 +3043,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMultipleValidities) {
////////////////
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload));
+ available_field_types, false, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3081,6 +3131,18 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
possible_field_types_validities[i]);
}
+ FormAndFieldSignatures expected_signatures;
+ expected_signatures.push_back(
+ {form_structure->form_signature(),
+ {
+ form_structure->field(0)->GetFieldSignature(),
+ form_structure->field(1)->GetFieldSignature(),
+ form_structure->field(2)->GetFieldSignature(),
+ form_structure->field(3)->GetFieldSignature(),
+ form_structure->field(4)->GetFieldSignature()
+ // Field 5 is checkable and hence skipped.
+ }});
+
ServerFieldTypeSet available_field_types;
available_field_types.insert(NAME_FIRST);
available_field_types.insert(NAME_LAST);
@@ -3119,10 +3181,13 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload));
+ available_field_types, false, std::string(), true, &encoded_upload,
+ &signatures));
+ EXPECT_EQ(signatures, expected_signatures);
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3134,7 +3199,9 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload2));
+ available_field_types, true, std::string(), true, &encoded_upload2,
+ &signatures));
+ EXPECT_EQ(signatures, expected_signatures);
encoded_upload2.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -3166,6 +3233,13 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
possible_field_types_validities[i]);
}
+ expected_signatures[0].first = form_structure->form_signature();
+ // Field 5 is checkable and hence skipped.
+ expected_signatures[0].second.push_back(
+ form_structure->field(6)->GetFieldSignature());
+ expected_signatures[0].second.push_back(
+ form_structure->field(7)->GetFieldSignature());
+
// Adjust the expected proto string.
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
@@ -3187,7 +3261,9 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3));
+ available_field_types, false, std::string(), true, &encoded_upload3,
+ &signatures));
+ EXPECT_EQ(signatures, expected_signatures);
encoded_upload3.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -3215,7 +3291,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
AutofillUploadContents encoded_upload4;
EXPECT_FALSE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload4));
+ available_field_types, false, std::string(), true, &encoded_upload4,
+ &signatures));
}
TEST_F(FormStructureTest,
@@ -3335,10 +3412,11 @@ TEST_F(FormStructureTest,
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
- EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, true,
- "42", true, &encoded_upload));
+ EXPECT_TRUE(form_structure->EncodeUploadRequest(
+ available_field_types, true, "42", true, &encoded_upload, &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3419,8 +3497,10 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) {
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
AutofillUploadContents encoded_upload;
+ FormAndFieldSignatures signatures;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3519,10 +3599,12 @@ TEST_F(FormStructureTest, EncodeUploadRequestWithPropertiesMask) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3601,11 +3683,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
available_field_types, true, std::string(),
- /* observed_submission= */ false, &encoded_upload));
+ /* observed_submission= */ false, &encoded_upload, &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3677,10 +3760,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3757,10 +3842,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithCssClassesAndIds) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3835,10 +3922,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -3917,10 +4006,12 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -4010,10 +4101,12 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, true, std::string(), true, &encoded_upload));
+ available_field_types, true, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -4086,10 +4179,12 @@ TEST_F(FormStructureTest, CheckDataPresence) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
- EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload));
+ EXPECT_TRUE(form_structure.EncodeUploadRequest(available_field_types, false,
+ std::string(), true,
+ &encoded_upload, &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -4119,7 +4214,8 @@ TEST_F(FormStructureTest, CheckDataPresence) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload2));
+ available_field_types, false, std::string(), true, &encoded_upload2,
+ &signatures));
encoded_upload2.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4172,7 +4268,8 @@ TEST_F(FormStructureTest, CheckDataPresence) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3));
+ available_field_types, false, std::string(), true, &encoded_upload3,
+ &signatures));
encoded_upload3.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4203,7 +4300,8 @@ TEST_F(FormStructureTest, CheckDataPresence) {
AutofillUploadContents encoded_upload4;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload4));
+ available_field_types, false, std::string(), true, &encoded_upload4,
+ &signatures));
encoded_upload4.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4270,7 +4368,8 @@ TEST_F(FormStructureTest, CheckDataPresence) {
AutofillUploadContents encoded_upload5;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload5));
+ available_field_types, false, std::string(), true, &encoded_upload5,
+ &signatures));
encoded_upload5.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4371,10 +4470,12 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
+ FormAndFieldSignatures signatures;
AutofillUploadContents encoded_upload;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload));
+ available_field_types, false, std::string(), true, &encoded_upload,
+ &signatures));
std::string encoded_upload_string;
encoded_upload.SerializeToString(&encoded_upload_string);
@@ -4397,7 +4498,8 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
AutofillUploadContents encoded_upload2;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload2));
+ available_field_types, false, std::string(), true, &encoded_upload2,
+ &signatures));
encoded_upload2.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4414,7 +4516,8 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
AutofillUploadContents encoded_upload3;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload3));
+ available_field_types, false, std::string(), true, &encoded_upload3,
+ &signatures));
encoded_upload3.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4439,7 +4542,8 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
AutofillUploadContents encoded_upload4;
EXPECT_TRUE(form_structure->EncodeUploadRequest(
- available_field_types, false, std::string(), true, &encoded_upload4));
+ available_field_types, false, std::string(), true, &encoded_upload4,
+ &signatures));
encoded_upload4.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
@@ -4466,10 +4570,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_PasswordsRevealed) {
FormStructure form_structure(form);
form_structure.set_passwords_were_revealed(true);
AutofillUploadContents upload;
+ FormAndFieldSignatures signatures;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
{{}} /* available_field_types */, false /* form_was_autofilled */,
std::string() /* login_form_signature */, true /* observed_submission */,
- &upload));
+ &upload, &signatures));
EXPECT_EQ(true, upload.passwords_revealed());
}
@@ -4488,10 +4593,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_IsFormTag) {
FormStructure form_structure(form);
form_structure.set_passwords_were_revealed(true);
AutofillUploadContents upload;
+ FormAndFieldSignatures signatures;
EXPECT_TRUE(form_structure.EncodeUploadRequest(
{{}} /* available_field_types */, false /* form_was_autofilled */,
std::string() /* login_form_signature */,
- true /* observed_submission */, &upload));
+ true /* observed_submission */, &upload, &signatures));
EXPECT_EQ(is_form_tag, upload.has_form_tag());
}
}
@@ -4518,6 +4624,9 @@ TEST_F(FormStructureTest, EncodeUploadRequest_RichMetadata) {
FormData form;
form.id_attribute = ASCIIToUTF16("form-id");
form.url = GURL("http://www.foo.com/");
+ form.button_titles = {
+ std::make_pair(ASCIIToUTF16("Submit"),
+ mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.full_url = GURL("http://www.foo.com/?foo=bar");
for (const auto& f : kFieldMetadata) {
FormFieldData field;
@@ -4540,10 +4649,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_RichMetadata) {
std::make_unique<RandomizedEncoder>(encoder));
AutofillUploadContents upload;
+ FormAndFieldSignatures signatures;
ASSERT_TRUE(form_structure.EncodeUploadRequest(
{{}} /* available_field_types */, false /* form_was_autofilled */,
std::string() /* login_form_signature */, true /* observed_submission */,
- &upload));
+ &upload, &signatures));
const auto form_signature = form_structure.form_signature();
@@ -4571,6 +4681,18 @@ TEST_F(FormStructureTest, EncodeUploadRequest_RichMetadata) {
RandomizedEncoder::FORM_URL, full_url));
ASSERT_EQ(static_cast<size_t>(upload.field_size()),
base::size(kFieldMetadata));
+
+ ASSERT_EQ(1, upload.randomized_form_metadata().button_title().size());
+ EXPECT_EQ(upload.randomized_form_metadata()
+ .button_title()[0]
+ .title()
+ .encoded_bits(),
+ encoder.EncodeForTesting(form_signature, FieldSignature(),
+ RandomizedEncoder::FORM_BUTTON_TITLES,
+ form.button_titles[0].first));
+ EXPECT_EQ(ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE,
+ upload.randomized_form_metadata().button_title()[0].type());
+
for (int i = 0; i < upload.field_size(); ++i) {
const auto& metadata = upload.field(i).randomized_field_metadata();
const auto& field = *form_structure.field(i);
@@ -4672,7 +4794,9 @@ TEST_F(FormStructureTest, Metadata_OnlySendFullUrlWithUserConsent) {
FormStructure form_structure(form);
form_structure.set_randomized_encoder(RandomizedEncoder::Create(&prefs));
AutofillUploadContents upload = AutofillUploadContents();
- form_structure.EncodeUploadRequest({}, true, "", true, &upload);
+ FormAndFieldSignatures signatures;
+ form_structure.EncodeUploadRequest({}, true, "", true, &upload,
+ &signatures);
EXPECT_EQ(has_consent, upload.randomized_form_metadata().has_url());
}
@@ -4798,7 +4922,7 @@ TEST_F(FormStructureTest, SkipFieldTest) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+ FormAndFieldSignatures encoded_signatures;
AutofillQueryContents encoded_query;
// Create the expected query and serialize it to a string.
@@ -4813,12 +4937,12 @@ TEST_F(FormStructureTest, SkipFieldTest) {
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
- const char kExpectedSignature[] = "18006745212084723782";
+ const FormSignature kExpectedSignature(18006745212084723782UL);
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
ASSERT_EQ(1U, encoded_signatures.size());
- EXPECT_EQ(kExpectedSignature, encoded_signatures[0]);
+ EXPECT_EQ(kExpectedSignature, encoded_signatures.front().first);
std::string encoded_query_string;
encoded_query.SerializeToString(&encoded_query_string);
@@ -4850,7 +4974,7 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLabels) {
std::vector<FormStructure*> forms;
FormStructure form_structure(form);
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+ FormAndFieldSignatures encoded_signatures;
AutofillQueryContents encoded_query;
// Create the expected query and serialize it to a string.
@@ -4867,8 +4991,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLabels) {
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
- EXPECT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
+ EXPECT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
std::string encoded_query_string;
encoded_query.SerializeToString(&encoded_query_string);
@@ -4905,7 +5029,7 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLongLabels) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+ FormAndFieldSignatures encoded_signatures;
AutofillQueryContents encoded_query;
// Create the expected query and serialize it to a string.
@@ -4922,8 +5046,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLongLabels) {
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
- EXPECT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
+ EXPECT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
std::string encoded_query_string;
encoded_query.SerializeToString(&encoded_query_string);
@@ -4954,7 +5078,7 @@ TEST_F(FormStructureTest, EncodeQueryRequest_MissingNames) {
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+ FormAndFieldSignatures encoded_signatures;
AutofillQueryContents encoded_query;
// Create the expected query and serialize it to a string.
@@ -4969,12 +5093,12 @@ TEST_F(FormStructureTest, EncodeQueryRequest_MissingNames) {
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
- const char kExpectedSignature[] = "16416961345885087496";
+ const FormSignature kExpectedSignature(16416961345885087496UL);
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
ASSERT_EQ(1U, encoded_signatures.size());
- EXPECT_EQ(kExpectedSignature, encoded_signatures[0]);
+ EXPECT_EQ(kExpectedSignature, encoded_signatures.front().first);
std::string encoded_query_string;
encoded_query.SerializeToString(&encoded_query_string);
@@ -5005,7 +5129,7 @@ TEST_F(FormStructureTest, EncodeQueryRequest_DisabledMetadataTrial) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+ FormAndFieldSignatures encoded_signatures;
AutofillQueryContents encoded_query;
// Create the expected query and serialize it to a string.
@@ -5020,12 +5144,12 @@ TEST_F(FormStructureTest, EncodeQueryRequest_DisabledMetadataTrial) {
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
- const char kExpectedSignature[] = "7635954436925888745";
+ const FormSignature kExpectedSignature(7635954436925888745UL);
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
ASSERT_EQ(1U, encoded_signatures.size());
- EXPECT_EQ(kExpectedSignature, encoded_signatures[0]);
+ EXPECT_EQ(kExpectedSignature, encoded_signatures.front().first);
std::string encoded_query_string;
encoded_query.SerializeToString(&encoded_query_string);
@@ -5075,6 +5199,73 @@ TEST_F(FormStructureTest, PossibleValues) {
// Tests proper resolution heuristic, server and html field types when the
// server returns NO_SERVER_DATA, UNKNOWN_TYPE, and a valid type.
+TEST_F(FormStructureTest, ParseQueryResponse_TooManyTypes) {
+ FormData form_data;
+ FormFieldData field;
+ form_data.url = GURL("http://foo.com");
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("First Name");
+ field.name = ASCIIToUTF16("fname");
+ form_data.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Last Name");
+ field.name = ASCIIToUTF16("lname");
+ form_data.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("email");
+ field.name = ASCIIToUTF16("email");
+ field.autocomplete_attribute = "address-level2";
+ form_data.fields.push_back(field);
+
+ FormStructure form(form_data);
+ form.DetermineHeuristicTypes();
+
+ // Setup the query response.
+ AutofillQueryResponseContents response;
+ std::string response_string;
+ response.add_field()->set_overall_type_prediction(NAME_FIRST);
+ response.add_field()->set_overall_type_prediction(NAME_LAST);
+ response.add_field()->set_overall_type_prediction(ADDRESS_HOME_LINE1);
+ response.add_field()->set_overall_type_prediction(EMAIL_ADDRESS);
+ response.add_field()->set_overall_type_prediction(UNKNOWN_TYPE);
+ ASSERT_TRUE(response.SerializeToString(&response_string));
+
+ // Parse the response and update the field type predictions.
+ std::vector<FormStructure*> forms{&form};
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
+ ASSERT_EQ(form.field_count(), 3U);
+
+ // Validate field 0.
+ EXPECT_EQ(NAME_FIRST, form.field(0)->heuristic_type());
+ EXPECT_EQ(NAME_FIRST, form.field(0)->server_type());
+ EXPECT_EQ(HTML_TYPE_UNSPECIFIED, form.field(0)->html_type());
+ EXPECT_EQ(NAME_FIRST, form.field(0)->Type().GetStorableType());
+
+ // Validate field 1.
+ EXPECT_EQ(NAME_LAST, form.field(1)->heuristic_type());
+ EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
+ EXPECT_EQ(HTML_TYPE_UNSPECIFIED, form.field(1)->html_type());
+ EXPECT_EQ(NAME_LAST, form.field(1)->Type().GetStorableType());
+
+ // Validate field 2. Note: HTML_TYPE_ADDRESS_LEVEL2 -> City
+ EXPECT_EQ(EMAIL_ADDRESS, form.field(2)->heuristic_type());
+ EXPECT_EQ(ADDRESS_HOME_LINE1, form.field(2)->server_type());
+ EXPECT_EQ(HTML_TYPE_ADDRESS_LEVEL2, form.field(2)->html_type());
+ EXPECT_EQ(ADDRESS_HOME_CITY, form.field(2)->Type().GetStorableType());
+
+ // Also check the extreme case of an empty form.
+ FormStructure empty_form{FormData()};
+ std::vector<FormStructure*> empty_forms{&empty_form};
+ FormStructure::ParseQueryResponse(response_string, empty_forms,
+ test::GetEncodedSignatures(empty_forms),
+ nullptr);
+ ASSERT_EQ(empty_form.field_count(), 0U);
+}
+
+// Tests proper resolution heuristic, server and html field types when the
+// server returns NO_SERVER_DATA, UNKNOWN_TYPE, and a valid type.
TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) {
FormData form_data;
FormFieldData field;
@@ -5107,7 +5298,8 @@ TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) {
// Parse the response and update the field type predictions.
std::vector<FormStructure*> forms{&form};
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(form.field_count(), 3U);
// Validate field 0.
@@ -5184,7 +5376,8 @@ TEST_F(FormStructureTest, ParseQueryResponse) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_GE(forms[0]->field_count(), 2U);
ASSERT_GE(forms[1]->field_count(), 2U);
@@ -5268,7 +5461,8 @@ TEST_F(FormStructureTest, ParseApiQueryResponse) {
base::Base64Encode(response_string, &encoded_response_string);
FormStructure::ParseApiQueryResponse(std::move(encoded_response_string),
- forms, nullptr);
+ forms, test::GetEncodedSignatures(forms),
+ nullptr);
// Verify that the form fields are properly filled with data retrieved from
// the query.
@@ -5311,6 +5505,7 @@ TEST_F(FormStructureTest, ParseApiQueryResponseWhenCannotParseProtoFromString) {
std::string response_string = "invalid string that cannot be parsed";
FormStructure::ParseApiQueryResponse(std::move(response_string), forms,
+ test::GetEncodedSignatures(forms),
nullptr);
// Verify that the form fields remain intact because ParseApiQueryResponse
@@ -5353,7 +5548,8 @@ TEST_F(FormStructureTest, ParseApiQueryResponseWhenPayloadNotBase64) {
std::string response_string;
ASSERT_TRUE(api_response.SerializeToString(&response_string));
- FormStructure::ParseApiQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseApiQueryResponse(
+ response_string, forms, test::GetEncodedSignatures(forms), nullptr);
// Verify that the form fields remain intact because ParseApiQueryResponse
// could not parse the server's response that was badly encoded.
@@ -5389,7 +5585,8 @@ TEST_F(FormStructureTest, ParseQueryResponse_AuthorDefinedTypes) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_GE(forms[0]->field_count(), 2U);
// Server type is parsed from the response and is the end result type.
@@ -5438,7 +5635,8 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) {
ASSERT_TRUE(response.SerializeToString(&response_string));
// Test that the expiry month field is rationalized away.
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
EXPECT_EQ(NAME_FULL, forms[0]->field(0)->Type().GetStorableType());
@@ -5478,7 +5676,8 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) {
ASSERT_TRUE(response.SerializeToString(&response_string));
// Test that the name fields are rationalized.
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(3U, forms[0]->field_count());
EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType());
@@ -5529,7 +5728,8 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) {
ASSERT_TRUE(response.SerializeToString(&response_string));
// Test that the extra month field is rationalized away.
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(5U, forms[0]->field_count());
EXPECT_EQ(CREDIT_CARD_NAME_FULL,
@@ -5580,7 +5780,8 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) {
ASSERT_TRUE(response.SerializeToString(&response_string));
// Test that the extra month field is rationalized away.
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
EXPECT_EQ(CREDIT_CARD_NAME_FULL,
@@ -5667,7 +5868,8 @@ TEST_F(FormStructureTest, RationalizePhoneNumber_RunsOncePerSection) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
EXPECT_FALSE(form_structure.phone_rationalized_["fullName_1-default"]);
form_structure.RationalizePhoneNumbersInSection("fullName_1-default");
@@ -5719,7 +5921,8 @@ TEST_F(FormStructureTest, RationalizeRepeatedFields_OneAddress) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(3U, forms[0]->field_count());
@@ -5771,7 +5974,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_TwoAddresses) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
@@ -5829,7 +6033,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_ThreeAddresses) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(5U, forms[0]->field_count());
@@ -5895,7 +6100,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_FourAddresses) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(6U, forms[0]->field_count());
@@ -5970,7 +6176,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_OneAddressEachSection) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
// Billing
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(6U, forms[0]->field_count());
@@ -6112,7 +6319,8 @@ TEST_F(
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(15U, forms[0]->field_count());
@@ -6197,7 +6405,8 @@ TEST_F(FormStructureTest,
ASSERT_TRUE(response.SerializeToString(&response_string));
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
// Billing
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(6U, forms[0]->field_count());
@@ -6288,7 +6497,8 @@ TEST_F(
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(9U, forms[0]->field_count());
@@ -6382,7 +6592,8 @@ TEST_F(FormStructureTest,
ASSERT_TRUE(response.SerializeToString(&response_string));
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(10U, forms[0]->field_count());
@@ -6508,7 +6719,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_CountryStateNoHeuristics) {
ASSERT_TRUE(response.SerializeToString(&response_string));
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(14U, forms[0]->field_count());
@@ -6639,7 +6851,8 @@ TEST_F(FormStructureTest,
ASSERT_TRUE(response.SerializeToString(&response_string));
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(14U, forms[0]->field_count());
@@ -6713,7 +6926,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_FirstFieldRationalized) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(5U, forms[0]->field_count());
@@ -6781,7 +6995,8 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_LastFieldRationalized) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(6U, forms[0]->field_count());
@@ -6852,7 +7067,8 @@ TEST_P(ParameterizedFormStructureTest,
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
@@ -6917,7 +7133,8 @@ TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
@@ -6992,7 +7209,8 @@ TEST_P(ParameterizedFormStructureTest, WithServerDataCCFields_CVC_NoOverwrite) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
@@ -7078,7 +7296,8 @@ TEST_P(RationalizationFieldTypeFilterTest, Rationalization_Rules_Filter_Out) {
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
@@ -7138,7 +7357,8 @@ TEST_P(RationalizationFieldTypeRelationshipsTest,
forms.push_back(&form_structure);
// Will call RationalizeFieldTypePredictions
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms,
+ test::GetEncodedSignatures(forms), nullptr);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
@@ -7168,11 +7388,11 @@ TEST_F(FormStructureTest, AllowBigForms) {
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- std::vector<std::string> encoded_signatures;
+ FormAndFieldSignatures encoded_signatures;
AutofillQueryContents encoded_query;
- ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
- &encoded_query));
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_query,
+ &encoded_signatures));
EXPECT_EQ(1u, encoded_signatures.size());
}
@@ -7200,12 +7420,14 @@ TEST_F(FormStructureTest, CreateForPasswordManagerUpload) {
FormSignature(1234),
{FieldSignature(1), FieldSignature(10), FieldSignature(100)});
AutofillUploadContents upload;
+ FormAndFieldSignatures signatures;
EXPECT_EQ(FormSignature(1234u), form->form_signature());
ASSERT_EQ(3u, form->field_count());
ASSERT_EQ(FieldSignature(100u), form->field(2)->GetFieldSignature());
EXPECT_TRUE(form->EncodeUploadRequest(
{} /* available_field_types */, false /* form_was_autofilled */,
- "" /*login_form_signature*/, true /*observed_submission*/, &upload));
+ "" /*login_form_signature*/, true /*observed_submission*/, &upload,
+ &signatures));
}
// Tests if a new logical form is started with the second appearance of a field
diff --git a/chromium/components/autofill/core/browser/geo/country_names.cc b/chromium/components/autofill/core/browser/geo/country_names.cc
index f632ff8f6ac..a5db1d0573d 100644
--- a/chromium/components/autofill/core/browser/geo/country_names.cc
+++ b/chromium/components/autofill/core/browser/geo/country_names.cc
@@ -130,7 +130,8 @@ const std::string CountryNames::GetCountryCodeForLocalizedCountryName(
result = country_names_for_locale.GetCountryCode(country);
// Put the country names for the locale into the cache.
- localized_country_names_cache_.Put(locale_name, std::move(result));
+ localized_country_names_cache_.Put(locale_name,
+ std::move(country_names_for_locale));
return result;
}
diff --git a/chromium/components/autofill/core/browser/geo/country_names_unittest.cc b/chromium/components/autofill/core/browser/geo/country_names_unittest.cc
index 46481c05e4b..2f971cb599c 100644
--- a/chromium/components/autofill/core/browser/geo/country_names_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/country_names_unittest.cc
@@ -74,6 +74,9 @@ TEST(CountryNamesTest, GetCountryCodeForLocalizedCountryName) {
TestCountryNames names("en_US");
EXPECT_EQ("AM", names.GetCountryCodeForLocalizedCountryName(
ASCIIToUTF16("Armenien"), "de"));
+ // Check that there is no cache by requesting the same result twice.
+ EXPECT_EQ("AM", names.GetCountryCodeForLocalizedCountryName(
+ ASCIIToUTF16("Armenien"), "de"));
EXPECT_EQ("AZ", names.GetCountryCodeForLocalizedCountryName(
ASCIIToUTF16("Azerbeidzjan"), "nl"));
}
diff --git a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc
index 3aa2b9d378a..4b42968d295 100644
--- a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc
+++ b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc
@@ -97,6 +97,8 @@ void FormEventLoggerBase::OnDidShowSuggestions(
OnSuggestionsShownOnce();
}
+ has_logged_autocomplete_off_ |= field.autocomplete_attribute == "off";
+
RecordShowSuggestions();
}
@@ -272,6 +274,11 @@ void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
has_logged_suggestion_filled_);
key_metrics_rows << Tr{} << "FillingAcceptance"
<< has_logged_suggestion_filled_;
+ UmaHistogramBoolean(
+ base::StrCat({"Autofill.Autocomplete.",
+ (has_logged_autocomplete_off_ ? "Off" : "NotOff"),
+ ".FillingAcceptance.", form_type_name_.c_str()}),
+ has_logged_suggestion_filled_);
}
if (has_logged_suggestion_filled_) {
// Whether a filled form and submitted form required no fixes to filled
diff --git a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h
index 5adfd9446d3..130c04e0e90 100644
--- a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h
+++ b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h
@@ -13,7 +13,6 @@
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "components/autofill/core/common/signatures.h"
namespace autofill {
@@ -111,6 +110,7 @@ class FormEventLoggerBase {
bool has_logged_user_hide_suggestions_ = false;
bool has_logged_suggestions_shown_ = false;
bool has_logged_suggestion_filled_ = false;
+ bool has_logged_autocomplete_off_ = false;
bool has_logged_will_submit_ = false;
bool has_logged_submitted_ = false;
bool logged_suggestion_filled_was_server_data_ = false;
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
new file mode 100644
index 00000000000..127700ebd5c
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -0,0 +1,13 @@
+// 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/payments/autofill_offer_manager.h"
+
+namespace autofill {
+
+AutofillOfferManager::AutofillOfferManager() = default;
+
+AutofillOfferManager::~AutofillOfferManager() = default;
+
+} // namespace autofill \ No newline at end of file
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
new file mode 100644
index 00000000000..ce93163cb9f
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -0,0 +1,42 @@
+// 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_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+
+namespace autofill {
+
+struct AutofillOfferData {
+ AutofillOfferData();
+ ~AutofillOfferData();
+ // The description of this offer.
+ base::string16 description;
+ // The name of this offer.
+ base::string16 name;
+ // The unique server id of this offer.
+ std::string offer_id;
+ // The ids of the cards this offer can be applied to.
+ std::vector<std::string> eligible_card_id;
+ // The merchant URL where this offer can be redeemed.
+ std::vector<std::string> merchant_domain;
+};
+
+// Manages all Autofill related offers. One per frame; owned by the
+// AutofillManager.
+class AutofillOfferManager {
+ public:
+ AutofillOfferManager();
+ virtual ~AutofillOfferManager();
+ AutofillOfferManager(const AutofillOfferManager&) = delete;
+ AutofillOfferManager& operator=(const AutofillOfferManager&) = delete;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_ \ No newline at end of file
diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc
index 762d557835b..8fdc3912d20 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc
@@ -47,7 +47,7 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile(
pref_service_(pref_service),
had_user_interaction_(false),
issuer_icon_id_(CreditCard::IconResourceId(card.network())),
- card_label_(card.NetworkAndLastFourDigits()),
+ card_label_(card.CardIdentifierStringForAutofillDisplay()),
card_sub_label_(card.AbbreviatedExpirationDateForDisplay(false)),
card_last_four_digits_(card.LastFourDigits()),
cardholder_name_(card.GetRawInfo(CREDIT_CARD_NAME_FULL)),
@@ -72,6 +72,15 @@ AutofillSaveCardInfoBarDelegateMobile::
}
}
+// static
+AutofillSaveCardInfoBarDelegateMobile*
+AutofillSaveCardInfoBarDelegateMobile::FromInfobarDelegate(
+ infobars::InfoBarDelegate* delegate) {
+ return delegate->GetIdentifier() == AUTOFILL_CC_INFOBAR_DELEGATE_MOBILE
+ ? static_cast<AutofillSaveCardInfoBarDelegateMobile*>(delegate)
+ : nullptr;
+}
+
void AutofillSaveCardInfoBarDelegateMobile::OnLegalMessageLinkClicked(
GURL url) {
infobar()->owner()->OpenURL(url, WindowOpenDisposition::NEW_FOREGROUND_TAB);
diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h
index 64721013e55..f1f9011b1e2 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h
@@ -39,6 +39,11 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
~AutofillSaveCardInfoBarDelegateMobile() override;
+ // Returns |delegate| as an AutofillSaveCardInfoBarDelegateMobile, or nullptr
+ // if it is of another type.
+ static AutofillSaveCardInfoBarDelegateMobile* FromInfobarDelegate(
+ infobars::InfoBarDelegate* delegate);
+
bool upload() const { return upload_; }
int issuer_icon_id() const { return issuer_icon_id_; }
const base::string16& card_label() const { return card_label_; }
@@ -58,7 +63,7 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
}
// Called when a link in the legal message text was clicked.
- void OnLegalMessageLinkClicked(GURL url);
+ virtual void OnLegalMessageLinkClicked(GURL url);
// Google Pay branding is enabled with a flag and only for cards upstreamed
// to Google.
@@ -82,9 +87,9 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
// Updates and then saves the card using |cardholder_name|,
// |expiration_date_month| and |expiration_date_year|, which were provided
// as part of the iOS save card Infobar dialog.
- bool UpdateAndAccept(base::string16 cardholder_name,
- base::string16 expiration_date_month,
- base::string16 expiration_date_year);
+ virtual bool UpdateAndAccept(base::string16 cardholder_name,
+ base::string16 expiration_date_month,
+ base::string16 expiration_date_year);
#endif // defined(OS_IOS)
private:
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 1d306acd09c..3a1c0a8f5bf 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
@@ -70,11 +70,6 @@ CreditCardAccessManager::CreditCardAccessManager(
base::WaitableEvent::InitialState::NOT_SIGNALED),
can_fetch_unmask_details_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::SIGNALED) {
-#if !defined(OS_IOS)
- // This is to initialize StrikeDatabase is if it hasn't been already, so that
- // its cache would be loaded and ready to use when the first CCAM is created.
- client_->GetStrikeDatabase();
-#endif
}
CreditCardAccessManager::~CreditCardAccessManager() {}
@@ -154,7 +149,7 @@ bool CreditCardAccessManager::GetDeletionConfirmationText(
return false;
if (title)
- title->assign(card->NetworkAndLastFourDigits());
+ title->assign(card->CardIdentifierStringForAutofillDisplay());
if (body) {
body->assign(l10n_util::GetStringUTF16(
IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY));
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index b507de35144..3c13e1d3de6 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -460,7 +460,7 @@ TEST_F(CreditCardAccessManagerTest, LocalCardGetDeletionConfirmationText) {
card, &title, &body));
// |title| and |body| should be updated appropriately.
- EXPECT_EQ(title, card->NetworkAndLastFourDigits());
+ EXPECT_EQ(title, card->CardIdentifierStringForAutofillDisplay());
EXPECT_EQ(body,
l10n_util::GetStringUTF16(
IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY));
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index 1260d1caf9a..6400469d8c9 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -75,6 +75,9 @@ void CreditCardFIDOAuthenticator::Authenticate(
requester_ = requester;
form_parsed_timestamp_ = form_parsed_timestamp;
+ // Cancel any previous pending WebAuthn requests.
+ authenticator()->Cancel();
+
if (card_ && IsValidRequestOptions(request_options.Clone())) {
current_flow_ = AUTHENTICATION_FLOW;
GetAssertion(ParseRequestOptions(std::move(request_options)));
@@ -85,6 +88,9 @@ void CreditCardFIDOAuthenticator::Authenticate(
void CreditCardFIDOAuthenticator::Register(std::string card_authorization_token,
base::Value creation_options) {
+ // Cancel any previous pending WebAuthn requests.
+ authenticator()->Cancel();
+
// If |creation_options| is set, then must enroll a new credential. Otherwise
// directly send request to payments for opting in.
card_authorization_token_ = card_authorization_token;
@@ -105,6 +111,10 @@ void CreditCardFIDOAuthenticator::Authorize(
base::Value request_options) {
requester_ = requester;
card_authorization_token_ = card_authorization_token;
+
+ // Cancel any previous pending WebAuthn requests.
+ authenticator()->Cancel();
+
if (IsValidRequestOptions(request_options)) {
// If user is already opted-in, then a new card is trying to be
// authorized. Otherwise, a user with a credential on file is trying to
@@ -116,6 +126,9 @@ void CreditCardFIDOAuthenticator::Authorize(
}
void CreditCardFIDOAuthenticator::OptOut() {
+ // Cancel any previous pending WebAuthn requests.
+ authenticator()->Cancel();
+
current_flow_ = OPT_OUT_FLOW;
card_authorization_token_ = std::string();
OptChange();
@@ -181,6 +194,8 @@ UserOptInIntention CreditCardFIDOAuthenticator::GetUserOptInIntention(
}
void CreditCardFIDOAuthenticator::CancelVerification() {
+ authenticator()->Cancel();
+
current_flow_ = NONE_FLOW;
// Full card request may not exist when this function is called. The full card
// request is created in OnDidGetAssertion() but the flow can be cancelled
@@ -193,6 +208,10 @@ void CreditCardFIDOAuthenticator::CancelVerification() {
void CreditCardFIDOAuthenticator::OnWebauthnOfferDialogRequested(
std::string card_authorization_token) {
card_authorization_token_ = card_authorization_token;
+
+ // Cancel any previous pending WebAuthn requests.
+ authenticator()->Cancel();
+
AutofillMetrics::LogWebauthnOptInPromoShown(
/*is_checkout_flow=*/!card_authorization_token_.empty());
@@ -651,7 +670,7 @@ base::Value CreditCardFIDOAuthenticator::ParseAssertionResponse(
response.SetKey("credential_id",
BytesToBase64(assertion_response->info->raw_id));
response.SetKey("authenticator_data",
- BytesToBase64(assertion_response->authenticator_data));
+ BytesToBase64(assertion_response->info->authenticator_data));
response.SetKey("client_data",
BytesToBase64(assertion_response->info->client_data_json));
response.SetKey("signature", BytesToBase64(assertion_response->signature));
@@ -733,6 +752,7 @@ void CreditCardFIDOAuthenticator::LogWebauthnResult(
return;
}
+ // TODO(crbug.com/949269): Add metrics for revoked pending WebAuthn requests.
AutofillMetrics::WebauthnResultMetric metric;
switch (status) {
case AuthenticatorStatus::SUCCESS:
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 617c2f22a46..e9e8c203a20 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
@@ -86,9 +86,6 @@ CreditCardSaveManager::CreditCardSaveManager(
payments_client_(payments_client),
app_locale_(app_locale),
personal_data_manager_(personal_data_manager) {
- // This is to initialize StrikeDatabase is if it hasn't been already, so that
- // its cache would be loaded and ready to use when the first CCSM is created.
- client_->GetStrikeDatabase();
}
CreditCardSaveManager::~CreditCardSaveManager() {}
@@ -255,8 +252,6 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
(should_request_expiration_date_from_user_ &&
personal_data_manager_->GetSyncSigninState() ==
AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled)) {
- DCHECK(base::FeatureList::IsEnabled(
- features::kAutofillUpstreamEditableExpirationDate));
LogCardUploadDecisions(upload_decision_metrics_);
pending_upload_request_origin_ = url::Origin();
return;
@@ -731,43 +726,39 @@ int CreditCardSaveManager::GetDetectedValues() const {
detected_values |= DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT;
}
- if (base::FeatureList::IsEnabled(
- features::kAutofillUpstreamEditableExpirationDate)) {
- // If expiration date month or expiration year are missing, signal that
- // expiration date will be explicitly requested in the offer-to-save bubble.
- if (!upload_request_.card
- .GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale_)
- .empty()) {
- detected_values |= DetectedValue::CARD_EXPIRATION_MONTH;
- }
- if (!(upload_request_.card
- .GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale_)
- .empty())) {
- detected_values |= DetectedValue::CARD_EXPIRATION_YEAR;
- }
+ // If expiration date month or expiration year are missing, signal that
+ // expiration date will be explicitly requested in the offer-to-save bubble.
+ if (!upload_request_.card
+ .GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale_)
+ .empty()) {
+ detected_values |= DetectedValue::CARD_EXPIRATION_MONTH;
+ }
+ if (!(upload_request_.card
+ .GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale_)
+ .empty())) {
+ detected_values |= DetectedValue::CARD_EXPIRATION_YEAR;
+ }
- // Set |USER_PROVIDED_EXPIRATION_DATE| if expiration date is detected as
- // expired or missing.
- if (detected_values & DetectedValue::CARD_EXPIRATION_MONTH &&
- detected_values & DetectedValue::CARD_EXPIRATION_YEAR) {
- int month_value = 0, year_value = 0;
- bool parsable =
- base::StringToInt(
- upload_request_.card.GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH),
- app_locale_),
- &month_value) &&
- base::StringToInt(
- upload_request_.card.GetInfo(
- AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale_),
- &year_value);
- DCHECK(parsable);
- if (!IsValidCreditCardExpirationDate(year_value, month_value,
- AutofillClock::Now())) {
- detected_values |= DetectedValue::USER_PROVIDED_EXPIRATION_DATE;
- }
- } else {
+ // Set |USER_PROVIDED_EXPIRATION_DATE| if expiration date is detected as
+ // expired or missing.
+ if (detected_values & DetectedValue::CARD_EXPIRATION_MONTH &&
+ detected_values & DetectedValue::CARD_EXPIRATION_YEAR) {
+ int month_value = 0, year_value = 0;
+ bool parsable =
+ base::StringToInt(upload_request_.card.GetInfo(
+ AutofillType(CREDIT_CARD_EXP_MONTH), app_locale_),
+ &month_value) &&
+ base::StringToInt(
+ upload_request_.card.GetInfo(
+ AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale_),
+ &year_value);
+ DCHECK(parsable);
+ if (!IsValidCreditCardExpirationDate(year_value, month_value,
+ AutofillClock::Now())) {
detected_values |= DetectedValue::USER_PROVIDED_EXPIRATION_DATE;
}
+ } else {
+ detected_values |= DetectedValue::USER_PROVIDED_EXPIRATION_DATE;
}
// If cardholder name is conflicting/missing and the user does NOT have a
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 184326bc942..8798b034fb0 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
@@ -2619,9 +2619,6 @@ TEST_F(
TEST_F(
CreditCardSaveManagerTest,
UploadCreditCard_ShouldRequestExpirationDate_ResetBetweenConsecutiveSaves) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
-
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2670,9 +2667,6 @@ TEST_F(
TEST_F(
CreditCardSaveManagerTest,
UploadCreditCard_WalletSyncTransportEnabled_ShouldNotRequestExpirationDate) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
-
// Wallet Sync Transport is enabled.
personal_data_.SetSyncAndSignInState(
AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled);
@@ -2709,9 +2703,6 @@ TEST_F(
TEST_F(
CreditCardSaveManagerTest,
UploadCreditCard_WalletSyncTransportNotEnabled_ShouldRequestExpirationDate) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
-
// Wallet Sync Transport is not enabled.
personal_data_.SetSyncAndSignInState(
AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled);
@@ -2750,9 +2741,6 @@ TEST_F(
TEST_F(
CreditCardSaveManagerTest,
UploadCreditCard_DoNotRequestExpirationDateIfMissingNameAndExpirationDate) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
-
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2782,36 +2770,6 @@ TEST_F(
}
TEST_F(CreditCardSaveManagerTest,
- UploadCreditCard_DoNotRequestExpirationDate_EditableExpDateOff) {
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
- // Create, fill and submit an address form in order to establish a recent
- // profile which can be selected for the upload request.
- FormData address_form;
- test::CreateTestAddressFormData(&address_form);
- FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("John", "Smith", "77401", "US", &address_form);
- FormSubmitted(address_form);
-
- // Set up our credit card form data.
- FormData credit_card_form;
- CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
- FormsSeen(std::vector<FormData>(1, credit_card_form));
-
- // Edit the data, and submit.
- credit_card_form.fields[0].value = ASCIIToUTF16("John Smith");
- credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
- credit_card_form.fields[2].value = ASCIIToUTF16("");
- credit_card_form.fields[3].value = ASCIIToUTF16("");
- credit_card_form.fields[4].value = ASCIIToUTF16("123");
-
- base::HistogramTester histogram_tester;
- FormSubmitted(credit_card_form);
- EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
- EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());
-}
-
-TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_RequestExpirationDateViaExpDateFixFlow) {
#if defined(OS_IOS)
// iOS should always provide a valid expiration date when attempting to
@@ -2824,8 +2782,6 @@ TEST_F(CreditCardSaveManagerTest,
}
#endif
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2878,8 +2834,6 @@ TEST_F(CreditCardSaveManagerTest,
}
#endif
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2932,8 +2886,6 @@ TEST_F(CreditCardSaveManagerTest,
}
#endif
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2986,8 +2938,6 @@ TEST_F(CreditCardSaveManagerTest,
}
#endif
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -3041,8 +2991,6 @@ TEST_F(
}
#endif
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillUpstreamEditableExpirationDate);
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
diff --git a/chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc b/chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc
index 257e22c22b2..1234667a475 100644
--- a/chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc
@@ -10,6 +10,7 @@
#include "base/check_op.h"
#include "base/json/json_reader.h"
+#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
index 742c4b8c80a..ec61627e313 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -41,9 +41,6 @@ LocalCardMigrationManager::LocalCardMigrationManager(
payments_client_(payments_client),
app_locale_(app_locale),
personal_data_manager_(personal_data_manager) {
- // This is to initialize StrikeDatabase is if it hasn't been already, so that
- // its cache would be loaded and ready to use when the first LCMM is created.
- client_->GetStrikeDatabase();
}
LocalCardMigrationManager::~LocalCardMigrationManager() {}
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index 10db6a376e2..f340bc58f33 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -218,6 +218,12 @@ base::Value BuildCreditCardDictionary(const CreditCard& credit_card,
SetStringIfNotEmpty(credit_card, CREDIT_CARD_NAME_FULL, app_locale,
"cardholder_name", card);
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableCardNicknameUpstream) &&
+ credit_card.HasValidNickname()) {
+ card.SetKey("nickname", base::Value(credit_card.nickname()));
+ }
+
card.SetKey("encrypted_pan", base::Value("__param:" + pan_field_name));
return card;
}
@@ -819,6 +825,13 @@ class UploadCardRequest : public PaymentsRequest {
if (base::StringToInt(exp_year, &value))
request_dict.SetKey("expiration_year", base::Value(value));
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableCardNicknameUpstream) &&
+ request_details_.card.HasValidNickname()) {
+ request_dict.SetKey("nickname",
+ base::Value(request_details_.card.nickname()));
+ }
+
SetActiveExperiments(request_details_.active_experiments, request_dict);
const base::string16 pan = request_details_.card.GetInfo(
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 ac12ca2ff90..821f70b48fc 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -235,12 +235,16 @@ class PaymentsClientTest : public testing::Test {
// Issue an UploadCard request. This requires an OAuth token before starting
// the request.
- void StartUploading(bool include_cvc) {
+ void StartUploading(bool include_cvc, bool include_nickname = false) {
PaymentsClient::UploadRequestDetails request_details;
request_details.billing_customer_number = 111222333444;
request_details.card = test::GetCreditCard();
if (include_cvc)
request_details.cvc = base::ASCIIToUTF16("123");
+ if (include_nickname) {
+ upstream_nickname_ = base::ASCIIToUTF16("grocery");
+ request_details.card.SetNickname(upstream_nickname_);
+ }
request_details.context_token = base::ASCIIToUTF16("context token");
request_details.risk_data = "some risk data";
request_details.app_locale = "language-LOCALE";
@@ -251,7 +255,8 @@ class PaymentsClientTest : public testing::Test {
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
- void StartMigrating(bool has_cardholder_name) {
+ void StartMigrating(bool has_cardholder_name,
+ bool set_nickname_for_first_card = false) {
PaymentsClient::MigrationRequestDetails request_details;
request_details.context_token = base::ASCIIToUTF16("context token");
request_details.risk_data = "some risk data";
@@ -259,6 +264,8 @@ class PaymentsClientTest : public testing::Test {
migratable_credit_cards_.clear();
CreditCard card1 = test::GetCreditCard();
+ if (set_nickname_for_first_card)
+ card1.SetNickname(base::ASCIIToUTF16("grocery"));
CreditCard card2 = test::GetCreditCard2();
if (!has_cardholder_name) {
card1.SetRawInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16(""));
@@ -313,6 +320,8 @@ class PaymentsClientTest : public testing::Test {
// A list of card BIN ranges supported by Google Payments, returned from a
// GetDetails upload save preflight call.
std::vector<std::pair<int, int>> supported_card_bin_ranges_;
+ // The nickname name in the UploadRequest that was supposed to be saved.
+ base::string16 upstream_nickname_;
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Credit cards to be upload saved during a local credit card migration call.
@@ -895,6 +904,41 @@ TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) {
EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") == std::string::npos);
}
+TEST_F(PaymentsClientTest, UploadIncludesCardNickname) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableCardNicknameUpstream);
+
+ StartUploading(/*include_cvc=*/true, /*include_nickname=*/true);
+ IssueOAuthToken();
+
+ // Card nickname was set.
+ EXPECT_TRUE(GetUploadData().find("nickname") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find(base::UTF16ToUTF8(upstream_nickname_)) !=
+ std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, UploadDoesNotIncludeCardNicknameFlagDisabled) {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillEnableCardNicknameUpstream);
+
+ StartUploading(/*include_cvc=*/true, /*include_nickname=*/true);
+ IssueOAuthToken();
+
+ // Card nickname was not set.
+ EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, UploadDoesNotIncludeCardNicknameEmptyNickname) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableCardNicknameUpstream);
+
+ StartUploading(/*include_cvc=*/true, /*include_nickname=*/false);
+ IssueOAuthToken();
+
+ // Card nickname was not set.
+ EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
+}
+
TEST_F(PaymentsClientTest, UnmaskMissingPan) {
StartUnmasking(CardUnmaskOptions());
ReturnResponse(net::HTTP_OK, "{}");
@@ -1087,6 +1131,37 @@ TEST_F(PaymentsClientTest,
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
+TEST_F(PaymentsClientTest, MigrationRequestIncludesCardNickname) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableCardNicknameUpstream);
+
+ StartMigrating(/*has_cardholder_name=*/true,
+ /*set_nickname_to_first_card=*/true);
+ IssueOAuthToken();
+
+ // Nickname was set for the first card.
+ std::size_t pos = GetUploadData().find("nickname");
+ EXPECT_TRUE(pos != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find(base::UTF16ToUTF8(
+ migratable_credit_cards_[0].credit_card().nickname())) !=
+ std::string::npos);
+
+ // Nickname was not set for the second card.
+ EXPECT_FALSE(GetUploadData().find("nickname", pos + 1) != std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, MigrationRequestExcludesCardNicknameIfFlagDisabled) {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillEnableCardNicknameUpstream);
+
+ StartMigrating(/*has_cardholder_name=*/true,
+ /*set_nickname_for_first_card=*/true);
+ IssueOAuthToken();
+
+ // Nickname was not set.
+ EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
+}
+
TEST_F(PaymentsClientTest, MigrationSuccessWithSaveResult) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
diff --git a/chromium/components/autofill/core/browser/payments/test_internal_authenticator.cc b/chromium/components/autofill/core/browser/payments/test_internal_authenticator.cc
new file mode 100644
index 00000000000..68a073b8114
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/test_internal_authenticator.cc
@@ -0,0 +1,15 @@
+// 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/payments/test_internal_authenticator.h"
+
+namespace autofill {
+
+void TestInternalAuthenticator::IsUserVerifyingPlatformAuthenticatorAvailable(
+ blink::mojom::Authenticator::
+ IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) {
+ std::move(callback).Run(false);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/test_internal_authenticator.h b/chromium/components/autofill/core/browser/payments/test_internal_authenticator.h
index ec6ec8902ba..aecafe23605 100644
--- a/chromium/components/autofill/core/browser/payments/test_internal_authenticator.h
+++ b/chromium/components/autofill/core/browser/payments/test_internal_authenticator.h
@@ -28,7 +28,7 @@ class TestInternalAuthenticator : public InternalAuthenticator {
void IsUserVerifyingPlatformAuthenticatorAvailable(
blink::mojom::Authenticator::
IsUserVerifyingPlatformAuthenticatorAvailableCallback callback)
- override {}
+ override;
void Cancel() override {}
};
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index e45d579f73f..aa552996904 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -445,11 +445,6 @@ void PersonalDataManager::OnWebDataServiceRequestDone(
ReceiveLoadedDbValues(h, result.get(),
&pending_server_creditcards_query_,
&server_credit_cards_);
-
- // If the user has a saved unmasked server card and the experiment is
- // disabled, force mask all cards back to the unsaved state.
- if (!OfferStoreUnmaskedCards(is_off_the_record_))
- ResetFullServerCards();
}
break;
case AUTOFILL_CLOUDTOKEN_RESULT:
@@ -2067,12 +2062,17 @@ std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
? Suggestion::PREFIX_MATCH
: Suggestion::SUBSTRING_MATCH;
+ // Get the nickname for the card suggestion, which may not be the same as
+ // the card's nickname if there are duplicates of the card on file.
+ base::string16 suggestion_nickname =
+ GetDisplayNicknameForCreditCard(*credit_card);
+
// If the value is the card number, the label is the expiration date.
// Otherwise the label is the card number, or if that is empty the
// cardholder name. The label should never repeat the value.
if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
- suggestion->value =
- credit_card->CardIdentifierStringForAutofillDisplay();
+ suggestion->value = credit_card->CardIdentifierStringForAutofillDisplay(
+ suggestion_nickname);
#if defined(OS_ANDROID) || defined(OS_IOS)
suggestion->label = credit_card->GetInfo(
@@ -2082,9 +2082,10 @@ std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
#endif // defined(OS_ANDROID) || defined(OS_IOS)
} else if (credit_card->number().empty()) {
- // TODO(crbug/1059087): Update suggestion label with nickname for
- // empty-number local cards when nickname is supported for local card.
- if (type.GetStorableType() != CREDIT_CARD_NAME_FULL) {
+ DCHECK_EQ(credit_card->record_type(), CreditCard::LOCAL_CARD);
+ if (credit_card->HasValidNickname()) {
+ suggestion->label = credit_card->nickname();
+ } else if (type.GetStorableType() != CREDIT_CARD_NAME_FULL) {
suggestion->label = credit_card->GetInfo(
AutofillType(CREDIT_CARD_NAME_FULL), app_locale_);
}
@@ -2096,7 +2097,8 @@ std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
suggestion->label =
base::FeatureList::IsEnabled(features::kAutofillKeyboardAccessory)
? credit_card->ObfuscatedLastFourDigits()
- : credit_card->CardIdentifierStringForAutofillDisplay();
+ : credit_card->CardIdentifierStringForAutofillDisplay(
+ suggestion_nickname);
#elif defined(OS_IOS)
// E.g. "••••1234"".
suggestion->label = credit_card->ObfuscatedLastFourDigits();
@@ -2651,4 +2653,27 @@ void PersonalDataManager::MigrateUserOptedInWalletSyncTransportIfNeeded() {
/*opted_in=*/true);
}
+base::string16 PersonalDataManager::GetDisplayNicknameForCreditCard(
+ const CreditCard& card) const {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableCardNicknameManagement)) {
+ return base::string16();
+ }
+
+ // Always prefer a local nickname if available.
+ if (card.HasValidNickname() && card.record_type() == CreditCard::LOCAL_CARD)
+ return card.nickname();
+ // Either the card a) has no nickname or b) is a server card and we would
+ // prefer to use the nickname of a local card.
+ std::vector<CreditCard*> candidates = GetCreditCards();
+ for (CreditCard* candidate : candidates) {
+ if (candidate->guid() != card.guid() && candidate->HasSameNumberAs(card) &&
+ candidate->HasValidNickname()) {
+ return candidate->nickname();
+ }
+ }
+ // Fall back to nickname of |card|, which may be empty.
+ return card.nickname();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index 1e787a4d3c0..42d68aa0a67 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -752,6 +752,12 @@ class PersonalDataManager : public KeyedService,
// migrating from using email to Gaia ID as th account identifier.
void MigrateUserOptedInWalletSyncTransportIfNeeded();
+ // Return a nickname for the |card| to display. This is generally the nickname
+ // stored in |card|, unless |card| exists as a local and a server copy. In
+ // this case, we prefer the nickname of the local if it is defined. If only
+ // one copy has a nickname, take that.
+ base::string16 GetDisplayNicknameForCreditCard(const CreditCard& card) const;
+
// Stores the |app_locale| supplied on construction.
const std::string app_locale_;
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 766044927d5..10d3b58f676 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -1058,6 +1058,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
+ credit_card0.SetNickname(base::ASCIIToUTF16("card zero"));
CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
@@ -1068,6 +1069,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
test::SetCreditCardInfo(&credit_card2, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
+ credit_card2.SetNickname(base::ASCIIToUTF16("card two"));
// Add two test credit cards to the database.
personal_data_->AddCreditCard(credit_card0);
@@ -1082,6 +1084,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
// Update, remove, and add.
credit_card0.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Joe"));
+ credit_card0.SetNickname(base::ASCIIToUTF16("new card zero"));
personal_data_->UpdateCreditCard(credit_card0);
RemoveByGUIDFromPersonalDataManager(credit_card1.guid());
personal_data_->AddCreditCard(credit_card2);
@@ -1433,136 +1436,6 @@ TEST_F(PersonalDataManagerTest, KeepExistingLocalDataOnSignIn) {
EXPECT_EQ(0, local_card.Compare(*personal_data_->GetCreditCards()[0]));
}
-// Makes sure that full cards are re-masked when full PAN storage is off.
-TEST_F(PersonalDataManagerTest, RefuseToStoreFullCard) {
-// On Linux this should be disabled automatically. Elsewhere, only if the
-// flag is passed.
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- EXPECT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOfferStoreUnmaskedWalletCards));
-#else
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableOfferStoreUnmaskedWalletCards);
-#endif
-
- std::vector<CreditCard> server_cards;
- server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
- test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "378282246310005" /* American Express */, "04",
- "2999", "1");
- SetServerCards(server_cards);
- personal_data_->Refresh();
-
- WaitForOnPersonalDataChanged();
-
- ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
- EXPECT_EQ(CreditCard::MASKED_SERVER_CARD,
- personal_data_->GetCreditCards()[0]->record_type());
-}
-
-// Makes sure that full cards are only added as masked card when full PAN
-// storage is disabled.
-TEST_F(PersonalDataManagerTest, AddFullCardAsMaskedCard) {
-// On Linux this should be disabled automatically. Elsewhere, only if the
-// flag is passed.
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- EXPECT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOfferStoreUnmaskedWalletCards));
-#else
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableOfferStoreUnmaskedWalletCards);
-#endif
-
- CreditCard server_card(CreditCard::FULL_SERVER_CARD, "c789");
- test::SetCreditCardInfo(&server_card, "Clyde Barrow",
- "378282246310005" /* American Express */, "04",
- "2999", "1");
-
- personal_data_->AddFullServerCreditCard(server_card);
-
- WaitForOnPersonalDataChanged();
-
- ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
- EXPECT_EQ(CreditCard::MASKED_SERVER_CARD,
- personal_data_->GetCreditCards()[0]->record_type());
-}
-
-TEST_F(PersonalDataManagerTest, OfferStoreUnmaskedCards) {
-#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_MACOSX) || \
- defined(OS_IOS) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
- bool should_offer = true;
-#elif defined(OS_LINUX)
- bool should_offer = false;
-#endif
- EXPECT_EQ(should_offer, OfferStoreUnmaskedCards(/*is_off_the_record=*/false));
-}
-
-// Tests that OfferStoreUnmaskedCards always returns false if the user is off
-// the record.
-TEST_F(PersonalDataManagerTest, OfferStoreUnmaskedCards_OffTheRecord) {
- EXPECT_EQ(false, OfferStoreUnmaskedCards(/*is_off_the_record=*/true));
-}
-
-// Tests that UpdateServerCreditCard can be used to mask or unmask server cards.
-TEST_F(PersonalDataManagerTest, UpdateServerCreditCards) {
- EnableWalletCardImport();
-
- std::vector<CreditCard> server_cards;
- server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
- test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "3456" /* Visa */, "01", "2999", "1");
- server_cards.back().SetNetworkForMaskedCard(kVisaCard);
-
- server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456"));
- test::SetCreditCardInfo(&server_cards.back(), "Bonnie Parker",
- "5100" /* Mastercard */, "12", "2999", "1");
- server_cards.back().SetNetworkForMaskedCard(kMasterCard);
-
- server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
- test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "378282246310005" /* American Express */, "04",
- "2999", "1");
-
- SetServerCards(server_cards);
- personal_data_->Refresh();
-
- WaitForOnPersonalDataChanged();
-
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
- if (!OfferStoreUnmaskedCards(/*is_off_the_record=*/false)) {
- for (CreditCard* card : personal_data_->GetCreditCards()) {
- EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, card->record_type());
- }
- // The rest of this test doesn't work if we're force-masking all unmasked
- // cards.
- return;
- }
-
- // The GUIDs will be different, so just compare the data.
- for (size_t i = 0; i < 3; ++i)
- EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
-
- CreditCard* unmasked_card = &server_cards.front();
- unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD);
- unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456"));
- personal_data_->UpdateServerCreditCard(*unmasked_card);
-
- WaitForOnPersonalDataChanged();
-
- for (size_t i = 0; i < 3; ++i)
- EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
-
- CreditCard* remasked_card = &server_cards.back();
- remasked_card->set_record_type(CreditCard::MASKED_SERVER_CARD);
- remasked_card->SetNumber(base::ASCIIToUTF16("0005"));
- personal_data_->UpdateServerCreditCard(*remasked_card);
-
- WaitForOnPersonalDataChanged();
-
- for (size_t i = 0; i < 3; ++i)
- EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
-}
-
TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
@@ -3345,7 +3218,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_LocalCardsRanking) {
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(3U, suggestions.size());
@@ -3394,7 +3267,7 @@ TEST_F(PersonalDataManagerTest,
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(5U, suggestions.size());
@@ -3448,7 +3321,7 @@ TEST_F(PersonalDataManagerTest,
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(0U, suggestions.size());
}
@@ -3498,7 +3371,7 @@ TEST_F(PersonalDataManagerTest,
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(0U, suggestions.size());
}
@@ -3563,7 +3436,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) {
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/* include_server_cards= */ true);
ASSERT_EQ(3U, suggestions.size());
@@ -3691,7 +3564,8 @@ TEST_F(PersonalDataManagerTest,
// Test that a card that doesn't have a number is not shown in the suggestions
// when querying credit cards by their number.
-TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
+TEST_F(PersonalDataManagerTest,
+ GetCreditCardSuggestions_NumberMissing_QueryNumberField) {
// Create one normal credit card and one credit card with the number missing.
ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
@@ -3723,7 +3597,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NUMBER),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ(base::UTF8ToUTF16(std::string("Amex ") +
@@ -3737,6 +3611,36 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
#endif // defined (OS_ANDROID) || defined(OS_IOS)
}
+// Test that a card that doesn't have a number is shown in the suggestion list
+// with nickname if a non-number field is queried.
+TEST_F(PersonalDataManagerTest,
+ GetCreditCardSuggestions_NumberMissing_QueryNonNumberField) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableSurfacingServerCardNickname);
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
+
+ CreditCard credit_card("1141084B-72D7-4B73-90CF-3D6AC154673B",
+ test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card, "John Dillinger", "", "01", "2999",
+ "1");
+ credit_card.SetNickname(base::UTF8ToUTF16("nickname"));
+ personal_data_->AddCreditCard(credit_card);
+
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
+
+ // Ensures the suggestion label is the card's nickname.
+ std::vector<Suggestion> suggestions =
+ personal_data_->GetCreditCardSuggestions(
+ AutofillType(CREDIT_CARD_NAME_FULL),
+ /*field_contents=*/base::string16(),
+ /*include_server_cards=*/true);
+ ASSERT_EQ(1U, suggestions.size());
+ EXPECT_EQ(base::UTF8ToUTF16("nickname"), suggestions[0].label);
+}
+
// Tests the suggestions of duplicate local and server credit cards.
TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
EnableWalletCardImport();
@@ -3777,7 +3681,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(3U, suggestions.size());
EXPECT_EQ(base::ASCIIToUTF16("John Dillinger"), suggestions[0].value);
@@ -3785,7 +3689,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[2].value);
suggestions = personal_data_->GetCreditCardSuggestions(
- AutofillType(CREDIT_CARD_NUMBER), /* field_contents= */ base::string16(),
+ AutofillType(CREDIT_CARD_NUMBER), /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(3U, suggestions.size());
EXPECT_EQ(base::UTF8ToUTF16(std::string("Visa ") +
@@ -3824,7 +3728,7 @@ TEST_F(PersonalDataManagerTest,
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(),
+ /*field_contents=*/base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(3U, suggestions.size());
@@ -3839,7 +3743,7 @@ TEST_F(PersonalDataManagerTest,
suggestions = personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
- /* field_contents= */ base::string16(), /*include_server_cards=*/true);
+ /*field_contents=*/base::string16(), /*include_server_cards=*/true);
ASSERT_EQ(3U, suggestions.size());
}
@@ -4036,120 +3940,6 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) {
EXPECT_EQ(kArbitraryTime, added_card->modification_date());
}
-TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
- EnableWalletCardImport();
-
- std::vector<CreditCard> server_cards;
- server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
- test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "3456" /* Visa */, "01", "2999", "1");
- server_cards.back().SetNetworkForMaskedCard(kVisaCard);
-
- server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456"));
- test::SetCreditCardInfo(&server_cards.back(), "Bonnie Parker",
- "4444" /* Mastercard */, "12", "2999", "1");
- server_cards.back().SetNetworkForMaskedCard(kMasterCard);
-
- server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
- test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "378282246310005" /* American Express */, "04",
- "2999", "1");
-
- // Create the test clock and set the time to a specific value.
- TestAutofillClock test_clock;
- test_clock.SetNow(kArbitraryTime);
-
- SetServerCards(server_cards);
-
- // Make sure everything is set up correctly.
- personal_data_->Refresh();
- WaitForOnPersonalDataChanged();
- EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
-
- if (!OfferStoreUnmaskedCards(/*is_off_the_record=*/false)) {
- for (CreditCard* card : personal_data_->GetCreditCards()) {
- EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, card->record_type());
- }
- // The rest of this test doesn't work if we're force-masking all unmasked
- // cards.
- return;
- }
-
- // The GUIDs will be different, so just compare the data.
- for (size_t i = 0; i < 3; ++i)
- EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
-
- CreditCard* unmasked_card = &server_cards.front();
- unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD);
- unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456"));
- personal_data_->UpdateServerCreditCard(*unmasked_card);
-
- WaitForOnPersonalDataChanged();
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
-
- for (size_t i = 0; i < 3; ++i)
- EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
-
- // For an unmasked card, usage data starts out as 2 because of the unmasking
- // which is considered a use. The use date should now be the specified Now()
- // time kArbitraryTime.
- EXPECT_EQ(2U, personal_data_->GetCreditCards()[0]->use_count());
- EXPECT_EQ(kArbitraryTime, personal_data_->GetCreditCards()[0]->use_date());
-
- EXPECT_EQ(1U, personal_data_->GetCreditCards()[1]->use_count());
- EXPECT_NE(kArbitraryTime, personal_data_->GetCreditCards()[1]->use_date());
-
- // Having unmasked this card, usage stats should be 2 and
- // kArbitraryTime.
- EXPECT_EQ(2U, personal_data_->GetCreditCards()[2]->use_count());
- EXPECT_EQ(kArbitraryTime, personal_data_->GetCreditCards()[2]->use_date());
-
- // Change the Now() value for a second time.
- test_clock.SetNow(kSomeLaterTime);
-
- server_cards.back().set_guid(personal_data_->GetCreditCards()[2]->guid());
- personal_data_->RecordUseOf(server_cards.back());
-
- WaitForOnPersonalDataChanged();
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
- EXPECT_EQ(2U, personal_data_->GetCreditCards()[0]->use_count());
- EXPECT_EQ(kArbitraryTime, personal_data_->GetCreditCards()[0]->use_date());
-
- EXPECT_EQ(1U, personal_data_->GetCreditCards()[1]->use_count());
- EXPECT_NE(kArbitraryTime, personal_data_->GetCreditCards()[1]->use_date());
-
- // The RecordUseOf call should have incremented the use_count to 3 and set the
- // use_date to kSomeLaterTime.
- EXPECT_EQ(3U, personal_data_->GetCreditCards()[2]->use_count());
- EXPECT_EQ(kSomeLaterTime, personal_data_->GetCreditCards()[2]->use_date());
-
- // Can record usage stats on masked cards.
- server_cards[1].set_guid(personal_data_->GetCreditCards()[1]->guid());
- personal_data_->RecordUseOf(server_cards[1]);
-
- WaitForOnPersonalDataChanged();
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
- EXPECT_EQ(2U, personal_data_->GetCreditCards()[1]->use_count());
- EXPECT_EQ(kSomeLaterTime, personal_data_->GetCreditCards()[1]->use_date());
-
- // Change Now()'s return value for a third time.
- test_clock.SetNow(kMuchLaterTime);
-
- // Upgrading to unmasked retains the usage stats (and increments them).
- CreditCard* unmasked_card2 = &server_cards[1];
- unmasked_card2->set_record_type(CreditCard::FULL_SERVER_CARD);
- unmasked_card2->SetNumber(base::ASCIIToUTF16("5555555555554444"));
- personal_data_->UpdateServerCreditCard(*unmasked_card2);
-
- server_cards[1].set_guid(personal_data_->GetCreditCards()[1]->guid());
- personal_data_->RecordUseOf(server_cards[1]);
-
- WaitForOnPersonalDataChanged();
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
- EXPECT_EQ(3U, personal_data_->GetCreditCards()[1]->use_count());
- EXPECT_EQ(kMuchLaterTime, personal_data_->GetCreditCards()[1]->use_date());
-}
-
TEST_F(PersonalDataManagerTest, ClearAllServerData) {
// Add a server card.
std::vector<CreditCard> server_cards;
@@ -6746,21 +6536,6 @@ TEST_F(PersonalDataManagerTest, CreateDataForTest) {
}
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-// Make sure that it's not possible to add full server cards on Linux.
-TEST_F(PersonalDataManagerTest, CannotAddFullServerCardOnLinux) {
- SetUpThreeCardTypes();
-
- // Check that cards were masked and other were untouched.
- EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
- std::vector<CreditCard*> server_cards =
- personal_data_->GetServerCreditCards();
- EXPECT_EQ(2U, server_cards.size());
- for (CreditCard* card : server_cards)
- EXPECT_TRUE(card->record_type() == CreditCard::MASKED_SERVER_CARD);
-}
-#endif // #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-
// These tests are not applicable on Linux since it does not support full server
// cards.
#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
@@ -7884,11 +7659,11 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
///////////////////////////////////////////////////////////
// kSignedInAndWalletSyncTransportEnabled
///////////////////////////////////////////////////////////
- // Make a non-primary account available with both a refresh token and cookie
- // to be in Sync Transport for Wallet mode.
+ // Make a primary account with no sync consent available to be in Sync
+ // Transport for Wallet mode.
CoreAccountInfo active_info =
- identity_test_env_.MakeAccountAvailable(kSyncTransportAccountEmail);
- identity_test_env_.SetCookieAccounts({{active_info.email, active_info.gaia}});
+ identity_test_env_.MakeUnconsentedPrimaryAccountAvailable(
+ kSyncTransportAccountEmail);
sync_service_.SetAuthenticatedAccountInfo(active_info);
sync_service_.SetIsAuthenticatedAccountPrimary(false);
sync_service_.SetActiveDataTypes(
@@ -7943,12 +7718,11 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
prefs::ClearSyncTransportOptIns(prefs_.get());
ASSERT_FALSE(prefs::IsUserOptedInWalletSyncTransport(prefs_.get(),
active_info.account_id));
-#endif // !defined(OS_CHROMEOS)
///////////////////////////////////////////////////////////
// kSignedOut
///////////////////////////////////////////////////////////
- identity_test_env_.RemoveRefreshTokenForAccount(active_info.account_id);
+ identity_test_env_.ClearPrimaryAccount();
{
EXPECT_EQ(AutofillSyncSigninState::kSignedOut,
personal_data_->GetSyncSigninState());
@@ -7959,6 +7733,7 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
EXPECT_FALSE(prefs::IsUserOptedInWalletSyncTransport(
prefs_.get(), active_info.account_id));
}
+#endif // !defined(OS_CHROMEOS)
///////////////////////////////////////////////////////////
// kSignedInAndSyncFeature
@@ -8028,4 +7803,132 @@ TEST_F(PersonalDataManagerTest, AddAndGetUpiId) {
EXPECT_THAT(all_upi_ids, testing::ElementsAre(upi_id));
}
+struct ShareNicknameTestParam {
+ std::string local_nickname;
+ std::string server_nickname;
+ std::string expected_nickname;
+};
+
+const ShareNicknameTestParam kShareNicknameTestParam[] = {
+ {"", "", ""},
+ {"", "server nickname", "server nickname"},
+ {"local nickname", "", "local nickname"},
+ {"local nickname", "server nickname", "local nickname"},
+};
+
+class PersonalDataManagerTestForSharingNickname
+ : public PersonalDataManagerTest,
+ public testing::WithParamInterface<ShareNicknameTestParam> {
+ public:
+ PersonalDataManagerTestForSharingNickname()
+ : local_nickname_(base::UTF8ToUTF16(GetParam().local_nickname)),
+ server_nickname_(base::UTF8ToUTF16(GetParam().server_nickname)),
+ expected_nickname_(base::UTF8ToUTF16(GetParam().expected_nickname)) {}
+
+ CreditCard GetLocalCard() {
+ CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
+ test::kEmptyOrigin);
+ test::SetCreditCardInfo(&local_card, "Clyde Barrow",
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
+ local_card.set_use_count(3);
+ local_card.set_use_date(AutofillClock::Now() -
+ base::TimeDelta::FromDays(1));
+ local_card.SetNickname(local_nickname_);
+ return local_card;
+ }
+
+ CreditCard GetServerCard() {
+ CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "c789");
+ test::SetCreditCardInfo(&full_server_card, "Clyde Barrow",
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
+ full_server_card.SetNickname(server_nickname_);
+ return full_server_card;
+ }
+
+ base::string16 local_nickname_;
+ base::string16 server_nickname_;
+ base::string16 expected_nickname_;
+
+ protected:
+ void SetUp() override {
+ PersonalDataManagerTest::SetUp();
+ EnableWalletCardImport();
+ scoped_feature_list_.InitWithFeatures(
+ /*enabled_features=*/{features::
+ kAutofillEnableSurfacingServerCardNickname,
+ features::kAutofillEnableCardNicknameManagement},
+ /*disabled_features=*/{});
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ PersonalDataManagerTestForSharingNickname,
+ testing::ValuesIn(kShareNicknameTestParam));
+
+TEST_P(PersonalDataManagerTestForSharingNickname,
+ VerifySuggestion_DuplicateCards) {
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
+ CreditCard local_card = GetLocalCard();
+ personal_data_->AddCreditCard(local_card);
+
+ SetServerCards({GetServerCard()});
+
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(2U, personal_data_->GetCreditCards().size());
+
+ // Verifies the suggestion shows the right text.
+ std::vector<Suggestion> suggestions =
+ personal_data_->GetCreditCardSuggestions(
+ AutofillType(CREDIT_CARD_NUMBER),
+ /*field_contents=*/base::string16(),
+ /*include_server_cards=*/true);
+ ASSERT_EQ(1U, suggestions.size());
+ EXPECT_EQ(suggestions[0].value,
+ (expected_nickname_.empty() ? base::ASCIIToUTF16("Amex")
+ : expected_nickname_) +
+ base::UTF8ToUTF16(" ") +
+ local_card.ObfuscatedLastFourDigits());
+}
+
+TEST_P(PersonalDataManagerTestForSharingNickname,
+ VerifySuggestion_UnrelatedCards) {
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
+ CreditCard local_card = GetLocalCard();
+ personal_data_->AddCreditCard(local_card);
+
+ std::vector<CreditCard> server_cards;
+ CreditCard server_card = GetServerCard();
+ // Make sure the cards are different by giving a different card number.
+ server_card.SetNumber(base::ASCIIToUTF16("371449635398431"));
+ server_cards.emplace_back(server_card);
+ SetServerCards(server_cards);
+
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(2U, personal_data_->GetCreditCards().size());
+
+ // Verifies the suggestion shows the right text.
+ std::vector<Suggestion> suggestions =
+ personal_data_->GetCreditCardSuggestions(
+ AutofillType(CREDIT_CARD_NUMBER),
+ /*field_contents=*/base::string16(),
+ /*include_server_cards=*/true);
+ ASSERT_EQ(2U, suggestions.size());
+ EXPECT_THAT(
+ std::vector<base::string16>({suggestions[0].value, suggestions[1].value}),
+ testing::UnorderedElementsAre(
+ (server_nickname_.empty() ? base::ASCIIToUTF16("Amex")
+ : server_nickname_) +
+ base::UTF8ToUTF16(" ") + server_card.ObfuscatedLastFourDigits(),
+ (local_nickname_.empty() ? base::ASCIIToUTF16("Amex")
+ : local_nickname_) +
+ base::UTF8ToUTF16(" ") + local_card.ObfuscatedLastFourDigits()));
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index a36839bde15..3eb58500da2 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -117,6 +117,20 @@ message AutofillRandomizedValue {
optional bytes encoded_bits = 2;
}
+// Describes how the button is implemented in HTML source. Corresponds to
+// the mojo ButtonTitleType enum defined in
+// components/autofill/core/common/mojom/autofill_types.mojom.h
+enum ButtonTitleType {
+ NONE = 0;
+ BUTTON_ELEMENT_SUBMIT_TYPE = 1; // <button type='submit'>
+ BUTTON_ELEMENT_BUTTON_TYPE = 2; // <button type='button'>
+ INPUT_ELEMENT_SUBMIT_TYPE = 3; // <input type='submit'>
+ INPUT_ELEMENT_BUTTON_TYPE = 4; // <input type='button'>
+ HYPERLINK = 5; // e.g. <a class='button'>
+ DIV = 6; // e.g. <div id='submit'>
+ SPAN = 7; // e.g. <span name='btn'>
+}
+
// The collection of autofill field metadata to be sent using randomization.
message AutofillRandomizedFormMetadata {
// Form element id. Example: <form id="XXXXXXXX">
@@ -130,6 +144,21 @@ message AutofillRandomizedFormMetadata {
// Location of form as URL.
optional AutofillRandomizedValue url = 4;
+
+ // Information about a button's title (sync with another ButtonTitle in this
+ // proto).
+ message ButtonTitle {
+ // Text showed on the button.
+ optional AutofillRandomizedValue title = 1;
+
+ // Describes how the button is implemented in HTML source.
+ optional ButtonTitleType type = 2;
+ }
+ // Titles of form's buttons. Example: <input type="submit" value="XXXXX">
+ repeated ButtonTitle button_title = 5;
+
+ // Hash of the clear form URL, not randomized.
+ optional fixed32 checksum_for_url = 6;
}
// The collection of autofill field metadata to be sent using randomization.
@@ -386,24 +415,13 @@ message AutofillUploadContents {
// Form-level metadata observed by the client, randomized.
optional AutofillRandomizedFormMetadata randomized_form_metadata = 32;
- // Information about a button's title.
+ // Information about a button's title (sync with another ButtonTitle in this
+ // proto).
message ButtonTitle {
// Text showed on the button.
optional string title = 1;
- // Describes how the button is implemented in HTML source. Corresponds to
- // the mojo ButtonTitleType enum defined in
- // components/autofill/core/common/mojom/autofill_types.mojom.h
- enum ButtonTitleType {
- NONE = 0;
- BUTTON_ELEMENT_SUBMIT_TYPE = 1; // <button type='submit'>
- BUTTON_ELEMENT_BUTTON_TYPE = 2; // <button type='button'>
- INPUT_ELEMENT_SUBMIT_TYPE = 3; // <input type='submit'>
- INPUT_ELEMENT_BUTTON_TYPE = 4; // <input type='button'>
- HYPERLINK = 5; // e.g. <a class='button'>
- DIV = 6; // e.g. <div id='submit'>
- SPAN = 7; // e.g. <span name='btn'>
- }
+ // Describes how the button is implemented in HTML source.
optional ButtonTitleType type = 2;
}
// Titles of form's buttons.
diff --git a/chromium/components/autofill/core/browser/randomized_encoder.cc b/chromium/components/autofill/core/browser/randomized_encoder.cc
index 116e169b127..4a3a467f87d 100644
--- a/chromium/components/autofill/core/browser/randomized_encoder.cc
+++ b/chromium/components/autofill/core/browser/randomized_encoder.cc
@@ -204,6 +204,7 @@ const char RandomizedEncoder::FORM_NAME[] = "form-name";
const char RandomizedEncoder::FORM_ACTION[] = "form-action";
const char RandomizedEncoder::FORM_URL[] = "form-url";
const char RandomizedEncoder::FORM_CSS_CLASS[] = "form-css-class";
+const char RandomizedEncoder::FORM_BUTTON_TITLES[] = "button-titles";
const char RandomizedEncoder::FIELD_ID[] = "field-id";
const char RandomizedEncoder::FIELD_NAME[] = "field-name";
diff --git a/chromium/components/autofill/core/browser/randomized_encoder.h b/chromium/components/autofill/core/browser/randomized_encoder.h
index 70d7b429be6..aefd5e66630 100644
--- a/chromium/components/autofill/core/browser/randomized_encoder.h
+++ b/chromium/components/autofill/core/browser/randomized_encoder.h
@@ -33,6 +33,7 @@ class RandomizedEncoder {
static const char FORM_ACTION[];
static const char FORM_URL[];
static const char FORM_CSS_CLASS[];
+ static const char FORM_BUTTON_TITLES[];
// Field-level data-type identifiers.
static const char FIELD_ID[];
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 550946efd03..b40c031464b 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -204,11 +204,7 @@ bool TestAutofillClient::HasCreditCardScanFeature() {
void TestAutofillClient::ScanCreditCard(CreditCardScanCallback callback) {}
void TestAutofillClient::ShowAutofillPopup(
- const gfx::RectF& element_bounds,
- base::i18n::TextDirection text_direction,
- const std::vector<Suggestion>& suggestions,
- bool autoselect_first_suggestion,
- PopupType popup_type,
+ const AutofillClient::PopupOpenArgs& open_args,
base::WeakPtr<AutofillPopupDelegate> delegate) {}
void TestAutofillClient::UpdateAutofillPopupDataListValues(
@@ -221,6 +217,10 @@ base::span<const Suggestion> TestAutofillClient::GetPopupSuggestions() const {
void TestAutofillClient::PinPopupView() {}
+AutofillClient::PopupOpenArgs TestAutofillClient::GetReopenPopupArgs() const {
+ return {};
+}
+
void TestAutofillClient::UpdatePopup(const std::vector<Suggestion>& suggestions,
PopupType popup_type) {}
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index 608f1f4ca5d..11abe949a24 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -116,17 +116,14 @@ class TestAutofillClient : public AutofillClient {
bool HasCreditCardScanFeature() override;
void ScanCreditCard(CreditCardScanCallback callback) override;
void ShowAutofillPopup(
- const gfx::RectF& element_bounds,
- base::i18n::TextDirection text_direction,
- const std::vector<Suggestion>& suggestions,
- bool autoselect_first_suggestion,
- PopupType popup_type,
+ const AutofillClient::PopupOpenArgs& open_args,
base::WeakPtr<AutofillPopupDelegate> delegate) override;
void UpdateAutofillPopupDataListValues(
const std::vector<base::string16>& values,
const std::vector<base::string16>& labels) override;
base::span<const Suggestion> GetPopupSuggestions() const override;
void PinPopupView() override;
+ AutofillClient::PopupOpenArgs GetReopenPopupArgs() const override;
void UpdatePopup(const std::vector<Suggestion>& suggestions,
PopupType popup_type) override;
void HideAutofillPopup(PopupHidingReason reason) override;
diff --git a/chromium/components/autofill/core/browser/test_autofill_download_manager.cc b/chromium/components/autofill/core/browser/test_autofill_download_manager.cc
index ea4795edfb5..31261f58e9a 100644
--- a/chromium/components/autofill/core/browser/test_autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_download_manager.cc
@@ -26,7 +26,8 @@ void TestAutofillDownloadManager::VerifyLastQueriedForms(
const std::vector<FormData>& expected_forms) {
ASSERT_EQ(expected_forms.size(), last_queried_forms_.size());
for (size_t i = 0; i < expected_forms.size(); ++i) {
- EXPECT_EQ(*last_queried_forms_[i], expected_forms[i]);
+ EXPECT_EQ(last_queried_forms_[i]->unique_renderer_id(),
+ expected_forms[i].unique_renderer_id);
}
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.cc b/chromium/components/autofill/core/browser/test_autofill_manager.cc
index 6d402345ade..ca610fc8d93 100644
--- a/chromium/components/autofill/core/browser/test_autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_manager.cc
@@ -109,6 +109,7 @@ void TestAutofillManager::AddSeenForm(
std::unique_ptr<TestFormStructure> form_structure =
std::make_unique<TestFormStructure>(empty_form);
form_structure->SetFieldTypes(heuristic_types, server_types);
+ form_structure->identify_sections_for_testing();
AddSeenFormStructure(std::move(form_structure));
form_interactions_ukm_logger()->OnFormsParsed(client()->GetUkmSourceId());
@@ -116,8 +117,8 @@ void TestAutofillManager::AddSeenForm(
void TestAutofillManager::AddSeenFormStructure(
std::unique_ptr<FormStructure> form_structure) {
- const auto signature = form_structure->form_signature();
- (*mutable_form_structures())[signature] = std::move(form_structure);
+ const auto renderer_id = form_structure->unique_renderer_id();
+ (*mutable_form_structures())[renderer_id] = std::move(form_structure);
}
void TestAutofillManager::ClearFormStructures() {
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.cc b/chromium/components/autofill/core/browser/test_autofill_provider.cc
index ef5137b008c..2102a1974f9 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.cc
@@ -50,6 +50,8 @@ void TestAutofillProvider::OnFormsSeen(AutofillHandlerProxy* handler,
const std::vector<FormData>& forms,
const base::TimeTicks timestamp) {}
+void TestAutofillProvider::OnHidePopup(AutofillHandlerProxy* handler) {}
+
void TestAutofillProvider::Reset(AutofillHandlerProxy* handler) {}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.h b/chromium/components/autofill/core/browser/test_autofill_provider.h
index a7fc221cf57..7a21e59c6bb 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.h
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.h
@@ -48,6 +48,7 @@ class TestAutofillProvider : public AutofillProvider {
void OnFormsSeen(AutofillHandlerProxy* handler,
const std::vector<FormData>& forms,
const base::TimeTicks timestamp) override;
+ void OnHidePopup(AutofillHandlerProxy* handler) override;
void Reset(AutofillHandlerProxy* handler) override;
};
diff --git a/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc b/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc
index fd1a0d98e22..1728083a998 100644
--- a/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc
+++ b/chromium/components/autofill/core/browser/ui/accessory_sheet_data.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/ui/accessory_sheet_data.h"
+#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/ui/accessory_sheet_enums.h"
diff --git a/chromium/components/autofill/core/browser/ui/accessory_sheet_enums.h b/chromium/components/autofill/core/browser/ui/accessory_sheet_enums.h
index e2086f5c1bd..97a2cbf5eb4 100644
--- a/chromium/components/autofill/core/browser/ui/accessory_sheet_enums.h
+++ b/chromium/components/autofill/core/browser/ui/accessory_sheet_enums.h
@@ -40,6 +40,16 @@ enum class AccessoryAction {
COUNT,
};
+// Used to record metrics for accessory toggles. Entries should not be
+// renumbered and numeric values should never be reused. Must be kept in sync
+// with the enum in enums.xml. A java IntDef@ is generated from this.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.keyboard_accessory
+enum class AccessoryToggleType {
+ SAVE_PASSWORDS_TOGGLE_ON = 0,
+ SAVE_PASSWORDS_TOGGLE_OFF = 1,
+ COUNT,
+};
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_ACCESSORY_SHEET_ENUMS_H_
diff --git a/chromium/components/autofill/core/browser/ui/address_combobox_model.cc b/chromium/components/autofill/core/browser/ui/address_combobox_model.cc
index eecc105f85b..89c03f9c433 100644
--- a/chromium/components/autofill/core/browser/ui/address_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/address_combobox_model.cc
@@ -46,7 +46,7 @@ int AddressComboboxModel::GetItemCount() const {
return addresses_.size() + kNbHeaderEntries;
}
-base::string16 AddressComboboxModel::GetItemAt(int index) {
+base::string16 AddressComboboxModel::GetItemAt(int index) const {
DCHECK_GE(index, 0);
// A special entry is always added at index 0 and a separator at index 1.
DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries);
@@ -66,7 +66,7 @@ base::string16 AddressComboboxModel::GetItemAt(int index) {
return addresses_[index - kNbHeaderEntries].second;
}
-bool AddressComboboxModel::IsItemSeparatorAt(int index) {
+bool AddressComboboxModel::IsItemSeparatorAt(int index) const {
// The only separator is between the "Select" entry at 0 and the first address
// at index 2. So there must be at least one address for a separator to be
// shown.
diff --git a/chromium/components/autofill/core/browser/ui/address_combobox_model.h b/chromium/components/autofill/core/browser/ui/address_combobox_model.h
index dda2c0fcd41..deb54889c04 100644
--- a/chromium/components/autofill/core/browser/ui/address_combobox_model.h
+++ b/chromium/components/autofill/core/browser/ui/address_combobox_model.h
@@ -35,8 +35,8 @@ class AddressComboboxModel : public ui::ComboboxModel {
// ui::ComboboxModel implementation:
int GetItemCount() const override;
- base::string16 GetItemAt(int index) override;
- bool IsItemSeparatorAt(int index) override;
+ base::string16 GetItemAt(int index) const override;
+ bool IsItemSeparatorAt(int index) const override;
int GetDefaultIndex() const override;
void AddObserver(ui::ComboboxModelObserver* observer) override;
void RemoveObserver(ui::ComboboxModelObserver* observer) override;
diff --git a/chromium/components/autofill/core/browser/ui/country_combobox_model.cc b/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
index b15cc2bacec..11bc1b1b670 100644
--- a/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
@@ -79,7 +79,7 @@ int CountryComboboxModel::GetItemCount() const {
return countries_.size();
}
-base::string16 CountryComboboxModel::GetItemAt(int index) {
+base::string16 CountryComboboxModel::GetItemAt(int index) const {
AutofillCountry* country = countries_[index].get();
if (country)
return countries_[index]->name();
@@ -89,7 +89,7 @@ base::string16 CountryComboboxModel::GetItemAt(int index) {
return base::ASCIIToUTF16("---");
}
-bool CountryComboboxModel::IsItemSeparatorAt(int index) {
+bool CountryComboboxModel::IsItemSeparatorAt(int index) const {
return !countries_[index];
}
diff --git a/chromium/components/autofill/core/browser/ui/country_combobox_model.h b/chromium/components/autofill/core/browser/ui/country_combobox_model.h
index fb00d162795..712cab208f5 100644
--- a/chromium/components/autofill/core/browser/ui/country_combobox_model.h
+++ b/chromium/components/autofill/core/browser/ui/country_combobox_model.h
@@ -36,8 +36,8 @@ class CountryComboboxModel : public ui::ComboboxModel {
// ui::ComboboxModel implementation:
int GetItemCount() const override;
- base::string16 GetItemAt(int index) override;
- bool IsItemSeparatorAt(int index) override;
+ base::string16 GetItemAt(int index) const override;
+ bool IsItemSeparatorAt(int index) const override;
// The list of countries always has the default country at the top as well as
// within the sorted vector.
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl.cc
index a5a81c68130..84de5925de8 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl.cc
@@ -41,7 +41,7 @@ void CardExpirationDateFixFlowControllerImpl::Show(
DCHECK(!callback.is_null());
DCHECK(card_expiration_date_fix_flow_view);
- card_label_ = card.NetworkAndLastFourDigits();
+ card_label_ = card.CardIdentifierStringForAutofillDisplay();
if (card_expiration_date_fix_flow_view_)
card_expiration_date_fix_flow_view_->ControllerGone();
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 b3834c9347d..b4fdd61137e 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,10 +11,12 @@
#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"
#include "components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
@@ -29,9 +31,9 @@ class CardExpirationDateFixFlowControllerImplGenericTest {
public:
CardExpirationDateFixFlowControllerImplGenericTest() {}
- void ShowPrompt() {
+ void ShowPrompt(CreditCard credit_card = CreditCard()) {
controller_->Show(
- test_card_expiration_date_fix_flow_view_.get(), autofill::CreditCard(),
+ test_card_expiration_date_fix_flow_view_.get(), credit_card,
base::BindOnce(
&CardExpirationDateFixFlowControllerImplGenericTest::OnAccepted,
weak_ptr_factory_.GetWeakPtr()));
@@ -106,4 +108,41 @@ TEST_F(CardExpirationDateFixFlowControllerImplTest, LogDismissed) {
1);
}
+// Tests to ensure the card nickname is shown correctly in the expiration fix
+// flow prompt. The param indicates whether the nickname experiment is enabled.
+class CardExpirationDateFixFlowControllerImplTestForNickname
+ : public CardExpirationDateFixFlowControllerImplTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ CardExpirationDateFixFlowControllerImpl* GetController() {
+ return controller_.get();
+ }
+
+ protected:
+ CardExpirationDateFixFlowControllerImplTestForNickname() {
+ scoped_feature_list_.InitWithFeatureState(
+ features::kAutofillEnableSurfacingServerCardNickname, GetParam());
+ }
+
+ ~CardExpirationDateFixFlowControllerImplTestForNickname() override = default;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ CardExpirationDateFixFlowControllerImplTestForNickname,
+ testing::Bool());
+
+TEST_P(CardExpirationDateFixFlowControllerImplTestForNickname,
+ CardIdentifierString) {
+ CreditCard card = test::GetCreditCard();
+ card.SetNickname(base::ASCIIToUTF16("nickname"));
+ ShowPrompt(card);
+
+ EXPECT_EQ(GetController()->GetCardLabel(),
+ GetParam() ? card.NicknameAndLastFourDigitsForTesting()
+ : card.NetworkAndLastFourDigits());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
index d2a1cb31699..d980b3621e8 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
@@ -32,7 +32,6 @@ class CardUnmaskPromptController {
virtual base::string16 GetOkButtonLabel() const = 0;
virtual int GetCvcImageRid() const = 0;
virtual bool ShouldRequestExpirationDate() const = 0;
- virtual bool CanStoreLocally() const = 0;
virtual bool GetStoreLocallyStartState() const = 0;
#if defined(OS_ANDROID)
virtual bool ShouldOfferWebauthn() const = 0;
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
index d3ac2eae1f9..f693be09c4f 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
@@ -27,9 +27,8 @@
namespace autofill {
CardUnmaskPromptControllerImpl::CardUnmaskPromptControllerImpl(
- PrefService* pref_service,
- bool is_off_the_record)
- : pref_service_(pref_service), is_off_the_record_(is_off_the_record) {}
+ PrefService* pref_service)
+ : pref_service_(pref_service) {}
CardUnmaskPromptControllerImpl::~CardUnmaskPromptControllerImpl() {
if (card_unmask_view_)
@@ -125,23 +124,15 @@ void CardUnmaskPromptControllerImpl::OnUnmaskPromptAccepted(
pending_details_.exp_month = exp_month;
pending_details_.exp_year = exp_year;
}
- if (CanStoreLocally()) {
- pending_details_.should_store_pan = should_store_pan;
- // Remember the last choice the user made (on this device).
- pref_service_->SetBoolean(prefs::kAutofillWalletImportStorageCheckboxState,
- should_store_pan);
- } else {
- DCHECK(!should_store_pan);
- pending_details_.should_store_pan = false;
- }
+ DCHECK(!should_store_pan);
+ pending_details_.should_store_pan = false;
- // On Android, the FIDO authentication checkbox is only shown when the local
- // storage checkbox is not shown and the flag is turned on. If it is shown,
- // then remember the last choice the user made on this device.
+ // On Android, the FIDO authentication checkbox is only shown when the flag is
+ // turned on. If it is shown, then remember the last choice the user made on
+ // this device.
#if defined(OS_ANDROID)
if (base::FeatureList::IsEnabled(
- features::kAutofillCreditCardAuthentication) &&
- !CanStoreLocally()) {
+ features::kAutofillCreditCardAuthentication)) {
pending_details_.enable_fido_auth = enable_fido_auth;
pref_service_->SetBoolean(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, enable_fido_auth);
@@ -212,22 +203,6 @@ bool CardUnmaskPromptControllerImpl::ShouldRequestExpirationDate() const {
new_card_link_clicked_;
}
-bool CardUnmaskPromptControllerImpl::CanStoreLocally() const {
- if (base::FeatureList::IsEnabled(
- features::kAutofillNoLocalSaveOnUnmaskSuccess)) {
- return false;
- }
- // Never offer to save for incognito.
- if (is_off_the_record_)
- return false;
- if (reason_ == AutofillClient::UNMASK_FOR_PAYMENT_REQUEST)
- return false;
- if (card_.record_type() == CreditCard::LOCAL_CARD)
- return false;
-
- return OfferStoreUnmaskedCards(is_off_the_record_);
-}
-
bool CardUnmaskPromptControllerImpl::GetStoreLocallyStartState() const {
return pref_service_->GetBoolean(
prefs::kAutofillWalletImportStorageCheckboxState);
@@ -326,22 +301,6 @@ void CardUnmaskPromptControllerImpl::LogOnCloseEvents() {
AutofillMetrics::UNMASK_PROMPT_SAVED_CARD_LOCALLY,
card_.HasValidNickname());
}
-
- if (CanStoreLocally()) {
- // Tracking changes in local save preference.
- AutofillMetrics::UnmaskPromptEvent event;
- if (unmasking_initial_should_store_pan_ && final_should_store_pan) {
- event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_OUT;
- } else if (!unmasking_initial_should_store_pan_ &&
- !final_should_store_pan) {
- event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_IN;
- } else if (unmasking_initial_should_store_pan_ && !final_should_store_pan) {
- event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_OUT;
- } else {
- event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_IN;
- }
- AutofillMetrics::LogUnmaskPromptEvent(event, card_.HasValidNickname());
- }
}
AutofillMetrics::UnmaskPromptEvent
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
index 67e6622b06f..d5c31d30500 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
@@ -22,8 +22,7 @@ class CardUnmaskPromptView;
class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
public:
- CardUnmaskPromptControllerImpl(PrefService* pref_service,
- bool is_off_the_record);
+ explicit CardUnmaskPromptControllerImpl(PrefService* pref_service);
virtual ~CardUnmaskPromptControllerImpl();
// This should be OnceCallback<unique_ptr<CardUnmaskPromptView>> but there are
@@ -54,7 +53,6 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
base::string16 GetOkButtonLabel() const override;
int GetCvcImageRid() const override;
bool ShouldRequestExpirationDate() const override;
- bool CanStoreLocally() const override;
bool GetStoreLocallyStartState() const override;
#if defined(OS_ANDROID)
bool ShouldOfferWebauthn() const override;
@@ -78,7 +76,6 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
PrefService* pref_service_;
bool new_card_link_clicked_ = false;
- bool is_off_the_record_;
CreditCard card_;
AutofillClient::UnmaskCardReason reason_;
base::WeakPtr<CardUnmaskDelegate> delegate_;
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
index fba820d9cc9..27ee2995f52 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
@@ -69,15 +69,11 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
public:
explicit TestCardUnmaskPromptController(
TestingPrefServiceSimple* pref_service)
- : CardUnmaskPromptControllerImpl(pref_service, false),
- can_store_locally_(!base::FeatureList::IsEnabled(
- features::kAutofillNoLocalSaveOnUnmaskSuccess)) {}
+ : CardUnmaskPromptControllerImpl(pref_service) {}
- bool CanStoreLocally() const override { return can_store_locally_; }
#if defined(OS_ANDROID)
bool ShouldOfferWebauthn() const override { return should_offer_webauthn_; }
#endif
- void set_can_store_locally(bool can) { can_store_locally_ = can; }
void set_should_offer_webauthn(bool should) {
should_offer_webauthn_ = should;
}
@@ -87,7 +83,6 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
}
private:
- bool can_store_locally_;
bool should_offer_webauthn_;
base::WeakPtrFactory<TestCardUnmaskPromptController> weak_factory_{this};
@@ -173,7 +168,6 @@ TEST_F(CardUnmaskPromptControllerImplTest,
FidoAuthOfferCheckboxStatePersistent) {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillCreditCardAuthentication);
- controller_->set_can_store_locally(false);
ShowPromptAndSimulateResponse(/*should_store_pan=*/false,
/*enable_fido_auth=*/true);
EXPECT_TRUE(pref_service_->GetBoolean(
@@ -189,7 +183,6 @@ TEST_F(CardUnmaskPromptControllerImplTest,
PopulateCheckboxToUserProvidedUnmaskDetails) {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillCreditCardAuthentication);
- controller_->set_can_store_locally(false);
ShowPromptAndSimulateResponse(/*should_store_pan=*/false,
/*enable_fido_auth=*/true);
@@ -486,7 +479,6 @@ TEST_P(LoggingValidationTestForNickname, LogUnmaskedCardAfterFailure) {
}
TEST_P(LoggingValidationTestForNickname, DontLogForHiddenCheckbox) {
- controller_->set_can_store_locally(false);
ShowPromptAndSimulateResponse(/*should_store_pan=*/false,
/*enable_fido_auth=*/false);
base::HistogramTester histogram_tester;
diff --git a/chromium/components/autofill/core/browser/ui/popup_types.h b/chromium/components/autofill/core/browser/ui/popup_types.h
index 1656116a9b2..21918b9bc20 100644
--- a/chromium/components/autofill/core/browser/ui/popup_types.h
+++ b/chromium/components/autofill/core/browser/ui/popup_types.h
@@ -34,6 +34,9 @@ enum class PopupHidingReason {
kUserAborted, // The user explicitly dismissed the popup (e.g. ESC key).
kViewDestroyed, // The popup view (or its controller) goes out of scope.
kWidgetChanged, // The platform-native UI changed (e.g. window resize).
+ kInsufficientSpace, // Not enough space in content area to display an display
+ // at least one row of the popup within the bounds of the
+ // content area.
};
} // namespace autofill
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 3d912a483ff..0b5f7978e40 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
@@ -46,9 +46,9 @@ int RegionComboboxModel::GetItemCount() const {
return regions_.size();
}
-base::string16 RegionComboboxModel::GetItemAt(int index) {
+base::string16 RegionComboboxModel::GetItemAt(int index) const {
DCHECK_GE(index, 0);
- // This might happen because of the asynchonous nature of the data.
+ // This might happen because of the asynchronous nature of the data.
if (static_cast<size_t>(index) >= regions_.size())
return l10n_util::GetStringUTF16(IDS_AUTOFILL_LOADING_REGIONS);
@@ -60,8 +60,8 @@ base::string16 RegionComboboxModel::GetItemAt(int index) {
return base::ASCIIToUTF16("---");
}
-bool RegionComboboxModel::IsItemSeparatorAt(int index) {
- // This might happen because of the asynchonous nature of the data.
+bool RegionComboboxModel::IsItemSeparatorAt(int index) const {
+ // This might happen because of the asynchronous nature of the data.
DCHECK_GE(index, 0);
if (static_cast<size_t>(index) >= regions_.size())
return false;
diff --git a/chromium/components/autofill/core/browser/ui/region_combobox_model.h b/chromium/components/autofill/core/browser/ui/region_combobox_model.h
index 7e1018fe7d0..52d6a50df82 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model.h
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model.h
@@ -49,8 +49,8 @@ class RegionComboboxModel : public ui::ComboboxModel {
// ui::ComboboxModel implementation:
int GetItemCount() const override;
- base::string16 GetItemAt(int index) override;
- bool IsItemSeparatorAt(int index) override;
+ base::string16 GetItemAt(int index) const override;
+ bool IsItemSeparatorAt(int index) const override;
void AddObserver(ui::ComboboxModelObserver* observer) override;
void RemoveObserver(ui::ComboboxModelObserver* observer) override;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_change.h b/chromium/components/autofill/core/browser/webdata/autofill_change.h
index 605ff81bf0c..670858ac8d5 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_change.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_change.h
@@ -8,7 +8,7 @@
#include <string>
#include <vector>
-#include "base/logging.h"
+#include "base/check.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index ca4e266d38c..d2db94bca69 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -148,6 +148,7 @@ void BindCreditCardToStatement(const CreditCard& credit_card,
s->BindInt64(index++, modification_date.ToTimeT());
s->BindString(index++, credit_card.origin());
s->BindString(index++, credit_card.billing_address_id());
+ s->BindString16(index++, credit_card.nickname());
}
base::string16 UnencryptedCardFromColumn(
@@ -187,8 +188,7 @@ std::unique_ptr<CreditCard> CreditCardFromStatement(
base::Time::FromTimeT(s.ColumnInt64(index++)));
credit_card->set_origin(s.ColumnString(index++));
credit_card->set_billing_address_id(s.ColumnString(index++));
- credit_card->set_bank_name(s.ColumnString(index++));
-
+ credit_card->SetNickname(s.ColumnString16(index++));
return credit_card;
}
@@ -499,6 +499,9 @@ bool AutofillTable::MigrateToVersion(int version,
case 86:
*update_compatible_version = false;
return MigrateToVersion86RemoveUnmaskedCreditCardsUseColumns();
+ case 87:
+ *update_compatible_version = false;
+ return MigrateToVersion87AddCreditCardNicknameColumn();
}
return true;
}
@@ -1103,8 +1106,8 @@ bool AutofillTable::AddCreditCard(const CreditCard& credit_card) {
"INSERT INTO credit_cards"
"(guid, name_on_card, expiration_month, expiration_year, "
" card_number_encrypted, use_count, use_date, date_modified, origin,"
- " billing_address_id)"
- "VALUES (?,?,?,?,?,?,?,?,?,?)"));
+ " billing_address_id, nickname)"
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?)"));
BindCreditCardToStatement(credit_card, AutofillClock::Now(), &s,
*autofill_table_encryptor_);
@@ -1129,7 +1132,7 @@ bool AutofillTable::UpdateCreditCard(const CreditCard& credit_card) {
"UPDATE credit_cards "
"SET guid=?, name_on_card=?, expiration_month=?,"
"expiration_year=?, card_number_encrypted=?, use_count=?, use_date=?,"
- "date_modified=?, origin=?, billing_address_id=?"
+ "date_modified=?, origin=?, billing_address_id=?, nickname=?"
"WHERE guid=?1"));
BindCreditCardToStatement(credit_card,
update_modification_date
@@ -1184,7 +1187,7 @@ std::unique_ptr<CreditCard> AutofillTable::GetCreditCard(
sql::Statement s(db_->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
"card_number_encrypted, use_count, use_date, date_modified, "
- "origin, billing_address_id "
+ "origin, billing_address_id, nickname "
"FROM credit_cards "
"WHERE guid = ?"));
s.BindString(0, guid);
@@ -2825,6 +2828,12 @@ bool AutofillTable::MigrateToVersion86RemoveUnmaskedCreditCardsUseColumns() {
transaction.Commit();
}
+bool AutofillTable::MigrateToVersion87AddCreditCardNicknameColumn() {
+ // Add the nickname column to the credit_card table.
+ return db_->DoesColumnExist("credit_cards", "nickname") ||
+ db_->Execute("ALTER TABLE credit_cards ADD COLUMN nickname VARCHAR");
+}
+
bool AutofillTable::AddFormFieldValuesTime(
const std::vector<FormFieldData>& elements,
std::vector<AutofillChange>* changes,
@@ -3085,7 +3094,8 @@ bool AutofillTable::InitCreditCardsTable() {
"origin VARCHAR DEFAULT '', "
"use_count INTEGER NOT NULL DEFAULT 0, "
"use_date INTEGER NOT NULL DEFAULT 0, "
- "billing_address_id VARCHAR) ")) {
+ "billing_address_id VARCHAR, "
+ "nickname VARCHAR)")) {
NOTREACHED();
return false;
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index 2e61fdeed6e..a283890f43f 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -154,6 +154,8 @@ struct PaymentsCustomerData;
// is the billing address for this card. Can be null in the
// database, but always returned as an empty string in
// CreditCard. Added in version 66.
+// nickname A nickname for the card, entered by the user. Added in
+// version 87.
//
// masked_credit_cards
// This table contains "masked" credit card information
@@ -556,6 +558,7 @@ class AutofillTable : public WebDatabaseTable,
bool MigrateToVersion84AddNicknameColumn();
bool MigrateToVersion85AddCardIssuerColumnToMaskedCreditCard();
bool MigrateToVersion86RemoveUnmaskedCreditCardsUseColumns();
+ bool MigrateToVersion87AddCreditCardNicknameColumn();
// Max data length saved in the table, AKA the maximum length allowed for
// form data.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index 84c2a30305e..5572c259b0d 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -986,6 +986,7 @@ TEST_F(AutofillTableTest, CreditCard) {
work_creditcard.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
work_creditcard.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
ASCIIToUTF16("2013"));
+ work_creditcard.SetNickname(ASCIIToUTF16("Corporate card"));
Time pre_creation_time = AutofillClock::Now();
EXPECT_TRUE(table_->AddCreditCard(work_creditcard));
@@ -998,7 +999,7 @@ TEST_F(AutofillTableTest, CreditCard) {
EXPECT_EQ(work_creditcard, *db_creditcard);
sql::Statement s_work(db_->GetSQLConnection()->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
+ "card_number_encrypted, date_modified, nickname "
"FROM credit_cards WHERE guid=?"));
s_work.BindString(0, work_creditcard.guid());
ASSERT_TRUE(s_work.is_valid());
@@ -1017,6 +1018,7 @@ TEST_F(AutofillTableTest, CreditCard) {
target_creditcard.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("06"));
target_creditcard.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
ASCIIToUTF16("2012"));
+ target_creditcard.SetNickname(ASCIIToUTF16("Grocery card"));
pre_creation_time = AutofillClock::Now();
EXPECT_TRUE(table_->AddCreditCard(target_creditcard));
@@ -1026,7 +1028,7 @@ TEST_F(AutofillTableTest, CreditCard) {
EXPECT_EQ(target_creditcard, *db_creditcard);
sql::Statement s_target(db_->GetSQLConnection()->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
+ "card_number_encrypted, date_modified, nickname "
"FROM credit_cards WHERE guid=?"));
s_target.BindString(0, target_creditcard.guid());
ASSERT_TRUE(s_target.is_valid());
@@ -1039,6 +1041,7 @@ TEST_F(AutofillTableTest, CreditCard) {
target_creditcard.set_origin("Interactive Autofill dialog");
target_creditcard.SetRawInfo(CREDIT_CARD_NAME_FULL,
ASCIIToUTF16("Charles Grady"));
+ target_creditcard.SetNickname(ASCIIToUTF16("Supermarket"));
Time pre_modification_time = AutofillClock::Now();
EXPECT_TRUE(table_->UpdateCreditCard(target_creditcard));
Time post_modification_time = AutofillClock::Now();
@@ -1047,7 +1050,7 @@ TEST_F(AutofillTableTest, CreditCard) {
EXPECT_EQ(target_creditcard, *db_creditcard);
sql::Statement s_target_updated(db_->GetSQLConnection()->GetUniqueStatement(
"SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
+ "card_number_encrypted, date_modified, nickname "
"FROM credit_cards WHERE guid=?"));
s_target_updated.BindString(0, target_creditcard.guid());
ASSERT_TRUE(s_target_updated.is_valid());
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 56e5daeb9f7..e43c36f6c40 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
@@ -664,7 +664,10 @@ AutofillWalletMetadataSyncBridge::MergeRemoteChanges(
if (is_any_local_modified) {
web_data_backend_->NotifyOfMultipleAutofillChanges();
}
- return base::nullopt;
+
+ return static_cast<syncer::SyncMetadataStoreChangeList*>(
+ metadata_change_list.get())
+ ->TakeError();
}
template <class DataType>
diff --git a/chromium/components/autofill/core/common/autofill_data_validation.cc b/chromium/components/autofill/core/common/autofill_data_validation.cc
index 92254628e63..67010537037 100644
--- a/chromium/components/autofill/core/common/autofill_data_validation.cc
+++ b/chromium/components/autofill/core/common/autofill_data_validation.cc
@@ -54,7 +54,7 @@ bool IsValidFormData(const FormData& form) {
}
bool IsValidPasswordFormFillData(const PasswordFormFillData& form) {
- if (!IsValidString16(form.name) || !IsValidGURL(form.origin) ||
+ if (!IsValidString16(form.name) || !IsValidGURL(form.url) ||
!IsValidGURL(form.action) || !IsValidFormFieldData(form.username_field) ||
!IsValidFormFieldData(form.password_field) ||
!IsValidString(form.preferred_realm)) {
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index 3856188c371..bfa1eec50ee 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -54,7 +54,7 @@ const base::Feature kAutofillCreditCardAssist{
// Controls whether we download server credit cards to the ephemeral
// account-based storage when sync the transport is enabled.
-const base::Feature kAutofillEnableAccountWalletStorage{
+const base::Feature kAutofillEnableAccountWalletStorage {
"AutofillEnableAccountWalletStorage",
#if defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_IOS)
// Wallet transport is only currently available on Win/Mac/Linux.
@@ -65,6 +65,12 @@ const base::Feature kAutofillEnableAccountWalletStorage{
#endif
};
+// Controls whether to detect and fill the augmented phone country code field
+// when enabled.
+const base::Feature kAutofillEnableAugmentedPhoneCountryCode{
+ "AutofillEnableAugmentedPhoneCountryCode",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether we use COMPANY as part of Autofill
const base::Feature kAutofillEnableCompanyName{
"AutofillEnableCompanyName", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -91,6 +97,13 @@ const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{
"AutofillEnforceMinRequiredFieldsForUpload",
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
+// instead of only the focused one shall be extracted and sent to Android
+// autofill service when the autofill session created.
+const base::Feature kAutofillExtractAllDatalists{
+ "AutofillExtractAllDatalists", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Autofill uses the local heuristic such that address forms are only filled if
// at least 3 fields are fillable according to local heuristics. Unfortunately,
// the criterion for fillability is only that the field type is unknown. So many
@@ -99,6 +112,24 @@ const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{
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 suggestions are displayed in the keyboard accessory
// instead of the regular popup.
const base::Feature kAutofillKeyboardAccessory{
@@ -124,6 +155,15 @@ const base::Feature kAutofillPreferServerNamePredictions{
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{
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index 30cf3076fc1..b0cf11a8ae2 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -29,12 +29,17 @@ extern const base::Feature kAutofillCacheQueryResponses;
extern const base::Feature kAutofillCreateDataForTest;
extern const base::Feature kAutofillCreditCardAssist;
extern const base::Feature kAutofillEnableAccountWalletStorage;
+extern const base::Feature kAutofillEnableAugmentedPhoneCountryCode;
extern const base::Feature kAutofillEnableCompanyName;
extern const base::Feature kAutofillEnableHideSuggestionsUI;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
+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 kAutofillKeyboardAccessory;
extern const base::Feature kAutofillPruneSuggestions;
extern const base::Feature kAutofillMetadataUploads;
@@ -42,6 +47,8 @@ extern const base::Feature kAutofillOffNoServerData;
extern const base::Feature kAutofillOverrideWithRaterConsensus;
extern const base::Feature kAutofillPreferServerNamePredictions;
extern const base::Feature kAutofillProfileClientValidation;
+extern const base::Feature kAutofillProfileImportFromUnfocusableFields;
+extern const base::Feature kAutofillProfileImportFromUnifiedSection;
extern const base::Feature kAutofillProfileServerValidation;
extern const base::Feature kAutofillRejectCompanyBirthyear;
extern const base::Feature kAutofillRejectCompanySocialTitle;
diff --git a/chromium/components/autofill/core/common/autofill_internals/log_message.cc b/chromium/components/autofill/core/common/autofill_internals/log_message.cc
index 60da13de84e..db6483203a5 100644
--- a/chromium/components/autofill/core/common/autofill_internals/log_message.cc
+++ b/chromium/components/autofill/core/common/autofill_internals/log_message.cc
@@ -5,6 +5,7 @@
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "base/logging.h"
+#include "base/notreached.h"
#include "components/autofill/core/common/logging/log_buffer.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc b/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc
index 2e1597b07bf..0c5f9a033b7 100644
--- a/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc
+++ b/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc
@@ -5,6 +5,7 @@
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "base/logging.h"
+#include "base/notreached.h"
#include "components/autofill/core/common/logging/log_buffer.h"
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 24c62fb5a3c..5d728a56936 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.cc
+++ b/chromium/components/autofill/core/common/autofill_payments_features.cc
@@ -39,7 +39,14 @@ const base::Feature kAutofillCreditCardAblationExperiment{
// Enables the use of platform authenticators through WebAuthn to retrieve
// credit cards from Google payments.
const base::Feature kAutofillCreditCardAuthentication{
- "AutofillCreditCardAuthentication", base::FEATURE_DISABLED_BY_DEFAULT};
+ "AutofillCreditCardAuthentication",
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+ // Better Auth project is fully launched on Win/Mac.
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
// When enabled, if credit card upload succeeded, the avatar icon will show a
// highlight otherwise, the credit card icon image will be updated and if user
@@ -48,10 +55,15 @@ const base::Feature kAutofillCreditCardUploadFeedback{
"AutofillCreditCardUploadFeedback", base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, the credit card nicknames will be manageable. They can be
-// uploaded to Payments or be modified locally.
+// modified locally.
const base::Feature kAutofillEnableCardNicknameManagement{
"AutofillEnableCardNicknameManagement", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, the credit card nicknames will be manageable. They can be
+// uploaded to Payments.
+const base::Feature kAutofillEnableCardNicknameUpstream{
+ "AutofillEnableCardNicknameUpstream", base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, autofill payments bubbles' result will be recorded as either
// 'accepted', 'cancelled', 'closed', 'not interacted' or 'lost focus'.
const base::Feature kAutofillEnableFixedPaymentsBubbleLogging{
@@ -62,6 +74,11 @@ const base::Feature kAutofillEnableFixedPaymentsBubbleLogging{
const base::Feature kAutofillEnableGoogleIssuedCard{
"AutofillEnableGoogleIssuedCard", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, offer data will be retrieved during downstream and shown in
+// the dropdown list.
+const base::Feature kAutofillEnableOffersInDownstream{
+ "kAutofillEnableOffersInDownstream", base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, all payments related bubbles will not be dismissed upon page
// navigation.
const base::Feature kAutofillEnableStickyPaymentsBubble{
@@ -83,11 +100,6 @@ const base::Feature kAutofillEnableToolbarStatusChip{
const base::Feature kAutofillEnableVirtualCard{
"AutofillEnableVirtualCard", base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, will remove the option to save unmasked server cards as
-// FULL_SERVER_CARDs upon successful unmask.
-const base::Feature kAutofillNoLocalSaveOnUnmaskSuccess{
- "AutofillNoLocalSaveOnUnmaskSuccess", base::FEATURE_ENABLED_BY_DEFAULT};
-
// When enabled, the Save Card infobar will be dismissed by a user initiated
// navigation other than one caused by submitted form.
const base::Feature kAutofillSaveCardDismissOnNavigation{
@@ -110,9 +122,6 @@ const base::Feature kAutofillUpstream{"AutofillUpstream",
const base::Feature kAutofillUpstreamAllowAllEmailDomains{
"AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillUpstreamEditableExpirationDate{
- "AutofillUpstreamEditableExpirationDate", base::FEATURE_ENABLED_BY_DEFAULT};
-
bool ShouldShowImprovedUserConsentForCreditCardSave() {
#if defined(OS_WIN) || defined(OS_MACOSX) || \
(defined(OS_LINUX) && !defined(OS_CHROMEOS))
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h
index 4e5c628c5c1..e76903e0ca6 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.h
+++ b/chromium/components/autofill/core/common/autofill_payments_features.h
@@ -25,18 +25,18 @@ extern const base::Feature kAutofillCreditCardAblationExperiment;
extern const base::Feature kAutofillCreditCardAuthentication;
extern const base::Feature kAutofillCreditCardUploadFeedback;
extern const base::Feature kAutofillEnableCardNicknameManagement;
+extern const base::Feature kAutofillEnableCardNicknameUpstream;
extern const base::Feature kAutofillEnableFixedPaymentsBubbleLogging;
extern const base::Feature kAutofillEnableGoogleIssuedCard;
+extern const base::Feature kAutofillEnableOffersInDownstream;
extern const base::Feature kAutofillEnableStickyPaymentsBubble;
extern const base::Feature kAutofillEnableSurfacingServerCardNickname;
extern const base::Feature kAutofillEnableToolbarStatusChip;
extern const base::Feature kAutofillEnableVirtualCard;
-extern const base::Feature kAutofillNoLocalSaveOnUnmaskSuccess;
extern const base::Feature kAutofillSaveCardDismissOnNavigation;
extern const base::Feature kAutofillSaveCardInfobarEditSupport;
extern const base::Feature kAutofillUpstream;
extern const base::Feature kAutofillUpstreamAllowAllEmailDomains;
-extern const base::Feature kAutofillUpstreamEditableExpirationDate;
// Return whether a [No thanks] button and new messaging is shown in the save
// card bubbles. This will be called only on desktop platforms.
diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.cc b/chromium/components/autofill/core/common/autofill_regex_constants.cc
index 697333ffb6c..f1334a24043 100644
--- a/chromium/components/autofill/core/common/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/common/autofill_regex_constants.cc
@@ -259,6 +259,7 @@ const char kGiftCardRe[] = "gift.?(card|cert)";
const char kDebitGiftCardRe[] =
"(?:visa|mastercard|discover|amex|american express).*gift.?card";
const char kDebitCardRe[] = "debit.*card";
+const char kDayRe[] = "day";
/////////////////////////////////////////////////////////////////////////////
// email_field.cc
@@ -350,6 +351,8 @@ const char kPhoneRe[] =
"|电话" // zh-CN
"|മൊബൈല്‍" // ml for mobile
"|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?"; // ko-KR
+const char kAugmentedPhoneCountryCodeRe[] =
+ "^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$";
const char kCountryCodeRe[] =
"country.*code|ccode|_cc|phone.*code|user.*phone.*code";
const char kAreaCodeNotextRe[] = "^\\($";
diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.h b/chromium/components/autofill/core/common/autofill_regex_constants.h
index 5cd1e1d80f8..af69056041b 100644
--- a/chromium/components/autofill/core/common/autofill_regex_constants.h
+++ b/chromium/components/autofill/core/common/autofill_regex_constants.h
@@ -37,6 +37,7 @@ extern const char kCardIgnoredRe[];
extern const char kGiftCardRe[];
extern const char kDebitGiftCardRe[];
extern const char kDebitCardRe[];
+extern const char kDayRe[];
extern const char kEmailRe[];
extern const char kNameIgnoredRe[];
extern const char kNameRe[];
@@ -46,6 +47,7 @@ extern const char kMiddleInitialRe[];
extern const char kMiddleNameRe[];
extern const char kLastNameRe[];
extern const char kPhoneRe[];
+extern const char kAugmentedPhoneCountryCodeRe[];
extern const char kCountryCodeRe[];
extern const char kAreaCodeNotextRe[];
extern const char kAreaCodeRe[];
diff --git a/chromium/components/autofill/core/common/autofill_regexes.cc b/chromium/components/autofill/core/common/autofill_regexes.cc
index 8053897a792..02254fa266a 100644
--- a/chromium/components/autofill/core/common/autofill_regexes.cc
+++ b/chromium/components/autofill/core/common/autofill_regexes.cc
@@ -64,7 +64,8 @@ namespace autofill {
bool MatchesPattern(const base::string16& input,
const base::string16& pattern,
- base::string16* match) {
+ base::string16* match,
+ int32_t group_to_be_captured) {
static base::NoDestructor<AutofillRegexes> g_autofill_regexes;
static base::NoDestructor<base::Lock> g_lock;
base::AutoLock lock(*g_lock);
@@ -78,7 +79,8 @@ bool MatchesPattern(const base::string16& input,
DCHECK(U_SUCCESS(status));
if (matched == TRUE && match) {
- icu::UnicodeString match_unicode = matcher->group(0, status);
+ icu::UnicodeString match_unicode =
+ matcher->group(group_to_be_captured, status);
DCHECK(U_SUCCESS(status));
*match = base::i18n::UnicodeStringToString16(match_unicode);
}
diff --git a/chromium/components/autofill/core/common/autofill_regexes.h b/chromium/components/autofill/core/common/autofill_regexes.h
index 9bed8f717ce..837130b582c 100644
--- a/chromium/components/autofill/core/common/autofill_regexes.h
+++ b/chromium/components/autofill/core/common/autofill_regexes.h
@@ -12,10 +12,11 @@ namespace autofill {
// Case-insensitive regular expression matching.
// Returns true if |pattern| is found in |input|.
-// If |match| is not nullptr, the matched part is assigned to it.
+// The |group_to_be_captured| numbered group is captured into |match|.
bool MatchesPattern(const base::string16& input,
const base::string16& pattern,
- base::string16* match = nullptr);
+ base::string16* match = nullptr,
+ int32_t group_to_be_captured = 0);
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h
index 06b7805ac2b..9b591942ef9 100644
--- a/chromium/components/autofill/core/common/form_data.h
+++ b/chromium/components/autofill/core/common/form_data.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/strings/string16.h"
+#include "build/build_config.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/renderer_id.h"
@@ -114,6 +115,9 @@ struct FormData {
std::vector<FieldRendererId> username_predictions;
// True if this is a Gaia form which should be skipped on saving.
bool is_gaia_with_skip_save_password_form = false;
+#if defined(OS_IOS)
+ std::string frame_id;
+#endif
};
// For testing.
diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc
index 81aa5d980ff..fc998f879ef 100644
--- a/chromium/components/autofill/core/common/form_field_data.cc
+++ b/chromium/components/autofill/core/common/form_field_data.cc
@@ -441,6 +441,7 @@ LogBuffer& operator<<(LogBuffer& buffer, const FormFieldData& field) {
buffer << Tr{} << "Is focusable:" << field.is_focusable;
buffer << Tr{} << "Is enabled:" << field.is_enabled;
buffer << Tr{} << "Is readonly:" << field.is_readonly;
+ buffer << Tr{} << "Is empty:" << (field.value.empty() ? "Yes" : "No");
buffer << CTag{"table"};
return buffer;
}
diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h
index 10ea42b8524..84becbef96c 100644
--- a/chromium/components/autofill/core/common/form_field_data.h
+++ b/chromium/components/autofill/core/common/form_field_data.h
@@ -188,6 +188,14 @@ struct FormFieldData {
// is valid if not empty, will not be synced to the server side or be used for
// field comparison and isn't in serialize methods.
gfx::RectF bounds;
+
+ // The datalist is associated with this field, if any. The following two
+ // vectors valid if not empty, will not be synced to the server side or be
+ // used for field comparison and aren't in serialize methods.
+ // The datalist option is intentionally separated from option_values and
+ // option_contents because they are handled very differently in autofill.
+ std::vector<base::string16> datalist_values;
+ std::vector<base::string16> datalist_labels;
};
// Serialize and deserialize FormFieldData. These are used when FormData objects
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
index bd4ea2c4bff..fabc693b7c4 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
@@ -150,6 +150,9 @@ struct FormFieldData {
LabelSource label_source;
gfx.mojom.RectF bounds;
+
+ array<mojo_base.mojom.String16> datalist_values;
+ array<mojo_base.mojom.String16> datalist_labels;
};
struct ButtonTitleInfo {
@@ -206,7 +209,7 @@ struct PasswordAndMetadata {
// autofill::PasswordFormFillData
struct PasswordFormFillData {
FormRendererId form_renderer_id;
- url.mojom.Url origin;
+ url.mojom.Url url;
url.mojom.Url action;
FormFieldData username_field;
FormFieldData password_field;
@@ -278,7 +281,7 @@ struct PasswordForm {
Scheme scheme;
string signon_realm;
- url.mojom.Url origin_with_path;
+ url.mojom.Url url;
url.mojom.Url action;
string affiliated_web_realm;
mojo_base.mojom.String16 submit_element;
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 968c22d22ba..7b14bd7ce24 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -104,6 +104,11 @@ bool StructTraits<
if (!data.ReadBounds(&out->bounds))
return false;
+ if (!data.ReadDatalistValues(&out->datalist_values))
+ return false;
+ if (!data.ReadDatalistLabels(&out->datalist_labels))
+ return false;
+
return true;
}
@@ -219,7 +224,7 @@ bool StructTraits<autofill::mojom::PasswordFormFillDataDataView,
Read(autofill::mojom::PasswordFormFillDataDataView data,
autofill::PasswordFormFillData* out) {
if (!data.ReadFormRendererId(&out->form_renderer_id) ||
- !data.ReadOrigin(&out->origin) || !data.ReadAction(&out->action) ||
+ !data.ReadUrl(&out->url) || !data.ReadAction(&out->action) ||
!data.ReadUsernameField(&out->username_field) ||
!data.ReadPasswordField(&out->password_field) ||
!data.ReadPreferredRealm(&out->preferred_realm) ||
@@ -269,8 +274,7 @@ bool StructTraits<
autofill::PasswordForm>::Read(autofill::mojom::PasswordFormDataView data,
autofill::PasswordForm* out) {
if (!data.ReadScheme(&out->scheme) ||
- !data.ReadSignonRealm(&out->signon_realm) ||
- !data.ReadOriginWithPath(&out->origin) ||
+ !data.ReadSignonRealm(&out->signon_realm) || !data.ReadUrl(&out->url) ||
!data.ReadAction(&out->action) ||
!data.ReadAffiliatedWebRealm(&out->affiliated_web_realm) ||
!data.ReadSubmitElement(&out->submit_element) ||
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 0d19056c39f..650f438831b 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -177,6 +177,16 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView,
return r.bounds;
}
+ static const std::vector<base::string16>& datalist_values(
+ const autofill::FormFieldData& r) {
+ return r.datalist_values;
+ }
+
+ static const std::vector<base::string16>& datalist_labels(
+ const autofill::FormFieldData& r) {
+ return r.datalist_labels;
+ }
+
static bool Read(autofill::mojom::FormFieldDataDataView data,
autofill::FormFieldData* out);
};
@@ -363,8 +373,8 @@ struct StructTraits<autofill::mojom::PasswordFormFillDataDataView,
return r.form_renderer_id;
}
- static const GURL& origin(const autofill::PasswordFormFillData& r) {
- return r.origin;
+ static const GURL& url(const autofill::PasswordFormFillData& r) {
+ return r.url;
}
static const GURL& action(const autofill::PasswordFormFillData& r) {
@@ -484,9 +494,7 @@ struct StructTraits<autofill::mojom::PasswordFormDataView,
return r.signon_realm;
}
- static const GURL& origin_with_path(const autofill::PasswordForm& r) {
- return r.origin;
- }
+ static const GURL& url(const autofill::PasswordForm& r) { return r.url; }
static const GURL& action(const autofill::PasswordForm& r) {
return r.action;
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 438d958d7df..366c50b514e 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
@@ -49,7 +49,7 @@ void CreateTestFieldDataPredictions(const std::string& signature,
void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) {
fill_data->form_renderer_id = autofill::FormRendererId(1234);
- fill_data->origin = GURL("https://foo.com/");
+ fill_data->url = GURL("https://foo.com/");
fill_data->action = GURL("https://foo.com/login");
test::CreateTestSelectField("TestUsernameFieldLabel", "TestUsernameFieldName",
"TestUsernameFieldValue", kOptions, kOptions, 4,
@@ -78,7 +78,7 @@ void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) {
void CreateTestPasswordForm(PasswordForm* form) {
form->scheme = PasswordForm::Scheme::kHtml;
form->signon_realm = "https://foo.com/";
- form->origin = GURL("https://foo.com/");
+ form->url = GURL("https://foo.com/");
form->action = GURL("https://foo.com/login");
form->affiliated_web_realm = "https://foo.com/";
form->submit_element = base::ASCIIToUTF16("test_submit");
@@ -132,7 +132,7 @@ void CreatePasswordGenerationUIData(
void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected,
const PasswordFormFillData& actual) {
EXPECT_EQ(expected.form_renderer_id, actual.form_renderer_id);
- EXPECT_EQ(expected.origin, actual.origin);
+ EXPECT_EQ(expected.url, actual.url);
EXPECT_EQ(expected.action, actual.action);
EXPECT_TRUE(EquivalentData(expected.username_field, actual.username_field));
EXPECT_TRUE(EquivalentData(expected.password_field, actual.password_field));
@@ -326,6 +326,36 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) {
loop.Run();
}
+TEST_F(AutofillTypeTraitsTestImpl, PassDataListFormFieldData) {
+ // Basically copied from PassFormFieldData and replaced Select with Datalist.
+ FormFieldData input;
+ test::CreateTestDatalistField("DatalistLabel", "DatalistName",
+ "DatalistValue", kOptions, kOptions, &input);
+ // Set other attributes to check if they are passed correctly.
+ input.id_attribute = base::ASCIIToUTF16("id");
+ input.name_attribute = base::ASCIIToUTF16("name");
+ input.autocomplete_attribute = "on";
+ input.placeholder = base::ASCIIToUTF16("placeholder");
+ input.css_classes = base::ASCIIToUTF16("class1");
+ input.aria_label = base::ASCIIToUTF16("aria label");
+ input.aria_description = base::ASCIIToUTF16("aria description");
+ input.max_length = 12345;
+ input.is_autofilled = true;
+ input.check_status = FormFieldData::CheckStatus::kChecked;
+ input.should_autocomplete = true;
+ input.role = FormFieldData::RoleAttribute::kPresentation;
+ input.text_direction = base::i18n::RIGHT_TO_LEFT;
+ input.properties_mask = FieldPropertiesFlags::kHadFocus;
+ input.typed_value = base::ASCIIToUTF16("TestTypedValue");
+ input.bounds = gfx::RectF(1, 2, 10, 100);
+
+ base::RunLoop loop;
+ mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote());
+ remote->PassFormFieldData(
+ input, base::BindOnce(&ExpectFormFieldData, input, loop.QuitClosure()));
+ loop.Run();
+}
+
TEST_F(AutofillTypeTraitsTestImpl, PassFormData) {
FormData input;
test::CreateTestAddressFormData(&input);
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc
index 4ef730d00c7..4f164e30c13 100644
--- a/chromium/components/autofill/core/common/password_form.cc
+++ b/chromium/components/autofill/core/common/password_form.cc
@@ -46,7 +46,7 @@ void PasswordFormToJSON(const PasswordForm& form,
target->SetBoolean("is_public_suffix_match", form.is_public_suffix_match);
target->SetBoolean("is_affiliation_based_match",
form.is_affiliation_based_match);
- target->SetString("origin", form.origin.possibly_invalid_spec());
+ target->SetString("url", form.url.possibly_invalid_spec());
target->SetString("action", form.action.possibly_invalid_spec());
target->SetString("submit_element", form.submit_element);
target->SetBoolean("has_renderer_ids", form.has_renderer_ids);
@@ -162,7 +162,7 @@ bool PasswordForm::HasNonEmptyPasswordValue() const {
bool PasswordForm::operator==(const PasswordForm& form) const {
return scheme == form.scheme && signon_realm == form.signon_realm &&
- origin == form.origin && action == form.action &&
+ url == form.url && action == form.action &&
submit_element == form.submit_element &&
has_renderer_ids == form.has_renderer_ids &&
username_element == form.username_element &&
@@ -214,8 +214,7 @@ bool PasswordForm::operator!=(const PasswordForm& form) const {
bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
const PasswordForm& right) {
- return (left.signon_realm == right.signon_realm &&
- left.origin == right.origin &&
+ 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);
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
index e4fea845c48..67694d8d4e6 100644
--- a/chromium/components/autofill/core/common/password_form.h
+++ b/chromium/components/autofill/core/common/password_form.h
@@ -64,14 +64,13 @@ struct PasswordForm {
// data from the database, so it must not be empty.
std::string signon_realm;
- // An origin 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.
+ // 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.
- // TODO(melandory): origin should be renamed in order to be consistent with
- // GURL definition of origin.
- GURL origin;
+ 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
@@ -298,13 +297,16 @@ struct PasswordForm {
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
+ kAccountStore = 2,
+ kMaxValue = kAccountStore
};
Store in_store = Store::kNotSet;
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 0e0ed4bc63e..abe21a09684 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -62,11 +62,10 @@ struct PasswordFormFillData {
// The name of the form.
base::string16 name;
- // An origin URL consists of the scheme, host, port and path; the rest is
- // stripped.
- GURL origin;
+ // An URL consisting of the scheme, host, port and path; the rest is stripped.
+ GURL url;
- // The action target of the form; like |origin| URL consists of the scheme,
+ // The action target of the form; like |url| URL consists of the scheme,
// host, port and path; the rest is stripped.
GURL action;
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.cc b/chromium/components/autofill/core/common/password_form_generation_data.cc
index 6ebec23be8c..04cccb19fbb 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.cc
+++ b/chromium/components/autofill/core/common/password_form_generation_data.cc
@@ -19,11 +19,9 @@ PasswordFormGenerationData::PasswordFormGenerationData(
#if defined(OS_IOS)
PasswordFormGenerationData::PasswordFormGenerationData(
FormRendererId form_renderer_id,
- base::string16 new_password_element,
FieldRendererId new_password_renderer_id,
FieldRendererId confirmation_password_renderer_id)
: form_renderer_id(form_renderer_id),
- new_password_element(new_password_element),
new_password_renderer_id(new_password_renderer_id),
confirmation_password_renderer_id(confirmation_password_renderer_id) {}
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 c76f1eccaa5..2618629d47a 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -22,7 +22,6 @@ struct PasswordFormGenerationData {
FieldRendererId confirmation_password_renderer_id);
#if defined(OS_IOS)
PasswordFormGenerationData(FormRendererId form_renderer_id,
- base::string16 new_password_element,
FieldRendererId new_password_renderer_id,
FieldRendererId confirmation_password_renderer_id);
@@ -33,9 +32,6 @@ struct PasswordFormGenerationData {
~PasswordFormGenerationData();
FormRendererId form_renderer_id;
- // TODO(crbug.com/1075444): Remove this once VotesUploader starts to use
- // unique renderer IDs.
- base::string16 new_password_element;
#endif
FieldRendererId new_password_renderer_id;
FieldRendererId confirmation_password_renderer_id;
diff --git a/chromium/components/autofill/core/common/renderer_id.h b/chromium/components/autofill/core/common/renderer_id.h
index 79eaab6620d..511d4d28461 100644
--- a/chromium/components/autofill/core/common/renderer_id.h
+++ b/chromium/components/autofill/core/common/renderer_id.h
@@ -29,6 +29,8 @@ using FieldRendererIdType =
// order to avoid having to define out-of-line constructors in all structs that
// contain renderer IDs.
+// The FormRendererId of a synthetic form is_null(). A synthetic form is the
+// collection of form fields outside of the scope of any <form> tag in a page.
class FormRendererId : public internal::FormRendererIdType {
using internal::FormRendererIdType::IdType;
};
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm
index fceb06e2fda..fafe880b37e 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent.mm
@@ -187,8 +187,7 @@ void GetFormField(autofill::FormFieldData* field,
_prefObserverBridge->ObserveChangesForPreference(
autofill::prefs::kAutofillProfileEnabled, &_prefChangeRegistrar);
- _jsAutofillManager = [[JsAutofillManager alloc]
- initWithReceiver:_webState->GetJSInjectionReceiver()];
+ _jsAutofillManager = [[JsAutofillManager alloc] init];
}
return self;
}
diff --git a/chromium/components/autofill/ios/browser/autofill_util.h b/chromium/components/autofill/ios/browser/autofill_util.h
index 7065abd8203..8c4f61538ee 100644
--- a/chromium/components/autofill/ios/browser/autofill_util.h
+++ b/chromium/components/autofill/ios/browser/autofill_util.h
@@ -72,7 +72,6 @@ bool ExtractFormFieldData(const base::DictionaryValue& field,
void ExecuteJavaScriptFunction(const std::string& name,
const std::vector<base::Value>& parameters,
web::WebFrame* frame,
- CRWJSInjectionReceiver* js_injection_receiver,
base::OnceCallback<void(NSString*)> callback);
} // namespace autofill
diff --git a/chromium/components/autofill/ios/browser/autofill_util.mm b/chromium/components/autofill/ios/browser/autofill_util.mm
index 8e14a554ba2..af140f29505 100644
--- a/chromium/components/autofill/ios/browser/autofill_util.mm
+++ b/chromium/components/autofill/ios/browser/autofill_util.mm
@@ -19,7 +19,6 @@
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
#import "ios/web/public/navigation/navigation_item.h"
#import "ios/web/public/navigation/navigation_manager.h"
#include "ios/web/public/security/ssl_status.h"
@@ -27,6 +26,9 @@
#include "url/gurl.h"
#include "url/origin.h"
+using base::NumberToString;
+using base::StringToUint;
+
namespace {
// The timeout for any JavaScript call in this file.
const int64_t kJavaScriptExecutionTimeoutInSeconds = 5;
@@ -50,17 +52,11 @@ bool IsContextSecureForWebState(web::WebState* web_state) {
}
std::unique_ptr<base::Value> ParseJson(NSString* json_string) {
- // Convert JSON string to JSON object |JSONValue|.
- int error_code = 0;
- std::string error_message;
- std::unique_ptr<base::Value> json_value(
- base::JSONReader::ReadAndReturnErrorDeprecated(
- base::SysNSStringToUTF8(json_string), base::JSON_PARSE_RFC,
- &error_code, &error_message));
- if (error_code)
+ base::Optional<base::Value> json_value =
+ base::JSONReader::Read(base::SysNSStringToUTF8(json_string));
+ if (!json_value)
return nullptr;
-
- return json_value;
+ return base::Value::ToUniquePtrValue(std::move(*json_value));
}
bool ExtractFormsData(NSString* forms_json,
@@ -123,9 +119,9 @@ bool ExtractFormData(const base::Value& form_value,
std::string unique_renderer_id;
form_dictionary->GetString("unique_renderer_id", &unique_renderer_id);
- if (!unique_renderer_id.empty()) {
- base::StringToUint(unique_renderer_id,
- &form_data->unique_renderer_id.value());
+ if (!unique_renderer_id.empty() &&
+ unique_renderer_id != NumberToString(kNotSetRendererID)) {
+ StringToUint(unique_renderer_id, &form_data->unique_renderer_id.value());
} else {
form_data->unique_renderer_id = FormRendererId();
}
@@ -141,6 +137,7 @@ bool ExtractFormData(const base::Value& form_value,
form_dictionary->GetBoolean("is_form_tag", &form_data->is_form_tag);
form_dictionary->GetBoolean("is_formless_checkout",
&form_data->is_formless_checkout);
+ form_dictionary->GetString("frame_id", &form_data->frame_id);
// Field list (mandatory) is extracted.
const base::ListValue* fields_list = nullptr;
@@ -169,9 +166,9 @@ bool ExtractFormFieldData(const base::DictionaryValue& field,
std::string unique_renderer_id;
field.GetString("unique_renderer_id", &unique_renderer_id);
- if (!unique_renderer_id.empty()) {
- base::StringToUint(unique_renderer_id,
- &field_data->unique_renderer_id.value());
+ if (!unique_renderer_id.empty() &&
+ unique_renderer_id != NumberToString(kNotSetRendererID)) {
+ StringToUint(unique_renderer_id, &field_data->unique_renderer_id.value());
} else {
field_data->unique_renderer_id = FieldRendererId();
}
@@ -233,7 +230,6 @@ bool ExtractFormFieldData(const base::DictionaryValue& field,
void ExecuteJavaScriptFunction(const std::string& name,
const std::vector<base::Value>& parameters,
web::WebFrame* frame,
- CRWJSInjectionReceiver* js_injection_receiver,
base::OnceCallback<void(NSString*)> callback) {
__block base::OnceCallback<void(NSString*)> cb = std::move(callback);
diff --git a/chromium/components/autofill/ios/browser/js_autofill_manager.h b/chromium/components/autofill/ios/browser/js_autofill_manager.h
index 15c404b9b3a..7ebd532dcd1 100644
--- a/chromium/components/autofill/ios/browser/js_autofill_manager.h
+++ b/chromium/components/autofill/ios/browser/js_autofill_manager.h
@@ -8,7 +8,6 @@
#include "base/ios/block_types.h"
#include "base/values.h"
#include "components/autofill/core/common/autofill_constants.h"
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
namespace web {
class WebFrame;
@@ -72,12 +71,6 @@ class WebFrame;
- (void)toggleTrackingUserEditedFields:(BOOL)state
inFrame:(web::WebFrame*)frame;
-// Designated initializer. |receiver| should not be nil.
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
- NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
@end
#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_JS_AUTOFILL_MANAGER_H_
diff --git a/chromium/components/autofill/ios/browser/js_autofill_manager.mm b/chromium/components/autofill/ios/browser/js_autofill_manager.mm
index 13592c9ba3a..4e8f9645df4 100644
--- a/chromium/components/autofill/ios/browser/js_autofill_manager.mm
+++ b/chromium/components/autofill/ios/browser/js_autofill_manager.mm
@@ -12,8 +12,6 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/format_macros.h"
-#include "base/json/json_writer.h"
-#include "base/json/string_escape.h"
#include "base/mac/foundation_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
@@ -26,19 +24,7 @@
#error "This file requires ARC support."
#endif
-@implementation JsAutofillManager {
- // The injection receiver used to evaluate JavaScript.
- __weak CRWJSInjectionReceiver* _receiver;
-}
-
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
- DCHECK(receiver);
- self = [super init];
- if (self) {
- _receiver = receiver;
- }
- return self;
-}
+@implementation JsAutofillManager
- (void)addJSDelayInFrame:(web::WebFrame*)frame {
const base::CommandLine* command_line =
@@ -52,7 +38,7 @@
std::vector<base::Value> parameters;
parameters.push_back(base::Value(commandLineDelay));
autofill::ExecuteJavaScriptFunction(
- "autofill.setDelay", parameters, frame, _receiver,
+ "autofill.setDelay", parameters, frame,
base::OnceCallback<void(NSString*)>());
}
}
@@ -70,8 +56,7 @@
parameters.push_back(base::Value(static_cast<int>(requiredFieldsCount)));
parameters.push_back(base::Value(restrictUnownedFieldsToFormlessCheckout));
autofill::ExecuteJavaScriptFunction("autofill.extractForms", parameters,
- frame, _receiver,
- base::BindOnce(completionHandler));
+ frame, base::BindOnce(completionHandler));
}
#pragma mark -
@@ -84,7 +69,7 @@
std::vector<base::Value> parameters;
parameters.push_back(std::move(*data));
autofill::ExecuteJavaScriptFunction("autofill.fillActiveFormField",
- parameters, frame, _receiver,
+ parameters, frame,
base::BindOnce(^(NSString*) {
completionHandler();
}));
@@ -94,7 +79,7 @@
std::vector<base::Value> parameters;
parameters.push_back(base::Value(state ? 200 : 0));
autofill::ExecuteJavaScriptFunction("formHandlers.trackFormMutations",
- parameters, frame, _receiver,
+ parameters, frame,
base::OnceCallback<void(NSString*)>());
}
@@ -104,7 +89,7 @@
parameters.push_back(base::Value(static_cast<bool>(state)));
autofill::ExecuteJavaScriptFunction(
"formHandlers.toggleTrackingUserEditedFields", parameters, frame,
- _receiver, base::OnceCallback<void(NSString*)>());
+ base::OnceCallback<void(NSString*)>());
}
- (void)fillForm:(std::unique_ptr<base::Value>)data
@@ -121,7 +106,7 @@
parameters.push_back(std::move(*data));
parameters.push_back(base::Value(fieldIdentifier));
autofill::ExecuteJavaScriptFunction("autofill.fillForm", parameters, frame,
- _receiver, base::BindOnce(^(NSString*) {
+ base::BindOnce(^(NSString*) {
completionHandler();
}));
}
@@ -135,7 +120,7 @@
parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldIdentifier)));
autofill::ExecuteJavaScriptFunction("autofill.clearAutofilledFields",
- parameters, frame, _receiver,
+ parameters, frame,
base::BindOnce(^(NSString*) {
completionHandler();
}));
@@ -147,7 +132,7 @@
std::vector<base::Value> parameters;
parameters.push_back(std::move(*data));
autofill::ExecuteJavaScriptFunction("autofill.fillPredictionData", parameters,
- frame, _receiver,
+ frame,
base::OnceCallback<void(NSString*)>());
}
diff --git a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
index e5767bba023..837546f40de 100644
--- a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
+++ b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
@@ -56,8 +56,7 @@
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
autofill::ExecuteJavaScriptFunction(
"suggestion.selectNextElement", parameters,
- [self frameWithFrameID:frameID], _receiver,
- base::OnceCallback<void(NSString*)>());
+ [self frameWithFrameID:frameID], base::OnceCallback<void(NSString*)>());
}
- (void)selectPreviousElementInFrameWithID:(NSString*)frameID {
@@ -72,8 +71,7 @@
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
autofill::ExecuteJavaScriptFunction(
"suggestion.selectPreviousElement", parameters,
- [self frameWithFrameID:frameID], _receiver,
- base::OnceCallback<void(NSString*)>());
+ [self frameWithFrameID:frameID], base::OnceCallback<void(NSString*)>());
}
- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
@@ -98,8 +96,7 @@
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
autofill::ExecuteJavaScriptFunction(
"suggestion.hasPreviousNextElements", parameters,
- [self frameWithFrameID:frameID], _receiver,
- base::BindOnce(^(NSString* result) {
+ [self frameWithFrameID:frameID], base::BindOnce(^(NSString* result) {
// The result maybe an empty string here due to 2 reasons:
// 1) When there is an exception running the JS
// 2) There is a race when the page is changing due to which
@@ -127,8 +124,7 @@
std::vector<base::Value> parameters;
autofill::ExecuteJavaScriptFunction(
"suggestion.blurActiveElement", parameters,
- [self frameWithFrameID:frameID], _receiver,
- base::OnceCallback<void(NSString*)>());
+ [self frameWithFrameID:frameID], base::OnceCallback<void(NSString*)>());
}
- (web::WebFrame*)frameWithFrameID:(NSString*)frameID {
diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm
index e04639c4d0c..d4e4020a628 100644
--- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm
+++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm
@@ -7,6 +7,7 @@
#import <Foundation/Foundation.h>
#include "base/bind.h"
+#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "components/autofill/ios/form_util/form_activity_observer.h"
diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm
index cffa22b4fa1..9acd740d56f 100644
--- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm
@@ -16,6 +16,8 @@
#import "ios/web/public/test/web_test_with_web_state.h"
#include "testing/platform_test.h"
+using web::WebFrame;
+
class FormTestClient : public web::TestWebClient {
public:
NSString* GetDocumentStartScriptForAllFrames(
@@ -61,19 +63,22 @@ TEST_F(FormActivityTabHelperTest, TestObserverDocumentSubmitted) {
ExecuteJavaScript(@"__gCrWeb.fill.setUpForUniqueIDs(0);");
ASSERT_FALSE(observer_->submit_document_info());
const std::string kTestFormName("form-name");
- const std::string kTestFormData(
- "[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/"
- "\",\"action\":\"https://chromium.test/\","
- "\"name_attribute\":\"form-name\",\"id_attribute\":\"\","
- "\"unique_renderer_id\":\"0\"}]");
+
+ WebFrame* main_frame = web_state()->GetWebFramesManager()->GetMainWebFrame();
+ std::string mainFrameID = main_frame->GetFrameId();
+ const std::string kTestFormData =
+ std::string("[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/"
+ "\",\"action\":\"https://chromium.test/\","
+ "\"name_attribute\":\"form-name\",\"id_attribute\":\"\","
+ "\"unique_renderer_id\":\"0\",\"frame_id\":\"") +
+ mainFrameID + std::string("\"}]");
+
bool has_user_gesture = false;
bool form_in_main_frame = true;
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return web_state()->GetWebFramesManager()->GetMainWebFrame() != nullptr;
}));
- web::WebFrame* main_frame =
- web_state()->GetWebFramesManager()->GetMainWebFrame();
ExecuteJavaScript(@"document.getElementById('submit').click();");
ASSERT_TRUE(observer_->submit_document_info());
@@ -96,19 +101,22 @@ TEST_F(FormActivityTabHelperTest, TestFormSubmittedHook) {
ExecuteJavaScript(@"__gCrWeb.fill.setUpForUniqueIDs(0);");
ASSERT_FALSE(observer_->submit_document_info());
const std::string kTestFormName("form-name");
- const std::string kTestFormData(
- "[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/"
- "\",\"action\":\"https://chromium.test/\","
- "\"name_attribute\":\"form-name\",\"id_attribute\":\"form\","
- "\"unique_renderer_id\":\"0\"}]");
+
+ WebFrame* main_frame = web_state()->GetWebFramesManager()->GetMainWebFrame();
+ std::string mainFrameID = main_frame->GetFrameId();
+ const std::string kTestFormData =
+ std::string("[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/"
+ "\",\"action\":\"https://chromium.test/\","
+ "\"name_attribute\":\"form-name\",\"id_attribute\":\"form\","
+ "\"unique_renderer_id\":\"0\",\"frame_id\":\"") +
+ mainFrameID + std::string("\"}]");
+
bool has_user_gesture = false;
bool form_in_main_frame = true;
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return web_state()->GetWebFramesManager()->GetMainWebFrame() != nullptr;
}));
- web::WebFrame* main_frame =
- web_state()->GetWebFramesManager()->GetMainWebFrame();
ExecuteJavaScript(@"document.getElementById('form').submit();");
ASSERT_TRUE(observer_->submit_document_info());
@@ -133,8 +141,7 @@ TEST_F(FormActivityTabHelperTest, TestObserverFormActivityFrameMessaging) {
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return web_state()->GetWebFramesManager()->GetMainWebFrame() != nullptr;
}));
- web::WebFrame* main_frame =
- web_state()->GetWebFramesManager()->GetMainWebFrame();
+ WebFrame* main_frame = web_state()->GetWebFramesManager()->GetMainWebFrame();
ASSERT_FALSE(observer_->form_activity_info());
// First call will set document.activeElement (which is usually set by user
// action. Second call will trigger the message.
diff --git a/chromium/components/autofill/ios/form_util/form_unittest.mm b/chromium/components/autofill/ios/form_util/form_unittest.mm
index b5e60552017..3f505ad8cd7 100644
--- a/chromium/components/autofill/ios/form_util/form_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/form_unittest.mm
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import "base/test/ios/wait_util.h"
#include "components/autofill/ios/form_util/form_activity_tab_helper.h"
#include "components/autofill/ios/form_util/test_form_activity_observer.h"
#import "ios/web/public/browser_state.h"
@@ -16,6 +17,9 @@
#error "This file requires ARC support."
#endif
+using base::test::ios::WaitUntilConditionOrTimeout;
+using base::test::ios::kWaitForJSCompletionTimeout;
+
class FormTestClient : public web::TestWebClient {
public:
NSString* GetDocumentStartScriptForAllFrames(
@@ -60,9 +64,9 @@ TEST_F(FormJsTest, KeyUpEventFocused) {
"var ev = new KeyboardEvent('keyup', {bubbles:true});"
"e.dispatchEvent(ev);");
autofill::TestFormActivityObserver* block_observer = observer_.get();
- WaitForCondition(^bool {
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return block_observer->form_activity_info() != nullptr;
- });
+ }));
autofill::TestFormActivityInfo* info = observer_->form_activity_info();
ASSERT_TRUE(info);
EXPECT_EQ("keyup", info->form_activity.type);
@@ -93,9 +97,9 @@ TEST_F(FormJsTest, FocusMainFrame) {
ASSERT_FALSE(observer_->form_activity_info());
ExecuteJavaScript(@"document.getElementById('id1').focus();");
autofill::TestFormActivityObserver* block_observer = observer_.get();
- WaitForCondition(^bool {
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return block_observer->form_activity_info() != nullptr;
- });
+ }));
autofill::TestFormActivityInfo* info = observer_->form_activity_info();
ASSERT_TRUE(info);
EXPECT_EQ("focus", info->form_activity.type);
@@ -131,9 +135,9 @@ TEST_F(FormJsTest, FocusSameOriginIFrame) {
@"document.getElementById('frame1').contentDocument.getElementById('id1')"
@".focus()");
autofill::TestFormActivityObserver* block_observer = observer_.get();
- WaitForCondition(^bool {
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return block_observer->form_activity_info() != nullptr;
- });
+ }));
autofill::TestFormActivityInfo* info = observer_->form_activity_info();
ASSERT_TRUE(info);
EXPECT_EQ("focus", info->form_activity.type);
@@ -168,10 +172,10 @@ TEST_F(FormJsTest, AddForm) {
@"document.body.appendChild(form);");
autofill::TestFormActivityObserver* block_observer = observer_.get();
__block autofill::TestFormActivityInfo* info = nil;
- WaitForCondition(^{
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
info = block_observer->form_activity_info();
return info != nil;
- });
+ }));
EXPECT_EQ("form_changed", info->form_activity.type);
EXPECT_FALSE(info->form_activity.input_missing);
}
@@ -186,10 +190,10 @@ TEST_F(FormJsTest, AddInput) {
@"document.getElementById('formId').appendChild(input);");
autofill::TestFormActivityObserver* block_observer = observer_.get();
__block autofill::TestFormActivityInfo* info = nil;
- WaitForCondition(^{
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
info = block_observer->form_activity_info();
return info != nil;
- });
+ }));
EXPECT_EQ("form_changed", info->form_activity.type);
EXPECT_FALSE(info->form_activity.input_missing);
}
@@ -204,10 +208,10 @@ TEST_F(FormJsTest, AddSelect) {
@"document.getElementById('formId').appendChild(select);");
autofill::TestFormActivityObserver* block_observer = observer_.get();
__block autofill::TestFormActivityInfo* info = nil;
- WaitForCondition(^{
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
info = block_observer->form_activity_info();
return info != nil;
- });
+ }));
EXPECT_EQ("form_changed", info->form_activity.type);
EXPECT_FALSE(info->form_activity.input_missing);
}
@@ -225,10 +229,32 @@ TEST_F(FormJsTest, AddOption) {
@"document.getElementById('select1').appendChild(option);");
autofill::TestFormActivityObserver* block_observer = observer_.get();
__block autofill::TestFormActivityInfo* info = nil;
- WaitForCondition(^{
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
info = block_observer->form_activity_info();
return info != nil;
- });
+ }));
EXPECT_EQ("form_changed", info->form_activity.type);
EXPECT_FALSE(info->form_activity.input_missing);
}
+
+// Tests that removing password form triggers 'password_form_removed" event.
+TEST_F(FormJsTest, RemoveForm) {
+ LoadHtml(@"<form id=\"form1\">"
+ "<input type=\"text\" name=\"username\" id=\"id1\">"
+ "<input type=\"password\" name=\"password\" id=\"id2\">"
+ "<input type=\"submit\" id=\"submit_input\"/>"
+ "</form>");
+ ExecuteJavaScript(@"__gCrWeb.fill.setUpForUniqueIDs(0);"
+ @"__gCrWeb.formHandlers.trackFormMutations(10);"
+ @"var form1 = document.getElementById('form1');"
+ @"__gCrWeb.fill.setUniqueIDIfNeeded(form1);"
+ @"form1.parentNode.removeChild(form1);");
+ autofill::TestFormActivityObserver* block_observer = observer_.get();
+ __block autofill::TestFormActivityInfo* info = nil;
+ ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+ info = block_observer->form_activity_info();
+ return info != nil;
+ }));
+ EXPECT_EQ("password_form_removed", info->form_activity.type);
+ EXPECT_FALSE(info->form_activity.input_missing);
+}
diff --git a/chromium/components/autofill/ios/form_util/resources/fill.js b/chromium/components/autofill/ios/form_util/resources/fill.js
index a48befb78a5..1108ece5273 100644
--- a/chromium/components/autofill/ios/form_util/resources/fill.js
+++ b/chromium/components/autofill/ios/form_util/resources/fill.js
@@ -34,6 +34,7 @@ let AutofillFormFieldData;
* origin: string,
* action: string,
* fields: Array<AutofillFormFieldData>
+ * frame_id: string
* }}
*/
let AutofillFormData;
@@ -144,6 +145,16 @@ __gCrWeb.fill.ROLE_ATTRIBUTE_PRESENTATION = 0;
__gCrWeb.fill.RENDERER_ID_NOT_SET = '-1';
/**
+ * The name of the JS Symbol used to set stable unique form and field IDs.
+ *
+ * This variable is |kNotSetRendererID| from
+ * chromium/src/components/autofill/ios/browser/autofill_util.h
+ *
+ * @const {string}
+ */
+__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME = '__gChrome~uniqueID';
+
+/**
* Returns true if an element can be autocompleted.
*
* This method aims to provide the same logic as method
@@ -838,13 +849,10 @@ __gCrWeb.fill.webFormElementToFormData = function(
form['name_attribute'] = formElement.getAttribute('name') || '';
form['id_attribute'] = formElement.getAttribute('id') || '';
- try {
- __gCrWeb.fill.setUniqueIDIfNeeded(formElement);
- const uniqueID = Symbol.for('__gChrome~uniqueID');
- form['unique_renderer_id'] = formElement[uniqueID].toString();
- } catch (e) {
- form['unique_renderer_id'] = __gCrWeb.fill.RENDERER_ID_NOT_SET;
- }
+ __gCrWeb.fill.setUniqueIDIfNeeded(formElement);
+ form['unique_renderer_id'] = __gCrWeb.fill.getUniqueID(formElement);
+
+ form['frame_id'] = frame.__gCrWeb.message.getFrameId();
// Note different from form_autofill_util.cc version of this method, which
// computes |form.action| using document.completeURL(form_element.action())
@@ -1938,12 +1946,8 @@ __gCrWeb.fill.webFormControlElementToFormField = function(
field['name_attribute'] = element.getAttribute('name') || '';
field['id_attribute'] = element.getAttribute('id') || '';
- try {
- const uniqueID = Symbol.for('__gChrome~uniqueID');
- field['unique_renderer_id'] = element[uniqueID].toString();
- } catch (e) {
- field['unique_renderer_id'] = __gCrWeb.fill.RENDERER_ID_NOT_SET;
- }
+ __gCrWeb.fill.setUniqueIDIfNeeded(element);
+ field['unique_renderer_id'] = __gCrWeb.fill.getUniqueID(element);
field['form_control_type'] = element.type;
const autocompleteAttribute = element.getAttribute('autocomplete');
@@ -2298,7 +2302,7 @@ __gCrWeb.fill.extractAutofillableElementsFromSet = function(controlElements) {
* @param {int} nextAvailableID Next available integer.
*/
__gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) {
- const uniqueID = Symbol.for('__gChrome~uniqueID');
+ const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
document[uniqueID] = nextAvailableID;
};
@@ -2306,9 +2310,29 @@ __gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) {
* @param {Element} element Form or form input element.
*/
__gCrWeb.fill.setUniqueIDIfNeeded = function(element) {
- const uniqueID = Symbol.for('__gChrome~uniqueID');
- if (typeof element[uniqueID] === 'undefined') {
- element[uniqueID] = document[uniqueID]++;
+ try {
+ const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
+ if (typeof element[uniqueID] === 'undefined') {
+ element[uniqueID] = document[uniqueID]++;
+ }
+ } catch (e) {
+ }
+};
+
+/**
+ * @param {Element} element Form or form input element.
+ * @return {String} Unique stable ID converted to string..
+ */
+__gCrWeb.fill.getUniqueID = function(element) {
+ try {
+ const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
+ if (typeof element[uniqueID] !== 'undefined' && !isNaN(element[uniqueID])) {
+ return element[uniqueID].toString();
+ } else {
+ return __gCrWeb.fill.RENDERER_ID_NOT_SET;
+ }
+ } catch (e) {
+ return __gCrWeb.fill.RENDERER_ID_NOT_SET;
}
};
diff --git a/chromium/components/autofill/ios/form_util/resources/form.js b/chromium/components/autofill/ios/form_util/resources/form.js
index d393d81f905..e857c9e88b5 100644
--- a/chromium/components/autofill/ios/form_util/resources/form.js
+++ b/chromium/components/autofill/ios/form_util/resources/form.js
@@ -280,7 +280,7 @@ __gCrWeb.form.getFormElementFromUniqueFormId = function(identifier) {
const forms = document.forms;
for (let i = 0; i < forms.length; i++) {
const form = forms[i];
- const uniqueID = Symbol.for('__gChrome~uniqueID');
+ const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
if (identifier === form[uniqueID]) {
return form;
}
diff --git a/chromium/components/autofill/ios/form_util/resources/form_handlers.js b/chromium/components/autofill/ios/form_util/resources/form_handlers.js
index a0e2bad0577..69f0d8d2c9c 100644
--- a/chromium/components/autofill/ios/form_util/resources/form_handlers.js
+++ b/chromium/components/autofill/ios/form_util/resources/form_handlers.js
@@ -110,22 +110,16 @@ function formActivity_(evt) {
if (target !== lastFocusedElement) {
return;
}
- let formUniqueIdString = __gCrWeb.fill.RENDERER_ID_NOT_SET;
- let fieldUniqueIdString = __gCrWeb.fill.RENDERER_ID_NOT_SET;
- try {
- __gCrWeb.fill.setUniqueIDIfNeeded(target.form);
- __gCrWeb.fill.setUniqueIDIfNeeded(target);
- const uniqueID = Symbol.for('__gChrome~uniqueID');
- formUniqueIdString = target.form[uniqueID].toString();
- fieldUniqueIdString = target[uniqueID].toString();
- } catch (e) {
- }
+ __gCrWeb.fill.setUniqueIDIfNeeded(target.form);
+ __gCrWeb.fill.setUniqueIDIfNeeded(target);
+ const formUniqueId = __gCrWeb.fill.getUniqueID(target.form);
+ const fieldUniqueId = __gCrWeb.fill.getUniqueID(target);
const msg = {
'command': 'form.activity',
'formName': __gCrWeb.form.getFormIdentifier(target.form),
- 'uniqueFormID': formUniqueIdString,
+ 'uniqueFormID': formUniqueId,
'fieldIdentifier': __gCrWeb.form.getFieldIdentifier(target),
- 'uniqueFieldID': fieldUniqueIdString,
+ 'uniqueFieldID': fieldUniqueId,
'fieldType': fieldType,
'type': evt.type,
'value': value,
@@ -267,6 +261,45 @@ __gCrWeb.formHandlers['trackFormMutations'] = function(delay) {
};
return sendFormMutationMessageAfterDelay_(msg, delay);
}
+
+ const removedElements = [];
+ for (let j = 0; j < mutation.removedNodes.length; j++) {
+ const node = mutation.removedNodes[j];
+ // Ignore non-element nodes.
+ if (node.nodeType !== Node.ELEMENT_NODE) {
+ continue;
+ }
+ removedElements.push(node);
+ [].push.apply(
+ removedElements, [].slice.call(node.getElementsByTagName('FORM')));
+ }
+ const formGone = removedElements.find(function(element) {
+ if (element.tagName.match(/(FORM)/)) {
+ for (let k = 0; k < element.elements.length; k++) {
+ if (element.elements[k].tagName.match(/(INPUT)/) &&
+ element.elements[k].type === 'password') {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ });
+ const uniqueFormId = __gCrWeb.fill.getUniqueID(formGone);
+ if (formGone) {
+ const msg = {
+ 'command': 'form.activity',
+ 'formName': '',
+ 'uniqueFormID': uniqueFormId,
+ 'fieldIdentifier': '',
+ 'uniqueFieldID': '',
+ 'fieldType': '',
+ 'type': 'password_form_removed',
+ 'value': '',
+ 'hasUserGesture': false
+ };
+ return sendFormMutationMessageAfterDelay_(msg, delay);
+ }
}
});
formMutationObserver.observe(document, {childList: true, subtree: true});