summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gyp3
-rw-r--r--base/i18n/case_conversion.cc34
-rw-r--r--base/i18n/case_conversion.h27
-rw-r--r--base/i18n/case_conversion_unittest.cc39
-rw-r--r--chrome/browser/autocomplete/search_provider.cc3
-rw-r--r--chrome/browser/bookmarks/bookmark_index.cc8
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc11
-rw-r--r--chrome/browser/download/download_item.cc9
-rw-r--r--chrome/browser/download/download_manager.cc3
-rw-r--r--chrome/browser/enumerate_modules_model_win.cc7
-rw-r--r--chrome/browser/history/in_memory_url_index.cc11
-rw-r--r--chrome/browser/history/query_parser.cc5
-rw-r--r--chrome/browser/history/url_database.cc7
-rw-r--r--chrome/browser/instant/instant_loader.cc9
-rw-r--r--chrome/browser/search_engines/template_url.cc3
-rw-r--r--chrome/browser/search_engines/template_url_model.cc3
-rw-r--r--chrome/browser/ui/gtk/edit_search_engine_dialog.cc3
-rw-r--r--chrome/browser/ui/views/shell_dialogs_win.cc3
-rw-r--r--chrome/browser/webdata/autofill_table.cc7
-rw-r--r--chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc3
-rw-r--r--net/ftp/ftp_directory_listing_parser_unittest.cc215
-rw-r--r--net/ftp/ftp_util.cc112
-rw-r--r--tools/valgrind/gtest_exclude/net_unittests.gtest-tsan.txt3
-rw-r--r--ui/base/l10n/l10n_util.cc20
-rw-r--r--ui/base/l10n/l10n_util.h6
-rw-r--r--ui/base/l10n/l10n_util_unittest.cc18
-rw-r--r--views/controls/menu/menu_controller.cc6
-rw-r--r--views/controls/menu/menu_item_view.cc7
-rw-r--r--views/controls/textfield/native_textfield_win.cc5
29 files changed, 359 insertions, 231 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 868e20e..da5d018 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -37,6 +37,8 @@
'i18n/break_iterator.h',
'i18n/char_iterator.cc',
'i18n/char_iterator.h',
+ 'i18n/case_conversion.cc',
+ 'i18n/case_conversion.h',
'i18n/file_util_icu.cc',
'i18n/file_util_icu.h',
'i18n/icu_encoding_detection.cc',
@@ -126,6 +128,7 @@
'id_map_unittest.cc',
'i18n/break_iterator_unittest.cc',
'i18n/char_iterator_unittest.cc',
+ 'i18n/case_conversion_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
'i18n/rtl_unittest.cc',
diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc
new file mode 100644
index 0000000..2dedade
--- /dev/null
+++ b/base/i18n/case_conversion.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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/i18n/case_conversion.h"
+
+#include "base/utf_string_conversions.h"
+#include "unicode/unistr.h"
+
+namespace base {
+namespace i18n {
+
+string16 ToLower(const string16& string) {
+ icu::UnicodeString unicode_string(string.c_str(), string.size());
+ unicode_string.toLower();
+ return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+std::wstring WideToLower(const std::wstring& string) {
+ return UTF16ToWide(ToLower(WideToUTF16(string)));
+}
+
+string16 ToUpper(const string16& string) {
+ icu::UnicodeString unicode_string(string.c_str(), string.size());
+ unicode_string.toUpper();
+ return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+std::wstring WideToUpper(const std::wstring& string) {
+ return UTF16ToWide(ToUpper(WideToUTF16(string)));
+}
+
+} // namespace i18n
+} // namespace base
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h
new file mode 100644
index 0000000..d834ede
--- /dev/null
+++ b/base/i18n/case_conversion.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 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 BASE_I18N_CASE_CONVERSION_
+#define BASE_I18N_CASE_CONVERSION_
+#pragma once
+
+#include <string>
+
+#include "base/string16.h"
+
+namespace base {
+namespace i18n {
+
+// Returns the lower case equivalent of string. Uses ICU's default locale.
+string16 ToLower(const string16& string);
+std::wstring WideToLower(const std::wstring& string);
+
+// Returns the upper case equivalent of string. Uses ICU's default locale.
+string16 ToUpper(const string16& string);
+std::wstring WideToUpper(const std::wstring& string);
+
+} // namespace i18n
+} // namespace base
+
+#endif // BASE_I18N_CASE_CONVERSION_
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc
new file mode 100644
index 0000000..87a349e
--- /dev/null
+++ b/base/i18n/case_conversion_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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/i18n/case_conversion.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Test upper and lower case string conversion.
+TEST(CaseConversionTest, UpperLower) {
+ string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
+ const string16 expected_lower(ASCIIToUTF16("text with upper & lower case."));
+ const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE."));
+
+ string16 result = base::i18n::ToLower(mixed);
+ EXPECT_EQ(expected_lower, result);
+
+ result = base::i18n::ToUpper(mixed);
+ EXPECT_EQ(expected_upper, result);
+}
+
+// Test upper and lower case string conversion.
+TEST(CaseConversionTest, WideUpperLower) {
+ std::wstring mixed(L"Text with UPPer & lowER casE.");
+ const std::wstring expected_lower(L"text with upper & lower case.");
+ const std::wstring expected_upper(L"TEXT WITH UPPER & LOWER CASE.");
+
+ std::wstring result = base::i18n::WideToLower(mixed);
+ EXPECT_EQ(expected_lower, result);
+
+ result = base::i18n::WideToUpper(mixed);
+ EXPECT_EQ(expected_upper, result);
+}
+
+// TODO(jshin): More tests are needed, especially with non-ASCII characters.
+
+} // namespace
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index fd40f47..235341c 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -8,6 +8,7 @@
#include <cmath>
#include "base/callback.h"
+#include "base/i18n/case_conversion.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/message_loop.h"
#include "base/string16.h"
@@ -836,7 +837,7 @@ void SearchProvider::AddMatchToMap(const string16& query_string,
// NOTE: Keep this ToLower() call in sync with url_database.cc.
const std::pair<MatchMap::iterator, bool> i = map->insert(
std::pair<string16, AutocompleteMatch>(
- l10n_util::ToLower(query_string), match));
+ base::i18n::ToLower(query_string), match));
// NOTE: We purposefully do a direct relevance comparison here instead of
// using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added
// first" rather than "items alphabetically first" when the scores are equal.
diff --git a/chrome/browser/bookmarks/bookmark_index.cc b/chrome/browser/bookmarks/bookmark_index.cc
index c247cb5..875140f 100644
--- a/chrome/browser/bookmarks/bookmark_index.cc
+++ b/chrome/browser/bookmarks/bookmark_index.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -8,6 +8,7 @@
#include <iterator>
#include <list>
+#include "base/i18n/case_conversion.h"
#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -242,8 +243,9 @@ std::vector<string16> BookmarkIndex::ExtractQueryWords(const string16& query) {
if (query.empty())
return std::vector<string16>();
QueryParser parser;
- // TODO: use ICU normalization.
- parser.ExtractQueryWords(l10n_util::ToLower(query), &terms);
+ // TODO(brettw): use ICU normalization:
+ // http://userguide.icu-project.org/transforms/normalization
+ parser.ExtractQueryWords(base::i18n::ToLower(query), &terms);
return terms;
}
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index 6090ea1..d5846a6 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/file_path.h"
+#include "base/i18n/case_conversion.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
@@ -194,10 +195,10 @@ bool DoesBookmarkContainWords(const BookmarkNode* node,
const std::string& languages) {
return
DoesBookmarkTextContainWords(
- l10n_util::ToLower(node->GetTitle()), words) ||
+ base::i18n::ToLower(node->GetTitle()), words) ||
DoesBookmarkTextContainWords(
- l10n_util::ToLower(UTF8ToUTF16(node->GetURL().spec())), words) ||
- DoesBookmarkTextContainWords(l10n_util::ToLower(
+ base::i18n::ToLower(UTF8ToUTF16(node->GetURL().spec())), words) ||
+ DoesBookmarkTextContainWords(base::i18n::ToLower(
net::FormatUrl(node->GetURL(), languages, net::kFormatUrlOmitNothing,
UnescapeRule::NORMAL, NULL, NULL, NULL)), words);
}
@@ -519,7 +520,7 @@ void GetBookmarksContainingText(BookmarkModel* model,
std::vector<const BookmarkNode*>* nodes) {
std::vector<string16> words;
QueryParser parser;
- parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
+ parser.ExtractQueryWords(base::i18n::ToLower(text), &words);
if (words.empty())
return;
@@ -539,7 +540,7 @@ bool DoesBookmarkContainText(const BookmarkNode* node,
const std::string& languages) {
std::vector<string16> words;
QueryParser parser;
- parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
+ parser.ExtractQueryWords(base::i18n::ToLower(text), &words);
if (words.empty())
return false;
diff --git a/chrome/browser/download/download_item.cc b/chrome/browser/download/download_item.cc
index 54165a9..ffbd4b2a 100644
--- a/chrome/browser/download/download_item.cc
+++ b/chrome/browser/download/download_item.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/format_macros.h"
+#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/stringprintf.h"
@@ -538,9 +539,9 @@ bool DownloadItem::MatchesQuery(const string16& query) const {
if (query.empty())
return true;
- DCHECK_EQ(query, l10n_util::ToLower(query));
+ DCHECK_EQ(query, base::i18n::ToLower(query));
- string16 url_raw(l10n_util::ToLower(UTF8ToUTF16(url().spec())));
+ string16 url_raw(base::i18n::ToLower(UTF8ToUTF16(url().spec())));
if (url_raw.find(query) != string16::npos)
return true;
@@ -551,11 +552,11 @@ bool DownloadItem::MatchesQuery(const string16& query) const {
// "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"
PrefService* prefs = download_manager_->profile()->GetPrefs();
std::string languages(prefs->GetString(prefs::kAcceptLanguages));
- string16 url_formatted(l10n_util::ToLower(net::FormatUrl(url(), languages)));
+ string16 url_formatted(base::i18n::ToLower(net::FormatUrl(url(), languages)));
if (url_formatted.find(query) != string16::npos)
return true;
- string16 path(l10n_util::ToLower(full_path().LossyDisplayName()));
+ string16 path(base::i18n::ToLower(full_path().LossyDisplayName()));
// This shouldn't just do a substring match; it is wrong for Unicode
// due to normalization and we have a fancier search-query system
// used elsewhere.
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index f7e05f7..6ef4a2b 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -6,6 +6,7 @@
#include "base/callback.h"
#include "base/file_util.h"
+#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/rand_util.h"
@@ -191,7 +192,7 @@ void DownloadManager::SearchDownloads(const string16& query,
std::vector<DownloadItem*>* result) {
DCHECK(result);
- string16 query_lower(l10n_util::ToLower(query));
+ string16 query_lower(base::i18n::ToLower(query));
for (DownloadMap::iterator it = history_downloads_.begin();
it != history_downloads_.end(); ++it) {
diff --git a/chrome/browser/enumerate_modules_model_win.cc b/chrome/browser/enumerate_modules_model_win.cc
index 69315e9..78ea9d1 100644
--- a/chrome/browser/enumerate_modules_model_win.cc
+++ b/chrome/browser/enumerate_modules_model_win.cc
@@ -11,6 +11,7 @@
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_version_info_win.h"
+#include "base/i18n/case_conversion.h"
#include "base/metrics/histogram.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
@@ -274,7 +275,7 @@ void ModuleEnumerator::NormalizeModule(Module* module) {
if (!ConvertToLongPath(path, &module->location))
module->location = path;
- module->location = l10n_util::ToLower(module->location);
+ module->location = base::i18n::ToLower(module->location);
// Location contains the filename, so the last slash is where the path
// ends.
@@ -586,8 +587,8 @@ void ModuleEnumerator::PreparePathMappings() {
std::string path;
if (environment->GetVar(WideToASCII(*variable).c_str(), &path)) {
path_mapping_.push_back(
- std::make_pair(l10n_util::ToLower(UTF8ToWide(path)) + L"\\",
- L"%" + l10n_util::ToLower(*variable) + L"%"));
+ std::make_pair(base::i18n::WideToLower(UTF8ToWide(path)) + L"\\",
+ L"%" + base::i18n::ToLower(*variable) + L"%"));
}
}
}
diff --git a/chrome/browser/history/in_memory_url_index.cc b/chrome/browser/history/in_memory_url_index.cc
index 2fc67ec..f2c2bf3 100644
--- a/chrome/browser/history/in_memory_url_index.cc
+++ b/chrome/browser/history/in_memory_url_index.cc
@@ -12,6 +12,7 @@
#include "base/file_util.h"
#include "base/i18n/break_iterator.h"
+#include "base/i18n/case_conversion.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/time.h"
@@ -180,7 +181,7 @@ bool InMemoryURLIndex::IndexRow(const URLRow& row) {
history_info_map_[history_id] = new_row;
// Split URL into individual, unique words then add in the title words.
- url = l10n_util::ToLower(url);
+ url = base::i18n::ToLower(url);
String16Set url_words = WordSetFromString16(url);
String16Set title_words = WordSetFromString16(row.title());
String16Set words;
@@ -353,7 +354,7 @@ ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms(
String16Vector lower_terms;
for (String16Vector::const_iterator term_iter = terms.begin();
term_iter != terms.end(); ++term_iter)
- lower_terms.push_back(l10n_util::ToLower(*term_iter));
+ lower_terms.push_back(base::i18n::ToLower(*term_iter));
String16Vector::value_type all_terms(JoinString(lower_terms, ' '));
HistoryIDSet history_id_set = HistoryIDSetFromWords(all_terms);
@@ -477,7 +478,7 @@ InMemoryURLIndex::String16Set InMemoryURLIndex::WordSetFromString16(
String16Set word_set;
for (String16Vector::const_iterator iter = words.begin(); iter != words.end();
++iter)
- word_set.insert(l10n_util::ToLower(*iter));
+ word_set.insert(base::i18n::ToLower(*iter));
return word_set;
}
@@ -710,8 +711,8 @@ ScoredHistoryMatch InMemoryURLIndex::ScoredMatchForURL(
// Figure out where each search term appears in the URL and/or page title
// so that we can score as well as provide autocomplete highlighting.
- string16 url = l10n_util::ToLower(UTF8ToUTF16(gurl.spec()));
- string16 title = l10n_util::ToLower(row.title());
+ string16 url = base::i18n::ToLower(UTF8ToUTF16(gurl.spec()));
+ string16 title = base::i18n::ToLower(row.title());
int term_num = 0;
for (String16Vector::const_iterator iter = terms.begin(); iter != terms.end();
++iter, ++term_num) {
diff --git a/chrome/browser/history/query_parser.cc b/chrome/browser/history/query_parser.cc
index d2957f3..628879b 100644
--- a/chrome/browser/history/query_parser.cc
+++ b/chrome/browser/history/query_parser.cc
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/i18n/break_iterator.h"
+#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
@@ -313,7 +314,7 @@ int QueryParser::ParseQuery(const string16& query, string16* sqlite_query) {
void QueryParser::ParseQuery(const string16& query,
std::vector<QueryNode*>* nodes) {
QueryNodeList root;
- if (ParseQueryImpl(l10n_util::ToLower(query), &root))
+ if (ParseQueryImpl(base::i18n::ToLower(query), &root))
nodes->swap(*root.children());
}
@@ -333,7 +334,7 @@ bool QueryParser::DoesQueryMatch(const string16& text,
return false;
std::vector<QueryWord> query_words;
- string16 lower_text = l10n_util::ToLower(text);
+ string16 lower_text = base::i18n::ToLower(text);
ExtractQueryWords(lower_text, &query_words);
if (query_words.empty())
diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc
index 78ca0c5..cc9bf9e 100644
--- a/chrome/browser/history/url_database.cc
+++ b/chrome/browser/history/url_database.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -10,6 +10,7 @@
#include <vector>
#include "app/sql/statement.h"
+#include "base/i18n/case_conversion.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -426,7 +427,7 @@ bool URLDatabase::SetKeywordSearchTermsForURL(URLID url_id,
statement.BindInt64(0, keyword_id);
statement.BindInt64(1, url_id);
- statement.BindString16(2, l10n_util::ToLower(term));
+ statement.BindString16(2, base::i18n::ToLower(term));
statement.BindString16(3, term);
return statement.Run();
}
@@ -485,7 +486,7 @@ void URLDatabase::GetMostRecentKeywordSearchTerms(
return;
// NOTE: Keep this ToLower() call in sync with search_provider.cc.
- string16 lower_prefix = l10n_util::ToLower(prefix);
+ string16 lower_prefix = base::i18n::ToLower(prefix);
// This magic gives us a prefix search.
string16 next_prefix = lower_prefix;
next_prefix[next_prefix.size() - 1] =
diff --git a/chrome/browser/instant/instant_loader.cc b/chrome/browser/instant/instant_loader.cc
index a1920a0..ca99bea 100644
--- a/chrome/browser/instant/instant_loader.cc
+++ b/chrome/browser/instant/instant_loader.cc
@@ -10,6 +10,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/i18n/case_conversion.h"
#include "base/string_number_conversions.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
@@ -685,9 +686,9 @@ bool InstantLoader::Update(TabContentsWrapper* tab_contents,
host->Send(new ViewMsg_SearchBoxChange(
host->routing_id(), user_text_, verbatim, text_length, text_length));
- string16 complete_suggested_text_lower = l10n_util::ToLower(
+ string16 complete_suggested_text_lower = base::i18n::ToLower(
complete_suggested_text_);
- string16 user_text_lower = l10n_util::ToLower(user_text_);
+ string16 user_text_lower = base::i18n::ToLower(user_text_);
if (!verbatim &&
complete_suggested_text_lower.size() > user_text_lower.size() &&
!complete_suggested_text_lower.compare(0, user_text_lower.size(),
@@ -841,8 +842,8 @@ void InstantLoader::SetCompleteSuggestedText(
return;
}
- string16 user_text_lower = l10n_util::ToLower(user_text_);
- string16 complete_suggested_text_lower = l10n_util::ToLower(
+ string16 user_text_lower = base::i18n::ToLower(user_text_);
+ string16 complete_suggested_text_lower = base::i18n::ToLower(
complete_suggested_text);
last_suggestion_.clear();
if (user_text_lower.compare(0, user_text_lower.size(),
diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc
index 5952fdb3..1d276aa6 100644
--- a/chrome/browser/search_engines/template_url.cc
+++ b/chrome/browser/search_engines/template_url.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/search_engines/template_url.h"
+#include "base/i18n/case_conversion.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
@@ -628,7 +629,7 @@ void TemplateURL::SetInstantURL(const std::string& url,
void TemplateURL::set_keyword(const string16& keyword) {
// Case sensitive keyword matching is confusing. As such, we force all
// keywords to be lower case.
- keyword_ = l10n_util::ToLower(keyword);
+ keyword_ = base::i18n::ToLower(keyword);
autogenerate_keyword_ = false;
}
diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc
index 5e3d234..a2def18 100644
--- a/chrome/browser/search_engines/template_url_model.cc
+++ b/chrome/browser/search_engines/template_url_model.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/environment.h"
+#include "base/i18n/case_conversion.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
@@ -153,7 +154,7 @@ string16 TemplateURLModel::GenerateKeyword(const GURL& url,
// static
string16 TemplateURLModel::CleanUserInputKeyword(const string16& keyword) {
// Remove the scheme.
- string16 result(l10n_util::ToLower(keyword));
+ string16 result(base::i18n::ToLower(keyword));
url_parse::Component scheme_component;
if (url_parse::ExtractScheme(UTF16ToUTF8(keyword).c_str(),
static_cast<int>(keyword.length()),
diff --git a/chrome/browser/ui/gtk/edit_search_engine_dialog.cc b/chrome/browser/ui/gtk/edit_search_engine_dialog.cc
index a3e4940..24863f6 100644
--- a/chrome/browser/ui/gtk/edit_search_engine_dialog.cc
+++ b/chrome/browser/ui/gtk/edit_search_engine_dialog.cc
@@ -6,6 +6,7 @@
#include <gtk/gtk.h>
+#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
@@ -33,7 +34,7 @@ std::string GetDisplayURL(const TemplateURL& turl) {
void LowercaseInsertTextHandler(GtkEditable *editable, const gchar *text,
gint length, gint *position, gpointer data) {
string16 original_text = UTF8ToUTF16(text);
- string16 lower_text = l10n_util::ToLower(original_text);
+ string16 lower_text = base::i18n::ToLower(original_text);
if (lower_text != original_text) {
std::string result = UTF16ToUTF8(lower_text);
// Prevent ourselves getting called recursively about our own edit.
diff --git a/chrome/browser/ui/views/shell_dialogs_win.cc b/chrome/browser/ui/views/shell_dialogs_win.cc
index 5eba0de4..691f050 100644
--- a/chrome/browser/ui/views/shell_dialogs_win.cc
+++ b/chrome/browser/ui/views/shell_dialogs_win.cc
@@ -13,6 +13,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/i18n/case_conversion.h"
#include "base/message_loop.h"
#include "base/string_split.h"
#include "base/threading/thread.h"
@@ -143,7 +144,7 @@ std::wstring FormatFilterForExtensions(
// the we create a description "QQQ File (.qqq)").
include_all_files = true;
desc = l10n_util::GetStringFUTF16(IDS_APP_SAVEAS_EXTENSION_FORMAT,
- l10n_util::ToUpper(ext_name),
+ base::i18n::WideToUpper(ext_name),
ext_name);
}
if (desc.empty())
diff --git a/chrome/browser/webdata/autofill_table.cc b/chrome/browser/webdata/autofill_table.cc
index 75a9503..8e5242a 100644
--- a/chrome/browser/webdata/autofill_table.cc
+++ b/chrome/browser/webdata/autofill_table.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "app/sql/statement.h"
+#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
@@ -429,7 +430,7 @@ bool AutofillTable::GetFormValuesForElementName(const string16& name,
s.BindString16(0, name);
s.BindInt(1, limit);
} else {
- string16 prefix_lower = l10n_util::ToLower(prefix);
+ string16 prefix_lower = base::i18n::ToLower(prefix);
string16 next_prefix = prefix_lower;
next_prefix[next_prefix.length() - 1]++;
@@ -625,7 +626,7 @@ bool AutofillTable::InsertFormElement(const FormField& element,
s.BindString16(0, element.name);
s.BindString16(1, element.value);
- s.BindString16(2, l10n_util::ToLower(element.value));
+ s.BindString16(2, base::i18n::ToLower(element.value));
if (!s.Run()) {
NOTREACHED();
@@ -824,7 +825,7 @@ bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) {
s.BindString16(0, entry.key().name());
s.BindString16(1, entry.key().value());
- s.BindString16(2, l10n_util::ToLower(entry.key().value()));
+ s.BindString16(2, base::i18n::ToLower(entry.key().value()));
s.BindInt(3, entry.timestamps().size());
if (!s.Run()) {
diff --git a/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc b/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc
index 251cc75..73db09b 100644
--- a/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc
+++ b/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc
@@ -8,6 +8,7 @@
#include <map>
#include "base/compiler_specific.h"
+#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
@@ -199,7 +200,7 @@ void PhishingTermFeatureExtractor::ExtractFeaturesWithTimeout() {
}
void PhishingTermFeatureExtractor::HandleWord(const string16& word) {
- std::string word_lower = UTF16ToUTF8(l10n_util::ToLower(word));
+ std::string word_lower = UTF16ToUTF8(base::i18n::ToLower(word));
std::string word_hash = crypto::SHA256HashString(word_lower);
// Quick out if the word is not part of any term, which is the common case.
diff --git a/net/ftp/ftp_directory_listing_parser_unittest.cc b/net/ftp/ftp_directory_listing_parser_unittest.cc
index 6664a89..a0a58d2 100644
--- a/net/ftp/ftp_directory_listing_parser_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_unittest.cc
@@ -19,51 +19,11 @@ namespace net {
namespace {
-TEST(FtpDirectoryListingBufferTest, Parse) {
- const char* test_files[] = {
- "dir-listing-ls-1",
- "dir-listing-ls-1-utf8",
- "dir-listing-ls-2",
- "dir-listing-ls-3",
- "dir-listing-ls-4",
- "dir-listing-ls-5",
- "dir-listing-ls-6",
- "dir-listing-ls-7",
- "dir-listing-ls-8",
- "dir-listing-ls-9",
- "dir-listing-ls-10",
- "dir-listing-ls-11",
- "dir-listing-ls-12",
- "dir-listing-ls-13",
- "dir-listing-ls-14",
- "dir-listing-ls-15",
- "dir-listing-ls-16",
- "dir-listing-ls-17",
- "dir-listing-ls-18",
- "dir-listing-ls-19",
- "dir-listing-ls-20", // TODO(phajdan.jr): should use windows-1251 encoding.
- "dir-listing-ls-21", // TODO(phajdan.jr): should use windows-1251 encoding.
- "dir-listing-ls-22", // TODO(phajdan.jr): should use windows-1251 encoding.
- "dir-listing-ls-23",
- "dir-listing-ls-24",
-
- // Tests for Russian listings. The only difference between those
- // files is character encoding:
- "dir-listing-ls-25", // UTF-8
- "dir-listing-ls-26", // KOI8-R
- "dir-listing-ls-27", // windows-1251
-
- "dir-listing-netware-1",
- "dir-listing-netware-2",
- "dir-listing-vms-1",
- "dir-listing-vms-2",
- "dir-listing-vms-3",
- "dir-listing-vms-4",
- "dir-listing-vms-5",
- "dir-listing-windows-1",
- "dir-listing-windows-2",
- };
+class FtpDirectoryListingParserTest
+ : public testing::TestWithParam<const char*> {
+};
+TEST_P(FtpDirectoryListingParserTest, Parse) {
FilePath test_dir;
PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
test_dir = test_dir.AppendASCII("net");
@@ -79,71 +39,116 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
base::Time mock_current_time(
base::Time::FromLocalExploded(mock_current_time_exploded));
- for (size_t i = 0; i < arraysize(test_files); i++) {
- SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, test_files[i]));
-
- std::string test_listing;
- EXPECT_TRUE(file_util::ReadFileToString(test_dir.AppendASCII(test_files[i]),
- &test_listing));
-
- std::vector<FtpDirectoryListingEntry> entries;
- EXPECT_EQ(OK, ParseFtpDirectoryListing(test_listing,
- mock_current_time,
- &entries));
-
- std::string expected_listing;
- ASSERT_TRUE(file_util::ReadFileToString(
- test_dir.AppendASCII(std::string(test_files[i]) + ".expected"),
- &expected_listing));
-
- std::vector<std::string> lines;
- StringTokenizer tokenizer(expected_listing, "\r\n");
- while (tokenizer.GetNext())
- lines.push_back(tokenizer.token());
-
- ASSERT_EQ(8 * entries.size(), lines.size());
-
- for (size_t i = 0; i < lines.size() / 8; i++) {
- std::string type(lines[8 * i]);
- std::string name(lines[8 * i + 1]);
- int64 size;
- base::StringToInt64(lines[8 * i + 2], &size);
-
- SCOPED_TRACE(base::StringPrintf("Filename: %s", name.c_str()));
-
- int year, month, day_of_month, hour, minute;
- base::StringToInt(lines[8 * i + 3], &year);
- base::StringToInt(lines[8 * i + 4], &month);
- base::StringToInt(lines[8 * i + 5], &day_of_month);
- base::StringToInt(lines[8 * i + 6], &hour);
- base::StringToInt(lines[8 * i + 7], &minute);
-
- const FtpDirectoryListingEntry& entry = entries[i];
-
- if (type == "d") {
- EXPECT_EQ(FtpDirectoryListingEntry::DIRECTORY, entry.type);
- } else if (type == "-") {
- EXPECT_EQ(FtpDirectoryListingEntry::FILE, entry.type);
- } else if (type == "l") {
- EXPECT_EQ(FtpDirectoryListingEntry::SYMLINK, entry.type);
- } else {
- ADD_FAILURE() << "invalid gold test data: " << type;
- }
-
- EXPECT_EQ(UTF8ToUTF16(name), entry.name);
- EXPECT_EQ(size, entry.size);
-
- base::Time::Exploded time_exploded;
- entry.last_modified.LocalExplode(&time_exploded);
- EXPECT_EQ(year, time_exploded.year);
- EXPECT_EQ(month, time_exploded.month);
- EXPECT_EQ(day_of_month, time_exploded.day_of_month);
- EXPECT_EQ(hour, time_exploded.hour);
- EXPECT_EQ(minute, time_exploded.minute);
+ SCOPED_TRACE(base::StringPrintf("Test case: %s", GetParam()));
+
+ std::string test_listing;
+ EXPECT_TRUE(file_util::ReadFileToString(test_dir.AppendASCII(GetParam()),
+ &test_listing));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_EQ(OK, ParseFtpDirectoryListing(test_listing,
+ mock_current_time,
+ &entries));
+
+ std::string expected_listing;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ test_dir.AppendASCII(std::string(GetParam()) + ".expected"),
+ &expected_listing));
+
+ std::vector<std::string> lines;
+ StringTokenizer tokenizer(expected_listing, "\r\n");
+ while (tokenizer.GetNext())
+ lines.push_back(tokenizer.token());
+
+ ASSERT_EQ(8 * entries.size(), lines.size());
+
+ for (size_t i = 0; i < lines.size() / 8; i++) {
+ std::string type(lines[8 * i]);
+ std::string name(lines[8 * i + 1]);
+ int64 size;
+ base::StringToInt64(lines[8 * i + 2], &size);
+
+ SCOPED_TRACE(base::StringPrintf("Filename: %s", name.c_str()));
+
+ int year, month, day_of_month, hour, minute;
+ base::StringToInt(lines[8 * i + 3], &year);
+ base::StringToInt(lines[8 * i + 4], &month);
+ base::StringToInt(lines[8 * i + 5], &day_of_month);
+ base::StringToInt(lines[8 * i + 6], &hour);
+ base::StringToInt(lines[8 * i + 7], &minute);
+
+ const FtpDirectoryListingEntry& entry = entries[i];
+
+ if (type == "d") {
+ EXPECT_EQ(FtpDirectoryListingEntry::DIRECTORY, entry.type);
+ } else if (type == "-") {
+ EXPECT_EQ(FtpDirectoryListingEntry::FILE, entry.type);
+ } else if (type == "l") {
+ EXPECT_EQ(FtpDirectoryListingEntry::SYMLINK, entry.type);
+ } else {
+ ADD_FAILURE() << "invalid gold test data: " << type;
}
+
+ EXPECT_EQ(UTF8ToUTF16(name), entry.name);
+ EXPECT_EQ(size, entry.size);
+
+ base::Time::Exploded time_exploded;
+ entry.last_modified.LocalExplode(&time_exploded);
+ EXPECT_EQ(year, time_exploded.year);
+ EXPECT_EQ(month, time_exploded.month);
+ EXPECT_EQ(day_of_month, time_exploded.day_of_month);
+ EXPECT_EQ(hour, time_exploded.hour);
+ EXPECT_EQ(minute, time_exploded.minute);
}
}
+const char* kTestFiles[] = {
+ "dir-listing-ls-1",
+ "dir-listing-ls-1-utf8",
+ "dir-listing-ls-2",
+ "dir-listing-ls-3",
+ "dir-listing-ls-4",
+ "dir-listing-ls-5",
+ "dir-listing-ls-6",
+ "dir-listing-ls-7",
+ "dir-listing-ls-8",
+ "dir-listing-ls-9",
+ "dir-listing-ls-10",
+ "dir-listing-ls-11",
+ "dir-listing-ls-12",
+ "dir-listing-ls-13",
+ "dir-listing-ls-14",
+ "dir-listing-ls-15",
+ "dir-listing-ls-16",
+ "dir-listing-ls-17",
+ "dir-listing-ls-18",
+ "dir-listing-ls-19",
+ "dir-listing-ls-20", // TODO(phajdan.jr): should use windows-1251 encoding.
+ "dir-listing-ls-21", // TODO(phajdan.jr): should use windows-1251 encoding.
+ "dir-listing-ls-22", // TODO(phajdan.jr): should use windows-1251 encoding.
+ "dir-listing-ls-23",
+ "dir-listing-ls-24",
+
+ // Tests for Russian listings. The only difference between those
+ // files is character encoding:
+ "dir-listing-ls-25", // UTF-8
+ "dir-listing-ls-26", // KOI8-R
+ "dir-listing-ls-27", // windows-1251
+
+ "dir-listing-netware-1",
+ "dir-listing-netware-2",
+ "dir-listing-vms-1",
+ "dir-listing-vms-2",
+ "dir-listing-vms-3",
+ "dir-listing-vms-4",
+ "dir-listing-vms-5",
+ "dir-listing-windows-1",
+ "dir-listing-windows-2",
+};
+
+INSTANTIATE_TEST_CASE_P(, FtpDirectoryListingParserTest,
+ testing::ValuesIn(kTestFiles));
+
} // namespace
} // namespace net
diff --git a/net/ftp/ftp_util.cc b/net/ftp/ftp_util.cc
index 441c666..0f384bd 100644
--- a/net/ftp/ftp_util.cc
+++ b/net/ftp/ftp_util.cc
@@ -4,10 +4,13 @@
#include "net/ftp/ftp_util.h"
+#include <map>
#include <vector>
+#include "base/i18n/case_conversion.h"
#include "base/i18n/char_iterator.h"
#include "base/logging.h"
+#include "base/memory/singleton.h"
#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
@@ -111,47 +114,82 @@ std::string FtpUtil::VMSPathToUnix(const std::string& vms_path) {
return result;
}
-// static
-bool FtpUtil::AbbreviatedMonthToNumber(const string16& text, int* number) {
- icu::UnicodeString unicode_text(text.data(), text.size());
-
- int32_t locales_count;
- const icu::Locale* locales =
- icu::DateFormat::getAvailableLocales(locales_count);
-
- // Some FTP servers localize the date listings. To guess the locale,
- // we loop over all available ones.
- for (int32_t locale = 0; locale < locales_count; locale++) {
- UErrorCode status(U_ZERO_ERROR);
-
- icu::DateFormatSymbols format_symbols(locales[locale], status);
-
- // If we cannot get format symbols for some locale, it's not a fatal error.
- // Just try another one.
- if (U_FAILURE(status))
- continue;
-
- int32_t months_count;
- const icu::UnicodeString* months =
- format_symbols.getShortMonths(months_count);
-
- // Loop over all abbreviated month names in given locale.
- // An alternative solution (to parse |text| in given locale) is more
- // lenient, and may accept more than we want even with setLenient(false).
- for (int32_t month = 0; month < months_count; month++) {
- // Compare (case-insensitive), but just first three characters. Sometimes
- // ICU returns longer strings (for example for Russian locale), and in FTP
- // listings they are abbreviated to just three characters.
- // Note: ICU may also return strings shorter than three characters,
- // and those also should be accepted.
- if (months[month].caseCompare(0, 3, unicode_text, 0) == 0) {
- *number = month + 1;
- return true;
+namespace {
+
+// Lazy-initialized map of abbreviated month names.
+class AbbreviatedMonthsMap {
+ public:
+ static AbbreviatedMonthsMap* GetInstance() {
+ return Singleton<AbbreviatedMonthsMap>::get();
+ }
+
+ // Converts abbreviated month name |text| to its number (in range 1-12).
+ // On success returns true and puts the number in |number|.
+ bool GetMonthNumber(const string16& text, int* number) {
+ // Ignore the case of the month names. The simplest way to handle that
+ // is to make everything lowercase.
+ string16 text_lower(base::i18n::ToLower(text));
+
+ if (map_.find(text_lower) == map_.end())
+ return false;
+
+ *number = map_[text_lower];
+ return true;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<AbbreviatedMonthsMap>;
+
+ // Constructor, initializes the map based on ICU data. It is much faster
+ // to do that just once.
+ AbbreviatedMonthsMap() {
+ int32_t locales_count;
+ const icu::Locale* locales =
+ icu::DateFormat::getAvailableLocales(locales_count);
+
+ for (int32_t locale = 0; locale < locales_count; locale++) {
+ UErrorCode status(U_ZERO_ERROR);
+
+ icu::DateFormatSymbols format_symbols(locales[locale], status);
+
+ // If we cannot get format symbols for some locale, it's not a fatal
+ // error. Just try another one.
+ if (U_FAILURE(status))
+ continue;
+
+ int32_t months_count;
+ const icu::UnicodeString* months =
+ format_symbols.getShortMonths(months_count);
+
+ for (int32_t month = 0; month < months_count; month++) {
+ string16 month_name(months[month].getBuffer(),
+ static_cast<size_t>(months[month].length()));
+
+ // Ignore the case of the month names. The simplest way to handle that
+ // is to make everything lowercase.
+ month_name = base::i18n::ToLower(month_name);
+
+ map_[month_name] = month + 1;
+
+ // Sometimes ICU returns longer strings, but in FTP listings a shorter
+ // abbreviation is used (for example for the Russian locale). Make sure
+ // we always have a map entry for a three-letter abbreviation.
+ map_[month_name.substr(0, 3)] = month + 1;
}
}
}
- return false;
+ // Maps lowercase month names to numbers in range 1-12.
+ std::map<string16, int> map_;
+
+ DISALLOW_COPY_AND_ASSIGN(AbbreviatedMonthsMap);
+};
+
+} // namespace
+
+// static
+bool FtpUtil::AbbreviatedMonthToNumber(const string16& text, int* number) {
+ return AbbreviatedMonthsMap::GetInstance()->GetMonthNumber(text, number);
}
// static
diff --git a/tools/valgrind/gtest_exclude/net_unittests.gtest-tsan.txt b/tools/valgrind/gtest_exclude/net_unittests.gtest-tsan.txt
index dd0be86..506186c 100644
--- a/tools/valgrind/gtest_exclude/net_unittests.gtest-tsan.txt
+++ b/tools/valgrind/gtest_exclude/net_unittests.gtest-tsan.txt
@@ -22,6 +22,3 @@ DirectoryListerTest.BigDirRecursiveTest
# Crashes silently, see http://crbug.com/76911
URLRequestTest.FileTest
-
-# This test does not finish in our time-out period. http://crbug.com/79022
-FtpDirectoryListingBufferTest.Parse
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 139e8f1..e39cfbe 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -779,26 +779,6 @@ string16 TruncateString(const string16& string, size_t length) {
return string.substr(0, index) + kElideString;
}
-string16 ToLower(const string16& string) {
- icu::UnicodeString lower_u_str(
- icu::UnicodeString(FALSE, string.c_str(), string.size()).toLower(
- icu::Locale::getDefault()));
- string16 result;
- lower_u_str.extract(0, lower_u_str.length(),
- WriteInto(&result, lower_u_str.length() + 1));
- return result;
-}
-
-string16 ToUpper(const string16& string) {
- icu::UnicodeString upper_u_str(
- icu::UnicodeString(FALSE, string.c_str(), string.size()).toUpper(
- icu::Locale::getDefault()));
- string16 result;
- upper_u_str.extract(0, upper_u_str.length(),
- WriteInto(&result, upper_u_str.length() + 1));
- return result;
-}
-
// Compares the character data stored in two different string16 strings by
// specified Collator instance.
UCollationResult CompareString16WithCollator(const icu::Collator* collator,
diff --git a/ui/base/l10n/l10n_util.h b/ui/base/l10n/l10n_util.h
index d0418c0..1478ae2 100644
--- a/ui/base/l10n/l10n_util.h
+++ b/ui/base/l10n/l10n_util.h
@@ -131,12 +131,6 @@ string16 GetStringFUTF16Int(int message_id, int64 a);
// less.
string16 TruncateString(const string16& string, size_t length);
-// Returns the lower case equivalent of string.
-string16 ToLower(const string16& string);
-
-// Returns the upper case equivalent of string.
-string16 ToUpper(const string16& string);
-
// In place sorting of string16 strings using collation rules for |locale|.
void SortStrings16(const std::string& locale,
std::vector<string16>* strings);
diff --git a/ui/base/l10n/l10n_util_unittest.cc b/ui/base/l10n/l10n_util_unittest.cc
index 90aaeff..8b24181 100644
--- a/ui/base/l10n/l10n_util_unittest.cc
+++ b/ui/base/l10n/l10n_util_unittest.cc
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/environment.h"
#include "base/file_util.h"
+#include "base/i18n/case_conversion.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
@@ -303,19 +304,6 @@ TEST_F(L10nUtilTest, SortStringsUsingFunction) {
STLDeleteElements(&strings);
}
-// Test upper and lower case string conversion.
-TEST_F(L10nUtilTest, UpperLower) {
- string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
- const string16 expected_lower(ASCIIToUTF16("text with upper & lower case."));
- const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE."));
-
- string16 result = l10n_util::ToLower(mixed);
- EXPECT_EQ(expected_lower, result);
-
- result = l10n_util::ToUpper(mixed);
- EXPECT_EQ(expected_upper, result);
-}
-
TEST_F(L10nUtilTest, LocaleDisplayName) {
// TODO(jungshik): Make this test more extensive.
// Test zh-CN and zh-TW are treated as zh-Hans and zh-Hant.
@@ -336,12 +324,12 @@ TEST_F(L10nUtilTest, LocaleDisplayName) {
char16 buf_with_null[length_with_null] = { 0, 'a', 0, 'b' };
string16 string16_with_null(buf_with_null, length_with_null);
- string16 upper_with_null = l10n_util::ToUpper(string16_with_null);
+ string16 upper_with_null = base::i18n::ToUpper(string16_with_null);
ASSERT_EQ(length_with_null, upper_with_null.size());
EXPECT_TRUE(upper_with_null[0] == 0 && upper_with_null[1] == 'A' &&
upper_with_null[2] == 0 && upper_with_null[3] == 'B');
- string16 lower_with_null = l10n_util::ToLower(upper_with_null);
+ string16 lower_with_null = base::i18n::ToLower(upper_with_null);
ASSERT_EQ(length_with_null, upper_with_null.size());
EXPECT_TRUE(lower_with_null[0] == 0 && lower_with_null[1] == 'a' &&
lower_with_null[2] == 0 && lower_with_null[3] == 'b');
diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc
index 5703d69..5a0ed2d 100644
--- a/views/controls/menu/menu_controller.cc
+++ b/views/controls/menu/menu_controller.cc
@@ -4,6 +4,7 @@
#include "views/controls/menu/menu_controller.h"
+#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -61,8 +62,7 @@ bool TitleMatchesMnemonic(MenuItemView* menu, wchar_t key) {
if (menu->GetMnemonic())
return false;
- std::wstring lower_title = UTF16ToWide(
- l10n_util::ToLower(WideToUTF16(menu->GetTitle())));
+ std::wstring lower_title = base::i18n::WideToLower(menu->GetTitle());
return !lower_title.empty() && lower_title[0] == key;
}
@@ -1661,7 +1661,7 @@ bool MenuController::AcceptOrSelect(MenuItemView* parent,
bool MenuController::SelectByChar(wchar_t character) {
wchar_t char_array[1] = { character };
- wchar_t key = UTF16ToWide(l10n_util::ToLower(WideToUTF16(char_array)))[0];
+ wchar_t key = base::i18n::WideToLower(char_array)[0];
MenuItemView* item = pending_state_.item;
if (!item->HasSubmenu() || !item->GetSubmenu()->IsShowing())
item = item->GetParentMenuItem();
diff --git a/views/controls/menu/menu_item_view.cc b/views/controls/menu/menu_item_view.cc
index 4af6da7..8c2858a8 100644
--- a/views/controls/menu/menu_item_view.cc
+++ b/views/controls/menu/menu_item_view.cc
@@ -4,6 +4,7 @@
#include "views/controls/menu/menu_item_view.h"
+#include "base/i18n/case_conversion.h"
#include "base/utf_string_conversions.h"
#include "grit/app_strings.h"
#include "ui/base/accessibility/accessible_view_state.h"
@@ -393,7 +394,11 @@ wchar_t MenuItemView::GetMnemonic() {
if (index != std::wstring::npos) {
if (index + 1 != title.size() && title[index + 1] != '&') {
wchar_t char_array[1] = { title[index + 1] };
- return UTF16ToWide(l10n_util::ToLower(WideToUTF16(char_array)))[0];
+ // TODO(jshin): What about Turkish locale? See http://crbug.com/81719.
+ // If the mnemonic is capital I and the UI language is Turkish,
+ // lowercasing it results in 'small dotless i', which is different
+ // from a 'dotted i'. Similar issues may exist for az and lt locales.
+ return base::i18n::WideToLower(char_array)[0];
}
index++;
}
diff --git a/views/controls/textfield/native_textfield_win.cc b/views/controls/textfield/native_textfield_win.cc
index 9c4d196..5811cf9 100644
--- a/views/controls/textfield/native_textfield_win.cc
+++ b/views/controls/textfield/native_textfield_win.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -193,7 +194,7 @@ void NativeTextfieldWin::UpdateText() {
// sure both RTL and LTR strings are displayed properly.
base::i18n::AdjustStringForLocaleDirection(&text);
if (textfield_->style() & Textfield::STYLE_LOWERCASE)
- text = l10n_util::ToLower(text);
+ text = base::i18n::WideToLower(text);
SetWindowText(text.c_str());
UpdateAccessibleValue(text);
}
@@ -906,7 +907,7 @@ void NativeTextfieldWin::OnPaste() {
if (!clipboard_str.empty()) {
std::wstring collapsed(CollapseWhitespace(clipboard_str, false));
if (textfield_->style() & Textfield::STYLE_LOWERCASE)
- collapsed = l10n_util::ToLower(collapsed);
+ collapsed = base::i18n::WideToLower(collapsed);
// Force a Paste operation to trigger ContentsChanged, even if identical
// contents are pasted into the text box. See http://crbug.com/79002
ReplaceSel(L"", false);