summaryrefslogtreecommitdiff
path: root/chrome
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commitad18d877ddd2a44d98fa12ccd3dbbcf4d0ac4299 (patch)
tree10027f336435511475e392454359edea8e25895d /chrome
parent15477ed9af4859dacb069040b5d4de600803d3bc (diff)
downloaduxp-ad18d877ddd2a44d98fa12ccd3dbbcf4d0ac4299.tar.gz
Add m-esr52 at 52.6.0
Diffstat (limited to 'chrome')
-rw-r--r--chrome/RegistryMessageUtils.h209
-rw-r--r--chrome/moz.build40
-rw-r--r--chrome/nsChromeProtocolHandler.cpp215
-rw-r--r--chrome/nsChromeProtocolHandler.h37
-rw-r--r--chrome/nsChromeRegistry.cpp744
-rw-r--r--chrome/nsChromeRegistry.h172
-rw-r--r--chrome/nsChromeRegistryChrome.cpp991
-rw-r--r--chrome/nsChromeRegistryChrome.h182
-rw-r--r--chrome/nsChromeRegistryContent.cpp318
-rw-r--r--chrome/nsChromeRegistryContent.h84
-rw-r--r--chrome/nsIChromeRegistry.idl116
-rw-r--r--chrome/nsIToolkitChromeRegistry.idl28
-rw-r--r--chrome/test/moz.build10
-rw-r--r--chrome/test/unit/data/test_abi.manifest4
-rw-r--r--chrome/test/unit/data/test_bug292789.manifest4
-rw-r--r--chrome/test/unit/data/test_bug380398.manifest14
-rw-r--r--chrome/test/unit/data/test_bug397073.manifest6
-rw-r--r--chrome/test/unit/data/test_bug399707.manifest11
-rw-r--r--chrome/test/unit/data/test_bug401153.manifest11
-rw-r--r--chrome/test/unit/data/test_bug519468.manifest4
-rw-r--r--chrome/test/unit/data/test_bug564667.xpibin0 -> 569 bytes
-rw-r--r--chrome/test/unit/data/test_bug564667/chrome.manifest16
-rw-r--r--chrome/test/unit/data/test_bug564667/loaded.manifest2
-rw-r--r--chrome/test/unit/data/test_bug848297.manifest4
-rw-r--r--chrome/test/unit/data/test_crlf.manifest3
-rw-r--r--chrome/test/unit/data/test_data_protocol_registration.manifest5
-rw-r--r--chrome/test/unit/data/test_no_remote_registration.manifest32
-rw-r--r--chrome/test/unit/data/test_resolve_uris.manifest5
-rw-r--r--chrome/test/unit/head_crtestutils.js14
-rw-r--r--chrome/test/unit/test_abi.js29
-rw-r--r--chrome/test/unit/test_bug292789.js37
-rw-r--r--chrome/test/unit/test_bug380398.js68
-rw-r--r--chrome/test/unit/test_bug397073.js61
-rw-r--r--chrome/test/unit/test_bug399707.js64
-rw-r--r--chrome/test/unit/test_bug401153.js55
-rw-r--r--chrome/test/unit/test_bug415367.js48
-rw-r--r--chrome/test/unit/test_bug519468.js94
-rw-r--r--chrome/test/unit/test_bug564667.js121
-rw-r--r--chrome/test/unit/test_bug848297.js48
-rw-r--r--chrome/test/unit/test_crlf.js15
-rw-r--r--chrome/test/unit/test_data_protocol_registration.js65
-rw-r--r--chrome/test/unit/test_no_remote_registration.js202
-rw-r--r--chrome/test/unit/test_resolve_uris.js93
-rw-r--r--chrome/test/unit/xpcshell.ini20
-rw-r--r--chrome/test/unit_ipc/test_resolve_uris_ipc.js9
-rw-r--r--chrome/test/unit_ipc/xpcshell.ini10
46 files changed, 4320 insertions, 0 deletions
diff --git a/chrome/RegistryMessageUtils.h b/chrome/RegistryMessageUtils.h
new file mode 100644
index 0000000000..a9dc813314
--- /dev/null
+++ b/chrome/RegistryMessageUtils.h
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_RegistryMessageUtils_h
+#define mozilla_RegistryMessageUtils_h
+
+#include "ipc/IPCMessageUtils.h"
+#include "nsString.h"
+
+struct SerializedURI
+{
+ nsCString spec;
+ nsCString charset;
+
+ bool operator ==(const SerializedURI& rhs) const
+ {
+ return spec.Equals(rhs.spec) &&
+ charset.Equals(rhs.charset);
+ }
+};
+
+struct ChromePackage
+{
+ nsCString package;
+ SerializedURI contentBaseURI;
+ SerializedURI localeBaseURI;
+ SerializedURI skinBaseURI;
+ uint32_t flags;
+
+ bool operator ==(const ChromePackage& rhs) const
+ {
+ return package.Equals(rhs.package) &&
+ contentBaseURI == rhs.contentBaseURI &&
+ localeBaseURI == rhs.localeBaseURI &&
+ skinBaseURI == rhs.skinBaseURI &&
+ flags == rhs.flags;
+ }
+};
+
+struct SubstitutionMapping
+{
+ nsCString scheme;
+ nsCString path;
+ SerializedURI resolvedURI;
+
+ bool operator ==(const SubstitutionMapping& rhs) const
+ {
+ return scheme.Equals(rhs.scheme) &&
+ path.Equals(rhs.path) &&
+ resolvedURI == rhs.resolvedURI;
+ }
+};
+
+struct OverrideMapping
+{
+ SerializedURI originalURI;
+ SerializedURI overrideURI;
+
+ bool operator==(const OverrideMapping& rhs) const
+ {
+ return originalURI == rhs.originalURI &&
+ overrideURI == rhs.overrideURI;
+ }
+};
+
+namespace IPC {
+
+template<>
+struct ParamTraits<SerializedURI>
+{
+ typedef SerializedURI paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.spec);
+ WriteParam(aMsg, aParam.charset);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ nsCString spec, charset;
+ if (ReadParam(aMsg, aIter, &spec) &&
+ ReadParam(aMsg, aIter, &charset)) {
+ aResult->spec = spec;
+ aResult->charset = charset;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct ParamTraits<ChromePackage>
+{
+ typedef ChromePackage paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.package);
+ WriteParam(aMsg, aParam.contentBaseURI);
+ WriteParam(aMsg, aParam.localeBaseURI);
+ WriteParam(aMsg, aParam.skinBaseURI);
+ WriteParam(aMsg, aParam.flags);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ nsCString package;
+ SerializedURI contentBaseURI, localeBaseURI, skinBaseURI;
+ uint32_t flags;
+
+ if (ReadParam(aMsg, aIter, &package) &&
+ ReadParam(aMsg, aIter, &contentBaseURI) &&
+ ReadParam(aMsg, aIter, &localeBaseURI) &&
+ ReadParam(aMsg, aIter, &skinBaseURI) &&
+ ReadParam(aMsg, aIter, &flags)) {
+ aResult->package = package;
+ aResult->contentBaseURI = contentBaseURI;
+ aResult->localeBaseURI = localeBaseURI;
+ aResult->skinBaseURI = skinBaseURI;
+ aResult->flags = flags;
+ return true;
+ }
+ return false;
+ }
+
+ static void Log(const paramType& aParam, std::wstring* aLog)
+ {
+ aLog->append(StringPrintf(L"[%s, %s, %s, %s, %u]", aParam.package.get(),
+ aParam.contentBaseURI.spec.get(),
+ aParam.localeBaseURI.spec.get(),
+ aParam.skinBaseURI.spec.get(), aParam.flags));
+ }
+};
+
+template <>
+struct ParamTraits<SubstitutionMapping>
+{
+ typedef SubstitutionMapping paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.scheme);
+ WriteParam(aMsg, aParam.path);
+ WriteParam(aMsg, aParam.resolvedURI);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ nsCString scheme, path;
+ SerializedURI resolvedURI;
+
+ if (ReadParam(aMsg, aIter, &scheme) &&
+ ReadParam(aMsg, aIter, &path) &&
+ ReadParam(aMsg, aIter, &resolvedURI)) {
+ aResult->scheme = scheme;
+ aResult->path = path;
+ aResult->resolvedURI = resolvedURI;
+ return true;
+ }
+ return false;
+ }
+
+ static void Log(const paramType& aParam, std::wstring* aLog)
+ {
+ aLog->append(StringPrintf(L"[%s://%s, %s, %u]",
+ aParam.scheme.get(),
+ aParam.path.get(),
+ aParam.resolvedURI.spec.get()));
+ }
+};
+
+template <>
+struct ParamTraits<OverrideMapping>
+{
+ typedef OverrideMapping paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.originalURI);
+ WriteParam(aMsg, aParam.overrideURI);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ SerializedURI originalURI;
+ SerializedURI overrideURI;
+
+ if (ReadParam(aMsg, aIter, &originalURI) &&
+ ReadParam(aMsg, aIter, &overrideURI)) {
+ aResult->originalURI = originalURI;
+ aResult->overrideURI = overrideURI;
+ return true;
+ }
+ return false;
+ }
+
+ static void Log(const paramType& aParam, std::wstring* aLog)
+ {
+ aLog->append(StringPrintf(L"[%s, %s, %u]", aParam.originalURI.spec.get(),
+ aParam.overrideURI.spec.get()));
+ }
+};
+
+} // namespace IPC
+
+#endif // RegistryMessageUtils_h
diff --git a/chrome/moz.build b/chrome/moz.build
new file mode 100644
index 0000000000..b75e9435d4
--- /dev/null
+++ b/chrome/moz.build
@@ -0,0 +1,40 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+TEST_DIRS += ['test']
+
+XPIDL_SOURCES += [
+ 'nsIChromeRegistry.idl',
+ 'nsIToolkitChromeRegistry.idl',
+]
+
+XPIDL_MODULE = 'chrome'
+
+EXPORTS.mozilla.chrome += [
+ 'RegistryMessageUtils.h',
+]
+
+UNIFIED_SOURCES += [
+ 'nsChromeProtocolHandler.cpp',
+ 'nsChromeRegistry.cpp',
+ 'nsChromeRegistryChrome.cpp',
+ 'nsChromeRegistryContent.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '!/xpcom',
+ '/dom/base',
+ '/netwerk/base',
+ '/netwerk/protocol/res',
+ '/xpcom/components'
+]
+
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
+ CXXFLAGS += CONFIG['TK_CFLAGS']
diff --git a/chrome/nsChromeProtocolHandler.cpp b/chrome/nsChromeProtocolHandler.cpp
new file mode 100644
index 0000000000..f66c6d362f
--- /dev/null
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set ts=4 sw=4 sts=4 et cin: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+
+ A protocol handler for ``chrome:''
+
+*/
+
+#include "nsChromeProtocolHandler.h"
+#include "nsChromeRegistry.h"
+#include "nsCOMPtr.h"
+#include "nsThreadUtils.h"
+#include "nsIChannel.h"
+#include "nsIChromeRegistry.h"
+#include "nsIFile.h"
+#include "nsIFileChannel.h"
+#include "nsIIOService.h"
+#include "nsILoadGroup.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsIStandardURL.h"
+#include "nsNetUtil.h"
+#include "nsNetCID.h"
+#include "nsIURL.h"
+#include "nsString.h"
+#include "nsStandardURL.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS(nsChromeProtocolHandler,
+ nsIProtocolHandler,
+ nsISupportsWeakReference)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIProtocolHandler methods:
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::GetScheme(nsACString &result)
+{
+ result.AssignLiteral("chrome");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::GetDefaultPort(int32_t *result)
+{
+ *result = -1; // no port for chrome: URLs
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
+{
+ // don't override anything.
+ *_retval = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::GetProtocolFlags(uint32_t *result)
+{
+ *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
+ const char *aCharset,
+ nsIURI *aBaseURI,
+ nsIURI **result)
+{
+
+ // Chrome: URLs (currently) have no additional structure beyond that provided
+ // by standard URLs, so there is no "outer" given to CreateInstance
+
+ RefPtr<mozilla::net::nsStandardURL> surl = new mozilla::net::nsStandardURL();
+
+ nsresult rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec,
+ aCharset, aBaseURI);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // Canonify the "chrome:" URL; e.g., so that we collapse
+ // "chrome://navigator/content/" and "chrome://navigator/content"
+ // and "chrome://navigator/content/navigator.xul".
+
+ rv = nsChromeRegistry::Canonify(surl);
+ if (NS_FAILED(rv))
+ return rv;
+
+ surl->SetMutable(false);
+
+ surl.forget(result);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::NewChannel2(nsIURI* aURI,
+ nsILoadInfo* aLoadInfo,
+ nsIChannel** aResult)
+{
+ nsresult rv;
+
+ NS_ENSURE_ARG_POINTER(aURI);
+ NS_PRECONDITION(aResult, "Null out param");
+
+#ifdef DEBUG
+ // Check that the uri we got is already canonified
+ nsresult debug_rv;
+ nsCOMPtr<nsIURI> debugClone;
+ debug_rv = aURI->Clone(getter_AddRefs(debugClone));
+ if (NS_SUCCEEDED(debug_rv)) {
+ nsCOMPtr<nsIURL> debugURL (do_QueryInterface(debugClone));
+ debug_rv = nsChromeRegistry::Canonify(debugURL);
+ if (NS_SUCCEEDED(debug_rv)) {
+ bool same;
+ debug_rv = aURI->Equals(debugURL, &same);
+ if (NS_SUCCEEDED(debug_rv)) {
+ NS_ASSERTION(same, "Non-canonified chrome uri passed to nsChromeProtocolHandler::NewChannel!");
+ }
+ }
+ }
+#endif
+
+ nsCOMPtr<nsIChannel> result;
+
+ if (!nsChromeRegistry::gChromeRegistry) {
+ // We don't actually want this ref, we just want the service to
+ // initialize if it hasn't already.
+ nsCOMPtr<nsIChromeRegistry> reg =
+ mozilla::services::GetChromeRegistryService();
+ NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE);
+ }
+
+ nsCOMPtr<nsIURI> resolvedURI;
+ rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
+ if (NS_FAILED(rv)) {
+#ifdef DEBUG
+ printf("Couldn't convert chrome URL: %s\n",
+ aURI->GetSpecOrDefault().get());
+#endif
+ return rv;
+ }
+
+ rv = NS_NewChannelInternal(getter_AddRefs(result),
+ resolvedURI,
+ aLoadInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+#ifdef DEBUG
+ nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(result));
+ if (fileChan) {
+ nsCOMPtr<nsIFile> file;
+ fileChan->GetFile(getter_AddRefs(file));
+
+ bool exists = false;
+ file->Exists(&exists);
+ if (!exists) {
+ nsAutoCString path;
+ file->GetNativePath(path);
+ printf("Chrome file doesn't exist: %s\n", path.get());
+ }
+ }
+#endif
+
+ // Make sure that the channel remembers where it was
+ // originally loaded from.
+ nsLoadFlags loadFlags = 0;
+ result->GetLoadFlags(&loadFlags);
+ result->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE);
+ rv = result->SetOriginalURI(aURI);
+ if (NS_FAILED(rv)) return rv;
+
+ // Get a system principal for content files and set the owner
+ // property of the result
+ nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
+ nsAutoCString path;
+ rv = url->GetPath(path);
+ if (StringBeginsWith(path, NS_LITERAL_CSTRING("/content/")))
+ {
+ nsCOMPtr<nsIScriptSecurityManager> securityManager =
+ do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsIPrincipal> principal;
+ rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsISupports> owner = do_QueryInterface(principal);
+ result->SetOwner(owner);
+ }
+
+ // XXX Removed dependency-tracking code from here, because we're not
+ // tracking them anyways (with fastload we checked only in DEBUG
+ // and with startupcache not at all), but this is where we would start
+ // if we need to re-add.
+ // See bug 531886, bug 533038.
+ result->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
+
+ *aResult = result;
+ NS_ADDREF(*aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeProtocolHandler::NewChannel(nsIURI* aURI,
+ nsIChannel* *aResult)
+{
+ return NewChannel2(aURI, nullptr, aResult);
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/nsChromeProtocolHandler.h b/chrome/nsChromeProtocolHandler.h
new file mode 100644
index 0000000000..42c3f52be0
--- /dev/null
+++ b/chrome/nsChromeProtocolHandler.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsChromeProtocolHandler_h___
+#define nsChromeProtocolHandler_h___
+
+#include "nsIProtocolHandler.h"
+#include "nsWeakReference.h"
+#include "mozilla/Attributes.h"
+
+#define NS_CHROMEPROTOCOLHANDLER_CID \
+{ /* 61ba33c0-3031-11d3-8cd0-0060b0fc14a3 */ \
+ 0x61ba33c0, \
+ 0x3031, \
+ 0x11d3, \
+ {0x8c, 0xd0, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
+}
+
+class nsChromeProtocolHandler final : public nsIProtocolHandler,
+ public nsSupportsWeakReference
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // nsIProtocolHandler methods:
+ NS_DECL_NSIPROTOCOLHANDLER
+
+ // nsChromeProtocolHandler methods:
+ nsChromeProtocolHandler() {}
+
+private:
+ ~nsChromeProtocolHandler() {}
+};
+
+#endif /* nsChromeProtocolHandler_h___ */
diff --git a/chrome/nsChromeRegistry.cpp b/chrome/nsChromeRegistry.cpp
new file mode 100644
index 0000000000..0aa7f3f149
--- /dev/null
+++ b/chrome/nsChromeRegistry.cpp
@@ -0,0 +1,744 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsChromeRegistry.h"
+#include "nsChromeRegistryChrome.h"
+#include "nsChromeRegistryContent.h"
+
+#include "prprf.h"
+
+#include "nsCOMPtr.h"
+#include "nsError.h"
+#include "nsEscape.h"
+#include "nsNetUtil.h"
+#include "nsString.h"
+#include "nsQueryObject.h"
+
+#include "mozilla/dom/URL.h"
+#include "nsIConsoleService.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMLocation.h"
+#include "nsIDOMWindowCollection.h"
+#include "nsIDOMWindow.h"
+#include "nsIObserverService.h"
+#include "nsIPresShell.h"
+#include "nsIScriptError.h"
+#include "nsIWindowMediator.h"
+#include "nsIPrefService.h"
+#include "mozilla/StyleSheet.h"
+#include "mozilla/StyleSheetInlines.h"
+
+#ifdef ENABLE_INTL_API
+#include "unicode/uloc.h"
+#endif
+
+nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
+
+// DO NOT use namespace mozilla; it'll break due to a naming conflict between
+// mozilla::TextRange and a TextRange in OSX headers.
+using mozilla::StyleSheet;
+using mozilla::dom::IsChromeURI;
+
+////////////////////////////////////////////////////////////////////////////////
+
+void
+nsChromeRegistry::LogMessage(const char* aMsg, ...)
+{
+ nsCOMPtr<nsIConsoleService> console
+ (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+ if (!console)
+ return;
+
+ va_list args;
+ va_start(args, aMsg);
+ char* formatted = PR_vsmprintf(aMsg, args);
+ va_end(args);
+ if (!formatted)
+ return;
+
+ console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
+ PR_smprintf_free(formatted);
+}
+
+void
+nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint32_t flags,
+ const char* aMsg, ...)
+{
+ nsresult rv;
+
+ 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;
+
+ nsCString spec;
+ if (aURL)
+ aURL->GetSpec(spec);
+
+ rv = error->Init(NS_ConvertUTF8toUTF16(formatted),
+ NS_ConvertUTF8toUTF16(spec),
+ EmptyString(),
+ aLineNumber, 0, flags, "chrome registration");
+ PR_smprintf_free(formatted);
+
+ if (NS_FAILED(rv))
+ return;
+
+ console->LogMessage(error);
+}
+
+nsChromeRegistry::~nsChromeRegistry()
+{
+ gChromeRegistry = nullptr;
+}
+
+NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
+ NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
+ NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
+ NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
+#ifdef MOZ_XUL
+ NS_INTERFACE_MAP_ENTRY(nsIXULOverlayProvider)
+#endif
+ NS_INTERFACE_MAP_ENTRY(nsIObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChromeRegistry)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(nsChromeRegistry)
+NS_IMPL_RELEASE(nsChromeRegistry)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIChromeRegistry methods:
+
+already_AddRefed<nsIChromeRegistry>
+nsChromeRegistry::GetService()
+{
+ if (!gChromeRegistry)
+ {
+ // We don't actually want this ref, we just want the service to
+ // initialize if it hasn't already.
+ nsCOMPtr<nsIChromeRegistry> reg(
+ do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
+ if (!gChromeRegistry)
+ return nullptr;
+ }
+ nsCOMPtr<nsIChromeRegistry> registry = gChromeRegistry;
+ return registry.forget();
+}
+
+nsresult
+nsChromeRegistry::Init()
+{
+ // This initialization process is fairly complicated and may cause reentrant
+ // getservice calls to resolve chrome URIs (especially locale files). We
+ // don't want that, so we inform the protocol handler about our existence
+ // before we are actually fully initialized.
+ gChromeRegistry = this;
+
+ mInitialized = true;
+
+ return NS_OK;
+}
+
+nsresult
+nsChromeRegistry::GetProviderAndPath(nsIURL* aChromeURL,
+ nsACString& aProvider, nsACString& aPath)
+{
+ nsresult rv;
+
+#ifdef DEBUG
+ bool isChrome;
+ aChromeURL->SchemeIs("chrome", &isChrome);
+ NS_ASSERTION(isChrome, "Non-chrome URI?");
+#endif
+
+ nsAutoCString path;
+ rv = aChromeURL->GetPath(path);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (path.Length() < 3) {
+ LogMessage("Invalid chrome URI: %s", path.get());
+ return NS_ERROR_FAILURE;
+ }
+
+ path.SetLength(nsUnescapeCount(path.BeginWriting()));
+ NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
+
+ int32_t slash = path.FindChar('/', 1);
+ if (slash == 1) {
+ LogMessage("Invalid chrome URI: %s", path.get());
+ return NS_ERROR_FAILURE;
+ }
+
+ if (slash == -1) {
+ aPath.Truncate();
+ }
+ else {
+ if (slash == (int32_t) path.Length() - 1)
+ aPath.Truncate();
+ else
+ aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
+
+ --slash;
+ }
+
+ aProvider.Assign(path.get() + 1, slash);
+ return NS_OK;
+}
+
+
+nsresult
+nsChromeRegistry::Canonify(nsIURL* aChromeURL)
+{
+ NS_NAMED_LITERAL_CSTRING(kSlash, "/");
+
+ nsresult rv;
+
+ nsAutoCString provider, path;
+ rv = GetProviderAndPath(aChromeURL, provider, path);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (path.IsEmpty()) {
+ nsAutoCString package;
+ rv = aChromeURL->GetHost(package);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // we re-use the "path" local string to build a new URL path
+ path.Assign(kSlash + provider + kSlash + package);
+ if (provider.EqualsLiteral("content")) {
+ path.AppendLiteral(".xul");
+ }
+ else if (provider.EqualsLiteral("locale")) {
+ path.AppendLiteral(".dtd");
+ }
+ else if (provider.EqualsLiteral("skin")) {
+ path.AppendLiteral(".css");
+ }
+ else {
+ return NS_ERROR_INVALID_ARG;
+ }
+ aChromeURL->SetPath(path);
+ }
+ else {
+ // prevent directory traversals ("..")
+ // path is already unescaped once, but uris can get unescaped twice
+ const char* pos = path.BeginReading();
+ const char* end = path.EndReading();
+ while (pos < end) {
+ switch (*pos) {
+ case ':':
+ return NS_ERROR_DOM_BAD_URI;
+ case '.':
+ if (pos[1] == '.')
+ return NS_ERROR_DOM_BAD_URI;
+ break;
+ case '%':
+ // chrome: URIs with double-escapes are trying to trick us.
+ // watch for %2e, and %25 in case someone triple unescapes
+ if (pos[1] == '2' &&
+ ( pos[2] == 'e' || pos[2] == 'E' ||
+ pos[2] == '5' ))
+ return NS_ERROR_DOM_BAD_URI;
+ break;
+ case '?':
+ case '#':
+ pos = end;
+ continue;
+ }
+ ++pos;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult)
+{
+ nsresult rv;
+ if (NS_WARN_IF(!aChromeURI)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (mOverrideTable.Get(aChromeURI, aResult))
+ return NS_OK;
+
+ nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aChromeURI));
+ NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
+
+ nsAutoCString package, provider, path;
+ rv = chromeURL->GetHostPort(package);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = GetProviderAndPath(chromeURL, provider, path);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIURI* baseURI = GetBaseURIFromPackage(package, provider, path);
+
+ uint32_t flags;
+ rv = GetFlagsFromPackage(package, &flags);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (flags & PLATFORM_PACKAGE) {
+#if defined(XP_WIN)
+ path.Insert("win/", 0);
+#elif defined(XP_MACOSX)
+ path.Insert("mac/", 0);
+#else
+ path.Insert("unix/", 0);
+#endif
+ }
+
+ if (!baseURI) {
+ LogMessage("No chrome package registered for chrome://%s/%s/%s",
+ package.get(), provider.get(), path.get());
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
+
+ return NS_NewURI(aResult, path, nullptr, baseURI);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// theme stuff
+
+
+static void FlushSkinBindingsForWindow(nsPIDOMWindowOuter* aWindow)
+{
+ // Get the document.
+ nsCOMPtr<nsIDocument> document = aWindow->GetDoc();
+ if (!document)
+ return;
+
+ // Annihilate all XBL bindings.
+ document->FlushSkinBindings();
+}
+
+// XXXbsmedberg: move this to nsIWindowMediator
+NS_IMETHODIMP nsChromeRegistry::RefreshSkins()
+{
+ nsCOMPtr<nsIWindowMediator> windowMediator
+ (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
+ if (!windowMediator)
+ return NS_OK;
+
+ nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
+ windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
+ bool more;
+ windowEnumerator->HasMoreElements(&more);
+ while (more) {
+ nsCOMPtr<nsISupports> protoWindow;
+ windowEnumerator->GetNext(getter_AddRefs(protoWindow));
+ if (protoWindow) {
+ nsCOMPtr<nsPIDOMWindowOuter> domWindow = do_QueryInterface(protoWindow);
+ if (domWindow)
+ FlushSkinBindingsForWindow(domWindow);
+ }
+ windowEnumerator->HasMoreElements(&more);
+ }
+
+ FlushSkinCaches();
+
+ windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
+ windowEnumerator->HasMoreElements(&more);
+ while (more) {
+ nsCOMPtr<nsISupports> protoWindow;
+ windowEnumerator->GetNext(getter_AddRefs(protoWindow));
+ if (protoWindow) {
+ nsCOMPtr<nsPIDOMWindowOuter> domWindow = do_QueryInterface(protoWindow);
+ if (domWindow)
+ RefreshWindow(domWindow);
+ }
+ windowEnumerator->HasMoreElements(&more);
+ }
+
+ return NS_OK;
+}
+
+void
+nsChromeRegistry::FlushSkinCaches()
+{
+ nsCOMPtr<nsIObserverService> obsSvc =
+ mozilla::services::GetObserverService();
+ NS_ASSERTION(obsSvc, "Couldn't get observer service.");
+
+ obsSvc->NotifyObservers(static_cast<nsIChromeRegistry*>(this),
+ NS_CHROME_FLUSH_SKINS_TOPIC, nullptr);
+}
+
+// XXXbsmedberg: move this to windowmediator
+nsresult nsChromeRegistry::RefreshWindow(nsPIDOMWindowOuter* aWindow)
+{
+ // Deal with our subframes first.
+ nsCOMPtr<nsIDOMWindowCollection> frames = aWindow->GetFrames();
+ uint32_t length;
+ frames->GetLength(&length);
+ uint32_t j;
+ for (j = 0; j < length; j++) {
+ nsCOMPtr<mozIDOMWindowProxy> childWin;
+ frames->Item(j, getter_AddRefs(childWin));
+ nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(childWin);
+ RefreshWindow(piWindow);
+ }
+
+ nsresult rv;
+ // Get the document.
+ nsCOMPtr<nsIDocument> document = aWindow->GetDoc();
+ if (!document)
+ return NS_OK;
+
+ // Deal with the agent sheets first. Have to do all the style sets by hand.
+ nsCOMPtr<nsIPresShell> shell = document->GetShell();
+ if (shell) {
+ // Reload only the chrome URL agent style sheets.
+ nsTArray<RefPtr<StyleSheet>> agentSheets;
+ rv = shell->GetAgentStyleSheets(agentSheets);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsTArray<RefPtr<StyleSheet>> newAgentSheets;
+ for (StyleSheet* sheet : agentSheets) {
+ nsIURI* uri = sheet->GetSheetURI();
+
+ if (IsChromeURI(uri)) {
+ // Reload the sheet.
+ RefPtr<StyleSheet> newSheet;
+ rv = document->LoadChromeSheetSync(uri, true, &newSheet);
+ if (NS_FAILED(rv)) return rv;
+ if (newSheet) {
+ rv = newAgentSheets.AppendElement(newSheet) ? NS_OK : NS_ERROR_FAILURE;
+ if (NS_FAILED(rv)) return rv;
+ }
+ }
+ else { // Just use the same sheet.
+ rv = newAgentSheets.AppendElement(sheet) ? NS_OK : NS_ERROR_FAILURE;
+ if (NS_FAILED(rv)) return rv;
+ }
+ }
+
+ rv = shell->SetAgentStyleSheets(newAgentSheets);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ int32_t count = document->GetNumberOfStyleSheets();
+
+ // Build an array of style sheets we need to reload.
+ nsTArray<RefPtr<StyleSheet>> oldSheets(count);
+ nsTArray<RefPtr<StyleSheet>> newSheets(count);
+
+ // Iterate over the style sheets.
+ for (int32_t i = 0; i < count; i++) {
+ // Get the style sheet
+ StyleSheet* styleSheet = document->GetStyleSheetAt(i);
+ oldSheets.AppendElement(styleSheet);
+ }
+
+ // Iterate over our old sheets and kick off a sync load of the new
+ // sheet if and only if it's a non-inline sheet with a chrome URL.
+ for (StyleSheet* sheet : oldSheets) {
+ MOZ_ASSERT(sheet, "GetStyleSheetAt shouldn't return nullptr for "
+ "in-range sheet indexes");
+ nsIURI* uri = sheet->GetSheetURI();
+
+ if (!sheet->IsInline() && IsChromeURI(uri)) {
+ // Reload the sheet.
+ RefPtr<StyleSheet> newSheet;
+ // XXX what about chrome sheets that have a title or are disabled? This
+ // only works by sheer dumb luck.
+ document->LoadChromeSheetSync(uri, false, &newSheet);
+ // Even if it's null, we put in in there.
+ newSheets.AppendElement(newSheet);
+ } else {
+ // Just use the same sheet.
+ newSheets.AppendElement(sheet);
+ }
+ }
+
+ // Now notify the document that multiple sheets have been added and removed.
+ document->UpdateStyleSheets(oldSheets, newSheets);
+ return NS_OK;
+}
+
+void
+nsChromeRegistry::FlushAllCaches()
+{
+ nsCOMPtr<nsIObserverService> obsSvc =
+ mozilla::services::GetObserverService();
+ NS_ASSERTION(obsSvc, "Couldn't get observer service.");
+
+ obsSvc->NotifyObservers((nsIChromeRegistry*) this,
+ NS_CHROME_FLUSH_TOPIC, nullptr);
+}
+
+// xxxbsmedberg Move me to nsIWindowMediator
+NS_IMETHODIMP
+nsChromeRegistry::ReloadChrome()
+{
+ UpdateSelectedLocale();
+ FlushAllCaches();
+ // Do a reload of all top level windows.
+ nsresult rv = NS_OK;
+
+ // Get the window mediator
+ nsCOMPtr<nsIWindowMediator> windowMediator
+ (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
+ if (windowMediator) {
+ nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
+
+ rv = windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
+ if (NS_SUCCEEDED(rv)) {
+ // Get each dom window
+ bool more;
+ rv = windowEnumerator->HasMoreElements(&more);
+ if (NS_FAILED(rv)) return rv;
+ while (more) {
+ nsCOMPtr<nsISupports> protoWindow;
+ rv = windowEnumerator->GetNext(getter_AddRefs(protoWindow));
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsPIDOMWindowOuter> domWindow = do_QueryInterface(protoWindow);
+ if (domWindow) {
+ nsIDOMLocation* location = domWindow->GetLocation();
+ if (location) {
+ rv = location->Reload(false);
+ if (NS_FAILED(rv)) return rv;
+ }
+ }
+ }
+ rv = windowEnumerator->HasMoreElements(&more);
+ if (NS_FAILED(rv)) return rv;
+ }
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, bool *aResult)
+{
+ nsresult rv;
+ *aResult = false;
+
+#ifdef DEBUG
+ bool isChrome;
+ aChromeURI->SchemeIs("chrome", &isChrome);
+ NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowScriptsForPackage!");
+#endif
+
+ nsCOMPtr<nsIURL> url (do_QueryInterface(aChromeURI));
+ NS_ENSURE_TRUE(url, NS_NOINTERFACE);
+
+ nsAutoCString provider, file;
+ rv = GetProviderAndPath(url, provider, file);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!provider.EqualsLiteral("skin"))
+ *aResult = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistry::AllowContentToAccess(nsIURI *aURI, bool *aResult)
+{
+ nsresult rv;
+
+ *aResult = false;
+
+#ifdef DEBUG
+ bool isChrome;
+ aURI->SchemeIs("chrome", &isChrome);
+ NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowContentToAccess!");
+#endif
+
+ nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
+ if (!url) {
+ NS_ERROR("Chrome URL doesn't implement nsIURL.");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsAutoCString package;
+ rv = url->GetHostPort(package);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t flags;
+ rv = GetFlagsFromPackage(package, &flags);
+
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = !!(flags & CONTENT_ACCESSIBLE);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistry::CanLoadURLRemotely(nsIURI *aURI, bool *aResult)
+{
+ nsresult rv;
+
+ *aResult = false;
+
+#ifdef DEBUG
+ bool isChrome;
+ aURI->SchemeIs("chrome", &isChrome);
+ NS_ASSERTION(isChrome, "Non-chrome URI passed to CanLoadURLRemotely!");
+#endif
+
+ nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
+ if (!url) {
+ NS_ERROR("Chrome URL doesn't implement nsIURL.");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsAutoCString package;
+ rv = url->GetHostPort(package);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t flags;
+ rv = GetFlagsFromPackage(package, &flags);
+
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = !!(flags & REMOTE_ALLOWED);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistry::MustLoadURLRemotely(nsIURI *aURI, bool *aResult)
+{
+ nsresult rv;
+
+ *aResult = false;
+
+#ifdef DEBUG
+ bool isChrome;
+ aURI->SchemeIs("chrome", &isChrome);
+ NS_ASSERTION(isChrome, "Non-chrome URI passed to MustLoadURLRemotely!");
+#endif
+
+ nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
+ if (!url) {
+ NS_ERROR("Chrome URL doesn't implement nsIURL.");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsAutoCString package;
+ rv = url->GetHostPort(package);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t flags;
+ rv = GetFlagsFromPackage(package, &flags);
+
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = !!(flags & REMOTE_REQUIRED);
+ }
+ return NS_OK;
+}
+
+bool
+nsChromeRegistry::GetDirectionForLocale(const nsACString& aLocale)
+{
+ // first check the intl.uidirection.<locale> preference, and if that is not
+ // set, check the same preference but with just the first two characters of
+ // the locale. If that isn't set, default to left-to-right.
+ nsAutoCString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + aLocale;
+ nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (!prefBranch) {
+ return false;
+ }
+
+ nsXPIDLCString dir;
+ prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
+ if (dir.IsEmpty()) {
+ int32_t hyphen = prefString.FindChar('-');
+ if (hyphen >= 1) {
+ nsAutoCString shortPref(Substring(prefString, 0, hyphen));
+ prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
+ }
+ }
+
+ return dir.EqualsLiteral("rtl");
+}
+
+NS_IMETHODIMP_(bool)
+nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
+{
+ nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
+ if (!chromeURL)
+ return false;
+
+ bool isChrome = false;
+ nsresult rv = chromeURL->SchemeIs("chrome", &isChrome);
+ if (NS_FAILED(rv) || !isChrome)
+ return false;
+
+ nsAutoCString package;
+ rv = chromeURL->GetHostPort(package);
+ if (NS_FAILED(rv))
+ return false;
+
+ uint32_t flags;
+ rv = GetFlagsFromPackage(package, &flags);
+ return NS_SUCCEEDED(rv) && (flags & XPCNATIVEWRAPPERS);
+}
+
+already_AddRefed<nsChromeRegistry>
+nsChromeRegistry::GetSingleton()
+{
+ if (gChromeRegistry) {
+ RefPtr<nsChromeRegistry> registry = gChromeRegistry;
+ return registry.forget();
+ }
+
+ RefPtr<nsChromeRegistry> cr;
+ if (GeckoProcessType_Content == XRE_GetProcessType())
+ cr = new nsChromeRegistryContent();
+ else
+ cr = new nsChromeRegistryChrome();
+
+ if (NS_FAILED(cr->Init()))
+ return nullptr;
+
+ return cr.forget();
+}
+
+void
+nsChromeRegistry::SanitizeForBCP47(nsACString& aLocale)
+{
+#ifdef ENABLE_INTL_API
+ // Currently, the only locale code we use that's not BCP47-conformant is
+ // "ja-JP-mac" on OS X, but let's try to be more general than just
+ // hard-coding that here.
+ const int32_t LANG_TAG_CAPACITY = 128;
+ char langTag[LANG_TAG_CAPACITY];
+ nsAutoCString locale(aLocale);
+ UErrorCode err = U_ZERO_ERROR;
+ // This is a fail-safe method that will set langTag to "und" if it cannot
+ // match any part of the input locale code.
+ int32_t len = uloc_toLanguageTag(locale.get(), langTag, LANG_TAG_CAPACITY,
+ false, &err);
+ if (U_SUCCESS(err) && len > 0) {
+ aLocale.Assign(langTag, len);
+ }
+#else
+ // This is only really needed for Intl API purposes, AFAIK,
+ // so probably won't be used in a non-ENABLE_INTL_API build.
+ // But let's fix up the single anomalous code we actually ship,
+ // just in case:
+ if (aLocale.EqualsLiteral("ja-JP-mac")) {
+ aLocale.AssignLiteral("ja-JP");
+ }
+#endif
+}
diff --git a/chrome/nsChromeRegistry.h b/chrome/nsChromeRegistry.h
new file mode 100644
index 0000000000..f47c8e6050
--- /dev/null
+++ b/chrome/nsChromeRegistry.h
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsChromeRegistry_h
+#define nsChromeRegistry_h
+
+#include "nsIToolkitChromeRegistry.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+
+#ifdef MOZ_XUL
+#include "nsIXULOverlayProvider.h"
+#endif
+
+#include "nsString.h"
+#include "nsURIHashKey.h"
+#include "nsInterfaceHashtable.h"
+#include "nsXULAppAPI.h"
+#include "nsIXPConnect.h"
+
+#include "mozilla/FileLocation.h"
+
+class nsPIDOMWindowOuter;
+class nsIPrefBranch;
+class nsIURL;
+
+// The chrome registry is actually split between nsChromeRegistryChrome and
+// nsChromeRegistryContent. The work/data that is common to both resides in
+// the shared nsChromeRegistry implementation, with operations that only make
+// sense for one side erroring out in the other.
+
+// for component registration
+// {47049e42-1d87-482a-984d-56ae185e367a}
+#define NS_CHROMEREGISTRY_CID \
+{ 0x47049e42, 0x1d87, 0x482a, { 0x98, 0x4d, 0x56, 0xae, 0x18, 0x5e, 0x36, 0x7a } }
+
+class nsChromeRegistry : public nsIToolkitChromeRegistry,
+#ifdef MOZ_XUL
+ public nsIXULOverlayProvider,
+#endif
+ public nsIObserver,
+ public nsSupportsWeakReference
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ // nsIXULChromeRegistry methods:
+ NS_IMETHOD ReloadChrome() override;
+ NS_IMETHOD RefreshSkins() override;
+ NS_IMETHOD AllowScriptsForPackage(nsIURI* url,
+ bool* _retval) override;
+ NS_IMETHOD AllowContentToAccess(nsIURI* url,
+ bool* _retval) override;
+ NS_IMETHOD CanLoadURLRemotely(nsIURI* url,
+ bool* _retval) override;
+ NS_IMETHOD MustLoadURLRemotely(nsIURI* url,
+ bool* _retval) override;
+
+ // nsIChromeRegistry methods:
+ NS_IMETHOD_(bool) WrappersEnabled(nsIURI *aURI) override;
+ NS_IMETHOD ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult) override;
+
+ // nsChromeRegistry methods:
+ nsChromeRegistry() : mInitialized(false) { }
+
+ virtual nsresult Init();
+
+ static already_AddRefed<nsIChromeRegistry> GetService();
+
+ static nsChromeRegistry* gChromeRegistry;
+
+ static nsresult Canonify(nsIURL* aChromeURL);
+
+protected:
+ virtual ~nsChromeRegistry();
+
+ void FlushSkinCaches();
+ void FlushAllCaches();
+
+ // Update the selected locale used by the chrome registry, and fire a
+ // notification about this change
+ virtual nsresult UpdateSelectedLocale() = 0;
+
+ static void LogMessage(const char* aMsg, ...);
+ static void LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint32_t flags,
+ const char* aMsg, ...);
+
+ virtual nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
+ const nsCString& aProvider,
+ const nsCString& aPath) = 0;
+ virtual nsresult GetFlagsFromPackage(const nsCString& aPackage,
+ uint32_t* aFlags) = 0;
+
+ nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
+
+ static nsresult RefreshWindow(nsPIDOMWindowOuter* aWindow);
+ static nsresult GetProviderAndPath(nsIURL* aChromeURL,
+ nsACString& aProvider, nsACString& aPath);
+
+ bool GetDirectionForLocale(const nsACString& aLocale);
+
+ void SanitizeForBCP47(nsACString& aLocale);
+
+public:
+ static already_AddRefed<nsChromeRegistry> GetSingleton();
+
+ struct ManifestProcessingContext
+ {
+ ManifestProcessingContext(NSLocationType aType, mozilla::FileLocation &aFile)
+ : mType(aType)
+ , mFile(aFile)
+ { }
+
+ ~ManifestProcessingContext()
+ { }
+
+ nsIURI* GetManifestURI();
+ nsIXPConnect* GetXPConnect();
+
+ already_AddRefed<nsIURI> ResolveURI(const char* uri);
+
+ NSLocationType mType;
+ mozilla::FileLocation mFile;
+ nsCOMPtr<nsIURI> mManifestURI;
+ nsCOMPtr<nsIXPConnect> mXPConnect;
+ };
+
+ virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+ virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+ virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+ virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+ virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+ virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+ virtual void ManifestResource(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) = 0;
+
+ // Available flags
+ enum {
+ // This is a "platform" package (e.g. chrome://global-platform/).
+ // Appends one of win/ unix/ mac/ to the base URI.
+ PLATFORM_PACKAGE = 1 << 0,
+
+ // This package should use the new XPCNativeWrappers to separate
+ // content from chrome. This flag is currently unused (because we call
+ // into xpconnect at registration time).
+ XPCNATIVEWRAPPERS = 1 << 1,
+
+ // Content script may access files in this package
+ CONTENT_ACCESSIBLE = 1 << 2,
+
+ // Package may be loaded remotely
+ REMOTE_ALLOWED = 1 << 3,
+
+ // Package must be loaded remotely
+ REMOTE_REQUIRED = 1 << 4,
+ };
+
+ bool mInitialized;
+
+ // "Override" table (chrome URI string -> real URI)
+ nsInterfaceHashtable<nsURIHashKey, nsIURI> mOverrideTable;
+};
+
+#endif // nsChromeRegistry_h
diff --git a/chrome/nsChromeRegistryChrome.cpp b/chrome/nsChromeRegistryChrome.cpp
new file mode 100644
index 0000000000..037e866317
--- /dev/null
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -0,0 +1,991 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 sw=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ContentParent.h"
+#include "RegistryMessageUtils.h"
+#include "nsResProtocolHandler.h"
+
+#include "nsChromeRegistryChrome.h"
+
+#if defined(XP_WIN)
+#include <windows.h>
+#elif defined(XP_MACOSX)
+#include <CoreServices/CoreServices.h>
+#endif
+
+#include "nsArrayEnumerator.h"
+#include "nsComponentManager.h"
+#include "nsEnumeratorUtils.h"
+#include "nsNetUtil.h"
+#include "nsStringEnumerator.h"
+#include "nsTextFormatter.h"
+#include "nsXPCOMCIDInternal.h"
+
+#include "mozilla/LookAndFeel.h"
+#include "mozilla/Unused.h"
+
+#include "nsICommandLine.h"
+#include "nsILocaleService.h"
+#include "nsIObserverService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "mozilla/Preferences.h"
+#include "nsIResProtocolHandler.h"
+#include "nsIScriptError.h"
+#include "nsIXPConnect.h"
+#include "nsIXULRuntime.h"
+
+#define UILOCALE_CMD_LINE_ARG "UILocale"
+
+#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
+#define SELECTED_LOCALE_PREF "general.useragent.locale"
+#define SELECTED_SKIN_PREF "general.skins.selectedSkin"
+#define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
+
+using namespace mozilla;
+using mozilla::dom::ContentParent;
+using mozilla::dom::PContentParent;
+
+// We use a "best-fit" algorithm for matching locales and themes.
+// 1) the exact selected locale/theme
+// 2) (locales only) same language, different country
+// e.g. en-GB is the selected locale, only en-US is available
+// 3) any available locale/theme
+
+/**
+ * Match the language-part of two lang-COUNTRY codes, hopefully but
+ * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
+ * work, any other garbage-in will produce undefined results as long
+ * as it does not crash.
+ */
+static bool
+LanguagesMatch(const nsACString& a, const nsACString& b)
+{
+ if (a.Length() < 2 || b.Length() < 2)
+ return false;
+
+ nsACString::const_iterator as, ae, bs, be;
+ a.BeginReading(as);
+ a.EndReading(ae);
+ b.BeginReading(bs);
+ b.EndReading(be);
+
+ while (*as == *bs) {
+ if (*as == '-')
+ return true;
+
+ ++as; ++bs;
+
+ // reached the end
+ if (as == ae && bs == be)
+ return true;
+
+ // "a" is short
+ if (as == ae)
+ return (*bs == '-');
+
+ // "b" is short
+ if (bs == be)
+ return (*as == '-');
+ }
+
+ return false;
+}
+
+nsChromeRegistryChrome::nsChromeRegistryChrome()
+ : mProfileLoaded(false)
+ , mDynamicRegistration(true)
+{
+}
+
+nsChromeRegistryChrome::~nsChromeRegistryChrome()
+{
+}
+
+nsresult
+nsChromeRegistryChrome::Init()
+{
+ nsresult rv = nsChromeRegistry::Init();
+ if (NS_FAILED(rv))
+ return rv;
+
+ mSelectedLocale = NS_LITERAL_CSTRING("en-US");
+ mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
+
+ bool safeMode = false;
+ nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+ if (xulrun)
+ xulrun->GetInSafeMode(&safeMode);
+
+ nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
+ nsCOMPtr<nsIPrefBranch> prefs;
+
+ if (prefserv) {
+ if (safeMode) {
+ prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
+ } else {
+ prefs = do_QueryInterface(prefserv);
+ }
+ }
+
+ if (!prefs) {
+ NS_WARNING("Could not get pref service!");
+ } else {
+ nsXPIDLCString provider;
+ rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
+ if (NS_SUCCEEDED(rv))
+ mSelectedSkin = provider;
+
+ SelectLocaleFromPref(prefs);
+
+ rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true);
+ rv = prefs->AddObserver(SELECTED_LOCALE_PREF, this, true);
+ rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
+ }
+
+ nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
+ if (obsService) {
+ obsService->AddObserver(this, "command-line-startup", true);
+ obsService->AddObserver(this, "profile-initial-state", true);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::CheckForOSAccessibility()
+{
+ int32_t useAccessibilityTheme =
+ LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
+
+ if (useAccessibilityTheme) {
+ /* Set the skin to classic and remove pref observers */
+ if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
+ mSelectedSkin.AssignLiteral("classic/1.0");
+ RefreshSkins();
+ }
+
+ nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (prefs) {
+ prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
+ nsIUTF8StringEnumerator* *aResult)
+{
+ nsCString realpackage;
+ nsresult rv = OverrideLocalePackage(aPackage, realpackage);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsTArray<nsCString> *a = new nsTArray<nsCString>;
+ if (!a)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ PackageEntry* entry;
+ if (mPackagesHash.Get(realpackage, &entry)) {
+ entry->locales.EnumerateToArray(a);
+ }
+
+ rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
+ if (NS_FAILED(rv))
+ delete a;
+
+ return rv;
+}
+
+static nsresult
+getUILangCountry(nsACString& aUILang)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString uiLang;
+ rv = localeService->GetLocaleComponentForUserAgent(uiLang);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ CopyUTF16toUTF8(uiLang, aUILang);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
+{
+ *aResult = false;
+
+ nsAutoCString locale;
+ GetSelectedLocale(package, false, locale);
+ if (locale.Length() < 2)
+ return NS_OK;
+
+ *aResult = GetDirectionForLocale(locale);
+ return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
+ bool aAsBCP47,
+ nsACString& aLocale)
+{
+ nsCString realpackage;
+ nsresult rv = OverrideLocalePackage(aPackage, realpackage);
+ if (NS_FAILED(rv))
+ return rv;
+ PackageEntry* entry;
+ if (!mPackagesHash.Get(realpackage, &entry))
+ return NS_ERROR_FILE_NOT_FOUND;
+
+ aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
+ if (aLocale.IsEmpty())
+ return NS_ERROR_FAILURE;
+
+ if (aAsBCP47) {
+ SanitizeForBCP47(aLocale);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
+ nsACString& aOverride)
+{
+ const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
+ nsAdoptingCString override = mozilla::Preferences::GetCString(PromiseFlatCString(pref).get());
+ if (override) {
+ aOverride = override;
+ }
+ else {
+ aOverride = aPackage;
+ }
+ return NS_OK;
+}
+
+nsresult
+nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs)
+{
+ nsresult rv;
+ bool matchOSLocale = false;
+ rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
+
+ if (NS_SUCCEEDED(rv) && matchOSLocale) {
+ // compute lang and region code only when needed!
+ nsAutoCString uiLocale;
+ rv = getUILangCountry(uiLocale);
+ if (NS_SUCCEEDED(rv))
+ mSelectedLocale = uiLocale;
+ }
+ else {
+ nsXPIDLCString provider;
+ rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
+ if (NS_SUCCEEDED(rv)) {
+ mSelectedLocale = provider;
+ }
+ }
+
+ if (NS_FAILED(rv))
+ NS_ERROR("Couldn't select locale from pref!");
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
+ const char16_t *someData)
+{
+ nsresult rv = NS_OK;
+
+ if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
+ nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
+ NS_ASSERTION(prefs, "Bad observer call!");
+
+ NS_ConvertUTF16toUTF8 pref(someData);
+
+ if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
+ pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
+ rv = UpdateSelectedLocale();
+ if (NS_SUCCEEDED(rv) && mProfileLoaded)
+ FlushAllCaches();
+ }
+ else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
+ nsXPIDLCString provider;
+ rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Couldn't get new skin pref!");
+ return rv;
+ }
+
+ mSelectedSkin = provider;
+ RefreshSkins();
+ } else {
+ NS_ERROR("Unexpected pref!");
+ }
+ }
+ else if (!strcmp("command-line-startup", aTopic)) {
+ nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
+ if (cmdLine) {
+ nsAutoString uiLocale;
+ rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
+ false, uiLocale);
+ if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
+ CopyUTF16toUTF8(uiLocale, mSelectedLocale);
+ nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (prefs) {
+ prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
+ }
+ }
+ }
+ }
+ else if (!strcmp("profile-initial-state", aTopic)) {
+ mProfileLoaded = true;
+ }
+ else {
+ NS_ERROR("Unexpected observer topic!");
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::CheckForNewChrome()
+{
+ mPackagesHash.Clear();
+ mOverlayHash.Clear();
+ mStyleHash.Clear();
+ mOverrideTable.Clear();
+
+ mDynamicRegistration = false;
+
+ nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
+
+ mDynamicRegistration = true;
+
+ SendRegisteredChrome(nullptr);
+ return NS_OK;
+}
+
+nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ if (prefs) {
+ rv = SelectLocaleFromPref(prefs);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIObserverService> obsSvc =
+ mozilla::services::GetObserverService();
+ NS_ASSERTION(obsSvc, "Couldn't get observer service.");
+ obsSvc->NotifyObservers((nsIChromeRegistry*) this,
+ "selected-locale-has-changed", nullptr);
+ }
+ }
+
+ return rv;
+}
+
+static void
+SerializeURI(nsIURI* aURI,
+ SerializedURI& aSerializedURI)
+{
+ if (!aURI)
+ return;
+
+ aURI->GetSpec(aSerializedURI.spec);
+ aURI->GetOriginCharset(aSerializedURI.charset);
+}
+
+void
+nsChromeRegistryChrome::SendRegisteredChrome(
+ mozilla::dom::PContentParent* aParent)
+{
+ InfallibleTArray<ChromePackage> packages;
+ InfallibleTArray<SubstitutionMapping> resources;
+ InfallibleTArray<OverrideMapping> overrides;
+
+ for (auto iter = mPackagesHash.Iter(); !iter.Done(); iter.Next()) {
+ ChromePackage chromePackage;
+ ChromePackageFromPackageEntry(iter.Key(), iter.UserData(), &chromePackage,
+ mSelectedLocale, mSelectedSkin);
+ packages.AppendElement(chromePackage);
+ }
+
+ // If we were passed a parent then a new child process has been created and
+ // has requested all of the chrome so send it the resources too. Otherwise
+ // resource mappings are sent by the resource protocol handler dynamically.
+ if (aParent) {
+ nsCOMPtr<nsIIOService> io (do_GetIOService());
+ NS_ENSURE_TRUE_VOID(io);
+
+ nsCOMPtr<nsIProtocolHandler> ph;
+ nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
+ nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
+ rv = rph->CollectSubstitutions(resources);
+ NS_ENSURE_SUCCESS_VOID(rv);
+ }
+
+ for (auto iter = mOverrideTable.Iter(); !iter.Done(); iter.Next()) {
+ SerializedURI chromeURI, overrideURI;
+
+ SerializeURI(iter.Key(), chromeURI);
+ SerializeURI(iter.UserData(), overrideURI);
+
+ OverrideMapping override = { chromeURI, overrideURI };
+ overrides.AppendElement(override);
+ }
+
+ if (aParent) {
+ bool success = aParent->SendRegisterChrome(packages, resources, overrides,
+ mSelectedLocale, false);
+ NS_ENSURE_TRUE_VOID(success);
+ } else {
+ nsTArray<ContentParent*> parents;
+ ContentParent::GetAll(parents);
+ if (!parents.Length())
+ return;
+
+ for (uint32_t i = 0; i < parents.Length(); i++) {
+ DebugOnly<bool> success =
+ parents[i]->SendRegisterChrome(packages, resources, overrides,
+ mSelectedLocale, true);
+ NS_WARNING_ASSERTION(success,
+ "couldn't reset a child's registered chrome");
+ }
+ }
+}
+
+/* static */ void
+nsChromeRegistryChrome::ChromePackageFromPackageEntry(const nsACString& aPackageName,
+ PackageEntry* aPackage,
+ ChromePackage* aChromePackage,
+ const nsCString& aSelectedLocale,
+ const nsCString& aSelectedSkin)
+{
+ SerializeURI(aPackage->baseURI, aChromePackage->contentBaseURI);
+ SerializeURI(aPackage->locales.GetBase(aSelectedLocale,
+ nsProviderArray::LOCALE),
+ aChromePackage->localeBaseURI);
+ SerializeURI(aPackage->skins.GetBase(aSelectedSkin, nsProviderArray::ANY),
+ aChromePackage->skinBaseURI);
+ aChromePackage->package = aPackageName;
+ aChromePackage->flags = aPackage->flags;
+}
+
+static bool
+CanLoadResource(nsIURI* aResourceURI)
+{
+ bool isLocalResource = false;
+ (void)NS_URIChainHasFlags(aResourceURI,
+ nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
+ &isLocalResource);
+ return isLocalResource;
+}
+
+nsIURI*
+nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
+ const nsCString& aProvider,
+ const nsCString& aPath)
+{
+ PackageEntry* entry;
+ if (!mPackagesHash.Get(aPackage, &entry)) {
+ if (!mInitialized)
+ return nullptr;
+
+ LogMessage("No chrome package registered for chrome://%s/%s/%s",
+ aPackage.get(), aProvider.get(), aPath.get());
+
+ return nullptr;
+ }
+
+ if (aProvider.EqualsLiteral("locale")) {
+ return entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
+ }
+ else if (aProvider.EqualsLiteral("skin")) {
+ return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
+ }
+ else if (aProvider.EqualsLiteral("content")) {
+ return entry->baseURI;
+ }
+ return nullptr;
+}
+
+nsresult
+nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
+ uint32_t* aFlags)
+{
+ PackageEntry* entry;
+ if (!mPackagesHash.Get(aPackage, &entry))
+ return NS_ERROR_FILE_NOT_FOUND;
+
+ *aFlags = entry->flags;
+ return NS_OK;
+}
+
+nsChromeRegistryChrome::ProviderEntry*
+nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
+{
+ size_t i = mArray.Length();
+ if (!i)
+ return nullptr;
+
+ ProviderEntry* found = nullptr; // Only set if we find a partial-match locale
+ ProviderEntry* entry = nullptr;
+
+ while (i--) {
+ entry = &mArray[i];
+ if (aPreferred.Equals(entry->provider))
+ return entry;
+
+ if (aType != LOCALE)
+ continue;
+
+ if (LanguagesMatch(aPreferred, entry->provider)) {
+ found = entry;
+ continue;
+ }
+
+ if (!found && entry->provider.EqualsLiteral("en-US"))
+ found = entry;
+ }
+
+ if (!found && aType != EXACT)
+ return entry;
+
+ return found;
+}
+
+nsIURI*
+nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
+{
+ ProviderEntry* provider = GetProvider(aPreferred, aType);
+
+ if (!provider)
+ return nullptr;
+
+ return provider->baseURI;
+}
+
+const nsACString&
+nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
+{
+ ProviderEntry* entry = GetProvider(aPreferred, aType);
+
+ if (entry)
+ return entry->provider;
+
+ return EmptyCString();
+}
+
+void
+nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
+{
+ ProviderEntry* provider = GetProvider(aProvider, EXACT);
+
+ if (provider) {
+ provider->baseURI = aBaseURL;
+ return;
+ }
+
+ // no existing entries, add a new one
+ mArray.AppendElement(ProviderEntry(aProvider, aBaseURL));
+}
+
+void
+nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
+{
+ int32_t i = mArray.Length();
+ while (i--) {
+ a->AppendElement(mArray[i].provider);
+ }
+}
+
+void
+nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
+{
+ int32_t i = mArray.Count();
+ while (i--) {
+ bool equals;
+ if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
+ return;
+ }
+
+ mArray.AppendObject(aURI);
+}
+
+void
+nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
+{
+ OverlayListEntry* entry = mTable.PutEntry(aBase);
+ if (entry)
+ entry->AddURI(aOverlay);
+}
+
+const nsCOMArray<nsIURI>*
+nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
+{
+ OverlayListEntry* entry = mTable.GetEntry(aBase);
+ if (!entry)
+ return nullptr;
+
+ return &entry->mArray;
+}
+
+#ifdef MOZ_XUL
+NS_IMETHODIMP
+nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL,
+ nsISimpleEnumerator **aResult)
+{
+ nsCOMPtr<nsIURI> chromeURLWithoutHash;
+ if (aChromeURL) {
+ aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
+ }
+ const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(chromeURLWithoutHash);
+ if (!parray)
+ return NS_NewEmptyEnumerator(aResult);
+
+ return NS_NewArrayEnumerator(aResult, *parray);
+}
+
+NS_IMETHODIMP
+nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
+ nsISimpleEnumerator **aResult)
+{
+ nsCOMPtr<nsIURI> chromeURLWithoutHash;
+ if (aChromeURL) {
+ aChromeURL->CloneIgnoringRef(getter_AddRefs(chromeURLWithoutHash));
+ }
+ const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(chromeURLWithoutHash);
+ if (!parray)
+ return NS_NewEmptyEnumerator(aResult);
+
+ return NS_NewArrayEnumerator(aResult, *parray);
+}
+#endif // MOZ_XUL
+
+nsIURI*
+nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
+{
+ if (!mManifestURI) {
+ nsCString uri;
+ mFile.GetURIString(uri);
+ NS_NewURI(getter_AddRefs(mManifestURI), uri);
+ }
+ return mManifestURI;
+}
+
+nsIXPConnect*
+nsChromeRegistry::ManifestProcessingContext::GetXPConnect()
+{
+ if (!mXPConnect)
+ mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
+
+ return mXPConnect;
+}
+
+already_AddRefed<nsIURI>
+nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
+{
+ nsIURI* baseuri = GetManifestURI();
+ if (!baseuri)
+ return nullptr;
+
+ nsCOMPtr<nsIURI> resolved;
+ nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
+ if (NS_FAILED(rv))
+ return nullptr;
+
+ return resolved.forget();
+}
+
+static void
+EnsureLowerCase(char *aBuf)
+{
+ for (; *aBuf; ++aBuf) {
+ char ch = *aBuf;
+ if (ch >= 'A' && ch <= 'Z')
+ *aBuf = ch + 'a' - 'A';
+ }
+}
+
+static void
+SendManifestEntry(const ChromeRegistryItem &aItem)
+{
+ nsTArray<ContentParent*> parents;
+ ContentParent::GetAll(parents);
+ if (!parents.Length())
+ return;
+
+ for (uint32_t i = 0; i < parents.Length(); i++) {
+ Unused << parents[i]->SendRegisterChromeItem(aItem);
+ }
+}
+
+void
+nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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;
+ }
+
+ nsDependentCString packageName(package);
+ PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
+ entry->baseURI = resolved;
+ entry->flags = flags;
+
+ if (mDynamicRegistration) {
+ ChromePackage chromePackage;
+ ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
+ mSelectedLocale, mSelectedSkin);
+ SendManifestEntry(chromePackage);
+ }
+}
+
+void
+nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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;
+ }
+
+ nsDependentCString packageName(package);
+ PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
+ entry->locales.SetBase(nsDependentCString(provider), resolved);
+
+ if (mDynamicRegistration) {
+ ChromePackage chromePackage;
+ ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
+ mSelectedLocale, mSelectedSkin);
+ SendManifestEntry(chromePackage);
+ }
+}
+
+void
+nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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;
+ }
+
+ nsDependentCString packageName(package);
+ PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
+ entry->skins.SetBase(nsDependentCString(provider), resolved);
+
+ if (mDynamicRegistration) {
+ ChromePackage chromePackage;
+ ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
+ mSelectedLocale, mSelectedSkin);
+ SendManifestEntry(chromePackage);
+ }
+}
+
+void
+nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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;
+ }
+
+ nsCOMPtr<nsIURI> baseuriWithoutHash;
+ baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
+
+ mOverlayHash.Add(baseuriWithoutHash, overlayuri);
+}
+
+void
+nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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 a style overlay.", overlay);
+ return;
+ }
+
+ nsCOMPtr<nsIURI> baseuriWithoutHash;
+ baseuri->CloneIgnoringRef(getter_AddRefs(baseuriWithoutHash));
+
+ mStyleHash.Add(baseuriWithoutHash, overlayuri);
+}
+
+void
+nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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 (cx.mType == NS_SKIN_LOCATION) {
+ bool chromeSkinOnly = false;
+ nsresult rv = chromeuri->SchemeIs("chrome", &chromeSkinOnly);
+ chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
+ if (chromeSkinOnly) {
+ rv = resolveduri->SchemeIs("chrome", &chromeSkinOnly);
+ chromeSkinOnly = chromeSkinOnly && NS_SUCCEEDED(rv);
+ }
+ if (chromeSkinOnly) {
+ nsAutoCString chromePath, resolvedPath;
+ chromeuri->GetPath(chromePath);
+ resolveduri->GetPath(resolvedPath);
+ chromeSkinOnly = StringBeginsWith(chromePath, NS_LITERAL_CSTRING("/skin/")) &&
+ StringBeginsWith(resolvedPath, NS_LITERAL_CSTRING("/skin/"));
+ }
+ if (!chromeSkinOnly) {
+ LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+ "Cannot register non-chrome://.../skin/ URIs '%s' and '%s' as overrides and/or to be overridden from a skin manifest.",
+ chrome, resolved);
+ 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);
+
+ if (mDynamicRegistration) {
+ SerializedURI serializedChrome;
+ SerializedURI serializedOverride;
+
+ SerializeURI(chromeuri, serializedChrome);
+ SerializeURI(resolveduri, serializedOverride);
+
+ OverrideMapping override = { serializedChrome, serializedOverride };
+ SendManifestEntry(override);
+ }
+}
+
+void
+nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ 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;
+ nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+ if (NS_FAILED(rv))
+ return;
+
+ nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
+
+ 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);
+}
diff --git a/chrome/nsChromeRegistryChrome.h b/chrome/nsChromeRegistryChrome.h
new file mode 100644
index 0000000000..4d12ca7830
--- /dev/null
+++ b/chrome/nsChromeRegistryChrome.h
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsChromeRegistryChrome_h
+#define nsChromeRegistryChrome_h
+
+#include "nsCOMArray.h"
+#include "nsChromeRegistry.h"
+#include "nsTArray.h"
+#include "mozilla/Move.h"
+#include "nsClassHashtable.h"
+
+namespace mozilla {
+namespace dom {
+class PContentParent;
+} // namespace dom
+} // namespace mozilla
+
+class nsIPrefBranch;
+struct ChromePackage;
+
+class nsChromeRegistryChrome : public nsChromeRegistry
+{
+ public:
+ nsChromeRegistryChrome();
+ ~nsChromeRegistryChrome();
+
+ nsresult Init() override;
+
+ NS_IMETHOD CheckForNewChrome() override;
+ NS_IMETHOD CheckForOSAccessibility() override;
+ NS_IMETHOD GetLocalesForPackage(const nsACString& aPackage,
+ nsIUTF8StringEnumerator* *aResult) override;
+ NS_IMETHOD IsLocaleRTL(const nsACString& package,
+ bool *aResult) override;
+ NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+ bool aAsBCP47,
+ nsACString& aLocale) override;
+ NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
+ const char16_t *someData) override;
+
+#ifdef MOZ_XUL
+ NS_IMETHOD GetXULOverlays(nsIURI *aURI,
+ nsISimpleEnumerator **_retval) override;
+ NS_IMETHOD GetStyleOverlays(nsIURI *aURI,
+ nsISimpleEnumerator **_retval) override;
+#endif
+
+ // If aChild is non-null then it is a new child to notify. If aChild is
+ // null, then we have installed new chrome and we are resetting all of our
+ // children's registered chrome.
+ void SendRegisteredChrome(mozilla::dom::PContentParent* aChild);
+
+ private:
+ struct PackageEntry;
+ static void ChromePackageFromPackageEntry(const nsACString& aPackageName,
+ PackageEntry* aPackage,
+ ChromePackage* aChromePackage,
+ const nsCString& aSelectedLocale,
+ const nsCString& aSelectedSkin);
+
+ nsresult OverrideLocalePackage(const nsACString& aPackage,
+ nsACString& aOverride);
+ nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
+ nsresult UpdateSelectedLocale() override;
+ nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
+ const nsCString& aProvider,
+ const nsCString& aPath) override;
+ nsresult GetFlagsFromPackage(const nsCString& aPackage,
+ uint32_t* aFlags) override;
+
+ struct ProviderEntry
+ {
+ ProviderEntry(const nsACString& aProvider, nsIURI* aBase) :
+ provider(aProvider),
+ baseURI(aBase) { }
+
+ nsCString provider;
+ nsCOMPtr<nsIURI> baseURI;
+ };
+
+ class nsProviderArray
+ {
+ public:
+ nsProviderArray() :
+ mArray(1) { }
+ ~nsProviderArray() { }
+
+ // When looking up locales and skins, the "selected" locale is not always
+ // available. This enum identifies what kind of match is desired/found.
+ enum MatchType {
+ EXACT = 0,
+ LOCALE = 1, // "en-GB" is selected, we found "en-US"
+ ANY = 2
+ };
+
+ nsIURI* GetBase(const nsACString& aPreferred, MatchType aType);
+ const nsACString& GetSelected(const nsACString& aPreferred, MatchType aType);
+ void SetBase(const nsACString& aProvider, nsIURI* base);
+ void EnumerateToArray(nsTArray<nsCString> *a);
+
+ private:
+ ProviderEntry* GetProvider(const nsACString& aPreferred, MatchType aType);
+
+ nsTArray<ProviderEntry> mArray;
+ };
+
+ struct PackageEntry : public PLDHashEntryHdr
+ {
+ PackageEntry()
+ : flags(0) { }
+ ~PackageEntry() { }
+
+ nsCOMPtr<nsIURI> baseURI;
+ uint32_t flags;
+ nsProviderArray locales;
+ nsProviderArray skins;
+ };
+
+ class OverlayListEntry : public nsURIHashKey
+ {
+ public:
+ typedef nsURIHashKey::KeyType KeyType;
+ typedef nsURIHashKey::KeyTypePointer KeyTypePointer;
+
+ explicit OverlayListEntry(KeyTypePointer aKey) : nsURIHashKey(aKey) { }
+ OverlayListEntry(OverlayListEntry&& toMove) : nsURIHashKey(mozilla::Move(toMove)),
+ mArray(mozilla::Move(toMove.mArray)) { }
+ ~OverlayListEntry() { }
+
+ void AddURI(nsIURI* aURI);
+
+ nsCOMArray<nsIURI> mArray;
+ };
+
+ class OverlayListHash
+ {
+ public:
+ OverlayListHash() { }
+ ~OverlayListHash() { }
+
+ void Add(nsIURI* aBase, nsIURI* aOverlay);
+ void Clear() { mTable.Clear(); }
+ const nsCOMArray<nsIURI>* GetArray(nsIURI* aBase);
+
+ private:
+ nsTHashtable<OverlayListEntry> mTable;
+ };
+
+ // Hashes on the file to be overlaid (chrome://browser/content/browser.xul)
+ // to a list of overlays/stylesheets
+ OverlayListHash mOverlayHash;
+ OverlayListHash mStyleHash;
+
+ bool mProfileLoaded;
+ bool mDynamicRegistration;
+
+ nsCString mSelectedLocale;
+ nsCString mSelectedSkin;
+
+ // Hash of package names ("global") to PackageEntry objects
+ nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
+
+ virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestResource(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+};
+
+#endif // nsChromeRegistryChrome_h
diff --git a/chrome/nsChromeRegistryContent.cpp b/chrome/nsChromeRegistryContent.cpp
new file mode 100644
index 0000000000..321f3fbe18
--- /dev/null
+++ b/chrome/nsChromeRegistryContent.cpp
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 sw=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RegistryMessageUtils.h"
+#include "nsChromeRegistryContent.h"
+#include "nsString.h"
+#include "nsNetUtil.h"
+#include "nsIResProtocolHandler.h"
+
+nsChromeRegistryContent::nsChromeRegistryContent()
+{
+}
+
+void
+nsChromeRegistryContent::RegisterRemoteChrome(
+ const InfallibleTArray<ChromePackage>& aPackages,
+ const InfallibleTArray<SubstitutionMapping>& aSubstitutions,
+ const InfallibleTArray<OverrideMapping>& aOverrides,
+ const nsACString& aLocale,
+ bool aReset)
+{
+ MOZ_ASSERT(aReset || mLocale.IsEmpty(),
+ "RegisterChrome twice?");
+
+ if (aReset) {
+ mPackagesHash.Clear();
+ mOverrideTable.Clear();
+ // XXX Can't clear resources.
+ }
+
+ for (uint32_t i = aPackages.Length(); i > 0; ) {
+ --i;
+ RegisterPackage(aPackages[i]);
+ }
+
+ for (uint32_t i = aSubstitutions.Length(); i > 0; ) {
+ --i;
+ RegisterSubstitution(aSubstitutions[i]);
+ }
+
+ for (uint32_t i = aOverrides.Length(); i > 0; ) {
+ --i;
+ RegisterOverride(aOverrides[i]);
+ }
+
+ mLocale = aLocale;
+}
+
+void
+nsChromeRegistryContent::RegisterPackage(const ChromePackage& aPackage)
+{
+ nsCOMPtr<nsIIOService> io (do_GetIOService());
+ if (!io)
+ return;
+
+ nsCOMPtr<nsIURI> content, locale, skin;
+
+ if (aPackage.contentBaseURI.spec.Length()) {
+ nsresult rv = NS_NewURI(getter_AddRefs(content),
+ aPackage.contentBaseURI.spec,
+ aPackage.contentBaseURI.charset.get(),
+ nullptr, io);
+ if (NS_FAILED(rv))
+ return;
+ }
+ if (aPackage.localeBaseURI.spec.Length()) {
+ nsresult rv = NS_NewURI(getter_AddRefs(locale),
+ aPackage.localeBaseURI.spec,
+ aPackage.localeBaseURI.charset.get(),
+ nullptr, io);
+ if (NS_FAILED(rv))
+ return;
+ }
+ if (aPackage.skinBaseURI.spec.Length()) {
+ nsresult rv = NS_NewURI(getter_AddRefs(skin),
+ aPackage.skinBaseURI.spec,
+ aPackage.skinBaseURI.charset.get(),
+ nullptr, io);
+ if (NS_FAILED(rv))
+ return;
+ }
+
+ PackageEntry* entry = new PackageEntry;
+ entry->flags = aPackage.flags;
+ entry->contentBaseURI = content;
+ entry->localeBaseURI = locale;
+ entry->skinBaseURI = skin;
+
+ mPackagesHash.Put(aPackage.package, entry);
+}
+
+void
+nsChromeRegistryContent::RegisterSubstitution(const SubstitutionMapping& aSubstitution)
+{
+ nsCOMPtr<nsIIOService> io (do_GetIOService());
+ if (!io)
+ return;
+
+ nsCOMPtr<nsIProtocolHandler> ph;
+ nsresult rv = io->GetProtocolHandler(aSubstitution.scheme.get(), getter_AddRefs(ph));
+ if (NS_FAILED(rv))
+ return;
+
+ nsCOMPtr<nsISubstitutingProtocolHandler> sph (do_QueryInterface(ph));
+ if (!sph)
+ return;
+
+ nsCOMPtr<nsIURI> resolvedURI;
+ if (aSubstitution.resolvedURI.spec.Length()) {
+ rv = NS_NewURI(getter_AddRefs(resolvedURI),
+ aSubstitution.resolvedURI.spec,
+ aSubstitution.resolvedURI.charset.get(),
+ nullptr, io);
+ if (NS_FAILED(rv))
+ return;
+ }
+
+ rv = sph->SetSubstitution(aSubstitution.path, resolvedURI);
+ if (NS_FAILED(rv))
+ return;
+}
+
+void
+nsChromeRegistryContent::RegisterOverride(const OverrideMapping& aOverride)
+{
+ nsCOMPtr<nsIIOService> io (do_GetIOService());
+ if (!io)
+ return;
+
+ nsCOMPtr<nsIURI> chromeURI, overrideURI;
+ nsresult rv = NS_NewURI(getter_AddRefs(chromeURI),
+ aOverride.originalURI.spec,
+ aOverride.originalURI.charset.get(),
+ nullptr, io);
+ if (NS_FAILED(rv))
+ return;
+
+ rv = NS_NewURI(getter_AddRefs(overrideURI), aOverride.overrideURI.spec,
+ aOverride.overrideURI.charset.get(), nullptr, io);
+ if (NS_FAILED(rv))
+ return;
+
+ mOverrideTable.Put(chromeURI, overrideURI);
+}
+
+nsIURI*
+nsChromeRegistryContent::GetBaseURIFromPackage(const nsCString& aPackage,
+ const nsCString& aProvider,
+ const nsCString& aPath)
+{
+ PackageEntry* entry;
+ if (!mPackagesHash.Get(aPackage, &entry)) {
+ return nullptr;
+ }
+
+ if (aProvider.EqualsLiteral("locale")) {
+ return entry->localeBaseURI;
+ }
+ else if (aProvider.EqualsLiteral("skin")) {
+ return entry->skinBaseURI;
+ }
+ else if (aProvider.EqualsLiteral("content")) {
+ return entry->contentBaseURI;
+ }
+ return nullptr;
+}
+
+nsresult
+nsChromeRegistryContent::GetFlagsFromPackage(const nsCString& aPackage,
+ uint32_t* aFlags)
+{
+ PackageEntry* entry;
+ if (!mPackagesHash.Get(aPackage, &entry)) {
+ return NS_ERROR_FAILURE;
+ }
+ *aFlags = entry->flags;
+ return NS_OK;
+}
+
+// All functions following only make sense in chrome, and therefore assert
+
+#define CONTENT_NOTREACHED() \
+ NS_NOTREACHED("Content should not be calling this")
+
+#define CONTENT_NOT_IMPLEMENTED() \
+ CONTENT_NOTREACHED(); \
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetLocalesForPackage(const nsACString& aPackage,
+ nsIUTF8StringEnumerator* *aResult)
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::CheckForOSAccessibility()
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::CheckForNewChrome()
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::IsLocaleRTL(const nsACString& aPackage,
+ bool *aResult)
+{
+ if (aPackage != nsDependentCString("global")) {
+ NS_ERROR("Packages other than global unavailable");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ *aResult = GetDirectionForLocale(mLocale);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetSelectedLocale(const nsACString& aPackage,
+ bool aAsBCP47,
+ nsACString& aLocale)
+{
+ if (aPackage != nsDependentCString("global")) {
+ NS_ERROR("Uh-oh, caller wanted something other than 'some local'");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ aLocale = mLocale;
+ if (aAsBCP47) {
+ SanitizeForBCP47(aLocale);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData)
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetStyleOverlays(nsIURI *aChromeURL,
+ nsISimpleEnumerator **aResult)
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+NS_IMETHODIMP
+nsChromeRegistryContent::GetXULOverlays(nsIURI *aChromeURL,
+ nsISimpleEnumerator **aResult)
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+nsresult nsChromeRegistryContent::UpdateSelectedLocale()
+{
+ CONTENT_NOT_IMPLEMENTED();
+}
+
+void
+nsChromeRegistryContent::ManifestContent(ManifestProcessingContext& cx,
+ int lineno, char *const * argv,
+ int flags)
+{
+ CONTENT_NOTREACHED();
+}
+
+void
+nsChromeRegistryContent::ManifestLocale(ManifestProcessingContext& cx,
+ int lineno,
+ char *const * argv, int flags)
+{
+ CONTENT_NOTREACHED();
+}
+
+void
+nsChromeRegistryContent::ManifestSkin(ManifestProcessingContext& cx,
+ int lineno,
+ char *const * argv, int flags)
+{
+ CONTENT_NOTREACHED();
+}
+
+void
+nsChromeRegistryContent::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags)
+{
+ CONTENT_NOTREACHED();
+}
+
+void
+nsChromeRegistryContent::ManifestStyle(ManifestProcessingContext& cx,
+ int lineno,
+ char *const * argv, int flags)
+{
+ CONTENT_NOTREACHED();
+}
+
+void
+nsChromeRegistryContent::ManifestOverride(ManifestProcessingContext& cx,
+ int lineno,
+ char *const * argv, int flags)
+{
+ CONTENT_NOTREACHED();
+}
+
+void
+nsChromeRegistryContent::ManifestResource(ManifestProcessingContext& cx,
+ int lineno,
+ char *const * argv, int flags)
+{
+ CONTENT_NOTREACHED();
+}
diff --git a/chrome/nsChromeRegistryContent.h b/chrome/nsChromeRegistryContent.h
new file mode 100644
index 0000000000..0a74d13db2
--- /dev/null
+++ b/chrome/nsChromeRegistryContent.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsChromeRegistryContent_h
+#define nsChromeRegistryContent_h
+
+#include "nsChromeRegistry.h"
+#include "nsClassHashtable.h"
+
+struct ChromePackage;
+struct SubstitutionMapping;
+struct OverrideMapping;
+
+class nsChromeRegistryContent : public nsChromeRegistry
+{
+ public:
+ nsChromeRegistryContent();
+
+ void RegisterRemoteChrome(const InfallibleTArray<ChromePackage>& aPackages,
+ const InfallibleTArray<SubstitutionMapping>& aResources,
+ const InfallibleTArray<OverrideMapping>& aOverrides,
+ const nsACString& aLocale,
+ bool aReset);
+
+ NS_IMETHOD GetLocalesForPackage(const nsACString& aPackage,
+ nsIUTF8StringEnumerator* *aResult) override;
+ NS_IMETHOD CheckForNewChrome() override;
+ NS_IMETHOD CheckForOSAccessibility() override;
+ NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData) override;
+ NS_IMETHOD IsLocaleRTL(const nsACString& package,
+ bool *aResult) override;
+ NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+ bool aAsBCP47,
+ nsACString& aLocale) override;
+ NS_IMETHOD GetStyleOverlays(nsIURI *aChromeURL,
+ nsISimpleEnumerator **aResult) override;
+ NS_IMETHOD GetXULOverlays(nsIURI *aChromeURL,
+ nsISimpleEnumerator **aResult) override;
+
+ void RegisterPackage(const ChromePackage& aPackage);
+ void RegisterOverride(const OverrideMapping& aOverride);
+ void RegisterSubstitution(const SubstitutionMapping& aResource);
+
+ private:
+ struct PackageEntry
+ {
+ PackageEntry() : flags(0) { }
+ ~PackageEntry() { }
+
+ nsCOMPtr<nsIURI> contentBaseURI;
+ nsCOMPtr<nsIURI> localeBaseURI;
+ nsCOMPtr<nsIURI> skinBaseURI;
+ uint32_t flags;
+ };
+
+ nsresult UpdateSelectedLocale() override;
+ nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
+ const nsCString& aProvider,
+ const nsCString& aPath) override;
+ nsresult GetFlagsFromPackage(const nsCString& aPackage, uint32_t* aFlags) override;
+
+ nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
+ nsCString mLocale;
+
+ virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+ virtual void ManifestResource(ManifestProcessingContext& cx, int lineno,
+ char *const * argv, int flags) override;
+};
+
+#endif // nsChromeRegistryContent_h
diff --git a/chrome/nsIChromeRegistry.idl b/chrome/nsIChromeRegistry.idl
new file mode 100644
index 0000000000..8df3a8bdf9
--- /dev/null
+++ b/chrome/nsIChromeRegistry.idl
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIURI;
+
+[scriptable, uuid(249fb5ad-ae29-4e2c-a728-ba5cf464d188)]
+interface nsIChromeRegistry : nsISupports
+{
+ const int32_t NONE = 0;
+ const int32_t PARTIAL = 1;
+ const int32_t FULL = 2;
+
+ /**
+ * Resolve a chrome URL to an loadable URI using the information in the
+ * registry. Does not modify aChromeURL.
+ *
+ * Chrome URLs are allowed to be specified in "shorthand", leaving the
+ * "file" portion off. In that case, the URL is expanded to:
+ *
+ * chrome://package/provider/package.ext
+ *
+ * where "ext" is:
+ *
+ * "xul" for a "content" package,
+ * "css" for a "skin" package, and
+ * "dtd" for a "locale" package.
+ *
+ * @param aChromeURL the URL that is to be converted.
+ */
+ nsIURI convertChromeURL(in nsIURI aChromeURL);
+
+ /**
+ * refresh the chrome list at runtime, looking for new packages/etc
+ */
+ void checkForNewChrome();
+
+ /**
+ * returns whether XPCNativeWrappers are enabled for aURI.
+ */
+ [notxpcom] boolean wrappersEnabled(in nsIURI aURI);
+};
+
+[scriptable, uuid(93251ddf-5e85-4172-ac2a-31780562974f)]
+interface nsIXULChromeRegistry : nsIChromeRegistry
+{
+ /* Should be called when locales change to reload all chrome (including XUL). */
+ void reloadChrome();
+
+ // If the optional asBCP47 parameter is true, the locale code will be
+ // converted to a BCP47 language tag; in particular, this means that
+ // "ja-JP-mac" will be returned as "ja-JP-x-lvariant-mac", which can be
+ // passed to ECMA402 Intl API methods without throwing a RangeError.
+ ACString getSelectedLocale(in ACString packageName,
+ [optional] in boolean asBCP47);
+
+ // Get the direction of the locale via the intl.uidirection.<locale> pref
+ boolean isLocaleRTL(in ACString package);
+
+ /* Should be called when skins change. Reloads only stylesheets. */
+ void refreshSkins();
+
+ /**
+ * Installable skin XBL is not always granted the same privileges as other
+ * chrome. This asks the chrome registry whether scripts are allowed to be
+ * run for a particular chrome URI. Do not pass non-chrome URIs to this
+ * method.
+ */
+ boolean allowScriptsForPackage(in nsIURI url);
+
+ /**
+ * Content should only be allowed to load chrome JS from certain packages.
+ * This method reflects the contentaccessible flag on packages.
+ * Do not pass non-chrome URIs to this method.
+ */
+ boolean allowContentToAccess(in nsIURI url);
+
+ /**
+ * Returns true if the passed chrome URL is allowed to be loaded in a remote
+ * process. This reflects the remoteenabled flag on packages.
+ * Do not pass non-chrome URIs to this method.
+ */
+ boolean canLoadURLRemotely(in nsIURI url);
+
+ /**
+ * Returns true if the passed chrome URL must be loaded in a remote process.
+ * This reflects the remoterequired flag on packages.
+ * Do not pass non-chrome URIs to this method.
+ */
+ boolean mustLoadURLRemotely(in nsIURI url);
+};
+
+%{ C++
+
+#define NS_CHROMEREGISTRY_CONTRACTID \
+ "@mozilla.org/chrome/chrome-registry;1"
+
+/**
+ * Chrome registry will notify various caches that all chrome files need
+ * flushing.
+ */
+#define NS_CHROME_FLUSH_TOPIC \
+ "chrome-flush-caches"
+
+/**
+ * Chrome registry will notify various caches that skin files need flushing.
+ * If "chrome-flush-caches" is notified, this topic will *not* be notified.
+ */
+#define NS_CHROME_FLUSH_SKINS_TOPIC \
+ "chrome-flush-skin-caches"
+
+%}
diff --git a/chrome/nsIToolkitChromeRegistry.idl b/chrome/nsIToolkitChromeRegistry.idl
new file mode 100644
index 0000000000..3a9884517f
--- /dev/null
+++ b/chrome/nsIToolkitChromeRegistry.idl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width; 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIChromeRegistry.idl"
+
+interface nsIURI;
+interface nsIUTF8StringEnumerator;
+
+[scriptable, uuid(8727651c-9530-45a0-b81e-0e0690c30c50)]
+interface nsIToolkitChromeRegistry : nsIXULChromeRegistry
+{
+ /**
+ * If the OS has a "high-visibility" or "disabled-friendly" theme set,
+ * we want to force mozilla into the classic theme, which (for the most part
+ * obeys the system color/font settings. We cannot do this at initialization,
+ * because it depends on the toolkit (GTK2) being initialized, which is
+ * not the case in some embedding situations. Embedders have to manually
+ * call this method during the startup process.
+ */
+ void checkForOSAccessibility();
+
+ /**
+ * Get a list of locales available for the specified package.
+ */
+ nsIUTF8StringEnumerator getLocalesForPackage(in AUTF8String aPackage);
+};
diff --git a/chrome/test/moz.build b/chrome/test/moz.build
new file mode 100644
index 0000000000..ed3bd5bbe7
--- /dev/null
+++ b/chrome/test/moz.build
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPCSHELL_TESTS_MANIFESTS += [
+ 'unit/xpcshell.ini',
+ 'unit_ipc/xpcshell.ini',
+]
diff --git a/chrome/test/unit/data/test_abi.manifest b/chrome/test/unit/data/test_abi.manifest
new file mode 100644
index 0000000000..6d265fc99f
--- /dev/null
+++ b/chrome/test/unit/data/test_abi.manifest
@@ -0,0 +1,4 @@
+category abitest test1 found ABI=XPCShell_noarch-spidermonkey
+category abitest test2 notfound ABI=WINNT_noarch-spidermonkey
+category abitest test3 found ABI!=WINNT_noarch-spidermonkey
+category abitest test4 notfound ABI!=XPCShell_noarch-spidermonkey
diff --git a/chrome/test/unit/data/test_bug292789.manifest b/chrome/test/unit/data/test_bug292789.manifest
new file mode 100644
index 0000000000..df67aa15c8
--- /dev/null
+++ b/chrome/test/unit/data/test_bug292789.manifest
@@ -0,0 +1,4 @@
+content test1 test/
+content test2 test/ contentaccessible=yes
+content test3 test/ contentaccessible=no
+content test4 test/ contentaccessible
diff --git a/chrome/test/unit/data/test_bug380398.manifest b/chrome/test/unit/data/test_bug380398.manifest
new file mode 100644
index 0000000000..a2349c793f
--- /dev/null
+++ b/chrome/test/unit/data/test_bug380398.manifest
@@ -0,0 +1,14 @@
+# Success cases
+content test1 test/ appversion=5
+content test2 test/ appversion<6
+content test3 test/ appversion>4
+content test4 test/ appversion>=5
+content test5 test/ appversion<=5
+
+# Failure cases
+content test6 test/ appversion>5
+content test7 test/ appversion<5
+content test8 test/ appversion>
+content test9 test/ appversion<
+content test10 test/ appversion=
+content test11 test/ appversion
diff --git a/chrome/test/unit/data/test_bug397073.manifest b/chrome/test/unit/data/test_bug397073.manifest
new file mode 100644
index 0000000000..a219e8c7eb
--- /dev/null
+++ b/chrome/test/unit/data/test_bug397073.manifest
@@ -0,0 +1,6 @@
+# Success cases
+content test1 test/ os=xpcshell
+content test2 test/ os=XPCshell
+
+# Failure cases
+content test3 test/ os=FOOshell
diff --git a/chrome/test/unit/data/test_bug399707.manifest b/chrome/test/unit/data/test_bug399707.manifest
new file mode 100644
index 0000000000..ac0d972039
--- /dev/null
+++ b/chrome/test/unit/data/test_bug399707.manifest
@@ -0,0 +1,11 @@
+# Success cases
+content test1 test/ application={39885e5f-f6b4-4e2a-87e5-6259ecf79011}
+content test2 test/ application!={d51eecae-eab5-4779-85cb-45f1ec8657c8}
+content test3 test/ application!=
+
+# Failure cases
+content test4 test/ application=
+content test5 test/ application={d51eecae-eab5-4779-85cb-45f1ec8657c8}
+content test6 test/ application!={39885e5f-f6b4-4e2a-87e5-6259ecf79011}
+content test7 test/ appversion=={39885e5f-f6b4-4e2a-87e5-6259ecf79011}
+content test8 test/ application!!{d51eecae-eab5-4779-85cb-45f1ec8657c8}
diff --git a/chrome/test/unit/data/test_bug401153.manifest b/chrome/test/unit/data/test_bug401153.manifest
new file mode 100644
index 0000000000..4fcba1bdc1
--- /dev/null
+++ b/chrome/test/unit/data/test_bug401153.manifest
@@ -0,0 +1,11 @@
+# Should work
+resource test1 test1/
+
+# Mapping into jar files should work
+resource test3 jar:test3.jar!/resources/
+
+# Invalid line
+resource test4
+
+# Check we made it through the whole manifest
+resource test5 test5/
diff --git a/chrome/test/unit/data/test_bug519468.manifest b/chrome/test/unit/data/test_bug519468.manifest
new file mode 100644
index 0000000000..36f0a18f2a
--- /dev/null
+++ b/chrome/test/unit/data/test_bug519468.manifest
@@ -0,0 +1,4 @@
+locale testmatchos en-US jar:en-US.jar!/locale/en-US/global/
+locale testmatchos fr-FR jar:en-US.jar!/locale/en-US/global/
+locale testmatchos de-DE jar:en-US.jar!/locale/en-US/global/
+locale testmatchos xx-AA jar:en-US.jar!/locale/en-US/global/
diff --git a/chrome/test/unit/data/test_bug564667.xpi b/chrome/test/unit/data/test_bug564667.xpi
new file mode 100644
index 0000000000..be1632d8ca
--- /dev/null
+++ b/chrome/test/unit/data/test_bug564667.xpi
Binary files differ
diff --git a/chrome/test/unit/data/test_bug564667/chrome.manifest b/chrome/test/unit/data/test_bug564667/chrome.manifest
new file mode 100644
index 0000000000..b35692764b
--- /dev/null
+++ b/chrome/test/unit/data/test_bug564667/chrome.manifest
@@ -0,0 +1,16 @@
+# Locally defined URLs
+content test1 test/
+locale test1 en-US test/
+skin test1 test test/
+
+# Test Override
+content testOverride test/
+override chrome://testOverride/content file:///test1/override
+
+
+# Load external manifest
+manifest loaded.manifest
+
+# Failure Cases
+overlay chrome://test1/content/overlay.xul chrome://test1/content/test1.xul
+style chrome://test1/content/style.xul chrome://test1/content/test1.css
diff --git a/chrome/test/unit/data/test_bug564667/loaded.manifest b/chrome/test/unit/data/test_bug564667/loaded.manifest
new file mode 100644
index 0000000000..2f231856a4
--- /dev/null
+++ b/chrome/test/unit/data/test_bug564667/loaded.manifest
@@ -0,0 +1,2 @@
+content test2 test/
+locale test2 en-US test/
diff --git a/chrome/test/unit/data/test_bug848297.manifest b/chrome/test/unit/data/test_bug848297.manifest
new file mode 100644
index 0000000000..d9730a9ce7
--- /dev/null
+++ b/chrome/test/unit/data/test_bug848297.manifest
@@ -0,0 +1,4 @@
+locale basepack en-US jar:en-US.jar!/locale/en-US/global/
+locale basepack fr jar:en-US.jar!/locale/en-US/global/
+locale overpack en-US jar:en-US.jar!/locale/en-US/global/
+locale overpack de jar:en-US.jar!/locale/en-US/global/
diff --git a/chrome/test/unit/data/test_crlf.manifest b/chrome/test/unit/data/test_crlf.manifest
new file mode 100644
index 0000000000..0f3032112e
--- /dev/null
+++ b/chrome/test/unit/data/test_crlf.manifest
@@ -0,0 +1,3 @@
+# Note: the following lines begins/end with a CR
+
+ content test_crlf .
diff --git a/chrome/test/unit/data/test_data_protocol_registration.manifest b/chrome/test/unit/data/test_data_protocol_registration.manifest
new file mode 100644
index 0000000000..4effa6ee65
--- /dev/null
+++ b/chrome/test/unit/data/test_data_protocol_registration.manifest
@@ -0,0 +1,5 @@
+# package used only for valid override
+content good-package bar/
+
+# Local resource (should work)
+override chrome://good-package/content/test.xul data:application/vnd.mozilla.xul+xml,
diff --git a/chrome/test/unit/data/test_no_remote_registration.manifest b/chrome/test/unit/data/test_no_remote_registration.manifest
new file mode 100644
index 0000000000..b677850ca2
--- /dev/null
+++ b/chrome/test/unit/data/test_no_remote_registration.manifest
@@ -0,0 +1,32 @@
+# package used only for valid overlaying and overrides
+content good-package bar/
+
+# UI Resource URIs (should not work)
+content moz-protocol-ui-resource moz-protocol-ui-resource://foo/
+locale moz-protocol-ui-resource en-us moz-protocol-ui-resource://foo/
+skin moz-protocol-ui-resource skin1 moz-protocol-ui-resource://foo/
+override chrome://good-package/content/override-moz-protocol-ui-resource.xul moz-protocol-ui-resource://foo/
+resource moz-protocol-ui-resource moz-protocol-ui-resource://foo/
+
+# Local file URIs (should not work)
+content moz-protocol-local-file moz-protocol-local-file://foo/
+locale moz-protocol-local-file en-us moz-protocol-local-file://foo/
+skin moz-protocol-local-file skin1 moz-protocol-local-file://foo/
+override chrome://good-package/content/override-moz-protocol-local-file.xul moz-protocol-local-file://foo/
+resource moz-protocol-local-file moz-protocol-local-file://foo/
+
+# Loadable by anyone URIs (should not work)
+content moz-protocol-loadable-by-anyone moz-protocol-loadable-by-anyone://foo/
+locale moz-protocol-loadable-by-anyone en-us moz-protocol-loadable-by-anyone://foo/
+skin moz-protocol-loadable-by-anyone skin1 moz-protocol-loadable-by-anyone://foo/
+override chrome://good-package/content/override-moz-protocol-loadable-by-anyone.xul moz-protocol-loadable-by-anyone://foo/
+resource moz-protocol-loadable-by-anyone moz-protocol-loadable-by-anyone://foo/
+
+# Working protocols should be after this point. Failing ones should be before.
+
+# Local resource (should work)
+content moz-protocol-local-resource moz-protocol-local-resource://foo/
+locale moz-protocol-local-resource en-us moz-protocol-local-resource://foo/
+skin moz-protocol-local-resource skin1 moz-protocol-local-resource://foo/
+override chrome://good-package/content/override-moz-protocol-local-resource.xul moz-protocol-local-resource://foo/
+resource moz-protocol-local-resource moz-protocol-local-resource://foo/
diff --git a/chrome/test/unit/data/test_resolve_uris.manifest b/chrome/test/unit/data/test_resolve_uris.manifest
new file mode 100644
index 0000000000..43b497e67d
--- /dev/null
+++ b/chrome/test/unit/data/test_resolve_uris.manifest
@@ -0,0 +1,5 @@
+resource foo .
+content foo resource://foo/foo-content/
+locale foo foo resource://foo/foo-locale/
+skin foo foo resource://foo/foo-skin/
+override chrome://good-package/content/override-me.xul resource://foo/foo-override/override-me.xul
diff --git a/chrome/test/unit/head_crtestutils.js b/chrome/test/unit/head_crtestutils.js
new file mode 100644
index 0000000000..e3be96fd23
--- /dev/null
+++ b/chrome/test/unit/head_crtestutils.js
@@ -0,0 +1,14 @@
+const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
+const XULAPPINFO_CID = Components.ID("{4ba645d3-be6f-40d6-a42a-01b2f40091b8}");
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+
+
+function registerManifests(manifests)
+{
+ var reg = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ for (var manifest of manifests)
+ reg.autoRegister(manifest);
+}
diff --git a/chrome/test/unit/test_abi.js b/chrome/test/unit/test_abi.js
new file mode 100644
index 0000000000..076fd3215f
--- /dev/null
+++ b/chrome/test/unit/test_abi.js
@@ -0,0 +1,29 @@
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
+ name: "XPCShell",
+ ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ platformVersion: "1.9",
+});
+
+registerManifests([do_get_file("data/test_abi.manifest")]);
+
+const catman = Components.classes["@mozilla.org/categorymanager;1"].
+ getService(Components.interfaces.nsICategoryManager);
+
+function is_registered(name) {
+ try {
+ var d = catman.getCategoryEntry("abitest", name);
+ return d == "found";
+ }
+ catch (e) {
+ return false;
+ }
+}
+
+function run_test() {
+ do_check_true(is_registered("test1"));
+ do_check_false(is_registered("test2"));
+ do_check_true(is_registered("test3"));
+ do_check_false(is_registered("test4"));
+}
diff --git a/chrome/test/unit/test_bug292789.js b/chrome/test/unit/test_bug292789.js
new file mode 100644
index 0000000000..e57c8ac121
--- /dev/null
+++ b/chrome/test/unit/test_bug292789.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+const MANIFESTS = [
+ do_get_file("data/test_bug292789.manifest")
+];
+
+registerManifests(MANIFESTS);
+
+var gIOS;
+var gCR;
+
+function check_accessibility(spec, desired)
+{
+ var uri = gIOS.newURI(spec, null, null);
+ var actual = gCR.allowContentToAccess(uri);
+ do_check_eq(desired, actual);
+}
+
+function run_test()
+{
+ gIOS = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ gCR = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIXULChromeRegistry);
+ gCR.checkForNewChrome();
+
+ check_accessibility("chrome://test1/content/", false);
+ check_accessibility("chrome://test1/content/foo.js", false);
+ check_accessibility("chrome://test2/content/", true);
+ check_accessibility("chrome://test2/content/foo.js", true);
+ check_accessibility("chrome://test3/content/", false);
+ check_accessibility("chrome://test3/content/foo.js", false);
+ check_accessibility("chrome://test4/content/", true);
+}
diff --git a/chrome/test/unit/test_bug380398.js b/chrome/test/unit/test_bug380398.js
new file mode 100644
index 0000000000..ce0b6233ec
--- /dev/null
+++ b/chrome/test/unit/test_bug380398.js
@@ -0,0 +1,68 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+
+var MANIFESTS = [
+ do_get_file("data/test_bug380398.manifest")
+];
+
+registerManifests(MANIFESTS);
+
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
+ name: "XPCShell",
+ id: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ platformVersion: "1.9",
+});
+
+var gIOS = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIChromeRegistry);
+chromeReg.checkForNewChrome();
+
+var target = gIOS.newFileURI(do_get_file("data"));
+target = target.spec + "test/test.xul";
+
+function test_succeeded_mapping(namespace)
+{
+ var uri = gIOS.newURI("chrome://" + namespace + "/content/test.xul",
+ null, null);
+ try {
+ var result = chromeReg.convertChromeURL(uri);
+ do_check_eq(result.spec, target);
+ }
+ catch (ex) {
+ do_throw(namespace);
+ }
+}
+
+function test_failed_mapping(namespace)
+{
+ var uri = gIOS.newURI("chrome://" + namespace + "/content/test.xul",
+ null, null);
+ try {
+ var result = chromeReg.convertChromeURL(uri);
+ do_throw(namespace);
+ }
+ catch (ex) {
+ }
+}
+
+function run_test()
+{
+ test_succeeded_mapping("test1");
+ test_succeeded_mapping("test2");
+ test_succeeded_mapping("test3");
+ test_succeeded_mapping("test4");
+ test_succeeded_mapping("test5");
+ test_failed_mapping("test6");
+ test_failed_mapping("test7");
+ test_failed_mapping("test8");
+ test_failed_mapping("test9");
+ test_failed_mapping("test10");
+ test_failed_mapping("test11");
+}
diff --git a/chrome/test/unit/test_bug397073.js b/chrome/test/unit/test_bug397073.js
new file mode 100644
index 0000000000..fb9c6c0953
--- /dev/null
+++ b/chrome/test/unit/test_bug397073.js
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+var MANIFESTS = [
+ do_get_file("data/test_bug397073.manifest")
+];
+
+
+registerManifests(MANIFESTS);
+
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
+ name: "XPCShell",
+ ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ platformVersion: "1.9",
+});
+
+var gIOS = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIChromeRegistry);
+chromeReg.checkForNewChrome();
+
+var target = gIOS.newFileURI(do_get_file("data"));
+target = target.spec + "test/test.xul";
+
+function test_succeeded_mapping(namespace)
+{
+ var uri = gIOS.newURI("chrome://" + namespace + "/content/test.xul",
+ null, null);
+ try {
+ var result = chromeReg.convertChromeURL(uri);
+ do_check_eq(result.spec, target);
+ }
+ catch (ex) {
+ do_throw(namespace);
+ }
+}
+
+function test_failed_mapping(namespace)
+{
+ var uri = gIOS.newURI("chrome://" + namespace + "/content/test.xul",
+ null, null);
+ try {
+ var result = chromeReg.convertChromeURL(uri);
+ do_throw(namespace);
+ }
+ catch (ex) {
+ }
+}
+
+function run_test()
+{
+ test_succeeded_mapping("test1");
+ test_succeeded_mapping("test2");
+
+ test_failed_mapping("test3");
+}
diff --git a/chrome/test/unit/test_bug399707.js b/chrome/test/unit/test_bug399707.js
new file mode 100644
index 0000000000..05273550c3
--- /dev/null
+++ b/chrome/test/unit/test_bug399707.js
@@ -0,0 +1,64 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+var MANIFESTS = [
+ do_get_file("data/test_bug399707.manifest")
+];
+
+registerManifests(MANIFESTS);
+
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
+ name: "XPCShell",
+ ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ platformVersion: "1.9",
+});
+
+var gIOS = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIChromeRegistry);
+chromeReg.checkForNewChrome();
+
+var target = gIOS.newFileURI(do_get_file("data"));
+target = target.spec + "test/test.xul";
+
+function test_succeeded_mapping(namespace)
+{
+ var uri = gIOS.newURI("chrome://" + namespace + "/content/test.xul",
+ null, null);
+ try {
+ var result = chromeReg.convertChromeURL(uri);
+ do_check_eq(result.spec, target);
+ }
+ catch (ex) {
+ do_throw(namespace);
+ }
+}
+
+function test_failed_mapping(namespace)
+{
+ var uri = gIOS.newURI("chrome://" + namespace + "/content/test.xul",
+ null, null);
+ try {
+ var result = chromeReg.convertChromeURL(uri);
+ do_throw(namespace);
+ }
+ catch (ex) {
+ }
+}
+
+function run_test()
+{
+ test_succeeded_mapping("test1");
+ test_succeeded_mapping("test2");
+ test_succeeded_mapping("test3");
+ test_failed_mapping("test4");
+ test_failed_mapping("test5");
+ test_failed_mapping("test6");
+ test_failed_mapping("test7");
+ test_failed_mapping("test8");
+}
diff --git a/chrome/test/unit/test_bug401153.js b/chrome/test/unit/test_bug401153.js
new file mode 100644
index 0000000000..3317d8b1e3
--- /dev/null
+++ b/chrome/test/unit/test_bug401153.js
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+var MANIFESTS = [
+ do_get_file("data/test_bug401153.manifest")
+];
+
+registerManifests(MANIFESTS);
+
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
+ name: "XPCShell",
+ ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ platformVersion: "1.9",
+});
+
+var gIOS = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIChromeRegistry);
+chromeReg.checkForNewChrome();
+
+var rph = gIOS.getProtocolHandler("resource")
+ .QueryInterface(Ci.nsIResProtocolHandler);
+
+function test_succeeded_mapping(namespace, target)
+{
+ try {
+ do_check_true(rph.hasSubstitution(namespace));
+ var uri = gIOS.newURI("resource://" + namespace, null, null);
+ dump("### checking for " + target + ", getting " + rph.resolveURI(uri) + "\n");
+ do_check_eq(rph.resolveURI(uri), target);
+ }
+ catch (ex) {
+ dump(ex + "\n");
+ do_throw(namespace);
+ }
+}
+
+function test_failed_mapping(namespace)
+{
+ do_check_false(rph.hasSubstitution(namespace));
+}
+
+function run_test()
+{
+ var data = gIOS.newFileURI(do_get_file("data")).spec;
+ test_succeeded_mapping("test1", data + "test1/");
+ test_succeeded_mapping("test3", "jar:" + data + "test3.jar!/resources/");
+ test_failed_mapping("test4");
+ test_succeeded_mapping("test5", data + "test5/");
+}
diff --git a/chrome/test/unit/test_bug415367.js b/chrome/test/unit/test_bug415367.js
new file mode 100644
index 0000000000..6d02223c0e
--- /dev/null
+++ b/chrome/test/unit/test_bug415367.js
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+var gIOS = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+
+function test_uri(obj)
+{
+ var uri = null;
+ var failed = false;
+ var message = "";
+ try {
+ uri = gIOS.newURI(obj.uri, null, null);
+ if (!obj.result) {
+ failed = true;
+ message = obj.uri + " should not be accepted as a valid URI";
+ }
+ }
+ catch (ex) {
+ if (obj.result) {
+ failed = true;
+ message = obj.uri + " should be accepted as a valid URI";
+ }
+ }
+ if (failed)
+ do_throw(message);
+ if (obj.result) {
+ do_check_true(uri != null);
+ do_check_eq(uri.spec, obj.uri);
+ }
+}
+
+function run_test()
+{
+ var tests = [
+ {uri: "chrome://blah/content/blah.xul", result: true},
+ {uri: "chrome://blah/content/:/blah/blah.xul", result: false},
+ {uri: "chrome://blah/content/%252e./blah/blah.xul", result: false},
+ {uri: "chrome://blah/content/%252e%252e/blah/blah.xul", result: false},
+ {uri: "chrome://blah/content/blah.xul?param=%252e./blah/", result: true},
+ {uri: "chrome://blah/content/blah.xul?param=:/blah/", result: true},
+ {uri: "chrome://blah/content/blah.xul?param=%252e%252e/blah/", result: true},
+ ];
+ for (var i = 0; i < tests.length; ++ i)
+ test_uri(tests[i]);
+}
diff --git a/chrome/test/unit/test_bug519468.js b/chrome/test/unit/test_bug519468.js
new file mode 100644
index 0000000000..69c5c86220
--- /dev/null
+++ b/chrome/test/unit/test_bug519468.js
@@ -0,0 +1,94 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+var MANIFESTS = [
+ do_get_file("data/test_bug519468.manifest")
+];
+
+Components.utils.import("resource://testing-common/MockRegistrar.jsm");
+// Stub in the locale service so we can control what gets returned as the OS locale setting
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var stubOSLocale = null;
+
+StubLocaleService = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsILocaleService, Ci.nsISupports]),
+
+ getLocaleComponentForUserAgent: function SLS_getLocaleComponentForUserAgent()
+ {
+ return stubOSLocale;
+ }
+}
+
+MockRegistrar.register("@mozilla.org/intl/nslocaleservice;1", StubLocaleService);
+
+// Now fire up the test
+do_test_pending()
+registerManifests(MANIFESTS);
+
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIXULChromeRegistry)
+ .QueryInterface(Ci.nsIToolkitChromeRegistry);
+chromeReg.checkForNewChrome();
+
+var prefService = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService)
+ .QueryInterface(Ci.nsIPrefBranch);
+var os = Cc["@mozilla.org/observer-service;1"]
+ .getService(Ci.nsIObserverService);
+
+var testsLocale = [
+ // These tests cover when the OS local is included in our manifest
+ {matchOS: false, selected: "en-US", osLocale: "xx-AA", locale: "en-US"},
+ {matchOS: true, selected: "en-US", osLocale: "xx-AA", locale: "xx-AA"},
+ {matchOS: false, selected: "fr-FR", osLocale: "xx-AA", locale: "fr-FR"},
+ {matchOS: true, selected: "fr-FR", osLocale: "xx-AA", locale: "xx-AA"},
+ {matchOS: false, selected: "de-DE", osLocale: "xx-AA", locale: "de-DE"},
+ {matchOS: true, selected: "de-DE", osLocale: "xx-AA", locale: "xx-AA"},
+ // these tests cover the case where the OS locale is not available in our manifest, but the
+ // base language is (ie, substitute xx-AA which we have for xx-BB which we don't)
+ {matchOS: false, selected: "en-US", osLocale: "xx-BB", locale: "en-US"},
+ {matchOS: true, selected: "en-US", osLocale: "xx-BB", locale: "xx-AA"},
+ {matchOS: false, selected: "fr-FR", osLocale: "xx-BB", locale: "fr-FR"},
+ {matchOS: true, selected: "fr-FR", osLocale: "xx-BB", locale: "xx-AA"},
+ // These tests cover where the language is not available
+ {matchOS: false, selected: "en-US", osLocale: "xy-BB", locale: "en-US"},
+ {matchOS: true, selected: "en-US", osLocale: "xy-BB", locale: "en-US"},
+ {matchOS: false, selected: "fr-FR", osLocale: "xy-BB", locale: "fr-FR"},
+ {matchOS: true, selected: "fr-FR", osLocale: "xy-BB", locale: "en-US"},
+];
+
+var observedLocale = null;
+
+function test_locale(aTest) {
+ observedLocale = null;
+
+ stubOSLocale = aTest.osLocale;
+ prefService.setBoolPref("intl.locale.matchOS", aTest.matchOS);
+ prefService.setCharPref("general.useragent.locale", aTest.selected);
+
+ chromeReg.reloadChrome();
+
+ do_check_eq(observedLocale, aTest.locale);
+}
+
+// Callback function for observing locale change. May be called more than once
+// per test iteration.
+function checkValidity() {
+ observedLocale = chromeReg.getSelectedLocale("testmatchos");
+ dump("checkValidity called back with locale = " + observedLocale + "\n");
+}
+
+function run_test() {
+ os.addObserver(checkValidity, "selected-locale-has-changed", false);
+
+ for (let count = 0 ; count < testsLocale.length ; count++) {
+ dump("count = " + count + " " + testsLocale[count].toSource() + "\n");
+ test_locale(testsLocale[count]);
+ }
+
+ os.removeObserver(checkValidity, "selected-locale-has-changed");
+ do_test_finished();
+}
diff --git a/chrome/test/unit/test_bug564667.js b/chrome/test/unit/test_bug564667.js
new file mode 100644
index 0000000000..5f5e9940dc
--- /dev/null
+++ b/chrome/test/unit/test_bug564667.js
@@ -0,0 +1,121 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+const UNPACKAGED_ADDON = do_get_file("data/test_bug564667");
+const PACKAGED_ADDON = do_get_file("data/test_bug564667.xpi");
+
+var gIOS = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+
+var gCR = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry).
+ QueryInterface(Ci.nsIXULOverlayProvider);
+
+/*
+ * Checks that a mapping was added
+ */
+function test_mapping(chromeURL, target) {
+ var uri = gIOS.newURI(chromeURL, null, null);
+
+ try {
+ var result = gCR.convertChromeURL(uri);
+ do_check_eq(result.spec, target);
+ }
+ catch (ex) {
+ do_throw(chromeURL + " not Registered");
+ }
+}
+
+/*
+ * Checks that a mapping was removed
+ */
+function test_removed_mapping(chromeURL, target) {
+ var uri = gIOS.newURI(chromeURL, null, null);
+ try {
+ var result = gCR.convertChromeURL(uri);
+ do_throw(chromeURL + " not removed");
+ }
+ catch (ex) {
+ // This should throw
+ }
+}
+
+/*
+ * Checks if any overlay was added after loading
+ * the manifest files
+ *
+ * @param type The type of overlay: overlay|style
+ */
+function test_no_overlays(chromeURL, target, type) {
+ var type = type || "overlay";
+ var uri = gIOS.newURI(chromeURL, null, null);
+ var present = false, elem;
+
+ var overlays = (type == "overlay") ?
+ gCR.getXULOverlays(uri) : gCR.getStyleOverlays(uri);
+
+ // We shouldn't be allowed to register overlays nor styles
+ if (overlays.hasMoreElements()) {
+ if (type == "styles")
+ do_throw("Style Registered: " + chromeURL);
+ else
+ do_throw("Overlay Registered: " + chromeURL);
+ }
+}
+
+function testManifest(manifestPath, baseURI) {
+
+ // ------------------ Add manifest file ------------------------
+ Components.manager.addBootstrappedManifestLocation(manifestPath);
+
+ // Test Adding Content URL
+ test_mapping("chrome://test1/content", baseURI + "test/test1.xul");
+
+ // Test Adding Locale URL
+ test_mapping("chrome://test1/locale", baseURI + "test/test1.dtd");
+
+ // Test Adding Skin URL
+ test_mapping("chrome://test1/skin", baseURI + "test/test1.css");
+
+ // Test Adding Manifest URL
+ test_mapping("chrome://test2/content", baseURI + "test/test2.xul");
+ test_mapping("chrome://test2/locale", baseURI + "test/test2.dtd");
+
+ // Test Adding Override
+ test_mapping("chrome://testOverride/content", 'file:///test1/override')
+
+ // Test Not-Adding Overlays
+ test_no_overlays("chrome://test1/content/overlay.xul",
+ "chrome://test1/content/test1.xul");
+
+ // Test Not-Adding Styles
+ test_no_overlays("chrome://test1/content/style.xul",
+ "chrome://test1/content/test1.css", "styles");
+
+
+ // ------------------ Remove manifest file ------------------------
+ Components.manager.removeBootstrappedManifestLocation(manifestPath);
+
+ // Test Removing Content URL
+ test_removed_mapping("chrome://test1/content", baseURI + "test/test1.xul");
+
+ // Test Removing Content URL
+ test_removed_mapping("chrome://test1/locale", baseURI + "test/test1.dtd");
+
+ // Test Removing Skin URL
+ test_removed_mapping("chrome://test1/skin", baseURI + "test/test1.css");
+
+ // Test Removing Manifest URL
+ test_removed_mapping("chrome://test2/content", baseURI + "test/test2.xul");
+ test_removed_mapping("chrome://test2/locale", baseURI + "test/test2.dtd");
+}
+
+function run_test() {
+ // Test an unpackaged addon
+ testManifest(UNPACKAGED_ADDON, gIOS.newFileURI(UNPACKAGED_ADDON).spec);
+
+ // Test a packaged addon
+ testManifest(PACKAGED_ADDON, "jar:" + gIOS.newFileURI(PACKAGED_ADDON).spec + "!/");
+}
diff --git a/chrome/test/unit/test_bug848297.js b/chrome/test/unit/test_bug848297.js
new file mode 100644
index 0000000000..0875370f79
--- /dev/null
+++ b/chrome/test/unit/test_bug848297.js
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+var MANIFESTS = [
+ do_get_file("data/test_bug848297.manifest")
+];
+
+// Stub in the locale service so we can control what gets returned as the OS locale setting
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+registerManifests(MANIFESTS);
+
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIXULChromeRegistry)
+ .QueryInterface(Ci.nsIToolkitChromeRegistry);
+chromeReg.checkForNewChrome();
+
+var prefService = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService)
+ .QueryInterface(Ci.nsIPrefBranch);
+
+function enum_to_array(strings) {
+ let rv = [];
+ while (strings.hasMore()) {
+ rv.push(strings.getNext());
+ }
+ rv.sort();
+ return rv;
+}
+
+function run_test() {
+
+ // without override
+ prefService.setCharPref("general.useragent.locale", "de");
+ do_check_eq(chromeReg.getSelectedLocale("basepack"), "en-US");
+ do_check_eq(chromeReg.getSelectedLocale("overpack"), "de");
+ do_check_matches(enum_to_array(chromeReg.getLocalesForPackage("basepack")),
+ ['en-US', 'fr']);
+
+ // with override
+ prefService.setCharPref("chrome.override_package.basepack", "overpack");
+ do_check_eq(chromeReg.getSelectedLocale("basepack"), "de");
+ do_check_matches(enum_to_array(chromeReg.getLocalesForPackage("basepack")),
+ ['de', 'en-US']);
+
+}
diff --git a/chrome/test/unit/test_crlf.js b/chrome/test/unit/test_crlf.js
new file mode 100644
index 0000000000..b577c49a9c
--- /dev/null
+++ b/chrome/test/unit/test_crlf.js
@@ -0,0 +1,15 @@
+registerManifests([do_get_file("data/test_crlf.manifest")]);
+
+function run_test()
+{
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+
+ let ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ let sourceURI = ios.newURI("chrome://test_crlf/content/", null, null);
+ // this throws for packages that are not registered
+ let file = cr.convertChromeURL(sourceURI).QueryInterface(Ci.nsIFileURL).file;
+
+ do_check_true(file.equals(do_get_file("data/test_crlf.xul", true)));
+}
diff --git a/chrome/test/unit/test_data_protocol_registration.js b/chrome/test/unit/test_data_protocol_registration.js
new file mode 100644
index 0000000000..71138bd929
--- /dev/null
+++ b/chrome/test/unit/test_data_protocol_registration.js
@@ -0,0 +1,65 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=2 ts=2 sts=2 tw=78 expandtab :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var manifests = [
+ do_get_file("data/test_data_protocol_registration.manifest"),
+];
+registerManifests(manifests);
+
+var XULAppInfoFactory = {
+ // These two are used when we register all our factories (and unregister)
+ CID: XULAPPINFO_CID,
+ scheme: "XULAppInfo",
+ contractID: XULAPPINFO_CONTRACTID,
+ createInstance: function (outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return XULAppInfo.QueryInterface(iid);
+ }
+};
+
+function run_test()
+{
+ // Add our XULAppInfo factory
+ let factories = [XULAppInfoFactory];
+
+ // Register our factories
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .registerFactory(factory.CID, "test-" + factory.scheme,
+ factory.contractID, factory);
+ }
+
+ // Check for new chrome
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+ cr.checkForNewChrome();
+
+ // Check that our override worked
+ let expectedURI = "data:application/vnd.mozilla.xul+xml,";
+ let sourceURI = "chrome://good-package/content/test.xul";
+ try {
+ let ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ sourceURI = ios.newURI(sourceURI, null, null);
+ // this throws for packages that are not registered
+ let uri = cr.convertChromeURL(sourceURI).spec;
+
+ do_check_eq(expectedURI, uri);
+ }
+ catch (e) {
+ dump(e + "\n");
+ do_throw("Should have registered our URI!");
+ }
+
+ // Unregister our factories so we do not leak
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .unregisterFactory(factory.CID, factory);
+ }
+}
diff --git a/chrome/test/unit/test_no_remote_registration.js b/chrome/test/unit/test_no_remote_registration.js
new file mode 100644
index 0000000000..281a79dd32
--- /dev/null
+++ b/chrome/test/unit/test_no_remote_registration.js
@@ -0,0 +1,202 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=2 ts=2 sts=2 tw=78 expandtab :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var manifests = [
+ do_get_file("data/test_no_remote_registration.manifest"),
+];
+registerManifests(manifests);
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+var XULAppInfo = newAppInfo({
+ name: "XPCShell",
+ ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+ version: "5",
+ platformVersion: "1.9",
+});
+
+var XULAppInfoFactory = {
+ // These two are used when we register all our factories (and unregister)
+ CID: Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"),
+ scheme: "XULAppInfo",
+ contractID: "@mozilla.org/xre/app-info;1",
+ createInstance: function (outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return XULAppInfo.QueryInterface(iid);
+ }
+};
+
+function ProtocolHandler(aScheme, aFlags)
+{
+ this.scheme = aScheme;
+ this.protocolFlags = aFlags;
+ this.contractID = "@mozilla.org/network/protocol;1?name=" + aScheme;
+}
+
+ProtocolHandler.prototype =
+{
+ defaultPort: -1,
+ allowPort: () => false,
+ newURI: function(aSpec, aCharset, aBaseURI)
+ {
+ let uri = Cc["@mozilla.org/network/standard-url;1"].
+ createInstance(Ci.nsIURI);
+ uri.spec = aSpec;
+ if (!uri.scheme) {
+ // We got a partial uri, so let's resolve it with the base one
+ uri.spec = aBaseURI.resolve(aSpec);
+ }
+ return uri;
+ },
+ newChannel2: function() { throw Cr.NS_ERROR_NOT_IMPLEMENTED },
+ newChannel: function() { throw Cr.NS_ERROR_NOT_IMPLEMENTED },
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIProtocolHandler
+ ])
+};
+
+var testProtocols = [
+ // It doesn't matter if it has this flag - the only flag we accept is
+ // URI_IS_LOCAL_RESOURCE.
+ {scheme: "moz-protocol-ui-resource",
+ flags: Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE,
+ CID: Components.ID("{d6dedc93-558f-44fe-90f4-3b4bba8a0b14}"),
+ shouldRegister: false
+ },
+ // It doesn't matter if it has this flag - the only flag we accept is
+ // URI_IS_LOCAL_RESOURCE.
+ {scheme: "moz-protocol-local-file",
+ flags: Ci.nsIProtocolHandler.URI_IS_LOCAL_FILE,
+ CID: Components.ID("{ee30d594-0a2d-4f47-89cc-d4cde320ab69}"),
+ shouldRegister: false
+ },
+ // This clearly is non-local
+ {scheme: "moz-protocol-loadable-by-anyone",
+ flags: Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
+ CID: Components.ID("{c3735f23-3b0c-4a33-bfa0-79436dcd40b2}"),
+ shouldRegister: false
+ },
+ // This should always be last (unless we add more flags that are OK)
+ {scheme: "moz-protocol-local-resource",
+ flags: Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE,
+ CID: Components.ID("{b79e977c-f840-469a-b413-0125cc1b62a5}"),
+ shouldRegister: true
+ },
+];
+function run_test()
+{
+ // Create factories
+ let factories = [];
+ for (let i = 0; i < testProtocols.length; i++) {
+ factories[i] = {
+ scheme: testProtocols[i].scheme,
+ flags: testProtocols[i].flags,
+ CID: testProtocols[i].CID,
+ contractID: "@mozilla.org/network/protocol;1?name=" + testProtocols[i].scheme,
+ createInstance: function(aOuter, aIID)
+ {
+ if (aOuter != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ let handler = new ProtocolHandler(this.scheme, this.flags, this.CID);
+ return handler.QueryInterface(aIID);
+ }
+ };
+ }
+ // Add our XULAppInfo factory
+ factories.push(XULAppInfoFactory);
+
+ // Register our factories
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .registerFactory(factory.CID, "test-" + factory.scheme,
+ factory.contractID, factory);
+ }
+
+ // Check for new chrome
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+ cr.checkForNewChrome();
+
+ // See if our various things were able to register
+ let registrationTypes = [
+ "content",
+ "locale",
+ "skin",
+ "override",
+ "resource",
+ ];
+ for (let i = 0; i < testProtocols.length; i++) {
+ let protocol = testProtocols[i];
+ for (let j = 0; j < registrationTypes.length; j++) {
+ let type = registrationTypes[j];
+ dump("Testing protocol '" + protocol.scheme + "' with type '" + type +
+ "'\n");
+ let expectedURI = protocol.scheme + "://foo/";
+ let sourceURI = "chrome://" + protocol.scheme + "/" + type + "/";
+ switch (type) {
+ case "content":
+ expectedURI += protocol.scheme + ".xul";
+ break;
+ case "locale":
+ expectedURI += protocol.scheme + ".dtd";
+ break;
+ case "skin":
+ expectedURI += protocol.scheme + ".css";
+ break;
+ case "override":
+ sourceURI = "chrome://good-package/content/override-" +
+ protocol.scheme + ".xul";
+ break;
+ case "resource":
+ sourceURI = "resource://" + protocol.scheme + "/";
+ break;
+ };
+ try {
+ let ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ sourceURI = ios.newURI(sourceURI, null, null);
+ let uri;
+ if (type == "resource") {
+ // resources go about a slightly different way than everything else
+ let rph = ios.getProtocolHandler("resource").
+ QueryInterface(Ci.nsIResProtocolHandler);
+ // this throws for packages that are not registered
+ uri = rph.resolveURI(sourceURI);
+ }
+ else {
+ // this throws for packages that are not registered
+ uri = cr.convertChromeURL(sourceURI).spec;
+ }
+
+ if (protocol.shouldRegister) {
+ do_check_eq(expectedURI, uri);
+ }
+ else {
+ // Overrides will not throw, so we'll get to here. We want to make
+ // sure that the two strings are not the same in this situation.
+ do_check_neq(expectedURI, uri);
+ }
+ }
+ catch (e) {
+ if (protocol.shouldRegister) {
+ dump(e + "\n");
+ do_throw("Should have registered our URI for protocol " +
+ protocol.scheme);
+ }
+ }
+ }
+ }
+
+ // Unregister our factories so we do not leak
+ for (let i = 0; i < factories.length; i++) {
+ let factory = factories[i];
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
+ .unregisterFactory(factory.CID, factory);
+ }
+}
diff --git a/chrome/test/unit/test_resolve_uris.js b/chrome/test/unit/test_resolve_uris.js
new file mode 100644
index 0000000000..30ae9bc268
--- /dev/null
+++ b/chrome/test/unit/test_resolve_uris.js
@@ -0,0 +1,93 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// head_crtestutils.js doesn't get included in the child by default
+if (typeof registerManifests === "undefined") {
+ load("../unit/head_crtestutils.js");
+}
+
+var manifestFile = do_get_file("../unit/data/test_resolve_uris.manifest");
+
+var manifests = [ manifestFile ];
+registerManifests(manifests);
+
+var ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+
+function do_run_test()
+{
+ let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+
+ // If we don't have libxul or e10s then we don't have process separation, so
+ // we don't need to worry about checking for new chrome.
+ var appInfo = Cc["@mozilla.org/xre/app-info;1"];
+ if (!appInfo ||
+ (appInfo.getService(Ci.nsIXULRuntime).processType ==
+ Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT)) {
+ cr.checkForNewChrome();
+ }
+
+ // See if our various things were able to register
+ let registrationTypes = [
+ "content",
+ "locale",
+ "skin",
+ "override",
+ "resource",
+ ];
+
+ for (let j = 0; j < registrationTypes.length; j++) {
+ let type = registrationTypes[j];
+ dump("Testing type '" + type + "'\n");
+ let expectedURI = "resource://foo/foo-" + type + "/";
+ let sourceURI = "chrome://foo/" + type + "/";
+ switch (type) {
+ case "content":
+ expectedURI += "foo.xul";
+ break;
+ case "locale":
+ expectedURI += "foo.dtd";
+ break;
+ case "skin":
+ expectedURI += "foo.css";
+ break;
+ case "override":
+ sourceURI = "chrome://good-package/content/override-me.xul";
+ expectedURI += "override-me.xul";
+ break;
+ case "resource":
+ expectedURI = ios.newFileURI(manifestFile.parent).spec;
+ sourceURI = "resource://foo/";
+ break;
+ };
+ try {
+ sourceURI = ios.newURI(sourceURI, null, null);
+ let uri;
+ if (type == "resource") {
+ // resources go about a slightly different way than everything else
+ let rph = ios.getProtocolHandler("resource").
+ QueryInterface(Ci.nsIResProtocolHandler);
+ uri = rph.resolveURI(sourceURI);
+ }
+ else {
+ uri = cr.convertChromeURL(sourceURI).spec;
+ }
+
+ do_check_eq(expectedURI, uri);
+ }
+ catch (e) {
+ dump(e + "\n");
+ do_throw("Should have registered a handler for type '" +
+ type + "'\n");
+ }
+ }
+}
+
+if (typeof run_test === "undefined") {
+ run_test = function() {
+ do_run_test();
+ };
+}
diff --git a/chrome/test/unit/xpcshell.ini b/chrome/test/unit/xpcshell.ini
new file mode 100644
index 0000000000..3b9f84547f
--- /dev/null
+++ b/chrome/test/unit/xpcshell.ini
@@ -0,0 +1,20 @@
+[DEFAULT]
+head = head_crtestutils.js
+tail =
+support-files = data/**
+
+[test_abi.js]
+[test_bug292789.js]
+[test_bug380398.js]
+[test_bug397073.js]
+[test_bug399707.js]
+[test_bug401153.js]
+[test_bug415367.js]
+[test_bug519468.js]
+[test_bug564667.js]
+tags = addons
+[test_bug848297.js]
+[test_crlf.js]
+[test_data_protocol_registration.js]
+[test_no_remote_registration.js]
+[test_resolve_uris.js]
diff --git a/chrome/test/unit_ipc/test_resolve_uris_ipc.js b/chrome/test/unit_ipc/test_resolve_uris_ipc.js
new file mode 100644
index 0000000000..8babc23fd9
--- /dev/null
+++ b/chrome/test/unit_ipc/test_resolve_uris_ipc.js
@@ -0,0 +1,9 @@
+//
+// Run test script in content process instead of chrome (xpcshell's default)
+//
+
+function run_test() {
+ load("../unit/test_resolve_uris.js");
+ do_run_test();
+ run_test_in_child("../unit/test_resolve_uris.js");
+}
diff --git a/chrome/test/unit_ipc/xpcshell.ini b/chrome/test/unit_ipc/xpcshell.ini
new file mode 100644
index 0000000000..1633bf995c
--- /dev/null
+++ b/chrome/test/unit_ipc/xpcshell.ini
@@ -0,0 +1,10 @@
+[DEFAULT]
+head =
+tail =
+skip-if = toolkit == 'android'
+support-files =
+ !/chrome/test/unit/data/**
+ !/chrome/test/unit/test_resolve_uris.js
+ !/chrome/test/unit/head_crtestutils.js
+
+[test_resolve_uris_ipc.js]