tor-browser

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

OSPreferences_mac.cpp (5556B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 *
      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 "OSPreferences.h"
      8 #include "mozilla/intl/LocaleService.h"
      9 #include <CoreFoundation/CoreFoundation.h>
     10 #include <CoreText/CoreText.h>
     11 
     12 using namespace mozilla::intl;
     13 
     14 static void LocaleChangedNotificationCallback(CFNotificationCenterRef center,
     15                                              void* observer, CFStringRef name,
     16                                              const void* object,
     17                                              CFDictionaryRef userInfo) {
     18  if (!::CFEqual(name, kCFLocaleCurrentLocaleDidChangeNotification)) {
     19    return;
     20  }
     21  static_cast<OSPreferences*>(observer)->Refresh();
     22 }
     23 
     24 OSPreferences::OSPreferences() {
     25  ::CFNotificationCenterAddObserver(
     26      ::CFNotificationCenterGetLocalCenter(), this,
     27      LocaleChangedNotificationCallback,
     28      kCFLocaleCurrentLocaleDidChangeNotification, 0,
     29      CFNotificationSuspensionBehaviorDeliverImmediately);
     30 }
     31 
     32 bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
     33  MOZ_ASSERT(aLocaleList.IsEmpty());
     34 
     35  CFArrayRef langs = ::CFLocaleCopyPreferredLanguages();
     36  for (CFIndex i = 0; i < ::CFArrayGetCount(langs); i++) {
     37    CFStringRef lang = (CFStringRef)::CFArrayGetValueAtIndex(langs, i);
     38 
     39    AutoTArray<UniChar, 32> buffer;
     40    int size = ::CFStringGetLength(lang);
     41    buffer.SetLength(size);
     42 
     43    CFRange range = ::CFRangeMake(0, size);
     44    ::CFStringGetCharacters(lang, range, buffer.Elements());
     45 
     46    // Convert the locale string to the format that Mozilla expects
     47    NS_LossyConvertUTF16toASCII locale(
     48        reinterpret_cast<const char16_t*>(buffer.Elements()), buffer.Length());
     49 
     50    if (CanonicalizeLanguageTag(locale)) {
     51      aLocaleList.AppendElement(locale);
     52    }
     53  }
     54 
     55  ::CFRelease(langs);
     56 
     57  return !aLocaleList.IsEmpty();
     58 }
     59 
     60 bool OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList) {
     61  // For now we're just taking System Locales since we don't know of any better
     62  // API for regional prefs.
     63  return ReadSystemLocales(aLocaleList);
     64 }
     65 
     66 static CFDateFormatterStyle ToCFDateFormatterStyle(
     67    OSPreferences::DateTimeFormatStyle aFormatStyle) {
     68  switch (aFormatStyle) {
     69    case OSPreferences::DateTimeFormatStyle::None:
     70      return kCFDateFormatterNoStyle;
     71    case OSPreferences::DateTimeFormatStyle::Short:
     72      return kCFDateFormatterShortStyle;
     73    case OSPreferences::DateTimeFormatStyle::Medium:
     74      return kCFDateFormatterMediumStyle;
     75    case OSPreferences::DateTimeFormatStyle::Long:
     76      return kCFDateFormatterLongStyle;
     77    case OSPreferences::DateTimeFormatStyle::Full:
     78      return kCFDateFormatterFullStyle;
     79    case OSPreferences::DateTimeFormatStyle::Invalid:
     80      MOZ_ASSERT_UNREACHABLE("invalid time format");
     81      return kCFDateFormatterNoStyle;
     82  }
     83 }
     84 
     85 // Given an 8-bit Gecko string, create a corresponding CFLocale;
     86 // if aLocale is empty, returns a copy of the system's current locale.
     87 // May return null on failure.
     88 // Follows Core Foundation's Create rule, so the caller is responsible to
     89 // release the returned reference.
     90 static CFLocaleRef CreateCFLocaleFor(const nsACString& aLocale) {
     91  nsAutoCString reqLocale;
     92  nsAutoCString systemLocale;
     93 
     94  OSPreferences::GetInstance()->GetSystemLocale(systemLocale);
     95 
     96  if (aLocale.IsEmpty()) {
     97    LocaleService::GetInstance()->GetAppLocaleAsBCP47(reqLocale);
     98  } else {
     99    reqLocale.Assign(aLocale);
    100  }
    101 
    102  bool match = LocaleService::LanguagesMatch(reqLocale, systemLocale);
    103  if (match) {
    104    return ::CFLocaleCopyCurrent();
    105  }
    106 
    107  CFStringRef identifier = CFStringCreateWithBytesNoCopy(
    108      kCFAllocatorDefault, (const uint8_t*)reqLocale.BeginReading(),
    109      reqLocale.Length(), kCFStringEncodingASCII, false, kCFAllocatorNull);
    110  if (!identifier) {
    111    return nullptr;
    112  }
    113  CFLocaleRef locale = CFLocaleCreate(kCFAllocatorDefault, identifier);
    114  CFRelease(identifier);
    115  return locale;
    116 }
    117 
    118 /**
    119 * Cocoa API maps nicely to our four styles of date/time.
    120 *
    121 * The only caveat is that Cocoa takes regional preferences modifications
    122 * into account only when we pass an empty string as a locale.
    123 *
    124 * In all other cases it will return the default pattern for a given locale.
    125 */
    126 bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
    127                                        DateTimeFormatStyle aTimeStyle,
    128                                        const nsACString& aLocale,
    129                                        nsACString& aRetVal) {
    130  CFLocaleRef locale = CreateCFLocaleFor(aLocale);
    131  if (!locale) {
    132    return false;
    133  }
    134 
    135  CFDateFormatterRef formatter = CFDateFormatterCreate(
    136      kCFAllocatorDefault, locale, ToCFDateFormatterStyle(aDateStyle),
    137      ToCFDateFormatterStyle(aTimeStyle));
    138  if (!formatter) {
    139    return false;
    140  }
    141  CFStringRef format = CFDateFormatterGetFormat(formatter);
    142  CFRelease(locale);
    143 
    144  CFRange range = CFRangeMake(0, CFStringGetLength(format));
    145  nsAutoString str;
    146  str.SetLength(range.length);
    147  CFStringGetCharacters(format, range,
    148                        reinterpret_cast<UniChar*>(str.BeginWriting()));
    149  CFRelease(formatter);
    150 
    151  aRetVal = NS_ConvertUTF16toUTF8(str);
    152  return true;
    153 }
    154 
    155 void OSPreferences::RemoveObservers() {
    156  ::CFNotificationCenterRemoveObserver(
    157      ::CFNotificationCenterGetLocalCenter(), this,
    158      kCTFontManagerRegisteredFontsChangedNotification, 0);
    159 }