1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/chrome/src/nsChromeRegistryChrome.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1039 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/dom/PContentParent.h" 1.10 +#include "RegistryMessageUtils.h" 1.11 +#include "nsResProtocolHandler.h" 1.12 + 1.13 +#include "nsChromeRegistryChrome.h" 1.14 + 1.15 +#if defined(XP_WIN) 1.16 +#include <windows.h> 1.17 +#elif defined(XP_MACOSX) 1.18 +#include <CoreServices/CoreServices.h> 1.19 +#endif 1.20 + 1.21 +#include "nsArrayEnumerator.h" 1.22 +#include "nsComponentManager.h" 1.23 +#include "nsEnumeratorUtils.h" 1.24 +#include "nsNetUtil.h" 1.25 +#include "nsStringEnumerator.h" 1.26 +#include "nsTextFormatter.h" 1.27 +#include "nsXPCOMCIDInternal.h" 1.28 + 1.29 +#include "mozilla/LookAndFeel.h" 1.30 + 1.31 +#include "nsICommandLine.h" 1.32 +#include "nsILocaleService.h" 1.33 +#include "nsIObserverService.h" 1.34 +#include "nsIPrefBranch.h" 1.35 +#include "nsIPrefService.h" 1.36 +#include "mozilla/Preferences.h" 1.37 +#include "nsIResProtocolHandler.h" 1.38 +#include "nsIScriptError.h" 1.39 +#include "nsIXPConnect.h" 1.40 +#include "nsIXULRuntime.h" 1.41 + 1.42 +#define UILOCALE_CMD_LINE_ARG "UILocale" 1.43 + 1.44 +#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS" 1.45 +#define SELECTED_LOCALE_PREF "general.useragent.locale" 1.46 +#define SELECTED_SKIN_PREF "general.skins.selectedSkin" 1.47 +#define PACKAGE_OVERRIDE_BRANCH "chrome.override_package." 1.48 + 1.49 +using namespace mozilla; 1.50 + 1.51 +static PLDHashOperator 1.52 +RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, uint32_t number, void *arg) 1.53 +{ 1.54 + return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE); 1.55 +} 1.56 + 1.57 +// We use a "best-fit" algorithm for matching locales and themes. 1.58 +// 1) the exact selected locale/theme 1.59 +// 2) (locales only) same language, different country 1.60 +// e.g. en-GB is the selected locale, only en-US is available 1.61 +// 3) any available locale/theme 1.62 + 1.63 +/** 1.64 + * Match the language-part of two lang-COUNTRY codes, hopefully but 1.65 + * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also 1.66 + * work, any other garbage-in will produce undefined results as long 1.67 + * as it does not crash. 1.68 + */ 1.69 +static bool 1.70 +LanguagesMatch(const nsACString& a, const nsACString& b) 1.71 +{ 1.72 + if (a.Length() < 2 || b.Length() < 2) 1.73 + return false; 1.74 + 1.75 + nsACString::const_iterator as, ae, bs, be; 1.76 + a.BeginReading(as); 1.77 + a.EndReading(ae); 1.78 + b.BeginReading(bs); 1.79 + b.EndReading(be); 1.80 + 1.81 + while (*as == *bs) { 1.82 + if (*as == '-') 1.83 + return true; 1.84 + 1.85 + ++as; ++bs; 1.86 + 1.87 + // reached the end 1.88 + if (as == ae && bs == be) 1.89 + return true; 1.90 + 1.91 + // "a" is short 1.92 + if (as == ae) 1.93 + return (*bs == '-'); 1.94 + 1.95 + // "b" is short 1.96 + if (bs == be) 1.97 + return (*as == '-'); 1.98 + } 1.99 + 1.100 + return false; 1.101 +} 1.102 + 1.103 +nsChromeRegistryChrome::nsChromeRegistryChrome() 1.104 + : mProfileLoaded(false) 1.105 +{ 1.106 + mPackagesHash.ops = nullptr; 1.107 +} 1.108 + 1.109 +nsChromeRegistryChrome::~nsChromeRegistryChrome() 1.110 +{ 1.111 + if (mPackagesHash.ops) 1.112 + PL_DHashTableFinish(&mPackagesHash); 1.113 +} 1.114 + 1.115 +nsresult 1.116 +nsChromeRegistryChrome::Init() 1.117 +{ 1.118 + nsresult rv = nsChromeRegistry::Init(); 1.119 + if (NS_FAILED(rv)) 1.120 + return rv; 1.121 + 1.122 + mSelectedLocale = NS_LITERAL_CSTRING("en-US"); 1.123 + mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0"); 1.124 + 1.125 + PL_DHashTableInit(&mPackagesHash, &kTableOps, 1.126 + nullptr, sizeof(PackageEntry), 16); 1.127 + 1.128 + bool safeMode = false; 1.129 + nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID)); 1.130 + if (xulrun) 1.131 + xulrun->GetInSafeMode(&safeMode); 1.132 + 1.133 + nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID)); 1.134 + nsCOMPtr<nsIPrefBranch> prefs; 1.135 + 1.136 + if (safeMode) 1.137 + prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs)); 1.138 + else 1.139 + prefs = do_QueryInterface(prefserv); 1.140 + 1.141 + if (!prefs) { 1.142 + NS_WARNING("Could not get pref service!"); 1.143 + } 1.144 + else { 1.145 + nsXPIDLCString provider; 1.146 + rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider)); 1.147 + if (NS_SUCCEEDED(rv)) 1.148 + mSelectedSkin = provider; 1.149 + 1.150 + SelectLocaleFromPref(prefs); 1.151 + 1.152 + rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true); 1.153 + rv = prefs->AddObserver(SELECTED_LOCALE_PREF, this, true); 1.154 + rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true); 1.155 + } 1.156 + 1.157 + nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService(); 1.158 + if (obsService) { 1.159 + obsService->AddObserver(this, "command-line-startup", true); 1.160 + obsService->AddObserver(this, "profile-initial-state", true); 1.161 + } 1.162 + 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +NS_IMETHODIMP 1.167 +nsChromeRegistryChrome::CheckForOSAccessibility() 1.168 +{ 1.169 + int32_t useAccessibilityTheme = 1.170 + LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0); 1.171 + 1.172 + if (useAccessibilityTheme) { 1.173 + /* Set the skin to classic and remove pref observers */ 1.174 + if (!mSelectedSkin.EqualsLiteral("classic/1.0")) { 1.175 + mSelectedSkin.AssignLiteral("classic/1.0"); 1.176 + RefreshSkins(); 1.177 + } 1.178 + 1.179 + nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID)); 1.180 + if (prefs) { 1.181 + prefs->RemoveObserver(SELECTED_SKIN_PREF, this); 1.182 + } 1.183 + } 1.184 + 1.185 + return NS_OK; 1.186 +} 1.187 + 1.188 +NS_IMETHODIMP 1.189 +nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage, 1.190 + nsIUTF8StringEnumerator* *aResult) 1.191 +{ 1.192 + nsCString realpackage; 1.193 + nsresult rv = OverrideLocalePackage(aPackage, realpackage); 1.194 + if (NS_FAILED(rv)) 1.195 + return rv; 1.196 + 1.197 + nsTArray<nsCString> *a = new nsTArray<nsCString>; 1.198 + if (!a) 1.199 + return NS_ERROR_OUT_OF_MEMORY; 1.200 + 1.201 + PackageEntry* entry = 1.202 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.203 + & realpackage, 1.204 + PL_DHASH_LOOKUP)); 1.205 + 1.206 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.207 + entry->locales.EnumerateToArray(a); 1.208 + } 1.209 + 1.210 + rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a); 1.211 + if (NS_FAILED(rv)) 1.212 + delete a; 1.213 + 1.214 + return rv; 1.215 +} 1.216 + 1.217 +static nsresult 1.218 +getUILangCountry(nsACString& aUILang) 1.219 +{ 1.220 + nsresult rv; 1.221 + 1.222 + nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); 1.223 + NS_ENSURE_SUCCESS(rv, rv); 1.224 + 1.225 + nsAutoString uiLang; 1.226 + rv = localeService->GetLocaleComponentForUserAgent(uiLang); 1.227 + NS_ENSURE_SUCCESS(rv, rv); 1.228 + 1.229 + CopyUTF16toUTF8(uiLang, aUILang); 1.230 + return NS_OK; 1.231 +} 1.232 + 1.233 +NS_IMETHODIMP 1.234 +nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult) 1.235 +{ 1.236 + *aResult = false; 1.237 + 1.238 + nsAutoCString locale; 1.239 + GetSelectedLocale(package, locale); 1.240 + if (locale.Length() < 2) 1.241 + return NS_OK; 1.242 + 1.243 + // first check the intl.uidirection.<locale> preference, and if that is not 1.244 + // set, check the same preference but with just the first two characters of 1.245 + // the locale. If that isn't set, default to left-to-right. 1.246 + nsAutoCString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + locale; 1.247 + nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID)); 1.248 + if (!prefBranch) 1.249 + return NS_OK; 1.250 + 1.251 + nsXPIDLCString dir; 1.252 + prefBranch->GetCharPref(prefString.get(), getter_Copies(dir)); 1.253 + if (dir.IsEmpty()) { 1.254 + int32_t hyphen = prefString.FindChar('-'); 1.255 + if (hyphen >= 1) { 1.256 + nsAutoCString shortPref(Substring(prefString, 0, hyphen)); 1.257 + prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir)); 1.258 + } 1.259 + } 1.260 + *aResult = dir.EqualsLiteral("rtl"); 1.261 + return NS_OK; 1.262 +} 1.263 + 1.264 +nsresult 1.265 +nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage, 1.266 + nsACString& aLocale) 1.267 +{ 1.268 + nsCString realpackage; 1.269 + nsresult rv = OverrideLocalePackage(aPackage, realpackage); 1.270 + if (NS_FAILED(rv)) 1.271 + return rv; 1.272 + PackageEntry* entry = 1.273 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.274 + & realpackage, 1.275 + PL_DHASH_LOOKUP)); 1.276 + 1.277 + if (PL_DHASH_ENTRY_IS_FREE(entry)) 1.278 + return NS_ERROR_FAILURE; 1.279 + 1.280 + aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE); 1.281 + if (aLocale.IsEmpty()) 1.282 + return NS_ERROR_FAILURE; 1.283 + 1.284 + return NS_OK; 1.285 +} 1.286 + 1.287 +nsresult 1.288 +nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage, 1.289 + nsACString& aOverride) 1.290 +{ 1.291 + const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage; 1.292 + nsAdoptingCString override = mozilla::Preferences::GetCString(PromiseFlatCString(pref).get()); 1.293 + if (override) { 1.294 + aOverride = override; 1.295 + } 1.296 + else { 1.297 + aOverride = aPackage; 1.298 + } 1.299 + return NS_OK; 1.300 +} 1.301 + 1.302 +nsresult 1.303 +nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs) 1.304 +{ 1.305 + nsresult rv; 1.306 + bool matchOSLocale = false; 1.307 + rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale); 1.308 + 1.309 + if (NS_SUCCEEDED(rv) && matchOSLocale) { 1.310 + // compute lang and region code only when needed! 1.311 + nsAutoCString uiLocale; 1.312 + rv = getUILangCountry(uiLocale); 1.313 + if (NS_SUCCEEDED(rv)) 1.314 + mSelectedLocale = uiLocale; 1.315 + } 1.316 + else { 1.317 + nsXPIDLCString provider; 1.318 + rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider)); 1.319 + if (NS_SUCCEEDED(rv)) { 1.320 + mSelectedLocale = provider; 1.321 + } 1.322 + } 1.323 + 1.324 + if (NS_FAILED(rv)) 1.325 + NS_ERROR("Couldn't select locale from pref!"); 1.326 + 1.327 + return rv; 1.328 +} 1.329 + 1.330 +NS_IMETHODIMP 1.331 +nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic, 1.332 + const char16_t *someData) 1.333 +{ 1.334 + nsresult rv = NS_OK; 1.335 + 1.336 + if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) { 1.337 + nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject)); 1.338 + NS_ASSERTION(prefs, "Bad observer call!"); 1.339 + 1.340 + NS_ConvertUTF16toUTF8 pref(someData); 1.341 + 1.342 + if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) || 1.343 + pref.EqualsLiteral(SELECTED_LOCALE_PREF)) { 1.344 + rv = UpdateSelectedLocale(); 1.345 + if (NS_SUCCEEDED(rv) && mProfileLoaded) 1.346 + FlushAllCaches(); 1.347 + } 1.348 + else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) { 1.349 + nsXPIDLCString provider; 1.350 + rv = prefs->GetCharPref(pref.get(), getter_Copies(provider)); 1.351 + if (NS_FAILED(rv)) { 1.352 + NS_ERROR("Couldn't get new skin pref!"); 1.353 + return rv; 1.354 + } 1.355 + 1.356 + mSelectedSkin = provider; 1.357 + RefreshSkins(); 1.358 + } else { 1.359 + NS_ERROR("Unexpected pref!"); 1.360 + } 1.361 + } 1.362 + else if (!strcmp("command-line-startup", aTopic)) { 1.363 + nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject)); 1.364 + if (cmdLine) { 1.365 + nsAutoString uiLocale; 1.366 + rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG), 1.367 + false, uiLocale); 1.368 + if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) { 1.369 + CopyUTF16toUTF8(uiLocale, mSelectedLocale); 1.370 + nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID)); 1.371 + if (prefs) { 1.372 + prefs->RemoveObserver(SELECTED_LOCALE_PREF, this); 1.373 + } 1.374 + } 1.375 + } 1.376 + } 1.377 + else if (!strcmp("profile-initial-state", aTopic)) { 1.378 + mProfileLoaded = true; 1.379 + } 1.380 + else { 1.381 + NS_ERROR("Unexpected observer topic!"); 1.382 + } 1.383 + 1.384 + return rv; 1.385 +} 1.386 + 1.387 +NS_IMETHODIMP 1.388 +nsChromeRegistryChrome::CheckForNewChrome() 1.389 +{ 1.390 + PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nullptr); 1.391 + mOverlayHash.Clear(); 1.392 + mStyleHash.Clear(); 1.393 + mOverrideTable.Clear(); 1.394 + 1.395 + nsComponentManagerImpl::gComponentManager->RereadChromeManifests(); 1.396 + return NS_OK; 1.397 +} 1.398 + 1.399 +nsresult nsChromeRegistryChrome::UpdateSelectedLocale() 1.400 +{ 1.401 + nsresult rv = NS_OK; 1.402 + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); 1.403 + if (prefs) { 1.404 + rv = SelectLocaleFromPref(prefs); 1.405 + if (NS_SUCCEEDED(rv)) { 1.406 + nsCOMPtr<nsIObserverService> obsSvc = 1.407 + mozilla::services::GetObserverService(); 1.408 + NS_ASSERTION(obsSvc, "Couldn't get observer service."); 1.409 + obsSvc->NotifyObservers((nsIChromeRegistry*) this, 1.410 + "selected-locale-has-changed", nullptr); 1.411 + } 1.412 + } 1.413 + 1.414 + return rv; 1.415 +} 1.416 + 1.417 +static void 1.418 +SerializeURI(nsIURI* aURI, 1.419 + SerializedURI& aSerializedURI) 1.420 +{ 1.421 + if (!aURI) 1.422 + return; 1.423 + 1.424 + aURI->GetSpec(aSerializedURI.spec); 1.425 + aURI->GetOriginCharset(aSerializedURI.charset); 1.426 +} 1.427 + 1.428 +static PLDHashOperator 1.429 +EnumerateOverride(nsIURI* aURIKey, 1.430 + nsIURI* aURI, 1.431 + void* aArg) 1.432 +{ 1.433 + nsTArray<OverrideMapping>* overrides = 1.434 + static_cast<nsTArray<OverrideMapping>*>(aArg); 1.435 + 1.436 + SerializedURI chromeURI, overrideURI; 1.437 + 1.438 + SerializeURI(aURIKey, chromeURI); 1.439 + SerializeURI(aURI, overrideURI); 1.440 + 1.441 + OverrideMapping override = { 1.442 + chromeURI, overrideURI 1.443 + }; 1.444 + overrides->AppendElement(override); 1.445 + return (PLDHashOperator)PL_DHASH_NEXT; 1.446 +} 1.447 + 1.448 +struct EnumerationArgs 1.449 +{ 1.450 + InfallibleTArray<ChromePackage>& packages; 1.451 + const nsCString& selectedLocale; 1.452 + const nsCString& selectedSkin; 1.453 +}; 1.454 + 1.455 +void 1.456 +nsChromeRegistryChrome::SendRegisteredChrome( 1.457 + mozilla::dom::PContentParent* aParent) 1.458 +{ 1.459 + InfallibleTArray<ChromePackage> packages; 1.460 + InfallibleTArray<ResourceMapping> resources; 1.461 + InfallibleTArray<OverrideMapping> overrides; 1.462 + 1.463 + EnumerationArgs args = { 1.464 + packages, mSelectedLocale, mSelectedSkin 1.465 + }; 1.466 + PL_DHashTableEnumerate(&mPackagesHash, CollectPackages, &args); 1.467 + 1.468 + nsCOMPtr<nsIIOService> io (do_GetIOService()); 1.469 + NS_ENSURE_TRUE_VOID(io); 1.470 + 1.471 + nsCOMPtr<nsIProtocolHandler> ph; 1.472 + nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph)); 1.473 + NS_ENSURE_SUCCESS_VOID(rv); 1.474 + 1.475 + //FIXME: Some substitutions are set up lazily and might not exist yet 1.476 + nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph)); 1.477 + nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get()); 1.478 + rph->CollectSubstitutions(resources); 1.479 + 1.480 + mOverrideTable.EnumerateRead(&EnumerateOverride, &overrides); 1.481 + 1.482 + bool success = aParent->SendRegisterChrome(packages, resources, overrides, 1.483 + mSelectedLocale); 1.484 + NS_ENSURE_TRUE_VOID(success); 1.485 +} 1.486 + 1.487 +PLDHashOperator 1.488 +nsChromeRegistryChrome::CollectPackages(PLDHashTable *table, 1.489 + PLDHashEntryHdr *entry, 1.490 + uint32_t number, 1.491 + void *arg) 1.492 +{ 1.493 + EnumerationArgs* args = static_cast<EnumerationArgs*>(arg); 1.494 + PackageEntry* package = static_cast<PackageEntry*>(entry); 1.495 + 1.496 + SerializedURI contentURI, localeURI, skinURI; 1.497 + 1.498 + SerializeURI(package->baseURI, contentURI); 1.499 + SerializeURI(package->locales.GetBase(args->selectedLocale, 1.500 + nsProviderArray::LOCALE), localeURI); 1.501 + SerializeURI(package->skins.GetBase(args->selectedSkin, nsProviderArray::ANY), 1.502 + skinURI); 1.503 + 1.504 + ChromePackage chromePackage = { 1.505 + package->package, 1.506 + contentURI, 1.507 + localeURI, 1.508 + skinURI, 1.509 + package->flags 1.510 + }; 1.511 + args->packages.AppendElement(chromePackage); 1.512 + return (PLDHashOperator)PL_DHASH_NEXT; 1.513 +} 1.514 + 1.515 +static bool 1.516 +CanLoadResource(nsIURI* aResourceURI) 1.517 +{ 1.518 + bool isLocalResource = false; 1.519 + (void)NS_URIChainHasFlags(aResourceURI, 1.520 + nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, 1.521 + &isLocalResource); 1.522 + return isLocalResource; 1.523 +} 1.524 + 1.525 +nsIURI* 1.526 +nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage, 1.527 + const nsCString& aProvider, 1.528 + const nsCString& aPath) 1.529 +{ 1.530 + PackageEntry* entry = 1.531 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.532 + &aPackage, 1.533 + PL_DHASH_LOOKUP)); 1.534 + 1.535 + if (PL_DHASH_ENTRY_IS_FREE(entry)) { 1.536 + if (!mInitialized) 1.537 + return nullptr; 1.538 + 1.539 + LogMessage("No chrome package registered for chrome://%s/%s/%s", 1.540 + aPackage.get(), aProvider.get(), aPath.get()); 1.541 + 1.542 + return nullptr; 1.543 + } 1.544 + 1.545 + if (aProvider.EqualsLiteral("locale")) { 1.546 + return entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE); 1.547 + } 1.548 + else if (aProvider.EqualsLiteral("skin")) { 1.549 + return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY); 1.550 + } 1.551 + else if (aProvider.EqualsLiteral("content")) { 1.552 + return entry->baseURI; 1.553 + } 1.554 + return nullptr; 1.555 +} 1.556 + 1.557 +nsresult 1.558 +nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage, 1.559 + uint32_t* aFlags) 1.560 +{ 1.561 + PackageEntry* entry = 1.562 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.563 + & (nsACString&) aPackage, 1.564 + PL_DHASH_LOOKUP)); 1.565 + if (PL_DHASH_ENTRY_IS_FREE(entry)) 1.566 + return NS_ERROR_NOT_AVAILABLE; 1.567 + 1.568 + *aFlags = entry->flags; 1.569 + return NS_OK; 1.570 +} 1.571 + 1.572 +PLHashNumber 1.573 +nsChromeRegistryChrome::HashKey(PLDHashTable *table, const void *key) 1.574 +{ 1.575 + const nsACString& str = *reinterpret_cast<const nsACString*>(key); 1.576 + return HashString(str); 1.577 +} 1.578 + 1.579 +bool 1.580 +nsChromeRegistryChrome::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry, 1.581 + const void *key) 1.582 +{ 1.583 + const nsACString& str = *reinterpret_cast<const nsACString*>(key); 1.584 + const PackageEntry* pentry = static_cast<const PackageEntry*>(entry); 1.585 + return str.Equals(pentry->package); 1.586 +} 1.587 + 1.588 +void 1.589 +nsChromeRegistryChrome::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) 1.590 +{ 1.591 + PackageEntry* pentry = static_cast<PackageEntry*>(entry); 1.592 + pentry->~PackageEntry(); 1.593 +} 1.594 + 1.595 +bool 1.596 +nsChromeRegistryChrome::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, 1.597 + const void *key) 1.598 +{ 1.599 + const nsACString& str = *reinterpret_cast<const nsACString*>(key); 1.600 + 1.601 + new (entry) PackageEntry(str); 1.602 + return true; 1.603 +} 1.604 + 1.605 +const PLDHashTableOps 1.606 +nsChromeRegistryChrome::kTableOps = { 1.607 + PL_DHashAllocTable, 1.608 + PL_DHashFreeTable, 1.609 + HashKey, 1.610 + MatchKey, 1.611 + PL_DHashMoveEntryStub, 1.612 + ClearEntry, 1.613 + PL_DHashFinalizeStub, 1.614 + InitEntry 1.615 +}; 1.616 + 1.617 +nsChromeRegistryChrome::ProviderEntry* 1.618 +nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType) 1.619 +{ 1.620 + int32_t i = mArray.Count(); 1.621 + if (!i) 1.622 + return nullptr; 1.623 + 1.624 + ProviderEntry* found = nullptr; // Only set if we find a partial-match locale 1.625 + ProviderEntry* entry; 1.626 + 1.627 + while (i--) { 1.628 + entry = reinterpret_cast<ProviderEntry*>(mArray[i]); 1.629 + if (aPreferred.Equals(entry->provider)) 1.630 + return entry; 1.631 + 1.632 + if (aType != LOCALE) 1.633 + continue; 1.634 + 1.635 + if (LanguagesMatch(aPreferred, entry->provider)) { 1.636 + found = entry; 1.637 + continue; 1.638 + } 1.639 + 1.640 + if (!found && entry->provider.EqualsLiteral("en-US")) 1.641 + found = entry; 1.642 + } 1.643 + 1.644 + if (!found && aType != EXACT) 1.645 + return entry; 1.646 + 1.647 + return found; 1.648 +} 1.649 + 1.650 +nsIURI* 1.651 +nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType) 1.652 +{ 1.653 + ProviderEntry* provider = GetProvider(aPreferred, aType); 1.654 + 1.655 + if (!provider) 1.656 + return nullptr; 1.657 + 1.658 + return provider->baseURI; 1.659 +} 1.660 + 1.661 +const nsACString& 1.662 +nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType) 1.663 +{ 1.664 + ProviderEntry* entry = GetProvider(aPreferred, aType); 1.665 + 1.666 + if (entry) 1.667 + return entry->provider; 1.668 + 1.669 + return EmptyCString(); 1.670 +} 1.671 + 1.672 +void 1.673 +nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL) 1.674 +{ 1.675 + ProviderEntry* provider = GetProvider(aProvider, EXACT); 1.676 + 1.677 + if (provider) { 1.678 + provider->baseURI = aBaseURL; 1.679 + return; 1.680 + } 1.681 + 1.682 + // no existing entries, add a new one 1.683 + provider = new ProviderEntry(aProvider, aBaseURL); 1.684 + if (!provider) 1.685 + return; // It's safe to silently fail on OOM 1.686 + 1.687 + mArray.AppendElement(provider); 1.688 +} 1.689 + 1.690 +void 1.691 +nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a) 1.692 +{ 1.693 + int32_t i = mArray.Count(); 1.694 + while (i--) { 1.695 + ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]); 1.696 + a->AppendElement(entry->provider); 1.697 + } 1.698 +} 1.699 + 1.700 +void 1.701 +nsChromeRegistryChrome::nsProviderArray::Clear() 1.702 +{ 1.703 + int32_t i = mArray.Count(); 1.704 + while (i--) { 1.705 + ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]); 1.706 + delete entry; 1.707 + } 1.708 + 1.709 + mArray.Clear(); 1.710 +} 1.711 + 1.712 +void 1.713 +nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI) 1.714 +{ 1.715 + int32_t i = mArray.Count(); 1.716 + while (i--) { 1.717 + bool equals; 1.718 + if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals) 1.719 + return; 1.720 + } 1.721 + 1.722 + mArray.AppendObject(aURI); 1.723 +} 1.724 + 1.725 +void 1.726 +nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay) 1.727 +{ 1.728 + OverlayListEntry* entry = mTable.PutEntry(aBase); 1.729 + if (entry) 1.730 + entry->AddURI(aOverlay); 1.731 +} 1.732 + 1.733 +const nsCOMArray<nsIURI>* 1.734 +nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase) 1.735 +{ 1.736 + OverlayListEntry* entry = mTable.GetEntry(aBase); 1.737 + if (!entry) 1.738 + return nullptr; 1.739 + 1.740 + return &entry->mArray; 1.741 +} 1.742 + 1.743 +#ifdef MOZ_XUL 1.744 +NS_IMETHODIMP 1.745 +nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL, 1.746 + nsISimpleEnumerator **aResult) 1.747 +{ 1.748 + const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL); 1.749 + if (!parray) 1.750 + return NS_NewEmptyEnumerator(aResult); 1.751 + 1.752 + return NS_NewArrayEnumerator(aResult, *parray); 1.753 +} 1.754 + 1.755 +NS_IMETHODIMP 1.756 +nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL, 1.757 + nsISimpleEnumerator **aResult) 1.758 +{ 1.759 + const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL); 1.760 + if (!parray) 1.761 + return NS_NewEmptyEnumerator(aResult); 1.762 + 1.763 + return NS_NewArrayEnumerator(aResult, *parray); 1.764 +} 1.765 +#endif // MOZ_XUL 1.766 + 1.767 +nsIURI* 1.768 +nsChromeRegistry::ManifestProcessingContext::GetManifestURI() 1.769 +{ 1.770 + if (!mManifestURI) { 1.771 + nsCString uri; 1.772 + mFile.GetURIString(uri); 1.773 + NS_NewURI(getter_AddRefs(mManifestURI), uri); 1.774 + } 1.775 + return mManifestURI; 1.776 +} 1.777 + 1.778 +nsIXPConnect* 1.779 +nsChromeRegistry::ManifestProcessingContext::GetXPConnect() 1.780 +{ 1.781 + if (!mXPConnect) 1.782 + mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1"); 1.783 + 1.784 + return mXPConnect; 1.785 +} 1.786 + 1.787 +already_AddRefed<nsIURI> 1.788 +nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri) 1.789 +{ 1.790 + nsIURI* baseuri = GetManifestURI(); 1.791 + if (!baseuri) 1.792 + return nullptr; 1.793 + 1.794 + nsCOMPtr<nsIURI> resolved; 1.795 + nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri); 1.796 + if (NS_FAILED(rv)) 1.797 + return nullptr; 1.798 + 1.799 + return resolved.forget(); 1.800 +} 1.801 + 1.802 +static void 1.803 +EnsureLowerCase(char *aBuf) 1.804 +{ 1.805 + for (; *aBuf; ++aBuf) { 1.806 + char ch = *aBuf; 1.807 + if (ch >= 'A' && ch <= 'Z') 1.808 + *aBuf = ch + 'a' - 'A'; 1.809 + } 1.810 +} 1.811 + 1.812 +void 1.813 +nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno, 1.814 + char *const * argv, bool platform, 1.815 + bool contentaccessible) 1.816 +{ 1.817 + char* package = argv[0]; 1.818 + char* uri = argv[1]; 1.819 + 1.820 + EnsureLowerCase(package); 1.821 + 1.822 + nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri); 1.823 + if (!resolved) { 1.824 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.825 + "During chrome registration, unable to create URI '%s'.", uri); 1.826 + return; 1.827 + } 1.828 + 1.829 + if (!CanLoadResource(resolved)) { 1.830 + LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag, 1.831 + "During chrome registration, cannot register non-local URI '%s' as content.", 1.832 + uri); 1.833 + return; 1.834 + } 1.835 + 1.836 + PackageEntry* entry = 1.837 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.838 + & (const nsACString&) nsDependentCString(package), 1.839 + PL_DHASH_ADD)); 1.840 + if (!entry) 1.841 + return; 1.842 + 1.843 + entry->baseURI = resolved; 1.844 + 1.845 + if (platform) 1.846 + entry->flags |= PLATFORM_PACKAGE; 1.847 + if (contentaccessible) 1.848 + entry->flags |= CONTENT_ACCESSIBLE; 1.849 +} 1.850 + 1.851 +void 1.852 +nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno, 1.853 + char *const * argv, bool platform, 1.854 + bool contentaccessible) 1.855 +{ 1.856 + char* package = argv[0]; 1.857 + char* provider = argv[1]; 1.858 + char* uri = argv[2]; 1.859 + 1.860 + EnsureLowerCase(package); 1.861 + 1.862 + nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri); 1.863 + if (!resolved) { 1.864 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.865 + "During chrome registration, unable to create URI '%s'.", uri); 1.866 + return; 1.867 + } 1.868 + 1.869 + if (!CanLoadResource(resolved)) { 1.870 + LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag, 1.871 + "During chrome registration, cannot register non-local URI '%s' as content.", 1.872 + uri); 1.873 + return; 1.874 + } 1.875 + 1.876 + PackageEntry* entry = 1.877 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.878 + & (const nsACString&) nsDependentCString(package), 1.879 + PL_DHASH_ADD)); 1.880 + if (!entry) 1.881 + return; 1.882 + 1.883 + entry->locales.SetBase(nsDependentCString(provider), resolved); 1.884 +} 1.885 + 1.886 +void 1.887 +nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno, 1.888 + char *const * argv, bool platform, 1.889 + bool contentaccessible) 1.890 +{ 1.891 + char* package = argv[0]; 1.892 + char* provider = argv[1]; 1.893 + char* uri = argv[2]; 1.894 + 1.895 + EnsureLowerCase(package); 1.896 + 1.897 + nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri); 1.898 + if (!resolved) { 1.899 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.900 + "During chrome registration, unable to create URI '%s'.", uri); 1.901 + return; 1.902 + } 1.903 + 1.904 + if (!CanLoadResource(resolved)) { 1.905 + LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag, 1.906 + "During chrome registration, cannot register non-local URI '%s' as content.", 1.907 + uri); 1.908 + return; 1.909 + } 1.910 + 1.911 + PackageEntry* entry = 1.912 + static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash, 1.913 + & (const nsACString&) nsDependentCString(package), 1.914 + PL_DHASH_ADD)); 1.915 + if (!entry) 1.916 + return; 1.917 + 1.918 + entry->skins.SetBase(nsDependentCString(provider), resolved); 1.919 +} 1.920 + 1.921 +void 1.922 +nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno, 1.923 + char *const * argv, bool platform, 1.924 + bool contentaccessible) 1.925 +{ 1.926 + char* base = argv[0]; 1.927 + char* overlay = argv[1]; 1.928 + 1.929 + nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base); 1.930 + nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay); 1.931 + if (!baseuri || !overlayuri) { 1.932 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.933 + "During chrome registration, unable to create URI."); 1.934 + return; 1.935 + } 1.936 + 1.937 + if (!CanLoadResource(overlayuri)) { 1.938 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.939 + "Cannot register non-local URI '%s' as an overlay.", overlay); 1.940 + return; 1.941 + } 1.942 + 1.943 + mOverlayHash.Add(baseuri, overlayuri); 1.944 +} 1.945 + 1.946 +void 1.947 +nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno, 1.948 + char *const * argv, bool platform, 1.949 + bool contentaccessible) 1.950 +{ 1.951 + char* base = argv[0]; 1.952 + char* overlay = argv[1]; 1.953 + 1.954 + nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base); 1.955 + nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay); 1.956 + if (!baseuri || !overlayuri) { 1.957 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.958 + "During chrome registration, unable to create URI."); 1.959 + return; 1.960 + } 1.961 + 1.962 + if (!CanLoadResource(overlayuri)) { 1.963 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.964 + "Cannot register non-local URI '%s' as a style overlay.", overlay); 1.965 + return; 1.966 + } 1.967 + 1.968 + mStyleHash.Add(baseuri, overlayuri); 1.969 +} 1.970 + 1.971 +void 1.972 +nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno, 1.973 + char *const * argv, bool platform, 1.974 + bool contentaccessible) 1.975 +{ 1.976 + char* chrome = argv[0]; 1.977 + char* resolved = argv[1]; 1.978 + 1.979 + nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome); 1.980 + nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved); 1.981 + if (!chromeuri || !resolveduri) { 1.982 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.983 + "During chrome registration, unable to create URI."); 1.984 + return; 1.985 + } 1.986 + 1.987 + if (!CanLoadResource(resolveduri)) { 1.988 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.989 + "Cannot register non-local URI '%s' for an override.", resolved); 1.990 + return; 1.991 + } 1.992 + mOverrideTable.Put(chromeuri, resolveduri); 1.993 +} 1.994 + 1.995 +void 1.996 +nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno, 1.997 + char *const * argv, bool platform, 1.998 + bool contentaccessible) 1.999 +{ 1.1000 + char* package = argv[0]; 1.1001 + char* uri = argv[1]; 1.1002 + 1.1003 + EnsureLowerCase(package); 1.1004 + nsDependentCString host(package); 1.1005 + 1.1006 + nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService(); 1.1007 + if (!io) { 1.1008 + NS_WARNING("No IO service trying to process chrome manifests"); 1.1009 + return; 1.1010 + } 1.1011 + 1.1012 + nsCOMPtr<nsIProtocolHandler> ph; 1.1013 + nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph)); 1.1014 + if (NS_FAILED(rv)) 1.1015 + return; 1.1016 + 1.1017 + nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph); 1.1018 + 1.1019 + bool exists = false; 1.1020 + rv = rph->HasSubstitution(host, &exists); 1.1021 + if (exists) { 1.1022 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.1023 + "Duplicate resource declaration for '%s' ignored.", package); 1.1024 + return; 1.1025 + } 1.1026 + 1.1027 + nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri); 1.1028 + if (!resolved) { 1.1029 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.1030 + "During chrome registration, unable to create URI '%s'.", uri); 1.1031 + return; 1.1032 + } 1.1033 + 1.1034 + if (!CanLoadResource(resolved)) { 1.1035 + LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag, 1.1036 + "Warning: cannot register non-local URI '%s' as a resource.", 1.1037 + uri); 1.1038 + return; 1.1039 + } 1.1040 + 1.1041 + rph->SetSubstitution(host, resolved); 1.1042 +}