Bug 1580312 - Refactor ResponsiveUI into its own module. r=mtigley
[gecko.git] / chrome / nsChromeRegistryChrome.cpp
blob0abcddb2bf4183c3c4a7f7c98b6d21ad57af1a06
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 "nsIAppStartup.h"
32 #include "nsIObserverService.h"
33 #include "nsIPrefBranch.h"
34 #include "nsIPrefService.h"
35 #include "mozilla/Preferences.h"
36 #include "nsIResProtocolHandler.h"
37 #include "nsIScriptError.h"
38 #include "nsIXULRuntime.h"
40 #define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
41 #define SKIN NS_LITERAL_CSTRING("classic/1.0")
43 using namespace mozilla;
44 using mozilla::dom::ContentParent;
45 using mozilla::dom::PContentParent;
46 using mozilla::intl::LocaleService;
48 // We use a "best-fit" algorithm for matching locales and themes.
49 // 1) the exact selected locale/theme
50 // 2) (locales only) same language, different country
51 // e.g. en-GB is the selected locale, only en-US is available
52 // 3) any available locale/theme
54 /**
55 * Match the language-part of two lang-COUNTRY codes, hopefully but
56 * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
57 * work, any other garbage-in will produce undefined results as long
58 * as it does not crash.
60 static bool LanguagesMatch(const nsACString& a, const nsACString& b) {
61 if (a.Length() < 2 || b.Length() < 2) return false;
63 nsACString::const_iterator as, ae, bs, be;
64 a.BeginReading(as);
65 a.EndReading(ae);
66 b.BeginReading(bs);
67 b.EndReading(be);
69 while (*as == *bs) {
70 if (*as == '-') return true;
72 ++as;
73 ++bs;
75 // reached the end
76 if (as == ae && bs == be) return true;
78 // "a" is short
79 if (as == ae) return (*bs == '-');
81 // "b" is short
82 if (bs == be) return (*as == '-');
85 return false;
88 nsChromeRegistryChrome::nsChromeRegistryChrome()
89 : mProfileLoaded(false), mDynamicRegistration(true) {}
91 nsChromeRegistryChrome::~nsChromeRegistryChrome() {}
93 nsresult nsChromeRegistryChrome::Init() {
94 nsresult rv = nsChromeRegistry::Init();
95 if (NS_FAILED(rv)) return rv;
97 bool safeMode = false;
98 nsCOMPtr<nsIXULRuntime> xulrun(do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
99 if (xulrun) xulrun->GetInSafeMode(&safeMode);
101 nsCOMPtr<nsIObserverService> obsService =
102 mozilla::services::GetObserverService();
103 if (obsService) {
104 obsService->AddObserver(this, "profile-initial-state", true);
105 obsService->AddObserver(this, "intl:app-locales-changed", true);
108 return NS_OK;
111 NS_IMETHODIMP
112 nsChromeRegistryChrome::GetLocalesForPackage(
113 const nsACString& aPackage, nsIUTF8StringEnumerator** aResult) {
114 nsCString realpackage;
115 nsresult rv = OverrideLocalePackage(aPackage, realpackage);
116 if (NS_FAILED(rv)) return rv;
118 nsTArray<nsCString>* a = new nsTArray<nsCString>;
119 if (!a) return NS_ERROR_OUT_OF_MEMORY;
121 PackageEntry* entry;
122 if (mPackagesHash.Get(realpackage, &entry)) {
123 entry->locales.EnumerateToArray(a);
126 rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
127 if (NS_FAILED(rv)) delete a;
129 return rv;
132 NS_IMETHODIMP
133 nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool* aResult) {
134 *aResult = false;
136 nsAutoCString locale;
137 GetSelectedLocale(package, false, locale);
138 if (locale.Length() < 2) return NS_OK;
140 *aResult = GetDirectionForLocale(locale);
141 return NS_OK;
145 * This method negotiates only between the app locale and the available
146 * chrome packages.
148 * If you want to get the current application's UI locale, please use
149 * LocaleService::GetAppLocaleAsLangTag.
151 nsresult nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
152 bool aAsBCP47,
153 nsACString& aLocale) {
154 nsAutoCString reqLocale;
155 if (aPackage.EqualsLiteral("global")) {
156 LocaleService::GetInstance()->GetAppLocaleAsLangTag(reqLocale);
157 } else {
158 AutoTArray<nsCString, 10> requestedLocales;
159 LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
160 reqLocale.Assign(requestedLocales[0]);
163 nsCString realpackage;
164 nsresult rv = OverrideLocalePackage(aPackage, realpackage);
165 if (NS_FAILED(rv)) return rv;
166 PackageEntry* entry;
167 if (!mPackagesHash.Get(realpackage, &entry)) return NS_ERROR_FILE_NOT_FOUND;
169 aLocale = entry->locales.GetSelected(reqLocale, nsProviderArray::LOCALE);
170 if (aLocale.IsEmpty()) return NS_ERROR_FAILURE;
172 if (aAsBCP47) {
173 SanitizeForBCP47(aLocale);
176 return NS_OK;
179 nsresult nsChromeRegistryChrome::OverrideLocalePackage(
180 const nsACString& aPackage, nsACString& aOverride) {
181 const nsACString& pref =
182 NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
183 nsAutoCString override;
184 nsresult rv = mozilla::Preferences::GetCString(PromiseFlatCString(pref).get(),
185 override);
186 if (NS_SUCCEEDED(rv)) {
187 aOverride = override;
188 } else {
189 aOverride = aPackage;
191 return NS_OK;
194 NS_IMETHODIMP
195 nsChromeRegistryChrome::Observe(nsISupports* aSubject, const char* aTopic,
196 const char16_t* someData) {
197 nsresult rv = NS_OK;
199 if (!strcmp("profile-initial-state", aTopic)) {
200 mProfileLoaded = true;
201 } else if (!strcmp("intl:app-locales-changed", aTopic)) {
202 if (mProfileLoaded) {
203 FlushAllCaches();
205 } else {
206 NS_ERROR("Unexpected observer topic!");
209 return rv;
212 NS_IMETHODIMP
213 nsChromeRegistryChrome::CheckForNewChrome() {
214 nsCOMPtr<nsIAppStartup> appStartup = components::AppStartup::Service();
215 if (appStartup->GetShuttingDown()) {
216 MOZ_ASSERT(false, "checking for new chrome during shutdown");
217 return NS_ERROR_UNEXPECTED;
220 mPackagesHash.Clear();
221 mOverrideTable.Clear();
223 mDynamicRegistration = false;
225 nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
227 mDynamicRegistration = true;
229 SendRegisteredChrome(nullptr);
230 return NS_OK;
233 static void SerializeURI(nsIURI* aURI, SerializedURI& aSerializedURI) {
234 if (!aURI) return;
236 aURI->GetSpec(aSerializedURI.spec);
239 void nsChromeRegistryChrome::SendRegisteredChrome(
240 mozilla::dom::PContentParent* aParent) {
241 nsTArray<ChromePackage> packages;
242 nsTArray<SubstitutionMapping> resources;
243 nsTArray<OverrideMapping> overrides;
245 for (auto iter = mPackagesHash.Iter(); !iter.Done(); iter.Next()) {
246 ChromePackage chromePackage;
247 ChromePackageFromPackageEntry(iter.Key(), iter.UserData(), &chromePackage,
248 SKIN);
249 packages.AppendElement(chromePackage);
252 // If we were passed a parent then a new child process has been created and
253 // has requested all of the chrome so send it the resources too. Otherwise
254 // resource mappings are sent by the resource protocol handler dynamically.
255 if (aParent) {
256 nsCOMPtr<nsIIOService> io(do_GetIOService());
257 NS_ENSURE_TRUE_VOID(io);
259 nsCOMPtr<nsIProtocolHandler> ph;
260 nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
261 NS_ENSURE_SUCCESS_VOID(rv);
263 nsCOMPtr<nsIResProtocolHandler> irph(do_QueryInterface(ph));
264 nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
265 rv = rph->CollectSubstitutions(resources);
266 NS_ENSURE_SUCCESS_VOID(rv);
269 for (auto iter = mOverrideTable.Iter(); !iter.Done(); iter.Next()) {
270 SerializedURI chromeURI, overrideURI;
272 SerializeURI(iter.Key(), chromeURI);
273 SerializeURI(iter.UserData(), overrideURI);
275 OverrideMapping override = {chromeURI, overrideURI};
276 overrides.AppendElement(override);
279 nsAutoCString appLocale;
280 LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
282 if (aParent) {
283 bool success = aParent->SendRegisterChrome(packages, resources, overrides,
284 appLocale, false);
285 NS_ENSURE_TRUE_VOID(success);
286 } else {
287 nsTArray<ContentParent*> parents;
288 ContentParent::GetAll(parents);
289 if (!parents.Length()) return;
291 for (uint32_t i = 0; i < parents.Length(); i++) {
292 DebugOnly<bool> success = parents[i]->SendRegisterChrome(
293 packages, resources, overrides, appLocale, true);
294 NS_WARNING_ASSERTION(success,
295 "couldn't reset a child's registered chrome");
300 /* static */
301 void nsChromeRegistryChrome::ChromePackageFromPackageEntry(
302 const nsACString& aPackageName, PackageEntry* aPackage,
303 ChromePackage* aChromePackage, const nsCString& aSelectedSkin) {
304 nsAutoCString appLocale;
305 LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
307 SerializeURI(aPackage->baseURI, aChromePackage->contentBaseURI);
308 SerializeURI(aPackage->locales.GetBase(appLocale, nsProviderArray::LOCALE),
309 aChromePackage->localeBaseURI);
310 SerializeURI(aPackage->skins.GetBase(aSelectedSkin, nsProviderArray::ANY),
311 aChromePackage->skinBaseURI);
312 aChromePackage->package = aPackageName;
313 aChromePackage->flags = aPackage->flags;
316 static bool CanLoadResource(nsIURI* aResourceURI) {
317 bool isLocalResource = false;
318 (void)NS_URIChainHasFlags(aResourceURI,
319 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
320 &isLocalResource);
321 return isLocalResource;
324 nsIURI* nsChromeRegistryChrome::GetBaseURIFromPackage(
325 const nsCString& aPackage, const nsCString& aProvider,
326 const nsCString& aPath) {
327 PackageEntry* entry;
328 if (!mPackagesHash.Get(aPackage, &entry)) {
329 if (!mInitialized) return nullptr;
331 LogMessage("No chrome package registered for chrome://%s/%s/%s",
332 aPackage.get(), aProvider.get(), aPath.get());
334 return nullptr;
337 if (aProvider.EqualsLiteral("locale")) {
338 nsAutoCString appLocale;
339 LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
340 return entry->locales.GetBase(appLocale, nsProviderArray::LOCALE);
341 } else if (aProvider.EqualsLiteral("skin")) {
342 return entry->skins.GetBase(SKIN, nsProviderArray::ANY);
343 } else if (aProvider.EqualsLiteral("content")) {
344 return entry->baseURI;
346 return nullptr;
349 nsresult nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
350 uint32_t* aFlags) {
351 PackageEntry* entry;
352 if (!mPackagesHash.Get(aPackage, &entry)) return NS_ERROR_FILE_NOT_FOUND;
354 *aFlags = entry->flags;
355 return NS_OK;
358 nsChromeRegistryChrome::ProviderEntry*
359 nsChromeRegistryChrome::nsProviderArray::GetProvider(
360 const nsACString& aPreferred, MatchType aType) {
361 size_t i = mArray.Length();
362 if (!i) return nullptr;
364 ProviderEntry* found = nullptr; // Only set if we find a partial-match locale
365 ProviderEntry* entry = nullptr;
367 while (i--) {
368 entry = &mArray[i];
369 if (aPreferred.Equals(entry->provider)) return entry;
371 if (aType != LOCALE) continue;
373 if (LanguagesMatch(aPreferred, entry->provider)) {
374 found = entry;
375 continue;
378 if (!found && entry->provider.EqualsLiteral("en-US")) found = entry;
381 if (!found && aType != EXACT) return entry;
383 return found;
386 nsIURI* nsChromeRegistryChrome::nsProviderArray::GetBase(
387 const nsACString& aPreferred, MatchType aType) {
388 ProviderEntry* provider = GetProvider(aPreferred, aType);
390 if (!provider) return nullptr;
392 return provider->baseURI;
395 const nsACString& nsChromeRegistryChrome::nsProviderArray::GetSelected(
396 const nsACString& aPreferred, MatchType aType) {
397 ProviderEntry* entry = GetProvider(aPreferred, aType);
399 if (entry) return entry->provider;
401 return EmptyCString();
404 void nsChromeRegistryChrome::nsProviderArray::SetBase(
405 const nsACString& aProvider, nsIURI* aBaseURL) {
406 ProviderEntry* provider = GetProvider(aProvider, EXACT);
408 if (provider) {
409 provider->baseURI = aBaseURL;
410 return;
413 // no existing entries, add a new one
414 mArray.AppendElement(ProviderEntry(aProvider, aBaseURL));
417 void nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(
418 nsTArray<nsCString>* a) {
419 int32_t i = mArray.Length();
420 while (i--) {
421 a->AppendElement(mArray[i].provider);
425 nsIURI* nsChromeRegistry::ManifestProcessingContext::GetManifestURI() {
426 if (!mManifestURI) {
427 nsCString uri;
428 mFile.GetURIString(uri);
429 NS_NewURI(getter_AddRefs(mManifestURI), uri);
431 return mManifestURI;
434 already_AddRefed<nsIURI>
435 nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri) {
436 nsIURI* baseuri = GetManifestURI();
437 if (!baseuri) return nullptr;
439 nsCOMPtr<nsIURI> resolved;
440 nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
441 if (NS_FAILED(rv)) return nullptr;
443 return resolved.forget();
446 static void EnsureLowerCase(char* aBuf) {
447 for (; *aBuf; ++aBuf) {
448 char ch = *aBuf;
449 if (ch >= 'A' && ch <= 'Z') *aBuf = ch + 'a' - 'A';
453 static void SendManifestEntry(const ChromeRegistryItem& aItem) {
454 nsTArray<ContentParent*> parents;
455 ContentParent::GetAll(parents);
456 if (!parents.Length()) return;
458 for (uint32_t i = 0; i < parents.Length(); i++) {
459 Unused << parents[i]->SendRegisterChromeItem(aItem);
463 void nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx,
464 int lineno, char* const* argv,
465 int flags) {
466 char* package = argv[0];
467 char* uri = argv[1];
469 EnsureLowerCase(package);
471 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
472 if (!resolved) {
473 LogMessageWithContext(
474 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
475 "During chrome registration, unable to create URI '%s'.", uri);
476 return;
479 if (!CanLoadResource(resolved)) {
480 LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
481 "During chrome registration, cannot register "
482 "non-local URI '%s' as content.",
483 uri);
484 return;
487 nsDependentCString packageName(package);
488 PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
489 entry->baseURI = resolved;
490 entry->flags = flags;
492 if (mDynamicRegistration) {
493 ChromePackage chromePackage;
494 ChromePackageFromPackageEntry(packageName, entry, &chromePackage, SKIN);
495 SendManifestEntry(chromePackage);
499 void nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx,
500 int lineno, char* const* argv,
501 int flags) {
502 char* package = argv[0];
503 char* provider = argv[1];
504 char* uri = argv[2];
506 EnsureLowerCase(package);
508 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
509 if (!resolved) {
510 LogMessageWithContext(
511 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
512 "During chrome registration, unable to create URI '%s'.", uri);
513 return;
516 if (!CanLoadResource(resolved)) {
517 LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
518 "During chrome registration, cannot register "
519 "non-local URI '%s' as content.",
520 uri);
521 return;
524 nsDependentCString packageName(package);
525 PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
526 entry->locales.SetBase(nsDependentCString(provider), resolved);
528 if (mDynamicRegistration) {
529 ChromePackage chromePackage;
530 ChromePackageFromPackageEntry(packageName, entry, &chromePackage, SKIN);
531 SendManifestEntry(chromePackage);
534 // We use mainPackage as the package we track for reporting new locales being
535 // registered. For most cases it will be "global", but for Fennec it will be
536 // "browser".
537 nsAutoCString mainPackage;
538 nsresult rv =
539 OverrideLocalePackage(NS_LITERAL_CSTRING("global"), mainPackage);
540 if (NS_FAILED(rv)) {
541 return;
545 void nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx,
546 int lineno, char* const* argv,
547 int flags) {
548 char* package = argv[0];
549 char* provider = argv[1];
550 char* uri = argv[2];
552 EnsureLowerCase(package);
554 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
555 if (!resolved) {
556 LogMessageWithContext(
557 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
558 "During chrome registration, unable to create URI '%s'.", uri);
559 return;
562 if (!CanLoadResource(resolved)) {
563 LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
564 "During chrome registration, cannot register "
565 "non-local URI '%s' as content.",
566 uri);
567 return;
570 nsDependentCString packageName(package);
571 PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
572 entry->skins.SetBase(nsDependentCString(provider), resolved);
574 if (mDynamicRegistration) {
575 ChromePackage chromePackage;
576 ChromePackageFromPackageEntry(packageName, entry, &chromePackage, SKIN);
577 SendManifestEntry(chromePackage);
581 void nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx,
582 int lineno, char* const* argv,
583 int flags) {
584 char* chrome = argv[0];
585 char* resolved = argv[1];
587 nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
588 nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
589 if (!chromeuri || !resolveduri) {
590 LogMessageWithContext(cx.GetManifestURI(), lineno,
591 nsIScriptError::warningFlag,
592 "During chrome registration, unable to create URI.");
593 return;
596 if (cx.mType == NS_SKIN_LOCATION) {
597 bool chromeSkinOnly =
598 chromeuri->SchemeIs("chrome") && resolveduri->SchemeIs("chrome");
599 if (chromeSkinOnly) {
600 nsAutoCString chromePath, resolvedPath;
601 chromeuri->GetPathQueryRef(chromePath);
602 resolveduri->GetPathQueryRef(resolvedPath);
603 chromeSkinOnly =
604 StringBeginsWith(chromePath, NS_LITERAL_CSTRING("/skin/")) &&
605 StringBeginsWith(resolvedPath, NS_LITERAL_CSTRING("/skin/"));
607 if (!chromeSkinOnly) {
608 LogMessageWithContext(
609 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
610 "Cannot register non-chrome://.../skin/ URIs '%s' and '%s' as "
611 "overrides and/or to be overridden from a skin manifest.",
612 chrome, resolved);
613 return;
617 if (!CanLoadResource(resolveduri)) {
618 LogMessageWithContext(
619 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
620 "Cannot register non-local URI '%s' for an override.", resolved);
621 return;
623 mOverrideTable.Put(chromeuri, resolveduri);
625 if (mDynamicRegistration) {
626 SerializedURI serializedChrome;
627 SerializedURI serializedOverride;
629 SerializeURI(chromeuri, serializedChrome);
630 SerializeURI(resolveduri, serializedOverride);
632 OverrideMapping override = {serializedChrome, serializedOverride};
633 SendManifestEntry(override);
637 void nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx,
638 int lineno, char* const* argv,
639 int flags) {
640 char* package = argv[0];
641 char* uri = argv[1];
643 EnsureLowerCase(package);
644 nsDependentCString host(package);
646 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
647 if (!io) {
648 NS_WARNING("No IO service trying to process chrome manifests");
649 return;
652 nsCOMPtr<nsIProtocolHandler> ph;
653 nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
654 if (NS_FAILED(rv)) return;
656 nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
658 nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
659 if (!resolved) {
660 LogMessageWithContext(
661 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
662 "During chrome registration, unable to create URI '%s'.", uri);
663 return;
666 if (!CanLoadResource(resolved)) {
667 LogMessageWithContext(
668 cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
669 "Warning: cannot register non-local URI '%s' as a resource.", uri);
670 return;
673 // By default, Firefox resources are not content-accessible unless the
674 // manifests opts in.
675 bool contentAccessible = (flags & nsChromeRegistry::CONTENT_ACCESSIBLE);
677 uint32_t substitutionFlags = 0;
678 if (contentAccessible) {
679 substitutionFlags |= nsIResProtocolHandler::ALLOW_CONTENT_ACCESS;
681 rv = rph->SetSubstitutionWithFlags(host, resolved, substitutionFlags);
682 if (NS_FAILED(rv)) {
683 LogMessageWithContext(cx.GetManifestURI(), lineno,
684 nsIScriptError::warningFlag,
685 "Warning: cannot set substitution for '%s'.", uri);