tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XPCLocale.cpp (4421B)


      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 "js/LocaleSensitive.h"
     10 
     11 #include "nsIObserver.h"
     12 #include "nsIObserverService.h"
     13 #include "nsComponentManagerUtils.h"
     14 #include "nsIPrefService.h"
     15 #include "nsServiceManagerUtils.h"
     16 #include "mozilla/Services.h"
     17 #include "mozilla/CycleCollectedJSRuntime.h"
     18 #include "mozilla/CycleCollectedJSContext.h"
     19 #include "mozilla/intl/LocaleService.h"
     20 #include "mozilla/Preferences.h"
     21 
     22 #include "xpcpublic.h"
     23 #include "xpcprivate.h"
     24 
     25 using namespace mozilla;
     26 using mozilla::intl::LocaleService;
     27 
     28 class XPCLocaleObserver : public nsIObserver {
     29 public:
     30  NS_DECL_ISUPPORTS
     31  NS_DECL_NSIOBSERVER
     32 
     33  void Init();
     34 
     35 private:
     36  virtual ~XPCLocaleObserver() = default;
     37 };
     38 
     39 NS_IMPL_ISUPPORTS(XPCLocaleObserver, nsIObserver);
     40 
     41 void XPCLocaleObserver::Init() {
     42  nsCOMPtr<nsIObserverService> observerService =
     43      mozilla::services::GetObserverService();
     44 
     45  observerService->AddObserver(this, "intl:app-locales-changed", false);
     46 }
     47 
     48 NS_IMETHODIMP
     49 XPCLocaleObserver::Observe(nsISupports* aSubject, const char* aTopic,
     50                           const char16_t* aData) {
     51  if (!strcmp(aTopic, "intl:app-locales-changed")) {
     52    JSRuntime* rt = CycleCollectedJSRuntime::Get()->Runtime();
     53    if (!xpc_LocalizeRuntime(rt)) {
     54      return NS_ERROR_OUT_OF_MEMORY;
     55    }
     56    return NS_OK;
     57  }
     58 
     59  return NS_ERROR_UNEXPECTED;
     60 }
     61 
     62 /**
     63 * JS locale callbacks implemented by XPCOM modules.  These are theoretically
     64 * safe for use on multiple threads.  Unfortunately, the intl code underlying
     65 * these XPCOM modules doesn't yet support this, so in practice
     66 * XPCLocaleCallbacks are limited to the main thread.
     67 */
     68 struct XPCLocaleCallbacks : public JSLocaleCallbacks {
     69  XPCLocaleCallbacks() {
     70    MOZ_COUNT_CTOR(XPCLocaleCallbacks);
     71 
     72    // Disable the toLocaleUpper/Lower case hooks to use the standard,
     73    // locale-insensitive definition from String.prototype. (These hooks are
     74    // only consulted when JS_HAS_INTL_API is not set.) Since JS_HAS_INTL_API
     75    // is always set, these hooks should be disabled.
     76    localeToUpperCase = nullptr;
     77    localeToLowerCase = nullptr;
     78    localeCompare = nullptr;
     79    localeToUnicode = nullptr;
     80 
     81    // It's going to be retained by the ObserverService.
     82    RefPtr<XPCLocaleObserver> locObs = new XPCLocaleObserver();
     83    locObs->Init();
     84  }
     85 
     86  ~XPCLocaleCallbacks() {
     87    AssertThreadSafety();
     88    MOZ_COUNT_DTOR(XPCLocaleCallbacks);
     89  }
     90 
     91  /**
     92   * Return the XPCLocaleCallbacks that's hidden away in |rt|. (This impl uses
     93   * the locale callbacks struct to store away its per-context data.)
     94   */
     95  static XPCLocaleCallbacks* This(JSRuntime* rt) {
     96    // Locale information for |cx| was associated using xpc_LocalizeContext;
     97    // assert and double-check this.
     98    const JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt);
     99    MOZ_ASSERT(lc);
    100    MOZ_ASSERT(lc->localeToUpperCase == nullptr);
    101    MOZ_ASSERT(lc->localeToLowerCase == nullptr);
    102    MOZ_ASSERT(lc->localeCompare == nullptr);
    103    MOZ_ASSERT(lc->localeToUnicode == nullptr);
    104 
    105    const XPCLocaleCallbacks* ths = static_cast<const XPCLocaleCallbacks*>(lc);
    106    ths->AssertThreadSafety();
    107    return const_cast<XPCLocaleCallbacks*>(ths);
    108  }
    109 
    110 private:
    111  void AssertThreadSafety() const {
    112    NS_ASSERT_OWNINGTHREAD(XPCLocaleCallbacks);
    113  }
    114 
    115  NS_DECL_OWNINGTHREAD
    116 };
    117 
    118 bool xpc_LocalizeRuntime(JSRuntime* rt) {
    119  // We want to assign the locale callbacks only the first time we
    120  // localize the context.
    121  // All consequent calls to this function are result of language changes
    122  // and should not assign it again.
    123  const JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt);
    124  if (!lc) {
    125    JS_SetLocaleCallbacks(rt, new XPCLocaleCallbacks());
    126  }
    127 
    128  // Set the default locale from the regional prefs locales.
    129  AutoTArray<nsCString, 10> rpLocales;
    130  LocaleService::GetInstance()->GetRegionalPrefsLocales(rpLocales);
    131 
    132  MOZ_ASSERT(rpLocales.Length() > 0);
    133  return JS_SetDefaultLocale(rt, rpLocales[0].get());
    134 }
    135 
    136 void xpc_DelocalizeRuntime(JSRuntime* rt) {
    137  const XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(rt);
    138  JS_SetLocaleCallbacks(rt, nullptr);
    139  delete lc;
    140 }