mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-11-08 22:11:52 +00:00
983 lines
28 KiB
C++
983 lines
28 KiB
C++
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||
|
/* vim: set ts=2 sts=2 sw=2 et tw=80: */
|
||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||
|
|
||
|
#include "mozilla/dom/ContentParent.h"
|
||
|
#include "RegistryMessageUtils.h"
|
||
|
#include "nsResProtocolHandler.h"
|
||
|
|
||
|
#include "nsChromeRegistryChrome.h"
|
||
|
|
||
|
#if defined(XP_WIN)
|
||
|
#include <windows.h>
|
||
|
#elif defined(XP_MACOSX)
|
||
|
#include <CoreServices/CoreServices.h>
|
||
|
#endif
|
||
|
|
||
|
#include "nsArrayEnumerator.h"
|
||
|
#include "nsComponentManager.h"
|
||
|
#include "nsEnumeratorUtils.h"
|
||
|
#include "nsNetUtil.h"
|
||
|
#include "nsStringEnumerator.h"
|
||
|
#include "nsTextFormatter.h"
|
||
|
#include "nsXPCOMCIDInternal.h"
|
||
|
|
||
|
#include "mozilla/LookAndFeel.h"
|
||
|
#include "mozilla/unused.h"
|
||
|
|
||
|
#include "nsICommandLine.h"
|
||
|
#include "nsILocaleService.h"
|
||
|
#include "nsIObserverService.h"
|
||
|
#include "nsIPrefBranch.h"
|
||
|
#include "nsIPrefService.h"
|
||
|
#include "mozilla/Preferences.h"
|
||
|
#include "nsIResProtocolHandler.h"
|
||
|
#include "nsIScriptError.h"
|
||
|
#include "nsIXPConnect.h"
|
||
|
#include "nsIXULRuntime.h"
|
||
|
|
||
|
#define UILOCALE_CMD_LINE_ARG "UILocale"
|
||
|
|
||
|
#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
|
||
|
#define SELECTED_LOCALE_PREF "general.useragent.locale"
|
||
|
#define SELECTED_SKIN_PREF "general.skins.selectedSkin"
|
||
|
#define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
|
||
|
|
||
|
using namespace mozilla;
|
||
|
using mozilla::dom::ContentParent;
|
||
|
using mozilla::dom::PContentParent;
|
||
|
|
||
|
// We use a "best-fit" algorithm for matching locales and themes.
|
||
|
// 1) the exact selected locale/theme
|
||
|
// 2) (locales only) same language, different country
|
||
|
// e.g. en-GB is the selected locale, only en-US is available
|
||
|
// 3) any available locale/theme
|
||
|
|
||
|
/**
|
||
|
* Match the language-part of two lang-COUNTRY codes, hopefully but
|
||
|
* not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
|
||
|
* work, any other garbage-in will produce undefined results as long
|
||
|
* as it does not crash.
|
||
|
*/
|
||
|
static bool
|
||
|
LanguagesMatch(const nsACString& a, const nsACString& b)
|
||
|
{
|
||
|
if (a.Length() < 2 || b.Length() < 2)
|
||
|
return false;
|
||
|
|
||
|
nsACString::const_iterator as, ae, bs, be;
|
||
|
a.BeginReading(as);
|
||
|
a.EndReading(ae);
|
||
|
b.BeginReading(bs);
|
||
|
b.EndReading(be);
|
||
|
|
||
|
while (*as == *bs) {
|
||
|
if (*as == '-')
|
||
|
return true;
|
||
|
|
||
|
++as; ++bs;
|
||
|
|
||
|
// reached the end
|
||
|
if (as == ae && bs == be)
|
||
|
return true;
|
||
|
|
||
|
// "a" is short
|
||
|
if (as == ae)
|
||
|
return (*bs == '-');
|
||
|
|
||
|
// "b" is short
|
||
|
if (bs == be)
|
||
|
return (*as == '-');
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
nsChromeRegistryChrome::nsChromeRegistryChrome()
|
||
|
: mProfileLoaded(false)
|
||
|
, mDynamicRegistration(true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
nsChromeRegistryChrome::~nsChromeRegistryChrome()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsChromeRegistryChrome::Init()
|
||
|
{
|
||
|
nsresult rv = nsChromeRegistry::Init();
|
||
|
if (NS_FAILED(rv))
|
||
|
return rv;
|
||
|
|
||
|
mSelectedLocale = NS_LITERAL_CSTRING("en-US");
|
||
|
mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
|
||
|
|
||
|
bool safeMode = false;
|
||
|
nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
|
||
|
if (xulrun)
|
||
|
xulrun->GetInSafeMode(&safeMode);
|
||
|
|
||
|
nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||
|
nsCOMPtr<nsIPrefBranch> prefs;
|
||
|
|
||
|
if (safeMode)
|
||
|
prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
|
||
|
else
|
||
|
prefs = do_QueryInterface(prefserv);
|
||
|
|
||
|
if (!prefs) {
|
||
|
NS_WARNING("Could not get pref service!");
|
||
|
}
|
||
|
else {
|
||
|
nsXPIDLCString provider;
|
||
|
rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
|
||
|
if (NS_SUCCEEDED(rv))
|
||
|
mSelectedSkin = provider;
|
||
|
|
||
|
SelectLocaleFromPref(prefs);
|
||
|
|
||
|
rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true);
|
||
|
rv = prefs->AddObserver(SELECTED_LOCALE_PREF, this, true);
|
||
|
rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
|
||
|
}
|
||
|
|
||
|
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
|
||
|
if (obsService) {
|
||
|
obsService->AddObserver(this, "command-line-startup", true);
|
||
|
obsService->AddObserver(this, "profile-initial-state", true);
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::CheckForOSAccessibility()
|
||
|
{
|
||
|
int32_t useAccessibilityTheme =
|
||
|
LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
|
||
|
|
||
|
if (useAccessibilityTheme) {
|
||
|
/* Set the skin to classic and remove pref observers */
|
||
|
if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
|
||
|
mSelectedSkin.AssignLiteral("classic/1.0");
|
||
|
RefreshSkins();
|
||
|
}
|
||
|
|
||
|
nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||
|
if (prefs) {
|
||
|
prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
|
||
|
nsIUTF8StringEnumerator* *aResult)
|
||
|
{
|
||
|
nsCString realpackage;
|
||
|
nsresult rv = OverrideLocalePackage(aPackage, realpackage);
|
||
|
if (NS_FAILED(rv))
|
||
|
return rv;
|
||
|
|
||
|
nsTArray<nsCString> *a = new nsTArray<nsCString>;
|
||
|
if (!a)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
PackageEntry* entry;
|
||
|
if (mPackagesHash.Get(realpackage, &entry)) {
|
||
|
entry->locales.EnumerateToArray(a);
|
||
|
}
|
||
|
|
||
|
rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
|
||
|
if (NS_FAILED(rv))
|
||
|
delete a;
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
static nsresult
|
||
|
getUILangCountry(nsACString& aUILang)
|
||
|
{
|
||
|
nsresult rv;
|
||
|
|
||
|
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||
|
|
||
|
nsAutoString uiLang;
|
||
|
rv = localeService->GetLocaleComponentForUserAgent(uiLang);
|
||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||
|
|
||
|
CopyUTF16toUTF8(uiLang, aUILang);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
|
||
|
{
|
||
|
*aResult = false;
|
||
|
|
||
|
nsAutoCString locale;
|
||
|
GetSelectedLocale(package, locale);
|
||
|
if (locale.Length() < 2)
|
||
|
return NS_OK;
|
||
|
|
||
|
*aResult = GetDirectionForLocale(locale);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
|
||
|
nsACString& aLocale)
|
||
|
{
|
||
|
nsCString realpackage;
|
||
|
nsresult rv = OverrideLocalePackage(aPackage, realpackage);
|
||
|
if (NS_FAILED(rv))
|
||
|
return rv;
|
||
|
PackageEntry* entry;
|
||
|
if (!mPackagesHash.Get(realpackage, &entry))
|
||
|
return NS_ERROR_FILE_NOT_FOUND;
|
||
|
|
||
|
aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
|
||
|
if (aLocale.IsEmpty())
|
||
|
return NS_ERROR_FAILURE;
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
|
||
|
nsACString& aOverride)
|
||
|
{
|
||
|
const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
|
||
|
nsAdoptingCString override = mozilla::Preferences::GetCString(PromiseFlatCString(pref).get());
|
||
|
if (override) {
|
||
|
aOverride = override;
|
||
|
}
|
||
|
else {
|
||
|
aOverride = aPackage;
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs)
|
||
|
{
|
||
|
nsresult rv;
|
||
|
bool matchOSLocale = false;
|
||
|
rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
|
||
|
|
||
|
if (NS_SUCCEEDED(rv) && matchOSLocale) {
|
||
|
// compute lang and region code only when needed!
|
||
|
nsAutoCString uiLocale;
|
||
|
rv = getUILangCountry(uiLocale);
|
||
|
if (NS_SUCCEEDED(rv))
|
||
|
mSelectedLocale = uiLocale;
|
||
|
}
|
||
|
else {
|
||
|
nsXPIDLCString provider;
|
||
|
rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
|
||
|
if (NS_SUCCEEDED(rv)) {
|
||
|
mSelectedLocale = provider;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NS_FAILED(rv))
|
||
|
NS_ERROR("Couldn't select locale from pref!");
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
|
||
|
const char16_t *someData)
|
||
|
{
|
||
|
nsresult rv = NS_OK;
|
||
|
|
||
|
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
|
||
|
nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
|
||
|
NS_ASSERTION(prefs, "Bad observer call!");
|
||
|
|
||
|
NS_ConvertUTF16toUTF8 pref(someData);
|
||
|
|
||
|
if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
|
||
|
pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
|
||
|
rv = UpdateSelectedLocale();
|
||
|
if (NS_SUCCEEDED(rv) && mProfileLoaded)
|
||
|
FlushAllCaches();
|
||
|
}
|
||
|
else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
|
||
|
nsXPIDLCString provider;
|
||
|
rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
|
||
|
if (NS_FAILED(rv)) {
|
||
|
NS_ERROR("Couldn't get new skin pref!");
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
mSelectedSkin = provider;
|
||
|
RefreshSkins();
|
||
|
} else {
|
||
|
NS_ERROR("Unexpected pref!");
|
||
|
}
|
||
|
}
|
||
|
else if (!strcmp("command-line-startup", aTopic)) {
|
||
|
nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
|
||
|
if (cmdLine) {
|
||
|
nsAutoString uiLocale;
|
||
|
rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
|
||
|
false, uiLocale);
|
||
|
if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
|
||
|
CopyUTF16toUTF8(uiLocale, mSelectedLocale);
|
||
|
nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||
|
if (prefs) {
|
||
|
prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (!strcmp("profile-initial-state", aTopic)) {
|
||
|
mProfileLoaded = true;
|
||
|
}
|
||
|
else {
|
||
|
NS_ERROR("Unexpected observer topic!");
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::CheckForNewChrome()
|
||
|
{
|
||
|
mPackagesHash.Clear();
|
||
|
mOverlayHash.Clear();
|
||
|
mStyleHash.Clear();
|
||
|
mOverrideTable.Clear();
|
||
|
|
||
|
mDynamicRegistration = false;
|
||
|
|
||
|
nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
|
||
|
|
||
|
mDynamicRegistration = true;
|
||
|
|
||
|
SendRegisteredChrome(nullptr);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
|
||
|
{
|
||
|
nsresult rv = NS_OK;
|
||
|
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||
|
if (prefs) {
|
||
|
rv = SelectLocaleFromPref(prefs);
|
||
|
if (NS_SUCCEEDED(rv)) {
|
||
|
nsCOMPtr<nsIObserverService> obsSvc =
|
||
|
mozilla::services::GetObserverService();
|
||
|
NS_ASSERTION(obsSvc, "Couldn't get observer service.");
|
||
|
obsSvc->NotifyObservers((nsIChromeRegistry*) this,
|
||
|
"selected-locale-has-changed", nullptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
SerializeURI(nsIURI* aURI,
|
||
|
SerializedURI& aSerializedURI)
|
||
|
{
|
||
|
if (!aURI)
|
||
|
return;
|
||
|
|
||
|
aURI->GetSpec(aSerializedURI.spec);
|
||
|
aURI->GetOriginCharset(aSerializedURI.charset);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::SendRegisteredChrome(
|
||
|
mozilla::dom::PContentParent* aParent)
|
||
|
{
|
||
|
InfallibleTArray<ChromePackage> packages;
|
||
|
InfallibleTArray<SubstitutionMapping> resources;
|
||
|
InfallibleTArray<OverrideMapping> overrides;
|
||
|
|
||
|
for (auto iter = mPackagesHash.Iter(); !iter.Done(); iter.Next()) {
|
||
|
ChromePackage chromePackage;
|
||
|
ChromePackageFromPackageEntry(iter.Key(), iter.UserData(), &chromePackage,
|
||
|
mSelectedLocale, mSelectedSkin);
|
||
|
packages.AppendElement(chromePackage);
|
||
|
}
|
||
|
|
||
|
// If we were passed a parent then a new child process has been created and
|
||
|
// has requested all of the chrome so send it the resources too. Otherwise
|
||
|
// resource mappings are sent by the resource protocol handler dynamically.
|
||
|
if (aParent) {
|
||
|
nsCOMPtr<nsIIOService> io (do_GetIOService());
|
||
|
NS_ENSURE_TRUE_VOID(io);
|
||
|
|
||
|
nsCOMPtr<nsIProtocolHandler> ph;
|
||
|
nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
|
||
|
NS_ENSURE_SUCCESS_VOID(rv);
|
||
|
|
||
|
nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
|
||
|
nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
|
||
|
rph->CollectSubstitutions(resources);
|
||
|
}
|
||
|
|
||
|
for (auto iter = mOverrideTable.Iter(); !iter.Done(); iter.Next()) {
|
||
|
SerializedURI chromeURI, overrideURI;
|
||
|
|
||
|
SerializeURI(iter.Key(), chromeURI);
|
||
|
SerializeURI(iter.UserData(), overrideURI);
|
||
|
|
||
|
OverrideMapping override = { chromeURI, overrideURI };
|
||
|
overrides.AppendElement(override);
|
||
|
}
|
||
|
|
||
|
if (aParent) {
|
||
|
bool success = aParent->SendRegisterChrome(packages, resources, overrides,
|
||
|
mSelectedLocale, false);
|
||
|
NS_ENSURE_TRUE_VOID(success);
|
||
|
} else {
|
||
|
nsTArray<ContentParent*> parents;
|
||
|
ContentParent::GetAll(parents);
|
||
|
if (!parents.Length())
|
||
|
return;
|
||
|
|
||
|
for (uint32_t i = 0; i < parents.Length(); i++) {
|
||
|
DebugOnly<bool> success =
|
||
|
parents[i]->SendRegisterChrome(packages, resources, overrides,
|
||
|
mSelectedLocale, true);
|
||
|
NS_WARN_IF_FALSE(success, "couldn't reset a child's registered chrome");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* static */ void
|
||
|
nsChromeRegistryChrome::ChromePackageFromPackageEntry(const nsACString& aPackageName,
|
||
|
PackageEntry* aPackage,
|
||
|
ChromePackage* aChromePackage,
|
||
|
const nsCString& aSelectedLocale,
|
||
|
const nsCString& aSelectedSkin)
|
||
|
{
|
||
|
SerializeURI(aPackage->baseURI, aChromePackage->contentBaseURI);
|
||
|
SerializeURI(aPackage->locales.GetBase(aSelectedLocale,
|
||
|
nsProviderArray::LOCALE),
|
||
|
aChromePackage->localeBaseURI);
|
||
|
SerializeURI(aPackage->skins.GetBase(aSelectedSkin, nsProviderArray::ANY),
|
||
|
aChromePackage->skinBaseURI);
|
||
|
aChromePackage->package = aPackageName;
|
||
|
aChromePackage->flags = aPackage->flags;
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
CanLoadResource(nsIURI* aResourceURI)
|
||
|
{
|
||
|
bool isLocalResource = false;
|
||
|
(void)NS_URIChainHasFlags(aResourceURI,
|
||
|
nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
|
||
|
&isLocalResource);
|
||
|
return isLocalResource;
|
||
|
}
|
||
|
|
||
|
nsIURI*
|
||
|
nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
|
||
|
const nsCString& aProvider,
|
||
|
const nsCString& aPath)
|
||
|
{
|
||
|
PackageEntry* entry;
|
||
|
if (!mPackagesHash.Get(aPackage, &entry)) {
|
||
|
if (!mInitialized)
|
||
|
return nullptr;
|
||
|
|
||
|
LogMessage("No chrome package registered for chrome://%s/%s/%s",
|
||
|
aPackage.get(), aProvider.get(), aPath.get());
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
if (aProvider.EqualsLiteral("locale")) {
|
||
|
return entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
|
||
|
}
|
||
|
else if (aProvider.EqualsLiteral("skin")) {
|
||
|
return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
|
||
|
}
|
||
|
else if (aProvider.EqualsLiteral("content")) {
|
||
|
return entry->baseURI;
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
|
||
|
uint32_t* aFlags)
|
||
|
{
|
||
|
PackageEntry* entry;
|
||
|
if (!mPackagesHash.Get(aPackage, &entry))
|
||
|
return NS_ERROR_FILE_NOT_FOUND;
|
||
|
|
||
|
*aFlags = entry->flags;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
nsChromeRegistryChrome::ProviderEntry*
|
||
|
nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
|
||
|
{
|
||
|
size_t i = mArray.Length();
|
||
|
if (!i)
|
||
|
return nullptr;
|
||
|
|
||
|
ProviderEntry* found = nullptr; // Only set if we find a partial-match locale
|
||
|
ProviderEntry* entry = nullptr;
|
||
|
|
||
|
while (i--) {
|
||
|
entry = &mArray[i];
|
||
|
if (aPreferred.Equals(entry->provider))
|
||
|
return entry;
|
||
|
|
||
|
if (aType != LOCALE)
|
||
|
continue;
|
||
|
|
||
|
if (LanguagesMatch(aPreferred, entry->provider)) {
|
||
|
found = entry;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!found && entry->provider.EqualsLiteral("en-US"))
|
||
|
found = entry;
|
||
|
}
|
||
|
|
||
|
if (!found && aType != EXACT)
|
||
|
return entry;
|
||
|
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
nsIURI*
|
||
|
nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
|
||
|
{
|
||
|
ProviderEntry* provider = GetProvider(aPreferred, aType);
|
||
|
|
||
|
if (!provider)
|
||
|
return nullptr;
|
||
|
|
||
|
return provider->baseURI;
|
||
|
}
|
||
|
|
||
|
const nsACString&
|
||
|
nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
|
||
|
{
|
||
|
ProviderEntry* entry = GetProvider(aPreferred, aType);
|
||
|
|
||
|
if (entry)
|
||
|
return entry->provider;
|
||
|
|
||
|
return EmptyCString();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
|
||
|
{
|
||
|
ProviderEntry* provider = GetProvider(aProvider, EXACT);
|
||
|
|
||
|
if (provider) {
|
||
|
provider->baseURI = aBaseURL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// no existing entries, add a new one
|
||
|
mArray.AppendElement(ProviderEntry(aProvider, aBaseURL));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
|
||
|
{
|
||
|
int32_t i = mArray.Length();
|
||
|
while (i--) {
|
||
|
a->AppendElement(mArray[i].provider);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
|
||
|
{
|
||
|
int32_t i = mArray.Count();
|
||
|
while (i--) {
|
||
|
bool equals;
|
||
|
if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mArray.AppendObject(aURI);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
|
||
|
{
|
||
|
OverlayListEntry* entry = mTable.PutEntry(aBase);
|
||
|
if (entry)
|
||
|
entry->AddURI(aOverlay);
|
||
|
}
|
||
|
|
||
|
const nsCOMArray<nsIURI>*
|
||
|
nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
|
||
|
{
|
||
|
OverlayListEntry* entry = mTable.GetEntry(aBase);
|
||
|
if (!entry)
|
||
|
return nullptr;
|
||
|
|
||
|
return &entry->mArray;
|
||
|
}
|
||
|
|
||
|
#ifdef MOZ_XUL
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL,
|
||
|
nsISimpleEnumerator **aResult)
|
||
|
{
|
||
|
nsCOMPtr<nsIURI> chromeURLWithoutHash;
|
||
|
if (aChromeURL) {
|
||
|
aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
|
||
|
}
|
||
|
const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(chromeURLWithoutHash);
|
||
|
if (!parray)
|
||
|
return NS_NewEmptyEnumerator(aResult);
|
||
|
|
||
|
return NS_NewArrayEnumerator(aResult, *parray);
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
|
||
|
nsISimpleEnumerator **aResult)
|
||
|
{
|
||
|
nsCOMPtr<nsIURI> chromeURLWithoutHash;
|
||
|
if (aChromeURL) {
|
||
|
aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
|
||
|
}
|
||
|
const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(chromeURLWithoutHash);
|
||
|
if (!parray)
|
||
|
return NS_NewEmptyEnumerator(aResult);
|
||
|
|
||
|
return NS_NewArrayEnumerator(aResult, *parray);
|
||
|
}
|
||
|
#endif // MOZ_XUL
|
||
|
|
||
|
nsIURI*
|
||
|
nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
|
||
|
{
|
||
|
if (!mManifestURI) {
|
||
|
nsCString uri;
|
||
|
mFile.GetURIString(uri);
|
||
|
NS_NewURI(getter_AddRefs(mManifestURI), uri);
|
||
|
}
|
||
|
return mManifestURI;
|
||
|
}
|
||
|
|
||
|
nsIXPConnect*
|
||
|
nsChromeRegistry::ManifestProcessingContext::GetXPConnect()
|
||
|
{
|
||
|
if (!mXPConnect)
|
||
|
mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
|
||
|
|
||
|
return mXPConnect;
|
||
|
}
|
||
|
|
||
|
already_AddRefed<nsIURI>
|
||
|
nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
|
||
|
{
|
||
|
nsIURI* baseuri = GetManifestURI();
|
||
|
if (!baseuri)
|
||
|
return nullptr;
|
||
|
|
||
|
nsCOMPtr<nsIURI> resolved;
|
||
|
nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
|
||
|
if (NS_FAILED(rv))
|
||
|
return nullptr;
|
||
|
|
||
|
return resolved.forget();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
EnsureLowerCase(char *aBuf)
|
||
|
{
|
||
|
for (; *aBuf; ++aBuf) {
|
||
|
char ch = *aBuf;
|
||
|
if (ch >= 'A' && ch <= 'Z')
|
||
|
*aBuf = ch + 'a' - 'A';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
SendManifestEntry(const ChromeRegistryItem &aItem)
|
||
|
{
|
||
|
nsTArray<ContentParent*> parents;
|
||
|
ContentParent::GetAll(parents);
|
||
|
if (!parents.Length())
|
||
|
return;
|
||
|
|
||
|
for (uint32_t i = 0; i < parents.Length(); i++) {
|
||
|
Unused << parents[i]->SendRegisterChromeItem(aItem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* package = argv[0];
|
||
|
char* uri = argv[1];
|
||
|
|
||
|
EnsureLowerCase(package);
|
||
|
|
||
|
nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
|
||
|
if (!resolved) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI '%s'.", uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(resolved)) {
|
||
|
LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, cannot register non-local URI '%s' as content.",
|
||
|
uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nsDependentCString packageName(package);
|
||
|
PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
|
||
|
entry->baseURI = resolved;
|
||
|
entry->flags = flags;
|
||
|
|
||
|
if (mDynamicRegistration) {
|
||
|
ChromePackage chromePackage;
|
||
|
ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
|
||
|
mSelectedLocale, mSelectedSkin);
|
||
|
SendManifestEntry(chromePackage);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* package = argv[0];
|
||
|
char* provider = argv[1];
|
||
|
char* uri = argv[2];
|
||
|
|
||
|
EnsureLowerCase(package);
|
||
|
|
||
|
nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
|
||
|
if (!resolved) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI '%s'.", uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(resolved)) {
|
||
|
LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, cannot register non-local URI '%s' as content.",
|
||
|
uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nsDependentCString packageName(package);
|
||
|
PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
|
||
|
entry->locales.SetBase(nsDependentCString(provider), resolved);
|
||
|
|
||
|
if (mDynamicRegistration) {
|
||
|
ChromePackage chromePackage;
|
||
|
ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
|
||
|
mSelectedLocale, mSelectedSkin);
|
||
|
SendManifestEntry(chromePackage);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* package = argv[0];
|
||
|
char* provider = argv[1];
|
||
|
char* uri = argv[2];
|
||
|
|
||
|
EnsureLowerCase(package);
|
||
|
|
||
|
nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
|
||
|
if (!resolved) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI '%s'.", uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(resolved)) {
|
||
|
LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, cannot register non-local URI '%s' as content.",
|
||
|
uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nsDependentCString packageName(package);
|
||
|
PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
|
||
|
entry->skins.SetBase(nsDependentCString(provider), resolved);
|
||
|
|
||
|
if (mDynamicRegistration) {
|
||
|
ChromePackage chromePackage;
|
||
|
ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
|
||
|
mSelectedLocale, mSelectedSkin);
|
||
|
SendManifestEntry(chromePackage);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* base = argv[0];
|
||
|
char* overlay = argv[1];
|
||
|
|
||
|
nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
|
||
|
nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
|
||
|
if (!baseuri || !overlayuri) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(overlayuri)) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"Cannot register non-local URI '%s' as an overlay.", overlay);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nsCOMPtr<nsIURI> baseuriWithoutHash;
|
||
|
baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
|
||
|
|
||
|
mOverlayHash.Add(baseuriWithoutHash, overlayuri);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* base = argv[0];
|
||
|
char* overlay = argv[1];
|
||
|
|
||
|
nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
|
||
|
nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
|
||
|
if (!baseuri || !overlayuri) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(overlayuri)) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"Cannot register non-local URI '%s' as a style overlay.", overlay);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nsCOMPtr<nsIURI> baseuriWithoutHash;
|
||
|
baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
|
||
|
|
||
|
mStyleHash.Add(baseuriWithoutHash, overlayuri);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* chrome = argv[0];
|
||
|
char* resolved = argv[1];
|
||
|
|
||
|
nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
|
||
|
nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
|
||
|
if (!chromeuri || !resolveduri) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (cx.mType == NS_SKIN_LOCATION) {
|
||
|
bool chromeSkinOnly = false;
|
||
|
nsresult rv = chromeuri->SchemeIs("chrome", &chromeSkinOnly);
|
||
|
chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
|
||
|
if (chromeSkinOnly) {
|
||
|
rv = resolveduri->SchemeIs("chrome", &chromeSkinOnly);
|
||
|
chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
|
||
|
}
|
||
|
if (chromeSkinOnly) {
|
||
|
nsAutoCString chromePath, resolvedPath;
|
||
|
chromeuri->GetPath(chromePath);
|
||
|
resolveduri->GetPath(resolvedPath);
|
||
|
chromeSkinOnly = StringBeginsWith(chromePath, NS_LITERAL_CSTRING("/skin/")) &&
|
||
|
StringBeginsWith(resolvedPath, NS_LITERAL_CSTRING("/skin/"));
|
||
|
}
|
||
|
if (!chromeSkinOnly) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"Cannot register non-chrome://.../skin/ URIs '%s' and '%s' as overrides and/or to be overridden from a skin manifest.",
|
||
|
chrome, resolved);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(resolveduri)) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"Cannot register non-local URI '%s' for an override.", resolved);
|
||
|
return;
|
||
|
}
|
||
|
mOverrideTable.Put(chromeuri, resolveduri);
|
||
|
|
||
|
if (mDynamicRegistration) {
|
||
|
SerializedURI serializedChrome;
|
||
|
SerializedURI serializedOverride;
|
||
|
|
||
|
SerializeURI(chromeuri, serializedChrome);
|
||
|
SerializeURI(resolveduri, serializedOverride);
|
||
|
|
||
|
OverrideMapping override = { serializedChrome, serializedOverride };
|
||
|
SendManifestEntry(override);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno,
|
||
|
char *const * argv, int flags)
|
||
|
{
|
||
|
char* package = argv[0];
|
||
|
char* uri = argv[1];
|
||
|
|
||
|
EnsureLowerCase(package);
|
||
|
nsDependentCString host(package);
|
||
|
|
||
|
nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
|
||
|
if (!io) {
|
||
|
NS_WARNING("No IO service trying to process chrome manifests");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nsCOMPtr<nsIProtocolHandler> ph;
|
||
|
nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
|
||
|
if (NS_FAILED(rv))
|
||
|
return;
|
||
|
|
||
|
nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
|
||
|
|
||
|
nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
|
||
|
if (!resolved) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"During chrome registration, unable to create URI '%s'.", uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!CanLoadResource(resolved)) {
|
||
|
LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
|
||
|
"Warning: cannot register non-local URI '%s' as a resource.",
|
||
|
uri);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rph->SetSubstitution(host, resolved);
|
||
|
}
|