michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/FallbackEncoding.h" michael@0: michael@0: #include "mozilla/dom/EncodingUtils.h" michael@0: #include "nsUConvPropertySearch.h" michael@0: #include "nsIChromeRegistry.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/Services.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: static const char* localesFallbacks[][3] = { michael@0: #include "localesfallbacks.properties.h" michael@0: }; michael@0: michael@0: static const char* domainsFallbacks[][3] = { michael@0: #include "domainsfallbacks.properties.h" michael@0: }; michael@0: michael@0: static const char* nonParticipatingDomains[][3] = { michael@0: #include "nonparticipatingdomains.properties.h" michael@0: }; michael@0: michael@0: FallbackEncoding* FallbackEncoding::sInstance = nullptr; michael@0: bool FallbackEncoding::sGuessFallbackFromTopLevelDomain = true; michael@0: michael@0: FallbackEncoding::FallbackEncoding() michael@0: { michael@0: MOZ_COUNT_CTOR(FallbackEncoding); michael@0: MOZ_ASSERT(!FallbackEncoding::sInstance, michael@0: "Singleton already exists."); michael@0: } michael@0: michael@0: FallbackEncoding::~FallbackEncoding() michael@0: { michael@0: MOZ_COUNT_DTOR(FallbackEncoding); michael@0: } michael@0: michael@0: void michael@0: FallbackEncoding::Get(nsACString& aFallback) michael@0: { michael@0: if (!mFallback.IsEmpty()) { michael@0: aFallback = mFallback; michael@0: return; michael@0: } michael@0: michael@0: const nsAdoptingCString& override = michael@0: Preferences::GetCString("intl.charset.fallback.override"); michael@0: // Don't let the user break things by setting the override to unreasonable michael@0: // values via about:config michael@0: if (!EncodingUtils::FindEncodingForLabel(override, mFallback) || michael@0: !EncodingUtils::IsAsciiCompatible(mFallback) || michael@0: mFallback.EqualsLiteral("UTF-8")) { michael@0: mFallback.Truncate(); michael@0: } michael@0: michael@0: if (!mFallback.IsEmpty()) { michael@0: aFallback = mFallback; michael@0: return; michael@0: } michael@0: michael@0: nsAutoCString locale; michael@0: nsCOMPtr registry = michael@0: mozilla::services::GetXULChromeRegistryService(); michael@0: if (registry) { michael@0: registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), locale); michael@0: } michael@0: michael@0: // Let's lower case the string just in case unofficial language packs michael@0: // don't stick to conventions. michael@0: ToLowerCase(locale); // ASCII lowercasing with CString input! michael@0: michael@0: // Special case Traditional Chinese before throwing away stuff after the michael@0: // language itself. Today we only ship zh-TW, but be defensive about michael@0: // possible future values. michael@0: if (locale.EqualsLiteral("zh-tw") || michael@0: locale.EqualsLiteral("zh-hk") || michael@0: locale.EqualsLiteral("zh-mo") || michael@0: locale.EqualsLiteral("zh-hant")) { michael@0: mFallback.AssignLiteral("Big5"); michael@0: aFallback = mFallback; michael@0: return; michael@0: } michael@0: michael@0: // Throw away regions and other variants to accommodate weird stuff seen michael@0: // in telemetry--apparently unofficial language packs. michael@0: int32_t index = locale.FindChar('-'); michael@0: if (index >= 0) { michael@0: locale.Truncate(index); michael@0: } michael@0: michael@0: if (NS_FAILED(nsUConvPropertySearch::SearchPropertyValue( michael@0: localesFallbacks, ArrayLength(localesFallbacks), locale, mFallback))) { michael@0: mFallback.AssignLiteral("windows-1252"); michael@0: } michael@0: michael@0: aFallback = mFallback; michael@0: } michael@0: michael@0: void michael@0: FallbackEncoding::FromLocale(nsACString& aFallback) michael@0: { michael@0: MOZ_ASSERT(FallbackEncoding::sInstance, michael@0: "Using uninitialized fallback cache."); michael@0: FallbackEncoding::sInstance->Get(aFallback); michael@0: } michael@0: michael@0: // PrefChangedFunc michael@0: void michael@0: FallbackEncoding::PrefChanged(const char*, void*) michael@0: { michael@0: MOZ_ASSERT(FallbackEncoding::sInstance, michael@0: "Pref callback called with null fallback cache."); michael@0: FallbackEncoding::sInstance->Invalidate(); michael@0: } michael@0: michael@0: void michael@0: FallbackEncoding::Initialize() michael@0: { michael@0: MOZ_ASSERT(!FallbackEncoding::sInstance, michael@0: "Initializing pre-existing fallback cache."); michael@0: FallbackEncoding::sInstance = new FallbackEncoding; michael@0: Preferences::RegisterCallback(FallbackEncoding::PrefChanged, michael@0: "intl.charset.fallback.override", michael@0: nullptr); michael@0: Preferences::RegisterCallback(FallbackEncoding::PrefChanged, michael@0: "general.useragent.locale", michael@0: nullptr); michael@0: Preferences::AddBoolVarCache(&sGuessFallbackFromTopLevelDomain, michael@0: "intl.charset.fallback.tld"); michael@0: } michael@0: michael@0: void michael@0: FallbackEncoding::Shutdown() michael@0: { michael@0: MOZ_ASSERT(FallbackEncoding::sInstance, michael@0: "Releasing non-existent fallback cache."); michael@0: delete FallbackEncoding::sInstance; michael@0: FallbackEncoding::sInstance = nullptr; michael@0: } michael@0: michael@0: bool michael@0: FallbackEncoding::IsParticipatingTopLevelDomain(const nsACString& aTLD) michael@0: { michael@0: nsAutoCString dummy; michael@0: return NS_FAILED(nsUConvPropertySearch::SearchPropertyValue( michael@0: nonParticipatingDomains, michael@0: ArrayLength(nonParticipatingDomains), michael@0: aTLD, michael@0: dummy)); michael@0: } michael@0: michael@0: void michael@0: FallbackEncoding::FromTopLevelDomain(const nsACString& aTLD, michael@0: nsACString& aFallback) michael@0: { michael@0: if (NS_FAILED(nsUConvPropertySearch::SearchPropertyValue( michael@0: domainsFallbacks, ArrayLength(domainsFallbacks), aTLD, aFallback))) { michael@0: aFallback.AssignLiteral("windows-1252"); michael@0: } michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla