#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/form_field_data.h"
#include "grit/components_strings.h"
-#include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_data.h"
+#include "third_party/libaddressinput/chromium/addressinput_util.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
#include "ui/base/l10n/l10n_util.h"
using base::ASCIIToUTF16;
COMPANY_NAME,
};
+ std::vector<ServerFieldType> default_fields;
if (!suggested_fields) {
- DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
- distinguishing_fields->assign(
+ default_fields.assign(
kDefaultDistinguishingFields,
kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
- return;
+ if (excluded_field == UNKNOWN_TYPE) {
+ distinguishing_fields->swap(default_fields);
+ return;
+ }
+ suggested_fields = &default_fields;
}
// Keep track of which fields we've seen so that we avoid duplicate entries.
}
template <class T>
-void CopyValuesToItems(ServerFieldType type,
- const std::vector<base::string16>& values,
- std::vector<T>* form_group_items,
- const T& prototype) {
+void CopyRawValuesToItems(ServerFieldType type,
+ const std::vector<base::string16>& values,
+ const T& prototype,
+ std::vector<T>* form_group_items) {
form_group_items->resize(values.size(), prototype);
for (size_t i = 0; i < form_group_items->size(); ++i) {
(*form_group_items)[i].SetRawInfo(type, values[i]);
}
// Must have at least one (possibly empty) element.
- if (form_group_items->empty())
- form_group_items->resize(1, prototype);
+ form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
+}
+
+template <class T>
+void CopyValuesToItems(AutofillType type,
+ const std::vector<base::string16>& values,
+ const T& prototype,
+ const std::string& app_locale,
+ std::vector<T>* form_group_items) {
+ form_group_items->resize(values.size(), prototype);
+ for (size_t i = 0; i < form_group_items->size(); ++i) {
+ (*form_group_items)[i].SetInfo(type, values[i], app_locale);
+ }
+ // Must have at least one (possibly empty) element.
+ form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
}
template <class T>
const std::string& app_locale)
: phone_(phone),
country_code_(country_code),
- app_locale_(app_locale) {
- }
+ app_locale_(app_locale) {}
bool operator()(const base::string16& phone) {
return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
}
- bool operator()(const base::string16* phone) {
- return i18n::PhoneNumbersMatch(*phone, phone_, country_code_, app_locale_);
- }
-
private:
base::string16 phone_;
std::string country_code_;
};
// Functor used to check for case-insensitive equality of two strings.
-struct CaseInsensitiveStringEquals
- : public std::binary_function<base::string16, base::string16, bool>
-{
- bool operator()(const base::string16& x, const base::string16& y) const {
- return
- x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y);
+struct CaseInsensitiveStringEquals {
+ public:
+ CaseInsensitiveStringEquals(const base::string16& other)
+ : other_(other) {}
+
+ bool operator()(const base::string16& x) const {
+ return x.size() == other_.size() &&
+ base::StringToLowerASCII(x) == base::StringToLowerASCII(other_);
}
+
+ private:
+ const base::string16& other_;
};
} // namespace
if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
scoped_ptr< ::i18n::addressinput::AddressData> address_data =
i18n::CreateAddressDataFromAutofillProfile(*this, app_locale);
- if (!address_data->HasAllRequiredFields())
+ if (!addressinput::HasAllRequiredFields(*address_data))
return base::string16();
std::vector<std::string> lines;
- address_data->FormatForDisplay(&lines);
+ ::i18n::addressinput::GetFormattedNationalAddress(*address_data, &lines);
return base::UTF8ToUTF16(JoinString(lines, '\n'));
}
switch (AutofillType(type).group()) {
case NAME:
case NAME_BILLING:
- CopyValuesToItems(type, values, &name_, NameInfo());
+ CopyRawValuesToItems(type, values, NameInfo(), &name_);
break;
+
case EMAIL:
- CopyValuesToItems(type, values, &email_, EmailInfo());
+ CopyRawValuesToItems(type, values, EmailInfo(), &email_);
break;
+
case PHONE_HOME:
case PHONE_BILLING:
- CopyValuesToItems(type,
- values,
- &phone_number_,
- PhoneNumber(this));
+ CopyRawValuesToItems(type, values, PhoneNumber(this), &phone_number_);
break;
+
default:
- if (values.size() == 1) {
+ if (values.size() == 1U) {
SetRawInfo(type, values[0]);
- } else if (values.size() == 0) {
+ } else if (values.empty()) {
SetRawInfo(type, base::string16());
} else {
// Shouldn't attempt to set multiple values on single-valued field.
GetMultiInfoImpl(AutofillType(type), std::string(), values);
}
+void AutofillProfile::SetMultiInfo(const AutofillType& type,
+ const std::vector<base::string16>& values,
+ const std::string& app_locale) {
+ switch (AutofillType(type).group()) {
+ case NAME:
+ case NAME_BILLING:
+ CopyValuesToItems(type, values, NameInfo(), app_locale, &name_);
+ break;
+
+ case EMAIL:
+ CopyValuesToItems(type, values, EmailInfo(), app_locale, &email_);
+ break;
+
+ case PHONE_HOME:
+ case PHONE_BILLING:
+ CopyValuesToItems(
+ type, values, PhoneNumber(this), app_locale, &phone_number_);
+ break;
+
+ default:
+ if (values.size() == 1U) {
+ SetInfo(type, values[0], app_locale);
+ } else if (values.empty()) {
+ SetInfo(type, base::string16(), app_locale);
+ } else {
+ // Shouldn't attempt to set multiple values on single-valued field.
+ NOTREACHED();
+ }
+ break;
+ }
+}
+
void AutofillProfile::GetMultiInfo(const AutofillType& type,
const std::string& app_locale,
std::vector<base::string16>* values) const {
return comparison;
}
- const ServerFieldType multi_value_types[] = { NAME_FIRST,
+ const ServerFieldType multi_value_types[] = { NAME_FULL,
+ NAME_FIRST,
NAME_MIDDLE,
NAME_LAST,
EMAIL_ADDRESS,
app_locale)) {
return false;
}
- } else if (StringToLowerASCII(GetRawInfo(*it)) !=
- StringToLowerASCII(profile.GetRawInfo(*it))) {
+ } else if (base::StringToLowerASCII(GetRawInfo(*it)) !=
+ base::StringToLowerASCII(profile.GetRawInfo(*it))) {
return false;
}
}
}
void AutofillProfile::OverwriteOrAppendNames(
- const std::vector<NameInfo>& names) {
+ const std::vector<NameInfo>& names,
+ const std::string& app_locale) {
std::vector<NameInfo> results(name_);
for (std::vector<NameInfo>::const_iterator it = names.begin();
it != names.end();
for (size_t index = 0; index < name_.size(); ++index) {
NameInfo current_name = name_[index];
- if (current_name.EqualsIgnoreCase(imported_name)) {
+ if (current_name.ParsedNamesAreEqual(imported_name)) {
+ if (current_name.GetRawInfo(NAME_FULL).empty()) {
+ current_name.SetRawInfo(NAME_FULL,
+ imported_name.GetRawInfo(NAME_FULL));
+ }
+
should_append_imported_name = false;
break;
}
- base::string16 full_name = current_name.GetRawInfo(NAME_FULL);
- if (StringToLowerASCII(full_name) ==
- StringToLowerASCII(imported_name.GetRawInfo(NAME_FULL))) {
+ AutofillType type = AutofillType(NAME_FULL);
+ base::string16 full_name = current_name.GetInfo(type, app_locale);
+ if (base::StringToLowerASCII(full_name) ==
+ base::StringToLowerASCII(imported_name.GetInfo(type, app_locale))) {
// The imported name has the same full name string as one of the
// existing names for this profile. Because full names are
// _heuristically_ parsed into {first, middle, last} name components,
// parse, as this more likely represents the correct, user-input parse
// of the name.
NameInfo heuristically_parsed_name;
- heuristically_parsed_name.SetRawInfo(NAME_FULL, full_name);
- if (imported_name.EqualsIgnoreCase(heuristically_parsed_name)) {
+ heuristically_parsed_name.SetInfo(type, full_name, app_locale);
+ if (imported_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
should_append_imported_name = false;
break;
}
- if (current_name.EqualsIgnoreCase(heuristically_parsed_name)) {
+ if (current_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
results[index] = imported_name;
should_append_imported_name = false;
break;
for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
iter != field_types.end(); ++iter) {
- if (AutofillProfile::SupportsMultiValue(*iter)) {
- std::vector<base::string16> new_values;
- profile.GetRawMultiInfo(*iter, &new_values);
- std::vector<base::string16> existing_values;
- GetRawMultiInfo(*iter, &existing_values);
-
- // GetMultiInfo always returns at least one element, even if the profile
- // has no data stored for this field type.
- if (existing_values.size() == 1 && existing_values.front().empty())
- existing_values.clear();
-
- FieldTypeGroup group = AutofillType(*iter).group();
- for (std::vector<base::string16>::iterator value_iter =
- new_values.begin();
- value_iter != new_values.end(); ++value_iter) {
- // Don't add duplicates.
- if (group == PHONE_HOME) {
- AddPhoneIfUnique(*value_iter, app_locale, &existing_values);
- } else {
- std::vector<base::string16>::const_iterator existing_iter =
- std::find_if(
- existing_values.begin(), existing_values.end(),
- std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
- if (existing_iter == existing_values.end())
- existing_values.insert(existing_values.end(), *value_iter);
- }
- }
- if (group == NAME)
- OverwriteOrAppendNames(profile.name_);
- else
- SetRawMultiInfo(*iter, existing_values);
- } else {
+ FieldTypeGroup group = AutofillType(*iter).group();
+ // Special case names.
+ if (group == NAME) {
+ OverwriteOrAppendNames(profile.name_, app_locale);
+ continue;
+ }
+
+ // Single value field --- overwrite.
+ if (!AutofillProfile::SupportsMultiValue(*iter)) {
base::string16 new_value = profile.GetRawInfo(*iter);
- if (StringToLowerASCII(GetRawInfo(*iter)) !=
- StringToLowerASCII(new_value)) {
+ if (base::StringToLowerASCII(GetRawInfo(*iter)) !=
+ base::StringToLowerASCII(new_value)) {
SetRawInfo(*iter, new_value);
}
+ continue;
+ }
+
+ // Multi value field --- overwrite/append.
+ std::vector<base::string16> new_values;
+ profile.GetRawMultiInfo(*iter, &new_values);
+ std::vector<base::string16> existing_values;
+ GetRawMultiInfo(*iter, &existing_values);
+
+ // GetMultiInfo always returns at least one element, even if the profile
+ // has no data stored for this field type.
+ if (existing_values.size() == 1 && existing_values.front().empty())
+ existing_values.clear();
+
+ for (std::vector<base::string16>::iterator value_iter =
+ new_values.begin();
+ value_iter != new_values.end(); ++value_iter) {
+ // Don't add duplicates. Most types get case insensitive matching.
+ std::vector<base::string16>::const_iterator existing_iter;
+
+ if (group == PHONE_HOME) {
+ // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
+ // "(800)356-9377" and "356-9377" are considered the same.
+ std::string country_code =
+ base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
+ existing_iter =
+ std::find_if(existing_values.begin(), existing_values.end(),
+ FindByPhone(*value_iter, country_code, app_locale));
+ } else {
+ existing_iter =
+ std::find_if(existing_values.begin(), existing_values.end(),
+ CaseInsensitiveStringEquals(*value_iter));
+ }
+
+ if (existing_iter == existing_values.end())
+ existing_values.insert(existing_values.end(), *value_iter);
}
+
+ SetRawMultiInfo(*iter, existing_values);
}
}
// static
void AutofillProfile::CreateDifferentiatingLabels(
const std::vector<AutofillProfile*>& profiles,
+ const std::string& app_locale,
std::vector<base::string16>* labels) {
const size_t kMinimalFieldsShown = 2;
CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
- labels);
+ app_locale, labels);
DCHECK_EQ(profiles.size(), labels->size());
}
const std::vector<ServerFieldType>* suggested_fields,
ServerFieldType excluded_field,
size_t minimal_fields_shown,
+ const std::string& app_locale,
std::vector<base::string16>* labels) {
std::vector<ServerFieldType> fields_to_use;
GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
for (size_t i = 0; i < profiles.size(); ++i) {
base::string16 label =
profiles[i]->ConstructInferredLabel(fields_to_use,
- minimal_fields_shown);
+ minimal_fields_shown,
+ app_locale);
labels_to_profiles[label].push_back(i);
}
// We have more than one profile with the same label, so add
// differentiating fields.
CreateInferredLabelsHelper(profiles, it->second, fields_to_use,
- minimal_fields_shown, labels);
+ minimal_fields_shown, app_locale, labels);
}
}
}
}
}
-void AutofillProfile::AddPhoneIfUnique(
- const base::string16& phone,
- const std::string& app_locale,
- std::vector<base::string16>* existing_phones) {
- DCHECK(existing_phones);
- // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
- // "(800)356-9377" and "356-9377" are considered the same.
- std::string country_code =
- base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
- if (std::find_if(existing_phones->begin(), existing_phones->end(),
- FindByPhone(phone, country_code, app_locale)) ==
- existing_phones->end()) {
- existing_phones->push_back(phone);
- }
-}
-
base::string16 AutofillProfile::ConstructInferredLabel(
const std::vector<ServerFieldType>& included_fields,
- size_t num_fields_to_use) const {
+ size_t num_fields_to_use,
+ const std::string& app_locale) const {
const base::string16 separator =
l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
included_fields.begin();
it != included_fields.end() && num_fields_used < num_fields_to_use;
++it) {
- base::string16 field = GetRawInfo(*it);
+ base::string16 field = GetInfo(AutofillType(*it), app_locale);
if (field.empty())
continue;
const std::list<size_t>& indices,
const std::vector<ServerFieldType>& fields,
size_t num_fields_to_include,
+ const std::string& app_locale,
std::vector<base::string16>* labels) {
// For efficiency, we first construct a map of fields to their text values and
// each value's frequency.
for (std::list<size_t>::const_iterator it = indices.begin();
it != indices.end(); ++it) {
const AutofillProfile* profile = profiles[*it];
- base::string16 field_text = profile->GetRawInfo(*field);
+ base::string16 field_text =
+ profile->GetInfo(AutofillType(*field), app_locale);
// If this label is not already in the map, add it with frequency 0.
if (!field_text_frequencies.count(field_text))
for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
field != fields.end(); ++field) {
// Skip over empty fields.
- base::string16 field_text = profile->GetRawInfo(*field);
+ base::string16 field_text =
+ profile->GetInfo(AutofillType(*field), app_locale);
if (field_text.empty())
continue;
break;
}
- (*labels)[*it] =
- profile->ConstructInferredLabel(label_fields, label_fields.size());
+ (*labels)[*it] = profile->ConstructInferredLabel(
+ label_fields, label_fields.size(), app_locale);
}
}
case NO_GROUP:
case CREDIT_CARD:
case PASSWORD_FIELD:
+ case TRANSACTION:
return NULL;
}