Bug 542907 - "e10s: Chrome registry should be unified between parent and child" [r=benjamin]
authorJosh Matthews <josh>
Thu, 11 Mar 2010 18:33:00 +1300
changeset 46751 38e4a1494075499de239f9dbac21e40b6fecb011
parent 46750 ce1f9da9f83e1319d0850f5308dd3089b1a763f6
child 46752 2e3c323495c2501f4580386479252f53bdc32cc3
push id14210
push userdougt@mozilla.com
push dateThu, 01 Jul 2010 06:28:42 +0000
treeherdermozilla-central@3aff97777291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbenjamin
bugs542907
milestone1.9.3a4pre
Bug 542907 - "e10s: Chrome registry should be unified between parent and child" [r=benjamin]
chrome/src/Makefile.in
chrome/src/RegistryMessageUtils.h
chrome/src/nsChromeFactory.cpp
chrome/src/nsChromeRegistry.cpp
chrome/src/nsChromeRegistry.h
chrome/src/nsChromeRegistryChrome.cpp
chrome/src/nsChromeRegistryChrome.h
chrome/src/nsChromeRegistryContent.cpp
chrome/src/nsChromeRegistryContent.h
chrome/test/Makefile.in
chrome/test/unit/data/test_resolve_uris.manifest
chrome/test/unit/test_resolve_uris.js
chrome/test/unit_ipc/test_resolve_uris_ipc.js
dom/ipc/ContentProcessChild.cpp
dom/ipc/ContentProcessChild.h
dom/ipc/ContentProcessParent.cpp
dom/ipc/Makefile.in
dom/ipc/PContentProcess.ipdl
netwerk/protocol/res/src/Makefile.in
netwerk/protocol/res/src/nsResProtocolHandler.cpp
netwerk/protocol/res/src/nsResProtocolHandler.h
--- a/chrome/src/Makefile.in
+++ b/chrome/src/Makefile.in
@@ -45,34 +45,51 @@ include $(DEPTH)/config/autoconf.mk
 MODULE          = chrome
 LIBRARY_NAME    = chrome
 EXPORT_LIBRARY = 1
 IS_COMPONENT    = 1
 MODULE_NAME     = nsChromeModule
 GRE_MODULE      = 1
 LIBXUL_LIBRARY  = 1
 
+EXPORTS_NAMESPACES = mozilla/chrome
+
+EXPORTS_mozilla/chrome = \
+		RegistryMessageUtils.h \
+		$(NULL)
 
 CPPSRCS		= \
 		nsChromeFactory.cpp \
 		nsChromeRegistry.cpp \
+		nsChromeRegistryChrome.cpp \
 		nsChromeProtocolHandler.cpp \
 		$(NULL)
 
+ifdef MOZ_IPC
+CPPSRCS += nsChromeRegistryContent.cpp
+endif
+
 EXTRA_DSO_LDOPTS = \
                 $(MOZ_UNICHARUTIL_LIBS) \
                 $(MOZ_COMPONENT_LIBS) \
                 $(NULL)
 
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 EXTRA_DSO_LDOPTS += $(MOZ_GTK2_LIBS)
 endif
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 EXTRA_DSO_LDOPTS += $(TK_LIBS)
 endif
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
+LOCAL_INCLUDES += \
+		-I$(topsrcdir)/netwerk/protocol/res/src \
+		-I$(topsrcdir)/netwerk/base/src \
+		$(NULL)
+
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS          += $(MOZ_GTK2_CFLAGS)
 endif
 
new file mode 100644
--- /dev/null
+++ b/chrome/src/RegistryMessageUtils.h
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Initial Developer)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_RegistryMessageUtils_h
+#define mozilla_RegistryMessageUtils_h
+
+#include "IPC/IPCMessageUtils.h"
+#include "nsStringGlue.h"
+
+struct SerializedURI
+{
+  nsCString spec;
+  nsCString charset;
+};
+
+struct ChromePackage
+{
+  nsCString package;
+  SerializedURI contentBaseURI;
+  SerializedURI localeBaseURI;
+  SerializedURI skinBaseURI;
+  PRUint32 flags;
+};
+
+struct ResourceMapping
+{
+  nsCString resource;
+  SerializedURI resolvedURI;
+};
+
+struct OverrideMapping
+{
+  SerializedURI originalURI;
+  SerializedURI overrideURI;
+};
+
+namespace IPC {
+
+template<>
+struct ParamTraits<SerializedURI>
+{
+  typedef SerializedURI paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.spec);
+    WriteParam(aMsg, aParam.charset);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    nsCString spec, charset;
+    if (ReadParam(aMsg, aIter, &spec) &&
+        ReadParam(aMsg, aIter, &charset)) {
+      aResult->spec = spec;
+      aResult->charset = charset;
+      return true;
+    }
+    return false;
+  }
+};
+  
+template <>
+struct ParamTraits<ChromePackage>
+{
+  typedef ChromePackage paramType;
+  
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.package);
+    WriteParam(aMsg, aParam.contentBaseURI);
+    WriteParam(aMsg, aParam.localeBaseURI);
+    WriteParam(aMsg, aParam.skinBaseURI);
+    WriteParam(aMsg, aParam.flags);
+  }
+  
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    nsCString package;
+    SerializedURI contentBaseURI, localeBaseURI, skinBaseURI;
+    PRUint32 flags;
+    
+    if (ReadParam(aMsg, aIter, &package) &&
+        ReadParam(aMsg, aIter, &contentBaseURI) &&
+        ReadParam(aMsg, aIter, &localeBaseURI) &&
+        ReadParam(aMsg, aIter, &skinBaseURI) &&
+        ReadParam(aMsg, aIter, &flags)) {
+      aResult->package = package;
+      aResult->contentBaseURI = contentBaseURI;
+      aResult->localeBaseURI = localeBaseURI;
+      aResult->skinBaseURI = skinBaseURI;
+      aResult->flags = flags;
+      return true;
+    }
+    return false;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    aLog->append(StringPrintf(L"[%s, %s, %s, %s, %u]", aParam.package.get(),
+                             aParam.contentBaseURI.spec.get(),
+                             aParam.localeBaseURI.spec.get(),
+                             aParam.skinBaseURI.spec.get(), aParam.flags));
+  }
+};
+
+template <>
+struct ParamTraits<ResourceMapping>
+{
+  typedef ResourceMapping paramType;
+  
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.resource);
+    WriteParam(aMsg, aParam.resolvedURI);
+  }
+  
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    nsCString resource;
+    SerializedURI resolvedURI;
+    
+    if (ReadParam(aMsg, aIter, &resource) &&
+        ReadParam(aMsg, aIter, &resolvedURI)) {
+      aResult->resource = resource;
+      aResult->resolvedURI = resolvedURI;
+      return true;
+    }
+    return false;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    aLog->append(StringPrintf(L"[%s, %s, %u]", aParam.resource.get(),
+                             aParam.resolvedURI.spec.get()));
+  }
+};
+
+template <>
+struct ParamTraits<OverrideMapping>
+{
+  typedef OverrideMapping paramType;
+  
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.originalURI);
+    WriteParam(aMsg, aParam.overrideURI);
+  }
+  
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    SerializedURI originalURI;
+    SerializedURI overrideURI;
+    
+    if (ReadParam(aMsg, aIter, &originalURI) &&
+        ReadParam(aMsg, aIter, &overrideURI)) {
+      aResult->originalURI = originalURI;
+      aResult->overrideURI = overrideURI;
+      return true;
+    }
+    return false;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    aLog->append(StringPrintf(L"[%s, %s, %u]", aParam.originalURI.spec.get(),
+                             aParam.overrideURI.spec.get()));
+  }
+};
+
+}
+
+#endif // RegistryMessageUtils_h
--- a/chrome/src/nsChromeFactory.cpp
+++ b/chrome/src/nsChromeFactory.cpp
@@ -40,18 +40,47 @@
 #include "nsIGenericFactory.h"
 
 #include "nsIServiceManager.h"
 #include "nsIComponentManager.h"
 #include "nsIChromeRegistry.h"
 #include "nscore.h"
 #include "nsChromeProtocolHandler.h"
 #include "nsChromeRegistry.h"
+#include "nsChromeRegistryChrome.h"
 
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsChromeRegistry, Init)
+#ifdef MOZ_IPC
+#include "nsXULAppAPI.h"
+#include "nsChromeRegistryContent.h"
+#endif
+
+static nsChromeRegistry* GetSingleton()
+{
+    nsChromeRegistry* chromeRegistry = nsChromeRegistry::gChromeRegistry;
+    if (chromeRegistry) {
+        NS_ADDREF(chromeRegistry);
+        return chromeRegistry;
+    }
+    
+#ifdef MOZ_IPC
+    if (XRE_GetProcessType() == GeckoProcessType_Content)
+        chromeRegistry = new nsChromeRegistryContent;
+#endif
+    if (!chromeRegistry)
+        chromeRegistry = new nsChromeRegistryChrome;
+
+    if (chromeRegistry) {
+        NS_ADDREF(chromeRegistry);
+        if (NS_FAILED(chromeRegistry->Init()))
+            NS_RELEASE(chromeRegistry);
+    }
+    return chromeRegistry;
+}
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsChromeRegistry, GetSingleton);
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsChromeProtocolHandler)
 
 // The list of components we register
 static const nsModuleComponentInfo components[] = 
 {
     { "Chrome Registry", 
       NS_CHROMEREGISTRY_CID,
       NS_CHROMEREGISTRY_CONTRACTID, 
--- a/chrome/src/nsChromeRegistry.cpp
+++ b/chrome/src/nsChromeRegistry.cpp
@@ -40,97 +40,48 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsChromeRegistry.h"
 
 #include <string.h>
 
 #include "prio.h"
 #include "prprf.h"
-#if defined(XP_WIN)
-#include <windows.h>
-#elif defined(XP_MACOSX)
-#include <CoreServices/CoreServices.h>
-#elif defined(MOZ_WIDGET_GTK2)
-#include <gtk/gtk.h>
-#endif
 
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsArrayEnumerator.h"
-#include "nsStringEnumerator.h"
-#include "nsEnumeratorUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDOMError.h"
 #include "nsEscape.h"
-#include "nsInt64.h"
 #include "nsLayoutCID.h"
-#include "nsNetCID.h"
 #include "nsNetUtil.h"
-#include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
-#include "nsWidgetsCID.h"
-#include "nsXPCOMCIDInternal.h"
-#include "nsXPIDLString.h"
-#include "nsXULAppAPI.h"
-#include "nsTextFormatter.h"
 
-#include "nsIAtom.h"
-#include "nsICommandLine.h"
 #include "nsICSSStyleSheet.h"
 #include "nsIConsoleService.h"
-#include "nsIDirectoryService.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocShell.h"
-#include "nsIDocumentObserver.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMLocation.h"
 #include "nsIDOMWindowCollection.h"
 #include "nsIDOMWindowInternal.h"
-#include "nsIFileChannel.h"
-#include "nsIFileURL.h"
 #include "nsIIOService.h"
 #include "nsIJARProtocolHandler.h"
-#include "nsIJARURI.h"
-#include "nsILocalFile.h"
-#include "nsILocaleService.h"
-#include "nsILookAndFeel.h"
 #include "nsIObserverService.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
-#include "nsIPrefBranch2.h"
 #include "nsIPresShell.h"
 #include "nsIProtocolHandler.h"
-#include "nsIResProtocolHandler.h"
 #include "nsIScriptError.h"
-#include "nsIServiceManager.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIStyleSheet.h"
-#include "nsISupportsArray.h"
-#include "nsIVersionComparator.h"
 #include "nsIWindowMediator.h"
-#include "nsIXPConnect.h"
-#include "nsIXULAppInfo.h"
-#include "nsIXULRuntime.h"
-
-#define UILOCALE_CMD_LINE_ARG "UILocale"
-
-#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
-#define SELECTED_LOCALE_PREF "general.useragent.locale"
-#define SELECTED_SKIN_PREF   "general.skins.selectedSkin"
-
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static void
-LogMessage(const char* aMsg, ...)
+void
+nsChromeRegistry::LogMessage(const char* aMsg, ...)
 {
   nsCOMPtr<nsIConsoleService> console 
     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!console)
     return;
 
   va_list args;
   va_start(args, aMsg);
@@ -138,19 +89,19 @@ LogMessage(const char* aMsg, ...)
   va_end(args);
   if (!formatted)
     return;
 
   console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
   PR_smprintf_free(formatted);
 }
 
-static void
-LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
-                      const char* aMsg, ...)
+void
+nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
+                                        const char* aMsg, ...)
 {
   nsresult rv;
 
   nsCOMPtr<nsIConsoleService> console 
     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
 
   nsCOMPtr<nsIScriptError> error
     (do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
@@ -175,252 +126,18 @@ LogMessageWithContext(nsIURI* aURL, PRUi
   PR_smprintf_free(formatted);
 
   if (NS_FAILED(rv))
     return;
 
   console->LogMessage(error);
 }
 
-// We use a "best-fit" algorithm for matching locales and themes. 
-// 1) the exact selected locale/theme
-// 2) (locales only) same language, different country
-//    e.g. en-GB is the selected locale, only en-US is available
-// 3) any available locale/theme
-
-/**
- * Match the language-part of two lang-COUNTRY codes, hopefully but
- * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
- * work, any other garbage-in will produce undefined results as long
- * as it does not crash.
- */
-static PRBool
-LanguagesMatch(const nsACString& a, const nsACString& b)
-{
-  if (a.Length() < 2 || b.Length() < 2)
-    return PR_FALSE;
-
-  nsACString::const_iterator as, ae, bs, be;
-  a.BeginReading(as);
-  a.EndReading(ae);
-  b.BeginReading(bs);
-  b.EndReading(be);
-
-  while (*as == *bs) {
-    if (*as == '-')
-      return PR_TRUE;
- 
-    ++as; ++bs;
-
-    // reached the end
-    if (as == ae && bs == be)
-      return PR_TRUE;
-
-    // "a" is short
-    if (as == ae)
-      return (*bs == '-');
-
-    // "b" is short
-    if (bs == be)
-      return (*as == '-');
-  }
-
-  return PR_FALSE;
-}
-
-static PRBool
-CanLoadResource(nsIURI* aResourceURI)
-{
-  PRBool isLocalResource = PR_FALSE;
-  (void)NS_URIChainHasFlags(aResourceURI,
-                            nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
-                            &isLocalResource);
-  return isLocalResource;
-}
-
-nsChromeRegistry::ProviderEntry*
-nsChromeRegistry::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
-{
-  PRInt32 i = mArray.Count();
-  if (!i)
-    return nsnull;
-
-  ProviderEntry* found = nsnull;  // Only set if we find a partial-match locale
-  ProviderEntry* entry;
-
-  while (i--) {
-    entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
-    if (aPreferred.Equals(entry->provider))
-      return entry;
-
-    if (aType != LOCALE)
-      continue;
-
-    if (LanguagesMatch(aPreferred, entry->provider)) {
-      found = entry;
-      continue;
-    }
-
-    if (!found && entry->provider.EqualsLiteral("en-US"))
-      found = entry;
-  }
-
-  if (!found && aType != EXACT)
-    return entry;
-
-  return found;
-}
-
-nsIURI*
-nsChromeRegistry::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
-{
-  ProviderEntry* provider = GetProvider(aPreferred, aType);
-
-  if (!provider)
-    return nsnull;
-
-  return provider->baseURI;
-}
-
-const nsACString&
-nsChromeRegistry::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
-{
-  ProviderEntry* entry = GetProvider(aPreferred, aType);
-
-  if (entry)
-    return entry->provider;
-
-  return EmptyCString();
-}
-
-void
-nsChromeRegistry::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
-{
-  ProviderEntry* provider = GetProvider(aProvider, EXACT);
-
-  if (provider) {
-    provider->baseURI = aBaseURL;
-    return;
-  }
-
-  // no existing entries, add a new one
-  provider = new ProviderEntry(aProvider, aBaseURL);
-  if (!provider)
-    return; // It's safe to silently fail on OOM
-
-  mArray.AppendElement(provider);
-}
-
-void
-nsChromeRegistry::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
-{
-  PRInt32 i = mArray.Count();
-  while (i--) {
-    ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
-    a->AppendElement(entry->provider);
-  }
-}
-
-void
-nsChromeRegistry::nsProviderArray::Clear()
-{
-  PRInt32 i = mArray.Count();
-  while (i--) {
-    ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
-    delete entry;
-  }
-
-  mArray.Clear();
-}
-
-nsChromeRegistry::PackageEntry::PackageEntry(const nsACString& aPackage) :
-  package(aPackage), flags(0)
-{
-}
-
-PLHashNumber
-nsChromeRegistry::HashKey(PLDHashTable *table, const void *key)
-{
-  const nsACString& str = *reinterpret_cast<const nsACString*>(key);
-  return HashString(str);
-}
-
-PRBool
-nsChromeRegistry::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
-                           const void *key)
-{
-  const nsACString& str = *reinterpret_cast<const nsACString*>(key);
-  const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
-  return str.Equals(pentry->package);
-}
-
-void
-nsChromeRegistry::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
-{
-  PackageEntry* pentry = static_cast<PackageEntry*>(entry);
-  pentry->~PackageEntry();
-}
-
-PRBool
-nsChromeRegistry::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
-                            const void *key)
-{
-  const nsACString& str = *reinterpret_cast<const nsACString*>(key);
-
-  new (entry) PackageEntry(str);
-  return PR_TRUE;
-}
-
-const PLDHashTableOps
-nsChromeRegistry::kTableOps = {
-  PL_DHashAllocTable,
-  PL_DHashFreeTable,
-  HashKey,
-  MatchKey,
-  PL_DHashMoveEntryStub,
-  ClearEntry,
-  PL_DHashFinalizeStub,
-  InitEntry
-};
-
-void
-nsChromeRegistry::OverlayListEntry::AddURI(nsIURI* aURI)
-{
-  PRInt32 i = mArray.Count();
-  while (i--) {
-    PRBool equals;
-    if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
-        return;
-  }
-
-  mArray.AppendObject(aURI);
-}
-
-void
-nsChromeRegistry::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
-{
-  OverlayListEntry* entry = mTable.PutEntry(aBase);
-  if (entry)
-    entry->AddURI(aOverlay);
-}
-
-const nsCOMArray<nsIURI>*
-nsChromeRegistry::OverlayListHash::GetArray(nsIURI* aBase)
-{
-  OverlayListEntry* entry = mTable.GetEntry(aBase);
-  if (!entry)
-    return nsnull;
-
-  return &entry->mArray;
-}
-
 nsChromeRegistry::~nsChromeRegistry()
 {
-  if (mPackagesHash.ops)
-    PL_DHashTableFinish(&mPackagesHash);
   gChromeRegistry = nsnull;
 }
 
 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
   NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
   NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
   NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
 #ifdef MOZ_XUL
@@ -432,30 +149,30 @@ NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsChromeRegistry)
 NS_IMPL_RELEASE(nsChromeRegistry)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIChromeRegistry methods:
 
-static nsresult
-getUILangCountry(nsACString& aUILang)
+already_AddRefed<nsIChromeRegistry>
+nsChromeRegistry::GetService()
 {
-  nsresult rv;
-
-  nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString uiLang;
-  rv = localeService->GetLocaleComponentForUserAgent(uiLang);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  CopyUTF16toUTF8(uiLang, aUILang);
-  return NS_OK;
+  if (!nsChromeRegistry::gChromeRegistry)
+  {
+    // We don't actually want this ref, we just want the service to
+    // initialize if it hasn't already.
+    nsCOMPtr<nsIChromeRegistry> reg(
+        do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
+    if (!gChromeRegistry)
+      return NULL;
+  }
+  NS_IF_ADDREF(gChromeRegistry);
+  return gChromeRegistry;
 }
 
 nsresult
 nsChromeRegistry::Init()
 {
   nsresult rv;
 
   // Check to see if necko and the JAR protocol handler are registered yet
@@ -469,108 +186,30 @@ nsChromeRegistry::Init()
   nsCOMPtr<nsIProtocolHandler> ph;
   rv = io->GetProtocolHandler("jar", getter_AddRefs(ph));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIJARProtocolHandler> jph = do_QueryInterface(ph);
   if (!jph)
     return NS_ERROR_NOT_INITIALIZED;
 
-  if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
-                         nsnull, sizeof(PackageEntry), 16))
+  if (!mOverrideTable.Init())
     return NS_ERROR_FAILURE;
 
-  if (!mOverlayHash.Init() ||
-      !mStyleHash.Init() ||
-      !mOverrideTable.Init())
-    return NS_ERROR_FAILURE;
-
-  mSelectedLocale = NS_LITERAL_CSTRING("en-US");
-  mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
-
   // This initialization process is fairly complicated and may cause reentrant
   // getservice calls to resolve chrome URIs (especially locale files). We
   // don't want that, so we inform the protocol handler about our existence
   // before we are actually fully initialized.
   gChromeRegistry = this;
 
-  PRBool safeMode = PR_FALSE;
-  nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
-  if (xulrun)
-    xulrun->GetInSafeMode(&safeMode);
-  
-  nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
-  nsCOMPtr<nsIPrefBranch> prefs;
-
-  if (safeMode)
-    prefserv->GetDefaultBranch(nsnull, getter_AddRefs(prefs));
-  else
-    prefs = do_QueryInterface(prefserv);
-
-  if (!prefs) {
-    NS_WARNING("Could not get pref service!");
-  }
-  else {
-    nsXPIDLCString provider;
-    rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
-    if (NS_SUCCEEDED(rv))
-      mSelectedSkin = provider;
-
-    SelectLocaleFromPref(prefs);
-
-    nsCOMPtr<nsIPrefBranch2> prefs2 (do_QueryInterface(prefs));
-    if (prefs2) {
-      rv = prefs2->AddObserver(MATCH_OS_LOCALE_PREF, this, PR_TRUE);
-      rv = prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
-      rv = prefs2->AddObserver(SELECTED_SKIN_PREF, this, PR_TRUE);
-    }
-  }
-
-  nsCOMPtr<nsIObserverService> obsService (do_GetService("@mozilla.org/observer-service;1"));
-  if (obsService) {
-    obsService->AddObserver(this, "command-line-startup", PR_TRUE);
-    obsService->AddObserver(this, "profile-initial-state", PR_TRUE);
-  }
-
-  CheckForNewChrome();
-
   mInitialized = PR_TRUE;
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsChromeRegistry::CheckForOSAccessibility()
-{
-  nsresult rv;
-
-  nsCOMPtr<nsILookAndFeel> lookAndFeel (do_GetService(kLookAndFeelCID));
-  if (lookAndFeel) {
-    PRInt32 useAccessibilityTheme = 0;
-
-    rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_UseAccessibilityTheme,
-                                useAccessibilityTheme);
-
-    if (NS_SUCCEEDED(rv) && useAccessibilityTheme) {
-      /* Set the skin to classic and remove pref observers */
-      if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
-        mSelectedSkin.AssignLiteral("classic/1.0");
-        RefreshSkins();
-      }
-
-      nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
-      if (prefs) {
-        prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
 nsresult
 nsChromeRegistry::GetProviderAndPath(nsIURL* aChromeURL,
                                      nsACString& aProvider, nsACString& aPath)
 {
   nsresult rv;
 
 #ifdef DEBUG
   PRBool isChrome;
@@ -692,157 +331,44 @@ nsChromeRegistry::ConvertChromeURL(nsIUR
 
   nsCAutoString package, provider, path;
   rv = chromeURL->GetHostPort(package);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = GetProviderAndPath(chromeURL, provider, path);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  PackageEntry* entry =
-    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                    & (nsACString&) package,
-                                                    PL_DHASH_LOOKUP));
+  nsIURI* baseURI;
+  rv = GetBaseURIFromPackage(package, provider, path, &baseURI);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if (PL_DHASH_ENTRY_IS_FREE(entry)) {
-    if (!mInitialized)
-      return NS_ERROR_NOT_INITIALIZED;
+  PRUint32 flags;
+  rv = GetFlagsFromPackage(package, &flags);
+  if (NS_FAILED(rv))
+    return rv;
 
-    LogMessage("No chrome package registered for chrome://%s/%s/%s",
-               package.get(), provider.get(), path.get());
-
-    return NS_ERROR_FAILURE;
-  }
-
-  if (entry->flags & PackageEntry::PLATFORM_PACKAGE) {
+  if (flags & PLATFORM_PACKAGE) {
 #if defined(XP_WIN) || defined(XP_OS2)
     path.Insert("win/", 0);
 #elif defined(XP_MACOSX)
     path.Insert("mac/", 0);
 #else
     path.Insert("unix/", 0);
 #endif
   }
 
-  nsIURI* baseURI = nsnull;
-  if (provider.EqualsLiteral("locale")) {
-    baseURI = entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
-  }
-  else if (provider.EqualsLiteral("skin")) {
-    baseURI = entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
-  }
-  else if (provider.EqualsLiteral("content")) {
-    baseURI = entry->baseURI;
-  }
-
   if (!baseURI) {
     LogMessage("No chrome package registered for chrome://%s/%s/%s",
                package.get(), provider.get(), path.get());
     return NS_ERROR_FAILURE;
   }
 
   return NS_NewURI(aResult, path, nsnull, baseURI);
 }
 
-nsresult
-nsChromeRegistry::GetSelectedLocale(const nsACString& aPackage, nsACString& aLocale)
-{
-  PackageEntry* entry =
-    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                       & aPackage,
-                                                       PL_DHASH_LOOKUP));
-
-  if (PL_DHASH_ENTRY_IS_FREE(entry))
-    return NS_ERROR_FAILURE;
-
-  aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
-  if (aLocale.IsEmpty())
-    return NS_ERROR_FAILURE;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsChromeRegistry::IsLocaleRTL(const nsACString& package, PRBool *aResult)
-{
-  *aResult = PR_FALSE;
-
-  nsCAutoString locale;
-  GetSelectedLocale(package, locale);
-  if (locale.Length() < 2)
-    return NS_OK;
-
-  // first check the intl.uidirection.<locale> preference, and if that is not
-  // set, check the same preference but with just the first two characters of
-  // the locale. If that isn't set, default to left-to-right.
-  nsCAutoString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + locale;
-  nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (!prefBranch)
-    return NS_OK;
-  
-  nsXPIDLCString dir;
-  prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
-  if (dir.IsEmpty()) {
-    PRInt32 hyphen = prefString.FindChar('-');
-    if (hyphen >= 1) {
-      nsCAutoString shortPref(Substring(prefString, 0, hyphen));
-      prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
-    }
-  }
-  *aResult = dir.EqualsLiteral("rtl");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsChromeRegistry::GetLocalesForPackage(const nsACString& aPackage,
-                                       nsIUTF8StringEnumerator* *aResult)
-{
-  nsTArray<nsCString> *a = new nsTArray<nsCString>;
-  if (!a)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  PackageEntry* entry =
-    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                       & aPackage,
-                                                       PL_DHASH_LOOKUP));
-
-  if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
-    entry->locales.EnumerateToArray(a);
-  }
-
-  nsresult rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
-  if (NS_FAILED(rv))
-    delete a;
-
-  return rv;
-}
-
-#ifdef MOZ_XUL
-NS_IMETHODIMP
-nsChromeRegistry::GetStyleOverlays(nsIURI *aChromeURL,
-                                   nsISimpleEnumerator **aResult)
-{
-  const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
-  if (!parray)
-    return NS_NewEmptyEnumerator(aResult);
-
-  return NS_NewArrayEnumerator(aResult, *parray);
-}
-
-NS_IMETHODIMP
-nsChromeRegistry::GetXULOverlays(nsIURI *aChromeURL, nsISimpleEnumerator **aResult)
-{
-  const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
-  if (!parray)
-    return NS_NewEmptyEnumerator(aResult);
-
-  return NS_NewArrayEnumerator(aResult, *parray);
-}
-#endif // MOZ_XUL
-
 ////////////////////////////////////////////////////////////////////////
 
 // theme stuff
 
 
 static void FlushSkinBindingsForWindow(nsIDOMWindowInternal* aWindow)
 {
   // Get the DOM document.
@@ -1123,131 +649,22 @@ nsChromeRegistry::AllowContentToAccess(n
     NS_ERROR("Chrome URL doesn't implement nsIURL.");
     return NS_ERROR_UNEXPECTED;
   }
 
   nsCAutoString package;
   rv = url->GetHostPort(package);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  PackageEntry *entry =
-    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                    & (nsACString&) package,
-                                                    PL_DHASH_LOOKUP));
-
-  if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
-    *aResult = !!(entry->flags & PackageEntry::CONTENT_ACCESSIBLE);
-  }
-  return NS_OK;
-}
-
-static PLDHashOperator
-RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
-{
-  return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
-}
-
-NS_IMETHODIMP
-nsChromeRegistry::CheckForNewChrome()
-{
-  nsresult rv;
-
-  PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
-  mOverlayHash.Clear();
-  mStyleHash.Clear();
-  mOverrideTable.Clear();
-
-  nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
-  NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
-
-  // check the extra chrome directories
-  nsCOMPtr<nsISimpleEnumerator> chromeML;
-  rv = dirSvc->Get(NS_CHROME_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
-                   getter_AddRefs(chromeML));
-  if (NS_FAILED(rv)) {
-    // ok, then simply load all .manifest files in the app chrome dir.
-    nsCOMPtr<nsIFile> chromeDir;
-    rv = dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
-                     getter_AddRefs(chromeDir));
-    if (NS_FAILED(rv))
-      return rv;
-    rv = NS_NewSingletonEnumerator(getter_AddRefs(chromeML), chromeDir);
-    if (NS_FAILED(rv))
-      return rv;
-  }
-
-  PRBool exists;
-  nsCOMPtr<nsISupports> next;
-  while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
-    chromeML->GetNext(getter_AddRefs(next));
-    nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
-    if (!lmanifest) {
-      NS_ERROR("Directory enumerator returned a non-nsILocalFile");
-      continue;
-    }
+  PRUint32 flags;
+  rv = GetFlagsFromPackage(package, &flags);
 
-    PRBool isDir;
-    if (NS_SUCCEEDED(lmanifest->IsDirectory(&isDir)) && isDir) {
-      nsCOMPtr<nsISimpleEnumerator> entries;
-      rv = lmanifest->GetDirectoryEntries(getter_AddRefs(entries));
-      if (NS_FAILED(rv))
-        continue;
-
-      while (NS_SUCCEEDED(entries->HasMoreElements(&exists)) && exists) {
-        entries->GetNext(getter_AddRefs(next));
-        lmanifest = do_QueryInterface(next);
-        if (lmanifest) {
-          nsCAutoString leafName;
-          lmanifest->GetNativeLeafName(leafName);
-          if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".manifest"))) {
-            rv = ProcessManifest(lmanifest, PR_FALSE);
-            if (NS_FAILED(rv)) {
-              nsCAutoString path;
-              lmanifest->GetNativePath(path);
-              LogMessage("Failed to process chrome manifest '%s'.",
-                         path.get());
-
-            }
-          }
-        }
-      }
-    }
-    else {
-      rv = ProcessManifest(lmanifest, PR_FALSE);
-      if (NS_FAILED(rv)) {
-        nsCAutoString path;
-        lmanifest->GetNativePath(path);
-        LogMessage("Failed to process chrome manifest: '%s'.",
-                   path.get());
-      }
-    }
+  if (NS_SUCCEEDED(rv)) {
+    *aResult = !!(flags & CONTENT_ACCESSIBLE);
   }
-
-  rv = dirSvc->Get(NS_SKIN_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
-                   getter_AddRefs(chromeML));
-  if (NS_FAILED(rv))
-    return NS_OK;
-
-  while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
-    chromeML->GetNext(getter_AddRefs(next));
-    nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
-    if (!lmanifest) {
-      NS_ERROR("Directory enumerator returned a non-nsILocalFile");
-      continue;
-    }
-
-    rv = ProcessManifest(lmanifest, PR_TRUE);
-    if (NS_FAILED(rv)) {
-      nsCAutoString path;
-      lmanifest->GetNativePath(path);
-      LogMessage("Failed to process chrome manifest: '%s'.",
-                 path.get());
-    }
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP_(PRBool)
 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
 {
   nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
   if (!chromeURL)
@@ -1258,917 +675,12 @@ nsChromeRegistry::WrappersEnabled(nsIURI
   if (NS_FAILED(rv) || !isChrome)
     return PR_FALSE;
 
   nsCAutoString package;
   rv = chromeURL->GetHostPort(package);
   if (NS_FAILED(rv))
     return PR_FALSE;
 
-  PackageEntry* entry =
-    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                    & (nsACString&) package,
-                                                    PL_DHASH_LOOKUP));
-
-  return PL_DHASH_ENTRY_IS_LIVE(entry) &&
-         entry->flags & PackageEntry::XPCNATIVEWRAPPERS;
-}
-
-nsresult
-nsChromeRegistry::SelectLocaleFromPref(nsIPrefBranch* prefs)
-{
-  nsresult rv;
-  PRBool matchOSLocale = PR_FALSE, userLocaleOverride = PR_FALSE;
-  prefs->PrefHasUserValue(SELECTED_LOCALE_PREF, &userLocaleOverride);
-  rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
-
-  if (NS_SUCCEEDED(rv) && matchOSLocale && !userLocaleOverride) {
-    // compute lang and region code only when needed!
-    nsCAutoString uiLocale;
-    rv = getUILangCountry(uiLocale);
-    if (NS_SUCCEEDED(rv))
-      mSelectedLocale = uiLocale;
-  }
-  else {
-    nsXPIDLCString provider;
-    rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
-    if (NS_SUCCEEDED(rv)) {
-      mSelectedLocale = provider;
-    }
-  }
-
-  return rv;
-}
-
-NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
-{
-  nsresult rv = NS_OK;
-
-  if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
-    nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
-    NS_ASSERTION(prefs, "Bad observer call!");
-
-    NS_ConvertUTF16toUTF8 pref(someData);
-
-    if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
-        pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
-      rv = SelectLocaleFromPref(prefs);
-      if (NS_SUCCEEDED(rv) && mProfileLoaded)
-        FlushAllCaches();
-    }
-    else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
-      nsXPIDLCString provider;
-      rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
-      if (NS_FAILED(rv)) {
-        NS_ERROR("Couldn't get new locale pref!");
-        return rv;
-      }
-
-      mSelectedSkin = provider;
-      RefreshSkins();
-    } else {
-      NS_ERROR("Unexpected pref!");
-    }
-  }
-  else if (!strcmp("command-line-startup", aTopic)) {
-    nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
-    if (cmdLine) {
-      nsAutoString uiLocale;
-      rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
-                                        PR_FALSE, uiLocale);
-      if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
-        CopyUTF16toUTF8(uiLocale, mSelectedLocale);
-        nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
-        if (prefs) {
-          prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
-        }
-      }
-    }
-  }
-  else if (!strcmp("profile-initial-state", aTopic)) {
-    mProfileLoaded = PR_TRUE;
-  }
-  else {
-    NS_ERROR("Unexpected observer topic!");
-  }
-
-  return rv;
-}
-
-nsresult
-nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
-{
-  nsresult rv;
-
-  PRFileDesc* fd;
-  rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRInt32 n, size;
-  char *buf;
-
-  size = PR_Available(fd);
-  if (size == -1) {
-    rv = NS_ERROR_UNEXPECTED;
-    goto mend;
-  }
-
-  buf = (char *) malloc(size + 1);
-  if (!buf) {
-    rv = NS_ERROR_OUT_OF_MEMORY;
-    goto mend;
-  }
-
-  n = PR_Read(fd, buf, size);
-  if (n > 0) {
-    buf[size] = '\0';
-    rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
-  }
-  free(buf);
-
-mend:
-  PR_Close(fd);
-  return rv;
-}
-
-static const char kWhitespace[] = "\t ";
-static const char kNewlines[]   = "\r\n";
-
-/**
- * Check for a modifier flag of the following forms:
- *   "flag"   (same as "true")
- *   "flag=yes|true|1"
- *   "flag="no|false|0"
- * @param aFlag The flag to compare.
- * @param aData The tokenized data to check; this is lowercased
- *              before being passed in.
- * @param aResult If the flag is found, the value is assigned here.
- * @return Whether the flag was handled.
- */
-static PRBool
-CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
-{
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
-
-  if (aFlag.Length() == aData.Length()) {
-    // the data is simply "flag", which is the same as "flag=yes"
-    aResult = PR_TRUE;
-    return PR_TRUE;
-  }
-
-  if (aData.CharAt(aFlag.Length()) != '=') {
-    // the data is "flag2=", which is not anything we care about
-    return PR_FALSE;
-  }
-
-  if (aData.Length() == aFlag.Length() + 1) {
-    aResult = PR_FALSE;
-    return PR_TRUE;
-  }
-
-  switch (aData.CharAt(aFlag.Length() + 1)) {
-  case '1':
-  case 't': //true
-  case 'y': //yes
-    aResult = PR_TRUE;
-    return PR_TRUE;
-
-  case '0':
-  case 'f': //false
-  case 'n': //no
-    aResult = PR_FALSE;
-    return PR_TRUE;
-  }
-
-  return PR_FALSE;
-}
-
-enum TriState {
-  eUnspecified,
-  eBad,
-  eOK
-};
-
-/**
- * Check for a modifier flag of the following form:
- *   "flag=string"
- *   "flag!=string"
- * @param aFlag The flag to compare.
- * @param aData The tokenized data to check; this is lowercased
- *              before being passed in.
- * @param aValue The value that is expected.
- * @param aResult If this is "ok" when passed in, this is left alone.
- *                Otherwise if the flag is found it is set to eBad or eOK.
- * @return Whether the flag was handled.
- */
-static PRBool
-CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
-                const nsSubstring& aValue, TriState& aResult)
-{
-  if (aData.Length() < aFlag.Length() + 1)
-    return PR_FALSE;
-
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
-
-  PRBool comparison = PR_TRUE;
-  if (aData[aFlag.Length()] != '=') {
-    if (aData[aFlag.Length()] == '!' &&
-        aData.Length() >= aFlag.Length() + 2 &&
-        aData[aFlag.Length() + 1] == '=')
-      comparison = PR_FALSE;
-    else
-      return PR_FALSE;
-  }
-
-  if (aResult != eOK) {
-    nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
-    if (testdata.Equals(aValue))
-      aResult = comparison ? eOK : eBad;
-    else
-      aResult = comparison ? eBad : eOK;
-  }
-
-  return PR_TRUE;
-}
-
-/**
- * Check for a modifier flag of the following form:
- *   "flag=version"
- *   "flag<=version"
- *   "flag<version"
- *   "flag>=version"
- *   "flag>version"
- * @param aFlag The flag to compare.
- * @param aData The tokenized data to check; this is lowercased
- *              before being passed in.
- * @param aValue The value that is expected. If this is empty then no
- *               comparison will match.
- * @param aChecker the version checker to use. If null, aResult will always
- *                 be eBad.
- * @param aResult If this is eOK when passed in, this is left alone.
- *                Otherwise if the flag is found it is set to eBad or eOK.
- * @return Whether the flag was handled.
- */
-
-#define COMPARE_EQ    1 << 0
-#define COMPARE_LT    1 << 1
-#define COMPARE_GT    1 << 2
-
-static PRBool
-CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
-                 const nsSubstring& aValue, nsIVersionComparator* aChecker,
-                 TriState& aResult)
-{
-  if (aData.Length() < aFlag.Length() + 2)
-    return PR_FALSE;
-
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
-
-  if (aValue.Length() == 0) {
-    if (aResult != eOK)
-      aResult = eBad;
-    return PR_TRUE;
-  }
-
-  PRUint32 comparison;
-  nsAutoString testdata;
-
-  switch (aData[aFlag.Length()]) {
-  case '=':
-    comparison = COMPARE_EQ;
-    testdata = Substring(aData, aFlag.Length() + 1);
-    break;
-
-  case '<':
-    if (aData[aFlag.Length() + 1] == '=') {
-      comparison = COMPARE_EQ | COMPARE_LT;
-      testdata = Substring(aData, aFlag.Length() + 2);
-    }
-    else {
-      comparison = COMPARE_LT;
-      testdata = Substring(aData, aFlag.Length() + 1);
-    }
-    break;
-
-  case '>':
-    if (aData[aFlag.Length() + 1] == '=') {
-      comparison = COMPARE_EQ | COMPARE_GT;
-      testdata = Substring(aData, aFlag.Length() + 2);
-    }
-    else {
-      comparison = COMPARE_GT;
-      testdata = Substring(aData, aFlag.Length() + 1);
-    }
-    break;
-
-  default:
-    return PR_FALSE;
-  }
-
-  if (testdata.Length() == 0)
-    return PR_FALSE;
-
-  if (aResult != eOK) {
-    if (!aChecker) {
-      aResult = eBad;
-    }
-    else {
-      PRInt32 c;
-      nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
-                                      NS_ConvertUTF16toUTF8(testdata), &c);
-      if (NS_FAILED(rv)) {
-        aResult = eBad;
-      }
-      else {
-        if ((c == 0 && comparison & COMPARE_EQ) ||
-            (c < 0 && comparison & COMPARE_LT) ||
-            (c > 0 && comparison & COMPARE_GT))
-          aResult = eOK;
-        else
-          aResult = eBad;
-      }
-    }
-  }
-
-  return PR_TRUE;
-}
-
-static void
-EnsureLowerCase(char *aBuf)
-{
-  for (; *aBuf; ++aBuf) {
-    char ch = *aBuf;
-    if (ch >= 'A' && ch <= 'Z')
-      *aBuf = ch + 'a' - 'A';
-  }
+  PRUint32 flags;
+  rv = GetFlagsFromPackage(package, &flags);
+  return NS_SUCCEEDED(rv) && (flags & XPCNATIVEWRAPPERS);
 }
-
-nsresult
-nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
-                                        nsILocalFile* aManifest,
-                                        PRBool aSkinOnly)
-{
-  nsresult rv;
-
-  NS_NAMED_LITERAL_STRING(kPlatform, "platform");
-  NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
-  NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
-  NS_NAMED_LITERAL_STRING(kApplication, "application");
-  NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
-  NS_NAMED_LITERAL_STRING(kOs, "os");
-  NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
-
-  nsCOMPtr<nsIIOService> io (do_GetIOService());
-  if (!io) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIProtocolHandler> ph;
-  rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
-  if (!rph) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIURI> manifestURI;
-  rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
-  nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
-
-  nsAutoString appID;
-  nsAutoString appVersion;
-  nsAutoString osTarget;
-  nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
-  if (xapp) {
-    nsCAutoString s;
-    rv = xapp->GetID(s);
-    if (NS_SUCCEEDED(rv))
-      CopyUTF8toUTF16(s, appID);
-
-    rv = xapp->GetVersion(s);
-    if (NS_SUCCEEDED(rv))
-      CopyUTF8toUTF16(s, appVersion);
-    
-    nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
-    if (xruntime) {
-      rv = xruntime->GetOS(s);
-      if (NS_SUCCEEDED(rv)) {
-        CopyUTF8toUTF16(s, osTarget);
-        ToLowerCase(osTarget);
-      }
-    }
-  }
-  
-  nsAutoString osVersion;
-#if defined(XP_WIN)
-  OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
-  if (GetVersionEx(&info)) {
-    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
-                                         info.dwMajorVersion,
-                                         info.dwMinorVersion);
-  }
-#elif defined(XP_MACOSX)
-  SInt32 majorVersion, minorVersion;
-  if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
-      (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
-    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
-                                         majorVersion,
-                                         minorVersion);
-  }
-#elif defined(MOZ_WIDGET_GTK2)
-  nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
-                                       gtk_major_version,
-                                       gtk_minor_version);
-#endif
-
-  char *token;
-  char *newline = buf;
-  PRUint32 line = 0;
-
-  // outer loop tokenizes by newline
-  while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
-    ++line;
-
-    if (*token == '#') // ignore lines that begin with # as comments
-      continue;
-
-    char *whitespace = token;
-    token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-    if (!token) continue;
-
-    if (!strcmp(token, "content")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring content registration in skin-only manifest.");
-        continue;
-      }
-      char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri     = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed content registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      // NOTE: We check for platform and xpcnativewrappers modifiers on
-      // content packages, but they are *applied* to content|skin|locale.
-
-      PRBool platform = PR_FALSE;
-      PRBool xpcNativeWrappers = PR_TRUE;
-      PRBool contentAccessible = PR_FALSE;
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-      TriState stOs = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckFlag(kPlatform, wtoken, platform) ||
-            CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
-            CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
-            CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad || 
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as content.",
-                              uri);
-        continue;
-      }
-
-      PackageEntry* entry =
-        static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                            & (const nsACString&) nsDependentCString(package),
-                                                            PL_DHASH_ADD));
-      if (!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      entry->baseURI = resolved;
-
-      if (platform)
-        entry->flags |= PackageEntry::PLATFORM_PACKAGE;
-      if (xpcNativeWrappers)
-        entry->flags |= PackageEntry::XPCNATIVEWRAPPERS;
-      if (contentAccessible)
-        entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
-      if (xpc) {
-        nsCAutoString urlp("chrome://");
-        urlp.Append(package);
-        urlp.Append('/');
-
-        rv = xpc->FlagSystemFilenamePrefix(urlp.get(), xpcNativeWrappers);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-    else if (!strcmp(token, "locale")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring locale registration in skin-only manifest.");
-        continue;
-      }
-      char *package  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri      = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !provider || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed locale registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a locale.",
-                              uri);
-        continue;
-      }
-
-      PackageEntry* entry =
-        static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                            & (const nsACString&) nsDependentCString(package),
-                                                            PL_DHASH_ADD));
-      if (!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      entry->locales.SetBase(nsDependentCString(provider), resolved);
-    }
-    else if (!strcmp(token, "skin")) {
-      char *package  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri      = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !provider || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed skin registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a skin.",
-                              uri);
-        continue;
-      }
-
-      PackageEntry* entry =
-        static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                            & (const nsACString&) nsDependentCString(package),
-                                                            PL_DHASH_ADD));
-      if (!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      entry->skins.SetBase(nsDependentCString(provider), resolved);
-    }
-    else if (!strcmp(token, "overlay")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring overlay registration in skin-only manifest.");
-        continue;
-      }
-      char *base    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!base || !overlay) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: malformed chrome overlay instruction.");
-        continue;
-      }
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> baseuri, overlayuri;
-      rv  = io->NewURI(nsDependentCString(base), nsnull, nsnull,
-                       getter_AddRefs(baseuri));
-      rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
-                       getter_AddRefs(overlayuri));
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
-        continue;
-      }
-
-      if (!CanLoadResource(overlayuri)) {
-        LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as an overlay.",
-                              overlay);
-        continue;
-      }
-
-      mOverlayHash.Add(baseuri, overlayuri);
-    }
-    else if (!strcmp(token, "style")) {
-      char *base    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!base || !overlay) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: malformed chrome style instruction.");
-        continue;
-      }
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> baseuri, overlayuri;
-      rv  = io->NewURI(nsDependentCString(base), nsnull, nsnull,
-                      getter_AddRefs(baseuri));
-      rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
-                       getter_AddRefs(overlayuri));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(overlayuri)) {
-        LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a style overlay.",
-                              overlay);
-        continue;
-      }
-
-      mStyleHash.Add(baseuri, overlayuri);
-    }
-    else if (!strcmp(token, "override")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring override registration in skin-only manifest.");
-        continue;
-      }
-
-      char *chrome    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *resolved  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!chrome || !resolved) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: malformed chrome override instruction.");
-        continue;
-      }
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> chromeuri, resolveduri;
-      rv  = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
-                      getter_AddRefs(chromeuri));
-      rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
-                       getter_AddRefs(resolveduri));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolveduri)) {
-        LogMessageWithContext(resolveduri, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as an override.",
-                              resolved);
-        continue;
-      }
-
-      mOverrideTable.Put(chromeuri, resolveduri);
-    }
-    else if (!strcmp(token, "resource")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring resource registration in skin-only manifest.");
-        continue;
-      }
-
-      char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri     = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed resource registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-      TriState stOs = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad || 
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-      
-      nsDependentCString host(package);
-
-      PRBool exists;
-      rv = rph->HasSubstitution(host, &exists);
-      NS_ENSURE_SUCCESS(rv, rv);
-      if (exists) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Duplicate resource declaration for '%s' ignored.",
-                              package);
-        continue;
-      }
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a resource.",
-                              uri);
-        continue;
-      }
-
-      rv = rph->SetSubstitution(host, resolved);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    else {
-      LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                            "Warning: Ignoring unrecognized chrome manifest instruction.");
-    }
-  }
-
-  return NS_OK;
-}
--- a/chrome/src/nsChromeRegistry.h
+++ b/chrome/src/nsChromeRegistry.h
@@ -32,232 +32,115 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifndef nsChromeRegistry_h
+#define nsChromeRegistry_h
+
 #include "nsIChromeRegistry.h"
 #include "nsIToolkitChromeRegistry.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 
 #ifdef MOZ_XUL
 #include "nsIXULOverlayProvider.h"
 #endif
 
 #include "pldhash.h"
 
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsURIHashKey.h"
-#include "nsVoidArray.h"
-#include "nsTArray.h"
 #include "nsInterfaceHashtable.h"
 
-struct PRFileDesc;
-class nsIAtom;
 class nsIDOMWindowInternal;
-class nsILocalFile;
-class nsIPrefBranch;
-class nsIRDFDataSource;
-class nsIRDFResource;
-class nsIRDFService;
-class nsISimpleEnumerator;
 class nsIURL;
 
+// The chrome registry is actually split between nsChromeRegistryChrome and
+// nsChromeRegistryContent. The work/data that is common to both resides in
+// the shared nsChromeRegistry implementation, with operations that only make
+// sense for one side erroring out in the other.
+
 // for component registration
 // {47049e42-1d87-482a-984d-56ae185e367a}
 #define NS_CHROMEREGISTRY_CID \
 { 0x47049e42, 0x1d87, 0x482a, { 0x98, 0x4d, 0x56, 0xae, 0x18, 0x5e, 0x36, 0x7a } }
 
 class nsChromeRegistry : public nsIToolkitChromeRegistry,
 #ifdef MOZ_XUL
                          public nsIXULOverlayProvider,
 #endif
                          public nsIObserver,
                          public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
 
-  // nsIChromeRegistry methods:
-  NS_DECL_NSICHROMEREGISTRY
-  NS_DECL_NSIXULCHROMEREGISTRY
-  NS_DECL_NSITOOLKITCHROMEREGISTRY
+  // nsIXULChromeRegistry methods:
+  NS_IMETHOD ReloadChrome();
+  NS_IMETHOD RefreshSkins();
+  NS_IMETHOD AllowScriptsForPackage(nsIURI* url,
+                                    PRBool* _retval NS_OUTPARAM);
+  NS_IMETHOD AllowContentToAccess(nsIURI* url,
+                                  PRBool* _retval NS_OUTPARAM);
 
-#ifdef MOZ_XUL
-  NS_DECL_NSIXULOVERLAYPROVIDER
-#endif
-
-  NS_DECL_NSIOBSERVER
+  // nsIChromeRegistry methods:
+  NS_IMETHOD_(PRBool) WrappersEnabled(nsIURI *aURI);
+  NS_IMETHOD ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult);
 
   // nsChromeRegistry methods:
-  nsChromeRegistry() : mInitialized(PR_FALSE), mProfileLoaded(PR_FALSE) {
-    mPackagesHash.ops = nsnull;
-  }
-  ~nsChromeRegistry();
+  nsChromeRegistry() : mInitialized(PR_FALSE) { }
+  virtual ~nsChromeRegistry();
 
-  nsresult Init();
+  virtual nsresult Init();
+
+  static already_AddRefed<nsIChromeRegistry> GetService();
 
   static nsChromeRegistry* gChromeRegistry;
 
   static nsresult Canonify(nsIURL* aChromeURL);
 
 protected:
-  nsresult GetDynamicInfo(nsIURI *aChromeURL, PRBool aIsOverlay, nsISimpleEnumerator **aResult);
-
-  nsresult LoadInstallDataSource();
-  nsresult LoadProfileDataSource();
-
   void FlushSkinCaches();
   void FlushAllCaches();
 
-private:
-  nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
+  static void LogMessage(const char* aMsg, ...);
+  static void LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
+                                    const char* aMsg, ...);
+
+  virtual nsresult GetBaseURIFromPackage(const nsCString& aPackage,
+                                         const nsCString& aProvider,
+                                         const nsCString& aPath,
+                                         nsIURI* *aResult) = 0;
+  virtual nsresult GetFlagsFromPackage(const nsCString& aPackage,
+                                       PRUint32* aFlags) = 0;
 
   static nsresult RefreshWindow(nsIDOMWindowInternal* aWindow);
   static nsresult GetProviderAndPath(nsIURL* aChromeURL,
                                      nsACString& aProvider, nsACString& aPath);
 
-#ifdef MOZ_XUL
-  NS_HIDDEN_(void) ProcessProvider(PRFileDesc *fd, nsIRDFService* aRDFs,
-                                   nsIRDFDataSource* ds, nsIRDFResource* aRoot,
-                                   PRBool aIsLocale, const nsACString& aBaseURL);
-  NS_HIDDEN_(void) ProcessOverlays(PRFileDesc *fd, nsIRDFDataSource* ds,
-                                   nsIRDFResource* aRoot,
-                                   const nsCSubstring& aType);
-#endif
-
-  NS_HIDDEN_(nsresult) ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly);
-  NS_HIDDEN_(nsresult) ProcessManifestBuffer(char *aBuffer, PRInt32 aLength, nsILocalFile* aManifest, PRBool aSkinOnly);
-  NS_HIDDEN_(nsresult) ProcessNewChromeFile(nsILocalFile *aListFile, nsIURI* aManifest);
-  NS_HIDDEN_(nsresult) ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength, nsIURI* aManifest);
-
-public:
-  struct ProviderEntry
-  {
-    ProviderEntry(const nsACString& aProvider, nsIURI* aBase) :
-      provider(aProvider),
-      baseURI(aBase) { }
-
-    nsCString        provider;
-    nsCOMPtr<nsIURI> baseURI;
-  };
+  // Available flags
+  enum {
+    // This is a "platform" package (e.g. chrome://global-platform/).
+    // Appends one of win/ unix/ mac/ to the base URI.
+    PLATFORM_PACKAGE = 1 << 0,
+    // This package should use the new XPCNativeWrappers to separate
+    // content from chrome. This flag is currently unused (because we call
+    // into xpconnect at registration time).
+    XPCNATIVEWRAPPERS = 1 << 1,
 
-  class nsProviderArray
-  {
-  public:
-    nsProviderArray() :
-      mArray(1) { }
-    ~nsProviderArray()
-      { Clear(); }
-
-    // When looking up locales and skins, the "selected" locale is not always
-    // available. This enum identifies what kind of match is desired/found.
-    enum MatchType {
-      EXACT = 0,
-      LOCALE = 1, // "en-GB" is selected, we found "en-US"
-      ANY = 2
-    };
-
-    nsIURI* GetBase(const nsACString& aPreferred, MatchType aType);
-    const nsACString& GetSelected(const nsACString& aPreferred, MatchType aType);
-    void    SetBase(const nsACString& aProvider, nsIURI* base);
-    void    EnumerateToArray(nsTArray<nsCString> *a);
-    void    Clear();
-
-  private:
-    ProviderEntry* GetProvider(const nsACString& aPreferred, MatchType aType);
-
-    nsVoidArray mArray;
+    // Content script may access files in this package
+    CONTENT_ACCESSIBLE = 1 << 2
   };
 
-  struct PackageEntry : public PLDHashEntryHdr
-  {
-    PackageEntry(const nsACString& package);
-    ~PackageEntry() { }
-
-    // Available flags
-    enum {
-      // This is a "platform" package (e.g. chrome://global-platform/).
-      // Appends one of win/ unix/ mac/ to the base URI.
-      PLATFORM_PACKAGE = 1 << 0,
-
-      // This package should use the new XPCNativeWrappers to separate
-      // content from chrome. This flag is currently unused (because we call
-      // into xpconnect at registration time).
-      XPCNATIVEWRAPPERS = 1 << 1,
-
-      // Content script may access files in this package
-      CONTENT_ACCESSIBLE = 1 << 2
-    };
-
-    nsCString        package;
-    nsCOMPtr<nsIURI> baseURI;
-    PRUint32         flags;
-    nsProviderArray  locales;
-    nsProviderArray  skins;
-  };
-
-private:
-  static PLDHashNumber HashKey(PLDHashTable *table, const void *key);
-  static PRBool        MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
-                                const void *key);
-  static void          ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry);
-  static PRBool        InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
-                                 const void *key);
-
-  static const PLDHashTableOps kTableOps;
-
-public:
-  class OverlayListEntry : public nsURIHashKey
-  {
-  public:
-    typedef nsURIHashKey::KeyType        KeyType;
-    typedef nsURIHashKey::KeyTypePointer KeyTypePointer;
-
-    OverlayListEntry(KeyTypePointer aKey) : nsURIHashKey(aKey) { }
-    OverlayListEntry(OverlayListEntry& toCopy) : nsURIHashKey(toCopy),
-                                                 mArray(toCopy.mArray) { }
-    ~OverlayListEntry() { }
-
-    void AddURI(nsIURI* aURI);
-
-    nsCOMArray<nsIURI> mArray;
-  };
-
-  class OverlayListHash
-  {
-  public:
-    OverlayListHash() { }
-    ~OverlayListHash() { }
-
-    PRBool Init() { return mTable.Init(); }
-    void Add(nsIURI* aBase, nsIURI* aOverlay);
-    void Clear() { mTable.Clear(); }
-    const nsCOMArray<nsIURI>* GetArray(nsIURI* aBase);
-
-  private:
-    nsTHashtable<OverlayListEntry> mTable;
-  };
-
-private:
   PRBool mInitialized;
-  PRBool mProfileLoaded;
-
-  // Hash of package names ("global") to PackageEntry objects
-  PLDHashTable mPackagesHash;
-
-  // Hashes on the file to be overlaid (chrome://browser/content/browser.xul)
-  // to a list of overlays/stylesheets
-  OverlayListHash mOverlayHash;
-  OverlayListHash mStyleHash;
 
   // "Override" table (chrome URI string -> real URI)
   nsInterfaceHashtable<nsURIHashKey, nsIURI> mOverrideTable;
+};
 
-  nsCString mSelectedLocale;
-  nsCString mSelectedSkin;
-};
+#endif // nsChromeRegistry_h
new file mode 100644
--- /dev/null
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -0,0 +1,1686 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Initial Developer)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef MOZ_IPC
+#include "mozilla/dom/PContentProcessParent.h"
+#include "RegistryMessageUtils.h"
+#include "nsResProtocolHandler.h"
+#endif
+
+#include "nsChromeRegistryChrome.h"
+
+#if defined(XP_WIN)
+#include <windows.h>
+#elif defined(XP_MACOSX)
+#include <CoreServices/CoreServices.h>
+#elif defined(MOZ_WIDGET_GTK2)
+#include <gtk/gtk.h>
+#endif
+
+#include "nsArrayEnumerator.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsEnumeratorUtils.h"
+#include "nsNetUtil.h"
+#include "nsStringEnumerator.h"
+#include "nsTextFormatter.h"
+#include "nsUnicharUtils.h"
+#include "nsWidgetsCID.h"
+#include "nsXPCOMCIDInternal.h"
+
+#include "nsICommandLine.h"
+#include "nsILocaleService.h"
+#include "nsILocalFile.h"
+#include "nsILookAndFeel.h"
+#include "nsIObserverService.h"
+#include "nsIPrefBranch2.h"
+#include "nsIPrefService.h"
+#include "nsIScriptError.h"
+#include "nsIVersionComparator.h"
+#include "nsIXPConnect.h"
+#include "nsIXULAppInfo.h"
+#include "nsIXULRuntime.h"
+
+#define UILOCALE_CMD_LINE_ARG "UILocale"
+
+#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
+#define SELECTED_LOCALE_PREF "general.useragent.locale"
+#define SELECTED_SKIN_PREF   "general.skins.selectedSkin"
+
+static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
+
+static PLDHashOperator
+RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
+{
+  return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
+}
+
+// We use a "best-fit" algorithm for matching locales and themes. 
+// 1) the exact selected locale/theme
+// 2) (locales only) same language, different country
+//    e.g. en-GB is the selected locale, only en-US is available
+// 3) any available locale/theme
+
+/**
+ * Match the language-part of two lang-COUNTRY codes, hopefully but
+ * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
+ * work, any other garbage-in will produce undefined results as long
+ * as it does not crash.
+ */
+static PRBool
+LanguagesMatch(const nsACString& a, const nsACString& b)
+{
+  if (a.Length() < 2 || b.Length() < 2)
+    return PR_FALSE;
+
+  nsACString::const_iterator as, ae, bs, be;
+  a.BeginReading(as);
+  a.EndReading(ae);
+  b.BeginReading(bs);
+  b.EndReading(be);
+
+  while (*as == *bs) {
+    if (*as == '-')
+      return PR_TRUE;
+ 
+    ++as; ++bs;
+
+    // reached the end
+    if (as == ae && bs == be)
+      return PR_TRUE;
+
+    // "a" is short
+    if (as == ae)
+      return (*bs == '-');
+
+    // "b" is short
+    if (bs == be)
+      return (*as == '-');
+  }
+
+  return PR_FALSE;
+}
+
+nsChromeRegistryChrome::nsChromeRegistryChrome()
+  : mProfileLoaded(PR_FALSE)
+{
+  mPackagesHash.ops = nsnull;
+}
+
+nsChromeRegistryChrome::~nsChromeRegistryChrome()
+{
+  if (mPackagesHash.ops)
+    PL_DHashTableFinish(&mPackagesHash);
+}
+
+nsresult
+nsChromeRegistryChrome::Init()
+{
+  nsresult rv = nsChromeRegistry::Init();
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (!mOverlayHash.Init() ||
+      !mStyleHash.Init())
+    return NS_ERROR_FAILURE;
+  
+  mSelectedLocale = NS_LITERAL_CSTRING("en-US");
+  mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
+
+  if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
+                         nsnull, sizeof(PackageEntry), 16))
+    return NS_ERROR_FAILURE;
+
+  PRBool safeMode = PR_FALSE;
+  nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+  if (xulrun)
+    xulrun->GetInSafeMode(&safeMode);
+  
+  nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
+  nsCOMPtr<nsIPrefBranch> prefs;
+
+  if (safeMode)
+    prefserv->GetDefaultBranch(nsnull, getter_AddRefs(prefs));
+  else
+    prefs = do_QueryInterface(prefserv);
+
+  if (!prefs) {
+    NS_WARNING("Could not get pref service!");
+  }
+  else {
+    nsXPIDLCString provider;
+    rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
+    if (NS_SUCCEEDED(rv))
+      mSelectedSkin = provider;
+
+    SelectLocaleFromPref(prefs);
+
+    nsCOMPtr<nsIPrefBranch2> prefs2 (do_QueryInterface(prefs));
+    if (prefs2) {
+      rv = prefs2->AddObserver(MATCH_OS_LOCALE_PREF, this, PR_TRUE);
+      rv = prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
+      rv = prefs2->AddObserver(SELECTED_SKIN_PREF, this, PR_TRUE);
+    }
+  }
+
+  nsCOMPtr<nsIObserverService> obsService (do_GetService("@mozilla.org/observer-service;1"));
+  if (obsService) {
+    obsService->AddObserver(this, "command-line-startup", PR_TRUE);
+    obsService->AddObserver(this, "profile-initial-state", PR_TRUE);
+  }
+
+  CheckForNewChrome();
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::CheckForOSAccessibility()
+{
+  nsresult rv;
+
+  nsCOMPtr<nsILookAndFeel> lookAndFeel (do_GetService(kLookAndFeelCID));
+  if (lookAndFeel) {
+    PRInt32 useAccessibilityTheme = 0;
+
+    rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_UseAccessibilityTheme,
+                                useAccessibilityTheme);
+
+    if (NS_SUCCEEDED(rv) && useAccessibilityTheme) {
+      /* Set the skin to classic and remove pref observers */
+      if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
+        mSelectedSkin.AssignLiteral("classic/1.0");
+        RefreshSkins();
+      }
+
+      nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
+      if (prefs) {
+        prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
+                                       nsIUTF8StringEnumerator* *aResult)
+{
+  nsTArray<nsCString> *a = new nsTArray<nsCString>;
+  if (!a)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  PackageEntry* entry =
+      static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                      & aPackage,
+                                                      PL_DHASH_LOOKUP));
+
+  if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
+    entry->locales.EnumerateToArray(a);
+  }
+
+  nsresult rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
+  if (NS_FAILED(rv))
+    delete a;
+
+  return rv;
+}
+
+static nsresult
+getUILangCountry(nsACString& aUILang)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString uiLang;
+  rv = localeService->GetLocaleComponentForUserAgent(uiLang);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  CopyUTF16toUTF8(uiLang, aUILang);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, PRBool *aResult)
+{
+  *aResult = PR_FALSE;
+
+  nsCAutoString locale;
+  GetSelectedLocale(package, locale);
+  if (locale.Length() < 2)
+    return NS_OK;
+
+  // first check the intl.uidirection.<locale> preference, and if that is not
+  // set, check the same preference but with just the first two characters of
+  // the locale. If that isn't set, default to left-to-right.
+  nsCAutoString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + locale;
+  nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
+  if (!prefBranch)
+    return NS_OK;
+  
+  nsXPIDLCString dir;
+  prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
+  if (dir.IsEmpty()) {
+    PRInt32 hyphen = prefString.FindChar('-');
+    if (hyphen >= 1) {
+      nsCAutoString shortPref(Substring(prefString, 0, hyphen));
+      prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
+    }
+  }
+  *aResult = dir.EqualsLiteral("rtl");
+  return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
+                                          nsACString& aLocale)
+{
+  PackageEntry* entry =
+      static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                      & aPackage,
+                                                      PL_DHASH_LOOKUP));
+
+  if (PL_DHASH_ENTRY_IS_FREE(entry))
+    return NS_ERROR_FAILURE;
+
+  aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
+  if (aLocale.IsEmpty())
+    return NS_ERROR_FAILURE;
+
+  return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs)
+{
+  nsresult rv;
+  PRBool matchOSLocale = PR_FALSE, userLocaleOverride = PR_FALSE;
+  prefs->PrefHasUserValue(SELECTED_LOCALE_PREF, &userLocaleOverride);
+  rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
+
+  if (NS_SUCCEEDED(rv) && matchOSLocale && !userLocaleOverride) {
+    // compute lang and region code only when needed!
+    nsCAutoString uiLocale;
+    rv = getUILangCountry(uiLocale);
+    if (NS_SUCCEEDED(rv))
+      mSelectedLocale = uiLocale;
+  }
+  else {
+    nsXPIDLCString provider;
+    rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
+    if (NS_SUCCEEDED(rv)) {
+      mSelectedLocale = provider;
+    }
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
+                                const PRUnichar *someData)
+{
+  nsresult rv = NS_OK;
+
+  if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
+    nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
+    NS_ASSERTION(prefs, "Bad observer call!");
+
+    NS_ConvertUTF16toUTF8 pref(someData);
+
+    if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
+        pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
+      rv = SelectLocaleFromPref(prefs);
+      if (NS_SUCCEEDED(rv) && mProfileLoaded)
+        FlushAllCaches();
+    }
+    else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
+      nsXPIDLCString provider;
+      rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
+      if (NS_FAILED(rv)) {
+        NS_ERROR("Couldn't get new locale pref!");
+        return rv;
+      }
+
+      mSelectedSkin = provider;
+      RefreshSkins();
+    } else {
+      NS_ERROR("Unexpected pref!");
+    }
+  }
+  else if (!strcmp("command-line-startup", aTopic)) {
+    nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
+    if (cmdLine) {
+      nsAutoString uiLocale;
+      rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
+                                        PR_FALSE, uiLocale);
+      if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
+        CopyUTF16toUTF8(uiLocale, mSelectedLocale);
+        nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
+        if (prefs) {
+          prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
+        }
+      }
+    }
+  }
+  else if (!strcmp("profile-initial-state", aTopic)) {
+    mProfileLoaded = PR_TRUE;
+  }
+  else {
+    NS_ERROR("Unexpected observer topic!");
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::CheckForNewChrome()
+{
+  nsresult rv;
+
+  PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
+  mOverlayHash.Clear();
+  mStyleHash.Clear();
+  mOverrideTable.Clear();
+
+  nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
+  NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
+
+  // check the extra chrome directories
+  nsCOMPtr<nsISimpleEnumerator> chromeML;
+  rv = dirSvc->Get(NS_CHROME_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
+                   getter_AddRefs(chromeML));
+  if (NS_FAILED(rv)) {
+    // ok, then simply load all .manifest files in the app chrome dir.
+    nsCOMPtr<nsIFile> chromeDir;
+    rv = dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
+                     getter_AddRefs(chromeDir));
+    if (NS_FAILED(rv))
+      return rv;
+    rv = NS_NewSingletonEnumerator(getter_AddRefs(chromeML), chromeDir);
+    if (NS_FAILED(rv))
+      return rv;
+  }
+
+  PRBool exists;
+  nsCOMPtr<nsISupports> next;
+  while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
+    chromeML->GetNext(getter_AddRefs(next));
+    nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
+    if (!lmanifest) {
+      NS_ERROR("Directory enumerator returned a non-nsILocalFile");
+      continue;
+    }
+
+    PRBool isDir;
+    if (NS_SUCCEEDED(lmanifest->IsDirectory(&isDir)) && isDir) {
+      nsCOMPtr<nsISimpleEnumerator> entries;
+      rv = lmanifest->GetDirectoryEntries(getter_AddRefs(entries));
+      if (NS_FAILED(rv))
+        continue;
+
+      while (NS_SUCCEEDED(entries->HasMoreElements(&exists)) && exists) {
+        entries->GetNext(getter_AddRefs(next));
+        lmanifest = do_QueryInterface(next);
+        if (lmanifest) {
+          nsCAutoString leafName;
+          lmanifest->GetNativeLeafName(leafName);
+          if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".manifest"))) {
+            rv = ProcessManifest(lmanifest, PR_FALSE);
+            if (NS_FAILED(rv)) {
+              nsCAutoString path;
+              lmanifest->GetNativePath(path);
+              LogMessage("Failed to process chrome manifest '%s'.",
+                         path.get());
+
+            }
+          }
+        }
+      }
+    }
+    else {
+      rv = ProcessManifest(lmanifest, PR_FALSE);
+      if (NS_FAILED(rv)) {
+        nsCAutoString path;
+        lmanifest->GetNativePath(path);
+        LogMessage("Failed to process chrome manifest: '%s'.",
+                   path.get());
+      }
+    }
+  }
+
+  rv = dirSvc->Get(NS_SKIN_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
+                   getter_AddRefs(chromeML));
+  if (NS_FAILED(rv))
+    return NS_OK;
+
+  while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
+    chromeML->GetNext(getter_AddRefs(next));
+    nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
+    if (!lmanifest) {
+      NS_ERROR("Directory enumerator returned a non-nsILocalFile");
+      continue;
+    }
+
+    rv = ProcessManifest(lmanifest, PR_TRUE);
+    if (NS_FAILED(rv)) {
+      nsCAutoString path;
+      lmanifest->GetNativePath(path);
+      LogMessage("Failed to process chrome manifest: '%s'.",
+                 path.get());
+    }
+  }
+
+  return NS_OK;
+}
+
+#ifdef MOZ_IPC
+static void
+SerializeURI(nsIURI* aURI,
+             SerializedURI& aSerializedURI)
+{
+  if (!aURI)
+    return;
+
+  aURI->GetSpec(aSerializedURI.spec);
+  aURI->GetOriginCharset(aSerializedURI.charset);
+}
+
+static PLDHashOperator
+EnumerateOverride(nsIURI* aURIKey,
+                  nsIURI* aURI,
+                  void* aArg)
+{
+  nsTArray<OverrideMapping>* overrides =
+      static_cast<nsTArray<OverrideMapping>*>(aArg);
+
+  SerializedURI chromeURI, overrideURI;
+
+  SerializeURI(aURIKey, chromeURI);
+  SerializeURI(aURI, overrideURI);
+        
+  OverrideMapping override = {
+    chromeURI, overrideURI
+  };
+  overrides->AppendElement(override);
+  return (PLDHashOperator)PL_DHASH_NEXT;
+}
+
+struct EnumerationArgs
+{
+  nsTArray<ChromePackage>& packages;
+  const nsCString& selectedLocale;
+  const nsCString& selectedSkin;
+};
+
+void
+nsChromeRegistryChrome::SendRegisteredChrome(
+    mozilla::dom::PContentProcessParent* aParent)
+{
+  nsTArray<ChromePackage> packages;
+  nsTArray<ResourceMapping> resources;
+  nsTArray<OverrideMapping> overrides;
+
+  EnumerationArgs args = {
+    packages, mSelectedLocale, mSelectedSkin
+  };
+  PL_DHashTableEnumerate(&mPackagesHash, CollectPackages, &args);
+
+  nsCOMPtr<nsIIOService> io (do_GetIOService());
+  NS_ENSURE_TRUE(io, );
+
+  nsCOMPtr<nsIProtocolHandler> ph;
+  nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+  NS_ENSURE_SUCCESS(rv, );
+
+  //FIXME: Some substitutions are set up lazily and might not exist yet
+  nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
+  nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
+  rph->CollectSubstitutions(resources);
+
+  mOverrideTable.EnumerateRead(&EnumerateOverride, &overrides);
+
+  bool success = aParent->SendRegisterChrome(packages, resources, overrides);
+  NS_ENSURE_TRUE(success, );
+}
+
+PLDHashOperator
+nsChromeRegistryChrome::CollectPackages(PLDHashTable *table,
+                                  PLDHashEntryHdr *entry,
+                                  PRUint32 number,
+                                  void *arg)
+{
+  EnumerationArgs* args = static_cast<EnumerationArgs*>(arg);
+  PackageEntry* package = static_cast<PackageEntry*>(entry);
+
+  SerializedURI contentURI, localeURI, skinURI;
+
+  SerializeURI(package->baseURI, contentURI);
+  SerializeURI(package->locales.GetBase(args->selectedLocale,
+                                        nsProviderArray::LOCALE), localeURI);
+  SerializeURI(package->skins.GetBase(args->selectedSkin, nsProviderArray::ANY),
+               skinURI);
+  
+  ChromePackage chromePackage = {
+    package->package,
+    contentURI,
+    localeURI,
+    skinURI,
+    package->flags
+  };
+  args->packages.AppendElement(chromePackage);
+  return (PLDHashOperator)PL_DHASH_NEXT;
+}
+#endif
+
+static PRBool
+CanLoadResource(nsIURI* aResourceURI)
+{
+  PRBool isLocalResource = PR_FALSE;
+  (void)NS_URIChainHasFlags(aResourceURI,
+                            nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
+                            &isLocalResource);
+  return isLocalResource;
+}
+
+nsresult
+nsChromeRegistryChrome::ProcessManifest(nsILocalFile* aManifest,
+                                        PRBool aSkinOnly)
+{
+  nsresult rv;
+
+  PRFileDesc* fd;
+  rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRInt32 n, size;
+  char *buf;
+
+  size = PR_Available(fd);
+  if (size == -1) {
+    rv = NS_ERROR_UNEXPECTED;
+    goto mend;
+  }
+
+  buf = (char *) malloc(size + 1);
+  if (!buf) {
+    rv = NS_ERROR_OUT_OF_MEMORY;
+    goto mend;
+  }
+
+  n = PR_Read(fd, buf, size);
+  if (n > 0) {
+    buf[size] = '\0';
+    rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
+  }
+  free(buf);
+
+mend:
+  PR_Close(fd);
+  return rv;
+}
+
+static const char kWhitespace[] = "\t ";
+static const char kNewlines[]   = "\r\n";
+
+/**
+ * Check for a modifier flag of the following forms:
+ *   "flag"   (same as "true")
+ *   "flag=yes|true|1"
+ *   "flag="no|false|0"
+ * @param aFlag The flag to compare.
+ * @param aData The tokenized data to check; this is lowercased
+ *              before being passed in.
+ * @param aResult If the flag is found, the value is assigned here.
+ * @return Whether the flag was handled.
+ */
+static PRBool
+CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
+{
+  if (!StringBeginsWith(aData, aFlag))
+    return PR_FALSE;
+
+  if (aFlag.Length() == aData.Length()) {
+    // the data is simply "flag", which is the same as "flag=yes"
+    aResult = PR_TRUE;
+    return PR_TRUE;
+  }
+
+  if (aData.CharAt(aFlag.Length()) != '=') {
+    // the data is "flag2=", which is not anything we care about
+    return PR_FALSE;
+  }
+
+  if (aData.Length() == aFlag.Length() + 1) {
+    aResult = PR_FALSE;
+    return PR_TRUE;
+  }
+
+  switch (aData.CharAt(aFlag.Length() + 1)) {
+    case '1':
+    case 't': //true
+    case 'y': //yes
+        aResult = PR_TRUE;
+    return PR_TRUE;
+
+    case '0':
+    case 'f': //false
+    case 'n': //no
+        aResult = PR_FALSE;
+    return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
+
+enum TriState {
+  eUnspecified,
+  eBad,
+  eOK
+};
+
+/**
+ * Check for a modifier flag of the following form:
+ *   "flag=string"
+ *   "flag!=string"
+ * @param aFlag The flag to compare.
+ * @param aData The tokenized data to check; this is lowercased
+ *              before being passed in.
+ * @param aValue The value that is expected.
+ * @param aResult If this is "ok" when passed in, this is left alone.
+ *                Otherwise if the flag is found it is set to eBad or eOK.
+ * @return Whether the flag was handled.
+ */
+static PRBool
+CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
+                const nsSubstring& aValue, TriState& aResult)
+{
+  if (aData.Length() < aFlag.Length() + 1)
+    return PR_FALSE;
+
+  if (!StringBeginsWith(aData, aFlag))
+    return PR_FALSE;
+
+  PRBool comparison = PR_TRUE;
+  if (aData[aFlag.Length()] != '=') {
+    if (aData[aFlag.Length()] == '!' &&
+        aData.Length() >= aFlag.Length() + 2 &&
+        aData[aFlag.Length() + 1] == '=')
+      comparison = PR_FALSE;
+    else
+      return PR_FALSE;
+  }
+
+  if (aResult != eOK) {
+    nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
+    if (testdata.Equals(aValue))
+      aResult = comparison ? eOK : eBad;
+    else
+      aResult = comparison ? eBad : eOK;
+  }
+
+  return PR_TRUE;
+}
+
+/**
+ * Check for a modifier flag of the following form:
+ *   "flag=version"
+ *   "flag<=version"
+ *   "flag<version"
+ *   "flag>=version"
+ *   "flag>version"
+ * @param aFlag The flag to compare.
+ * @param aData The tokenized data to check; this is lowercased
+ *              before being passed in.
+ * @param aValue The value that is expected. If this is empty then no
+ *               comparison will match.
+ * @param aChecker the version checker to use. If null, aResult will always
+ *                 be eBad.
+ * @param aResult If this is eOK when passed in, this is left alone.
+ *                Otherwise if the flag is found it is set to eBad or eOK.
+ * @return Whether the flag was handled.
+ */
+
+#define COMPARE_EQ    1 << 0
+#define COMPARE_LT    1 << 1
+#define COMPARE_GT    1 << 2
+
+static PRBool
+CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
+                 const nsSubstring& aValue, nsIVersionComparator* aChecker,
+                 TriState& aResult)
+{
+  if (aData.Length() < aFlag.Length() + 2)
+    return PR_FALSE;
+
+  if (!StringBeginsWith(aData, aFlag))
+    return PR_FALSE;
+
+  if (aValue.Length() == 0) {
+    if (aResult != eOK)
+      aResult = eBad;
+    return PR_TRUE;
+  }
+
+  PRUint32 comparison;
+  nsAutoString testdata;
+
+  switch (aData[aFlag.Length()]) {
+    case '=':
+      comparison = COMPARE_EQ;
+      testdata = Substring(aData, aFlag.Length() + 1);
+      break;
+
+    case '<':
+      if (aData[aFlag.Length() + 1] == '=') {
+        comparison = COMPARE_EQ | COMPARE_LT;
+        testdata = Substring(aData, aFlag.Length() + 2);
+      }
+      else {
+        comparison = COMPARE_LT;
+        testdata = Substring(aData, aFlag.Length() + 1);
+      }
+      break;
+
+    case '>':
+      if (aData[aFlag.Length() + 1] == '=') {
+        comparison = COMPARE_EQ | COMPARE_GT;
+        testdata = Substring(aData, aFlag.Length() + 2);
+      }
+      else {
+        comparison = COMPARE_GT;
+        testdata = Substring(aData, aFlag.Length() + 1);
+      }
+      break;
+
+    default:
+      return PR_FALSE;
+  }
+
+  if (testdata.Length() == 0)
+    return PR_FALSE;
+
+  if (aResult != eOK) {
+    if (!aChecker) {
+      aResult = eBad;
+    }
+    else {
+      PRInt32 c;
+      nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
+                                      NS_ConvertUTF16toUTF8(testdata), &c);
+      if (NS_FAILED(rv)) {
+        aResult = eBad;
+      }
+      else {
+        if ((c == 0 && comparison & COMPARE_EQ) ||
+            (c < 0 && comparison & COMPARE_LT) ||
+            (c > 0 && comparison & COMPARE_GT))
+          aResult = eOK;
+        else
+          aResult = eBad;
+      }
+    }
+  }
+
+  return PR_TRUE;
+}
+
+static void
+EnsureLowerCase(char *aBuf)
+{
+  for (; *aBuf; ++aBuf) {
+    char ch = *aBuf;
+    if (ch >= 'A' && ch <= 'Z')
+      *aBuf = ch + 'a' - 'A';
+  }
+}
+
+nsresult
+nsChromeRegistryChrome::ProcessManifestBuffer(char *buf, PRInt32 length,
+                                              nsILocalFile* aManifest,
+                                              PRBool aSkinOnly)
+{
+  nsresult rv;
+
+  NS_NAMED_LITERAL_STRING(kPlatform, "platform");
+  NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
+  NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
+  NS_NAMED_LITERAL_STRING(kApplication, "application");
+  NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
+  NS_NAMED_LITERAL_STRING(kOs, "os");
+  NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
+
+  nsCOMPtr<nsIIOService> io (do_GetIOService());
+  if (!io) return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIProtocolHandler> ph;
+  rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
+  if (!rph) return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIURI> manifestURI;
+  rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
+  nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
+
+  nsAutoString appID;
+  nsAutoString appVersion;
+  nsAutoString osTarget;
+  nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+  if (xapp) {
+    nsCAutoString s;
+    rv = xapp->GetID(s);
+    if (NS_SUCCEEDED(rv))
+      CopyUTF8toUTF16(s, appID);
+
+    rv = xapp->GetVersion(s);
+    if (NS_SUCCEEDED(rv))
+      CopyUTF8toUTF16(s, appVersion);
+    
+    nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
+    if (xruntime) {
+      rv = xruntime->GetOS(s);
+      if (NS_SUCCEEDED(rv)) {
+        CopyUTF8toUTF16(s, osTarget);
+        ToLowerCase(osTarget);
+      }
+    }
+  }
+  
+  nsAutoString osVersion;
+#if defined(XP_WIN)
+  OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
+  if (GetVersionEx(&info)) {
+    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+                              info.dwMajorVersion,
+                              info.dwMinorVersion);
+  }
+#elif defined(XP_MACOSX)
+  SInt32 majorVersion, minorVersion;
+  if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
+      (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
+    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+                              majorVersion,
+                              minorVersion);
+  }
+#elif defined(MOZ_WIDGET_GTK2)
+  nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+                            gtk_major_version,
+                            gtk_minor_version);
+#endif
+
+  char *token;
+  char *newline = buf;
+  PRUint32 line = 0;
+
+  // outer loop tokenizes by newline
+  while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
+    ++line;
+
+    if (*token == '#') // ignore lines that begin with # as comments
+      continue;
+
+    char *whitespace = token;
+    token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+    if (!token) continue;
+
+    if (!strcmp(token, "content")) {
+      if (aSkinOnly) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Ignoring content registration in skin-only manifest.");
+        continue;
+      }
+      char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *uri     = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!package || !uri) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Malformed content registration.");
+        continue;
+      }
+
+      EnsureLowerCase(package);
+
+      // NOTE: We check for platform and xpcnativewrappers modifiers on
+      // content packages, but they are *applied* to content|skin|locale.
+
+      PRBool platform = PR_FALSE;
+      PRBool xpcNativeWrappers = PR_TRUE;
+      PRBool contentAccessible = PR_FALSE;
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+      TriState stOs = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckFlag(kPlatform, wtoken, platform) ||
+            CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
+            CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
+            CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad || 
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+
+      nsCOMPtr<nsIURI> resolved;
+      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+                      getter_AddRefs(resolved));
+      if (NS_FAILED(rv))
+        continue;
+
+      if (!CanLoadResource(resolved)) {
+        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as content.",
+                              uri);
+        continue;
+      }
+
+      PackageEntry* entry =
+          static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                          & (const nsACString&) nsDependentCString(package),
+                                                          PL_DHASH_ADD));
+      if (!entry)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+      entry->baseURI = resolved;
+
+      if (platform)
+        entry->flags |= PLATFORM_PACKAGE;
+      if (xpcNativeWrappers)
+        entry->flags |= XPCNATIVEWRAPPERS;
+      if (contentAccessible)
+        entry->flags |= CONTENT_ACCESSIBLE;
+      if (xpc) {
+        nsCAutoString urlp("chrome://");
+        urlp.Append(package);
+        urlp.Append('/');
+
+        rv = xpc->FlagSystemFilenamePrefix(urlp.get(), xpcNativeWrappers);
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+    }
+    else if (!strcmp(token, "locale")) {
+      if (aSkinOnly) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Ignoring locale registration in skin-only manifest.");
+        continue;
+      }
+      char *package  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *uri      = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!package || !provider || !uri) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Malformed locale registration.");
+        continue;
+      }
+
+      EnsureLowerCase(package);
+
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOs = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad ||
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+
+      nsCOMPtr<nsIURI> resolved;
+      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+                      getter_AddRefs(resolved));
+      if (NS_FAILED(rv))
+        continue;
+
+      if (!CanLoadResource(resolved)) {
+        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as a locale.",
+                              uri);
+        continue;
+      }
+
+      PackageEntry* entry =
+          static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                          & (const nsACString&) nsDependentCString(package),
+                                                          PL_DHASH_ADD));
+      if (!entry)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+      entry->locales.SetBase(nsDependentCString(provider), resolved);
+    }
+    else if (!strcmp(token, "skin")) {
+      char *package  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *uri      = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!package || !provider || !uri) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Malformed skin registration.");
+        continue;
+      }
+
+      EnsureLowerCase(package);
+
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOs = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad ||
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+
+      nsCOMPtr<nsIURI> resolved;
+      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+                      getter_AddRefs(resolved));
+      if (NS_FAILED(rv))
+        continue;
+
+      if (!CanLoadResource(resolved)) {
+        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as a skin.",
+                              uri);
+        continue;
+      }
+
+      PackageEntry* entry =
+          static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                          & (const nsACString&) nsDependentCString(package),
+                                                          PL_DHASH_ADD));
+      if (!entry)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+      entry->skins.SetBase(nsDependentCString(provider), resolved);
+    }
+    else if (!strcmp(token, "overlay")) {
+      if (aSkinOnly) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Ignoring overlay registration in skin-only manifest.");
+        continue;
+      }
+      char *base    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!base || !overlay) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: malformed chrome overlay instruction.");
+        continue;
+      }
+
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOs = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad ||
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+
+      nsCOMPtr<nsIURI> baseuri, overlayuri;
+      rv  = io->NewURI(nsDependentCString(base), nsnull, nsnull,
+                       getter_AddRefs(baseuri));
+      rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
+                       getter_AddRefs(overlayuri));
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
+        continue;
+      }
+
+      if (!CanLoadResource(overlayuri)) {
+        LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as an overlay.",
+                              overlay);
+        continue;
+      }
+
+      mOverlayHash.Add(baseuri, overlayuri);
+    }
+    else if (!strcmp(token, "style")) {
+      char *base    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!base || !overlay) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: malformed chrome style instruction.");
+        continue;
+      }
+
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOs = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad ||
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+
+      nsCOMPtr<nsIURI> baseuri, overlayuri;
+      rv  = io->NewURI(nsDependentCString(base), nsnull, nsnull,
+                       getter_AddRefs(baseuri));
+      rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
+                       getter_AddRefs(overlayuri));
+      if (NS_FAILED(rv))
+        continue;
+
+      if (!CanLoadResource(overlayuri)) {
+        LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as a style overlay.",
+                              overlay);
+        continue;
+      }
+
+      mStyleHash.Add(baseuri, overlayuri);
+    }
+    else if (!strcmp(token, "override")) {
+      if (aSkinOnly) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Ignoring override registration in skin-only manifest.");
+        continue;
+      }
+
+      char *chrome    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *resolved  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!chrome || !resolved) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: malformed chrome override instruction.");
+        continue;
+      }
+
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOs = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad ||
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+
+      nsCOMPtr<nsIURI> chromeuri, resolveduri;
+      rv  = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
+                       getter_AddRefs(chromeuri));
+      rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
+                       getter_AddRefs(resolveduri));
+      if (NS_FAILED(rv))
+        continue;
+
+      if (!CanLoadResource(resolveduri)) {
+        LogMessageWithContext(resolveduri, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as an override.",
+                              resolved);
+        continue;
+      }
+
+      mOverrideTable.Put(chromeuri, resolveduri);
+    }
+    else if (!strcmp(token, "resource")) {
+      if (aSkinOnly) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Ignoring resource registration in skin-only manifest.");
+        continue;
+      }
+
+      char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      char *uri     = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+      if (!package || !uri) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Malformed resource registration.");
+        continue;
+      }
+
+      EnsureLowerCase(package);
+
+      TriState stAppVersion = eUnspecified;
+      TriState stApp = eUnspecified;
+      TriState stOsVersion = eUnspecified;
+      TriState stOs = eUnspecified;
+
+      PRBool badFlag = PR_FALSE;
+
+      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
+             !badFlag) {
+        NS_ConvertASCIItoUTF16 wtoken(token);
+        ToLowerCase(wtoken);
+
+        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
+            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
+          continue;
+
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Unrecognized chrome registration modifier '%s'.",
+                              token);
+        badFlag = PR_TRUE;
+      }
+
+      if (badFlag || stApp == eBad || stAppVersion == eBad || 
+          stOs == eBad || stOsVersion == eBad)
+        continue;
+      
+      nsDependentCString host(package);
+
+      PRBool exists;
+      rv = rph->HasSubstitution(host, &exists);
+      NS_ENSURE_SUCCESS(rv, rv);
+      if (exists) {
+        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                              "Warning: Duplicate resource declaration for '%s' ignored.",
+                              package);
+        continue;
+      }
+
+      nsCOMPtr<nsIURI> resolved;
+      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
+                      getter_AddRefs(resolved));
+      if (NS_FAILED(rv))
+        continue;
+
+      if (!CanLoadResource(resolved)) {
+        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
+                              "Warning: cannot register non-local URI '%s' as a resource.",
+                              uri);
+        continue;
+      }
+
+      rv = rph->SetSubstitution(host, resolved);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    else {
+      LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
+                            "Warning: Ignoring unrecognized chrome manifest instruction.");
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
+                                              const nsCString& aProvider,
+                                              const nsCString& aPath,
+                                              nsIURI* *aResult)
+{
+  PackageEntry* entry =
+      static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                      &aPackage,
+                                                      PL_DHASH_LOOKUP));
+
+  if (PL_DHASH_ENTRY_IS_FREE(entry)) {
+    if (!mInitialized)
+      return NS_ERROR_NOT_INITIALIZED;
+
+    LogMessage("No chrome package registered for chrome://%s/%s/%s",
+               aPackage.get(), aProvider.get(), aPath.get());
+
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResult = nsnull;
+  if (aProvider.EqualsLiteral("locale")) {
+    *aResult = entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
+  }
+  else if (aProvider.EqualsLiteral("skin")) {
+    *aResult = entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
+  }
+  else if (aProvider.EqualsLiteral("content")) {
+    *aResult = entry->baseURI;
+  }
+  return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
+                                            PRUint32* aFlags)
+{
+  PackageEntry* entry =
+      static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                      & (nsACString&) aPackage,
+                                                      PL_DHASH_LOOKUP));
+  if (PL_DHASH_ENTRY_IS_FREE(entry))
+    return NS_ERROR_NOT_AVAILABLE;
+
+  *aFlags = entry->flags;
+  return NS_OK;
+}
+
+PLHashNumber
+nsChromeRegistryChrome::HashKey(PLDHashTable *table, const void *key)
+{
+  const nsACString& str = *reinterpret_cast<const nsACString*>(key);
+  return HashString(str);
+}
+
+PRBool
+nsChromeRegistryChrome::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
+                           const void *key)
+{
+  const nsACString& str = *reinterpret_cast<const nsACString*>(key);
+  const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
+  return str.Equals(pentry->package);
+}
+
+void
+nsChromeRegistryChrome::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
+{
+  PackageEntry* pentry = static_cast<PackageEntry*>(entry);
+  pentry->~PackageEntry();
+}
+
+PRBool
+nsChromeRegistryChrome::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
+                            const void *key)
+{
+  const nsACString& str = *reinterpret_cast<const nsACString*>(key);
+
+  new (entry) PackageEntry(str);
+  return PR_TRUE;
+}
+
+const PLDHashTableOps
+nsChromeRegistryChrome::kTableOps = {
+  PL_DHashAllocTable,
+  PL_DHashFreeTable,
+  HashKey,
+  MatchKey,
+  PL_DHashMoveEntryStub,
+  ClearEntry,
+  PL_DHashFinalizeStub,
+  InitEntry
+};
+
+nsChromeRegistryChrome::ProviderEntry*
+nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
+{
+  PRInt32 i = mArray.Count();
+  if (!i)
+    return nsnull;
+
+  ProviderEntry* found = nsnull;  // Only set if we find a partial-match locale
+  ProviderEntry* entry;
+
+  while (i--) {
+    entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
+    if (aPreferred.Equals(entry->provider))
+      return entry;
+
+    if (aType != LOCALE)
+      continue;
+
+    if (LanguagesMatch(aPreferred, entry->provider)) {
+      found = entry;
+      continue;
+    }
+
+    if (!found && entry->provider.EqualsLiteral("en-US"))
+      found = entry;
+  }
+
+  if (!found && aType != EXACT)
+    return entry;
+
+  return found;
+}
+
+nsIURI*
+nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
+{
+  ProviderEntry* provider = GetProvider(aPreferred, aType);
+
+  if (!provider)
+    return nsnull;
+
+  return provider->baseURI;
+}
+
+const nsACString&
+nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
+{
+  ProviderEntry* entry = GetProvider(aPreferred, aType);
+
+  if (entry)
+    return entry->provider;
+
+  return EmptyCString();
+}
+
+void
+nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
+{
+  ProviderEntry* provider = GetProvider(aProvider, EXACT);
+
+  if (provider) {
+    provider->baseURI = aBaseURL;
+    return;
+  }
+
+  // no existing entries, add a new one
+  provider = new ProviderEntry(aProvider, aBaseURL);
+  if (!provider)
+    return; // It's safe to silently fail on OOM
+
+  mArray.AppendElement(provider);
+}
+
+void
+nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
+{
+  PRInt32 i = mArray.Count();
+  while (i--) {
+    ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
+    a->AppendElement(entry->provider);
+  }
+}
+
+void
+nsChromeRegistryChrome::nsProviderArray::Clear()
+{
+  PRInt32 i = mArray.Count();
+  while (i--) {
+    ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
+    delete entry;
+  }
+
+  mArray.Clear();
+}
+
+void
+nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
+{
+  PRInt32 i = mArray.Count();
+  while (i--) {
+    PRBool equals;
+    if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
+      return;
+  }
+
+  mArray.AppendObject(aURI);
+}
+
+void
+nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
+{
+  OverlayListEntry* entry = mTable.PutEntry(aBase);
+  if (entry)
+    entry->AddURI(aOverlay);
+}
+
+const nsCOMArray<nsIURI>*
+nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
+{
+  OverlayListEntry* entry = mTable.GetEntry(aBase);
+  if (!entry)
+    return nsnull;
+
+  return &entry->mArray;
+}
+
+#ifdef MOZ_XUL
+NS_IMETHODIMP
+nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL,
+                                         nsISimpleEnumerator **aResult)
+{
+  const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
+  if (!parray)
+    return NS_NewEmptyEnumerator(aResult);
+
+  return NS_NewArrayEnumerator(aResult, *parray);
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
+                                       nsISimpleEnumerator **aResult)
+{
+  const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
+  if (!parray)
+    return NS_NewEmptyEnumerator(aResult);
+
+  return NS_NewArrayEnumerator(aResult, *parray);
+}
+#endif // MOZ_XUL
new file mode 100644
--- /dev/null
+++ b/chrome/src/nsChromeRegistryChrome.h
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Initial Developer)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsChromeRegistryChrome_h
+#define nsChromeRegistryChrome_h
+
+#include "nsChromeRegistry.h"
+
+namespace mozilla {
+namespace dom {
+class PContentProcessParent;
+}
+}
+
+class nsIPrefBranch;
+
+class nsChromeRegistryChrome : public nsChromeRegistry
+{
+ public:
+  nsChromeRegistryChrome();
+  ~nsChromeRegistryChrome();
+
+  NS_OVERRIDE nsresult Init();
+
+  NS_OVERRIDE NS_IMETHOD CheckForNewChrome();
+  NS_OVERRIDE NS_IMETHOD CheckForOSAccessibility();
+  NS_OVERRIDE NS_IMETHOD GetLocalesForPackage(const nsACString& aPackage,
+                                              nsIUTF8StringEnumerator* *aResult);
+  NS_OVERRIDE NS_IMETHOD IsLocaleRTL(const nsACString& package,
+                                     PRBool *aResult);
+  NS_OVERRIDE NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+                                           nsACString& aLocale);
+  NS_OVERRIDE NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
+                                 const PRUnichar *someData);
+
+#ifdef MOZ_XUL
+  NS_OVERRIDE NS_IMETHOD GetXULOverlays(nsIURI *aURI,
+                                        nsISimpleEnumerator **_retval);
+  NS_OVERRIDE NS_IMETHOD GetStyleOverlays(nsIURI *aURI,
+                                          nsISimpleEnumerator **_retval);
+#endif
+  
+#ifdef MOZ_IPC
+  void SendRegisteredChrome(mozilla::dom::PContentProcessParent* aChild);
+#endif
+
+ private:
+#ifdef MOZ_IPC
+  static PLDHashOperator CollectPackages(PLDHashTable *table,
+                                         PLDHashEntryHdr *entry,
+                                         PRUint32 number, void *arg);
+#endif
+
+  NS_HIDDEN_(nsresult) ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly);
+  NS_HIDDEN_(nsresult) ProcessManifestBuffer(char *aBuffer, PRInt32 aLength, nsILocalFile* aManifest, PRBool aSkinOnly);
+
+  nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
+  NS_OVERRIDE nsresult GetBaseURIFromPackage(const nsCString& aPackage,
+                                             const nsCString& aProvider,
+                                             const nsCString& aPath,
+                                             nsIURI* *aResult);
+  NS_OVERRIDE nsresult GetFlagsFromPackage(const nsCString& aPackage,
+                                           PRUint32* aFlags);
+
+  static const PLDHashTableOps kTableOps;
+  static PLDHashNumber HashKey(PLDHashTable *table, const void *key);
+  static PRBool        MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
+                                const void *key);
+  static void          ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry);
+  static PRBool        InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
+                                 const void *key);
+
+  struct ProviderEntry
+  {
+    ProviderEntry(const nsACString& aProvider, nsIURI* aBase) :
+    provider(aProvider),
+    baseURI(aBase) { }
+
+    nsCString        provider;
+    nsCOMPtr<nsIURI> baseURI;
+  };
+
+  class nsProviderArray
+  {
+   public:
+    nsProviderArray() :
+    mArray(1) { }
+    ~nsProviderArray()
+    { Clear(); }
+
+    // When looking up locales and skins, the "selected" locale is not always
+    // available. This enum identifies what kind of match is desired/found.
+    enum MatchType {
+      EXACT = 0,
+      LOCALE = 1, // "en-GB" is selected, we found "en-US"
+      ANY = 2
+    };
+
+    nsIURI* GetBase(const nsACString& aPreferred, MatchType aType);
+    const nsACString& GetSelected(const nsACString& aPreferred, MatchType aType);
+    void    SetBase(const nsACString& aProvider, nsIURI* base);
+    void    EnumerateToArray(nsTArray<nsCString> *a);
+    void    Clear();
+
+   private:
+    ProviderEntry* GetProvider(const nsACString& aPreferred, MatchType aType);
+
+    nsVoidArray mArray;
+  };
+
+  struct PackageEntry : public PLDHashEntryHdr
+  {
+    PackageEntry(const nsACString& package)
+    : package(package), flags(0) { }
+    ~PackageEntry() { }
+
+    nsCString        package;
+    nsCOMPtr<nsIURI> baseURI;
+    PRUint32         flags;
+    nsProviderArray  locales;
+    nsProviderArray  skins;
+  };
+
+  class OverlayListEntry : public nsURIHashKey
+  {
+   public:
+    typedef nsURIHashKey::KeyType        KeyType;
+    typedef nsURIHashKey::KeyTypePointer KeyTypePointer;
+
+    OverlayListEntry(KeyTypePointer aKey) : nsURIHashKey(aKey) { }
+    OverlayListEntry(OverlayListEntry& toCopy) : nsURIHashKey(toCopy),
+                                                 mArray(toCopy.mArray) { }
+    ~OverlayListEntry() { }
+
+    void AddURI(nsIURI* aURI);
+
+    nsCOMArray<nsIURI> mArray;
+  };
+
+  class OverlayListHash
+  {
+   public:
+    OverlayListHash() { }
+    ~OverlayListHash() { }
+
+    PRBool Init() { return mTable.Init(); }
+    void Add(nsIURI* aBase, nsIURI* aOverlay);
+    void Clear() { mTable.Clear(); }
+    const nsCOMArray<nsIURI>* GetArray(nsIURI* aBase);
+
+   private:
+    nsTHashtable<OverlayListEntry> mTable;
+  };
+
+  // Hashes on the file to be overlaid (chrome://browser/content/browser.xul)
+  // to a list of overlays/stylesheets
+  OverlayListHash mOverlayHash;
+  OverlayListHash mStyleHash;
+
+  PRBool mProfileLoaded;
+  
+  nsCString mSelectedLocale;
+  nsCString mSelectedSkin;
+
+  // Hash of package names ("global") to PackageEntry objects
+  PLDHashTable mPackagesHash;
+};
+
+#endif // nsChromeRegistryChrome_h
new file mode 100644
--- /dev/null
+++ b/chrome/src/nsChromeRegistryContent.cpp
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Initial Developer)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "RegistryMessageUtils.h"
+#include "nsChromeRegistry.h"
+#include "nsChromeRegistryContent.h"
+#include "nsString.h"
+#include "nsNetUtil.h"
+#include "nsResProtocolHandler.h"
+
+nsChromeRegistryContent::nsChromeRegistryContent()
+{
+  mPackagesHash.Init();
+}
+
+void
+nsChromeRegistryContent::RegisterRemoteChrome(
+    const nsTArray<ChromePackage>& aPackages,
+    const nsTArray<ResourceMapping>& aResources,
+    const nsTArray<OverrideMapping>& aOverrides)
+{
+  for (PRUint32 i = aPackages.Length(); i > 0; ) {
+    --i;
+    RegisterPackage(aPackages[i]);
+  }
+
+  for (PRUint32 i = aResources.Length(); i > 0; ) {
+    --i;
+    RegisterResource(aResources[i]);
+  }
+
+  for (PRUint32 i = aOverrides.Length(); i > 0; ) {
+    --i;
+    RegisterOverride(aOverrides[i]);
+  }
+}
+
+void
+nsChromeRegistryContent::RegisterPackage(const ChromePackage& aPackage)
+{
+  nsCOMPtr<nsIIOService> io (do_GetIOService());
+  if (!io)
+    return;
+
+  nsCOMPtr<nsIURI> content, locale, skin;
+
+  if (aPackage.contentBaseURI.spec.Length()) {
+    nsresult rv = NS_NewURI(getter_AddRefs(content),
+                            aPackage.contentBaseURI.spec,
+                            aPackage.contentBaseURI.charset.get(),
+                            nsnull, io);
+    if (NS_FAILED(rv))
+      return;
+  }
+  if (aPackage.localeBaseURI.spec.Length()) {
+    nsresult rv = NS_NewURI(getter_AddRefs(locale),
+                            aPackage.localeBaseURI.spec,
+                            aPackage.localeBaseURI.charset.get(),
+                            nsnull, io);
+    if (NS_FAILED(rv))
+      return;
+  }
+  if (aPackage.skinBaseURI.spec.Length()) {
+    nsCOMPtr<nsIURI> skinBaseURI;
+    nsresult rv = NS_NewURI(getter_AddRefs(skin),
+                            aPackage.skinBaseURI.spec,
+                            aPackage.skinBaseURI.charset.get(),
+                            nsnull, io);
+    if (NS_FAILED(rv))
+      return;
+  }
+
+  PackageEntry* entry = new PackageEntry;
+  entry->flags = aPackage.flags;
+  entry->contentBaseURI = content;
+  entry->localeBaseURI = locale;
+  entry->skinBaseURI = skin;
+
+  nsresult rv = mPackagesHash.Put(aPackage.package, entry);
+  if (NS_FAILED(rv))
+    return;
+}
+
+void
+nsChromeRegistryContent::RegisterResource(const ResourceMapping& aResource)
+{
+  nsCOMPtr<nsIIOService> io (do_GetIOService());
+  if (!io)
+    return;
+
+  nsCOMPtr<nsIProtocolHandler> ph;
+  nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+  if (NS_FAILED(rv))
+    return;
+  
+  nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
+  if (!rph)
+    return;
+
+  nsCOMPtr<nsIURI> resolvedURI;
+  if (aResource.resolvedURI.spec.Length()) {
+    nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI),
+                            aResource.resolvedURI.spec,
+                            aResource.resolvedURI.charset.get(),
+                            nsnull, io);                 
+    if (NS_FAILED(rv))
+      return;
+  }
+
+  rv = rph->SetSubstitution(aResource.resource, resolvedURI);
+  if (NS_FAILED(rv))
+    return;
+}
+
+void
+nsChromeRegistryContent::RegisterOverride(const OverrideMapping& aOverride)
+{
+  nsCOMPtr<nsIIOService> io (do_GetIOService());
+  if (!io)
+    return;
+
+  nsCOMPtr<nsIURI> chromeURI, overrideURI;
+  nsresult rv = NS_NewURI(getter_AddRefs(chromeURI),
+                          aOverride.originalURI.spec,
+                          aOverride.originalURI.charset.get(),
+                          nsnull, io);
+  if (NS_FAILED(rv))
+    return;
+
+  rv = NS_NewURI(getter_AddRefs(overrideURI), aOverride.overrideURI.spec,
+                 aOverride.overrideURI.charset.get(), nsnull, io);
+  if (NS_FAILED(rv))
+    return;
+  
+  mOverrideTable.Put(chromeURI, overrideURI);
+}
+
+nsresult
+nsChromeRegistryContent::GetBaseURIFromPackage(const nsCString& aPackage,
+                                               const nsCString& aProvider,
+                                               const nsCString& aPath,
+                                               nsIURI* *aResult)
+{
+  PackageEntry* entry;
+  if (!mPackagesHash.Get(aPackage, &entry)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResult = nsnull;
+  if (aProvider.EqualsLiteral("locale")) {
+    *aResult = entry->localeBaseURI;
+  }
+  else if (aProvider.EqualsLiteral("skin")) {
+    *aResult = entry->skinBaseURI;
+  }
+  else if (aProvider.EqualsLiteral("content")) {
+    *aResult = entry->contentBaseURI;
+  }
+  return NS_OK;
+}
+
+nsresult
+nsChromeRegistryContent::GetFlagsFromPackage(const nsCString& aPackage,
+                                             PRUint32* aFlags)
+{
+  PackageEntry* entry;
+  if (!mPackagesHash.Get(aPackage, &entry)) {
+    return NS_ERROR_FAILURE;
+  }
+  *aFlags = entry->flags;
+  return NS_OK;
+}
+
+// All functions following only make sense in chrome, and therefore assert
+
+#define CONTENT_NOT_IMPLEMENTED() \
+  NS_NOTREACHED("Content should not be calling this"); \
+  return NS_ERROR_NOT_IMPLEMENTED;
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetLocalesForPackage(const nsACString& aPackage,
+                                              nsIUTF8StringEnumerator* *aResult)
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::CheckForOSAccessibility()
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::CheckForNewChrome()
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::IsLocaleRTL(const nsACString& package,
+                                     PRBool *aResult)
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetSelectedLocale(const nsACString& aPackage,
+                                           nsACString& aLocale)
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+  
+NS_IMETHODIMP
+nsChromeRegistryContent::Observe(nsISupports* aSubject, const char* aTopic,
+                                 const PRUnichar* aData)
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetStyleOverlays(nsIURI *aChromeURL,
+                                          nsISimpleEnumerator **aResult)
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetXULOverlays(nsIURI *aChromeURL,
+                                        nsISimpleEnumerator **aResult)
+{
+  CONTENT_NOT_IMPLEMENTED();
+}
new file mode 100644
--- /dev/null
+++ b/chrome/src/nsChromeRegistryContent.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Initial Developer)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsChromeRegistryContent_h
+#define nsChromeRegistryContent_h
+
+#include "nsChromeRegistry.h"
+#include "nsTArray.h"
+#include "nsClassHashtable.h"
+
+class nsCString;
+struct ChromePackage;
+struct ResourceMapping;
+struct OverrideMapping;
+
+class nsChromeRegistryContent : public nsChromeRegistry
+{
+ public:
+  nsChromeRegistryContent();
+  
+  void RegisterRemoteChrome(const nsTArray<ChromePackage>& aPackages,
+                            const nsTArray<ResourceMapping>& aResources,
+                            const nsTArray<OverrideMapping>& aOverrides);
+
+  NS_OVERRIDE NS_IMETHOD GetLocalesForPackage(const nsACString& aPackage,
+                                              nsIUTF8StringEnumerator* *aResult);
+  NS_OVERRIDE NS_IMETHOD CheckForNewChrome();
+  NS_OVERRIDE NS_IMETHOD CheckForOSAccessibility();
+  NS_OVERRIDE NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
+                                 const PRUnichar* aData);
+  NS_OVERRIDE NS_IMETHOD IsLocaleRTL(const nsACString& package,
+                                     PRBool *aResult);
+  NS_OVERRIDE NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+                                           nsACString& aLocale);
+  NS_OVERRIDE NS_IMETHOD GetStyleOverlays(nsIURI *aChromeURL,
+                                          nsISimpleEnumerator **aResult);
+  NS_OVERRIDE NS_IMETHOD GetXULOverlays(nsIURI *aChromeURL,
+                                        nsISimpleEnumerator **aResult);
+
+ private:
+  struct PackageEntry
+  {
+    PackageEntry() : flags(0) { }
+    ~PackageEntry() { }
+
+    nsCOMPtr<nsIURI> contentBaseURI;
+    nsCOMPtr<nsIURI> localeBaseURI;
+    nsCOMPtr<nsIURI> skinBaseURI;
+    PRUint32         flags;
+  };
+  
+  void RegisterPackage(const ChromePackage& aPackage);
+  void RegisterResource(const ResourceMapping& aResource);
+  void RegisterOverride(const OverrideMapping& aOverride);
+
+  NS_OVERRIDE nsresult GetBaseURIFromPackage(const nsCString& aPackage,
+                                 const nsCString& aProvider,
+                                 const nsCString& aPath,
+                                 nsIURI* *aResult);
+  NS_OVERRIDE nsresult GetFlagsFromPackage(const nsCString& aPackage, PRUint32* aFlags);
+
+  nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
+};
+
+#endif // nsChromeRegistryContent_h
--- a/chrome/test/Makefile.in
+++ b/chrome/test/Makefile.in
@@ -41,10 +41,13 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = test_chrome
 
 XPCSHELL_TESTS = unit \
                  $(NULL)
+ifdef MOZ_IPC
+XPCSHELL_TESTS += unit_ipc
+endif
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit/data/test_resolve_uris.manifest
@@ -0,0 +1,5 @@
+resource foo resource://foo/foo-resource/
+content foo resource://foo/foo-content/
+locale foo foo resource://foo/foo-locale/
+skin foo foo resource://foo/foo-skin/
+override chrome://good-package/content/override-me.xul resource://foo/foo-override/override-me.xul
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit/test_resolve_uris.js
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Chrome Registration Test Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// head_crtestutils.js doesn't get included in the child by default
+if (typeof registerManifests === "undefined") {
+  load("../unit/head_crtestutils.js");
+}
+
+let manifests = [
+    do_get_file("../unit/data/test_resolve_uris.manifest"),
+];
+registerManifests(manifests);
+
+function do_run_test()
+{
+  let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+           getService(Ci.nsIChromeRegistry);
+
+  var runtime = Components.classes["@mozilla.org/xre/app-info;1"]
+                .getService(Components.interfaces.nsIXULRuntime);
+  if (runtime.processType ==
+      Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
+    cr.checkForNewChrome();
+  }
+
+  // See if our various things were able to register
+  let registrationTypes = [
+      "content",
+      "locale",
+      "skin",
+      "override",
+      "resource",
+  ];
+
+  for (let j = 0; j < registrationTypes.length; j++) {
+    let type = registrationTypes[j];
+    dump("Testing type '" + type + "'\n");
+    let expectedURI = "resource://foo/foo-" + type + "/";
+    let sourceURI = "chrome://foo/" + type + "/";
+    switch (type) {
+      case "content":
+        expectedURI += "foo.xul";
+        break;
+      case "locale":
+        expectedURI += "foo.dtd";
+        break;
+      case "skin":
+        expectedURI += "foo.css";
+        break;
+      case "override":
+        sourceURI = "chrome://good-package/content/override-me.xul";
+        expectedURI += "override-me.xul";
+        break;
+      case "resource":
+        sourceURI = "resource://foo/";
+        break;
+    };
+    try {
+      let ios = Cc["@mozilla.org/network/io-service;1"].
+                getService(Ci.nsIIOService);
+      sourceURI = ios.newURI(sourceURI, null, null);
+      let uri;
+      if (type == "resource") {
+        // resources go about a slightly different way than everything else
+        let rph = ios.getProtocolHandler("resource").
+            QueryInterface(Ci.nsIResProtocolHandler);
+        uri = rph.resolveURI(sourceURI);
+      }
+      else {
+        uri = cr.convertChromeURL(sourceURI).spec;
+      }
+      
+      do_check_eq(expectedURI, uri);
+    }
+    catch (e) {
+      dump(e + "\n");
+      do_throw("Should have registered a handler for type '" +
+               type + "'\n");
+    }
+  }
+}
+
+if (typeof run_test === "undefined") {
+  run_test = function() {
+    do_run_test();
+  };
+}
new file mode 100644
--- /dev/null
+++ b/chrome/test/unit_ipc/test_resolve_uris_ipc.js
@@ -0,0 +1,9 @@
+//
+// Run test script in content process instead of chrome (xpcshell's default)
+//
+
+function run_test() {
+  load("../unit/test_resolve_uris.js");
+  do_run_test();
+  run_test_in_child("../unit/test_resolve_uris.js");
+}
--- a/dom/ipc/ContentProcessChild.cpp
+++ b/dom/ipc/ContentProcessChild.cpp
@@ -46,16 +46,19 @@
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/net/NeckoChild.h"
 
 #include "nsXULAppAPI.h"
 
 #include "base/message_loop.h"
 #include "base/task.h"
 
+#include "nsChromeRegistryContent.h"
+#include "mozilla/chrome/RegistryMessageUtils.h"
+
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 
 #ifdef MOZ_WIDGET_QT
 extern int    gArgc;
 extern char **gArgv;
 #endif
 
@@ -136,16 +139,28 @@ ContentProcessChild::AllocPNecko()
 
 bool 
 ContentProcessChild::DeallocPNecko(PNeckoChild* necko)
 {
     delete necko;
     return true;
 }
 
+bool
+ContentProcessChild::RecvRegisterChrome(const nsTArray<ChromePackage>& packages,
+                                        const nsTArray<ResourceMapping>& resources,
+                                        const nsTArray<OverrideMapping>& overrides)
+{
+    nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
+    nsChromeRegistryContent* chromeRegistry =
+        static_cast<nsChromeRegistryContent*>(registrySvc.get());
+    chromeRegistry->RegisterRemoteChrome(packages, resources, overrides);
+    return true;
+}
+
 void
 ContentProcessChild::Quit()
 {
     NS_ASSERTION(mQuit, "Exiting uncleanly!");
     mIFrames.Clear();
     mTestShells.Clear();
 }
 
--- a/dom/ipc/ContentProcessChild.h
+++ b/dom/ipc/ContentProcessChild.h
@@ -43,16 +43,20 @@
 
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 
 #ifdef MOZ_WIDGET_QT
 class QApplication;
 #endif
 
+struct ChromePackage;
+struct ResourceMapping;
+struct OverrideMapping;
+
 namespace mozilla {
 namespace dom {
 
 class ContentProcessChild : public PContentProcessChild
 {
 public:
     ContentProcessChild();
     virtual ~ContentProcessChild();
@@ -70,16 +74,20 @@ public:
     virtual bool DeallocPIFrameEmbedding(PIFrameEmbeddingChild*);
 
     virtual PTestShellChild* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellChild*);
 
     virtual PNeckoChild* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoChild*);
 
+    virtual bool RecvRegisterChrome(const nsTArray<ChromePackage>& packages,
+                                    const nsTArray<ResourceMapping>& resources,
+                                    const nsTArray<OverrideMapping>& overrides);
+
 private:
     NS_OVERRIDE
     virtual void ActorDestroy(ActorDestroyReason why);
 
     void Quit();
 
     static ContentProcessChild* sSingleton;
 
--- a/dom/ipc/ContentProcessParent.cpp
+++ b/dom/ipc/ContentProcessParent.cpp
@@ -43,16 +43,17 @@
 #include "mozilla/net/NeckoParent.h"
 
 #include "nsIObserverService.h"
 
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
+#include "nsChromeRegistryChrome.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 using mozilla::MonitorAutoEnter;
 
 namespace {
 PRBool gSingletonDied = PR_FALSE;
 }
@@ -125,16 +126,21 @@ ContentProcessParent::DestroyTestShell(T
 ContentProcessParent::ContentProcessParent()
     : mMonitor("ContentProcessParent::mMonitor")
     , mRunToCompletionDepth(0)
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
     mSubprocess->AsyncLaunch();
     Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
+
+    nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
+    nsChromeRegistryChrome* chromeRegistry =
+        static_cast<nsChromeRegistryChrome*>(registrySvc.get());
+    chromeRegistry->SendRegisteredChrome(this);
 }
 
 ContentProcessParent::~ContentProcessParent()
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     NS_ASSERTION(gSingleton == this, "More than one singleton?!");
     gSingletonDied = PR_TRUE;
     gSingleton = nsnull;
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -72,11 +72,12 @@ CPPSRCS = \
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
 		-I$(srcdir)/../../content/base/src \
 		-I$(srcdir)/../../content/events/src \
+		-I$(topsrcdir)/chrome/src \
 		$(NULL)
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
--- a/dom/ipc/PContentProcess.ipdl
+++ b/dom/ipc/PContentProcess.ipdl
@@ -36,29 +36,37 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 include protocol "PIFrameEmbedding.ipdl";
 include protocol "PTestShell.ipdl";
 include protocol "PNecko.ipdl";
 
 include "mozilla/TabTypes.h";
+include "mozilla/chrome/RegistryMessageUtils.h";
+
+using ChromePackage;
+using ResourceMapping;
+using OverrideMapping;
 
 namespace mozilla {
 namespace dom {
 
 rpc protocol PContentProcess
 {
     manages PIFrameEmbedding;
     manages PTestShell;
     manages PNecko;
 
 child:
     PIFrameEmbedding();
 
     PTestShell();
 
+    RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
+                   OverrideMapping[] overrides);
+
 parent:
     PNecko();
 };
 
 }
 }
--- a/netwerk/protocol/res/src/Makefile.in
+++ b/netwerk/protocol/res/src/Makefile.in
@@ -56,11 +56,13 @@ EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
 LOCAL_INCLUDES =                        \
         -I$(topsrcdir)/netwerk/base/src \
         $(NULL)
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
--- a/netwerk/protocol/res/src/nsResProtocolHandler.cpp
+++ b/netwerk/protocol/res/src/nsResProtocolHandler.cpp
@@ -33,16 +33,20 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifdef MOZ_IPC
+#include "mozilla/chrome/RegistryMessageUtils.h"
+#endif
+
 #include "nsResProtocolHandler.h"
 #include "nsAutoLock.h"
 #include "nsIURL.h"
 #include "nsIIOService.h"
 #include "nsIServiceManager.h"
 #include "nsILocalFile.h"
 #include "prenv.h"
 #include "prmem.h"
@@ -67,18 +71,16 @@ static nsResProtocolHandler *gResHandler
 //    set NSPR_LOG_MODULES=nsResProtocol:5
 //    set NSPR_LOG_FILE=log.txt
 //
 // this enables PR_LOG_ALWAYS level information and places all output in
 // the file log.txt
 //
 static PRLogModuleInfo *gResLog;
 #endif
-#define LOG(args) PR_LOG(gResLog, PR_LOG_DEBUG, args)
-
 #define kGRE_RESOURCES NS_LITERAL_CSTRING("gre-resources")
 
 //----------------------------------------------------------------------------
 // nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution
 //----------------------------------------------------------------------------
 
 nsresult
 nsResURL::EnsureFile()
@@ -203,16 +205,44 @@ nsResProtocolHandler::Init()
     // but once I finish multiple chrome registration I'm not sure that it is needed
 
     // XXX dveditz: resource://pchrome/ defeats profile directory salting
     // if web content can load it. Tread carefully.
 
     return rv;
 }
 
+#ifdef MOZ_IPC
+static PLDHashOperator
+EnumerateSubstitution(const nsACString& aKey,
+                      nsIURI* aURI,
+                      void* aArg)
+{
+    nsTArray<ResourceMapping>* resources =
+            static_cast<nsTArray<ResourceMapping>*>(aArg);
+    SerializedURI uri;
+    if (aURI) {
+        aURI->GetSpec(uri.spec);
+        aURI->GetOriginCharset(uri.charset);
+    }
+
+    ResourceMapping resource = {
+        nsDependentCString(aKey), uri
+    };
+    resources->AppendElement(resource);
+    return (PLDHashOperator)PL_DHASH_NEXT;
+}
+
+void
+nsResProtocolHandler::CollectSubstitutions(nsTArray<ResourceMapping>& aResources)
+{
+    mSubstitutions.EnumerateRead(&EnumerateSubstitution, &aResources);
+}
+#endif
+
 //----------------------------------------------------------------------------
 // nsResProtocolHandler::nsISupports
 //----------------------------------------------------------------------------
 
 NS_IMPL_THREADSAFE_ISUPPORTS3(nsResProtocolHandler,
                               nsIResProtocolHandler,
                               nsIProtocolHandler,
                               nsISupportsWeakReference)
@@ -408,13 +438,14 @@ nsResProtocolHandler::ResolveURI(nsIURI 
     if (NS_FAILED(rv)) return rv;
 
     rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result);
 
 #if defined(PR_LOGGING)
     if (PR_LOG_TEST(gResLog, PR_LOG_DEBUG)) {
         nsCAutoString spec;
         uri->GetAsciiSpec(spec);
-        LOG(("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
+        PR_LOG(gResLog, PR_LOG_DEBUG,
+               ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
     }
 #endif
     return rv;
 }
--- a/netwerk/protocol/res/src/nsResProtocolHandler.h
+++ b/netwerk/protocol/res/src/nsResProtocolHandler.h
@@ -42,16 +42,18 @@
 
 #include "nsIResProtocolHandler.h"
 #include "nsInterfaceHashtable.h"
 #include "nsISupportsArray.h"
 #include "nsIIOService.h"
 #include "nsWeakReference.h"
 #include "nsStandardURL.h"
 
+struct ResourceMapping;
+
 // nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution
 class nsResURL : public nsStandardURL
 {
 public:
     nsResURL() : nsStandardURL(PR_TRUE) {}
     virtual nsStandardURL* StartClone();
     virtual nsresult EnsureFile();
     NS_IMETHOD GetClassIDNoAlloc(nsCID *aCID);
@@ -64,16 +66,20 @@ public:
     NS_DECL_NSIPROTOCOLHANDLER
     NS_DECL_NSIRESPROTOCOLHANDLER
 
     nsResProtocolHandler();
     virtual ~nsResProtocolHandler();
 
     nsresult Init();
 
+#ifdef MOZ_IPC    
+    void CollectSubstitutions(nsTArray<ResourceMapping>& aResources);
+#endif
+
 private:
     nsresult AddSpecialDir(const char* aSpecialDir, const nsACString& aSubstitution);
     nsInterfaceHashtable<nsCStringHashKey,nsIURI> mSubstitutions;
     nsCOMPtr<nsIIOService> mIOService;
 
     friend class nsResURL;
 };