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