| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "base/i18n/rtl.h" | 
|  | 6 | 
|  | 7 #include "base/file_path.h" | 
|  | 8 #include "base/logging.h" | 
|  | 9 #include "base/string_util.h" | 
|  | 10 #include "base/utf_string_conversions.h" | 
|  | 11 #include "base/sys_string_conversions.h" | 
|  | 12 #include "unicode/coll.h" | 
|  | 13 #include "unicode/locid.h" | 
|  | 14 #include "unicode/uchar.h" | 
|  | 15 #include "unicode/uscript.h" | 
|  | 16 | 
|  | 17 #if defined(TOOLKIT_GTK) | 
|  | 18 #include <gtk/gtk.h> | 
|  | 19 #endif | 
|  | 20 | 
|  | 21 namespace base { | 
|  | 22 namespace i18n { | 
|  | 23 | 
|  | 24 // Represents the locale-specific ICU text direction. | 
|  | 25 static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION; | 
|  | 26 | 
|  | 27 void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) { | 
|  | 28   // Later we may have to change this to be OS-dependent so that | 
|  | 29   // it's not affected by ICU's default locale. It's all right | 
|  | 30   // to do this way because SetICUDefaultLocale is internal | 
|  | 31   // to this file and we know that it's not yet called when this function | 
|  | 32   // is called. | 
|  | 33   icu::Locale locale = icu::Locale::getDefault(); | 
|  | 34   const char* language = locale.getLanguage(); | 
|  | 35   const char* country = locale.getCountry(); | 
|  | 36   DCHECK(language); | 
|  | 37   *lang = language; | 
|  | 38   *region = country; | 
|  | 39 } | 
|  | 40 | 
|  | 41 // Convert Chrome locale name to ICU locale name | 
|  | 42 std::string ICULocaleName(const std::string& locale_string) { | 
|  | 43   // If not Spanish, just return it. | 
|  | 44   if (locale_string.substr(0, 2) != "es") | 
|  | 45     return locale_string; | 
|  | 46   // Expand es to es-ES. | 
|  | 47   if (LowerCaseEqualsASCII(locale_string, "es")) | 
|  | 48     return "es-ES"; | 
|  | 49   // Map es-419 (Latin American Spanish) to es-FOO depending on the system | 
|  | 50   // locale.  If it's es-RR other than es-ES, map to es-RR. Otherwise, map | 
|  | 51   // to es-MX (the most populous in Spanish-speaking Latin America). | 
|  | 52   if (LowerCaseEqualsASCII(locale_string, "es-419")) { | 
|  | 53     std::string lang, region; | 
|  | 54     GetLanguageAndRegionFromOS(&lang, ®ion); | 
|  | 55     if (LowerCaseEqualsASCII(lang, "es") && | 
|  | 56       !LowerCaseEqualsASCII(region, "es")) { | 
|  | 57         lang.append("-"); | 
|  | 58         lang.append(region); | 
|  | 59         return lang; | 
|  | 60     } | 
|  | 61     return "es-MX"; | 
|  | 62   } | 
|  | 63   // Currently, Chrome has only "es" and "es-419", but later we may have | 
|  | 64   // more specific "es-RR". | 
|  | 65   return locale_string; | 
|  | 66 } | 
|  | 67 | 
|  | 68 void SetICUDefaultLocale(const std::string& locale_string) { | 
|  | 69   icu::Locale locale(ICULocaleName(locale_string).c_str()); | 
|  | 70   UErrorCode error_code = U_ZERO_ERROR; | 
|  | 71   icu::Locale::setDefault(locale, error_code); | 
|  | 72   // This return value is actually bogus because Locale object is | 
|  | 73   // an ID and setDefault seems to always succeed (regardless of the | 
|  | 74   // presence of actual locale data). However, | 
|  | 75   // it does not hurt to have it as a sanity check. | 
|  | 76   DCHECK(U_SUCCESS(error_code)); | 
|  | 77   g_icu_text_direction = UNKNOWN_DIRECTION; | 
|  | 78 } | 
|  | 79 | 
|  | 80 TextDirection GetICUTextDirection() { | 
|  | 81   if (g_icu_text_direction == UNKNOWN_DIRECTION) { | 
|  | 82     const icu::Locale& locale = icu::Locale::getDefault(); | 
|  | 83     g_icu_text_direction = GetTextDirectionForLocale(locale.getName()); | 
|  | 84   } | 
|  | 85   return g_icu_text_direction; | 
|  | 86 } | 
|  | 87 | 
|  | 88 TextDirection GetTextDirection() { | 
|  | 89 #if defined(TOOLKIT_GTK) | 
|  | 90   GtkTextDirection gtk_dir = gtk_widget_get_default_direction(); | 
|  | 91   return (gtk_dir == GTK_TEXT_DIR_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; | 
|  | 92 #else | 
|  | 93   return GetICUTextDirection(); | 
|  | 94 #endif | 
|  | 95 } | 
|  | 96 | 
|  | 97 bool IsRTL() { | 
|  | 98   return GetTextDirection() == RIGHT_TO_LEFT; | 
|  | 99 } | 
|  | 100 | 
|  | 101 TextDirection GetTextDirectionForLocale(const char* locale_name) { | 
|  | 102   UErrorCode status = U_ZERO_ERROR; | 
|  | 103   ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status); | 
|  | 104   DCHECK(U_SUCCESS(status)); | 
|  | 105   // Treat anything other than RTL as LTR. | 
|  | 106   return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; | 
|  | 107 } | 
|  | 108 | 
|  | 109 TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) { | 
|  | 110 #if defined(WCHAR_T_IS_UTF32) | 
|  | 111   string16 text_utf16 = WideToUTF16(text); | 
|  | 112   const UChar* string = text_utf16.c_str(); | 
|  | 113 #else | 
|  | 114   const UChar* string = text.c_str(); | 
|  | 115 #endif | 
|  | 116   size_t length = text.length(); | 
|  | 117   size_t position = 0; | 
|  | 118   while (position < length) { | 
|  | 119     UChar32 character; | 
|  | 120     size_t next_position = position; | 
|  | 121     U16_NEXT(string, next_position, length, character); | 
|  | 122 | 
|  | 123     // Now that we have the character, we use ICU in order to query for the | 
|  | 124     // appropriate Unicode BiDi character type. | 
|  | 125     int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS); | 
|  | 126     if ((property == U_RIGHT_TO_LEFT) || | 
|  | 127         (property == U_RIGHT_TO_LEFT_ARABIC) || | 
|  | 128         (property == U_RIGHT_TO_LEFT_EMBEDDING) || | 
|  | 129         (property == U_RIGHT_TO_LEFT_OVERRIDE)) { | 
|  | 130       return RIGHT_TO_LEFT; | 
|  | 131     } else if ((property == U_LEFT_TO_RIGHT) || | 
|  | 132                (property == U_LEFT_TO_RIGHT_EMBEDDING) || | 
|  | 133                (property == U_LEFT_TO_RIGHT_OVERRIDE)) { | 
|  | 134       return LEFT_TO_RIGHT; | 
|  | 135     } | 
|  | 136 | 
|  | 137     position = next_position; | 
|  | 138   } | 
|  | 139 | 
|  | 140   return LEFT_TO_RIGHT; | 
|  | 141 } | 
|  | 142 | 
|  | 143 bool AdjustStringForLocaleDirection(const std::wstring& text, | 
|  | 144                                     std::wstring* localized_text) { | 
|  | 145   if (GetTextDirection() == LEFT_TO_RIGHT || text.length() == 0) | 
|  | 146     return false; | 
|  | 147 | 
|  | 148   // Marking the string as LTR if the locale is RTL and the string does not | 
|  | 149   // contain strong RTL characters. Otherwise, mark the string as RTL. | 
|  | 150   *localized_text = text; | 
|  | 151   bool has_rtl_chars = StringContainsStrongRTLChars(text); | 
|  | 152   if (!has_rtl_chars) | 
|  | 153     WrapStringWithLTRFormatting(localized_text); | 
|  | 154   else | 
|  | 155     WrapStringWithRTLFormatting(localized_text); | 
|  | 156 | 
|  | 157   return true; | 
|  | 158 } | 
|  | 159 | 
|  | 160 bool StringContainsStrongRTLChars(const std::wstring& text) { | 
|  | 161 #if defined(WCHAR_T_IS_UTF32) | 
|  | 162   string16 text_utf16 = WideToUTF16(text); | 
|  | 163   const UChar* string = text_utf16.c_str(); | 
|  | 164 #else | 
|  | 165   const UChar* string = text.c_str(); | 
|  | 166 #endif | 
|  | 167   size_t length = text.length(); | 
|  | 168   size_t position = 0; | 
|  | 169   while (position < length) { | 
|  | 170     UChar32 character; | 
|  | 171     size_t next_position = position; | 
|  | 172     U16_NEXT(string, next_position, length, character); | 
|  | 173 | 
|  | 174     // Now that we have the character, we use ICU in order to query for the | 
|  | 175     // appropriate Unicode BiDi character type. | 
|  | 176     int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS); | 
|  | 177     if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC)) | 
|  | 178       return true; | 
|  | 179 | 
|  | 180     position = next_position; | 
|  | 181   } | 
|  | 182 | 
|  | 183   return false; | 
|  | 184 } | 
|  | 185 | 
|  | 186 void WrapStringWithLTRFormatting(std::wstring* text) { | 
|  | 187   // Inserting an LRE (Left-To-Right Embedding) mark as the first character. | 
|  | 188   text->insert(0, 1, static_cast<wchar_t>(kLeftToRightEmbeddingMark)); | 
|  | 189 | 
|  | 190   // Inserting a PDF (Pop Directional Formatting) mark as the last character. | 
|  | 191   text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting)); | 
|  | 192 } | 
|  | 193 | 
|  | 194 void WrapStringWithRTLFormatting(std::wstring* text) { | 
|  | 195   // Inserting an RLE (Right-To-Left Embedding) mark as the first character. | 
|  | 196   text->insert(0, 1, static_cast<wchar_t>(kRightToLeftEmbeddingMark)); | 
|  | 197 | 
|  | 198   // Inserting a PDF (Pop Directional Formatting) mark as the last character. | 
|  | 199   text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting)); | 
|  | 200 } | 
|  | 201 | 
|  | 202 void WrapPathWithLTRFormatting(const FilePath& path, | 
|  | 203                                string16* rtl_safe_path) { | 
|  | 204   // Wrap the overall path with LRE-PDF pair which essentialy marks the | 
|  | 205   // string as a Left-To-Right string. | 
|  | 206   // Inserting an LRE (Left-To-Right Embedding) mark as the first character. | 
|  | 207   rtl_safe_path->push_back(kLeftToRightEmbeddingMark); | 
|  | 208 #if defined(OS_MACOSX) | 
|  | 209     rtl_safe_path->append(UTF8ToUTF16(path.value())); | 
|  | 210 #elif defined(OS_WIN) | 
|  | 211     rtl_safe_path->append(path.value()); | 
|  | 212 #else  // defined(OS_POSIX) && !defined(OS_MACOSX) | 
|  | 213     std::wstring wide_path = base::SysNativeMBToWide(path.value()); | 
|  | 214     rtl_safe_path->append(WideToUTF16(wide_path)); | 
|  | 215 #endif | 
|  | 216   // Inserting a PDF (Pop Directional Formatting) mark as the last character. | 
|  | 217   rtl_safe_path->push_back(kPopDirectionalFormatting); | 
|  | 218 } | 
|  | 219 | 
|  | 220 std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text) { | 
|  | 221   if (GetTextDirection() == RIGHT_TO_LEFT) | 
|  | 222     WrapStringWithLTRFormatting(text); | 
|  | 223   return *text; | 
|  | 224 } | 
|  | 225 | 
|  | 226 }  // namespace i18n | 
|  | 227 }  // namespace base | 
|  | 228 | 
| OLD | NEW | 
|---|