| Index: components/autofill/core/browser/country_names.cc
|
| diff --git a/components/autofill/core/browser/country_names.cc b/components/autofill/core/browser/country_names.cc
|
| index ce94dbb1591661fa3b576c383c47c73ca5b5d26d..f5b4cdff3aa87b02b3eec2379bdbe69a5d563dec 100644
|
| --- a/components/autofill/core/browser/country_names.cc
|
| +++ b/components/autofill/core/browser/country_names.cc
|
| @@ -7,6 +7,7 @@
|
| #include <stdint.h>
|
| #include <utility>
|
|
|
| +#include "base/lazy_instance.h"
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/memory/singleton.h"
|
| @@ -21,6 +22,11 @@
|
| namespace autofill {
|
| namespace {
|
|
|
| +// A copy of the application locale string, which should be ready for
|
| +// CountryName's construction.
|
| +static base::LazyInstance<std::string> g_application_locale =
|
| + LAZY_INSTANCE_INITIALIZER;
|
| +
|
| // Returns the ICU sort key corresponding to |str| for the given |collator|.
|
| // Uses |buffer| as temporary storage, and might resize |buffer| as a side-
|
| // effect. |buffer_size| should specify the |buffer|'s size, and is updated if
|
| @@ -74,6 +80,60 @@ std::map<std::string, std::string> GetCommonNames() {
|
| return common_names;
|
| }
|
|
|
| +// Creates collator for |locale| and sets its attributes as needed.
|
| +scoped_ptr<icu::Collator> CreateCollator(const icu::Locale& locale) {
|
| + scoped_ptr<icu::Collator> collator(
|
| + autofill::l10n::GetCollatorForLocale(locale));
|
| + if (!collator)
|
| + return nullptr;
|
| +
|
| + // Compare case-insensitively and ignoring punctuation.
|
| + UErrorCode ignored = U_ZERO_ERROR;
|
| + collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored);
|
| + ignored = U_ZERO_ERROR;
|
| + collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored);
|
| +
|
| + return collator;
|
| +}
|
| +
|
| +// If |locale| is different from "en_US", returns a collator for "en_US" and
|
| +// sets its attributes as appropriate. Otherwise returns null.
|
| +scoped_ptr<icu::Collator> CreateDefaultCollator(const icu::Locale& locale) {
|
| + icu::Locale default_locale("en_US");
|
| +
|
| + if (default_locale != locale)
|
| + return CreateCollator(default_locale);
|
| +
|
| + return nullptr;
|
| +}
|
| +
|
| +// Returns the mapping of country names localized to |locale| to their
|
| +// corresponding country codes. The provided |collator| should be suitable for
|
| +// the locale. The collator being null is handled gracefully by returning an
|
| +// empty map, to account for the very rare cases when the collator fails to
|
| +// initialize.
|
| +std::map<std::string, std::string> GetLocalizedNames(
|
| + const std::string& locale,
|
| + const icu::Collator* collator) {
|
| + if (!collator)
|
| + return std::map<std::string, std::string>();
|
| +
|
| + std::map<std::string, std::string> localized_names;
|
| + int32_t buffer_size = 1000;
|
| + scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
|
| +
|
| + for (const std::string& country_code :
|
| + CountryDataMap::GetInstance()->country_codes()) {
|
| + base::string16 country_name =
|
| + l10n_util::GetDisplayNameForCountry(country_code, locale);
|
| + std::string sort_key =
|
| + GetSortKey(*collator, country_name, &buffer, &buffer_size);
|
| +
|
| + localized_names.insert(std::make_pair(sort_key, country_code));
|
| + }
|
| + return localized_names;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // static
|
| @@ -81,12 +141,35 @@ CountryNames* CountryNames::GetInstance() {
|
| return base::Singleton<CountryNames>::get();
|
| }
|
|
|
| -CountryNames::CountryNames() : common_names_(GetCommonNames()) {}
|
| +// static
|
| +void CountryNames::SetLocaleString(std::string locale) {
|
| + DCHECK(!locale.empty());
|
| + // Application locale should never be empty. The empty value of
|
| + // |g_application_locale| means that it has not been initialized yet.
|
| + std::string* storage = g_application_locale.Pointer();
|
| + if (storage->empty()) {
|
| + *storage = std::move(locale);
|
| + }
|
| + // TODO(crbug.com/579971) CountryNames currently cannot adapt to changed
|
| + // locale without Chrome's restart.
|
| +}
|
| +
|
| +CountryNames::CountryNames(const std::string& locale_name)
|
| + : locale_(locale_name.c_str()),
|
| + collator_(CreateCollator(locale_)),
|
| + default_collator_(CreateDefaultCollator(locale_)),
|
| + common_names_(GetCommonNames()),
|
| + localized_names_(GetLocalizedNames(locale_name, collator_.get())),
|
| + default_localized_names_(
|
| + GetLocalizedNames("en_US", default_collator_.get())) {}
|
| +
|
| +CountryNames::CountryNames() : CountryNames(g_application_locale.Get()) {
|
| + DCHECK(!g_application_locale.Get().empty());
|
| +}
|
|
|
| CountryNames::~CountryNames() = default;
|
|
|
| -const std::string CountryNames::GetCountryCode(const base::string16& country,
|
| - const std::string& locale_name) {
|
| +const std::string CountryNames::GetCountryCode(const base::string16& country) {
|
| // First, check common country names, including 2- and 3-letter country codes.
|
| std::string country_utf8 = base::UTF16ToUTF8(base::ToUpperASCII(country));
|
| const auto result = common_names_.find(country_utf8);
|
| @@ -94,66 +177,33 @@ const std::string CountryNames::GetCountryCode(const base::string16& country,
|
| return result->second;
|
|
|
| // Next, check country names localized to the current locale.
|
| - icu::Locale locale(locale_name.c_str());
|
| - std::string country_code = GetCountryCodeForLocalizedName(country, locale);
|
| + std::string country_code =
|
| + GetCountryCodeForLocalizedName(country, localized_names_, *collator_);
|
| if (!country_code.empty())
|
| return country_code;
|
|
|
| - icu::Locale default_locale("en_US");
|
| // Finally, check country names localized to US English, unless done already.
|
| - if (default_locale != locale)
|
| - return GetCountryCodeForLocalizedName(country, default_locale);
|
| -
|
| - return std::string();
|
| -}
|
| -
|
| -void CountryNames::AddLocalizedNamesForLocale(const std::string& locale,
|
| - const icu::Collator& collator) {
|
| - // Nothing to do if we've previously added the localized names for the given
|
| - // |locale|.
|
| - if (locales_to_localized_names_.count(locale))
|
| - return;
|
| -
|
| - std::map<std::string, std::string> localized_names;
|
| - int32_t buffer_size = 1000;
|
| - scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
|
| -
|
| - for (const std::string& country_code :
|
| - CountryDataMap::GetInstance()->country_codes()) {
|
| - base::string16 country_name =
|
| - l10n_util::GetDisplayNameForCountry(country_code, locale);
|
| - std::string sort_key =
|
| - GetSortKey(collator, country_name, &buffer, &buffer_size);
|
| -
|
| - localized_names.insert(std::make_pair(sort_key, country_code));
|
| + if (default_collator_) {
|
| + return GetCountryCodeForLocalizedName(country, default_localized_names_,
|
| + *default_collator_);
|
| }
|
|
|
| - locales_to_localized_names_.insert(std::make_pair(locale, localized_names));
|
| + return std::string();
|
| }
|
|
|
| const std::string CountryNames::GetCountryCodeForLocalizedName(
|
| const base::string16& country_name,
|
| - const icu::Locale& locale) {
|
| - const icu::Collator* collator = GetCollatorForLocale(locale);
|
| - // In very rare cases, the collator fails to initialize.
|
| - if (!collator)
|
| - return std::string();
|
| -
|
| - std::string locale_name = locale.getName();
|
| - AddLocalizedNamesForLocale(locale_name, *collator);
|
| -
|
| + const std::map<std::string, std::string>& localized_names,
|
| + const icu::Collator& collator) {
|
| // As recommended[1] by ICU, initialize the buffer size to four times the
|
| // source string length.
|
| // [1] http://userguide.icu-project.org/collation/api#TOC-Examples
|
| int32_t buffer_size = country_name.size() * 4;
|
| scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
|
| std::string sort_key =
|
| - GetSortKey(*collator, country_name, &buffer, &buffer_size);
|
| + GetSortKey(collator, country_name, &buffer, &buffer_size);
|
|
|
| - const std::map<std::string, std::string>& localized_names =
|
| - locales_to_localized_names_[locale_name];
|
| - std::map<std::string, std::string>::const_iterator result =
|
| - localized_names.find(sort_key);
|
| + auto result = localized_names.find(sort_key);
|
|
|
| if (result != localized_names.end())
|
| return result->second;
|
| @@ -161,25 +211,4 @@ const std::string CountryNames::GetCountryCodeForLocalizedName(
|
| return std::string();
|
| }
|
|
|
| -const icu::Collator* CountryNames::GetCollatorForLocale(
|
| - const icu::Locale& locale) {
|
| - std::string locale_name = locale.getName();
|
| - if (!ContainsKey(collators_, locale_name)) {
|
| - scoped_ptr<icu::Collator> collator(
|
| - autofill::l10n::GetCollatorForLocale(locale));
|
| - if (!collator)
|
| - return nullptr;
|
| -
|
| - // Compare case-insensitively and ignoring punctuation.
|
| - UErrorCode ignored = U_ZERO_ERROR;
|
| - collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored);
|
| - ignored = U_ZERO_ERROR;
|
| - collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored);
|
| -
|
| - collators_[locale_name] = std::move(collator);
|
| - }
|
| -
|
| - return collators_[locale_name].get();
|
| -}
|
| -
|
| } // namespace autofill
|
|
|