summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-20 06:37:01 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-20 06:37:01 +0000
commit7cf1b6ced3b14cce1d66ca0ddc713851f0d37536 (patch)
tree1c2fc9f4d52bf3046addf820d5eec03a2e150749 /base
parentf9f4841b14a9f309ce5ee613f0d4de6afad88767 (diff)
downloadchromium_src-7cf1b6ced3b14cce1d66ca0ddc713851f0d37536.zip
chromium_src-7cf1b6ced3b14cce1d66ca0ddc713851f0d37536.tar.gz
chromium_src-7cf1b6ced3b14cce1d66ca0ddc713851f0d37536.tar.bz2
Move RTL related functions from app/l10n_util to base/i18n/rtl
TBR=darin BUG=none TEST=none Review URL: http://codereview.chromium.org/1073005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42182 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp3
-rw-r--r--base/file_path.h2
-rw-r--r--base/i18n/rtl.cc228
-rw-r--r--base/i18n/rtl.h121
-rw-r--r--base/i18n/rtl_unittest.cc258
5 files changed, 611 insertions, 1 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 802147e..581b38b 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -31,6 +31,8 @@
'i18n/icu_util.h',
'i18n/number_formatting.cc',
'i18n/number_formatting.h',
+ 'i18n/rtl.cc',
+ 'i18n/rtl.h',
'i18n/time_formatting.cc',
'i18n/time_formatting.h',
'i18n/word_iterator.cc',
@@ -76,6 +78,7 @@
'id_map_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
+ 'i18n/rtl_unittest.cc',
'i18n/word_iterator_unittest.cc',
'json/json_reader_unittest.cc',
'json/json_writer_unittest.cc',
diff --git a/base/file_path.h b/base/file_path.h
index a328c8a..61aa4fb 100644
--- a/base/file_path.h
+++ b/base/file_path.h
@@ -66,7 +66,7 @@
//
// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even
// when the UI language is RTL. This means you always need to pass filepaths
-// through l10n_util::WrapPathWithLTRFormatting() before displaying it in the
+// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the
// RTL UI.
//
// This is a very common source of bugs, please try to keep this in mind.
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
new file mode 100644
index 0000000..52f7de7
--- /dev/null
+++ b/base/i18n/rtl.cc
@@ -0,0 +1,228 @@
+// Copyright (c) 2010 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/rtl.h"
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/sys_string_conversions.h"
+#include "unicode/coll.h"
+#include "unicode/locid.h"
+#include "unicode/uchar.h"
+#include "unicode/uscript.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+namespace base {
+namespace i18n {
+
+// Represents the locale-specific ICU text direction.
+static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
+
+void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) {
+ // Later we may have to change this to be OS-dependent so that
+ // it's not affected by ICU's default locale. It's all right
+ // to do this way because SetICUDefaultLocale is internal
+ // to this file and we know that it's not yet called when this function
+ // is called.
+ icu::Locale locale = icu::Locale::getDefault();
+ const char* language = locale.getLanguage();
+ const char* country = locale.getCountry();
+ DCHECK(language);
+ *lang = language;
+ *region = country;
+}
+
+// Convert Chrome locale name to ICU locale name
+std::string ICULocaleName(const std::string& locale_string) {
+ // If not Spanish, just return it.
+ if (locale_string.substr(0, 2) != "es")
+ return locale_string;
+ // Expand es to es-ES.
+ if (LowerCaseEqualsASCII(locale_string, "es"))
+ return "es-ES";
+ // Map es-419 (Latin American Spanish) to es-FOO depending on the system
+ // locale. If it's es-RR other than es-ES, map to es-RR. Otherwise, map
+ // to es-MX (the most populous in Spanish-speaking Latin America).
+ if (LowerCaseEqualsASCII(locale_string, "es-419")) {
+ std::string lang, region;
+ GetLanguageAndRegionFromOS(&lang, &region);
+ if (LowerCaseEqualsASCII(lang, "es") &&
+ !LowerCaseEqualsASCII(region, "es")) {
+ lang.append("-");
+ lang.append(region);
+ return lang;
+ }
+ return "es-MX";
+ }
+ // Currently, Chrome has only "es" and "es-419", but later we may have
+ // more specific "es-RR".
+ return locale_string;
+}
+
+void SetICUDefaultLocale(const std::string& locale_string) {
+ icu::Locale locale(ICULocaleName(locale_string).c_str());
+ UErrorCode error_code = U_ZERO_ERROR;
+ icu::Locale::setDefault(locale, error_code);
+ // This return value is actually bogus because Locale object is
+ // an ID and setDefault seems to always succeed (regardless of the
+ // presence of actual locale data). However,
+ // it does not hurt to have it as a sanity check.
+ DCHECK(U_SUCCESS(error_code));
+ g_icu_text_direction = UNKNOWN_DIRECTION;
+}
+
+TextDirection GetICUTextDirection() {
+ if (g_icu_text_direction == UNKNOWN_DIRECTION) {
+ const icu::Locale& locale = icu::Locale::getDefault();
+ g_icu_text_direction = GetTextDirectionForLocale(locale.getName());
+ }
+ return g_icu_text_direction;
+}
+
+TextDirection GetTextDirection() {
+#if defined(TOOLKIT_GTK)
+ GtkTextDirection gtk_dir = gtk_widget_get_default_direction();
+ return (gtk_dir == GTK_TEXT_DIR_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
+#else
+ return GetICUTextDirection();
+#endif
+}
+
+bool IsRTL() {
+ return GetTextDirection() == RIGHT_TO_LEFT;
+}
+
+TextDirection GetTextDirectionForLocale(const char* locale_name) {
+ UErrorCode status = U_ZERO_ERROR;
+ ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
+ DCHECK(U_SUCCESS(status));
+ // Treat anything other than RTL as LTR.
+ return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
+}
+
+TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) {
+#if defined(WCHAR_T_IS_UTF32)
+ string16 text_utf16 = WideToUTF16(text);
+ const UChar* string = text_utf16.c_str();
+#else
+ const UChar* string = text.c_str();
+#endif
+ size_t length = text.length();
+ size_t position = 0;
+ while (position < length) {
+ UChar32 character;
+ size_t next_position = position;
+ U16_NEXT(string, next_position, length, character);
+
+ // Now that we have the character, we use ICU in order to query for the
+ // appropriate Unicode BiDi character type.
+ int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+ if ((property == U_RIGHT_TO_LEFT) ||
+ (property == U_RIGHT_TO_LEFT_ARABIC) ||
+ (property == U_RIGHT_TO_LEFT_EMBEDDING) ||
+ (property == U_RIGHT_TO_LEFT_OVERRIDE)) {
+ return RIGHT_TO_LEFT;
+ } else if ((property == U_LEFT_TO_RIGHT) ||
+ (property == U_LEFT_TO_RIGHT_EMBEDDING) ||
+ (property == U_LEFT_TO_RIGHT_OVERRIDE)) {
+ return LEFT_TO_RIGHT;
+ }
+
+ position = next_position;
+ }
+
+ return LEFT_TO_RIGHT;
+}
+
+bool AdjustStringForLocaleDirection(const std::wstring& text,
+ std::wstring* localized_text) {
+ if (GetTextDirection() == LEFT_TO_RIGHT || text.length() == 0)
+ return false;
+
+ // Marking the string as LTR if the locale is RTL and the string does not
+ // contain strong RTL characters. Otherwise, mark the string as RTL.
+ *localized_text = text;
+ bool has_rtl_chars = StringContainsStrongRTLChars(text);
+ if (!has_rtl_chars)
+ WrapStringWithLTRFormatting(localized_text);
+ else
+ WrapStringWithRTLFormatting(localized_text);
+
+ return true;
+}
+
+bool StringContainsStrongRTLChars(const std::wstring& text) {
+#if defined(WCHAR_T_IS_UTF32)
+ string16 text_utf16 = WideToUTF16(text);
+ const UChar* string = text_utf16.c_str();
+#else
+ const UChar* string = text.c_str();
+#endif
+ size_t length = text.length();
+ size_t position = 0;
+ while (position < length) {
+ UChar32 character;
+ size_t next_position = position;
+ U16_NEXT(string, next_position, length, character);
+
+ // Now that we have the character, we use ICU in order to query for the
+ // appropriate Unicode BiDi character type.
+ int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+ if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC))
+ return true;
+
+ position = next_position;
+ }
+
+ return false;
+}
+
+void WrapStringWithLTRFormatting(std::wstring* text) {
+ // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+ text->insert(0, 1, static_cast<wchar_t>(kLeftToRightEmbeddingMark));
+
+ // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+ text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting));
+}
+
+void WrapStringWithRTLFormatting(std::wstring* text) {
+ // Inserting an RLE (Right-To-Left Embedding) mark as the first character.
+ text->insert(0, 1, static_cast<wchar_t>(kRightToLeftEmbeddingMark));
+
+ // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+ text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting));
+}
+
+void WrapPathWithLTRFormatting(const FilePath& path,
+ string16* rtl_safe_path) {
+ // Wrap the overall path with LRE-PDF pair which essentialy marks the
+ // string as a Left-To-Right string.
+ // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+ rtl_safe_path->push_back(kLeftToRightEmbeddingMark);
+#if defined(OS_MACOSX)
+ rtl_safe_path->append(UTF8ToUTF16(path.value()));
+#elif defined(OS_WIN)
+ rtl_safe_path->append(path.value());
+#else // defined(OS_POSIX) && !defined(OS_MACOSX)
+ std::wstring wide_path = base::SysNativeMBToWide(path.value());
+ rtl_safe_path->append(WideToUTF16(wide_path));
+#endif
+ // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+ rtl_safe_path->push_back(kPopDirectionalFormatting);
+}
+
+std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text) {
+ if (GetTextDirection() == RIGHT_TO_LEFT)
+ WrapStringWithLTRFormatting(text);
+ return *text;
+}
+
+} // namespace i18n
+} // namespace base
+
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
new file mode 100644
index 0000000..05a5ff0
--- /dev/null
+++ b/base/i18n/rtl.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2010 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_RTL_H_
+#define BASE_I18N_RTL_H_
+
+#include "base/string16.h"
+
+class FilePath;
+
+namespace base {
+namespace i18n {
+
+const char16 kRightToLeftMark = 0x200f;
+const char16 kLeftToRightMark = 0x200e;
+const char16 kLeftToRightEmbeddingMark = 0x202A;
+const char16 kRightToLeftEmbeddingMark = 0x202B;
+const char16 kPopDirectionalFormatting = 0x202C;
+
+// Represents the text direction returned by the GetTextDirection() function.
+enum TextDirection {
+ UNKNOWN_DIRECTION,
+ RIGHT_TO_LEFT,
+ LEFT_TO_RIGHT,
+};
+
+// Get language and region from the OS.
+void GetLanguageAndRegionFromOS(std::string* lang, std::string* region);
+
+// Sets the default locale of ICU.
+// Once the application locale of Chrome in GetApplicationLocale is determined,
+// the default locale of ICU need to be changed to match the application locale
+// so that ICU functions work correctly in a locale-dependent manner.
+// This is handy in that we don't have to call GetApplicationLocale()
+// everytime we call locale-dependent ICU APIs as long as we make sure
+// that this is called before any locale-dependent API is called.
+void SetICUDefaultLocale(const std::string& locale_string);
+
+// Returns the text direction for the default ICU locale. It is assumed
+// that SetICUDefaultLocale has been called to set the default locale to
+// the UI locale of Chrome. Its return is one of the following three:
+// * LEFT_TO_RIGHT: Left-To-Right (e.g. English, Chinese, etc.);
+// * RIGHT_TO_LEFT: Right-To-Left (e.g. Arabic, Hebrew, etc.), and;
+// * UNKNOWN_DIRECTION: unknown (or error).
+TextDirection GetICUTextDirection();
+
+// Get the application text direction. (This is just the ICU direction,
+// except on GTK.)
+TextDirection GetTextDirection();
+
+// Returns true if the application text direction is right-to-left.
+bool IsRTL();
+
+// Returns the text direction for |locale_name|.
+TextDirection GetTextDirectionForLocale(const char* locale_name);
+
+// Given the string in |text|, returns the directionality of the first
+// character with strong directionality in the string. If no character in the
+// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi
+// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong
+// directionality characters. Please refer to http://unicode.org/reports/tr9/
+// for more information.
+TextDirection GetFirstStrongCharacterDirection(const std::wstring& text);
+
+// Given the string in |text|, this function creates a copy of the string with
+// the appropriate Unicode formatting marks that mark the string direction
+// (either left-to-right or right-to-left). The new string is returned in
+// |localized_text|. The function checks both the current locale and the
+// contents of the string in order to determine the direction of the returned
+// string. The function returns true if the string in |text| was properly
+// adjusted.
+//
+// Certain LTR strings are not rendered correctly when the context is RTL. For
+// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in
+// an RTL context. Calling this function will make sure the returned localized
+// string is always treated as a right-to-left string. This is done by
+// inserting certain Unicode formatting marks into the returned string.
+//
+// TODO(idana) bug# 1206120: this function adjusts the string in question only
+// if the current locale is right-to-left. The function does not take care of
+// the opposite case (an RTL string displayed in an LTR context) since
+// adjusting the string involves inserting Unicode formatting characters that
+// Windows does not handle well unless right-to-left language support is
+// installed. Since the English version of Windows doesn't have right-to-left
+// language support installed by default, inserting the direction Unicode mark
+// results in Windows displaying squares.
+bool AdjustStringForLocaleDirection(const std::wstring& text,
+ std::wstring* localized_text);
+
+// Returns true if the string contains at least one character with strong right
+// to left directionality; that is, a character with either R or AL Unicode
+// BiDi character type.
+bool StringContainsStrongRTLChars(const std::wstring& text);
+
+// Wraps a string with an LRE-PDF pair which essentialy marks the string as a
+// Left-To-Right string. Doing this is useful in order to make sure LTR
+// strings are rendered properly in an RTL context.
+void WrapStringWithLTRFormatting(std::wstring* text);
+
+// Wraps a string with an RLE-PDF pair which essentialy marks the string as a
+// Right-To-Left string. Doing this is useful in order to make sure RTL
+// strings are rendered properly in an LTR context.
+void WrapStringWithRTLFormatting(std::wstring* text);
+
+// Wraps file path to get it to display correctly in RTL UI. All filepaths
+// should be passed through this function before display in UI for RTL locales.
+void WrapPathWithLTRFormatting(const FilePath& path,
+ string16* rtl_safe_path);
+
+// Given the string in |text|, this function returns the adjusted string having
+// LTR directionality for display purpose. Which means that in RTL locale the
+// string is wrapped with LRE (Left-To-Right Embedding) and PDF (Pop
+// Directional Formatting) marks and returned. In LTR locale, the string itself
+// is returned.
+std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text);
+
+} // namespace i18n
+} // namespace base
+
+#endif // BASE_I18N_RTL_H_
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc
new file mode 100644
index 0000000..65d0f6b
--- /dev/null
+++ b/base/i18n/rtl_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2006-2008 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/rtl.h"
+
+#include "base/file_path.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+base::i18n::TextDirection GetTextDirection(const char* locale_name) {
+ return base::i18n::GetTextDirectionForLocale(locale_name);
+}
+}
+
+class RTLTest : public PlatformTest {
+};
+
+TEST_F(RTLTest, GetFirstStrongCharacterDirection) {
+ // Test pure LTR string.
+ std::wstring string(L"foo bar");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type L.
+ string.assign(L"foo \x05d0 bar");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type R.
+ string.assign(L"\x05d0 foo bar");
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string which starts with a character with weak directionality
+ // and in which the first character with strong directionality is a character
+ // with type L.
+ string.assign(L"!foo \x05d0 bar");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string which starts with a character with weak directionality
+ // and in which the first character with strong directionality is a character
+ // with type R.
+ string.assign(L",\x05d0 foo bar");
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type LRE.
+ string.assign(L"\x202a \x05d0 foo bar");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type LRO.
+ string.assign(L"\x202d \x05d0 foo bar");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type RLE.
+ string.assign(L"\x202b foo \x05d0 bar");
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type RLO.
+ string.assign(L"\x202e foo \x05d0 bar");
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test bidi string in which the first character with strong directionality
+ // is a character with type AL.
+ string.assign(L"\x0622 foo \x05d0 bar");
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test a string without strong directionality characters.
+ string.assign(L",!.{}");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test empty string.
+ string.assign(L"");
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+ // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+ // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+ // information).
+#if defined(WCHAR_T_IS_UTF32)
+ string.assign(L" ! \x10910" L"abc 123");
+#elif defined(WCHAR_T_IS_UTF16)
+ string.assign(L" ! \xd802\xdd10" L"abc 123");
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+
+#if defined(WCHAR_T_IS_UTF32)
+ string.assign(L" ! \x10401" L"abc 123");
+#elif defined(WCHAR_T_IS_UTF16)
+ string.assign(L" ! \xd801\xdc01" L"abc 123");
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
+ base::i18n::GetFirstStrongCharacterDirection(string));
+}
+
+typedef struct {
+ std::wstring path;
+ std::wstring wrapped_path;
+} PathAndWrappedPath;
+
+TEST_F(RTLTest, WrapPathWithLTRFormatting) {
+ std::wstring kSeparator;
+ kSeparator.push_back(static_cast<wchar_t>(FilePath::kSeparators[0]));
+ const PathAndWrappedPath test_data[] = {
+ // Test common path, such as "c:\foo\bar".
+ { L"c:" + kSeparator + L"foo" + kSeparator + L"bar",
+ L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator +
+ L"bar\x202c"
+ },
+ // Test path with file name, such as "c:\foo\bar\test.jpg".
+ { L"c:" + kSeparator + L"foo" + kSeparator + L"bar" + kSeparator +
+ L"test.jpg",
+ L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator +
+ L"bar" + kSeparator + L"test.jpg\x202c"
+ },
+ // Test path ending with punctuation, such as "c:\(foo)\bar.".
+ { L"c:" + kSeparator + L"(foo)" + kSeparator + L"bar.",
+ L"\x202a"L"c:" + kSeparator + L"(foo)" + kSeparator +
+ L"bar.\x202c"
+ },
+ // Test path ending with separator, such as "c:\foo\bar\".
+ { L"c:" + kSeparator + L"foo" + kSeparator + L"bar" + kSeparator,
+ L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator +
+ L"bar" + kSeparator + L"\x202c",
+ },
+ // Test path with RTL character.
+ { L"c:" + kSeparator + L"\x05d0",
+ L"\x202a"L"c:" + kSeparator + L"\x05d0\x202c",
+ },
+ // Test path with 2 level RTL directory names.
+ { L"c:" + kSeparator + L"\x05d0" + kSeparator + L"\x0622",
+ L"\x202a"L"c:" + kSeparator + L"\x05d0" + kSeparator +
+ L"\x0622\x202c",
+ },
+ // Test path with mixed RTL/LTR directory names and ending with punctuation.
+ { L"c:" + kSeparator + L"\x05d0" + kSeparator + L"\x0622" + kSeparator +
+ L"(foo)" + kSeparator + L"b.a.r.",
+ L"\x202a"L"c:" + kSeparator + L"\x05d0" + kSeparator +
+ L"\x0622" + kSeparator + L"(foo)" + kSeparator +
+ L"b.a.r.\x202c",
+ },
+ // Test path without driver name, such as "/foo/bar/test/jpg".
+ { kSeparator + L"foo" + kSeparator + L"bar" + kSeparator + L"test.jpg",
+ L"\x202a" + kSeparator + L"foo" + kSeparator + L"bar" +
+ kSeparator + L"test.jpg" + L"\x202c"
+ },
+ // Test path start with current directory, such as "./foo".
+ { L"." + kSeparator + L"foo",
+ L"\x202a"L"." + kSeparator + L"foo" + L"\x202c"
+ },
+ // Test path start with parent directory, such as "../foo/bar.jpg".
+ { L".." + kSeparator + L"foo" + kSeparator + L"bar.jpg",
+ L"\x202a"L".." + kSeparator + L"foo" + kSeparator +
+ L"bar.jpg" + L"\x202c"
+ },
+ // Test absolute path, such as "//foo/bar.jpg".
+ { kSeparator + kSeparator + L"foo" + kSeparator + L"bar.jpg",
+ L"\x202a" + kSeparator + kSeparator + L"foo" + kSeparator +
+ L"bar.jpg" + L"\x202c"
+ },
+ // Test path with mixed RTL/LTR directory names.
+ { L"c:" + kSeparator + L"foo" + kSeparator + L"\x05d0" + kSeparator +
+ L"\x0622" + kSeparator + L"\x05d1.jpg",
+ L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator + L"\x05d0" +
+ kSeparator + L"\x0622" + kSeparator + L"\x05d1.jpg" + L"\x202c",
+ },
+ // Test empty path.
+ { L"",
+ L"\x202a\x202c"
+ }
+ };
+ for (unsigned int i = 0; i < arraysize(test_data); ++i) {
+ string16 localized_file_path_string;
+ FilePath path = FilePath::FromWStringHack(test_data[i].path);
+ base::i18n::WrapPathWithLTRFormatting(path, &localized_file_path_string);
+ std::wstring wrapped_path = UTF16ToWide(localized_file_path_string);
+ EXPECT_EQ(wrapped_path, test_data[i].wrapped_path);
+ }
+}
+
+typedef struct {
+ std::wstring raw_filename;
+ std::wstring display_string;
+} StringAndLTRString;
+
+TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) {
+ const StringAndLTRString test_data[] = {
+ { L"test", L"\x202atest\x202c" },
+ { L"test.html", L"\x202atest.html\x202c" },
+ { L"\x05d0\x05d1\x05d2", L"\x202a\x05d0\x05d1\x05d2\x202c" },
+ { L"\x05d0\x05d1\x05d2.txt", L"\x202a\x05d0\x05d1\x05d2.txt\x202c" },
+ { L"\x05d0"L"abc", L"\x202a\x05d0"L"abc\x202c" },
+ { L"\x05d0"L"abc.txt", L"\x202a\x05d0"L"abc.txt\x202c" },
+ { L"abc\x05d0\x05d1", L"\x202a"L"abc\x05d0\x05d1\x202c" },
+ { L"abc\x05d0\x05d1.jpg", L"\x202a"L"abc\x05d0\x05d1.jpg\x202c" },
+ };
+ for (unsigned int i = 0; i < arraysize(test_data); ++i) {
+ std::wstring input = test_data[i].raw_filename;
+ std::wstring expected =
+ base::i18n::GetDisplayStringInLTRDirectionality(&input);
+ if (base::i18n::IsRTL())
+ EXPECT_EQ(test_data[i].display_string, expected);
+ else
+ EXPECT_EQ(input, expected);
+ }
+}
+
+TEST_F(RTLTest, GetTextDirection) {
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ar"));
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ar_EG"));
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("he"));
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("he_IL"));
+ // iw is an obsolete code for Hebrew.
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("iw"));
+ // Although we're not yet localized to Farsi and Urdu, we
+ // do have the text layout direction information for them.
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("fa"));
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ur"));
+#if 0
+ // Enable these when we include the minimal locale data for Azerbaijani
+ // written in Arabic and Dhivehi. At the moment, our copy of
+ // ICU data does not have entries for them.
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("az_Arab"));
+ // Dhivehi that uses Thaana script.
+ EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("dv"));
+#endif
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("en"));
+ // Chinese in China with '-'.
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("zh-CN"));
+ // Filipino : 3-letter code
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("fil"));
+ // Russian
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("ru"));
+ // Japanese that uses multiple scripts
+ EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("ja"));
+} \ No newline at end of file