Bug 547353 - [OOPP] Mouse pointer coordinates misaligned with winless Silverlight...
[mozilla-central.git] / chrome / src / nsChromeRegistry.cpp
blob0491906139536da3dfa0d11ca070fb8d5161f87b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Original Author: David W. Hyatt (hyatt@netscape.com)
25 * Gagan Saksena <gagan@netscape.com>
26 * Benjamin Smedberg <benjamin@smedbergs.us>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsChromeRegistry.h"
44 #include <string.h>
46 #include "prio.h"
47 #include "prprf.h"
48 #if defined(XP_WIN)
49 #include <windows.h>
50 #elif defined(XP_MACOSX)
51 #include <Carbon/Carbon.h>
52 #elif defined(MOZ_WIDGET_GTK2)
53 #include <gtk/gtk.h>
54 #endif
56 #include "nsAppDirectoryServiceDefs.h"
57 #include "nsArrayEnumerator.h"
58 #include "nsStringEnumerator.h"
59 #include "nsEnumeratorUtils.h"
60 #include "nsCOMPtr.h"
61 #include "nsDOMError.h"
62 #include "nsEscape.h"
63 #include "nsInt64.h"
64 #include "nsLayoutCID.h"
65 #include "nsNetCID.h"
66 #include "nsNetUtil.h"
67 #include "nsReadableUtils.h"
68 #include "nsStaticAtom.h"
69 #include "nsString.h"
70 #include "nsUnicharUtils.h"
71 #include "nsWidgetsCID.h"
72 #include "nsXPCOMCIDInternal.h"
73 #include "nsXPIDLString.h"
74 #include "nsXULAppAPI.h"
75 #include "nsTextFormatter.h"
77 #include "nsIAtom.h"
78 #include "nsICommandLine.h"
79 #include "nsICSSLoader.h"
80 #include "nsICSSStyleSheet.h"
81 #include "nsIConsoleService.h"
82 #include "nsIDirectoryService.h"
83 #include "nsIDocument.h"
84 #include "nsIDOMDocument.h"
85 #include "nsIDocShell.h"
86 #include "nsIDocumentObserver.h"
87 #include "nsIDOMElement.h"
88 #include "nsIDOMLocation.h"
89 #include "nsIDOMWindowCollection.h"
90 #include "nsIDOMWindowInternal.h"
91 #include "nsIFileChannel.h"
92 #include "nsIFileURL.h"
93 #include "nsIIOService.h"
94 #include "nsIJARProtocolHandler.h"
95 #include "nsIJARURI.h"
96 #include "nsILocalFile.h"
97 #include "nsILocaleService.h"
98 #include "nsILookAndFeel.h"
99 #include "nsIObserverService.h"
100 #include "nsIPrefService.h"
101 #include "nsIPrefBranch.h"
102 #include "nsIPrefBranch2.h"
103 #include "nsIPresShell.h"
104 #include "nsIProtocolHandler.h"
105 #include "nsIResProtocolHandler.h"
106 #include "nsIScriptError.h"
107 #include "nsIServiceManager.h"
108 #include "nsISimpleEnumerator.h"
109 #include "nsIStyleSheet.h"
110 #include "nsISupportsArray.h"
111 #include "nsIVersionComparator.h"
112 #include "nsIWindowMediator.h"
113 #include "nsIXPConnect.h"
114 #include "nsIXULAppInfo.h"
115 #include "nsIXULRuntime.h"
117 #define UILOCALE_CMD_LINE_ARG "UILocale"
119 #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
120 #define SELECTED_LOCALE_PREF "general.useragent.locale"
121 #define SELECTED_SKIN_PREF "general.skins.selectedSkin"
123 static NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID);
124 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
126 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
128 ////////////////////////////////////////////////////////////////////////////////
130 static void
131 LogMessage(const char* aMsg, ...)
133 nsCOMPtr<nsIConsoleService> console
134 (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
135 if (!console)
136 return;
138 va_list args;
139 va_start(args, aMsg);
140 char* formatted = PR_vsmprintf(aMsg, args);
141 va_end(args);
142 if (!formatted)
143 return;
145 console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
146 PR_smprintf_free(formatted);
149 static void
150 LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
151 const char* aMsg, ...)
153 nsresult rv;
155 nsCOMPtr<nsIConsoleService> console
156 (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
158 nsCOMPtr<nsIScriptError> error
159 (do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
160 if (!console || !error)
161 return;
163 va_list args;
164 va_start(args, aMsg);
165 char* formatted = PR_vsmprintf(aMsg, args);
166 va_end(args);
167 if (!formatted)
168 return;
170 nsCString spec;
171 if (aURL)
172 aURL->GetSpec(spec);
174 rv = error->Init(NS_ConvertUTF8toUTF16(formatted).get(),
175 NS_ConvertUTF8toUTF16(spec).get(),
176 nsnull,
177 aLineNumber, 0, flags, "chrome registration");
178 PR_smprintf_free(formatted);
180 if (NS_FAILED(rv))
181 return;
183 console->LogMessage(error);
186 // We use a "best-fit" algorithm for matching locales and themes.
187 // 1) the exact selected locale/theme
188 // 2) (locales only) same language, different country
189 // e.g. en-GB is the selected locale, only en-US is available
190 // 3) any available locale/theme
193 * Match the language-part of two lang-COUNTRY codes, hopefully but
194 * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
195 * work, any other garbage-in will produce undefined results as long
196 * as it does not crash.
198 static PRBool
199 LanguagesMatch(const nsACString& a, const nsACString& b)
201 if (a.Length() < 2 || b.Length() < 2)
202 return PR_FALSE;
204 nsACString::const_iterator as, ae, bs, be;
205 a.BeginReading(as);
206 a.EndReading(ae);
207 b.BeginReading(bs);
208 b.EndReading(be);
210 while (*as == *bs) {
211 if (*as == '-')
212 return PR_TRUE;
214 ++as; ++bs;
216 // reached the end
217 if (as == ae && bs == be)
218 return PR_TRUE;
220 // "a" is short
221 if (as == ae)
222 return (*bs == '-');
224 // "b" is short
225 if (bs == be)
226 return (*as == '-');
229 return PR_FALSE;
232 static PRBool
233 CanLoadResource(nsIURI* aResourceURI)
235 PRBool isLocalResource = PR_FALSE;
236 (void)NS_URIChainHasFlags(aResourceURI,
237 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
238 &isLocalResource);
239 return isLocalResource;
242 nsChromeRegistry::ProviderEntry*
243 nsChromeRegistry::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
245 PRInt32 i = mArray.Count();
246 if (!i)
247 return nsnull;
249 ProviderEntry* found = nsnull; // Only set if we find a partial-match locale
250 ProviderEntry* entry;
252 while (i--) {
253 entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
254 if (aPreferred.Equals(entry->provider))
255 return entry;
257 if (aType != LOCALE)
258 continue;
260 if (LanguagesMatch(aPreferred, entry->provider)) {
261 found = entry;
262 continue;
265 if (!found && entry->provider.EqualsLiteral("en-US"))
266 found = entry;
269 if (!found && aType != EXACT)
270 return entry;
272 return found;
275 nsIURI*
276 nsChromeRegistry::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
278 ProviderEntry* provider = GetProvider(aPreferred, aType);
280 if (!provider)
281 return nsnull;
283 return provider->baseURI;
286 const nsACString&
287 nsChromeRegistry::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
289 ProviderEntry* entry = GetProvider(aPreferred, aType);
291 if (entry)
292 return entry->provider;
294 return EmptyCString();
297 void
298 nsChromeRegistry::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
300 ProviderEntry* provider = GetProvider(aProvider, EXACT);
302 if (provider) {
303 provider->baseURI = aBaseURL;
304 return;
307 // no existing entries, add a new one
308 provider = new ProviderEntry(aProvider, aBaseURL);
309 if (!provider)
310 return; // It's safe to silently fail on OOM
312 mArray.AppendElement(provider);
315 void
316 nsChromeRegistry::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
318 PRInt32 i = mArray.Count();
319 while (i--) {
320 ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
321 a->AppendElement(entry->provider);
325 void
326 nsChromeRegistry::nsProviderArray::Clear()
328 PRInt32 i = mArray.Count();
329 while (i--) {
330 ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
331 delete entry;
334 mArray.Clear();
337 nsChromeRegistry::PackageEntry::PackageEntry(const nsACString& aPackage) :
338 package(aPackage), flags(0)
342 PLHashNumber
343 nsChromeRegistry::HashKey(PLDHashTable *table, const void *key)
345 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
346 return HashString(str);
349 PRBool
350 nsChromeRegistry::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
351 const void *key)
353 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
354 const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
355 return str.Equals(pentry->package);
358 void
359 nsChromeRegistry::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
361 PackageEntry* pentry = static_cast<PackageEntry*>(entry);
362 pentry->~PackageEntry();
365 PRBool
366 nsChromeRegistry::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
367 const void *key)
369 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
371 new (entry) PackageEntry(str);
372 return PR_TRUE;
375 const PLDHashTableOps
376 nsChromeRegistry::kTableOps = {
377 PL_DHashAllocTable,
378 PL_DHashFreeTable,
379 HashKey,
380 MatchKey,
381 PL_DHashMoveEntryStub,
382 ClearEntry,
383 PL_DHashFinalizeStub,
384 InitEntry
387 void
388 nsChromeRegistry::OverlayListEntry::AddURI(nsIURI* aURI)
390 PRInt32 i = mArray.Count();
391 while (i--) {
392 PRBool equals;
393 if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
394 return;
397 mArray.AppendObject(aURI);
400 void
401 nsChromeRegistry::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
403 OverlayListEntry* entry = mTable.PutEntry(aBase);
404 if (entry)
405 entry->AddURI(aOverlay);
408 const nsCOMArray<nsIURI>*
409 nsChromeRegistry::OverlayListHash::GetArray(nsIURI* aBase)
411 OverlayListEntry* entry = mTable.GetEntry(aBase);
412 if (!entry)
413 return nsnull;
415 return &entry->mArray;
418 nsChromeRegistry::~nsChromeRegistry()
420 if (mPackagesHash.ops)
421 PL_DHashTableFinish(&mPackagesHash);
422 gChromeRegistry = nsnull;
425 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
426 NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
427 NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
428 NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
429 #ifdef MOZ_XUL
430 NS_INTERFACE_MAP_ENTRY(nsIXULOverlayProvider)
431 #endif
432 NS_INTERFACE_MAP_ENTRY(nsIObserver)
433 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
434 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChromeRegistry)
435 NS_INTERFACE_MAP_END
437 NS_IMPL_ADDREF(nsChromeRegistry)
438 NS_IMPL_RELEASE(nsChromeRegistry)
440 ////////////////////////////////////////////////////////////////////////////////
441 // nsIChromeRegistry methods:
443 static nsresult
444 getUILangCountry(nsACString& aUILang)
446 nsresult rv;
448 nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
449 NS_ENSURE_SUCCESS(rv, rv);
451 nsAutoString uiLang;
452 rv = localeService->GetLocaleComponentForUserAgent(uiLang);
453 NS_ENSURE_SUCCESS(rv, rv);
455 CopyUTF16toUTF8(uiLang, aUILang);
456 return NS_OK;
459 nsresult
460 nsChromeRegistry::Init()
462 nsresult rv;
464 // Check to see if necko and the JAR protocol handler are registered yet
465 // if not, somebody is doing work during XPCOM registration that they
466 // shouldn't be doing. See bug 292549, where JS components are trying
467 // to call Components.utils.import("chrome:///") early in registration
469 nsCOMPtr<nsIIOService> io (do_GetIOService());
470 if (!io) return NS_ERROR_FAILURE;
472 nsCOMPtr<nsIProtocolHandler> ph;
473 rv = io->GetProtocolHandler("jar", getter_AddRefs(ph));
474 NS_ENSURE_SUCCESS(rv, rv);
476 nsCOMPtr<nsIJARProtocolHandler> jph = do_QueryInterface(ph);
477 if (!jph)
478 return NS_ERROR_NOT_INITIALIZED;
480 if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
481 nsnull, sizeof(PackageEntry), 16))
482 return NS_ERROR_FAILURE;
484 if (!mOverlayHash.Init() ||
485 !mStyleHash.Init() ||
486 !mOverrideTable.Init())
487 return NS_ERROR_FAILURE;
489 mSelectedLocale = NS_LITERAL_CSTRING("en-US");
490 mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
492 // This initialization process is fairly complicated and may cause reentrant
493 // getservice calls to resolve chrome URIs (especially locale files). We
494 // don't want that, so we inform the protocol handler about our existence
495 // before we are actually fully initialized.
496 gChromeRegistry = this;
498 PRBool safeMode = PR_FALSE;
499 nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
500 if (xulrun)
501 xulrun->GetInSafeMode(&safeMode);
503 nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
504 nsCOMPtr<nsIPrefBranch> prefs;
506 if (safeMode)
507 prefserv->GetDefaultBranch(nsnull, getter_AddRefs(prefs));
508 else
509 prefs = do_QueryInterface(prefserv);
511 if (!prefs) {
512 NS_WARNING("Could not get pref service!");
514 else {
515 nsXPIDLCString provider;
516 rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
517 if (NS_SUCCEEDED(rv))
518 mSelectedSkin = provider;
520 SelectLocaleFromPref(prefs);
522 nsCOMPtr<nsIPrefBranch2> prefs2 (do_QueryInterface(prefs));
523 if (prefs2) {
524 rv = prefs2->AddObserver(MATCH_OS_LOCALE_PREF, this, PR_TRUE);
525 rv = prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
526 rv = prefs2->AddObserver(SELECTED_SKIN_PREF, this, PR_TRUE);
530 nsCOMPtr<nsIObserverService> obsService (do_GetService("@mozilla.org/observer-service;1"));
531 if (obsService) {
532 obsService->AddObserver(this, "command-line-startup", PR_TRUE);
533 obsService->AddObserver(this, "profile-initial-state", PR_TRUE);
536 CheckForNewChrome();
538 mInitialized = PR_TRUE;
540 return NS_OK;
543 NS_IMETHODIMP
544 nsChromeRegistry::CheckForOSAccessibility()
546 nsresult rv;
548 nsCOMPtr<nsILookAndFeel> lookAndFeel (do_GetService(kLookAndFeelCID));
549 if (lookAndFeel) {
550 PRInt32 useAccessibilityTheme = 0;
552 rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_UseAccessibilityTheme,
553 useAccessibilityTheme);
555 if (NS_SUCCEEDED(rv) && useAccessibilityTheme) {
556 /* Set the skin to classic and remove pref observers */
557 if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
558 mSelectedSkin.AssignLiteral("classic/1.0");
559 RefreshSkins();
562 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
563 if (prefs) {
564 prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
569 return NS_OK;
572 nsresult
573 nsChromeRegistry::GetProviderAndPath(nsIURL* aChromeURL,
574 nsACString& aProvider, nsACString& aPath)
576 nsresult rv;
578 #ifdef DEBUG
579 PRBool isChrome;
580 aChromeURL->SchemeIs("chrome", &isChrome);
581 NS_ASSERTION(isChrome, "Non-chrome URI?");
582 #endif
584 nsCAutoString path;
585 rv = aChromeURL->GetPath(path);
586 NS_ENSURE_SUCCESS(rv, rv);
588 if (path.Length() < 3) {
589 LogMessage("Invalid chrome URI: %s", path.get());
590 return NS_ERROR_FAILURE;
593 path.SetLength(nsUnescapeCount(path.BeginWriting()));
594 NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
596 PRInt32 slash = path.FindChar('/', 1);
597 if (slash == 1) {
598 LogMessage("Invalid chrome URI: %s", path.get());
599 return NS_ERROR_FAILURE;
602 if (slash == -1) {
603 aPath.Truncate();
605 else {
606 if (slash == (PRInt32) path.Length() - 1)
607 aPath.Truncate();
608 else
609 aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
611 --slash;
614 aProvider.Assign(path.get() + 1, slash);
615 return NS_OK;
619 nsresult
620 nsChromeRegistry::Canonify(nsIURL* aChromeURL)
622 NS_NAMED_LITERAL_CSTRING(kSlash, "/");
624 nsresult rv;
626 nsCAutoString provider, path;
627 rv = GetProviderAndPath(aChromeURL, provider, path);
628 NS_ENSURE_SUCCESS(rv, rv);
630 if (path.IsEmpty()) {
631 nsCAutoString package;
632 rv = aChromeURL->GetHost(package);
633 NS_ENSURE_SUCCESS(rv, rv);
635 // we re-use the "path" local string to build a new URL path
636 path.Assign(kSlash + provider + kSlash + package);
637 if (provider.EqualsLiteral("content")) {
638 path.AppendLiteral(".xul");
640 else if (provider.EqualsLiteral("locale")) {
641 path.AppendLiteral(".dtd");
643 else if (provider.EqualsLiteral("skin")) {
644 path.AppendLiteral(".css");
646 else {
647 return NS_ERROR_INVALID_ARG;
649 aChromeURL->SetPath(path);
651 else {
652 // prevent directory traversals ("..")
653 // path is already unescaped once, but uris can get unescaped twice
654 const char* pos = path.BeginReading();
655 const char* end = path.EndReading();
656 while (pos < end) {
657 switch (*pos) {
658 case ':':
659 return NS_ERROR_DOM_BAD_URI;
660 case '.':
661 if (pos[1] == '.')
662 return NS_ERROR_DOM_BAD_URI;
663 break;
664 case '%':
665 // chrome: URIs with double-escapes are trying to trick us.
666 // watch for %2e, and %25 in case someone triple unescapes
667 if (pos[1] == '2' &&
668 ( pos[2] == 'e' || pos[2] == 'E' ||
669 pos[2] == '5' ))
670 return NS_ERROR_DOM_BAD_URI;
671 break;
672 case '?':
673 case '#':
674 pos = end;
675 continue;
677 ++pos;
681 return NS_OK;
684 NS_IMETHODIMP
685 nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult)
687 nsresult rv;
688 NS_ASSERTION(aChromeURI, "null url!");
690 if (mOverrideTable.Get(aChromeURI, aResult))
691 return NS_OK;
693 nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aChromeURI));
694 NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
696 nsCAutoString package, provider, path;
697 rv = chromeURL->GetHostPort(package);
698 NS_ENSURE_SUCCESS(rv, rv);
700 rv = GetProviderAndPath(chromeURL, provider, path);
701 NS_ENSURE_SUCCESS(rv, rv);
703 PackageEntry* entry =
704 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
705 & (nsACString&) package,
706 PL_DHASH_LOOKUP));
708 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
709 if (!mInitialized)
710 return NS_ERROR_NOT_INITIALIZED;
712 LogMessage("No chrome package registered for chrome://%s/%s/%s",
713 package.get(), provider.get(), path.get());
715 return NS_ERROR_FAILURE;
718 if (entry->flags & PackageEntry::PLATFORM_PACKAGE) {
719 #if defined(XP_WIN) || defined(XP_OS2)
720 path.Insert("win/", 0);
721 #elif defined(XP_MACOSX)
722 path.Insert("mac/", 0);
723 #else
724 path.Insert("unix/", 0);
725 #endif
728 nsIURI* baseURI = nsnull;
729 if (provider.EqualsLiteral("locale")) {
730 baseURI = entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
732 else if (provider.EqualsLiteral("skin")) {
733 baseURI = entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
735 else if (provider.EqualsLiteral("content")) {
736 baseURI = entry->baseURI;
739 if (!baseURI) {
740 LogMessage("No chrome package registered for chrome://%s/%s/%s",
741 package.get(), provider.get(), path.get());
742 return NS_ERROR_FAILURE;
745 return NS_NewURI(aResult, path, nsnull, baseURI);
748 nsresult
749 nsChromeRegistry::GetSelectedLocale(const nsACString& aPackage, nsACString& aLocale)
751 PackageEntry* entry =
752 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
753 & aPackage,
754 PL_DHASH_LOOKUP));
756 if (PL_DHASH_ENTRY_IS_FREE(entry))
757 return NS_ERROR_FAILURE;
759 aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
760 if (aLocale.IsEmpty())
761 return NS_ERROR_FAILURE;
763 return NS_OK;
766 NS_IMETHODIMP
767 nsChromeRegistry::IsLocaleRTL(const nsACString& package, PRBool *aResult)
769 *aResult = PR_FALSE;
771 nsCAutoString locale;
772 GetSelectedLocale(package, locale);
773 if (locale.Length() < 2)
774 return NS_OK;
776 // first check the intl.uidirection.<locale> preference, and if that is not
777 // set, check the same preference but with just the first two characters of
778 // the locale. If that isn't set, default to left-to-right.
779 nsCAutoString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + locale;
780 nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
781 if (!prefBranch)
782 return NS_OK;
784 nsXPIDLCString dir;
785 prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
786 if (dir.IsEmpty()) {
787 PRInt32 hyphen = prefString.FindChar('-');
788 if (hyphen >= 1) {
789 nsCAutoString shortPref(Substring(prefString, 0, hyphen));
790 prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
793 *aResult = dir.EqualsLiteral("rtl");
794 return NS_OK;
797 NS_IMETHODIMP
798 nsChromeRegistry::GetLocalesForPackage(const nsACString& aPackage,
799 nsIUTF8StringEnumerator* *aResult)
801 nsTArray<nsCString> *a = new nsTArray<nsCString>;
802 if (!a)
803 return NS_ERROR_OUT_OF_MEMORY;
805 PackageEntry* entry =
806 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
807 & aPackage,
808 PL_DHASH_LOOKUP));
810 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
811 entry->locales.EnumerateToArray(a);
814 nsresult rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
815 if (NS_FAILED(rv))
816 delete a;
818 return rv;
821 #ifdef MOZ_XUL
822 NS_IMETHODIMP
823 nsChromeRegistry::GetStyleOverlays(nsIURI *aChromeURL,
824 nsISimpleEnumerator **aResult)
826 const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
827 if (!parray)
828 return NS_NewEmptyEnumerator(aResult);
830 return NS_NewArrayEnumerator(aResult, *parray);
833 NS_IMETHODIMP
834 nsChromeRegistry::GetXULOverlays(nsIURI *aChromeURL, nsISimpleEnumerator **aResult)
836 const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
837 if (!parray)
838 return NS_NewEmptyEnumerator(aResult);
840 return NS_NewArrayEnumerator(aResult, *parray);
842 #endif // MOZ_XUL
844 ////////////////////////////////////////////////////////////////////////
846 // theme stuff
849 static void FlushSkinBindingsForWindow(nsIDOMWindowInternal* aWindow)
851 // Get the DOM document.
852 nsCOMPtr<nsIDOMDocument> domDocument;
853 aWindow->GetDocument(getter_AddRefs(domDocument));
854 if (!domDocument)
855 return;
857 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
858 if (!document)
859 return;
861 // Annihilate all XBL bindings.
862 document->FlushSkinBindings();
865 // XXXbsmedberg: move this to nsIWindowMediator
866 NS_IMETHODIMP nsChromeRegistry::RefreshSkins()
868 nsCOMPtr<nsICSSLoader> cssLoader(do_CreateInstance(kCSSLoaderCID));
869 if (!cssLoader)
870 return NS_OK;
872 nsCOMPtr<nsIWindowMediator> windowMediator
873 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
874 if (!windowMediator)
875 return NS_OK;
877 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
878 windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
879 PRBool more;
880 windowEnumerator->HasMoreElements(&more);
881 while (more) {
882 nsCOMPtr<nsISupports> protoWindow;
883 windowEnumerator->GetNext(getter_AddRefs(protoWindow));
884 if (protoWindow) {
885 nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
886 if (domWindow)
887 FlushSkinBindingsForWindow(domWindow);
889 windowEnumerator->HasMoreElements(&more);
892 FlushSkinCaches();
894 windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
895 windowEnumerator->HasMoreElements(&more);
896 while (more) {
897 nsCOMPtr<nsISupports> protoWindow;
898 windowEnumerator->GetNext(getter_AddRefs(protoWindow));
899 if (protoWindow) {
900 nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
901 if (domWindow)
902 RefreshWindow(domWindow, cssLoader);
904 windowEnumerator->HasMoreElements(&more);
907 return NS_OK;
910 void
911 nsChromeRegistry::FlushSkinCaches()
913 nsCOMPtr<nsIObserverService> obsSvc =
914 do_GetService("@mozilla.org/observer-service;1");
915 NS_ASSERTION(obsSvc, "Couldn't get observer service.");
917 obsSvc->NotifyObservers(static_cast<nsIChromeRegistry*>(this),
918 NS_CHROME_FLUSH_SKINS_TOPIC, nsnull);
921 static PRBool IsChromeURI(nsIURI* aURI)
923 PRBool isChrome=PR_FALSE;
924 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
925 return PR_TRUE;
926 return PR_FALSE;
929 // XXXbsmedberg: move this to windowmediator
930 nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindowInternal* aWindow,
931 nsICSSLoader* aCSSLoader)
933 // Deal with our subframes first.
934 nsCOMPtr<nsIDOMWindowCollection> frames;
935 aWindow->GetFrames(getter_AddRefs(frames));
936 PRUint32 length;
937 frames->GetLength(&length);
938 PRUint32 j;
939 for (j = 0; j < length; j++) {
940 nsCOMPtr<nsIDOMWindow> childWin;
941 frames->Item(j, getter_AddRefs(childWin));
942 nsCOMPtr<nsIDOMWindowInternal> childInt(do_QueryInterface(childWin));
943 RefreshWindow(childInt, aCSSLoader);
946 nsresult rv;
947 // Get the DOM document.
948 nsCOMPtr<nsIDOMDocument> domDocument;
949 aWindow->GetDocument(getter_AddRefs(domDocument));
950 if (!domDocument)
951 return NS_OK;
953 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
954 if (!document)
955 return NS_OK;
957 // Deal with the agent sheets first. Have to do all the style sets by hand.
958 nsCOMPtr<nsIPresShell> shell = document->GetPrimaryShell();
959 if (shell) {
960 // Reload only the chrome URL agent style sheets.
961 nsCOMArray<nsIStyleSheet> agentSheets;
962 rv = shell->GetAgentStyleSheets(agentSheets);
963 NS_ENSURE_SUCCESS(rv, rv);
965 nsCOMArray<nsIStyleSheet> newAgentSheets;
966 for (PRInt32 l = 0; l < agentSheets.Count(); ++l) {
967 nsIStyleSheet *sheet = agentSheets[l];
969 nsCOMPtr<nsIURI> uri;
970 rv = sheet->GetSheetURI(getter_AddRefs(uri));
971 if (NS_FAILED(rv)) return rv;
973 if (IsChromeURI(uri)) {
974 // Reload the sheet.
975 nsCOMPtr<nsICSSStyleSheet> newSheet;
976 rv = aCSSLoader->LoadSheetSync(uri, PR_TRUE, PR_TRUE,
977 getter_AddRefs(newSheet));
978 if (NS_FAILED(rv)) return rv;
979 if (newSheet) {
980 rv = newAgentSheets.AppendObject(newSheet) ? NS_OK : NS_ERROR_FAILURE;
981 if (NS_FAILED(rv)) return rv;
984 else { // Just use the same sheet.
985 rv = newAgentSheets.AppendObject(sheet) ? NS_OK : NS_ERROR_FAILURE;
986 if (NS_FAILED(rv)) return rv;
990 rv = shell->SetAgentStyleSheets(newAgentSheets);
991 NS_ENSURE_SUCCESS(rv, rv);
994 // Build an array of nsIURIs of style sheets we need to load.
995 nsCOMArray<nsIStyleSheet> oldSheets;
996 nsCOMArray<nsIStyleSheet> newSheets;
998 PRInt32 count = document->GetNumberOfStyleSheets();
1000 // Iterate over the style sheets.
1001 PRInt32 i;
1002 for (i = 0; i < count; i++) {
1003 // Get the style sheet
1004 nsIStyleSheet *styleSheet = document->GetStyleSheetAt(i);
1006 if (!oldSheets.AppendObject(styleSheet)) {
1007 return NS_ERROR_OUT_OF_MEMORY;
1011 // Iterate over our old sheets and kick off a sync load of the new
1012 // sheet if and only if it's a chrome URL.
1013 for (i = 0; i < count; i++) {
1014 nsCOMPtr<nsICSSStyleSheet> sheet = do_QueryInterface(oldSheets[i]);
1015 nsIURI* uri = sheet ? sheet->GetOriginalURI() : nsnull;
1017 if (uri && IsChromeURI(uri)) {
1018 // Reload the sheet.
1019 nsCOMPtr<nsICSSStyleSheet> newSheet;
1020 // XXX what about chrome sheets that have a title or are disabled? This
1021 // only works by sheer dumb luck.
1022 // XXXbz this should really use the document's CSSLoader!
1023 aCSSLoader->LoadSheetSync(uri, getter_AddRefs(newSheet));
1024 // Even if it's null, we put in in there.
1025 newSheets.AppendObject(newSheet);
1027 else {
1028 // Just use the same sheet.
1029 newSheets.AppendObject(sheet);
1033 // Now notify the document that multiple sheets have been added and removed.
1034 document->UpdateStyleSheets(oldSheets, newSheets);
1035 return NS_OK;
1038 void
1039 nsChromeRegistry::FlushAllCaches()
1041 nsCOMPtr<nsIObserverService> obsSvc =
1042 do_GetService("@mozilla.org/observer-service;1");
1043 NS_ASSERTION(obsSvc, "Couldn't get observer service.");
1045 obsSvc->NotifyObservers((nsIChromeRegistry*) this,
1046 NS_CHROME_FLUSH_TOPIC, nsnull);
1049 // xxxbsmedberg Move me to nsIWindowMediator
1050 NS_IMETHODIMP
1051 nsChromeRegistry::ReloadChrome()
1053 FlushAllCaches();
1054 // Do a reload of all top level windows.
1055 nsresult rv = NS_OK;
1057 // Get the window mediator
1058 nsCOMPtr<nsIWindowMediator> windowMediator
1059 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1060 if (windowMediator) {
1061 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
1063 rv = windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
1064 if (NS_SUCCEEDED(rv)) {
1065 // Get each dom window
1066 PRBool more;
1067 rv = windowEnumerator->HasMoreElements(&more);
1068 if (NS_FAILED(rv)) return rv;
1069 while (more) {
1070 nsCOMPtr<nsISupports> protoWindow;
1071 rv = windowEnumerator->GetNext(getter_AddRefs(protoWindow));
1072 if (NS_SUCCEEDED(rv)) {
1073 nsCOMPtr<nsIDOMWindowInternal> domWindow =
1074 do_QueryInterface(protoWindow);
1075 if (domWindow) {
1076 nsCOMPtr<nsIDOMLocation> location;
1077 domWindow->GetLocation(getter_AddRefs(location));
1078 if (location) {
1079 rv = location->Reload(PR_FALSE);
1080 if (NS_FAILED(rv)) return rv;
1084 rv = windowEnumerator->HasMoreElements(&more);
1085 if (NS_FAILED(rv)) return rv;
1089 return rv;
1092 NS_IMETHODIMP
1093 nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, PRBool *aResult)
1095 nsresult rv;
1096 *aResult = PR_FALSE;
1098 #ifdef DEBUG
1099 PRBool isChrome;
1100 aChromeURI->SchemeIs("chrome", &isChrome);
1101 NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowScriptsForPackage!");
1102 #endif
1104 nsCOMPtr<nsIURL> url (do_QueryInterface(aChromeURI));
1105 NS_ENSURE_TRUE(url, NS_NOINTERFACE);
1107 nsCAutoString provider, file;
1108 rv = GetProviderAndPath(url, provider, file);
1109 NS_ENSURE_SUCCESS(rv, rv);
1111 if (!provider.EqualsLiteral("skin"))
1112 *aResult = PR_TRUE;
1114 return NS_OK;
1117 NS_IMETHODIMP
1118 nsChromeRegistry::AllowContentToAccess(nsIURI *aURI, PRBool *aResult)
1120 nsresult rv;
1122 *aResult = PR_FALSE;
1124 #ifdef DEBUG
1125 PRBool isChrome;
1126 aURI->SchemeIs("chrome", &isChrome);
1127 NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowContentToAccess!");
1128 #endif
1130 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
1131 if (!url) {
1132 NS_ERROR("Chrome URL doesn't implement nsIURL.");
1133 return NS_ERROR_UNEXPECTED;
1136 nsCAutoString package;
1137 rv = url->GetHostPort(package);
1138 NS_ENSURE_SUCCESS(rv, rv);
1140 PackageEntry *entry =
1141 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1142 & (nsACString&) package,
1143 PL_DHASH_LOOKUP));
1145 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
1146 *aResult = !!(entry->flags & PackageEntry::CONTENT_ACCESSIBLE);
1148 return NS_OK;
1151 static PLDHashOperator
1152 RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
1154 return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
1157 NS_IMETHODIMP
1158 nsChromeRegistry::CheckForNewChrome()
1160 nsresult rv;
1162 PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
1163 mOverlayHash.Clear();
1164 mStyleHash.Clear();
1165 mOverrideTable.Clear();
1167 nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
1168 NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
1170 // check the extra chrome directories
1171 nsCOMPtr<nsISimpleEnumerator> chromeML;
1172 rv = dirSvc->Get(NS_CHROME_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
1173 getter_AddRefs(chromeML));
1174 if (NS_FAILED(rv)) {
1175 // ok, then simply load all .manifest files in the app chrome dir.
1176 nsCOMPtr<nsIFile> chromeDir;
1177 rv = dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
1178 getter_AddRefs(chromeDir));
1179 if (NS_FAILED(rv))
1180 return rv;
1181 rv = NS_NewSingletonEnumerator(getter_AddRefs(chromeML), chromeDir);
1182 if (NS_FAILED(rv))
1183 return rv;
1186 PRBool exists;
1187 nsCOMPtr<nsISupports> next;
1188 while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
1189 chromeML->GetNext(getter_AddRefs(next));
1190 nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
1191 if (!lmanifest) {
1192 NS_ERROR("Directory enumerator returned a non-nsILocalFile");
1193 continue;
1196 PRBool isDir;
1197 if (NS_SUCCEEDED(lmanifest->IsDirectory(&isDir)) && isDir) {
1198 nsCOMPtr<nsISimpleEnumerator> entries;
1199 rv = lmanifest->GetDirectoryEntries(getter_AddRefs(entries));
1200 if (NS_FAILED(rv))
1201 continue;
1203 while (NS_SUCCEEDED(entries->HasMoreElements(&exists)) && exists) {
1204 entries->GetNext(getter_AddRefs(next));
1205 lmanifest = do_QueryInterface(next);
1206 if (lmanifest) {
1207 nsCAutoString leafName;
1208 lmanifest->GetNativeLeafName(leafName);
1209 if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".manifest"))) {
1210 rv = ProcessManifest(lmanifest, PR_FALSE);
1211 if (NS_FAILED(rv)) {
1212 nsCAutoString path;
1213 lmanifest->GetNativePath(path);
1214 LogMessage("Failed to process chrome manifest '%s'.",
1215 path.get());
1222 else {
1223 rv = ProcessManifest(lmanifest, PR_FALSE);
1224 if (NS_FAILED(rv)) {
1225 nsCAutoString path;
1226 lmanifest->GetNativePath(path);
1227 LogMessage("Failed to process chrome manifest: '%s'.",
1228 path.get());
1233 rv = dirSvc->Get(NS_SKIN_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
1234 getter_AddRefs(chromeML));
1235 if (NS_FAILED(rv))
1236 return NS_OK;
1238 while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
1239 chromeML->GetNext(getter_AddRefs(next));
1240 nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
1241 if (!lmanifest) {
1242 NS_ERROR("Directory enumerator returned a non-nsILocalFile");
1243 continue;
1246 rv = ProcessManifest(lmanifest, PR_TRUE);
1247 if (NS_FAILED(rv)) {
1248 nsCAutoString path;
1249 lmanifest->GetNativePath(path);
1250 LogMessage("Failed to process chrome manifest: '%s'.",
1251 path.get());
1255 return NS_OK;
1258 NS_IMETHODIMP_(PRBool)
1259 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
1261 nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
1262 if (!chromeURL)
1263 return PR_FALSE;
1265 PRBool isChrome = PR_FALSE;
1266 nsresult rv = chromeURL->SchemeIs("chrome", &isChrome);
1267 if (NS_FAILED(rv) || !isChrome)
1268 return PR_FALSE;
1270 nsCAutoString package;
1271 rv = chromeURL->GetHostPort(package);
1272 if (NS_FAILED(rv))
1273 return PR_FALSE;
1275 PackageEntry* entry =
1276 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1277 & (nsACString&) package,
1278 PL_DHASH_LOOKUP));
1280 return PL_DHASH_ENTRY_IS_LIVE(entry) &&
1281 entry->flags & PackageEntry::XPCNATIVEWRAPPERS;
1284 nsresult
1285 nsChromeRegistry::SelectLocaleFromPref(nsIPrefBranch* prefs)
1287 nsresult rv;
1288 PRBool matchOSLocale = PR_FALSE, userLocaleOverride = PR_FALSE;
1289 prefs->PrefHasUserValue(SELECTED_LOCALE_PREF, &userLocaleOverride);
1290 rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
1292 if (NS_SUCCEEDED(rv) && matchOSLocale && !userLocaleOverride) {
1293 // compute lang and region code only when needed!
1294 nsCAutoString uiLocale;
1295 rv = getUILangCountry(uiLocale);
1296 if (NS_SUCCEEDED(rv))
1297 mSelectedLocale = uiLocale;
1299 else {
1300 nsXPIDLCString provider;
1301 rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
1302 if (NS_SUCCEEDED(rv)) {
1303 mSelectedLocale = provider;
1307 return rv;
1310 NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
1312 nsresult rv = NS_OK;
1314 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
1315 nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
1316 NS_ASSERTION(prefs, "Bad observer call!");
1318 NS_ConvertUTF16toUTF8 pref(someData);
1320 if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
1321 pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
1322 rv = SelectLocaleFromPref(prefs);
1323 if (NS_SUCCEEDED(rv) && mProfileLoaded)
1324 FlushAllCaches();
1326 else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
1327 nsXPIDLCString provider;
1328 rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
1329 if (NS_FAILED(rv)) {
1330 NS_ERROR("Couldn't get new locale pref!");
1331 return rv;
1334 mSelectedSkin = provider;
1335 RefreshSkins();
1336 } else {
1337 NS_ERROR("Unexpected pref!");
1340 else if (!strcmp("command-line-startup", aTopic)) {
1341 nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
1342 if (cmdLine) {
1343 nsAutoString uiLocale;
1344 rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
1345 PR_FALSE, uiLocale);
1346 if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
1347 CopyUTF16toUTF8(uiLocale, mSelectedLocale);
1348 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
1349 if (prefs) {
1350 prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
1355 else if (!strcmp("profile-initial-state", aTopic)) {
1356 mProfileLoaded = PR_TRUE;
1358 else {
1359 NS_ERROR("Unexpected observer topic!");
1362 return rv;
1365 nsresult
1366 nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
1368 nsresult rv;
1370 PRFileDesc* fd;
1371 rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1372 NS_ENSURE_SUCCESS(rv, rv);
1374 PRInt32 n, size;
1375 char *buf;
1377 size = PR_Available(fd);
1378 if (size == -1) {
1379 rv = NS_ERROR_UNEXPECTED;
1380 goto mend;
1383 buf = (char *) malloc(size + 1);
1384 if (!buf) {
1385 rv = NS_ERROR_OUT_OF_MEMORY;
1386 goto mend;
1389 n = PR_Read(fd, buf, size);
1390 if (n > 0) {
1391 buf[size] = '\0';
1392 rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
1394 free(buf);
1396 mend:
1397 PR_Close(fd);
1398 return rv;
1401 static const char kWhitespace[] = "\t ";
1402 static const char kNewlines[] = "\r\n";
1405 * Check for a modifier flag of the following forms:
1406 * "flag" (same as "true")
1407 * "flag=yes|true|1"
1408 * "flag="no|false|0"
1409 * @param aFlag The flag to compare.
1410 * @param aData The tokenized data to check; this is lowercased
1411 * before being passed in.
1412 * @param aResult If the flag is found, the value is assigned here.
1413 * @return Whether the flag was handled.
1415 static PRBool
1416 CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
1418 if (!StringBeginsWith(aData, aFlag))
1419 return PR_FALSE;
1421 if (aFlag.Length() == aData.Length()) {
1422 // the data is simply "flag", which is the same as "flag=yes"
1423 aResult = PR_TRUE;
1424 return PR_TRUE;
1427 if (aData.CharAt(aFlag.Length()) != '=') {
1428 // the data is "flag2=", which is not anything we care about
1429 return PR_FALSE;
1432 if (aData.Length() == aFlag.Length() + 1) {
1433 aResult = PR_FALSE;
1434 return PR_TRUE;
1437 switch (aData.CharAt(aFlag.Length() + 1)) {
1438 case '1':
1439 case 't': //true
1440 case 'y': //yes
1441 aResult = PR_TRUE;
1442 return PR_TRUE;
1444 case '0':
1445 case 'f': //false
1446 case 'n': //no
1447 aResult = PR_FALSE;
1448 return PR_TRUE;
1451 return PR_FALSE;
1454 enum TriState {
1455 eUnspecified,
1456 eBad,
1461 * Check for a modifier flag of the following form:
1462 * "flag=string"
1463 * "flag!=string"
1464 * @param aFlag The flag to compare.
1465 * @param aData The tokenized data to check; this is lowercased
1466 * before being passed in.
1467 * @param aValue The value that is expected.
1468 * @param aResult If this is "ok" when passed in, this is left alone.
1469 * Otherwise if the flag is found it is set to eBad or eOK.
1470 * @return Whether the flag was handled.
1472 static PRBool
1473 CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
1474 const nsSubstring& aValue, TriState& aResult)
1476 if (aData.Length() < aFlag.Length() + 1)
1477 return PR_FALSE;
1479 if (!StringBeginsWith(aData, aFlag))
1480 return PR_FALSE;
1482 PRBool comparison = PR_TRUE;
1483 if (aData[aFlag.Length()] != '=') {
1484 if (aData[aFlag.Length()] == '!' &&
1485 aData.Length() >= aFlag.Length() + 2 &&
1486 aData[aFlag.Length() + 1] == '=')
1487 comparison = PR_FALSE;
1488 else
1489 return PR_FALSE;
1492 if (aResult != eOK) {
1493 nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
1494 if (testdata.Equals(aValue))
1495 aResult = comparison ? eOK : eBad;
1496 else
1497 aResult = comparison ? eBad : eOK;
1500 return PR_TRUE;
1504 * Check for a modifier flag of the following form:
1505 * "flag=version"
1506 * "flag<=version"
1507 * "flag<version"
1508 * "flag>=version"
1509 * "flag>version"
1510 * @param aFlag The flag to compare.
1511 * @param aData The tokenized data to check; this is lowercased
1512 * before being passed in.
1513 * @param aValue The value that is expected. If this is empty then no
1514 * comparison will match.
1515 * @param aChecker the version checker to use. If null, aResult will always
1516 * be eBad.
1517 * @param aResult If this is eOK when passed in, this is left alone.
1518 * Otherwise if the flag is found it is set to eBad or eOK.
1519 * @return Whether the flag was handled.
1522 #define COMPARE_EQ 1 << 0
1523 #define COMPARE_LT 1 << 1
1524 #define COMPARE_GT 1 << 2
1526 static PRBool
1527 CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
1528 const nsSubstring& aValue, nsIVersionComparator* aChecker,
1529 TriState& aResult)
1531 if (aData.Length() < aFlag.Length() + 2)
1532 return PR_FALSE;
1534 if (!StringBeginsWith(aData, aFlag))
1535 return PR_FALSE;
1537 if (aValue.Length() == 0) {
1538 if (aResult != eOK)
1539 aResult = eBad;
1540 return PR_TRUE;
1543 PRUint32 comparison;
1544 nsAutoString testdata;
1546 switch (aData[aFlag.Length()]) {
1547 case '=':
1548 comparison = COMPARE_EQ;
1549 testdata = Substring(aData, aFlag.Length() + 1);
1550 break;
1552 case '<':
1553 if (aData[aFlag.Length() + 1] == '=') {
1554 comparison = COMPARE_EQ | COMPARE_LT;
1555 testdata = Substring(aData, aFlag.Length() + 2);
1557 else {
1558 comparison = COMPARE_LT;
1559 testdata = Substring(aData, aFlag.Length() + 1);
1561 break;
1563 case '>':
1564 if (aData[aFlag.Length() + 1] == '=') {
1565 comparison = COMPARE_EQ | COMPARE_GT;
1566 testdata = Substring(aData, aFlag.Length() + 2);
1568 else {
1569 comparison = COMPARE_GT;
1570 testdata = Substring(aData, aFlag.Length() + 1);
1572 break;
1574 default:
1575 return PR_FALSE;
1578 if (testdata.Length() == 0)
1579 return PR_FALSE;
1581 if (aResult != eOK) {
1582 if (!aChecker) {
1583 aResult = eBad;
1585 else {
1586 PRInt32 c;
1587 nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
1588 NS_ConvertUTF16toUTF8(testdata), &c);
1589 if (NS_FAILED(rv)) {
1590 aResult = eBad;
1592 else {
1593 if ((c == 0 && comparison & COMPARE_EQ) ||
1594 (c < 0 && comparison & COMPARE_LT) ||
1595 (c > 0 && comparison & COMPARE_GT))
1596 aResult = eOK;
1597 else
1598 aResult = eBad;
1603 return PR_TRUE;
1606 static void
1607 EnsureLowerCase(char *aBuf)
1609 for (; *aBuf; ++aBuf) {
1610 char ch = *aBuf;
1611 if (ch >= 'A' && ch <= 'Z')
1612 *aBuf = ch + 'a' - 'A';
1616 nsresult
1617 nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
1618 nsILocalFile* aManifest,
1619 PRBool aSkinOnly)
1621 nsresult rv;
1623 NS_NAMED_LITERAL_STRING(kPlatform, "platform");
1624 NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
1625 NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
1626 NS_NAMED_LITERAL_STRING(kApplication, "application");
1627 NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
1628 NS_NAMED_LITERAL_STRING(kOs, "os");
1629 NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
1631 nsCOMPtr<nsIIOService> io (do_GetIOService());
1632 if (!io) return NS_ERROR_FAILURE;
1634 nsCOMPtr<nsIProtocolHandler> ph;
1635 rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
1636 NS_ENSURE_SUCCESS(rv, rv);
1638 nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
1639 if (!rph) return NS_ERROR_FAILURE;
1641 nsCOMPtr<nsIURI> manifestURI;
1642 rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
1643 NS_ENSURE_SUCCESS(rv, rv);
1645 nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
1646 nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
1648 nsAutoString appID;
1649 nsAutoString appVersion;
1650 nsAutoString osTarget;
1651 nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
1652 if (xapp) {
1653 nsCAutoString s;
1654 rv = xapp->GetID(s);
1655 if (NS_SUCCEEDED(rv))
1656 CopyUTF8toUTF16(s, appID);
1658 rv = xapp->GetVersion(s);
1659 if (NS_SUCCEEDED(rv))
1660 CopyUTF8toUTF16(s, appVersion);
1662 nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
1663 if (xruntime) {
1664 rv = xruntime->GetOS(s);
1665 if (NS_SUCCEEDED(rv)) {
1666 CopyUTF8toUTF16(s, osTarget);
1667 ToLowerCase(osTarget);
1672 nsAutoString osVersion;
1673 #if defined(XP_WIN)
1674 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
1675 if (GetVersionEx(&info)) {
1676 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
1677 info.dwMajorVersion,
1678 info.dwMinorVersion);
1680 #elif defined(XP_MACOSX)
1681 SInt32 majorVersion, minorVersion;
1682 if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
1683 (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
1684 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
1685 majorVersion,
1686 minorVersion);
1688 #elif defined(MOZ_WIDGET_GTK2)
1689 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
1690 gtk_major_version,
1691 gtk_minor_version);
1692 #endif
1694 char *token;
1695 char *newline = buf;
1696 PRUint32 line = 0;
1698 // outer loop tokenizes by newline
1699 while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
1700 ++line;
1702 if (*token == '#') // ignore lines that begin with # as comments
1703 continue;
1705 char *whitespace = token;
1706 token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1707 if (!token) continue;
1709 if (!strcmp(token, "content")) {
1710 if (aSkinOnly) {
1711 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1712 "Warning: Ignoring content registration in skin-only manifest.");
1713 continue;
1715 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1716 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1717 if (!package || !uri) {
1718 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1719 "Warning: Malformed content registration.");
1720 continue;
1723 EnsureLowerCase(package);
1725 // NOTE: We check for platform and xpcnativewrappers modifiers on
1726 // content packages, but they are *applied* to content|skin|locale.
1728 PRBool platform = PR_FALSE;
1729 PRBool xpcNativeWrappers = PR_TRUE;
1730 PRBool contentAccessible = PR_FALSE;
1731 TriState stAppVersion = eUnspecified;
1732 TriState stApp = eUnspecified;
1733 TriState stOsVersion = eUnspecified;
1734 TriState stOs = eUnspecified;
1736 PRBool badFlag = PR_FALSE;
1738 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
1739 !badFlag) {
1740 NS_ConvertASCIItoUTF16 wtoken(token);
1741 ToLowerCase(wtoken);
1743 if (CheckFlag(kPlatform, wtoken, platform) ||
1744 CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
1745 CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
1746 CheckStringFlag(kApplication, wtoken, appID, stApp) ||
1747 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
1748 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
1749 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
1750 continue;
1752 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1753 "Warning: Unrecognized chrome registration modifier '%s'.",
1754 token);
1755 badFlag = PR_TRUE;
1758 if (badFlag || stApp == eBad || stAppVersion == eBad ||
1759 stOs == eBad || stOsVersion == eBad)
1760 continue;
1762 nsCOMPtr<nsIURI> resolved;
1763 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
1764 getter_AddRefs(resolved));
1765 if (NS_FAILED(rv))
1766 continue;
1768 if (!CanLoadResource(resolved)) {
1769 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
1770 "Warning: cannot register non-local URI '%s' as content.",
1771 uri);
1772 continue;
1775 PackageEntry* entry =
1776 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1777 & (const nsACString&) nsDependentCString(package),
1778 PL_DHASH_ADD));
1779 if (!entry)
1780 return NS_ERROR_OUT_OF_MEMORY;
1782 entry->baseURI = resolved;
1784 if (platform)
1785 entry->flags |= PackageEntry::PLATFORM_PACKAGE;
1786 if (xpcNativeWrappers)
1787 entry->flags |= PackageEntry::XPCNATIVEWRAPPERS;
1788 if (contentAccessible)
1789 entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
1790 if (xpc) {
1791 nsCAutoString urlp("chrome://");
1792 urlp.Append(package);
1793 urlp.Append('/');
1795 rv = xpc->FlagSystemFilenamePrefix(urlp.get(), xpcNativeWrappers);
1796 NS_ENSURE_SUCCESS(rv, rv);
1799 else if (!strcmp(token, "locale")) {
1800 if (aSkinOnly) {
1801 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1802 "Warning: Ignoring locale registration in skin-only manifest.");
1803 continue;
1805 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1806 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1807 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1808 if (!package || !provider || !uri) {
1809 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1810 "Warning: Malformed locale registration.");
1811 continue;
1814 EnsureLowerCase(package);
1816 TriState stAppVersion = eUnspecified;
1817 TriState stApp = eUnspecified;
1818 TriState stOs = eUnspecified;
1819 TriState stOsVersion = eUnspecified;
1821 PRBool badFlag = PR_FALSE;
1823 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
1824 !badFlag) {
1825 NS_ConvertASCIItoUTF16 wtoken(token);
1826 ToLowerCase(wtoken);
1828 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
1829 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
1830 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
1831 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
1832 continue;
1834 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1835 "Warning: Unrecognized chrome registration modifier '%s'.",
1836 token);
1837 badFlag = PR_TRUE;
1840 if (badFlag || stApp == eBad || stAppVersion == eBad ||
1841 stOs == eBad || stOsVersion == eBad)
1842 continue;
1844 nsCOMPtr<nsIURI> resolved;
1845 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
1846 getter_AddRefs(resolved));
1847 if (NS_FAILED(rv))
1848 continue;
1850 if (!CanLoadResource(resolved)) {
1851 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
1852 "Warning: cannot register non-local URI '%s' as a locale.",
1853 uri);
1854 continue;
1857 PackageEntry* entry =
1858 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1859 & (const nsACString&) nsDependentCString(package),
1860 PL_DHASH_ADD));
1861 if (!entry)
1862 return NS_ERROR_OUT_OF_MEMORY;
1864 entry->locales.SetBase(nsDependentCString(provider), resolved);
1866 else if (!strcmp(token, "skin")) {
1867 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1868 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1869 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1870 if (!package || !provider || !uri) {
1871 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1872 "Warning: Malformed skin registration.");
1873 continue;
1876 EnsureLowerCase(package);
1878 TriState stAppVersion = eUnspecified;
1879 TriState stApp = eUnspecified;
1880 TriState stOs = eUnspecified;
1881 TriState stOsVersion = eUnspecified;
1883 PRBool badFlag = PR_FALSE;
1885 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
1886 !badFlag) {
1887 NS_ConvertASCIItoUTF16 wtoken(token);
1888 ToLowerCase(wtoken);
1890 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
1891 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
1892 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
1893 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
1894 continue;
1896 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1897 "Warning: Unrecognized chrome registration modifier '%s'.",
1898 token);
1899 badFlag = PR_TRUE;
1902 if (badFlag || stApp == eBad || stAppVersion == eBad ||
1903 stOs == eBad || stOsVersion == eBad)
1904 continue;
1906 nsCOMPtr<nsIURI> resolved;
1907 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
1908 getter_AddRefs(resolved));
1909 if (NS_FAILED(rv))
1910 continue;
1912 if (!CanLoadResource(resolved)) {
1913 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
1914 "Warning: cannot register non-local URI '%s' as a skin.",
1915 uri);
1916 continue;
1919 PackageEntry* entry =
1920 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1921 & (const nsACString&) nsDependentCString(package),
1922 PL_DHASH_ADD));
1923 if (!entry)
1924 return NS_ERROR_OUT_OF_MEMORY;
1926 entry->skins.SetBase(nsDependentCString(provider), resolved);
1928 else if (!strcmp(token, "overlay")) {
1929 if (aSkinOnly) {
1930 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1931 "Warning: Ignoring overlay registration in skin-only manifest.");
1932 continue;
1934 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1935 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1936 if (!base || !overlay) {
1937 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1938 "Warning: malformed chrome overlay instruction.");
1939 continue;
1942 TriState stAppVersion = eUnspecified;
1943 TriState stApp = eUnspecified;
1944 TriState stOs = eUnspecified;
1945 TriState stOsVersion = eUnspecified;
1947 PRBool badFlag = PR_FALSE;
1949 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
1950 !badFlag) {
1951 NS_ConvertASCIItoUTF16 wtoken(token);
1952 ToLowerCase(wtoken);
1954 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
1955 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
1956 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
1957 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
1958 continue;
1960 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1961 "Warning: Unrecognized chrome registration modifier '%s'.",
1962 token);
1963 badFlag = PR_TRUE;
1966 if (badFlag || stApp == eBad || stAppVersion == eBad ||
1967 stOs == eBad || stOsVersion == eBad)
1968 continue;
1970 nsCOMPtr<nsIURI> baseuri, overlayuri;
1971 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
1972 getter_AddRefs(baseuri));
1973 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
1974 getter_AddRefs(overlayuri));
1975 if (NS_FAILED(rv)) {
1976 NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
1977 continue;
1980 if (!CanLoadResource(overlayuri)) {
1981 LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
1982 "Warning: cannot register non-local URI '%s' as an overlay.",
1983 overlay);
1984 continue;
1987 mOverlayHash.Add(baseuri, overlayuri);
1989 else if (!strcmp(token, "style")) {
1990 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1991 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
1992 if (!base || !overlay) {
1993 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
1994 "Warning: malformed chrome style instruction.");
1995 continue;
1998 TriState stAppVersion = eUnspecified;
1999 TriState stApp = eUnspecified;
2000 TriState stOs = eUnspecified;
2001 TriState stOsVersion = eUnspecified;
2003 PRBool badFlag = PR_FALSE;
2005 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2006 !badFlag) {
2007 NS_ConvertASCIItoUTF16 wtoken(token);
2008 ToLowerCase(wtoken);
2010 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2011 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2012 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2013 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2014 continue;
2016 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2017 "Warning: Unrecognized chrome registration modifier '%s'.",
2018 token);
2019 badFlag = PR_TRUE;
2022 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2023 stOs == eBad || stOsVersion == eBad)
2024 continue;
2026 nsCOMPtr<nsIURI> baseuri, overlayuri;
2027 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2028 getter_AddRefs(baseuri));
2029 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2030 getter_AddRefs(overlayuri));
2031 if (NS_FAILED(rv))
2032 continue;
2034 if (!CanLoadResource(overlayuri)) {
2035 LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
2036 "Warning: cannot register non-local URI '%s' as a style overlay.",
2037 overlay);
2038 continue;
2041 mStyleHash.Add(baseuri, overlayuri);
2043 else if (!strcmp(token, "override")) {
2044 if (aSkinOnly) {
2045 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2046 "Warning: Ignoring override registration in skin-only manifest.");
2047 continue;
2050 char *chrome = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2051 char *resolved = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2052 if (!chrome || !resolved) {
2053 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2054 "Warning: malformed chrome override instruction.");
2055 continue;
2058 TriState stAppVersion = eUnspecified;
2059 TriState stApp = eUnspecified;
2060 TriState stOs = eUnspecified;
2061 TriState stOsVersion = eUnspecified;
2063 PRBool badFlag = PR_FALSE;
2065 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2066 !badFlag) {
2067 NS_ConvertASCIItoUTF16 wtoken(token);
2068 ToLowerCase(wtoken);
2070 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2071 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2072 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2073 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2074 continue;
2076 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2077 "Warning: Unrecognized chrome registration modifier '%s'.",
2078 token);
2079 badFlag = PR_TRUE;
2082 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2083 stOs == eBad || stOsVersion == eBad)
2084 continue;
2086 nsCOMPtr<nsIURI> chromeuri, resolveduri;
2087 rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
2088 getter_AddRefs(chromeuri));
2089 rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
2090 getter_AddRefs(resolveduri));
2091 if (NS_FAILED(rv))
2092 continue;
2094 if (!CanLoadResource(resolveduri)) {
2095 LogMessageWithContext(resolveduri, line, nsIScriptError::warningFlag,
2096 "Warning: cannot register non-local URI '%s' as an override.",
2097 resolved);
2098 continue;
2101 mOverrideTable.Put(chromeuri, resolveduri);
2103 else if (!strcmp(token, "resource")) {
2104 if (aSkinOnly) {
2105 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2106 "Warning: Ignoring resource registration in skin-only manifest.");
2107 continue;
2110 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2111 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2112 if (!package || !uri) {
2113 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2114 "Warning: Malformed resource registration.");
2115 continue;
2118 EnsureLowerCase(package);
2120 TriState stAppVersion = eUnspecified;
2121 TriState stApp = eUnspecified;
2122 TriState stOsVersion = eUnspecified;
2123 TriState stOs = eUnspecified;
2125 PRBool badFlag = PR_FALSE;
2127 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2128 !badFlag) {
2129 NS_ConvertASCIItoUTF16 wtoken(token);
2130 ToLowerCase(wtoken);
2132 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2133 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2134 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2135 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2136 continue;
2138 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2139 "Warning: Unrecognized chrome registration modifier '%s'.",
2140 token);
2141 badFlag = PR_TRUE;
2144 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2145 stOs == eBad || stOsVersion == eBad)
2146 continue;
2148 nsDependentCString host(package);
2150 PRBool exists;
2151 rv = rph->HasSubstitution(host, &exists);
2152 NS_ENSURE_SUCCESS(rv, rv);
2153 if (exists) {
2154 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2155 "Warning: Duplicate resource declaration for '%s' ignored.",
2156 package);
2157 continue;
2160 nsCOMPtr<nsIURI> resolved;
2161 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2162 getter_AddRefs(resolved));
2163 if (NS_FAILED(rv))
2164 continue;
2166 if (!CanLoadResource(resolved)) {
2167 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
2168 "Warning: cannot register non-local URI '%s' as a resource.",
2169 uri);
2170 continue;
2173 rv = rph->SetSubstitution(host, resolved);
2174 NS_ENSURE_SUCCESS(rv, rv);
2176 else {
2177 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2178 "Warning: Ignoring unrecognized chrome manifest instruction.");
2182 return NS_OK;