LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCLocale.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 29 87 33.3 %
Date: 2017-07-14 16:53:18 Functions: 7 18 38.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "mozilla/Assertions.h"
       8             : 
       9             : #include "jsapi.h"
      10             : 
      11             : #include "nsCollationCID.h"
      12             : #include "nsJSUtils.h"
      13             : #include "nsICollation.h"
      14             : #include "nsIObserver.h"
      15             : #include "nsNativeCharsetUtils.h"
      16             : #include "nsComponentManagerUtils.h"
      17             : #include "nsServiceManagerUtils.h"
      18             : #include "mozilla/CycleCollectedJSContext.h"
      19             : #include "mozilla/intl/LocaleService.h"
      20             : #include "mozilla/Preferences.h"
      21             : 
      22             : #include "xpcpublic.h"
      23             : 
      24             : using namespace JS;
      25             : using namespace mozilla;
      26             : using mozilla::intl::LocaleService;
      27             : 
      28           3 : class XPCLocaleObserver : public nsIObserver
      29             : {
      30             : public:
      31             :   NS_DECL_ISUPPORTS
      32             :   NS_DECL_NSIOBSERVER
      33             : 
      34             :   void Init();
      35             : 
      36             : private:
      37           0 :   virtual ~XPCLocaleObserver() {};
      38             : };
      39             : 
      40          17 : NS_IMPL_ISUPPORTS(XPCLocaleObserver, nsIObserver);
      41             : 
      42             : void
      43           3 : XPCLocaleObserver::Init()
      44             : {
      45             :   nsCOMPtr<nsIObserverService> observerService =
      46           6 :     mozilla::services::GetObserverService();
      47             : 
      48           3 :   observerService->AddObserver(this, "intl:app-locales-changed", false);
      49           3 : }
      50             : 
      51             : NS_IMETHODIMP
      52           2 : XPCLocaleObserver::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
      53             : {
      54           2 :   if (!strcmp(aTopic, "intl:app-locales-changed")) {
      55           2 :     JSContext* cx = CycleCollectedJSContext::Get()->Context();
      56           2 :     if (!xpc_LocalizeContext(cx)) {
      57           0 :       return NS_ERROR_OUT_OF_MEMORY;
      58             :     }
      59           2 :     return NS_OK;
      60             :   }
      61             : 
      62           0 :   return NS_ERROR_UNEXPECTED;
      63             : }
      64             : 
      65             : /**
      66             :  * JS locale callbacks implemented by XPCOM modules.  These are theoretically
      67             :  * safe for use on multiple threads.  Unfortunately, the intl code underlying
      68             :  * these XPCOM modules doesn't yet support this, so in practice
      69             :  * XPCLocaleCallbacks are limited to the main thread.
      70             :  */
      71             : struct XPCLocaleCallbacks : public JSLocaleCallbacks
      72             : {
      73           3 :   XPCLocaleCallbacks()
      74           3 :   {
      75           3 :     MOZ_COUNT_CTOR(XPCLocaleCallbacks);
      76             : 
      77             :     // Disable the toLocaleUpper/Lower case hooks to use the standard,
      78             :     // locale-insensitive definition from String.prototype. (These hooks are
      79             :     // only consulted when EXPOSE_INTL_API is not set.)
      80           3 :     localeToUpperCase = nullptr;
      81           3 :     localeToLowerCase = nullptr;
      82           3 :     localeCompare = LocaleCompare;
      83           3 :     localeToUnicode = LocaleToUnicode;
      84             : 
      85             :     // It's going to be retained by the ObserverService.
      86           6 :     RefPtr<XPCLocaleObserver> locObs = new XPCLocaleObserver();
      87           3 :     locObs->Init();
      88           3 :   }
      89             : 
      90           0 :   ~XPCLocaleCallbacks()
      91           0 :   {
      92           0 :     AssertThreadSafety();
      93           0 :     MOZ_COUNT_DTOR(XPCLocaleCallbacks);
      94           0 :   }
      95             : 
      96             :   /**
      97             :    * Return the XPCLocaleCallbacks that's hidden away in |cx|. (This impl uses
      98             :    * the locale callbacks struct to store away its per-context data.)
      99             :    */
     100             :   static XPCLocaleCallbacks*
     101           0 :   This(JSContext* cx)
     102             :   {
     103             :     // Locale information for |cx| was associated using xpc_LocalizeContext;
     104             :     // assert and double-check this.
     105           0 :     const JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(cx);
     106           0 :     MOZ_ASSERT(lc);
     107           0 :     MOZ_ASSERT(lc->localeToUpperCase == nullptr);
     108           0 :     MOZ_ASSERT(lc->localeToLowerCase == nullptr);
     109           0 :     MOZ_ASSERT(lc->localeCompare == LocaleCompare);
     110           0 :     MOZ_ASSERT(lc->localeToUnicode == LocaleToUnicode);
     111             : 
     112           0 :     const XPCLocaleCallbacks* ths = static_cast<const XPCLocaleCallbacks*>(lc);
     113           0 :     ths->AssertThreadSafety();
     114           0 :     return const_cast<XPCLocaleCallbacks*>(ths);
     115             :   }
     116             : 
     117             :   static bool
     118           0 :   LocaleToUnicode(JSContext* cx, const char* src, MutableHandleValue rval)
     119             :   {
     120           0 :     return This(cx)->ToUnicode(cx, src, rval);
     121             :   }
     122             : 
     123             :   static bool
     124           0 :   LocaleCompare(JSContext* cx, HandleString src1, HandleString src2, MutableHandleValue rval)
     125             :   {
     126           0 :     return This(cx)->Compare(cx, src1, src2, rval);
     127             :   }
     128             : 
     129             : private:
     130             :   bool
     131           0 :   Compare(JSContext* cx, HandleString src1, HandleString src2, MutableHandleValue rval)
     132             :   {
     133             :     nsresult rv;
     134             : 
     135           0 :     if (!mCollation) {
     136             :       nsCOMPtr<nsICollationFactory> colFactory =
     137           0 :         do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
     138             : 
     139           0 :       if (NS_SUCCEEDED(rv)) {
     140           0 :         rv = colFactory->CreateCollation(getter_AddRefs(mCollation));
     141             :       }
     142             : 
     143           0 :       if (NS_FAILED(rv)) {
     144           0 :         xpc::Throw(cx, rv);
     145           0 :         return false;
     146             :       }
     147             :     }
     148             : 
     149           0 :     nsAutoJSString autoStr1, autoStr2;
     150           0 :     if (!autoStr1.init(cx, src1) || !autoStr2.init(cx, src2)) {
     151           0 :       return false;
     152             :     }
     153             : 
     154             :     int32_t result;
     155           0 :     rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault,
     156           0 :                                    autoStr1, autoStr2, &result);
     157             : 
     158           0 :     if (NS_FAILED(rv)) {
     159           0 :       xpc::Throw(cx, rv);
     160           0 :       return false;
     161             :     }
     162             : 
     163           0 :     rval.setInt32(result);
     164           0 :     return true;
     165             :   }
     166             : 
     167             :   bool
     168           0 :   ToUnicode(JSContext* cx, const char* src, MutableHandleValue rval)
     169             :   {
     170             :     // This code is only used by our prioprietary toLocaleFormat method
     171             :     // and should be removed once we get rid of it.
     172             :     // toLocaleFormat is used in non-ICU scenarios where we don't have
     173             :     // access to any other date/time than the OS one, so we have to also
     174             :     // use the OS locale for unicode conversions.
     175             :     // See bug 1349470 for more details.
     176           0 :     nsAutoString result;
     177           0 :     NS_CopyNativeToUnicode(nsDependentCString(src), result);
     178             :     JSString* ucstr =
     179           0 :       JS_NewUCStringCopyN(cx, result.get(), result.Length());
     180           0 :     if (ucstr) {
     181           0 :       rval.setString(ucstr);
     182           0 :       return true;
     183             :     }
     184             : 
     185           0 :     xpc::Throw(cx, NS_ERROR_OUT_OF_MEMORY);
     186           0 :     return false;
     187             :   }
     188             : 
     189           0 :   void AssertThreadSafety() const
     190             :   {
     191           0 :     NS_ASSERT_OWNINGTHREAD(XPCLocaleCallbacks);
     192           0 :   }
     193             : 
     194             :   nsCOMPtr<nsICollation> mCollation;
     195             : 
     196             :   NS_DECL_OWNINGTHREAD
     197             : };
     198             : 
     199             : bool
     200           5 : xpc_LocalizeContext(JSContext* cx)
     201             : {
     202             :   // We want to assign the locale callbacks only the first time we
     203             :   // localize the context.
     204             :   // All consequent calls to this function are result of language changes
     205             :   // and should not assign it again.
     206           5 :   const JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(cx);
     207           5 :   if (!lc) {
     208           3 :     JS_SetLocaleCallbacks(cx, new XPCLocaleCallbacks());
     209             :   }
     210             : 
     211             :   // Set the default locale.
     212             : 
     213             :   // Check a pref to see if we should use US English locale regardless
     214             :   // of the system locale.
     215           5 :   if (Preferences::GetBool("javascript.use_us_english_locale", false)) {
     216           0 :     return JS_SetDefaultLocale(cx, "en-US");
     217             :   }
     218             : 
     219             :   // No pref has been found, so get the default locale from the
     220             :   // application's locale.
     221          10 :   nsAutoCString appLocaleStr;
     222           5 :   LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocaleStr);
     223             : 
     224           5 :   return JS_SetDefaultLocale(cx, appLocaleStr.get());
     225             : }
     226             : 
     227             : void
     228           0 : xpc_DelocalizeContext(JSContext* cx)
     229             : {
     230           0 :   const XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(cx);
     231           0 :   JS_SetLocaleCallbacks(cx, nullptr);
     232           0 :   delete lc;
     233           0 : }

Generated by: LCOV version 1.13