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