Line data Source code
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/. */
6 :
7 : #include "mozilla/dom/ContentParent.h"
8 : #include "RegistryMessageUtils.h"
9 : #include "nsResProtocolHandler.h"
10 :
11 : #include "nsChromeRegistryChrome.h"
12 :
13 : #if defined(XP_WIN)
14 : #include <windows.h>
15 : #elif defined(XP_MACOSX)
16 : #include <CoreServices/CoreServices.h>
17 : #endif
18 :
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"
26 :
27 : #include "mozilla/LookAndFeel.h"
28 : #include "mozilla/Unused.h"
29 : #include "mozilla/intl/LocaleService.h"
30 :
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"
38 :
39 : #define SELECTED_SKIN_PREF "general.skins.selectedSkin"
40 : #define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
41 :
42 : using namespace mozilla;
43 : using mozilla::dom::ContentParent;
44 : using mozilla::dom::PContentParent;
45 : using mozilla::intl::LocaleService;
46 :
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
52 :
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.
58 : */
59 : static bool
60 0 : LanguagesMatch(const nsACString& a, const nsACString& b)
61 : {
62 0 : if (a.Length() < 2 || b.Length() < 2)
63 0 : return false;
64 :
65 0 : nsACString::const_iterator as, ae, bs, be;
66 0 : a.BeginReading(as);
67 0 : a.EndReading(ae);
68 0 : b.BeginReading(bs);
69 0 : b.EndReading(be);
70 :
71 0 : while (*as == *bs) {
72 0 : if (*as == '-')
73 0 : return true;
74 :
75 0 : ++as; ++bs;
76 :
77 : // reached the end
78 0 : if (as == ae && bs == be)
79 0 : return true;
80 :
81 : // "a" is short
82 0 : if (as == ae)
83 0 : return (*bs == '-');
84 :
85 : // "b" is short
86 0 : if (bs == be)
87 0 : return (*as == '-');
88 : }
89 :
90 0 : return false;
91 : }
92 :
93 1 : nsChromeRegistryChrome::nsChromeRegistryChrome()
94 : : mProfileLoaded(false)
95 1 : , mDynamicRegistration(true)
96 : {
97 1 : }
98 :
99 0 : nsChromeRegistryChrome::~nsChromeRegistryChrome()
100 : {
101 0 : }
102 :
103 : nsresult
104 1 : nsChromeRegistryChrome::Init()
105 : {
106 1 : nsresult rv = nsChromeRegistry::Init();
107 1 : if (NS_FAILED(rv))
108 0 : return rv;
109 :
110 1 : mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
111 :
112 1 : bool safeMode = false;
113 2 : nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
114 1 : if (xulrun)
115 1 : xulrun->GetInSafeMode(&safeMode);
116 :
117 2 : nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
118 2 : nsCOMPtr<nsIPrefBranch> prefs;
119 :
120 1 : if (prefserv) {
121 1 : if (safeMode) {
122 0 : prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
123 : } else {
124 1 : prefs = do_QueryInterface(prefserv);
125 : }
126 : }
127 :
128 1 : if (!prefs) {
129 0 : NS_WARNING("Could not get pref service!");
130 : } else {
131 2 : nsXPIDLCString provider;
132 1 : rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
133 1 : if (NS_SUCCEEDED(rv))
134 1 : mSelectedSkin = provider;
135 :
136 1 : rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
137 : }
138 :
139 2 : nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
140 1 : if (obsService) {
141 1 : obsService->AddObserver(this, "profile-initial-state", true);
142 1 : obsService->AddObserver(this, "intl:app-locales-changed", true);
143 : }
144 :
145 1 : return NS_OK;
146 : }
147 :
148 : NS_IMETHODIMP
149 1 : nsChromeRegistryChrome::CheckForOSAccessibility()
150 : {
151 : int32_t useAccessibilityTheme =
152 1 : LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
153 :
154 1 : if (useAccessibilityTheme) {
155 : /* Set the skin to classic and remove pref observers */
156 0 : if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
157 0 : mSelectedSkin.AssignLiteral("classic/1.0");
158 0 : RefreshSkins();
159 : }
160 :
161 0 : nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
162 0 : if (prefs) {
163 0 : prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
164 : }
165 : }
166 :
167 1 : return NS_OK;
168 : }
169 :
170 : NS_IMETHODIMP
171 2 : nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
172 : nsIUTF8StringEnumerator* *aResult)
173 : {
174 4 : nsCString realpackage;
175 2 : nsresult rv = OverrideLocalePackage(aPackage, realpackage);
176 2 : if (NS_FAILED(rv))
177 0 : return rv;
178 :
179 2 : nsTArray<nsCString> *a = new nsTArray<nsCString>;
180 2 : if (!a)
181 0 : return NS_ERROR_OUT_OF_MEMORY;
182 :
183 : PackageEntry* entry;
184 2 : if (mPackagesHash.Get(realpackage, &entry)) {
185 1 : entry->locales.EnumerateToArray(a);
186 : }
187 :
188 2 : rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
189 2 : if (NS_FAILED(rv))
190 0 : delete a;
191 :
192 2 : return rv;
193 : }
194 :
195 : NS_IMETHODIMP
196 1 : nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
197 : {
198 1 : *aResult = false;
199 :
200 2 : nsAutoCString locale;
201 1 : GetSelectedLocale(package, false, locale);
202 1 : if (locale.Length() < 2)
203 0 : return NS_OK;
204 :
205 1 : *aResult = GetDirectionForLocale(locale);
206 1 : return NS_OK;
207 : }
208 :
209 : /**
210 : * This method negotiates only between the app locale and the available
211 : * chrome packages.
212 : *
213 : * If you want to get the current application's UI locale, please use
214 : * LocaleService::GetAppLocaleAsLangTag.
215 : */
216 : nsresult
217 1 : nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
218 : bool aAsBCP47,
219 : nsACString& aLocale)
220 : {
221 2 : nsAutoCString reqLocale;
222 1 : if (aPackage.Equals("global")) {
223 0 : LocaleService::GetInstance()->GetAppLocaleAsLangTag(reqLocale);
224 : } else {
225 2 : AutoTArray<nsCString, 10> requestedLocales;
226 1 : LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
227 1 : reqLocale.Assign(requestedLocales[0]);
228 : }
229 :
230 2 : nsCString realpackage;
231 1 : nsresult rv = OverrideLocalePackage(aPackage, realpackage);
232 1 : if (NS_FAILED(rv))
233 0 : return rv;
234 : PackageEntry* entry;
235 1 : if (!mPackagesHash.Get(realpackage, &entry))
236 0 : return NS_ERROR_FILE_NOT_FOUND;
237 :
238 1 : aLocale = entry->locales.GetSelected(reqLocale, nsProviderArray::LOCALE);
239 1 : if (aLocale.IsEmpty())
240 0 : return NS_ERROR_FAILURE;
241 :
242 1 : if (aAsBCP47) {
243 0 : SanitizeForBCP47(aLocale);
244 : }
245 :
246 1 : return NS_OK;
247 : }
248 :
249 : nsresult
250 27 : nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
251 : nsACString& aOverride)
252 : {
253 54 : const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
254 54 : nsAdoptingCString override = mozilla::Preferences::GetCString(PromiseFlatCString(pref).get());
255 27 : if (override) {
256 0 : aOverride = override;
257 : }
258 : else {
259 27 : aOverride = aPackage;
260 : }
261 54 : return NS_OK;
262 : }
263 :
264 : NS_IMETHODIMP
265 1 : nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
266 : const char16_t *someData)
267 : {
268 1 : nsresult rv = NS_OK;
269 :
270 1 : if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
271 0 : nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
272 0 : NS_ASSERTION(prefs, "Bad observer call!");
273 :
274 0 : NS_ConvertUTF16toUTF8 pref(someData);
275 :
276 0 : if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
277 0 : nsXPIDLCString provider;
278 0 : rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
279 0 : if (NS_FAILED(rv)) {
280 0 : NS_ERROR("Couldn't get new skin pref!");
281 0 : return rv;
282 : }
283 :
284 0 : mSelectedSkin = provider;
285 0 : RefreshSkins();
286 : } else {
287 0 : NS_ERROR("Unexpected pref!");
288 : }
289 : }
290 1 : else if (!strcmp("profile-initial-state", aTopic)) {
291 1 : mProfileLoaded = true;
292 : }
293 0 : else if (!strcmp("intl:app-locales-changed", aTopic)) {
294 0 : if (mProfileLoaded) {
295 0 : FlushAllCaches();
296 : }
297 : }
298 : else {
299 0 : NS_ERROR("Unexpected observer topic!");
300 : }
301 :
302 1 : return rv;
303 : }
304 :
305 : NS_IMETHODIMP
306 0 : nsChromeRegistryChrome::CheckForNewChrome()
307 : {
308 0 : mPackagesHash.Clear();
309 0 : mOverlayHash.Clear();
310 0 : mStyleHash.Clear();
311 0 : mOverrideTable.Clear();
312 :
313 0 : mDynamicRegistration = false;
314 :
315 0 : nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
316 :
317 0 : mDynamicRegistration = true;
318 :
319 0 : SendRegisteredChrome(nullptr);
320 0 : return NS_OK;
321 : }
322 :
323 : static void
324 579 : SerializeURI(nsIURI* aURI,
325 : SerializedURI& aSerializedURI)
326 : {
327 579 : if (!aURI)
328 236 : return;
329 :
330 343 : aURI->GetSpec(aSerializedURI.spec);
331 343 : aURI->GetOriginCharset(aSerializedURI.charset);
332 : }
333 :
334 : void
335 2 : nsChromeRegistryChrome::SendRegisteredChrome(
336 : mozilla::dom::PContentParent* aParent)
337 : {
338 4 : InfallibleTArray<ChromePackage> packages;
339 4 : InfallibleTArray<SubstitutionMapping> resources;
340 4 : InfallibleTArray<OverrideMapping> overrides;
341 :
342 90 : for (auto iter = mPackagesHash.Iter(); !iter.Done(); iter.Next()) {
343 176 : ChromePackage chromePackage;
344 88 : ChromePackageFromPackageEntry(iter.Key(), iter.UserData(), &chromePackage,
345 88 : mSelectedSkin);
346 88 : packages.AppendElement(chromePackage);
347 : }
348 :
349 : // If we were passed a parent then a new child process has been created and
350 : // has requested all of the chrome so send it the resources too. Otherwise
351 : // resource mappings are sent by the resource protocol handler dynamically.
352 2 : if (aParent) {
353 4 : nsCOMPtr<nsIIOService> io (do_GetIOService());
354 2 : NS_ENSURE_TRUE_VOID(io);
355 :
356 4 : nsCOMPtr<nsIProtocolHandler> ph;
357 2 : nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
358 2 : NS_ENSURE_SUCCESS_VOID(rv);
359 :
360 4 : nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
361 2 : nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
362 2 : rv = rph->CollectSubstitutions(resources);
363 2 : NS_ENSURE_SUCCESS_VOID(rv);
364 : }
365 :
366 42 : for (auto iter = mOverrideTable.Iter(); !iter.Done(); iter.Next()) {
367 80 : SerializedURI chromeURI, overrideURI;
368 :
369 40 : SerializeURI(iter.Key(), chromeURI);
370 40 : SerializeURI(iter.UserData(), overrideURI);
371 :
372 80 : OverrideMapping override = { chromeURI, overrideURI };
373 40 : overrides.AppendElement(override);
374 : }
375 :
376 4 : nsAutoCString appLocale;
377 2 : LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
378 :
379 2 : if (aParent) {
380 4 : bool success = aParent->SendRegisterChrome(packages, resources, overrides,
381 2 : appLocale, false);
382 2 : NS_ENSURE_TRUE_VOID(success);
383 : } else {
384 0 : nsTArray<ContentParent*> parents;
385 0 : ContentParent::GetAll(parents);
386 0 : if (!parents.Length())
387 0 : return;
388 :
389 0 : for (uint32_t i = 0; i < parents.Length(); i++) {
390 : DebugOnly<bool> success =
391 0 : parents[i]->SendRegisterChrome(packages, resources, overrides,
392 0 : appLocale, true);
393 0 : NS_WARNING_ASSERTION(success,
394 : "couldn't reset a child's registered chrome");
395 : }
396 : }
397 : }
398 :
399 : /* static */ void
400 153 : nsChromeRegistryChrome::ChromePackageFromPackageEntry(const nsACString& aPackageName,
401 : PackageEntry* aPackage,
402 : ChromePackage* aChromePackage,
403 : const nsCString& aSelectedSkin)
404 : {
405 306 : nsAutoCString appLocale;
406 153 : LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
407 :
408 153 : SerializeURI(aPackage->baseURI, aChromePackage->contentBaseURI);
409 153 : SerializeURI(aPackage->locales.GetBase(appLocale, nsProviderArray::LOCALE),
410 153 : aChromePackage->localeBaseURI);
411 153 : SerializeURI(aPackage->skins.GetBase(aSelectedSkin, nsProviderArray::ANY),
412 153 : aChromePackage->skinBaseURI);
413 153 : aChromePackage->package = aPackageName;
414 153 : aChromePackage->flags = aPackage->flags;
415 153 : }
416 :
417 : static bool
418 103 : CanLoadResource(nsIURI* aResourceURI)
419 : {
420 103 : bool isLocalResource = false;
421 : (void)NS_URIChainHasFlags(aResourceURI,
422 : nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
423 103 : &isLocalResource);
424 103 : return isLocalResource;
425 : }
426 :
427 : nsIURI*
428 179 : nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
429 : const nsCString& aProvider,
430 : const nsCString& aPath)
431 : {
432 : PackageEntry* entry;
433 179 : if (!mPackagesHash.Get(aPackage, &entry)) {
434 0 : if (!mInitialized)
435 0 : return nullptr;
436 :
437 0 : LogMessage("No chrome package registered for chrome://%s/%s/%s",
438 0 : aPackage.get(), aProvider.get(), aPath.get());
439 :
440 0 : return nullptr;
441 : }
442 :
443 179 : if (aProvider.EqualsLiteral("locale")) {
444 38 : nsAutoCString appLocale;
445 19 : LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
446 19 : return entry->locales.GetBase(appLocale, nsProviderArray::LOCALE);
447 : }
448 160 : else if (aProvider.EqualsLiteral("skin")) {
449 61 : return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
450 : }
451 99 : else if (aProvider.EqualsLiteral("content")) {
452 99 : return entry->baseURI;
453 : }
454 0 : return nullptr;
455 : }
456 :
457 : nsresult
458 893 : nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
459 : uint32_t* aFlags)
460 : {
461 : PackageEntry* entry;
462 893 : if (!mPackagesHash.Get(aPackage, &entry))
463 0 : return NS_ERROR_FILE_NOT_FOUND;
464 :
465 893 : *aFlags = entry->flags;
466 893 : return NS_OK;
467 : }
468 :
469 : nsChromeRegistryChrome::ProviderEntry*
470 426 : nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
471 : {
472 426 : size_t i = mArray.Length();
473 426 : if (!i)
474 215 : return nullptr;
475 :
476 211 : ProviderEntry* found = nullptr; // Only set if we find a partial-match locale
477 211 : ProviderEntry* entry = nullptr;
478 :
479 211 : while (i--) {
480 211 : entry = &mArray[i];
481 211 : if (aPreferred.Equals(entry->provider))
482 211 : return entry;
483 :
484 0 : if (aType != LOCALE)
485 0 : continue;
486 :
487 0 : if (LanguagesMatch(aPreferred, entry->provider)) {
488 0 : found = entry;
489 0 : continue;
490 : }
491 :
492 0 : if (!found && entry->provider.EqualsLiteral("en-US"))
493 0 : found = entry;
494 : }
495 :
496 0 : if (!found && aType != EXACT)
497 0 : return entry;
498 :
499 0 : return found;
500 : }
501 :
502 : nsIURI*
503 386 : nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
504 : {
505 386 : ProviderEntry* provider = GetProvider(aPreferred, aType);
506 :
507 386 : if (!provider)
508 176 : return nullptr;
509 :
510 210 : return provider->baseURI;
511 : }
512 :
513 : const nsACString&
514 1 : nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
515 : {
516 1 : ProviderEntry* entry = GetProvider(aPreferred, aType);
517 :
518 1 : if (entry)
519 1 : return entry->provider;
520 :
521 0 : return EmptyCString();
522 : }
523 :
524 : void
525 39 : nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
526 : {
527 39 : ProviderEntry* provider = GetProvider(aProvider, EXACT);
528 :
529 39 : if (provider) {
530 0 : provider->baseURI = aBaseURL;
531 0 : return;
532 : }
533 :
534 : // no existing entries, add a new one
535 39 : mArray.AppendElement(ProviderEntry(aProvider, aBaseURL));
536 : }
537 :
538 : void
539 1 : nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
540 : {
541 1 : int32_t i = mArray.Length();
542 3 : while (i--) {
543 1 : a->AppendElement(mArray[i].provider);
544 : }
545 1 : }
546 :
547 : void
548 7 : nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
549 : {
550 7 : int32_t i = mArray.Count();
551 11 : while (i--) {
552 : bool equals;
553 2 : if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
554 0 : return;
555 : }
556 :
557 7 : mArray.AppendObject(aURI);
558 : }
559 :
560 : void
561 7 : nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
562 : {
563 7 : OverlayListEntry* entry = mTable.PutEntry(aBase);
564 7 : if (entry)
565 7 : entry->AddURI(aOverlay);
566 7 : }
567 :
568 : const nsCOMArray<nsIURI>*
569 6 : nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
570 : {
571 6 : OverlayListEntry* entry = mTable.GetEntry(aBase);
572 6 : if (!entry)
573 5 : return nullptr;
574 :
575 1 : return &entry->mArray;
576 : }
577 :
578 : #ifdef MOZ_XUL
579 : NS_IMETHODIMP
580 0 : nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL,
581 : nsISimpleEnumerator **aResult)
582 : {
583 0 : nsCOMPtr<nsIURI> chromeURLWithoutHash;
584 0 : if (aChromeURL) {
585 0 : aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
586 : }
587 0 : const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(chromeURLWithoutHash);
588 0 : if (!parray)
589 0 : return NS_NewEmptyEnumerator(aResult);
590 :
591 0 : return NS_NewArrayEnumerator(aResult, *parray);
592 : }
593 :
594 : NS_IMETHODIMP
595 6 : nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
596 : nsISimpleEnumerator **aResult)
597 : {
598 12 : nsCOMPtr<nsIURI> chromeURLWithoutHash;
599 6 : if (aChromeURL) {
600 6 : aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
601 : }
602 6 : const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(chromeURLWithoutHash);
603 6 : if (!parray)
604 5 : return NS_NewEmptyEnumerator(aResult);
605 :
606 1 : return NS_NewArrayEnumerator(aResult, *parray);
607 : }
608 : #endif // MOZ_XUL
609 :
610 : nsIURI*
611 130 : nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
612 : {
613 130 : if (!mManifestURI) {
614 66 : nsCString uri;
615 33 : mFile.GetURIString(uri);
616 33 : NS_NewURI(getter_AddRefs(mManifestURI), uri);
617 : }
618 130 : return mManifestURI;
619 : }
620 :
621 : already_AddRefed<nsIURI>
622 130 : nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
623 : {
624 130 : nsIURI* baseuri = GetManifestURI();
625 130 : if (!baseuri)
626 0 : return nullptr;
627 :
628 260 : nsCOMPtr<nsIURI> resolved;
629 130 : nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
630 130 : if (NS_FAILED(rv))
631 0 : return nullptr;
632 :
633 130 : return resolved.forget();
634 : }
635 :
636 : static void
637 859 : EnsureLowerCase(char *aBuf)
638 : {
639 1642 : for (; *aBuf; ++aBuf) {
640 783 : char ch = *aBuf;
641 783 : if (ch >= 'A' && ch <= 'Z')
642 0 : *aBuf = ch + 'a' - 'A';
643 : }
644 76 : }
645 :
646 : static void
647 85 : SendManifestEntry(const ChromeRegistryItem &aItem)
648 : {
649 85 : nsTArray<ContentParent*> parents;
650 85 : ContentParent::GetAll(parents);
651 85 : if (!parents.Length())
652 85 : return;
653 :
654 0 : for (uint32_t i = 0; i < parents.Length(); i++) {
655 0 : Unused << parents[i]->SendRegisterChromeItem(aItem);
656 : }
657 : }
658 :
659 : void
660 26 : nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno,
661 : char *const * argv, int flags)
662 : {
663 26 : char* package = argv[0];
664 26 : char* uri = argv[1];
665 :
666 26 : EnsureLowerCase(package);
667 :
668 52 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
669 26 : if (!resolved) {
670 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
671 0 : "During chrome registration, unable to create URI '%s'.", uri);
672 0 : return;
673 : }
674 :
675 26 : if (!CanLoadResource(resolved)) {
676 0 : LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
677 : "During chrome registration, cannot register non-local URI '%s' as content.",
678 0 : uri);
679 0 : return;
680 : }
681 :
682 52 : nsDependentCString packageName(package);
683 26 : PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
684 26 : entry->baseURI = resolved;
685 26 : entry->flags = flags;
686 :
687 26 : if (mDynamicRegistration) {
688 52 : ChromePackage chromePackage;
689 26 : ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
690 26 : mSelectedSkin);
691 26 : SendManifestEntry(chromePackage);
692 : }
693 : }
694 :
695 : void
696 24 : nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
697 : char *const * argv, int flags)
698 : {
699 24 : char* package = argv[0];
700 24 : char* provider = argv[1];
701 24 : char* uri = argv[2];
702 :
703 24 : EnsureLowerCase(package);
704 :
705 48 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
706 24 : if (!resolved) {
707 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
708 0 : "During chrome registration, unable to create URI '%s'.", uri);
709 0 : return;
710 : }
711 :
712 24 : if (!CanLoadResource(resolved)) {
713 0 : LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
714 : "During chrome registration, cannot register non-local URI '%s' as content.",
715 0 : uri);
716 0 : return;
717 : }
718 :
719 48 : nsDependentCString packageName(package);
720 24 : PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
721 24 : entry->locales.SetBase(nsDependentCString(provider), resolved);
722 :
723 24 : if (mDynamicRegistration) {
724 48 : ChromePackage chromePackage;
725 24 : ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
726 24 : mSelectedSkin);
727 24 : SendManifestEntry(chromePackage);
728 : }
729 :
730 : // We use mainPackage as the package we track for reporting new locales being
731 : // registered. For most cases it will be "global", but for Fennec it will be
732 : // "browser".
733 48 : nsAutoCString mainPackage;
734 24 : nsresult rv = OverrideLocalePackage(NS_LITERAL_CSTRING("global"), mainPackage);
735 24 : if (NS_FAILED(rv)) {
736 0 : return;
737 : }
738 :
739 24 : if (mainPackage.Equals(package)) {
740 : // We should refresh the LocaleService, since the available
741 : // locales changed.
742 1 : LocaleService::GetInstance()->OnAvailableLocalesChanged();
743 : }
744 : }
745 :
746 : void
747 15 : nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
748 : char *const * argv, int flags)
749 : {
750 15 : char* package = argv[0];
751 15 : char* provider = argv[1];
752 15 : char* uri = argv[2];
753 :
754 15 : EnsureLowerCase(package);
755 :
756 30 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
757 15 : if (!resolved) {
758 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
759 0 : "During chrome registration, unable to create URI '%s'.", uri);
760 0 : return;
761 : }
762 :
763 15 : if (!CanLoadResource(resolved)) {
764 0 : LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
765 : "During chrome registration, cannot register non-local URI '%s' as content.",
766 0 : uri);
767 0 : return;
768 : }
769 :
770 30 : nsDependentCString packageName(package);
771 15 : PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
772 15 : entry->skins.SetBase(nsDependentCString(provider), resolved);
773 :
774 15 : if (mDynamicRegistration) {
775 30 : ChromePackage chromePackage;
776 15 : ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
777 15 : mSelectedSkin);
778 15 : SendManifestEntry(chromePackage);
779 : }
780 : }
781 :
782 : void
783 7 : nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
784 : char *const * argv, int flags)
785 : {
786 7 : char* base = argv[0];
787 7 : char* overlay = argv[1];
788 :
789 14 : nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
790 14 : nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
791 7 : if (!baseuri || !overlayuri) {
792 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
793 0 : "During chrome registration, unable to create URI.");
794 0 : return;
795 : }
796 :
797 7 : if (!CanLoadResource(overlayuri)) {
798 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
799 0 : "Cannot register non-local URI '%s' as an overlay.", overlay);
800 0 : return;
801 : }
802 :
803 14 : nsCOMPtr<nsIURI> baseuriWithoutHash;
804 7 : baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
805 :
806 7 : mOverlayHash.Add(baseuriWithoutHash, overlayuri);
807 : }
808 :
809 : void
810 0 : nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno,
811 : char *const * argv, int flags)
812 : {
813 0 : char* base = argv[0];
814 0 : char* overlay = argv[1];
815 :
816 0 : nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
817 0 : nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
818 0 : if (!baseuri || !overlayuri) {
819 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
820 0 : "During chrome registration, unable to create URI.");
821 0 : return;
822 : }
823 :
824 0 : if (!CanLoadResource(overlayuri)) {
825 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
826 0 : "Cannot register non-local URI '%s' as a style overlay.", overlay);
827 0 : return;
828 : }
829 :
830 0 : nsCOMPtr<nsIURI> baseuriWithoutHash;
831 0 : baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
832 :
833 0 : mStyleHash.Add(baseuriWithoutHash, overlayuri);
834 : }
835 :
836 : void
837 20 : nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno,
838 : char *const * argv, int flags)
839 : {
840 20 : char* chrome = argv[0];
841 20 : char* resolved = argv[1];
842 :
843 40 : nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
844 40 : nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
845 20 : if (!chromeuri || !resolveduri) {
846 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
847 0 : "During chrome registration, unable to create URI.");
848 0 : return;
849 : }
850 :
851 20 : if (cx.mType == NS_SKIN_LOCATION) {
852 14 : bool chromeSkinOnly = false;
853 14 : nsresult rv = chromeuri->SchemeIs("chrome", &chromeSkinOnly);
854 14 : chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
855 14 : if (chromeSkinOnly) {
856 14 : rv = resolveduri->SchemeIs("chrome", &chromeSkinOnly);
857 14 : chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
858 : }
859 14 : if (chromeSkinOnly) {
860 28 : nsAutoCString chromePath, resolvedPath;
861 14 : chromeuri->GetPath(chromePath);
862 14 : resolveduri->GetPath(resolvedPath);
863 70 : chromeSkinOnly = StringBeginsWith(chromePath, NS_LITERAL_CSTRING("/skin/")) &&
864 42 : StringBeginsWith(resolvedPath, NS_LITERAL_CSTRING("/skin/"));
865 : }
866 14 : if (!chromeSkinOnly) {
867 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
868 : "Cannot register non-chrome://.../skin/ URIs '%s' and '%s' as overrides and/or to be overridden from a skin manifest.",
869 0 : chrome, resolved);
870 0 : return;
871 : }
872 : }
873 :
874 20 : if (!CanLoadResource(resolveduri)) {
875 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
876 0 : "Cannot register non-local URI '%s' for an override.", resolved);
877 0 : return;
878 : }
879 20 : mOverrideTable.Put(chromeuri, resolveduri);
880 :
881 20 : if (mDynamicRegistration) {
882 40 : SerializedURI serializedChrome;
883 40 : SerializedURI serializedOverride;
884 :
885 20 : SerializeURI(chromeuri, serializedChrome);
886 20 : SerializeURI(resolveduri, serializedOverride);
887 :
888 40 : OverrideMapping override = { serializedChrome, serializedOverride };
889 20 : SendManifestEntry(override);
890 : }
891 : }
892 :
893 : void
894 11 : nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno,
895 : char *const * argv, int flags)
896 : {
897 11 : char* package = argv[0];
898 11 : char* uri = argv[1];
899 :
900 11 : EnsureLowerCase(package);
901 22 : nsDependentCString host(package);
902 :
903 22 : nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
904 11 : if (!io) {
905 0 : NS_WARNING("No IO service trying to process chrome manifests");
906 0 : return;
907 : }
908 :
909 22 : nsCOMPtr<nsIProtocolHandler> ph;
910 11 : nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
911 11 : if (NS_FAILED(rv))
912 0 : return;
913 :
914 22 : nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
915 :
916 22 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
917 11 : if (!resolved) {
918 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
919 0 : "During chrome registration, unable to create URI '%s'.", uri);
920 0 : return;
921 : }
922 :
923 11 : if (!CanLoadResource(resolved)) {
924 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
925 : "Warning: cannot register non-local URI '%s' as a resource.",
926 0 : uri);
927 0 : return;
928 : }
929 :
930 11 : rv = rph->SetSubstitution(host, resolved);
931 11 : if (NS_FAILED(rv)) {
932 0 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
933 : "Warning: cannot set substitution for '%s'.",
934 0 : uri);
935 : }
936 : }
|