Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#include "OSPreferences.h"
#include "mozilla/intl/LocaleService.h"
#include <Carbon/Carbon.h>
using namespace mozilla::intl;
static void LocaleChangedNotificationCallback(CFNotificationCenterRef center,
void* observer, CFStringRef name,
const void* object,
CFDictionaryRef userInfo) {
if (!::CFEqual(name, kCFLocaleCurrentLocaleDidChangeNotification)) {
OSPreferences::OSPreferences() {
::CFNotificationCenterGetLocalCenter(), this,
kCFLocaleCurrentLocaleDidChangeNotification, 0,
bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
CFArrayRef langs = ::CFLocaleCopyPreferredLanguages();
for (CFIndex i = 0; i < ::CFArrayGetCount(langs); i++) {
CFStringRef lang = (CFStringRef)::CFArrayGetValueAtIndex(langs, i);
AutoTArray<UniChar, 32> buffer;
int size = ::CFStringGetLength(lang);
CFRange range = ::CFRangeMake(0, size);
::CFStringGetCharacters(lang, range, buffer.Elements());
// Convert the locale string to the format that Mozilla expects
NS_LossyConvertUTF16toASCII locale(
reinterpret_cast<const char16_t*>(buffer.Elements()), buffer.Length());
if (CanonicalizeLanguageTag(locale)) {
return !aLocaleList.IsEmpty();
bool OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList) {
// For now we're just taking System Locales since we don't know of any better
// API for regional prefs.
return ReadSystemLocales(aLocaleList);
static CFDateFormatterStyle ToCFDateFormatterStyle(
OSPreferences::DateTimeFormatStyle aFormatStyle) {
switch (aFormatStyle) {
case OSPreferences::DateTimeFormatStyle::None:
return kCFDateFormatterNoStyle;
case OSPreferences::DateTimeFormatStyle::Short:
return kCFDateFormatterShortStyle;
case OSPreferences::DateTimeFormatStyle::Medium:
return kCFDateFormatterMediumStyle;
case OSPreferences::DateTimeFormatStyle::Long:
return kCFDateFormatterLongStyle;
case OSPreferences::DateTimeFormatStyle::Full:
return kCFDateFormatterFullStyle;
case OSPreferences::DateTimeFormatStyle::Invalid:
MOZ_ASSERT_UNREACHABLE("invalid time format");
return kCFDateFormatterNoStyle;
// Given an 8-bit Gecko string, create a corresponding CFLocale;
// if aLocale is empty, returns a copy of the system's current locale.
// May return null on failure.
// Follows Core Foundation's Create rule, so the caller is responsible to
// release the returned reference.
static CFLocaleRef CreateCFLocaleFor(const nsACString& aLocale) {
nsAutoCString reqLocale;
nsAutoCString systemLocale;
if (aLocale.IsEmpty()) {
} else {
bool match = LocaleService::LanguagesMatch(reqLocale, systemLocale);
if (match) {
return ::CFLocaleCopyCurrent();
CFStringRef identifier = CFStringCreateWithBytesNoCopy(
kCFAllocatorDefault, (const uint8_t*)reqLocale.BeginReading(),
reqLocale.Length(), kCFStringEncodingASCII, false, kCFAllocatorNull);
if (!identifier) {
return nullptr;
CFLocaleRef locale = CFLocaleCreate(kCFAllocatorDefault, identifier);
return locale;
* Cocoa API maps nicely to our four styles of date/time.
* The only caveat is that Cocoa takes regional preferences modifications
* into account only when we pass an empty string as a locale.
* In all other cases it will return the default pattern for a given locale.
bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsACString& aRetVal) {
CFLocaleRef locale = CreateCFLocaleFor(aLocale);
if (!locale) {
return false;
CFDateFormatterRef formatter = CFDateFormatterCreate(
kCFAllocatorDefault, locale, ToCFDateFormatterStyle(aDateStyle),
if (!formatter) {
return false;
CFStringRef format = CFDateFormatterGetFormat(formatter);
CFRange range = CFRangeMake(0, CFStringGetLength(format));
nsAutoString str;
CFStringGetCharacters(format, range,
aRetVal = NS_ConvertUTF16toUTF8(str);
return true;
void OSPreferences::RemoveObservers() {
::CFNotificationCenterGetLocalCenter(), this,
kCTFontManagerRegisteredFontsChangedNotification, 0);