1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/rtl.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "unicode/coll.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "unicode/locid.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "unicode/uchar.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "unicode/uscript.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_USES_GTK)
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <gtk/gtk.h>
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21513209b27ff55e2841eac0e4120199c23acce758Ben Murdochnamespace {
22513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
23513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Extract language and country, ignore keywords, concatenate using dash.
24513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstd::string GetLocaleString(const icu::Locale& locale) {
25513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const char* language = locale.getLanguage();
26513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const char* country = locale.getCountry();
27513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
28513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string result =
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      (language != NULL && *language != '\0') ? language : "und";
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (country != NULL && *country != '\0') {
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    result += '-';
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    result += country;
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return result;
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace base {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace i18n {
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Represents the locale-specific ICU text direction.
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Convert the ICU default locale to a string.
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstd::string GetConfiguredLocale() {
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return GetLocaleString(icu::Locale::getDefault());
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Convert the ICU canonicalized locale to a string.
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstd::string GetCanonicalLocale(const char* locale) {
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return GetLocaleString(icu::Locale::createCanonical(locale));
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Convert Chrome locale name to ICU locale name
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string ICULocaleName(const std::string& locale_string) {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If not Spanish, just return it.
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (locale_string.substr(0, 2) != "es")
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return locale_string;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Expand es to es-ES.
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (LowerCaseEqualsASCII(locale_string, "es"))
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return "es-ES";
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Map es-419 (Latin American Spanish) to es-FOO depending on the system
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // locale.  If it's es-RR other than es-ES, map to es-RR. Otherwise, map
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to es-MX (the most populous in Spanish-speaking Latin America).
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (LowerCaseEqualsASCII(locale_string, "es-419")) {
69513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const icu::Locale& locale = icu::Locale::getDefault();
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    std::string language = locale.getLanguage();
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const char* country = locale.getCountry();
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (LowerCaseEqualsASCII(language, "es") &&
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      !LowerCaseEqualsASCII(country, "es")) {
74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        language += '-';
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        language += country;
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        return language;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return "es-MX";
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Currently, Chrome has only "es" and "es-419", but later we may have
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // more specific "es-RR".
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return locale_string;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SetICUDefaultLocale(const std::string& locale_string) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  icu::Locale locale(ICULocaleName(locale_string).c_str());
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UErrorCode error_code = U_ZERO_ERROR;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  icu::Locale::setDefault(locale, error_code);
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This return value is actually bogus because Locale object is
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // an ID and setDefault seems to always succeed (regardless of the
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // presence of actual locale data). However,
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // it does not hurt to have it as a sanity check.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(U_SUCCESS(error_code));
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_icu_text_direction = UNKNOWN_DIRECTION;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we use Views toolkit on top of GtkWidget, then we need to keep
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GtkWidget's default text direction consistent with ICU's text direction.
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Because in this case ICU's text direction will be used instead.
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See IsRTL() function below.
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_USES_GTK) && !defined(TOOLKIT_GTK)
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_default_direction(
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ICUIsRTL() ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsRTL() {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_GTK)
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkTextDirection gtk_dir = gtk_widget_get_default_direction();
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (gtk_dir == GTK_TEXT_DIR_RTL);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ICUIsRTL();
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ICUIsRTL() {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (g_icu_text_direction == UNKNOWN_DIRECTION) {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const icu::Locale& locale = icu::Locale::getDefault();
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    g_icu_text_direction = GetTextDirectionForLocale(locale.getName());
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return g_icu_text_direction == RIGHT_TO_LEFT;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTextDirection GetTextDirectionForLocale(const char* locale_name) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UErrorCode status = U_ZERO_ERROR;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(U_SUCCESS(status));
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Treat anything other than RTL as LTR.
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTextDirection GetFirstStrongCharacterDirection(const string16& text) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const UChar* string = text.c_str();
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t length = text.length();
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t position = 0;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (position < length) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UChar32 character;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t next_position = position;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    U16_NEXT(string, next_position, length, character);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Now that we have the character, we use ICU in order to query for the
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // appropriate Unicode BiDi character type.
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((property == U_RIGHT_TO_LEFT) ||
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (property == U_RIGHT_TO_LEFT_ARABIC) ||
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (property == U_RIGHT_TO_LEFT_EMBEDDING) ||
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (property == U_RIGHT_TO_LEFT_OVERRIDE)) {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return RIGHT_TO_LEFT;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if ((property == U_LEFT_TO_RIGHT) ||
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               (property == U_LEFT_TO_RIGHT_EMBEDDING) ||
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               (property == U_LEFT_TO_RIGHT_OVERRIDE)) {
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return LEFT_TO_RIGHT;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    position = next_position;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return LEFT_TO_RIGHT;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(WCHAR_T_IS_UTF32)
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTextDirection GetFirstStrongCharacterDirection(const std::wstring& text) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetFirstStrongCharacterDirection(WideToUTF16(text));
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_WIN)
167201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool AdjustStringForLocaleDirection(string16* text) {
168201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!IsRTL() || text->empty())
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Marking the string as LTR if the locale is RTL and the string does not
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // contain strong RTL characters. Otherwise, mark the string as RTL.
173201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!has_rtl_chars)
175201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    WrapStringWithLTRFormatting(text);
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
177201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    WrapStringWithRTLFormatting(text);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
18121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#else
18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool AdjustStringForLocaleDirection(string16* text) {
18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // On OS X & GTK the directionality of a label is determined by the first
18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // strongly directional character.
18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // However, we want to make sure that in an LTR-language-UI all strings are
18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // left aligned and vice versa.
18721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // A problem can arise if we display a string which starts with user input.
18821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // User input may be of the opposite directionality to the UI. So the whole
18921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // string will be displayed in the opposite directionality, e.g. if we want to
19021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // display in an LTR UI [such as US English]:
19121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  //
19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // EMAN_NOISNETXE is now installed.
19321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  //
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Since EXTENSION_NAME begins with a strong RTL char, the label's
19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // directionality will be set to RTL and the string will be displayed visually
19621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // as:
19721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  //
19821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // .is now installed EMAN_NOISNETXE
19921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  //
20021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // In order to solve this issue, we prepend an LRM to the string. An LRM is a
20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // strongly directional LTR char.
20221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // We also append an LRM at the end, which ensures that we're in an LTR
20321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // context.
20421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
20521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the
20621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // box so there is no issue with displaying zero-width bidi control characters
20721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // on any system.  Thus no need for the !IsRTL() check here.
20821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (text->empty())
20921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
21021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
21121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool ui_direction_is_rtl = IsRTL();
21221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!ui_direction_is_rtl && has_rtl_chars) {
21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    WrapStringWithRTLFormatting(text);
21621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    text->insert(0, 1, kLeftToRightMark);
21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    text->push_back(kLeftToRightMark);
21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  } else if (ui_direction_is_rtl && has_rtl_chars) {
21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    WrapStringWithRTLFormatting(text);
22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    text->insert(0, 1, kRightToLeftMark);
22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    text->push_back(kRightToLeftMark);
22221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  } else if (ui_direction_is_rtl) {
22321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    WrapStringWithLTRFormatting(text);
22421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    text->insert(0, 1, kRightToLeftMark);
22521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    text->push_back(kRightToLeftMark);
22621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
22721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
22821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
22921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
23021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
23121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif  // !OS_WIN
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(WCHAR_T_IS_UTF32)
234201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool AdjustStringForLocaleDirection(std::wstring* text) {
235201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  string16 temp = WideToUTF16(*text);
236201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (AdjustStringForLocaleDirection(&temp)) {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We should only touch the output on success.
238201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    *text = UTF16ToWide(temp);
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StringContainsStrongRTLChars(const string16& text) {
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const UChar* string = text.c_str();
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t length = text.length();
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t position = 0;
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (position < length) {
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UChar32 character;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t next_position = position;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    U16_NEXT(string, next_position, length, character);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Now that we have the character, we use ICU in order to query for the
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // appropriate Unicode BiDi character type.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC))
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    position = next_position;
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(WCHAR_T_IS_UTF32)
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StringContainsStrongRTLChars(const std::wstring& text) {
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return StringContainsStrongRTLChars(WideToUTF16(text));
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WrapStringWithLTRFormatting(string16* text) {
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text->empty())
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->insert(0, 1, kLeftToRightEmbeddingMark);
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->push_back(kPopDirectionalFormatting);
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(WCHAR_T_IS_UTF32)
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WrapStringWithLTRFormatting(std::wstring* text) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text->empty())
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->insert(0, 1, static_cast<wchar_t>(kLeftToRightEmbeddingMark));
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting));
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WrapStringWithRTLFormatting(string16* text) {
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text->empty())
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting an RLE (Right-To-Left Embedding) mark as the first character.
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->insert(0, 1, kRightToLeftEmbeddingMark);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->push_back(kPopDirectionalFormatting);
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(WCHAR_T_IS_UTF32)
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WrapStringWithRTLFormatting(std::wstring* text) {
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text->empty())
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting an RLE (Right-To-Left Embedding) mark as the first character.
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->insert(0, 1, static_cast<wchar_t>(kRightToLeftEmbeddingMark));
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting));
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WrapPathWithLTRFormatting(const FilePath& path,
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               string16* rtl_safe_path) {
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Wrap the overall path with LRE-PDF pair which essentialy marks the
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // string as a Left-To-Right string.
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rtl_safe_path->push_back(kLeftToRightEmbeddingMark);
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rtl_safe_path->append(UTF8ToUTF16(path.value()));
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN)
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rtl_safe_path->append(path.value());
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else  // defined(OS_POSIX) && !defined(OS_MACOSX)
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring wide_path = base::SysNativeMBToWide(path.value());
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rtl_safe_path->append(WideToUTF16(wide_path));
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rtl_safe_path->push_back(kPopDirectionalFormatting);
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 GetDisplayStringInLTRDirectionality(const string16& text) {
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!IsRTL())
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return text;
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  string16 text_mutable(text);
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  WrapStringWithLTRFormatting(&text_mutable);
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return text_mutable;
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst string16 StripWrappingBidiControlCharacters(const string16& text) {
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text.empty())
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return text;
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t begin_index = 0;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char16 begin = text[begin_index];
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (begin == kLeftToRightEmbeddingMark ||
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      begin == kRightToLeftEmbeddingMark ||
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      begin == kLeftToRightOverride ||
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      begin == kRightToLeftOverride)
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++begin_index;
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t end_index = text.length() - 1;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text[end_index] == kPopDirectionalFormatting)
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    --end_index;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return text.substr(begin_index, end_index - begin_index + 1);
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace i18n
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace base
364