Bug 1467571 [wpt PR 11385] - Make manifest's parsers quicker, a=testonly
[gecko.git] / chrome / nsChromeRegistryChrome.cpp
blob8a62ab34f3d45aab9c84106ed70dff6ae18c6985
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sts=2 sw=2 et tw=80: */
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/. */
7 #include "mozilla/dom/ContentParent.h"
8 #include "RegistryMessageUtils.h"
9 #include "nsResProtocolHandler.h"
11 #include "nsChromeRegistryChrome.h"
13 #if defined(XP_WIN)
14 #include <windows.h>
15 #elif defined(XP_MACOSX)
16 #include <CoreServices/CoreServices.h>
17 #endif
19 #include "nsArrayEnumerator.h"
20 #include "nsComponentManager.h"
21 #include "nsEnumeratorUtils.h"
22 #include "nsNetUtil.h"
23 #include "nsStringEnumerator.h"
24 #include "nsTextFormatter.h"
25 #include "nsXPCOMCIDInternal.h"
27 #include "mozilla/LookAndFeel.h"
28 #include "mozilla/Unused.h"
29 #include "mozilla/intl/LocaleService.h"
31 #include "nsIObserverService.h"
32 #include "nsIPrefBranch.h"
33 #include "nsIPrefService.h"
34 #include "mozilla/Preferences.h"
35 #include "nsIResProtocolHandler.h"
36 #include "nsIScriptError.h"
37 #include "nsIXULRuntime.h"
39 #define SELECTED_SKIN_PREF "general.skins.selectedSkin"
40 #define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
42 using namespace mozilla;
43 using mozilla::dom::ContentParent;
44 using mozilla::dom::PContentParent;
45 using mozilla::intl::LocaleService;
47 // We use a "best-fit" algorithm for matching locales and themes.
48 // 1) the exact selected locale/theme
49 // 2) (locales only) same language, different country
50 // e.g. en-GB is the selected locale, only en-US is available
51 // 3) any available locale/theme
53 /**
54 * Match the language-part of two lang-COUNTRY codes, hopefully but
55 * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
56 * work, any other garbage-in will produce undefined results as long
57 * as it does not crash.
59 static bool
60 LanguagesMatch(const nsACString& a, const nsACString& b)
62 if (a.Length() < 2 || b.Length() < 2)
63 return false;
65 nsACString::const_iterator as, ae, bs, be;
66 a.BeginReading(as);
67 a.EndReading(ae);
68 b.BeginReading(bs);
69 b.EndReading(be);
71 while (*as == *bs) {
72 if (*as == '-')
73 return true;
75 ++as; ++bs;
77 // reached the end
78 if (as == ae && bs == be)
79 return true;
81 // "a" is short
82 if (as == ae)
83 return (*bs == '-');
85 // "b" is short
86 if (bs == be)
87 return (*as == '-');
90 return false;
93 nsChromeRegistryChrome::nsChromeRegistryChrome()
94 : mProfileLoaded(false)
95 , mDynamicRegistration(true)
99 nsChromeRegistryChrome::~nsChromeRegistryChrome()
103 nsresult
104 nsChromeRegistryChrome::Init()
106 nsresult rv = nsChromeRegistry::Init();
107 if (NS_FAILED(rv))
108 return rv;
110 mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
112 bool safeMode = false;
113 nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
114 if (xulrun)
115 xulrun->GetInSafeMode(&safeMode);
117 nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
118 nsCOMPtr<nsIPrefBranch> prefs;
120 if (prefserv) {
121 if (safeMode) {
122 prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
123 } else {
124 prefs = do_QueryInterface(prefserv);
128 if (!prefs) {
129 NS_WARNING("Could not get pref service!");
130 } else {
131 nsAutoCString provider;
132 rv = prefs->GetCharPref(SELECTED_SKIN_PREF, provider);
133 if (NS_SUCCEEDED(rv))
134 mSelectedSkin = provider;
136 rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
139 nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
140 if (obsService) {
141 obsService->AddObserver(this, "profile-initial-state", true);
142 obsService->AddObserver(this, "intl:app-locales-changed", true);
145 return NS_OK;
148 NS_IMETHODIMP
149 nsChromeRegistryChrome::CheckForOSAccessibility()
151 int32_t useAccessibilityTheme =
152 LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
154 if (useAccessibilityTheme) {
155 /* Set the skin to classic and remove pref observers */
156 if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
157 mSelectedSkin.AssignLiteral("classic/1.0");
158 RefreshSkins();
161 nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
162 if (prefs) {
163 prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
167 return NS_OK;
170 NS_IMETHODIMP
171 nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
172 nsIUTF8StringEnumerator* *aResult)
174 nsCString realpackage;
175 nsresult rv = OverrideLocalePackage(aPackage, realpackage);
176 if (NS_FAILED(rv))
177 return rv;
179 nsTArray<nsCString> *a = new nsTArray<nsCString>;
180 if (!a)
181 return NS_ERROR_OUT_OF_MEMORY;
183 PackageEntry* entry;
184 if (mPackagesHash.Get(realpackage, &entry)) {
185 entry->locales.EnumerateToArray(a);
188 rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
189 if (NS_FAILED(rv))
190 delete a;
192 return rv;
195 NS_IMETHODIMP
196 nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
198 *aResult = false;
200 nsAutoCString locale;
201 GetSelectedLocale(package, false, locale);
202 if (locale.Length() < 2)
203 return NS_OK;
205 *aResult = GetDirectionForLocale(locale);
206 return NS_OK;
210 * This method negotiates only between the app locale and the available
211 * chrome packages.
213 * If you want to get the current application's UI locale, please use
214 * LocaleService::GetAppLocaleAsLangTag.
216 nsresult
217 nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
218 bool aAsBCP47,
219 nsACString& aLocale)
221 nsAutoCString reqLocale;
222 if (aPackage.EqualsLiteral("global")) {
223 LocaleService::GetInstance()->GetAppLocaleAsLangTag(reqLocale);
224 } else {
225 AutoTArray<nsCString, 10> requestedLocales;
226 LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
227 reqLocale.Assign(requestedLocales[0]);
230 nsCString realpackage;
231 nsresult rv = OverrideLocalePackage(aPackage, realpackage);
232 if (NS_FAILED(rv))
233 return rv;
234 PackageEntry* entry;
235 if (!mPackagesHash.Get(realpackage, &entry))
236 return NS_ERROR_FILE_NOT_FOUND;
238 aLocale = entry->locales.GetSelected(reqLocale, nsProviderArray::LOCALE);
239 if (aLocale.IsEmpty())
240 return NS_ERROR_FAILURE;
242 if (aAsBCP47) {
243 SanitizeForBCP47(aLocale);
246 return NS_OK;
249 nsresult
250 nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
251 nsACString& aOverride)
253 const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
254 nsAutoCString override;
255 nsresult rv =
256 mozilla::Preferences::GetCString(PromiseFlatCString(pref).get(), override);
257 if (NS_SUCCEEDED(rv)) {
258 aOverride = override;
259 } else {
260 aOverride = aPackage;
262 return NS_OK;
265 NS_IMETHODIMP
266 nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
267 const char16_t *someData)
269 nsresult rv = NS_OK;
271 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
272 nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
273 NS_ASSERTION(prefs, "Bad observer call!");
275 NS_ConvertUTF16toUTF8 pref(someData);
277 if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
278 nsAutoCString provider;
279 rv = prefs->GetCharPref(pref.get(), provider);
280 if (NS_FAILED(rv)) {
281 NS_ERROR("Couldn't get new skin pref!");
282 return rv;
285 mSelectedSkin = provider;
286 RefreshSkins();
287 } else {
288 NS_ERROR("Unexpected pref!");
291 else if (!strcmp("profile-initial-state", aTopic)) {
292 mProfileLoaded = true;
294 else if (!strcmp("intl:app-locales-changed", aTopic)) {
295 if (mProfileLoaded) {
296 FlushAllCaches();
299 else {
300 NS_ERROR("Unexpected observer topic!");
303 return rv;
306 NS_IMETHODIMP
307 nsChromeRegistryChrome::CheckForNewChrome()
309 mPackagesHash.Clear();
310 mOverlayHash.Clear();
311 mOverrideTable.Clear();
313 mDynamicRegistration = false;
315 nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
317 mDynamicRegistration = true;
319 SendRegisteredChrome(nullptr);
320 return NS_OK;
323 static void
324 SerializeURI(nsIURI* aURI,
325 SerializedURI& aSerializedURI)
327 if (!aURI)
328 return;
330 aURI->GetSpec(aSerializedURI.spec);
333 void
334 nsChromeRegistryChrome::SendRegisteredChrome(
335 mozilla::dom::PContentParent* aParent)
337 InfallibleTArray<ChromePackage> packages;
338 InfallibleTArray<SubstitutionMapping> resources;
339 InfallibleTArray<OverrideMapping> overrides;
341 for (auto iter = mPackagesHash.Iter(); !iter.Done(); iter.Next()) {
342 ChromePackage chromePackage;
343 ChromePackageFromPackageEntry(iter.Key(), iter.UserData(), &chromePackage,
344 mSelectedSkin);
345 packages.AppendElement(chromePackage);
348 // If we were passed a parent then a new child process has been created and
349 // has requested all of the chrome so send it the resources too. Otherwise
350 // resource mappings are sent by the resource protocol handler dynamically.
351 if (aParent) {
352 nsCOMPtr<nsIIOService> io (do_GetIOService());
353 NS_ENSURE_TRUE_VOID(io);
355 nsCOMPtr<nsIProtocolHandler> ph;
356 nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
357 NS_ENSURE_SUCCESS_VOID(rv);
359 nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
360 nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
361 rv = rph->CollectSubstitutions(resources);
362 NS_ENSURE_SUCCESS_VOID(rv);
365 for (auto iter = mOverrideTable.Iter(); !iter.Done(); iter.Next()) {
366 SerializedURI chromeURI, overrideURI;
368 SerializeURI(iter.Key(), chromeURI);
369 SerializeURI(iter.UserData(), overrideURI);
371 OverrideMapping override = { chromeURI, overrideURI };
372 overrides.AppendElement(override);
375 nsAutoCString appLocale;
376 LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
378 if (aParent) {
379 bool success = aParent->SendRegisterChrome(packages, resources, overrides,
380 appLocale, false);
381 NS_ENSURE_TRUE_VOID(success);
382 } else {
383 nsTArray<ContentParent*> parents;
384 ContentParent::GetAll(parents);
385 if (!parents.Length())
386 return;
388 for (uint32_t i = 0; i < parents.Length(); i++) {
389 DebugOnly<bool> success =
390 parents[i]->SendRegisterChrome(packages, resources, overrides,
391 appLocale, true);
392 NS_WARNING_ASSERTION(success,
393 "couldn't reset a child's registered chrome");
398 /* static */ void
399 nsChromeRegistryChrome::ChromePackageFromPackageEntry(const nsACString& aPackageName,
400 PackageEntry* aPackage,
401 ChromePackage* aChromePackage,
402 const nsCString& aSelectedSkin)
404 nsAutoCString appLocale;
405 LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
407 SerializeURI(aPackage->baseURI, aChromePackage->contentBaseURI);
408 SerializeURI(aPackage->locales.GetBase(appLocale, nsProviderArray::LOCALE),
409 aChromePackage->localeBaseURI);
410 SerializeURI(aPackage->skins.GetBase(aSelectedSkin, nsProviderArray::ANY),
411 aChromePackage->skinBaseURI);
412 aChromePackage->package = aPackageName;
413 aChromePackage->flags = aPackage->flags;
416 static bool
417 CanLoadResource(nsIURI* aResourceURI)
419 bool isLocalResource = false;
420 (void)NS_URIChainHasFlags(aResourceURI,
421 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
422 &isLocalResource);
423 return isLocalResource;
426 nsIURI*
427 nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
428 const nsCString& aProvider,
429 const nsCString& aPath)
431 PackageEntry* entry;
432 if (!mPackagesHash.Get(aPackage, &entry)) {
433 if (!mInitialized)
434 return nullptr;
436 LogMessage("No chrome package registered for chrome://%s/%s/%s",
437 aPackage.get(), aProvider.get(), aPath.get());
439 return nullptr;
442 if (aProvider.EqualsLiteral("locale")) {
443 nsAutoCString appLocale;
444 LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
445 return entry->locales.GetBase(appLocale, nsProviderArray::LOCALE);
447 else if (aProvider.EqualsLiteral("skin")) {
448 return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
450 else if (aProvider.EqualsLiteral("content")) {
451 return entry->baseURI;
453 return nullptr;
456 nsresult
457 nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
458 uint32_t* aFlags)
460 PackageEntry* entry;
461 if (!mPackagesHash.Get(aPackage, &entry))
462 return NS_ERROR_FILE_NOT_FOUND;
464 *aFlags = entry->flags;
465 return NS_OK;
468 nsChromeRegistryChrome::ProviderEntry*
469 nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
471 size_t i = mArray.Length();
472 if (!i)
473 return nullptr;
475 ProviderEntry* found = nullptr; // Only set if we find a partial-match locale
476 ProviderEntry* entry = nullptr;
478 while (i--) {
479 entry = &mArray[i];
480 if (aPreferred.Equals(entry->provider))
481 return entry;
483 if (aType != LOCALE)
484 continue;
486 if (LanguagesMatch(aPreferred, entry->provider)) {
487 found = entry;
488 continue;
491 if (!found && entry->provider.EqualsLiteral("en-US"))
492 found = entry;
495 if (!found && aType != EXACT)
496 return entry;
498 return found;
501 nsIURI*
502 nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
504 ProviderEntry* provider = GetProvider(aPreferred, aType);
506 if (!provider)
507 return nullptr;
509 return provider->baseURI;
512 const nsACString&
513 nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
515 ProviderEntry* entry = GetProvider(aPreferred, aType);
517 if (entry)
518 return entry->provider;
520 return EmptyCString();
523 void
524 nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
526 ProviderEntry* provider = GetProvider(aProvider, EXACT);
528 if (provider) {
529 provider->baseURI = aBaseURL;
530 return;
533 // no existing entries, add a new one
534 mArray.AppendElement(ProviderEntry(aProvider, aBaseURL));
537 void
538 nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
540 int32_t i = mArray.Length();
541 while (i--) {
542 a->AppendElement(mArray[i].provider);
546 void
547 nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
549 int32_t i = mArray.Count();
550 while (i--) {
551 bool equals;
552 if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
553 return;
556 mArray.AppendObject(aURI);
559 void
560 nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
562 OverlayListEntry* entry = mTable.PutEntry(aBase);
563 if (entry)
564 entry->AddURI(aOverlay);
567 const nsCOMArray<nsIURI>*
568 nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
570 OverlayListEntry* entry = mTable.GetEntry(aBase);
571 if (!entry)
572 return nullptr;
574 return &entry->mArray;
577 #ifdef MOZ_XUL
578 NS_IMETHODIMP
579 nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
580 nsISimpleEnumerator **aResult)
582 nsCOMPtr<nsIURI> chromeURLWithoutHash;
583 if (aChromeURL) {
584 aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
586 const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(chromeURLWithoutHash);
587 if (!parray)
588 return NS_NewEmptyEnumerator(aResult);
590 return NS_NewArrayEnumerator(aResult, *parray);
592 #endif // MOZ_XUL
594 nsIURI*
595 nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
597 if (!mManifestURI) {
598 nsCString uri;
599 mFile.GetURIString(uri);
600 NS_NewURI(getter_AddRefs(mManifestURI), uri);
602 return mManifestURI;
605 already_AddRefed<nsIURI>
606 nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
608 nsIURI* baseuri = GetManifestURI();
609 if (!baseuri)
610 return nullptr;
612 nsCOMPtr<nsIURI> resolved;
613 nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
614 if (NS_FAILED(rv))
615 return nullptr;
617 return resolved.forget();
620 static void
621 EnsureLowerCase(char *aBuf)
623 for (; *aBuf; ++aBuf) {
624 char ch = *aBuf;
625 if (ch >= 'A' && ch <= 'Z')
626 *aBuf = ch + 'a' - 'A';
630 static void
631 SendManifestEntry(const ChromeRegistryItem &aItem)
633 nsTArray<ContentParent*> parents;
634 ContentParent::GetAll(parents);
635 if (!parents.Length())
636 return;
638 for (uint32_t i = 0; i < parents.Length(); i++) {
639 Unused << parents[i]->SendRegisterChromeItem(aItem);
643 void
644 nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno,
645 char *const * argv, int flags)
647 char* package = argv[0];
648 char* uri = argv[1];
650 EnsureLowerCase(package);
652 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
653 if (!resolved) {
654 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
655 "During chrome registration, unable to create URI '%s'.", uri);
656 return;
659 if (!CanLoadResource(resolved)) {
660 LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
661 "During chrome registration, cannot register non-local URI '%s' as content.",
662 uri);
663 return;
666 nsDependentCString packageName(package);
667 PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
668 entry->baseURI = resolved;
669 entry->flags = flags;
671 if (mDynamicRegistration) {
672 ChromePackage chromePackage;
673 ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
674 mSelectedSkin);
675 SendManifestEntry(chromePackage);
679 void
680 nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
681 char *const * argv, int flags)
683 char* package = argv[0];
684 char* provider = argv[1];
685 char* uri = argv[2];
687 EnsureLowerCase(package);
689 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
690 if (!resolved) {
691 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
692 "During chrome registration, unable to create URI '%s'.", uri);
693 return;
696 if (!CanLoadResource(resolved)) {
697 LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
698 "During chrome registration, cannot register non-local URI '%s' as content.",
699 uri);
700 return;
703 nsDependentCString packageName(package);
704 PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
705 entry->locales.SetBase(nsDependentCString(provider), resolved);
707 if (mDynamicRegistration) {
708 ChromePackage chromePackage;
709 ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
710 mSelectedSkin);
711 SendManifestEntry(chromePackage);
714 // We use mainPackage as the package we track for reporting new locales being
715 // registered. For most cases it will be "global", but for Fennec it will be
716 // "browser".
717 nsAutoCString mainPackage;
718 nsresult rv = OverrideLocalePackage(NS_LITERAL_CSTRING("global"), mainPackage);
719 if (NS_FAILED(rv)) {
720 return;
724 void
725 nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
726 char *const * argv, int flags)
728 char* package = argv[0];
729 char* provider = argv[1];
730 char* uri = argv[2];
732 EnsureLowerCase(package);
734 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
735 if (!resolved) {
736 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
737 "During chrome registration, unable to create URI '%s'.", uri);
738 return;
741 if (!CanLoadResource(resolved)) {
742 LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
743 "During chrome registration, cannot register non-local URI '%s' as content.",
744 uri);
745 return;
748 nsDependentCString packageName(package);
749 PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
750 entry->skins.SetBase(nsDependentCString(provider), resolved);
752 if (mDynamicRegistration) {
753 ChromePackage chromePackage;
754 ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
755 mSelectedSkin);
756 SendManifestEntry(chromePackage);
760 void
761 nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
762 char *const * argv, int flags)
764 char* base = argv[0];
765 char* overlay = argv[1];
767 nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
768 nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
769 if (!baseuri || !overlayuri) {
770 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
771 "During chrome registration, unable to create URI.");
772 return;
775 if (!CanLoadResource(overlayuri)) {
776 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
777 "Cannot register non-local URI '%s' as an overlay.", overlay);
778 return;
781 nsCOMPtr<nsIURI> baseuriWithoutHash;
782 baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
784 mOverlayHash.Add(baseuriWithoutHash, overlayuri);
787 void
788 nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno,
789 char *const * argv, int flags)
791 char* chrome = argv[0];
792 char* resolved = argv[1];
794 nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
795 nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
796 if (!chromeuri || !resolveduri) {
797 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
798 "During chrome registration, unable to create URI.");
799 return;
802 if (cx.mType == NS_SKIN_LOCATION) {
803 bool chromeSkinOnly = false;
804 nsresult rv = chromeuri->SchemeIs("chrome", &chromeSkinOnly);
805 chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
806 if (chromeSkinOnly) {
807 rv = resolveduri->SchemeIs("chrome", &chromeSkinOnly);
808 chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
810 if (chromeSkinOnly) {
811 nsAutoCString chromePath, resolvedPath;
812 chromeuri->GetPathQueryRef(chromePath);
813 resolveduri->GetPathQueryRef(resolvedPath);
814 chromeSkinOnly = StringBeginsWith(chromePath, NS_LITERAL_CSTRING("/skin/")) &&
815 StringBeginsWith(resolvedPath, NS_LITERAL_CSTRING("/skin/"));
817 if (!chromeSkinOnly) {
818 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
819 "Cannot register non-chrome://.../skin/ URIs '%s' and '%s' as overrides and/or to be overridden from a skin manifest.",
820 chrome, resolved);
821 return;
825 if (!CanLoadResource(resolveduri)) {
826 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
827 "Cannot register non-local URI '%s' for an override.", resolved);
828 return;
830 mOverrideTable.Put(chromeuri, resolveduri);
832 if (mDynamicRegistration) {
833 SerializedURI serializedChrome;
834 SerializedURI serializedOverride;
836 SerializeURI(chromeuri, serializedChrome);
837 SerializeURI(resolveduri, serializedOverride);
839 OverrideMapping override = { serializedChrome, serializedOverride };
840 SendManifestEntry(override);
844 void
845 nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno,
846 char *const * argv, int flags)
848 char* package = argv[0];
849 char* uri = argv[1];
851 EnsureLowerCase(package);
852 nsDependentCString host(package);
854 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
855 if (!io) {
856 NS_WARNING("No IO service trying to process chrome manifests");
857 return;
860 nsCOMPtr<nsIProtocolHandler> ph;
861 nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
862 if (NS_FAILED(rv))
863 return;
865 nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
867 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
868 if (!resolved) {
869 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
870 "During chrome registration, unable to create URI '%s'.", uri);
871 return;
874 if (!CanLoadResource(resolved)) {
875 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
876 "Warning: cannot register non-local URI '%s' as a resource.",
877 uri);
878 return;
881 // By default, Firefox resources are not content-accessible unless the
882 // manifests opts in.
883 bool contentAccessible = (flags & nsChromeRegistry::CONTENT_ACCESSIBLE);
885 uint32_t substitutionFlags = 0;
886 if (contentAccessible) {
887 substitutionFlags |= nsIResProtocolHandler::ALLOW_CONTENT_ACCESS;
889 rv = rph->SetSubstitutionWithFlags(host, resolved, substitutionFlags);
890 if (NS_FAILED(rv)) {
891 LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
892 "Warning: cannot set substitution for '%s'.",
893 uri);