Bug 568691 part C - Register all components based on reading .manifest files from the components directories. Binary components auto-register using "binary-component name.dll". JS components register using "component CID file.js" "contract @mozilla.org/contract;1 CID" and "category categoryname keyname value".
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 11 Jun 2010 16:13:26 -0400
changeset 47005 c5827927d1403dfd94ab40c9235c1e0202684aa0
parent 47004 1b5cdc6d408502cc4721847482b4809f8a3dc427
child 47007 6f1e1300abcd96e3b5f7fd5bbab69fd836c1c2bf
push idunknown
push userunknown
push dateunknown
bugs568691
milestone1.9.3a6pre
Bug 568691 part C - Register all components based on reading .manifest files from the components directories. Binary components auto-register using "binary-component name.dll". JS components register using "component CID file.js" "contract @mozilla.org/contract;1 CID" and "category categoryname keyname value". This patch has some bugs, specifically we stop looking for .manifest files in chrome/. I will fix that in a followup. It also probably breaks non-libxul builds because of ordering issues. Another followup will actually fix our in-tree JS components and add build machinery for creating a proper components.manifest file.
chrome/src/Makefile.in
chrome/src/nsChromeFactory.cpp
chrome/src/nsChromeRegistry.cpp
chrome/src/nsChromeRegistry.h
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/loader/mozJSComponentLoader.h
toolkit/library/libxul-config.mk
toolkit/library/nsStaticXULComponents.cpp
toolkit/toolkit-tiers.mk
xpcom/Makefile.in
xpcom/build/Makefile.in
xpcom/build/dlldeps.cpp
xpcom/build/nsXPComInit.cpp
xpcom/build/nsXULAppAPI.h
xpcom/components/Makefile.in
xpcom/components/ManifestParser.cpp
xpcom/components/ManifestParser.h
xpcom/components/nsComponentManager.cpp
xpcom/components/nsComponentManager.h
xpcom/glue/nsClassHashtable.h
xpcom/sample/Makefile.in
xpcom/sample/nsSample.js
xpcom/sample/nsSample.manifest
xpcom/tests/TestRegistrationOrder.cpp
--- a/chrome/src/Makefile.in
+++ b/chrome/src/Makefile.in
@@ -38,26 +38,22 @@
 DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE          = chrome
-LIBRARY_NAME    = chrome
-EXPORT_LIBRARY = 1
-IS_COMPONENT    = 1
-MODULE_NAME     = nsChromeModule
-GRE_MODULE      = 1
+LIBRARY_NAME    = chrome_s
 LIBXUL_LIBRARY  = 1
+FORCE_STATIC_LIB = 1
 
 
 CPPSRCS		= \
-		nsChromeFactory.cpp \
 		nsChromeRegistry.cpp \
 		nsChromeProtocolHandler.cpp \
 		$(NULL)
 
 EXTRA_DSO_LDOPTS = \
                 $(MOZ_UNICHARUTIL_LIBS) \
                 $(MOZ_COMPONENT_LIBS) \
                 $(NULL)
@@ -71,8 +67,12 @@ EXTRA_DSO_LDOPTS += $(TK_LIBS)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS          += $(MOZ_GTK2_CFLAGS)
 endif
 
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/xpcom/components \
+  -I$(DEPTH)/xpcom \
+  $(NULL)
deleted file mode 100644
--- a/chrome/src/nsChromeFactory.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** 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
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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 "nsCOMPtr.h"
-#include "mozilla/ModuleUtils.h"
-
-#include "nsIServiceManager.h"
-#include "nsIComponentManager.h"
-#include "nsIChromeRegistry.h"
-#include "nscore.h"
-#include "nsChromeProtocolHandler.h"
-#include "nsChromeRegistry.h"
-
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsChromeRegistry, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsChromeProtocolHandler)
-
-NS_DEFINE_NAMED_CID(NS_CHROMEREGISTRY_CID);
-NS_DEFINE_NAMED_CID(NS_CHROMEPROTOCOLHANDLER_CID);
-
-static const mozilla::Module::CIDEntry kChromeCIDs[] = {
-    { &kNS_CHROMEREGISTRY_CID, false, NULL, nsChromeRegistryConstructor },
-    { &kNS_CHROMEPROTOCOLHANDLER_CID, false, NULL, nsChromeProtocolHandlerConstructor },
-    { NULL }
-};
-
-static const mozilla::Module::ContractIDEntry kChromeContracts[] = {
-    { NS_CHROMEREGISTRY_CONTRACTID, &kNS_CHROMEREGISTRY_CID },
-    { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "chrome", &kNS_CHROMEPROTOCOLHANDLER_CID },
-    { NULL }
-};
-
-static const mozilla::Module kChromeModule = {
-    mozilla::Module::kVersion,
-    kChromeCIDs,
-    kChromeContracts
-};
-
-NSMODULE_DEFN(nsChromeModule) = &kChromeModule;
-
--- a/chrome/src/nsChromeRegistry.cpp
+++ b/chrome/src/nsChromeRegistry.cpp
@@ -50,16 +50,17 @@
 #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 "nsComponentManager.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"
@@ -457,27 +458,18 @@ nsresult
 nsChromeRegistry::Init()
 {
   nsresult rv;
 
   // Check to see if necko and the JAR protocol handler are registered yet
   // if not, somebody is doing work during XPCOM registration that they
   // shouldn't be doing. See bug 292549, where JS components are trying
   // to call Components.utils.import("chrome:///") early in registration
-
-  nsCOMPtr<nsIIOService> io (do_GetIOService());
-  if (!io) return NS_ERROR_FAILURE;
-
-  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;
+  NS_ASSERTION(nsCOMPtr<nsIIOService>(mozilla::services::GetIOService()),
+               "I/O service not registered or available early enough?");
 
   if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
                          nsnull, sizeof(PackageEntry), 16))
     return NS_ERROR_FAILURE;
 
   if (!mOverlayHash.Init() ||
       !mStyleHash.Init() ||
       !mOverrideTable.Init())
@@ -526,18 +518,16 @@ nsChromeRegistry::Init()
 
   nsCOMPtr<nsIObserverService> obsService =
     mozilla::services::GetObserverService();
   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()
 {
@@ -1142,111 +1132,22 @@ 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;
-    }
-
-    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());
-    }
-  }
-
+  nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
   return NS_OK;
 }
 
 NS_IMETHODIMP_(PRBool)
 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
 {
   nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
   if (!chromeURL)
@@ -1346,822 +1247,288 @@ NS_IMETHODIMP nsChromeRegistry::Observe(
   }
   else {
     NS_ERROR("Unexpected observer topic!");
   }
 
   return rv;
 }
 
-nsresult
-nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
+nsIURI*
+nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
 {
-  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";
+  if (!mManifestURI) {
+    nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
+    if (!io) {
+      NS_WARNING("No IO service trying to process chrome manifests");
+      return NULL;
+    }
 
-/**
- * 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;
+    io->NewFileURI(mFile, getter_AddRefs(mManifestURI));
   }
-
-  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;
+  return mManifestURI;
 }
 
-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)
+nsIXPConnect*
+nsChromeRegistry::ManifestProcessingContext::GetXPConnect()
 {
-  if (aData.Length() < aFlag.Length() + 1)
-    return PR_FALSE;
-
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
+  if (!mXPConnect)
+    mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
 
-  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;
+  return mXPConnect;
 }
 
-/**
- * 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)
+already_AddRefed<nsIURI>
+nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
 {
-  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;
+  nsIURI* baseuri = GetManifestURI();
+  if (!baseuri)
+    return NULL;
 
-  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;
-  }
+  nsCOMPtr<nsIURI> resolved;
+  nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
+  if (NS_FAILED(rv))
+    return NULL;
 
-  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;
+  return resolved.forget();
 }
 
 static void
 EnsureLowerCase(char *aBuf)
 {
   for (; *aBuf; ++aBuf) {
     char ch = *aBuf;
     if (ch >= 'A' && ch <= 'Z')
       *aBuf = ch + 'a' - 'A';
   }
 }
 
-nsresult
-nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
-                                        nsILocalFile* aManifest,
-                                        PRBool aSkinOnly)
+void
+nsChromeRegistry::ManifestContent(ManifestProcessingContext& cx, int lineno,
+                                  char *const * argv, bool platform, bool contentaccessible)
 {
-  nsresult rv;
+  char* package = argv[0];
+  char* uri = argv[1];
+
+  EnsureLowerCase(package);
+
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
+
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, cannot register non-local URI '%s' as content.",
+                          uri);
+    return;
+  }
+
+  PackageEntry* entry =
+    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                    & (const nsACString&) nsDependentCString(package),
+                                                    PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->baseURI = resolved;
+
+  if (platform)
+    entry->flags |= PackageEntry::PLATFORM_PACKAGE;
+  if (contentaccessible)
+    entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
+  if (cx.GetXPConnect()) {
+    nsCAutoString urlp("chrome://");
+    urlp.Append(package);
+    urlp.Append('/');
+
+    cx.GetXPConnect()->FlagSystemFilenamePrefix(urlp.get(), true);
+  }
+}
+
+void
+nsChromeRegistry::ManifestLocale(ManifestProcessingContext& cx, int lineno,
+                                 char *const * argv, bool platform, bool contentaccessible)
+{
+  char* package = argv[0];
+  char* provider = argv[1];
+  char* uri = argv[2];
+
+  EnsureLowerCase(package);
+
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
+
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, cannot register non-local URI '%s' as content.",
+                          uri);
+    return;
+  }
+
+  PackageEntry* entry =
+    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                    & (const nsACString&) nsDependentCString(package),
+                                                    PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->locales.SetBase(nsDependentCString(provider), resolved);
+}
+
+void
+nsChromeRegistry::ManifestSkin(ManifestProcessingContext& cx, int lineno,
+                               char *const * argv, bool platform, bool contentaccessible)
+{
+  char* package = argv[0];
+  char* provider = argv[1];
+  char* uri = argv[2];
+
+  EnsureLowerCase(package);
+
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
 
-  NS_NAMED_LITERAL_STRING(kPlatform, "platform");
-  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");
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, cannot register non-local URI '%s' as content.",
+                          uri);
+    return;
+  }
+
+  PackageEntry* entry =
+    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                    & (const nsACString&) nsDependentCString(package),
+                                                    PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->skins.SetBase(nsDependentCString(provider), resolved);
+}
+
+void
+nsChromeRegistry::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+                                  char *const * argv, bool platform, bool contentaccessible)
+{
+  char* base = argv[0];
+  char* overlay = argv[1];
+
+  nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
+  nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
+  if (!baseuri || !overlayuri) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI.");
+    return;
+  }
+
+  if (!CanLoadResource(overlayuri)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Cannot register non-local URI '%s' as an overlay.", overlay);
+    return;
+  }
+
+  mOverlayHash.Add(baseuri, overlayuri);
+}
+
+void
+nsChromeRegistry::ManifestStyle(ManifestProcessingContext& cx, int lineno,
+                                char *const * argv, bool platform, bool contentaccessible)
+{
+  char* base = argv[0];
+  char* overlay = argv[1];
 
-  nsCOMPtr<nsIIOService> io (do_GetIOService());
-  if (!io) return NS_ERROR_FAILURE;
+  nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
+  nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
+  if (!baseuri || !overlayuri) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI.");
+    return;
+  }
+
+  if (!CanLoadResource(overlayuri)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Cannot register non-local URI '%s' as a style overlay.", overlay);
+    return;
+  }
+
+  mStyleHash.Add(baseuri, overlayuri);
+}
+
+void
+nsChromeRegistry::ManifestOverride(ManifestProcessingContext& cx, int lineno,
+                                   char *const * argv, bool platform, bool contentaccessible)
+{
+  char* chrome = argv[0];
+  char* resolved = argv[1];
+
+  nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
+  nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
+  if (!chromeuri || !resolveduri) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI.");
+    return;
+  }
+
+  if (!CanLoadResource(resolveduri)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Cannot register non-local URI '%s' for an override.", resolved);
+    return;
+  }
+  mOverrideTable.Put(chromeuri, resolveduri);
+}
+
+void
+nsChromeRegistry::ManifestResource(ManifestProcessingContext& cx, int lineno,
+                                   char *const * argv, bool platform, bool contentaccessible)
+{
+  char* package = argv[0];
+  char* uri = argv[1];
+
+  EnsureLowerCase(package);
+  nsDependentCString host(package);
+
+  nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
+  if (!io) {
+    NS_WARNING("No IO service trying to process chrome manifests");
+    return;
+  }
 
   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);
-      }
-    }
-  }
+  nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+  if (NS_FAILED(rv))
+    return;
   
-  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 modifiers on content packages, but they
-      // are *applied* to content|skin|locale.
-
-      PRBool platform = PR_FALSE;
-      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(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 (contentAccessible)
-        entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
-      if (xpc) {
-        nsCAutoString urlp("chrome://");
-        urlp.Append(package);
-        urlp.Append('/');
-
-        rv = xpc->FlagSystemFilenamePrefix(urlp.get(), true);
-        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<nsIResProtocolHandler> rph = do_QueryInterface(ph);
 
-      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.");
-    }
+  PRBool exists = PR_FALSE;
+  rv = rph->HasSubstitution(host, &exists);
+  if (exists) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Duplicate resource declaration for '%s' ignored.", package);
+    return;
   }
 
-  return NS_OK;
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
+
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Warning: cannot register non-local URI '%s' as a resource.",
+                          uri);
+    return;
+  }
+
+  rph->SetSubstitution(host, resolved);
 }
--- a/chrome/src/nsChromeRegistry.h
+++ b/chrome/src/nsChromeRegistry.h
@@ -50,16 +50,19 @@
 
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsURIHashKey.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
 #include "nsInterfaceHashtable.h"
+#include "nsXULAppAPI.h"
+#include "nsIResProtocolHandler.h"
+#include "nsIXPConnect.h"
 
 struct PRFileDesc;
 class nsIAtom;
 class nsIDOMWindowInternal;
 class nsILocalFile;
 class nsIPrefBranch;
 class nsIRDFDataSource;
 class nsIRDFResource;
@@ -116,29 +119,51 @@ protected:
 
 private:
   nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
 
   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
+public:
+  struct ManifestProcessingContext
+  {
+    ManifestProcessingContext(NSLocationType aType, nsILocalFile* aFile)
+      : mType(aType)
+      , mFile(aFile)
+    { }
+    ~ManifestProcessingContext()
+    { }
+
+    nsIURI* GetManifestURI();
+    nsIXPConnect* GetXPConnect();
+
+    already_AddRefed<nsIURI> ResolveURI(const char* uri);
 
-  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);
+    NSLocationType mType;
+    nsCOMPtr<nsILocalFile> mFile;
+    nsCOMPtr<nsIURI> mManifestURI;
+    nsCOMPtr<nsIXPConnect> mXPConnect;
+  };
+
+  void ManifestContent(ManifestProcessingContext& cx, int lineno,
+                       char *const * argv, bool platform, bool contentaccessible);
+  void ManifestLocale(ManifestProcessingContext& cx, int lineno,
+                      char *const * argv, bool platform, bool contentaccessible);
+  void ManifestSkin(ManifestProcessingContext& cx, int lineno,
+                    char *const * argv, bool platform, bool contentaccessible);
+  void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+                       char *const * argv, bool platform, bool contentaccessible);
+  void ManifestStyle(ManifestProcessingContext& cx, int lineno,
+                     char *const * argv, bool platform, bool contentaccessible);
+  void ManifestOverride(ManifestProcessingContext& cx, int lineno,
+                        char *const * argv, bool platform, bool contentaccessible);
+  void ManifestResource(ManifestProcessingContext& cx, int lineno,
+                        char *const * argv, bool platform, bool contentaccessible);
 
 public:
   struct ProviderEntry
   {
     ProviderEntry(const nsACString& aProvider, nsIURI* aBase) :
       provider(aProvider),
       baseURI(aBase) { }
 
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -750,57 +750,55 @@ mozJSComponentLoader::LoadModule(nsILoca
 
     rv = file_holder->GetJSObject(&file_jsobj);
     if (NS_FAILED(rv)) {
         return NULL;
     }
 
     JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);
 
-    jsval argv[2], retval, NSGetFactory_val;
+    jsval NSGetFactory_val;
 
     if (!JS_GetProperty(cx, entry->global, "NSGetFactory", &NSGetFactory_val) ||
         JSVAL_IS_VOID(NSGetFactory_val)) {
         return NULL;
     }
 
     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
         nsCAutoString path;
         aComponentFile->GetNativePath(path);
 
         JS_ReportError(cx, "%s has NSGetFactory property that is not a function",
                        path.get());
         return NULL;
     }
     
     JSObject *jsGetFactoryObj;
-    if (!JS_ValueToObject(cx, retval, &jsGetFactoryObj) ||
+    if (!JS_ValueToObject(cx, NSGetFactory_val, &jsGetFactoryObj) ||
         !jsGetFactoryObj) {
         /* XXX report error properly */
         return NULL;
     }
 
     rv = xpc->WrapJS(cx, jsGetFactoryObj,
-                     NS_GET_IID(xpcIJSGetFactory), getter_AddRefs(entry->getfactory));
+                     NS_GET_IID(xpcIJSGetFactory), getter_AddRefs(entry->getfactoryobj));
     if (NS_FAILED(rv)) {
         /* XXX report error properly */
 #ifdef DEBUG
         fprintf(stderr, "mJCL: couldn't get nsIModule from jsval\n");
 #endif
         return NULL;
     }
 
     // Cache this module for later
     if (!mModules.Put(lfhash, entry))
         return NULL;
 
     // The hash owns the ModuleEntry now, forget about it
-    entry.forget();
-
-    return entry;
+    return entry.forget();
 }
 
 // Some stack based classes for cleaning up on early return
 #ifdef HAVE_PR_MEMMAP
 class FileAutoCloser
 {
  public:
     explicit FileAutoCloser(PRFileDesc *file) : mFile(file) {}
@@ -1372,24 +1370,32 @@ mozJSComponentLoader::GlobalForLocation(
         *aGlobal = nsnull;
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     JS_AddNamedRoot(cx, aGlobal, *aLocation);
     return NS_OK;
 }
 
+/* static */ PLDHashOperator
+mozJSComponentLoader::ClearModules(nsIHashable* key, ModuleEntry*& entry, void* cx)
+{
+    entry->Clear();
+    return PL_DHASH_REMOVE;
+}
+    
 void
 mozJSComponentLoader::UnloadModules()
 {
     mInitialized = PR_FALSE;
 
     mInProgressImports.Clear();
     mImports.Clear();
-    mModules.Clear();
+
+    mModules.Enumerate(ClearModules, NULL);
 
     // Destroying our context will force a GC.
     JS_DestroyContext(mContext);
     mContext = nsnull;
 
     mRuntimeService = nsnull;
     mContextStack = nsnull;
 #ifdef DEBUG_shaver_off
@@ -1655,16 +1661,31 @@ mozJSComponentLoader::Observe(nsISupport
     }
     else {
         NS_ERROR("Unexpected observer topic.");
     }
 
     return NS_OK;
 }
 
+/* static */ already_AddRefed<nsIFactory>
+mozJSComponentLoader::ModuleEntry::GetFactory(const mozilla::Module& module,
+                                              const mozilla::Module::CIDEntry& entry)
+{
+    const ModuleEntry& self = static_cast<const ModuleEntry&>(module);
+    NS_ASSERTION(self.getfactoryobj, "Handing out an uninitialized module?");
+
+    nsCOMPtr<nsIFactory> f;
+    nsresult rv = self.getfactoryobj->Get(*entry.cid, getter_AddRefs(f));
+    if (NS_FAILED(rv))
+        return NULL;
+
+    return f.forget();
+}
+
 //----------------------------------------------------------------------
 
 JSCLContextHelper::JSCLContextHelper(mozJSComponentLoader *loader)
     : mContext(loader->mContext), mContextThread(0),
       mContextStack(loader->mContextStack)
 {
     mContextStack->Push(mContext);
     mContextThread = JS_GetContextThread(mContext);
--- a/js/src/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.h
@@ -137,42 +137,59 @@ class mozJSComponentLoader : public mozi
 #endif
     JSRuntime *mRuntime;
     JSContext *mContext;
 
     class ModuleEntry : public mozilla::Module
     {
     public:
         ModuleEntry() : mozilla::Module() {
-            
+            mVersion = mozilla::Module::kVersion;
+            mCIDs = NULL;
+            mContractIDs = NULL;
+            mCategoryEntries = NULL;
+            getfactory = GetFactory;
+            loaded = NULL;
+            unloaded = NULL;
+
             global = nsnull;
             location = nsnull;
         }
 
         ~ModuleEntry() {
-            getfactory = NULL;
+            Clear();
+        }
+
+        void Clear() {
+            getfactoryobj = NULL;
 
             if (global) {
                 JSAutoRequest ar(sSelf->mContext);
                 JS_ClearScope(sSelf->mContext, global);
                 JS_RemoveRoot(sSelf->mContext, &global);
             }
 
             if (location)
                 NS_Free(location);
+
+            global = NULL;
+            location = NULL;
         }
 
         static already_AddRefed<nsIFactory> GetFactory(const mozilla::Module& module,
                                                        const mozilla::Module::CIDEntry& entry);
 
-        nsCOMPtr<xpcIJSGetFactory> getfactory;
+        nsCOMPtr<xpcIJSGetFactory> getfactoryobj;
         JSObject            *global;
         char                *location;
     };
 
     friend class ModuleEntry;
 
-    nsClassHashtable<nsHashableHashKey, ModuleEntry> mModules;
+    // Modules are intentionally leaked, but still cleared.
+    static PLDHashOperator ClearModules(nsIHashable* key, ModuleEntry*& entry, void* cx);
+    nsDataHashtable<nsHashableHashKey, ModuleEntry*> mModules;
+
     nsClassHashtable<nsHashableHashKey, ModuleEntry> mImports;
     nsDataHashtable<nsHashableHashKey, ModuleEntry*> mInProgressImports;
 
     PRBool mInitialized;
 };
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -139,17 +139,16 @@ COMPONENT_LIBS += \
 	htmlpars \
 	imglib2 \
 	gklayout \
 	docshell \
 	embedcomponents \
 	webbrwsr \
 	nsappshell \
 	txmgr \
-	chrome \
 	commandlines \
 	extensions \
 	toolkitcomps \
 	pipboot \
 	pipnss \
 	appcomps \
 	$(NULL)
 
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -247,17 +247,16 @@
     MODULE(nsLayoutModule)                   \
     MODULE(docshell_provider)                \
     MODULE(embedcomponents)                  \
     MODULE(Browser_Embedding_Module)         \
     ACCESS_MODULES                           \
     MODULE(appshell)                         \
     MODULE(nsTransactionManagerModule)       \
     COMPOSER_MODULE                          \
-    MODULE(nsChromeModule)                   \
     MODULE(application)                      \
     MODULE(Apprunner)                        \
     MODULE(CommandLineModule)                \
     FILEVIEW_MODULE                          \
     STORAGE_MODULE                           \
     PLACES_MODULES                           \
     XULENABLED_MODULES                       \
     MODULE(AddonsModule)                     \
--- a/toolkit/toolkit-tiers.mk
+++ b/toolkit/toolkit-tiers.mk
@@ -195,17 +195,17 @@ endif
 ifdef ACCESSIBILITY
 tier_platform_dirs    += accessible
 endif
 
 #
 # "toolkit" - xpfe & toolkit
 #
 
-tier_platform_dirs += chrome profile
+tier_platform_dirs += profile
 
 # This must preceed xpfe
 ifdef MOZ_JPROF
 tier_platform_dirs        += tools/jprof
 endif
 
 tier_platform_dirs	+= xpfe/components
 
--- a/xpcom/Makefile.in
+++ b/xpcom/Makefile.in
@@ -52,16 +52,17 @@ DIRS		= \
 		base \
 		ds \
 		io \
 		components \
 		threads \
 		reflect \
 		proxy \
                 system \
+		../chrome \
 		build \
 		$(NULL)
 
 ifndef MOZ_ENABLE_LIBXUL
 DIRS += stub
 endif
 
 ifeq ($(OS_ARCH),WINNT)
--- a/xpcom/build/Makefile.in
+++ b/xpcom/build/Makefile.in
@@ -77,16 +77,17 @@ CPPSRCS += dlldeps.cpp
 endif
 endif
 
 ifdef MOZ_OMNIJAR
 CPPSRCS += Omnijar.cpp
 endif
 
 SHARED_LIBRARY_LIBS = \
+		$(DEPTH)/chrome/src/chrome_s.$(LIB_SUFFIX) \
 		../ds/$(LIB_PREFIX)xpcomds_s.$(LIB_SUFFIX) \
 		../io/$(LIB_PREFIX)xpcomio_s.$(LIB_SUFFIX) \
 		../components/$(LIB_PREFIX)xpcomcomponents_s.$(LIB_SUFFIX) \
 		../threads/$(LIB_PREFIX)xpcomthreads_s.$(LIB_SUFFIX) \
 		../proxy/src/$(LIB_PREFIX)xpcomproxy_s.$(LIB_SUFFIX) \
 		../base/$(LIB_PREFIX)xpcombase_s.$(LIB_SUFFIX) \
 		../reflect/xptcall/src/$(LIB_PREFIX)xptcall.$(LIB_SUFFIX) \
 		../reflect/xptcall/src/$(LIB_PREFIX)xptcmd.$(LIB_SUFFIX) \
@@ -108,16 +109,17 @@ LOCAL_INCLUDES	= \
 		-I$(srcdir)/../base \
 		-I$(srcdir)/../ds \
 		-I$(srcdir)/../io \
 		-I$(srcdir)/../components \
 		-I$(srcdir)/../threads \
 		-I$(srcdir)/../threads/_xpidlgen \
 		-I$(srcdir)/../proxy/src \
 		-I$(srcdir)/../reflect/xptinfo/src \
+		-I$(topsrcdir)/chrome/src \
 		$(NULL)
 
 EXPORTS_NAMESPACES = mozilla
 
 SDK_HEADERS =  \
   nsXPCOM.h       \
   nsXPCOMCID.h    \
   $(NULL)
--- a/xpcom/build/dlldeps.cpp
+++ b/xpcom/build/dlldeps.cpp
@@ -301,10 +301,10 @@ void XXXNeverCalled()
     TimeStamp theTimeStamp = TimeStamp::Now();
     TimeDuration theTimeDuration = TimeDuration::FromMilliseconds(0);
 
     NS_WildCardValid((const char *)nsnull);
     NS_WildCardValid((const PRUnichar *)nsnull);
     NS_WildCardMatch((const char *)nsnull, (const char *)nsnull, PR_FALSE);
     NS_WildCardMatch((const PRUnichar *)nsnull, (const PRUnichar *)nsnull, PR_FALSE);
     XRE_AddStaticComponent(NULL);
-    XRE_AddComponentLocation(NULL);
+    XRE_AddComponentLocation(NS_COMPONENT_LOCATION, NULL);
 }
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -138,16 +138,19 @@ extern nsresult nsStringInputStreamConst
 
 #include "nsSystemInfo.h"
 #include "nsMemoryReporterManager.h"
 
 #include <locale.h>
 #include "mozilla/Services.h"
 #include "mozilla/FunctionTimer.h"
 
+#include "nsChromeRegistry.h"
+#include "nsChromeProtocolHandler.h"
+
 #ifdef MOZ_IPC
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/message_loop.h"
 
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 
 using base::AtExitManager;
@@ -259,16 +262,22 @@ nsXPTIInterfaceInfoManagerGetSingleton(n
 
 nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL;
 PRBool gXPCOMShuttingDown = PR_FALSE;
 
 static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
 static NS_DEFINE_CID(kINIParserFactoryCID, NS_INIPARSERFACTORY_CID);
 static NS_DEFINE_CID(kSimpleUnicharStreamFactoryCID, NS_SIMPLE_UNICHAR_STREAM_FACTORY_CID);
 
+NS_DEFINE_NAMED_CID(NS_CHROMEREGISTRY_CID);
+NS_DEFINE_NAMED_CID(NS_CHROMEPROTOCOLHANDLER_CID);
+
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsChromeRegistry, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsChromeProtocolHandler)
+
 #define NS_PERSISTENTPROPERTIES_CID NS_IPERSISTENTPROPERTIES_CID /* sigh */
 #define NS_XPCOMPROXY_CID NS_PROXYEVENT_MANAGER_CID
 
 static already_AddRefed<nsIFactory>
 CreateINIParserFactory(const mozilla::Module& module,
                        const mozilla::Module::CIDEntry& entry)
 {
     nsIFactory* f = new nsINIParserFactory();
@@ -288,23 +297,27 @@ CreateUnicharStreamFactory(const mozilla
 #undef COMPONENT
 
 #define COMPONENT(NAME, Ctor) { &kNS_##NAME##_CID, false, NULL, Ctor },
 const mozilla::Module::CIDEntry kXPCOMCIDEntries[] = {
     { &kComponentManagerCID, true, NULL, nsComponentManagerImpl::Create },
     { &kINIParserFactoryCID, false, CreateINIParserFactory },
     { &kSimpleUnicharStreamFactoryCID, false, CreateUnicharStreamFactory },
 #include "XPCOMModule.inc"
+    { &kNS_CHROMEREGISTRY_CID, false, NULL, nsChromeRegistryConstructor },
+    { &kNS_CHROMEPROTOCOLHANDLER_CID, false, NULL, nsChromeProtocolHandlerConstructor },
     { NULL }
 };
 #undef COMPONENT
 
 #define COMPONENT(NAME, Ctor) { NS_##NAME##_CONTRACTID, &kNS_##NAME##_CID },
 const mozilla::Module::ContractIDEntry kXPCOMContracts[] = {
 #include "XPCOMModule.inc"
+    { NS_CHROMEREGISTRY_CONTRACTID, &kNS_CHROMEREGISTRY_CID },
+    { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "chrome", &kNS_CHROMEPROTOCOLHANDLER_CID },
     { NULL }
 };
 #undef COMPONENT
 
 const mozilla::Module kXPCOMModule = { mozilla::Module::kVersion, kXPCOMCIDEntries, kXPCOMContracts };
 
 // gDebug will be freed during shutdown.
 static nsIDebug* gDebug = nsnull;
@@ -468,35 +481,28 @@ NS_InitXPCOM2(nsIServiceManager* *result
     }
 #endif
 
     NS_ASSERTION(nsComponentManagerImpl::gComponentManager == NULL, "CompMgr not null at init");
 
     NS_TIME_FUNCTION_MARK("Next: component manager init");
 
     // Create the Component/Service Manager
-    nsComponentManagerImpl *compMgr = new nsComponentManagerImpl();
-    if (compMgr == NULL)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(compMgr);
+    nsComponentManagerImpl::gComponentManager = new nsComponentManagerImpl();
+    NS_ADDREF(nsComponentManagerImpl::gComponentManager);
     
-    rv = compMgr->Init();
+    rv = nsComponentManagerImpl::gComponentManager->Init();
     if (NS_FAILED(rv))
     {
-        NS_RELEASE(compMgr);
+        NS_RELEASE(nsComponentManagerImpl::gComponentManager);
         return rv;
     }
 
-    nsComponentManagerImpl::gComponentManager = compMgr;
-
     if (result) {
-        nsIServiceManager *serviceManager =
-            static_cast<nsIServiceManager*>(compMgr);
-
-        NS_ADDREF(*result = serviceManager);
+        NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
     }
 
     NS_TIME_FUNCTION_MARK("Next: cycle collector startup");
 
     rv = nsCycleCollector_startup();
     if (NS_FAILED(rv)) return rv;
 
     NS_TIME_FUNCTION_MARK("Next: interface info manager init");
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -348,27 +348,41 @@ XRE_API(nsresult,
 
 /**
  * Register static XPCOM component information.
  * This method may be called at any time before or after XRE_main or
  * XRE_InitEmbedding.
  */
 XRE_API(nsresult,
         XRE_AddStaticComponent, (const mozilla::Module* aComponent))
+
 /**
  * Register XPCOM components found in an array of files/directories.
  * This method may be called at any time before or after XRE_main or
  * XRE_InitEmbedding.
  *
  * @param aFiles An array of files or directories.
  * @param aFileCount the number of items in the aFiles array.
  * @note appdir/components is registered automatically.
+ *
+ * NS_COMPONENT_LOCATION specifies a location to search for binary XPCOM
+ * components as well as component/chrome manifest files.
+ *
+ * NS_SKIN_LOCATION specifies a location to search for chrome manifest files
+ * which are only allowed to register only skin packages and style overlays.
  */
+enum NSLocationType
+{
+  NS_COMPONENT_LOCATION,
+  NS_SKIN_LOCATION
+};
+
 XRE_API(nsresult,
-        XRE_AddComponentLocation, (nsILocalFile* aLocation))
+        XRE_AddComponentLocation, (NSLocationType aType,
+                                   nsILocalFile* aLocation))
 
 /**
  * Fire notifications to inform the toolkit about a new profile. This
  * method should be called after XRE_InitEmbedding if the embedder
  * wishes to run with a profile. Normally the embedder should call
  * XRE_LockProfileDirectory to lock the directory before calling this
  * method.
  *
--- a/xpcom/components/Makefile.in
+++ b/xpcom/components/Makefile.in
@@ -41,16 +41,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xpcom
 XPIDL_MODULE	= xpcom_components
 LIBRARY_NAME	= xpcomcomponents_s
 GRE_MODULE	= 1
+LIBXUL_LIBRARY = 1
 MOZILLA_INTERNAL_API = 1
 
 EXPORTS_NAMESPACES = mozilla
 
 EXPORTS	= \
   nsCategoryManagerUtils.h \
   $(NULL)
 
@@ -59,16 +60,17 @@ EXPORTS_mozilla = \
   Module.h \
   ModuleLoader.h \
   ModuleUtils.h \
   $(NULL)
 
 CPPSRCS		= \
 		nsCategoryManager.cpp \
 		nsComponentManager.cpp \
+		ManifestParser.cpp \
 		nsNativeComponentLoader.cpp \
 		GenericFactory.cpp \
 		$(NULL)
 
 SDK_XPIDLSRCS	= \
 		nsIClassInfo.idl	      \
 		nsIComponentRegistrar.idl     \
 		nsIFactory.idl                \
@@ -79,16 +81,17 @@ SDK_XPIDLSRCS	= \
 
 LOCAL_INCLUDES	= \
 	-I$(srcdir)/../reflect/xptinfo/src \
 	-I$(srcdir)/../base \
 	-I$(srcdir)/../thread \
 	-I$(srcdir)/../ds \
 	-I$(srcdir)/../build \
 	-I.. \
+	-I$(topsrcdir)/chrome/src \
 	$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 # Force use of PIC
 FORCE_USE_PIC	= 1
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/xpcom/components/ManifestParser.cpp
@@ -0,0 +1,472 @@
+/* -*- 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 Firefox
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 "ManifestParser.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 "nsTextFormatter.h"
+#include "nsUnicharUtils.h"
+#include "nsVersionComparator.h"
+#include "nsXPCOMCIDInternal.h"
+
+#include "nsIConsoleService.h"
+#include "nsIScriptError.h"
+#include "nsIXULAppInfo.h"
+#include "nsIXULRuntime.h"
+
+struct ManifestDirective
+{
+  const char* directive;
+  int argc;
+
+  // Some directives should only be delivered for NS_COMPONENT_LOCATION
+  // manifests.
+  bool componentonly;
+
+  bool ischrome;
+
+  // The platform/contentaccessible flags only apply to content directives.
+  bool contentflags;
+
+  // Function to handle this directive. This isn't a union because C++ still
+  // hasn't learned how to initialize unions in a sane way.
+  void (nsComponentManagerImpl::*mgrfunc)
+    (nsComponentManagerImpl::ManifestProcessingContext& cx,
+     int lineno, char *const * argv);
+  void (nsChromeRegistry::*regfunc)
+    (nsChromeRegistry::ManifestProcessingContext& cx,
+     int lineno, char *const *argv,
+     bool platform, bool contentaccessible);
+};
+static const ManifestDirective kParsingTable[] = {
+  { "binary-component", 1, true, false, false,
+    &nsComponentManagerImpl::ManifestBinaryComponent, NULL },
+  { "component",        2, true, false, false,
+    &nsComponentManagerImpl::ManifestComponent, NULL },
+  { "contract",         2, true, false, false,
+    &nsComponentManagerImpl::ManifestContract, NULL },
+  { "category",         3, true, false, false,
+    &nsComponentManagerImpl::ManifestCategory, NULL },
+  { "content",          2, true, true,  true,
+    NULL, &nsChromeRegistry::ManifestContent },
+  { "locale",           3, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestLocale },
+  { "skin",             3, false, true,  false,
+    NULL, &nsChromeRegistry::ManifestSkin },
+  { "overlay",          2, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestOverlay },
+  { "style",            2, false, true,  false,
+    NULL, &nsChromeRegistry::ManifestStyle },
+  { "override",         2, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestOverride },
+  { "resource",         2, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestResource }
+};
+
+static const char kWhitespace[] = "\t ";
+static const char kNewlines[]   = "\r\n";
+
+static void LogMessageWithContext(nsILocalFile* aFile, PRUint32 aLineNumber, const char* aMsg, ...)
+{
+  nsCOMPtr<nsIConsoleService> console =
+    do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+  nsCOMPtr<nsIScriptError> error =
+    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
+  if (!console || !error)
+    return;
+
+  va_list args;
+  va_start(args, aMsg);
+  char* formatted = PR_vsmprintf(aMsg, args);
+  va_end(args);
+  if (!formatted)
+    return;
+
+  nsString file;
+  aFile->GetPath(file);
+
+  nsresult rv = error->Init(NS_ConvertUTF8toUTF16(formatted).get(),
+			    file.get(), NULL,
+			    aLineNumber, 0, nsIScriptError::warningFlag,
+			    "chrome registration");
+  PR_smprintf_free(formatted);
+  if (NS_FAILED(rv))
+    return;
+
+  console->LogMessage(error);
+}
+
+/**
+ * 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 bool
+CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, bool& aResult)
+{
+  if (!StringBeginsWith(aData, aFlag))
+    return false;
+
+  if (aFlag.Length() == aData.Length()) {
+    // the data is simply "flag", which is the same as "flag=yes"
+    aResult = true;
+    return true;
+  }
+
+  if (aData.CharAt(aFlag.Length()) != '=') {
+    // the data is "flag2=", which is not anything we care about
+    return false;
+  }
+
+  if (aData.Length() == aFlag.Length() + 1) {
+    aResult = false;
+    return true;
+  }
+
+  switch (aData.CharAt(aFlag.Length() + 1)) {
+  case '1':
+  case 't': //true
+  case 'y': //yes
+    aResult = true;
+    return true;
+
+  case '0':
+  case 'f': //false
+  case 'n': //no
+    aResult = false;
+    return true;
+  }
+
+  return 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 bool
+CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
+                const nsSubstring& aValue, TriState& aResult)
+{
+  if (aData.Length() < aFlag.Length() + 1)
+    return false;
+
+  if (!StringBeginsWith(aData, aFlag))
+    return false;
+
+  bool comparison = true;
+  if (aData[aFlag.Length()] != '=') {
+    if (aData[aFlag.Length()] == '!' &&
+        aData.Length() >= aFlag.Length() + 2 &&
+        aData[aFlag.Length() + 1] == '=')
+      comparison = false;
+    else
+      return 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 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 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 bool
+CheckVersionFlag(const nsString& aFlag, const nsString& aData,
+                 const nsString& aValue, TriState& aResult)
+{
+  if (aData.Length() < aFlag.Length() + 2)
+    return false;
+
+  if (!StringBeginsWith(aData, aFlag))
+    return false;
+
+  if (aValue.Length() == 0) {
+    if (aResult != eOK)
+      aResult = eBad;
+    return 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 false;
+  }
+
+  if (testdata.Length() == 0)
+    return false;
+
+  if (aResult != eOK) {
+    PRInt32 c = NS_CompareVersions(aValue.get(), testdata.get());
+    if ((c == 0 && comparison & COMPARE_EQ) ||
+	(c < 0 && comparison & COMPARE_LT) ||
+	(c > 0 && comparison & COMPARE_GT))
+      aResult = eOK;
+    else
+      aResult = eBad;
+  }
+
+  return true;
+}
+
+void
+ParseManifest(NSLocationType aType, nsILocalFile* aFile, char* buf)
+{
+  nsresult rv;
+
+  nsComponentManagerImpl::ManifestProcessingContext mgrcx(aType, aFile);
+  nsChromeRegistry::ManifestProcessingContext chromecx(aType, aFile);
+
+  NS_NAMED_LITERAL_STRING(kPlatform, "platform");
+  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");
+
+  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;
+
+    const ManifestDirective* directive = NULL;
+    for (const ManifestDirective* d = kParsingTable;
+	 d < kParsingTable + NS_ARRAY_LENGTH(kParsingTable);
+	 ++d) {
+      if (!strcmp(d->directive, token)) {
+	directive = d;
+	break;
+      }
+    }
+    if (!directive) {
+      LogMessageWithContext(aFile, line, "Ignoring unrecognized chrome manifest directive '%s'.", token);
+      continue;
+    }
+    if (directive->componentonly && NS_COMPONENT_LOCATION != aType) {
+      LogMessageWithContext(aFile, line, "Skin manifest not allowed to use '%s' directive.", token);
+      continue;
+    }
+
+    NS_ASSERTION(directive->argc < 4, "Need to reset argv array length");
+    char* argv[4];
+    for (int i = 0; i < directive->argc; ++i)
+      argv[i] = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+
+    if (!argv[directive->argc - 1]) {
+      LogMessageWithContext(aFile, line, "Not enough arguments for chrome manifest directive '%s', expected %i.", token, directive->argc);
+      continue;
+    }
+
+    bool ok = true;
+    TriState stAppVersion = eUnspecified;
+    TriState stApp = eUnspecified;
+    TriState stOsVersion = eUnspecified;
+    TriState stOs = eUnspecified;
+    bool platform = false;
+    bool contentAccessible = false;
+
+    while (NULL != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) {
+      NS_ConvertASCIItoUTF16 wtoken(token);
+      ToLowerCase(wtoken);
+
+      if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+	  CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+	  CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
+	  CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion))
+	continue;
+
+      if (directive->contentflags &&
+	  (CheckFlag(kPlatform, wtoken, platform) ||
+	   CheckFlag(kContentAccessible, wtoken, contentAccessible)))
+	  continue;
+
+      LogMessageWithContext(aFile, line, "Unrecognized chrome manifest modifier '%s'.", token);
+      ok = false;
+    }
+
+    if (!ok || stApp == eBad || stAppVersion == eBad || stOs == eBad || stOsVersion == eBad)
+      continue;
+
+    if (directive->ischrome)
+      (nsChromeRegistry::gChromeRegistry->*(directive->regfunc))
+	(chromecx, line, argv, platform, contentAccessible);
+    else
+      (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))
+	(mgrcx, line, argv);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/components/ManifestParser.h
@@ -0,0 +1,48 @@
+/* -*- 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 Firefox
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ManifestParser_h
+#define ManifestParser_h
+
+#include "nsComponentManager.h"
+#include "nsChromeRegistry.h"
+
+class nsILocalFile;
+
+void ParseManifest(NSLocationType type, nsILocalFile* file, char* buf);
+
+#endif // ManifestParser_h
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -84,16 +84,17 @@
 #include "prcmon.h"
 #include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
 #include "nsThreadUtils.h"
 #include "prthread.h"
 #include "private/pprthred.h"
 #include "nsTArray.h"
 #include "prio.h"
 #include "mozilla/FunctionTimer.h"
+#include "ManifestParser.h"
 
 #include "nsInt64.h"
 #include "nsManifestLineReader.h"
 #include "mozilla/GenericFactory.h"
 #include "nsSupportsPrimitives.h"
 #include "nsArrayEnumerator.h"
 #include "nsStringEnumerator.h"
 
@@ -308,25 +309,26 @@ nsComponentManagerImpl::InitializeStatic
         return;
 
     sStaticModules = new nsTArray<const mozilla::Module*>;
     for (const mozilla::Module *const *staticModules = kPStaticModules;
          *staticModules; ++staticModules)
         sStaticModules->AppendElement(*staticModules);
 }
 
-nsCOMArray<nsILocalFile>* nsComponentManagerImpl::sModuleLocations;
+nsTArray<nsComponentManagerImpl::ComponentLocation>*
+nsComponentManagerImpl::sModuleLocations;
 
 /* static */ void
 nsComponentManagerImpl::InitializeModuleLocations()
 {
     if (sModuleLocations)
         return;
 
-    sModuleLocations = new nsCOMArray<nsILocalFile>;
+    sModuleLocations = new nsTArray<ComponentLocation>;
 }
 
 nsresult nsComponentManagerImpl::Init()
 {
     NS_TIME_FUNCTION;
 
     PR_ASSERT(NOT_INITIALIZED == mStatus);
 
@@ -336,70 +338,85 @@ nsresult nsComponentManagerImpl::Init()
     }
 
     // Initialize our arena
     NS_TIME_FUNCTION_MARK("Next: init component manager arena");
     PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
 
     mFactories.Init(CONTRACTID_HASHTABLE_INITIAL_SIZE);
     mContractIDs.Init(CONTRACTID_HASHTABLE_INITIAL_SIZE);
+    mLoaderMap.Init();
+    mKnownFileModules.Init();
 
     mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
     if (mMon == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
 
     static const char *const kComponents[] = { "components", NULL };
 
     nsCOMPtr<nsILocalFile> greComponents =
         GetLocationFromDirectoryService(NS_GRE_DIR, kComponents);
 
     nsCOMPtr<nsILocalFile> appComponents =
         GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR, kComponents);
     InitializeStaticModules();
     InitializeModuleLocations();
 
+    ComponentLocation* l = sModuleLocations->InsertElementAt(0);
+    l->type = NS_COMPONENT_LOCATION;
+    l->location = appComponents;
+
     PRBool equals = PR_FALSE;
     appComponents->Equals(greComponents, &equals);
-    if (!equals)
-        sModuleLocations->InsertObjectAt(greComponents, 0);
-    sModuleLocations->InsertObjectAt(appComponents, 0);
+    if (!equals) {
+        l = sModuleLocations->InsertElementAt(0);
+        l->type = NS_COMPONENT_LOCATION;
+        l->location = greComponents;
+    }
 
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
            ("nsComponentManager: Initialized."));
 
     NS_TIME_FUNCTION_MARK("Next: init native module loader");
     nsresult rv = mNativeModuleLoader.Init();
     if (NS_FAILED(rv))
         return rv;
 
     nsCategoryManager::GetSingleton()->SuppressNotifications(true);
 
     RegisterModule(&kXPCOMModule, NULL);
 
     for (PRUint32 i = 0; i < sStaticModules->Length(); ++i)
         RegisterModule((*sStaticModules)[i], NULL);
 
-    for (PRInt32 i = 0; i < sModuleLocations->Count(); ++i)
-        RegisterLocation((*sModuleLocations)[i]);
+    for (PRUint32 i = 0; i < sModuleLocations->Length(); ++i) {
+        ComponentLocation& l = sModuleLocations->ElementAt(i);
+        RegisterLocation(l.type, l.location);
+    }
 
     nsCategoryManager::GetSingleton()->SuppressNotifications(false);
 
     mStatus = NORMAL;
 
     return NS_OK;
 }
 
 void
 nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule,
                                        nsILocalFile* aFile)
 {
     nsAutoMonitor mon(mMon);
 
     KnownModule* m = new KnownModule(aModule, aFile);
-    mKnownModules.AppendElement(m);
+    if (aFile) {
+        nsCOMPtr<nsIHashable> h = do_QueryInterface(aFile);
+        mKnownFileModules.Put(h, m);
+    }
+    else
+        mKnownStaticModules.AppendElement(m);
 
     if (aModule->mCIDs) {
         const mozilla::Module::CIDEntry* entry;
         for (entry = aModule->mCIDs; entry->cid; ++entry)
             RegisterCIDEntry(entry, m);
     }
 
     if (aModule->mContractIDs) {
@@ -447,81 +464,278 @@ nsComponentManagerImpl::RegisterContract
         // XXX REPORT ERROR, CID isn't registered
         return;
     }
 
     mContractIDs.Put(nsDependentCString(aEntry->contractid), f);
 }
 
 void
-nsComponentManagerImpl::RegisterLocation(nsILocalFile* aLocation)
+nsComponentManagerImpl::RegisterLocation(NSLocationType aType,
+                                         nsILocalFile* aLocation)
 {
+    nsCOMArray<nsILocalFile> manifests;
+
     PRBool directory = PR_FALSE;
     aLocation->IsDirectory(&directory);
     if (directory)
-        RegisterDirectory(aLocation);
+        RegisterDirectory(aType, aLocation, manifests);
     else
-        RegisterFile(aLocation);
+        RegisterFile(aType, aLocation, manifests);
+
+    for (PRInt32 i = 0; i < manifests.Count(); ++i)
+        RegisterManifestFile(aType, manifests[i]);
 }
 
 void
-nsComponentManagerImpl::RegisterDirectory(nsILocalFile* aDirectory)
+nsComponentManagerImpl::RegisterDirectory(NSLocationType aType,
+                                          nsILocalFile* aDirectory,
+                                          nsCOMArray<nsILocalFile>& aManifests)
 {
     nsCOMPtr<nsISimpleEnumerator> entries;
     aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
     if (!entries)
         return;
 
     PRBool more;
     while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
         nsCOMPtr<nsISupports> supp;
         entries->GetNext(getter_AddRefs(supp));
         nsCOMPtr<nsILocalFile> f = do_QueryInterface(supp);
         if (!f)
             continue;
 
-        RegisterFile(f);
+        RegisterFile(aType, f, aManifests);
     }
 }
 
-void
-nsComponentManagerImpl::RegisterFile(nsILocalFile* aFile)
+static void
+GetExtension(nsILocalFile* file, nsCString& extension)
 {
-    nsCString extension;
-    aFile->GetNativePath(extension);
+    file->GetNativePath(extension);
 
     PRInt32 dotPos = extension.RFindChar('.');
     if (kNotFound == dotPos)
+        extension.Truncate();
+    else
+        extension.Cut(0, dotPos + 1);
+}
+
+void
+nsComponentManagerImpl::RegisterFile(NSLocationType aType,
+                                     nsILocalFile* aFile,
+                                     nsCOMArray<nsILocalFile>& aManifests)
+{
+    nsCString extension;
+    GetExtension(aFile, extension);
+
+    if (NS_COMPONENT_LOCATION == aType) {
+        if (extension.EqualsLiteral("xpt")) {
+            xptiInterfaceInfoManager::GetSingleton()
+                ->RegisterFile(aFile,
+                               xptiInterfaceInfoManager::XPT);
+        }
+        else if (extension.EqualsLiteral("jar")) {
+            xptiInterfaceInfoManager::GetSingleton()
+                ->RegisterFile(aFile,
+                               xptiInterfaceInfoManager::ZIP);
+        }
+    }
+
+    if (extension.LowerCaseEqualsLiteral("manifest"))
+        aManifests.AppendObject(aFile);
+}
+
+namespace {
+struct AutoCloseFD
+{
+    AutoCloseFD()
+        : mFD(NULL)
+    { }
+    ~AutoCloseFD() {
+        if (mFD)
+            PR_Close(mFD);
+    }
+    operator PRFileDesc*() {
+        return mFD;
+    }
+
+    PRFileDesc** operator&() {
+        NS_ASSERTION(!mFD, "Re-opening a file");
+        return &mFD;
+    }
+
+    PRFileDesc* mFD;
+};
+
+} // anonymous namespace
+
+void
+nsComponentManagerImpl::RegisterManifestFile(NSLocationType aType,
+                                             nsILocalFile* aFile)
+{
+    nsresult rv;
+
+    AutoCloseFD fd;
+    rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
+    if (NS_FAILED(rv))
+        return;
+
+    PRFileInfo64 fileInfo;
+    if (PR_SUCCESS != PR_GetOpenFileInfo64(fd, &fileInfo))
+        return;
+
+    if (fileInfo.size > PRInt64(PR_INT32_MAX))
         return;
 
-    extension.Cut(0, dotPos + 1);
-    if (extension.LowerCaseEqualsLiteral(NAKED_DLL_SUFFIX)) {
-        const mozilla::Module* m = mNativeModuleLoader.LoadModule(aFile);
-        if (!m)
+    nsAutoArrayPtr<char> data(new char[PRInt32(fileInfo.size + 1)]);
+
+    for (PRInt32 totalRead = 0; totalRead < fileInfo.size; ) {
+        PRInt32 read = PR_Read(fd, data + totalRead, PRInt32(fileInfo.size));
+        if (read < 0)
             return;
-        RegisterModule(m, aFile);
+        totalRead += read;
+    }
+
+    data[fileInfo.size] = '\0';
+    ParseManifest(aType, aFile, data);
+}
+
+void
+nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* file = argv[0];
+
+    nsCOMPtr<nsIFile> cfile;
+    cx.mFile->GetParent(getter_AddRefs(cfile));
+    nsCOMPtr<nsILocalFile> clfile = do_QueryInterface(cfile);
+
+    nsresult rv = clfile->AppendRelativeNativePath(nsDependentCString(file));
+    if (NS_FAILED(rv)) {
+        NS_WARNING("Couldn't append relative path?");
+        return;
+    }
+
+    const mozilla::Module* m = mNativeModuleLoader.LoadModule(clfile);
+    if (!m) {
+        // XXX report load error
+        return;
+    }
+    RegisterModule(m, clfile);
+}
+
+void
+nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* id = argv[0];
+    char* file = argv[1];
+
+    nsID cid;
+    if (!cid.Parse(id)) {
+        // XXX report parse error
+        return;
+    }
+
+    nsAutoMonitor mon(mMon);
+    nsFactoryEntry* f = mFactories.Get(cid);
+    if (f) {
+        // XXX report double-register error
+        return;
+    }
+
+    nsCOMPtr<nsIFile> cfile;
+    cx.mFile->GetParent(getter_AddRefs(cfile));
+    nsCOMPtr<nsILocalFile> clfile = do_QueryInterface(cfile);
+
+    nsresult rv = clfile->AppendRelativeNativePath(nsDependentCString(file));
+    if (NS_FAILED(rv)) {
+        NS_WARNING("Couldn't append relative path?");
+        return;
     }
-    else if (extension.EqualsLiteral("xpt")) {
-        xptiInterfaceInfoManager::GetSingleton()
-            ->RegisterFile(aFile,
-                           xptiInterfaceInfoManager::XPT);
+
+    nsCOMPtr<nsIHashable> h = do_QueryInterface(clfile);
+    KnownModule* km = mKnownFileModules.Get(h);
+    if (!km) {
+        km = new KnownModule(clfile);
+        mKnownFileModules.Put(h, km);
+    }
+
+    void* place;
+
+    PL_ARENA_ALLOCATE(place, &mArena, sizeof(nsCID));
+    nsID* permanentCID = static_cast<nsID*>(place);
+    *permanentCID = cid;
+
+    PL_ARENA_ALLOCATE(place, &mArena, sizeof(mozilla::Module::CIDEntry));
+    mozilla::Module::CIDEntry* e = new (place) mozilla::Module::CIDEntry();
+    e->cid = permanentCID;
+
+    f = new nsFactoryEntry(e, km);
+    mFactories.Put(cid, f);
+}
+
+void
+nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* contract = argv[0];
+    char* id = argv[1];
+
+    nsID cid;
+    if (!cid.Parse(id)) {
+        // XXX report parse error
+        return;
     }
-    else if (extension.EqualsLiteral("jar")) {
-        xptiInterfaceInfoManager::GetSingleton()
-            ->RegisterFile(aFile,
-                           xptiInterfaceInfoManager::ZIP);
+
+    nsAutoMonitor mon(mMon);
+    nsFactoryEntry* f = mFactories.Get(cid);
+    if (!f) {
+        // XXX report unregistered CID
+        return;
     }
+
+    mContractIDs.Put(nsDependentCString(contract), f);
+}
+
+void
+nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* category = argv[0];
+    char* key = argv[1];
+    char* value = argv[2];
+
+    nsCategoryManager::GetSingleton()->
+        AddCategoryEntry(category, key, value);
+}
+
+void
+nsComponentManagerImpl::RereadChromeManifests()
+{
+    NS_ERROR("XXX Not done!");
+}
+
+bool
+nsComponentManagerImpl::KnownModule::EnsureLoader()
+{
+    if (!mLoader) {
+        nsCString extension;
+        GetExtension(mFile, extension);
+
+        mLoader = nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension);
+    }
+    return !!mLoader;
 }
 
 bool
 nsComponentManagerImpl::KnownModule::Load()
 {
     if (mFailed)
         return false;
     if (!mModule) {
+        if (!EnsureLoader())
+            return false;
         mModule = mLoader->LoadModule(mFile);
         if (!mModule) {
             mFailed = true;
             return false;
         }
     }
     if (!mLoaded) {
         if (mModule->loaded) {
@@ -545,16 +759,18 @@ nsresult nsComponentManagerImpl::Shutdow
     mStatus = SHUTDOWN_IN_PROGRESS;
 
     // Shutdown the component manager
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
 
     // Release all cached factories
     mContractIDs.Clear();
     mFactories.Clear(); // XXX release the objects, don't just clear
+    mLoaderMap.Clear();
+    mKnownFileModules.Clear();
 
     mLoaderData.Clear();
 
     // Unload libraries
     mNativeModuleLoader.UnloadLibraries();
 
     // delete arena for strings and small objects
     PL_FinishArenaPool(&mArena);
@@ -1239,26 +1455,16 @@ nsComponentManagerImpl::LoaderForExtensi
             return NULL;
 
         mLoaderMap.Put(aExt, loader);
     }
 
     return loader.forget();
 }
 
-static void
-ReportLoadFailure(nsIFile* aFile, nsIConsoleService* aCS)
-{
-    nsAutoString message;
-    aFile->GetPath(message);
-    message.Insert(NS_LITERAL_STRING("Failed to load XPCOM component: "), 0);
-
-    aCS->LogStringMessage(message.get());
-}
-
 NS_IMETHODIMP
 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
                                         const char* aName,
                                         const char* aContractID,
                                         nsIFactory* aFactory)
 {
     nsAutoPtr<nsFactoryEntry> f = new nsFactoryEntry(aFactory);
 
@@ -1413,17 +1619,17 @@ nsFactoryEntry::GetFactory()
 
         if (!mModule->Load())
             return NULL;
 
         if (mModule->Module()->getfactory) {
             mFactory = mModule->Module()->getfactory(*mModule->Module(),
                                                     *mCIDEntry);
         }
-        if (mCIDEntry->getfactory) {
+        else if (mCIDEntry->getfactory) {
             mFactory = mCIDEntry->getfactory(*mModule->Module(), *mCIDEntry);
         }
         else {
             NS_ASSERTION(mCIDEntry->constructor, "no getfactory or constructor");
             mFactory = new mozilla::GenericFactory(mCIDEntry->constructor);
         }
         if (!mFactory)
             return NULL;
@@ -1476,19 +1682,22 @@ XRE_AddStaticComponent(const mozilla::Mo
     if (nsComponentManagerImpl::gComponentManager &&
         nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
         nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent, NULL);
 
     return NS_OK;
 }
 
 EXPORT_XPCOM_API(nsresult)
-XRE_AddComponentLocation(nsILocalFile* aLocation)
+XRE_AddComponentLocation(NSLocationType aType, nsILocalFile* aLocation)
 {
     nsComponentManagerImpl::InitializeModuleLocations();
-    nsComponentManagerImpl::sModuleLocations->AppendObject(aLocation);
+    nsComponentManagerImpl::ComponentLocation* c = 
+        nsComponentManagerImpl::sModuleLocations->AppendElement();
+    c->type = aType;
+    c->location = aLocation;
 
     if (nsComponentManagerImpl::gComponentManager &&
         nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
-        nsComponentManagerImpl::gComponentManager->RegisterLocation(aLocation);
+        nsComponentManagerImpl::gComponentManager->RegisterLocation(aType, aLocation);
 
     return NS_OK;
 }
--- a/xpcom/components/nsComponentManager.h
+++ b/xpcom/components/nsComponentManager.h
@@ -42,31 +42,33 @@
 
 #include "xpcom-private.h"
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsIServiceManager.h"
 #include "nsILocalFile.h"
 #include "mozilla/Module.h"
 #include "mozilla/ModuleLoader.h"
+#include "nsXULAppAPI.h"
 #include "nsNativeComponentLoader.h"
 #include "nsIFactory.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "pldhash.h"
 #include "prtime.h"
 #include "prmon.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
 #include "nsIFile.h"
 #include "plarena.h"
 #include "nsCOMArray.h"
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
+#include "nsClassHashtable.h"
 #include "nsTArray.h"
 
 struct nsFactoryEntry;
 class nsIServiceManager;
 struct PRThread;
 
 #define NS_COMPONENTMANAGER_CID                      \
 { /* 91775d60-d5dc-11d2-92fb-00e09805570f */         \
@@ -152,74 +154,111 @@ public:
     nsDataHashtable<nsIDHashKey, nsFactoryEntry*> mFactories;
     nsDataHashtable<nsCStringHashKey, nsFactoryEntry*> mContractIDs;
 
     PRMonitor*          mMon;
 
     static void InitializeStaticModules();
     static void InitializeModuleLocations();
 
+    struct ComponentLocation
+    {
+        NSLocationType type;
+        nsCOMPtr<nsILocalFile> location;
+    };
+
     static nsTArray<const mozilla::Module*>* sStaticModules;
-    static nsCOMArray<nsILocalFile>* sModuleLocations;
+    static nsTArray<ComponentLocation>* sModuleLocations;
 
     nsNativeModuleLoader mNativeModuleLoader;
 
     class KnownModule
     {
     public:
         /**
          * Static or binary module.
          */
         KnownModule(const mozilla::Module* aModule, nsILocalFile* aFile)
             : mModule(aModule)
             , mFile(aFile)
             , mLoaded(false)
             , mFailed(false)
         { }
 
-        KnownModule(nsILocalFile* aFile, mozilla::ModuleLoader* aLoader)
+        KnownModule(nsILocalFile* aFile)
             : mModule(NULL)
             , mFile(aFile)
-            , mLoader(aLoader)
+            , mLoader(NULL)
             , mLoaded(false)
             , mFailed(false)
         { }
 
         ~KnownModule()
         {
             if (mLoaded && mModule->unloaded)
                 mModule->unloaded();
         }
 
+        bool EnsureLoader();
         bool Load();
 
         const mozilla::Module* Module() const
         {
             return mModule;
         }
 
     private:
         const mozilla::Module* mModule;
         nsCOMPtr<nsILocalFile> mFile;
         nsCOMPtr<mozilla::ModuleLoader> mLoader;
         bool mLoaded;
         bool mFailed;
     };
 
-    nsTArray< nsAutoPtr<KnownModule> > mKnownModules;
+    // The KnownModule is kept alive by these members, it is referenced by pointer
+    // from the factory entries.
+    nsTArray< nsAutoPtr<KnownModule> > mKnownStaticModules;
+    nsClassHashtable<nsHashableHashKey, KnownModule> mKnownFileModules;
 
     void RegisterModule(const mozilla::Module* aModule,
                         nsILocalFile* aFile);
     void RegisterCIDEntry(const mozilla::Module::CIDEntry* aEntry,
                           KnownModule* aModule);
     void RegisterContractID(const mozilla::Module::ContractIDEntry* aEntry);
 
-    void RegisterLocation(nsILocalFile* aLocation);
-    void RegisterDirectory(nsILocalFile* aDirectory);
-    void RegisterFile(nsILocalFile* aFile);
+    void RegisterLocation(NSLocationType aType, nsILocalFile* aLocation);
+
+    // Register XPT/XPTJAR files, and fills aManifests with .manifest
+    // files, which must be registered after all DLLs so that networking is
+    // registered.
+    void RegisterDirectory(NSLocationType aType, nsILocalFile* aDirectory,
+                           nsCOMArray<nsILocalFile>& aManifests);
+    void RegisterFile(NSLocationType aType, nsILocalFile* aFile,
+                      nsCOMArray<nsILocalFile>& aManifests);
+
+    void RegisterManifestFile(NSLocationType aType, nsILocalFile* aFile);
+
+    struct ManifestProcessingContext
+    {
+        ManifestProcessingContext(NSLocationType aType, nsILocalFile* aFile)
+            : mType(aType)
+            , mFile(aFile)
+        { }
+        ~ManifestProcessingContext() { }
+
+        NSLocationType mType;
+        nsCOMPtr<nsILocalFile> mFile;
+    };
+
+    void ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv);
+    void ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv);
+    void ManifestContract(ManifestProcessingContext& cx, int lineno, char* const * argv);
+    void ManifestCategory(ManifestProcessingContext& cx, int lineno, char* const * argv);
+
+    void RereadChromeManifests();
 
     // Shutdown
     enum {
         NOT_INITIALIZED,
         NORMAL,
         SHUTDOWN_IN_PROGRESS,
         SHUTDOWN_COMPLETE
     } mStatus;
--- a/xpcom/glue/nsClassHashtable.h
+++ b/xpcom/glue/nsClassHashtable.h
@@ -58,16 +58,22 @@ public:
   typedef typename KeyClass::KeyType KeyType;
   typedef T* UserDataType;
 
   /**
    * @copydoc nsBaseHashtable::Get
    * @param pData if the key doesn't exist, pData will be set to nsnull.
    */
   PRBool Get(KeyType aKey, UserDataType* pData) const;
+
+  /**
+   * @copydoc nsBaseHashtable::Get
+   * @returns NULL if the key is not present.
+   */
+  UserDataType Get(KeyType aKey) const;
 };
 
 
 /**
  * Thread-safe version of nsClassHashtable
  * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
  *   for a complete specification.
  * @param Class the class-type being wrapped
@@ -109,16 +115,29 @@ nsClassHashtable<KeyClass,T>::Get(KeyTyp
   }
 
   if (retVal)
     *retVal = nsnull;
 
   return PR_FALSE;
 }
 
+template<class KeyClass,class T>
+T*
+nsClassHashtable<KeyClass,T>::Get(KeyType aKey) const
+{
+  typename nsBaseHashtable<KeyClass,nsAutoPtr<T>,T*>::EntryType* ent =
+    GetEntry(aKey);
+
+  if (!ent)
+    return NULL;
+
+  return ent->mData;
+}
+
 
 //
 // nsClassHashtableMT definitions
 //
 
 template<class KeyClass,class T>
 PRBool
 nsClassHashtableMT<KeyClass,T>::Get(KeyType aKey, T** retVal) const
--- a/xpcom/sample/Makefile.in
+++ b/xpcom/sample/Makefile.in
@@ -104,8 +104,13 @@ endif
 include $(topsrcdir)/config/rules.mk
 
 libs:: $(TARGETS)
 	$(INSTALL) $(srcdir)/xpconnect-sample.html $(DIST)/bin/res/samples
 
 install:: $(TARGETS)
 	$(SYSINSTALL) $(IFLAGS1) $(srcdir)/xpconnect-sample.html $(DESTDIR)$(mozappdir)/res/samples
 
+# XXX TEMPORARY DEMONSTRATION HACK
+libs::
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(srcdir)/nsSample.manifest > $(DIST)/bin/components/nsSample.manifest
+
+DEFINES += -DSHARED_LIBRARY=$(SHARED_LIBRARY)
--- a/xpcom/sample/nsSample.js
+++ b/xpcom/sample/nsSample.js
@@ -35,95 +35,35 @@ mySample.prototype = {
         if (iid.equals(Components.interfaces.nsISample) ||
             iid.equals(Components.interfaces.nsISupports))
             return this;
 
         throw Components.results.NS_ERROR_NO_INTERFACE;
     },
 
     val: "<default value>"
-}
-
-var myModule = {
-    firstTime: true,
-
-    /*
-     * RegisterSelf is called at registration time (component installation
-     * or the only-until-release startup autoregistration) and is responsible
-     * for notifying the component manager of all components implemented in
-     * this module.  The fileSpec, location and type parameters are mostly
-     * opaque, and should be passed on to the registerComponent call
-     * unmolested.
-     */
-    registerSelf: function (compMgr, fileSpec, location, type) {
-        if (this.firstTime) {
-            debug("*** Deferring registration of sample JS components\n");
-            this.firstTime = false;
-            throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
-        }
-        debug("*** Registering sample JS components\n");
-        compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-        compMgr.registerFactoryLocation(this.myCID,
-                                        "Sample JS Component",
-                                        this.myProgID,
-                                        fileSpec,
-                                        location,
-                                        type);
-    },
-
-    /*
-     * The GetClassObject method is responsible for producing Factory objects
-     */
-    getClassObject: function (compMgr, cid, iid) {
-        if (!cid.equals(this.myCID))
-            throw Components.results.NS_ERROR_NO_INTERFACE;
-
-        if (!iid.equals(Components.interfaces.nsIFactory))
-            throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-
-        return this.myFactory;
-    },
-
-    /* CID for this class */
-    myCID: Components.ID("{dea98e50-1dd1-11b2-9344-8902b4805a2e}"),
-
-    /* ProgID for this class */
-    myProgID: "@mozilla.org/jssample;1",
-
-    /* factory object */
-    myFactory: {
-        /*
-         * Construct an instance of the interface specified by iid, possibly
-         * aggregating it with the provided outer.  (If you don't know what
-         * aggregation is all about, you don't need to.  It reduces even the
-         * mightiest of XPCOM warriors to snivelling cowards.)
-         */
-        createInstance: function (outer, iid) {
-            debug("CI: " + iid + "\n");
-            if (outer != null)
-                throw Components.results.NS_ERROR_NO_AGGREGATION;
-
-            return (new mySample()).QueryInterface(iid);
-        }
-    },
-
-    /*
-     * The canUnload method signals that the component is about to be unloaded.
-     * C++ components can return false to indicate that they don't wish to be
-     * unloaded, but the return value from JS components' canUnload is ignored:
-     * mark-and-sweep will keep everything around until it's no longer in use,
-     * making unconditional ``unload'' safe.
-     *
-     * You still need to provide a (likely useless) canUnload method, though:
-     * it's part of the nsIModule interface contract, and the JS loader _will_
-     * call it.
-     */
-    canUnload: function(compMgr) {
-        debug("*** Unloading sample JS components\n");
-        return true;
-    }
 };
 
-function NSGetModule(compMgr, fileSpec) {
-    return myModule;
+const kMyCID = Components.ID("{dea98e50-1dd1-11b2-9344-8902b4805a2e}");
+
+const kMyFactory = {
+    /*
+     * Construct an instance of the interface specified by iid, possibly
+     * aggregating it with the provided outer.  (If you don't know what
+     * aggregation is all about, you don't need to.  It reduces even the
+     * mightiest of XPCOM warriors to snivelling cowards.)
+     */
+ createInstance: function (outer, iid) {
+   debug("CI: " + iid + "\n");
+   if (outer != null)
+     throw Components.results.NS_ERROR_NO_AGGREGATION;
+
+   return (new mySample()).QueryInterface(iid);
+  }
+};
+
+function NSGetFactory(cid)
+{
+    if (cid.equals(kMyCID))
+        return kMyFactory;
+        
+    throw Components.results.NS_ERROR_FACTORY_NOT_REGISTERED;
 }
-
-
new file mode 100644
--- /dev/null
+++ b/xpcom/sample/nsSample.manifest
@@ -0,0 +1,3 @@
+component dea98e50-1dd1-11b2-9344-8902b4805a2e nsSample.js
+contract @mozilla.org/jssample;1 dea98e50-1dd1-11b2-9344-8902b4805a2e
+binary-component @SHARED_LIBRARY@
--- a/xpcom/tests/TestRegistrationOrder.cpp
+++ b/xpcom/tests/TestRegistrationOrder.cpp
@@ -156,18 +156,20 @@ int main(int argc, char** argv)
   if (argc < 2)
   {
     fprintf(stderr, "not enough arguments -- need registration dir path\n");
     return 1;
   }
 
   
   const char *regPath = argv[1];
-  XRE_AddComponentLocation(nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "core")));
-  XRE_AddComponentLocation(nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "extension")));
+  XRE_AddComponentLocation(NS_COMPONENT_LOCATION,
+                           nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "core")));
+  XRE_AddComponentLocation(NS_COMPONENT_LOCATION,
+                           nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "extension")));
   ScopedXPCOM xpcom("RegistrationOrder");
   if (xpcom.failed())
     return 1;
 
   int rv = 0;
   if (NS_FAILED(TestRegular()))
     rv = 1;
   if (NS_FAILED(TestDeferred()))