Commit ff4559a4 authored by Clemens Arbesser's avatar Clemens Arbesser Committed by Commit Bot

[Autofill Assistant] Refactor field formatter

This CL refactors the field formatter such that non-integer keys are
also supported. This is in preparation for an upcoming CL where this
will be required.

Bug: b/145043394
Change-Id: I603ea66b2ef338d43c263cfa00031eb11dda565d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2235615
Commit-Queue: Clemens Arbesser <arbesser@google.com>
Reviewed-by: default avatarSandro Maggi <sandromaggi@google.com>
Cr-Commit-Position: refs/heads/master@{#777327}
parent 30705dd5
......@@ -84,8 +84,6 @@ jumbo_static_library("browser") {
"actions/wait_for_dom_action.h",
"actions/wait_for_navigation_action.cc",
"actions/wait_for_navigation_action.h",
"autofill_field_formatter.cc",
"autofill_field_formatter.h",
"basic_interactions.cc",
"basic_interactions.h",
"batch_element_checker.cc",
......@@ -115,6 +113,8 @@ jumbo_static_library("browser") {
"event_handler.h",
"features.cc",
"features.h",
"field_formatter.cc",
"field_formatter.h",
"generic_ui_java_generated_enums.h",
"info_box.cc",
"info_box.h",
......@@ -254,7 +254,6 @@ source_set("unit_tests") {
"actions/use_credit_card_action_unittest.cc",
"actions/wait_for_document_action_unittest.cc",
"actions/wait_for_dom_action_unittest.cc",
"autofill_field_formatter_unittest.cc",
"basic_interactions_unittest.cc",
"batch_element_checker_unittest.cc",
"controller_unittest.cc",
......@@ -262,6 +261,7 @@ source_set("unit_tests") {
"element_area_unittest.cc",
"element_precondition_unittest.cc",
"event_handler_unittest.cc",
"field_formatter_unittest.cc",
"protocol_utils_unittest.cc",
"retry_timer_unittest.cc",
"script_executor_unittest.cc",
......
......@@ -11,9 +11,9 @@
#include "base/callback.h"
#include "base/optional.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/autofill_field_formatter.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/field_formatter.h"
namespace autofill_assistant {
namespace {
......@@ -51,7 +51,7 @@ RequiredFieldsFallbackHandler::~RequiredFieldsFallbackHandler() = default;
RequiredFieldsFallbackHandler::RequiredFieldsFallbackHandler(
const std::vector<RequiredField>& required_fields,
const std::map<int, std::string>& fallback_values,
const std::map<std::string, std::string>& fallback_values,
ActionDelegate* delegate)
: required_fields_(required_fields),
fallback_values_(fallback_values),
......@@ -154,8 +154,8 @@ void RequiredFieldsFallbackHandler::OnCheckRequiredFieldsDone(
continue;
}
if (autofill_field_formatter::FormatString(required_field.value_expression,
fallback_values_)
if (field_formatter::FormatAutofillString(required_field.value_expression,
fallback_values_)
.has_value()) {
has_fallbacks = true;
} else {
......@@ -192,7 +192,7 @@ void RequiredFieldsFallbackHandler::SetFallbackFieldValuesSequentially(
// Set the next field to its fallback value.
const RequiredField& required_field = required_fields_[required_fields_index];
auto fallback_value = autofill_field_formatter::FormatString(
auto fallback_value = field_formatter::FormatAutofillString(
required_field.value_expression, fallback_values_);
if (!fallback_value.has_value()) {
VLOG(3) << "No fallback for " << required_field.selector;
......
......@@ -28,7 +28,7 @@ class RequiredFieldsFallbackHandler {
public:
explicit RequiredFieldsFallbackHandler(
const std::vector<RequiredField>& required_fields,
const std::map<int, std::string>& fallback_values,
const std::map<std::string, std::string>& fallback_values,
ActionDelegate* delegate);
~RequiredFieldsFallbackHandler();
......@@ -87,7 +87,7 @@ class RequiredFieldsFallbackHandler {
ClientStatus client_status_;
std::vector<RequiredField> required_fields_;
std::map<int, std::string> fallback_values_;
std::map<std::string, std::string> fallback_values_;
base::OnceCallback<void(const ClientStatus&,
const base::Optional<ClientStatus>&)>
status_update_callback_;
......
......@@ -84,12 +84,14 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
CreateRequiredField("52", {"#card_number"}),
CreateRequiredField("-3", {"#card_network"})};
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL),
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL)),
"John Doe");
fallback_values.emplace(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_NETWORK), "");
fallback_values.emplace(base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NETWORK)),
"");
RequiredFieldsFallbackHandler fallback_handler(
required_fields, fallback_values, &mock_action_delegate_);
......@@ -144,13 +146,14 @@ TEST_F(RequiredFieldsFallbackHandlerTest, AddsFirstFieldFillingError) {
CreateRequiredField("51", {"#card_name"}),
CreateRequiredField("52", {"#card_number"})};
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL),
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL)),
"John Doe");
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NUMBER),
"4111111111111111");
fallback_values.emplace(base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_NUMBER)),
"4111111111111111");
RequiredFieldsFallbackHandler fallback_handler(
required_fields, fallback_values, &mock_action_delegate_);
......@@ -222,9 +225,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FillsEmptyRequiredField) {
std::vector<RequiredField> required_fields = {
CreateRequiredField("51", {"#card_name"})};
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL),
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL)),
"John Doe");
RequiredFieldsFallbackHandler fallback_handler(
......@@ -253,9 +257,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FallsBackForForcedFilledField) {
CreateRequiredField("51", {"#card_name"})};
required_fields[0].forced = true;
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL),
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL)),
"John Doe");
RequiredFieldsFallbackHandler fallback_handler(
......@@ -328,11 +333,14 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FillsFieldWithPattern) {
std::vector<RequiredField> required_fields = {
CreateRequiredField("${53}/${55}", {"#card_expiry"})};
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH), "08");
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH)),
"08");
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_4_DIGIT_YEAR),
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_EXP_4_DIGIT_YEAR)),
"2050");
RequiredFieldsFallbackHandler fallback_handler(
......@@ -361,9 +369,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
CreateRequiredField("53", {"#card_expiry"}),
CreateRequiredField("-3", {"#card_network"})};
std::map<int, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_NETWORK), "");
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NETWORK)),
"");
RequiredFieldsFallbackHandler fallback_handler(
required_fields, fallback_values, &mock_action_delegate_);
......@@ -408,35 +417,6 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
std::move(callback));
}
TEST_F(RequiredFieldsFallbackHandlerTest, IgnoresNonIntegerKeys) {
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
Expectation set_value =
EXPECT_CALL(mock_action_delegate_,
OnSetFieldValue(Eq(Selector({"#card_expiry"})), "${KEY}", _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.After(set_value)
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
std::vector<RequiredField> required_fields = {
CreateRequiredField("${KEY}", {"#card_expiry"})};
RequiredFieldsFallbackHandler fallback_handler(required_fields, {},
&mock_action_delegate_);
base::OnceCallback<void(const ClientStatus&,
const base::Optional<ClientStatus>&)>
callback =
base::BindOnce([](const ClientStatus& status,
const base::Optional<ClientStatus>& detail_status) {
EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
});
fallback_handler.CheckAndFallbackRequiredFields(OkClientStatus(),
std::move(callback));
}
TEST_F(RequiredFieldsFallbackHandlerTest, ClicksOnCustomDropdown) {
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
EXPECT_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _)).Times(0);
......@@ -458,9 +438,11 @@ TEST_F(RequiredFieldsFallbackHandlerTest, ClicksOnCustomDropdown) {
CreateRequiredField("53", {"#card_expiry"})};
required_fields[0].fallback_click_element = Selector({".option"});
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH), "08");
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH)),
"08");
RequiredFieldsFallbackHandler fallback_handler(
required_fields, fallback_values, &mock_action_delegate_);
......@@ -498,9 +480,11 @@ TEST_F(RequiredFieldsFallbackHandlerTest, CustomDropdownClicksStopOnError) {
CreateRequiredField("53", {"#card_expiry"})};
required_fields[0].fallback_click_element = Selector({".option"});
std::map<int, std::string> fallback_values;
std::map<std::string, std::string> fallback_values;
fallback_values.emplace(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH), "08");
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH)),
"08");
RequiredFieldsFallbackHandler fallback_handler(
required_fields, fallback_values, &mock_action_delegate_);
......
......@@ -15,8 +15,8 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/actions/fallback_handler/required_field.h"
#include "components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h"
#include "components/autofill_assistant/browser/autofill_field_formatter.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/field_formatter.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/value_util.h"
......@@ -173,8 +173,8 @@ void UseAddressAction::ExecuteFallback(const ClientStatus& status) {
DCHECK(fallback_handler_ == nullptr);
fallback_handler_ = std::make_unique<RequiredFieldsFallbackHandler>(
required_fields,
autofill_field_formatter::CreateAutofillMappings(*profile_,
/* locale = */ "en-US"),
field_formatter::CreateAutofillMappings(*profile_,
/* locale = */ "en-US"),
delegate_);
fallback_handler_->CheckAndFallbackRequiredFields(
......
......@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
......@@ -20,8 +21,8 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/actions/fallback_handler/required_field.h"
#include "components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h"
#include "components/autofill_assistant/browser/autofill_field_formatter.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/field_formatter.h"
#include "components/autofill_assistant/browser/user_model.h"
namespace autofill_assistant {
......@@ -150,14 +151,16 @@ void UseCreditCardAction::OnGetFullCard(
required_fields.emplace_back(required_field);
}
std::map<int, std::string> fallback_values =
autofill_field_formatter::CreateAutofillMappings(*card,
/* locale = */ "en-US");
std::map<std::string, std::string> fallback_values =
field_formatter::CreateAutofillMappings(*card,
/* locale = */ "en-US");
fallback_values.emplace(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_VERIFICATION_CODE),
base::NumberToString(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_VERIFICATION_CODE)),
base::UTF16ToUTF8(cvc));
fallback_values.emplace(
(int)AutofillFormatProto::CREDIT_CARD_RAW_NUMBER,
base::NumberToString(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_RAW_NUMBER)),
base::UTF16ToUTF8(card->GetRawInfo(autofill::CREDIT_CARD_NUMBER)));
DCHECK(fallback_handler_ == nullptr);
......
......@@ -9,7 +9,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill_assistant/browser/autofill_field_formatter.h"
#include "components/autofill_assistant/browser/field_formatter.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/trigger_context.h"
#include "components/autofill_assistant/browser/user_model.h"
......@@ -167,9 +167,9 @@ bool ValueToString(UserModel* user_model,
<< ": credit card not found";
return false;
}
auto formatted_string = autofill_field_formatter::FormatString(
auto formatted_string = field_formatter::FormatAutofillString(
proto.autofill_format().pattern(),
autofill_field_formatter::CreateAutofillMappings(
field_formatter::CreateAutofillMappings(
*credit_card, proto.autofill_format().locale()));
if (!formatted_string.has_value()) {
DVLOG(2) << "Error evaluating " << __func__
......@@ -191,9 +191,9 @@ bool ValueToString(UserModel* user_model,
DVLOG(2) << "Error evaluating " << __func__ << ": profile not found";
return false;
}
auto formatted_string = autofill_field_formatter::FormatString(
auto formatted_string = field_formatter::FormatAutofillString(
proto.autofill_format().pattern(),
autofill_field_formatter::CreateAutofillMappings(
field_formatter::CreateAutofillMappings(
*profile, proto.autofill_format().locale()));
if (!formatted_string.has_value()) {
DVLOG(2) << "Error evaluating " << __func__
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill_assistant/browser/autofill_field_formatter.h"
#include "components/autofill_assistant/browser/field_formatter.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
......@@ -13,28 +13,28 @@
#include "third_party/re2/src/re2/stringpiece.h"
namespace {
// Regex to find placeholders of the form ${N}, where N is an integer (possibly
// negative).
const char kPlaceholderExtractor[] = R"re(\$\{(-?\d+)\})re";
// Regex to find placeholders of the form ${key}, where key is an arbitrary
// string that does not contain curly braces.
const char kPlaceholderExtractor[] = R"re(\$\{([^{}]+)\})re";
base::Optional<std::string> GetFieldValue(
const std::map<int, std::string>& mappings,
int i) {
auto it = mappings.find(i);
const std::map<std::string, std::string>& mappings,
const std::string& key) {
auto it = mappings.find(key);
if (it == mappings.end()) {
return base::nullopt;
}
return it->second;
}
std::map<int, std::string> CreateFormGroupMappings(
std::map<std::string, std::string> CreateFormGroupMappings(
const autofill::FormGroup& form_group,
const std::string& locale) {
std::map<int, std::string> mappings;
std::map<std::string, std::string> mappings;
autofill::ServerFieldTypeSet available_fields;
form_group.GetNonEmptyTypes(locale, &available_fields);
for (const auto& field : available_fields) {
mappings.emplace(static_cast<int>(field),
mappings.emplace(base::NumberToString(static_cast<int>(field)),
base::UTF16ToUTF8(form_group.GetInfo(
autofill::AutofillType(field), locale)));
}
......@@ -44,11 +44,11 @@ std::map<int, std::string> CreateFormGroupMappings(
} // namespace
namespace autofill_assistant {
namespace autofill_field_formatter {
namespace field_formatter {
base::Optional<std::string> FormatString(
base::Optional<std::string> FormatAutofillString(
const std::string& pattern,
const std::map<int, std::string> mappings) {
const std::map<std::string, std::string>& mappings) {
if (pattern.empty()) {
return std::string();
}
......@@ -56,15 +56,26 @@ base::Optional<std::string> FormatString(
// Special case: if the input is a single number, interpret as ${N}.
int field_type;
if (base::StringToInt(pattern, &field_type)) {
return GetFieldValue(mappings, field_type);
return GetFieldValue(mappings, pattern);
}
return FormatString(pattern, mappings);
}
base::Optional<std::string> FormatString(
const std::string& pattern,
const std::map<std::string, std::string>& mappings) {
if (pattern.empty()) {
return std::string();
}
std::string key;
std::string out = pattern;
re2::StringPiece input(pattern);
while (re2::RE2::FindAndConsume(&input, kPlaceholderExtractor, &field_type)) {
auto rewrite_value = GetFieldValue(mappings, field_type);
while (re2::RE2::FindAndConsume(&input, kPlaceholderExtractor, &key)) {
auto rewrite_value = GetFieldValue(mappings, key);
if (!rewrite_value.has_value()) {
VLOG(2) << "No value for " << field_type << " in " << pattern;
VLOG(2) << "No value for " << key << " in " << pattern;
return base::nullopt;
}
......@@ -76,14 +87,15 @@ base::Optional<std::string> FormatString(
}
template <>
std::map<int, std::string> CreateAutofillMappings<autofill::AutofillProfile>(
std::map<std::string, std::string>
CreateAutofillMappings<autofill::AutofillProfile>(
const autofill::AutofillProfile& profile,
const std::string& locale) {
return CreateFormGroupMappings(profile, locale);
}
template <>
std::map<int, std::string> CreateAutofillMappings<autofill::CreditCard>(
std::map<std::string, std::string> CreateAutofillMappings<autofill::CreditCard>(
const autofill::CreditCard& credit_card,
const std::string& locale) {
auto mappings = CreateFormGroupMappings(credit_card, locale);
......@@ -92,24 +104,24 @@ std::map<int, std::string> CreateAutofillMappings<autofill::CreditCard>(
autofill::data_util::GetPaymentRequestData(credit_card.network())
.basic_card_issuer_network);
if (!network.empty()) {
mappings[static_cast<int>(AutofillFormatProto::CREDIT_CARD_NETWORK)] =
network;
mappings[base::NumberToString(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_NETWORK))] = network;
}
auto network_for_display = base::UTF16ToUTF8(credit_card.NetworkForDisplay());
if (!network_for_display.empty()) {
mappings[static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NETWORK_FOR_DISPLAY)] =
mappings[base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NETWORK_FOR_DISPLAY))] =
network_for_display;
}
auto last_four_digits = base::UTF16ToUTF8(credit_card.LastFourDigits());
if (!last_four_digits.empty()) {
mappings[static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NUMBER_LAST_FOUR_DIGITS)] =
mappings[base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NUMBER_LAST_FOUR_DIGITS))] =
last_four_digits;
}
return mappings;
}
} // namespace autofill_field_formatter
} // namespace field_formatter
} // namespace autofill_assistant
......@@ -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_ASSISTANT_BROWSER_AUTOFILL_FIELD_FORMATTER_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_FIELD_FORMATTER_H_
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_FIELD_FORMATTER_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_FIELD_FORMATTER_H_
#include <map>
#include <string>
......@@ -12,26 +12,33 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
namespace autofill_assistant {
namespace autofill_field_formatter {
namespace field_formatter {
// Replaces all placeholder occurrences of the form ${N} in |pattern| with the
// corresponding value in |mappings|. Returns the result or nullopt if any
// of the requested fields was not available. As a special case, input patterns
// Replaces all placeholder occurrences of the form ${key} in |input| with the
// corresponding value in |mappings|, where |key| is an arbitrary string that
// does not contain curly braces. Fails if any of the found placeholders is not
// in |mappings|.
base::Optional<std::string> FormatString(
const std::string& input,
const std::map<std::string, std::string>& mappings);
// Same as |FormatString|, but also supports a special case: input patterns
// containing a single integer are also allowed and implicitly interpreted as
// ${N}.
base::Optional<std::string> FormatString(
base::Optional<std::string> FormatAutofillString(
const std::string& pattern,
const std::map<int, std::string> mappings);
const std::map<std::string, std::string>& mappings);
// Creates a lookup map for all non-empty autofill and custom
// AutofillFormatProto::AutofillAssistantCustomField field types in
// |autofill_data_model|.
// |locale| should be a locale string such as "en-US".
template <typename T>
std::map<int, std::string> CreateAutofillMappings(const T& autofill_data_model,
const std::string& locale);
std::map<std::string, std::string> CreateAutofillMappings(
const T& autofill_data_model,
const std::string& locale);
} // namespace autofill_field_formatter
} // namespace field_formatter
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_FIELD_FORMATTER_H_
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_FIELD_FORMATTER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment