js/xpconnect/src/XPCLocale.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "mozilla/Assertions.h"
     9 #include "jsapi.h"
    11 #include "nsCollationCID.h"
    12 #include "nsJSUtils.h"
    13 #include "nsICharsetConverterManager.h"
    14 #include "nsIPlatformCharset.h"
    15 #include "nsILocaleService.h"
    16 #include "nsICollation.h"
    17 #include "nsUnicharUtils.h"
    18 #include "nsComponentManagerUtils.h"
    19 #include "nsServiceManagerUtils.h"
    21 #include "xpcpublic.h"
    23 using namespace JS;
    25 /**
    26  * JS locale callbacks implemented by XPCOM modules.  These are theoretically
    27  * safe for use on multiple threads.  Unfortunately, the intl code underlying
    28  * these XPCOM modules doesn't yet support this, so in practice
    29  * XPCLocaleCallbacks are limited to the main thread.
    30  */
    31 struct XPCLocaleCallbacks : public JSLocaleCallbacks
    32 {
    33   XPCLocaleCallbacks()
    34 #ifdef DEBUG
    35     : mThread(PR_GetCurrentThread())
    36 #endif
    37   {
    38     MOZ_COUNT_CTOR(XPCLocaleCallbacks);
    40     localeToUpperCase = LocaleToUpperCase;
    41     localeToLowerCase = LocaleToLowerCase;
    42     localeCompare = LocaleCompare;
    43     localeToUnicode = LocaleToUnicode;
    44     localeGetErrorMessage = nullptr;
    45   }
    47   ~XPCLocaleCallbacks()
    48   {
    49     AssertThreadSafety();
    50     MOZ_COUNT_DTOR(XPCLocaleCallbacks);
    51   }
    53   /**
    54    * Return the XPCLocaleCallbacks that's hidden away in |rt|. (This impl uses
    55    * the locale callbacks struct to store away its per-runtime data.)
    56    */
    57   static XPCLocaleCallbacks*
    58   This(JSRuntime *rt)
    59   {
    60     // Locale information for |rt| was associated using xpc_LocalizeRuntime;
    61     // assert and double-check this.
    62     JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt);
    63     MOZ_ASSERT(lc);
    64     MOZ_ASSERT(lc->localeToUpperCase == LocaleToUpperCase);
    65     MOZ_ASSERT(lc->localeToLowerCase == LocaleToLowerCase);
    66     MOZ_ASSERT(lc->localeCompare == LocaleCompare);
    67     MOZ_ASSERT(lc->localeToUnicode == LocaleToUnicode);
    69     XPCLocaleCallbacks* ths = static_cast<XPCLocaleCallbacks*>(lc);
    70     ths->AssertThreadSafety();
    71     return ths;
    72   }
    74   static bool
    75   LocaleToUpperCase(JSContext *cx, HandleString src, MutableHandleValue rval)
    76   {
    77     return ChangeCase(cx, src, rval, ToUpperCase);
    78   }
    80   static bool
    81   LocaleToLowerCase(JSContext *cx, HandleString src, MutableHandleValue rval)
    82   {
    83     return ChangeCase(cx, src, rval, ToLowerCase);
    84   }
    86   static bool
    87   LocaleToUnicode(JSContext* cx, const char* src, MutableHandleValue rval)
    88   {
    89     return This(JS_GetRuntime(cx))->ToUnicode(cx, src, rval);
    90   }
    92   static bool
    93   LocaleCompare(JSContext *cx, HandleString src1, HandleString src2, MutableHandleValue rval)
    94   {
    95     return This(JS_GetRuntime(cx))->Compare(cx, src1, src2, rval);
    96   }
    98 private:
    99   static bool
   100   ChangeCase(JSContext* cx, HandleString src, MutableHandleValue rval,
   101              void(*changeCaseFnc)(const nsAString&, nsAString&))
   102   {
   103     nsDependentJSString depStr;
   104     if (!depStr.init(cx, src)) {
   105       return false;
   106     }
   108     nsAutoString result;
   109     changeCaseFnc(depStr, result);
   111     JSString *ucstr =
   112       JS_NewUCStringCopyN(cx, result.get(), result.Length());
   113     if (!ucstr) {
   114       return false;
   115     }
   117     rval.set(STRING_TO_JSVAL(ucstr));
   118     return true;
   119   }
   121   bool
   122   Compare(JSContext *cx, HandleString src1, HandleString src2, MutableHandleValue rval)
   123   {
   124     nsresult rv;
   126     if (!mCollation) {
   127       nsCOMPtr<nsILocaleService> localeService =
   128         do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
   130       if (NS_SUCCEEDED(rv)) {
   131         nsCOMPtr<nsILocale> locale;
   132         rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
   134         if (NS_SUCCEEDED(rv)) {
   135           nsCOMPtr<nsICollationFactory> colFactory =
   136             do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
   138           if (NS_SUCCEEDED(rv)) {
   139             rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation));
   140           }
   141         }
   142       }
   144       if (NS_FAILED(rv)) {
   145         xpc::Throw(cx, rv);
   146         return false;
   147       }
   148     }
   150     nsDependentJSString depStr1, depStr2;
   151     if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
   152       return false;
   153     }
   155     int32_t result;
   156     rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault,
   157                                    depStr1, depStr2, &result);
   159     if (NS_FAILED(rv)) {
   160       xpc::Throw(cx, rv);
   161       return false;
   162     }
   164     rval.set(INT_TO_JSVAL(result));
   165     return true;
   166   }
   168   bool
   169   ToUnicode(JSContext* cx, const char* src, MutableHandleValue rval)
   170   {
   171     nsresult rv;
   173     if (!mDecoder) {
   174       // use app default locale
   175       nsCOMPtr<nsILocaleService> localeService =
   176         do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
   177       if (NS_SUCCEEDED(rv)) {
   178         nsCOMPtr<nsILocale> appLocale;
   179         rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
   180         if (NS_SUCCEEDED(rv)) {
   181           nsAutoString localeStr;
   182           rv = appLocale->
   183                GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
   184           MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to get app locale info");
   186           nsCOMPtr<nsIPlatformCharset> platformCharset =
   187             do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
   189           if (NS_SUCCEEDED(rv)) {
   190             nsAutoCString charset;
   191             rv = platformCharset->GetDefaultCharsetForLocale(localeStr, charset);
   192             if (NS_SUCCEEDED(rv)) {
   193               // get/create unicode decoder for charset
   194               nsCOMPtr<nsICharsetConverterManager> ccm =
   195                 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
   196               if (NS_SUCCEEDED(rv))
   197                 ccm->GetUnicodeDecoder(charset.get(), getter_AddRefs(mDecoder));
   198             }
   199           }
   200         }
   201       }
   202     }
   204     int32_t srcLength = strlen(src);
   206     if (mDecoder) {
   207       int32_t unicharLength = srcLength;
   208       char16_t *unichars =
   209         (char16_t *)JS_malloc(cx, (srcLength + 1) * sizeof(char16_t));
   210       if (unichars) {
   211         rv = mDecoder->Convert(src, &srcLength, unichars, &unicharLength);
   212         if (NS_SUCCEEDED(rv)) {
   213           // terminate the returned string
   214           unichars[unicharLength] = 0;
   216           // nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
   217           if (unicharLength + 1 < srcLength + 1) {
   218             char16_t *shrunkUnichars =
   219               (char16_t *)JS_realloc(cx, unichars,
   220                                       (unicharLength + 1) * sizeof(char16_t));
   221             if (shrunkUnichars)
   222               unichars = shrunkUnichars;
   223           }
   224           JSString *str = JS_NewUCString(cx, reinterpret_cast<jschar*>(unichars), unicharLength);
   225           if (str) {
   226             rval.setString(str);
   227             return true;
   228           }
   229         }
   230         JS_free(cx, unichars);
   231       }
   232     }
   234     xpc::Throw(cx, NS_ERROR_OUT_OF_MEMORY);
   235     return false;
   236   }
   238   void AssertThreadSafety()
   239   {
   240     MOZ_ASSERT(mThread == PR_GetCurrentThread(),
   241                "XPCLocaleCallbacks used unsafely!");
   242   }
   244   nsCOMPtr<nsICollation> mCollation;
   245   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
   246 #ifdef DEBUG
   247   PRThread* mThread;
   248 #endif
   249 };
   251 bool
   252 xpc_LocalizeRuntime(JSRuntime *rt)
   253 {
   254   JS_SetLocaleCallbacks(rt, new XPCLocaleCallbacks());
   256   // Set the default locale.
   257   nsCOMPtr<nsILocaleService> localeService =
   258     do_GetService(NS_LOCALESERVICE_CONTRACTID);
   259   if (!localeService)
   260     return false;
   262   nsCOMPtr<nsILocale> appLocale;
   263   nsresult rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
   264   if (NS_FAILED(rv))
   265     return false;
   267   nsAutoString localeStr;
   268   rv = appLocale->GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
   269   MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to get app locale info");
   270   NS_LossyConvertUTF16toASCII locale(localeStr);
   272   return !!JS_SetDefaultLocale(rt, locale.get());
   273 }
   275 void
   276 xpc_DelocalizeRuntime(JSRuntime *rt)
   277 {
   278   XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(rt);
   279   JS_SetLocaleCallbacks(rt, nullptr);
   280   delete lc;
   281 }

mercurial