[tor-commits] [torbrowser/maint-2.4] Update patches for Firefox 17ESR.

mikeperry at torproject.org mikeperry at torproject.org
Thu Jan 17 01:20:19 UTC 2013


commit 4281125f4d3d7a2c337d48b6569689ab254083da
Author: Mike Perry <mikeperry-git at fscked.org>
Date:   Wed Jan 16 00:19:54 2013 -0800

    Update patches for Firefox 17ESR.
---
 ...-Block-Components.interfaces-from-content.patch |   37 +
 ...nents.interfaces-lookupMethod-from-conten.patch |   50 --
 ...0002-Make-Permissions-Manager-memory-only.patch |   28 +-
 ...-Make-Intermediate-Cert-Store-memory-only.patch |   21 +-
 .../firefox/0004-Add-a-string-based-cacheKey.patch |   32 +-
 .../0005-Block-all-plugins-except-flash.patch      |   20 +-
 ...ontent-pref-service-memory-only-clearable.patch |   10 +-
 ...owser-exit-when-not-launched-from-Vidalia.patch |   52 +-
 .../0008-Disable-SSL-Session-ID-tracking.patch     |    4 +-
 ...observer-event-to-close-persistent-connec.patch |   20 +-
 ...ice-and-system-specific-CSS-Media-Queries.patch |  101 +--
 ...11-Limit-the-number-of-fonts-per-document.patch |   97 ++-
 .../0012-Rebrand-Firefox-to-TorBrowser.patch       |   29 +-
 .../0013-Make-Download-manager-memory-only.patch   |   18 +-
 .../0014-Add-DDG-and-StartPage-to-Omnibox.patch    |    4 +-
 ...-nsICacheService.EvictEntries-synchronous.patch |   23 +-
 .../firefox/0016-Prevent-WebSocket-DNS-leak.patch  |   55 +-
 ...ize-HTTP-request-order-and-pipeline-depth.patch |  296 +++-----
 ...Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch |  545 ++++++++++++
 ...th-headers-before-the-modify-request-obse.patch |   52 --
 ...Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch |  532 ------------
 ...d-mozIThirdPartyUtil.getFirstPartyURI-API.patch |  154 ++++
 .../0020-Add-canvas-image-extraction-prompt.patch  |  548 ++++++++++++
 ...d-mozIThirdPartyUtil.getFirstPartyURI-API.patch |  155 ----
 .../0021-Add-canvas-image-extraction-prompt.patch  |  551 ------------
 ...nt-window-coordinates-for-mouse-event-scr.patch |   77 ++
 ...se-physical-screen-info.-via-window-and-w.patch |  310 +++++++
 ...nt-window-coordinates-for-mouse-event-scr.patch |   43 -
 ...se-physical-screen-info.-via-window-and-w.patch |  312 -------
 ...not-expose-system-colors-to-CSS-or-canvas.patch |  466 ++++++++++
 ...not-expose-system-colors-to-CSS-or-canvas.patch |  537 ------------
 ...solate-the-Image-Cache-per-url-bar-domain.patch |  912 ++++++++++++++++++++
 .../0025-nsIHTTPChannel.redirectTo-API.patch       |  474 ++++++++++
 ...26-Isolate-DOM-storage-to-first-party-URI.patch |  776 +++++++++++++++++
 34 files changed, 4673 insertions(+), 2668 deletions(-)

diff --git a/src/current-patches/firefox/0001-Block-Components.interfaces-from-content.patch b/src/current-patches/firefox/0001-Block-Components.interfaces-from-content.patch
new file mode 100644
index 0000000..7a2faac
--- /dev/null
+++ b/src/current-patches/firefox/0001-Block-Components.interfaces-from-content.patch
@@ -0,0 +1,37 @@
+From 60f2318ffa6e9a3bdb37192378e0711aa14bd772 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Tue, 4 Dec 2012 15:41:09 -0800
+Subject: [PATCH 01/26] Block Components.interfaces from content
+
+This patch removes the ability of content script to access
+Components.interfaces.*.
+
+Components.interfaces is useful for fingerprinting the platform, OS, and
+Firebox version.
+
+It appears to have no other legitimate use. See also:
+https://bugzilla.mozilla.org/show_bug.cgi?id=429070
+https://trac.torproject.org/projects/tor/ticket/2874
+
+Note: We no longer block Components.lookupMethod, because we no longer rely on
+JS hooks for fingerprinting defenses.
+---
+ js/xpconnect/src/XPCComponents.cpp |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
+index 3a14254..4040349 100644
+--- a/js/xpconnect/src/XPCComponents.cpp
++++ b/js/xpconnect/src/XPCComponents.cpp
+@@ -4838,7 +4838,7 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
+ NS_IMETHODIMP
+ nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
+ {
+-    static const char* allowed[] = { "interfaces", "interfacesByID", "results", nullptr};
++    static const char* allowed[] = { "results", nullptr};
+     *_retval = xpc_CheckAccessList(propertyName, allowed);
+     return NS_OK;
+ }
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0001-Block-Components.interfaces-lookupMethod-from-conten.patch b/src/current-patches/firefox/0001-Block-Components.interfaces-lookupMethod-from-conten.patch
deleted file mode 100644
index 1a82800..0000000
--- a/src/current-patches/firefox/0001-Block-Components.interfaces-lookupMethod-from-conten.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 1c2ccbea73720db5405602e4033c69b706068a8b Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 1 Feb 2012 15:40:40 -0800
-Subject: [PATCH 01/24] Block Components.interfaces,lookupMethod from content
-
-This patch removes the ability of content script to access
-Components.interfaces.* as well as call or access Components.lookupMethod.
-
-These two interfaces seem to be exposed to content script only to make our
-lives difficult. Components.lookupMethod can undo our JS hooks, and
-Components.interfaces is useful for fingerprinting the platform, OS, and
-Firebox version.
-
-They appear to have no other legitimate use. See also:
-https://bugzilla.mozilla.org/show_bug.cgi?id=429070
-https://trac.torproject.org/projects/tor/ticket/2873
-https://trac.torproject.org/projects/tor/ticket/2874
----
- js/xpconnect/src/XPCComponents.cpp |    8 ++++++--
- 1 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
-index 38bfe08..7224b9b 100644
---- a/js/xpconnect/src/XPCComponents.cpp
-+++ b/js/xpconnect/src/XPCComponents.cpp
-@@ -4502,7 +4502,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
- NS_IMETHODIMP
- nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
- {
--    static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
-+    // XXX: Pref observer? Also, is this what we want? Seems like a plan
-+    //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
-+    static const char* allowed[] = { "isSuccessCode", nsnull };
-     *_retval = xpc_CheckAccessList(methodName, allowed);
-     return NS_OK;
- }
-@@ -4511,7 +4513,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
- NS_IMETHODIMP
- nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
- {
--    static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
-+    // XXX: Pref observer? Also, is this what we want? Seems like a plan
-+    //    static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
-+    static const char* allowed[] = { "results", nsnull};
-     *_retval = xpc_CheckAccessList(propertyName, allowed);
-     return NS_OK;
- }
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch b/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch
index fa23d93..cb04eae 100644
--- a/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch
+++ b/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch
@@ -1,7 +1,7 @@
-From cd983b1b57b1f4ae10c8deec5aa12ec957fdc855 Mon Sep 17 00:00:00 2001
+From db27e73d62d4f680b98a4ad9e7493b62070e23ae Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 1 Feb 2012 15:45:16 -0800
-Subject: [PATCH 02/24] Make Permissions Manager memory-only
+Date: Tue, 4 Dec 2012 15:45:59 -0800
+Subject: [PATCH 02/26] Make Permissions Manager memory-only
 
 This patch exposes a pref 'permissions.memory_only' that properly isolates the
 permissions manager to memory, which is responsible for all user specified
@@ -16,21 +16,21 @@ https://trac.torproject.org/projects/tor/ticket/2950
  1 files changed, 31 insertions(+), 3 deletions(-)
 
 diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
-index 67eb216..12cc7cf 100644
+index 9c50080..4102408 100644
 --- a/extensions/cookie/nsPermissionManager.cpp
 +++ b/extensions/cookie/nsPermissionManager.cpp
-@@ -58,6 +58,10 @@
- #include "mozStorageHelper.h"
- #include "mozStorageCID.h"
- #include "nsXULAppAPI.h"
+@@ -24,6 +24,10 @@
+ #include "nsIPrincipal.h"
+ #include "nsContentUtils.h"
+ #include "nsIScriptSecurityManager.h"
 +#include "nsCOMPtr.h"
 +#include "nsIPrefService.h"
 +#include "nsIPrefBranch.h"
 +#include "nsIPrefBranch2.h"
  
- static nsPermissionManager *gPermissionManager = nsnull;
+ static nsPermissionManager *gPermissionManager = nullptr;
  
-@@ -203,6 +207,11 @@ nsPermissionManager::Init()
+@@ -301,6 +305,11 @@ nsPermissionManager::Init()
      mObserverService->AddObserver(this, "profile-do-change", true);
    }
  
@@ -42,7 +42,7 @@ index 67eb216..12cc7cf 100644
    if (IsChildProcess()) {
      // Get the permissions from the parent process
      InfallibleTArray<IPC::Permission> perms;
-@@ -251,8 +260,18 @@ nsPermissionManager::InitDB(bool aRemoveFile)
+@@ -356,8 +365,18 @@ nsPermissionManager::InitDB(bool aRemoveFile)
    if (!storage)
      return NS_ERROR_UNEXPECTED;
  
@@ -62,7 +62,7 @@ index 67eb216..12cc7cf 100644
    NS_ENSURE_SUCCESS(rv, rv);
  
    bool ready;
-@@ -262,7 +281,11 @@ nsPermissionManager::InitDB(bool aRemoveFile)
+@@ -367,7 +386,11 @@ nsPermissionManager::InitDB(bool aRemoveFile)
      rv = permissionsFile->Remove(false);
      NS_ENSURE_SUCCESS(rv, rv);
  
@@ -75,7 +75,7 @@ index 67eb216..12cc7cf 100644
      NS_ENSURE_SUCCESS(rv, rv);
  
      mDBConn->GetConnectionReady(&ready);
-@@ -783,7 +806,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
+@@ -1052,7 +1075,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
  {
    ENSURE_NOT_CHILD_PROCESS;
  
@@ -88,7 +88,7 @@ index 67eb216..12cc7cf 100644
 +  } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
      // The profile is about to change,
      // or is going away because the application is shutting down.
-     if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
+     mIsShuttingDown = true;
 -- 
 1.7.5.4
 
diff --git a/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch
index b10fb85..a367d67 100644
--- a/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch
+++ b/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch
@@ -1,25 +1,26 @@
-From f100a7979e1a44863a8a67a09743f0e17b5dd14e Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at fscked.org>
-Date: Fri, 19 Aug 2011 17:58:23 -0700
-Subject: [PATCH 03/24] Make Intermediate Cert Store memory-only.
+From ac380269829788ddbd721d642ec57af0fff350de Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Tue, 4 Dec 2012 15:51:07 -0800
+Subject: [PATCH 03/26] Make Intermediate Cert Store memory-only.
 
 This patch makes the intermediate SSL cert store exist in memory only.
 
 The pref must be set before startup in prefs.js.
 https://trac.torproject.org/projects/tor/ticket/2949
 ---
- security/manager/ssl/src/nsNSSComponent.cpp |   15 ++++++++++++++-
- 1 files changed, 14 insertions(+), 1 deletions(-)
+ security/manager/ssl/src/nsNSSComponent.cpp |   17 +++++++++++++++--
+ 1 files changed, 15 insertions(+), 2 deletions(-)
 
 diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
-index a08c4ef..0ec3713 100644
+index c9205bc..159985c 100644
 --- a/security/manager/ssl/src/nsNSSComponent.cpp
 +++ b/security/manager/ssl/src/nsNSSComponent.cpp
-@@ -1730,8 +1730,21 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
+@@ -1736,8 +1736,21 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
      // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
      // "/usr/lib/nss/libnssckbi.so".
-     PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
+     uint32_t init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
 -    SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
+-                                         SECMOD_DB, init_flags);
 +    bool nocertdb = false;
 +    mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
 +
@@ -33,7 +34,7 @@ index a08c4ef..0ec3713 100644
 +        init_rv = ::NSS_NoDB_Init(NULL);
 +    } else {
 +        init_rv = ::NSS_Initialize(profileStr.get(), "", "",
-                                          SECMOD_DB, init_flags);
++                                          SECMOD_DB, init_flags);
 +    }
  
      if (init_rv != SECSuccess) {
diff --git a/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch b/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch
index f3afa97..c1ca50a 100644
--- a/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch
+++ b/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch
@@ -1,7 +1,7 @@
-From d674d09bc233d200b1ebc47f8e6ac4ebd6e4225a Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at fscked.org>
-Date: Fri, 2 Sep 2011 20:47:02 -0700
-Subject: [PATCH 04/24] Add a string-based cacheKey.
+From e991fbe8787ad8a50621f6a11633a121910d77fb Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Tue, 4 Dec 2012 16:01:42 -0800
+Subject: [PATCH 04/26] Add a string-based cacheKey.
 
 Used for isolating cache according to same-origin policy.
 ---
@@ -11,10 +11,10 @@ Used for isolating cache according to same-origin policy.
  3 files changed, 30 insertions(+), 0 deletions(-)
 
 diff --git a/netwerk/base/public/nsICachingChannel.idl b/netwerk/base/public/nsICachingChannel.idl
-index 2da46d6..4ee5774 100644
+index 3119dd9..fd2ec89 100644
 --- a/netwerk/base/public/nsICachingChannel.idl
 +++ b/netwerk/base/public/nsICachingChannel.idl
-@@ -98,6 +98,13 @@ interface nsICachingChannel : nsICacheInfoChannel
+@@ -65,6 +65,13 @@ interface nsICachingChannel : nsICacheInfoChannel
      attribute nsISupports cacheKey;
  
      /**
@@ -29,10 +29,10 @@ index 2da46d6..4ee5774 100644
       * may fail if the disk cache is not present.  The value of this attribute
       * is usually only settable during the processing of a channel's
 diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
-index dec2a83..97bd84c 100644
+index f1ae96a..9223d08 100644
 --- a/netwerk/protocol/http/nsHttpChannel.cpp
 +++ b/netwerk/protocol/http/nsHttpChannel.cpp
-@@ -2392,6 +2392,12 @@ nsHttpChannel::AssembleCacheKey(const char *spec, PRUint32 postID,
+@@ -2721,6 +2721,12 @@ nsHttpChannel::AssembleCacheKey(const char *spec, uint32_t postID,
          cacheKey.Append(buf);
      }
  
@@ -45,8 +45,8 @@ index dec2a83..97bd84c 100644
      if (!cacheKey.IsEmpty()) {
          cacheKey.AppendLiteral("uri=");
      }
-@@ -4695,6 +4701,22 @@ nsHttpChannel::SetCacheForOfflineUse(bool value)
- }
+@@ -5179,6 +5185,22 @@ nsHttpChannel::SetCacheTokenCachedCharset(const nsACString &aCharset)
+ //-----------------------------------------------------------------------------
  
  NS_IMETHODIMP
 +nsHttpChannel::GetCacheDomain(nsACString &value)
@@ -65,17 +65,17 @@ index dec2a83..97bd84c 100644
 +}
 +
 +NS_IMETHODIMP
- nsHttpChannel::GetOfflineCacheClientID(nsACString &value)
+ nsHttpChannel::GetCacheToken(nsISupports **token)
  {
-     value = mOfflineCacheClientID;
+     NS_ENSURE_ARG_POINTER(token);
 diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
-index 88ce469..53538cf 100644
+index 5b8c654..5b4ddb9 100644
 --- a/netwerk/protocol/http/nsHttpChannel.h
 +++ b/netwerk/protocol/http/nsHttpChannel.h
-@@ -303,6 +303,7 @@ private:
-     nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
+@@ -298,6 +298,7 @@ private:
      nsCacheAccessMode                 mOfflineCacheAccess;
-     nsCString                         mOfflineCacheClientID;
+     uint32_t                          mOfflineCacheLastModifiedTime;
+     nsCOMPtr<nsIApplicationCache>     mApplicationCacheForWrite;
 +    nsCString                         mCacheDomain;
  
      // auth specific data
diff --git a/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch b/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch
index e7a831e..f452b0f 100644
--- a/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch
+++ b/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch
@@ -1,7 +1,7 @@
-From 88a390822d232ba037de1f15091977ca7e1064bf Mon Sep 17 00:00:00 2001
+From 1ff6423fed745b7efd041fb6397065bd39a16d1a Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 1 Feb 2012 15:50:15 -0800
-Subject: [PATCH 05/24] Block all plugins except flash.
+Date: Tue, 4 Dec 2012 16:03:13 -0800
+Subject: [PATCH 05/26] Block all plugins except flash.
 
 We cannot use the @mozilla.org/extensions/blocklist;1 service, because we
 actually want to stop plugins from ever entering the browser's process space
@@ -17,12 +17,12 @@ on a better way. Until then, it is delta-darwinism for us.
  2 files changed, 35 insertions(+), 0 deletions(-)
 
 diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp
-index 992bcd4..f56f231 100644
+index b4233fa..1fe506a 100644
 --- a/dom/plugins/base/nsPluginHost.cpp
 +++ b/dom/plugins/base/nsPluginHost.cpp
-@@ -1968,6 +1968,35 @@ bool nsPluginHost::IsDuplicatePlugin(nsPluginTag * aPluginTag)
-   return false;
- }
+@@ -2040,6 +2040,35 @@ struct CompareFilesByTime
+ 
+ } // anonymous namespace
  
 +PRBool nsPluginHost::GhettoBlacklist(nsIFile *pluginFile)
 +{
@@ -56,7 +56,7 @@ index 992bcd4..f56f231 100644
  typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
  
  nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
-@@ -2101,6 +2130,10 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
+@@ -2144,6 +2173,10 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
        continue;
      }
  
@@ -68,10 +68,10 @@ index 992bcd4..f56f231 100644
      if (!pluginTag) {
        nsPluginFile pluginFile(localfile);
 diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h
-index 39a8891..c262abf 100644
+index fdaa76d..9e328a2 100644
 --- a/dom/plugins/base/nsPluginHost.h
 +++ b/dom/plugins/base/nsPluginHost.h
-@@ -278,6 +278,8 @@ private:
+@@ -261,6 +261,8 @@ private:
    // Loads all cached plugins info into mCachedPlugins
    nsresult ReadPluginInfo();
  
diff --git a/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch b/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch
index 17af793..32eb7c2 100644
--- a/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch
+++ b/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch
@@ -1,7 +1,7 @@
-From 71ba98d81a6ecada62af4d2ee03be050d371d996 Mon Sep 17 00:00:00 2001
+From 60c8edec8d90c6661ab5577970800c01b1205e02 Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at fscked.org>
 Date: Thu, 8 Sep 2011 08:40:17 -0700
-Subject: [PATCH 06/24] Make content pref service memory-only + clearable
+Subject: [PATCH 06/26] Make content pref service memory-only + clearable
 
 This prevents random urls from being inserted into content-prefs.sqllite in
 the profile directory as content prefs change (includes site-zoom and perhaps
@@ -11,10 +11,10 @@ other site prefs?).
  1 files changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/toolkit/components/contentprefs/nsContentPrefService.js b/toolkit/components/contentprefs/nsContentPrefService.js
-index adfb650..1619d5f 100644
+index ed8ad2e..794c9f3 100644
 --- a/toolkit/components/contentprefs/nsContentPrefService.js
 +++ b/toolkit/components/contentprefs/nsContentPrefService.js
-@@ -1240,7 +1240,7 @@ ContentPrefService.prototype = {
+@@ -1206,7 +1206,7 @@ ContentPrefService.prototype = {
  
      var dbConnection;
  
@@ -23,7 +23,7 @@ index adfb650..1619d5f 100644
        dbConnection = this._dbCreate(dbService, dbFile);
      else {
        try {
-@@ -1288,7 +1288,7 @@ ContentPrefService.prototype = {
+@@ -1254,7 +1254,7 @@ ContentPrefService.prototype = {
    },
  
    _dbCreate: function ContentPrefService__dbCreate(aDBService, aDBFile) {
diff --git a/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch b/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch
index cc496d3..80c55c2 100644
--- a/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch
+++ b/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch
@@ -1,7 +1,7 @@
-From 12579def59d67416b841f6b0a6eadfd94bba72e9 Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at fscked.org>
-Date: Sun, 9 Oct 2011 22:50:07 -0700
-Subject: [PATCH 07/24] Make Tor Browser exit when not launched from Vidalia
+From 5f9d3e18c44f8b25f34e68fb6b35b229d3561559 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Tue, 4 Dec 2012 16:29:24 -0800
+Subject: [PATCH 07/26] Make Tor Browser exit when not launched from Vidalia
 
 Turns out the Windows 7 UI encourages users to "dock" their Tor Browser app
 for easy relaunch. If they manage to do this, we should fail closed rather
@@ -12,35 +12,33 @@ https://trac.torproject.org/projects/tor/ticket/4192. We can do a better
 localized fix w/ a translated alert menu later, if it seems like this might
 actually be common.
 ---
- browser/base/content/browser.js |   15 +++++++++++++++
- 1 files changed, 15 insertions(+), 0 deletions(-)
+ browser/base/content/browser.js |   13 +++++++++++++
+ 1 files changed, 13 insertions(+), 0 deletions(-)
 
 diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
-index f16a0c5..20e3666 100644
+index 80174dc..1fc137c 100644
 --- a/browser/base/content/browser.js
 +++ b/browser/base/content/browser.js
-@@ -1217,6 +1217,21 @@ function BrowserStartup() {
+@@ -1096,6 +1096,19 @@ var gBrowserInit = {
+     // setup simple gestures support
+     gGestureSupport.init(true);
  
-   prepareForStartup();
++    // If this is not a TBB profile, exit. 
++    // Solves https://trac.torproject.org/projects/tor/ticket/4192
++    var foundPref = false;
++    try {
++      foundPref = gPrefService.prefHasUserValue("torbrowser.version");
++    } catch(e) {
++      //dump("No pref: "+e);
++    }
++    if(!foundPref) {
++      var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
++                           .getService(Components.interfaces.nsIAppStartup);
++      appStartup.quit(3); // Force all windows to close, and then quit.
++    }
  
-+  // If this is not a TBB profile, exit. 
-+  // Solves https://trac.torproject.org/projects/tor/ticket/4192
-+  var foundPref = false;
-+  try {
-+    foundPref = gPrefService.prefHasUserValue("torbrowser.version");
-+  } catch(e) {
-+    //dump("No pref: "+e);
-+  }
-+  if(!foundPref) {
-+    var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
-+                         .getService(Components.interfaces.nsIAppStartup);
-+    appStartup.quit(3); // Force all windows to close, and then quit.
-+  }
-+
-+
-   if (uriToLoad && !isLoadingBlank) {
-     if (uriToLoad instanceof Ci.nsISupportsArray) {
-       let count = uriToLoad.Count();
+     if (uriToLoad && uriToLoad != "about:blank") {
+       if (uriToLoad instanceof Ci.nsISupportsArray) {
 -- 
 1.7.5.4
 
diff --git a/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch b/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch
index 39e1483..9b3de6b 100644
--- a/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch
+++ b/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch
@@ -1,7 +1,7 @@
-From 7586e413761858ce705d25d4a1673e608a162bed Mon Sep 17 00:00:00 2001
+From 376f1f9b86d4b04e121d25553feed2c4380088d2 Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at fscked.org>
 Date: Wed, 7 Dec 2011 19:36:38 -0800
-Subject: [PATCH 08/24] Disable SSL Session ID tracking.
+Subject: [PATCH 08/26] Disable SSL Session ID tracking.
 
 We can't easily bind SSL Session ID tracking to url bar domain,
 so we have to disable them to satisfy
diff --git a/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch b/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch
index e693c71..a366141 100644
--- a/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch
+++ b/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch
@@ -1,7 +1,7 @@
-From 9c6f997dd9a44336af9a1db17f5b680cc80a0e6c Mon Sep 17 00:00:00 2001
+From 74b6b99f7ac6e4a4153613feeafef53a5c3b9a4a Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 1 Feb 2012 15:53:28 -0800
-Subject: [PATCH 09/24] Provide an observer event to close persistent
+Date: Fri, 7 Sep 2012 16:18:26 -0700
+Subject: [PATCH 09/26] Provide an observer event to close persistent
  connections
 
 We need to prevent linkability across "New Identity", which includes closing
@@ -11,20 +11,20 @@ keep-alive connections.
  1 files changed, 7 insertions(+), 0 deletions(-)
 
 diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
-index 281d6ff..8125681 100644
+index d897a2c..e33ff08 100644
 --- a/netwerk/protocol/http/nsHttpHandler.cpp
 +++ b/netwerk/protocol/http/nsHttpHandler.cpp
-@@ -325,6 +325,7 @@ nsHttpHandler::Init()
+@@ -312,6 +312,7 @@ nsHttpHandler::Init()
          mObserverService->AddObserver(this, "net:clear-active-logins", true);
          mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
          mObserverService->AddObserver(this, "net:prune-dead-connections", true);
-+        mObserverService->AddObserver(this, "net:prune-all-connections", PR_TRUE);
++        mObserverService->AddObserver(this, "net:prune-all-connections", true);
+         mObserverService->AddObserver(this, "net:failed-to-process-uri-content", true);
      }
   
-     return NS_OK;
-@@ -1504,6 +1505,12 @@ nsHttpHandler::Observe(nsISupports *subject,
-             mConnMgr->PruneDeadConnections();
-         }
+@@ -1576,6 +1577,12 @@ nsHttpHandler::Observe(nsISupports *subject,
+         if (uri && mConnMgr)
+             mConnMgr->ReportFailedToProcess(uri);
      }
 +    else if (strcmp(topic, "net:prune-all-connections") == 0) {
 +        if (mConnMgr) {
diff --git a/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch b/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch
index 14e584c..9e49285 100644
--- a/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch
+++ b/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch
@@ -1,17 +1,17 @@
-From 8f97f2f36adb9e4416f3d19af10880c800c846c2 Mon Sep 17 00:00:00 2001
+From 278e285820d9082d2be161fbdee6c230a4477204 Mon Sep 17 00:00:00 2001
 From: Kathleen Brade <brade at pearlcrescent.com>
-Date: Thu, 4 Oct 2012 14:28:48 -0400
-Subject: [PATCH 10/24] Limit device and system specific CSS Media Queries.
+Date: Wed, 28 Nov 2012 09:49:40 -0500
+Subject: [PATCH 10/26] Limit device and system specific CSS Media Queries.
 
 ---
- layout/style/nsMediaFeatures.cpp |   71 ++++++++++++++++++++++++-------------
- 1 files changed, 46 insertions(+), 25 deletions(-)
+ layout/style/nsMediaFeatures.cpp |   68 +++++++++++++++++++++++++-------------
+ 1 files changed, 45 insertions(+), 23 deletions(-)
 
 diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp
-index 6eca06e..5b1df7e 100644
+index d5741ea..5f2e6dd 100644
 --- a/layout/style/nsMediaFeatures.cpp
 +++ b/layout/style/nsMediaFeatures.cpp
-@@ -130,6 +130,9 @@ GetDeviceContextFor(nsPresContext* aPresContext)
+@@ -98,6 +98,9 @@ GetDeviceContextFor(nsPresContext* aPresContext)
  static nsSize
  GetDeviceSize(nsPresContext* aPresContext)
  {
@@ -21,7 +21,7 @@ index 6eca06e..5b1df7e 100644
      nsSize size;
      if (aPresContext->IsRootPaginatedDocument())
          // We want the page size, including unprintable areas and margins.
-@@ -140,6 +143,7 @@ GetDeviceSize(nsPresContext* aPresContext)
+@@ -108,6 +111,7 @@ GetDeviceSize(nsPresContext* aPresContext)
          GetDeviceContextFor(aPresContext)->
              GetDeviceSurfaceDimensions(size.width, size.height);
      return size;
@@ -29,36 +29,7 @@ index 6eca06e..5b1df7e 100644
  }
  
  static nsresult
-@@ -183,17 +187,17 @@ static nsresult
- GetDeviceOrientation(nsPresContext* aPresContext, const nsMediaFeature*,
-                      nsCSSValue& aResult)
- {
--    nsSize size = GetDeviceSize(aPresContext);
--    PRInt32 orientation;
--    if (size.width > size.height) {
--        orientation = NS_STYLE_ORIENTATION_LANDSCAPE;
--    } else {
--        // Per spec, square viewports should be 'portrait'
--        orientation = NS_STYLE_ORIENTATION_PORTRAIT;
--    }
--
--    aResult.SetIntValue(orientation, eCSSUnit_Enumerated);
--    return NS_OK;
-+  nsSize size = GetDeviceSize(aPresContext);
-+  PRInt32 orientation;
-+  if (size.width > size.height) {
-+      orientation = NS_STYLE_ORIENTATION_LANDSCAPE;
-+  } else {
-+      // Per spec, square viewports should be 'portrait'
-+      orientation = NS_STYLE_ORIENTATION_PORTRAIT;
-+  }
-+
-+  aResult.SetIntValue(orientation, eCSSUnit_Enumerated);
-+  return NS_OK;
- }
- 
- static nsresult
-@@ -236,13 +240,17 @@ static nsresult
+@@ -204,13 +208,17 @@ static nsresult
  GetColor(nsPresContext* aPresContext, const nsMediaFeature*,
           nsCSSValue& aResult)
  {
@@ -67,9 +38,9 @@ index 6eca06e..5b1df7e 100644
 -    // 424386).
 -    // FIXME: On a monochrome device, return 0!
 -    nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
--    PRUint32 depth;
+-    uint32_t depth;
 -    dx->GetDepth(depth);
-+    PRUint32 depth = 24; // Always return 24 to non-chrome callers.
++    uint32_t depth = 24; // Always return 24 to non-chrome callers.
 +
 +    if (aPresContext->IsChrome()) {
 +        // FIXME:  This implementation is bogus.  nsDeviceContext
@@ -83,25 +54,42 @@ index 6eca06e..5b1df7e 100644
      // The spec says to use bits *per color component*, so divide by 3,
      // and round down, since the spec says to use the smallest when the
      // color components differ.
-@@ -280,9 +288,14 @@ static nsresult
+@@ -248,18 +256,23 @@ static nsresult
  GetResolution(nsPresContext* aPresContext, const nsMediaFeature*,
                nsCSSValue& aResult)
  {
--    // Resolution values are in device pixels, not CSS pixels.
--    nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
--    float dpi = float(dx->AppUnitsPerPhysicalInch()) / float(dx->AppUnitsPerDevPixel());
+-    // Resolution measures device pixels per CSS (inch/cm/pixel).  We
+-    // return it in device pixels per CSS inches.
+-    //
+-    // However, on platforms where the CSS viewport is not fixed to the
+-    // screen viewport, use the device resolution instead (bug 779527).
+-    nsIPresShell *shell = aPresContext->PresShell();
+-    float appUnitsPerInch = shell->GetIsViewportOverridden() ?
+-            GetDeviceContextFor(aPresContext)->AppUnitsPerPhysicalInch() :
+-            nsPresContext::AppUnitsPerCSSInch();
+-
+-    float dpi = appUnitsPerInch /
 +    float dpi = 96; // Always return 96 to non-chrome callers.
 +
 +    if (aPresContext->IsChrome()) {
-+      // Resolution values are in device pixels, not CSS pixels.
-+      nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
-+      dpi = float(dx->AppUnitsPerPhysicalInch()) / float(dx->AppUnitsPerDevPixel());
++        // Resolution measures device pixels per CSS (inch/cm/pixel).  We
++        // return it in device pixels per CSS inches.
++        //
++        // However, on platforms where the CSS viewport is not fixed to the
++        // screen viewport, use the device resolution instead (bug 779527).
++        nsIPresShell *shell = aPresContext->PresShell();
++        float appUnitsPerInch = shell->GetIsViewportOverridden() ?
++                GetDeviceContextFor(aPresContext)->AppUnitsPerPhysicalInch() :
++                nsPresContext::AppUnitsPerCSSInch();
++
++        dpi = appUnitsPerInch /
+                 float(aPresContext->AppUnitsPerDevPixel());
 +    }
 +
      aResult.SetFloatValue(dpi, eCSSUnit_Inch);
      return NS_OK;
  }
-@@ -311,8 +324,12 @@ static nsresult
+@@ -288,8 +301,12 @@ static nsresult
  GetDevicePixelRatio(nsPresContext* aPresContext, const nsMediaFeature*,
                      nsCSSValue& aResult)
  {
@@ -116,10 +104,11 @@ index 6eca06e..5b1df7e 100644
    return NS_OK;
  }
  
-@@ -320,18 +337,21 @@ static nsresult
+@@ -297,20 +314,24 @@ static nsresult
  GetSystemMetric(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
                  nsCSSValue& aResult)
  {
++  aResult.Reset();
 +  if (aPresContext->IsChrome()) {
      NS_ABORT_IF_FALSE(aFeature->mValueType == nsMediaFeature::eBoolInteger,
                        "unexpected type");
@@ -135,16 +124,20 @@ index 6eca06e..5b1df7e 100644
  GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
                  nsCSSValue& aResult)
  {
-+  if (aPresContext->IsChrome()) {
-     aResult.Reset();
+-    aResult.Reset();
++  aResult.Reset();
  #ifdef XP_WIN
-     PRUint8 windowsThemeId =
-@@ -350,7 +370,8 @@ GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
++  if (aPresContext->IsChrome()) {
+     uint8_t windowsThemeId =
+         nsCSSRuleProcessor::GetWindowsThemeIdentifier();
+ 
+@@ -326,8 +347,9 @@ GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
+             break;
          }
      }
++  }
  #endif
 -    return NS_OK;
-+  }
 +  return NS_OK;
  }
  
diff --git a/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch b/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch
index ff9e618..c6eb24f 100644
--- a/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch
+++ b/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch
@@ -1,7 +1,7 @@
-From cb3a6f45dd2c15d6b75084e1a4dded18ed638632 Mon Sep 17 00:00:00 2001
+From 9ae4f468446cd1edef028d2b60ccca91cad2bc2e Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 1 Feb 2012 16:01:21 -0800
-Subject: [PATCH 11/24] Limit the number of fonts per document.
+Date: Wed, 5 Dec 2012 12:25:21 -0800
+Subject: [PATCH 11/26] Limit the number of fonts per document.
 
 We create two prefs:
 browser.display.max_font_count and browser.display.max_font_attempts.
@@ -17,25 +17,39 @@ If a pref is not set or is negative, that limit does not apply.
 This is done to address:
 https://www.torproject.org/projects/torbrowser/design/#fingerprinting-linkability
 ---
+ gfx/thebes/gfxPangoFonts.cpp  |    1 +
  layout/base/nsPresContext.cpp |  100 +++++++++++++++++++++++++++++++++++++++++
  layout/base/nsPresContext.h   |    9 ++++
- layout/style/nsRuleNode.cpp   |   13 ++++-
- 3 files changed, 119 insertions(+), 3 deletions(-)
+ layout/style/nsCSSParser.cpp  |    1 +
+ layout/style/nsRuleNode.cpp   |   14 +++++-
+ 5 files changed, 122 insertions(+), 3 deletions(-)
 
+diff --git a/gfx/thebes/gfxPangoFonts.cpp b/gfx/thebes/gfxPangoFonts.cpp
+index c94a299..88c8b8e 100644
+--- a/gfx/thebes/gfxPangoFonts.cpp
++++ b/gfx/thebes/gfxPangoFonts.cpp
+@@ -1408,6 +1408,7 @@ gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
+         const nsTArray< nsCountedRef<FcPattern> > *familyFonts = nullptr;
+ 
+         // Is this an @font-face family?
++        // XXX: Make use of this + pass to nsFont??
+         bool isUserFont = false;
+         if (mUserFontSet) {
+             // Have some @font-face definitions
 diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
-index e1587db..9690d9c 100644
+index d47460a..8064fb4 100644
 --- a/layout/base/nsPresContext.cpp
 +++ b/layout/base/nsPresContext.cpp
-@@ -98,6 +98,8 @@
- #include "FrameLayerBuilder.h"
+@@ -63,6 +63,8 @@
  #include "nsDOMMediaQueryList.h"
  #include "nsSMILAnimationController.h"
+ #include "mozilla/css/ImageLoader.h"
 +#include "nsString.h"
 +#include "nsUnicharUtils.h"
  
  #ifdef IBMBIDI
  #include "nsBidiPresUtils.h"
-@@ -706,6 +708,10 @@ nsPresContext::GetUserPreferences()
+@@ -712,6 +714,10 @@ nsPresContext::GetUserPreferences()
    // * use fonts?
    mUseDocumentFonts =
      Preferences::GetInt("browser.display.use_document_fonts") != 0;
@@ -46,7 +60,7 @@ index e1587db..9690d9c 100644
  
    // * replace backslashes with Yen signs? (bug 245770)
    mEnableJapaneseTransform =
-@@ -1300,6 +1306,100 @@ nsPresContext::GetDefaultFont(PRUint8 aFontID) const
+@@ -1328,6 +1334,100 @@ nsPresContext::GetDefaultFont(uint8_t aFontID, nsIAtom *aLanguage) const
    return font;
  }
  
@@ -148,10 +162,10 @@ index e1587db..9690d9c 100644
  nsPresContext::SetFullZoom(float aZoom)
  {
 diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h
-index ecd01d8..552a69a 100644
+index 5f0f528..ffe4766 100644
 --- a/layout/base/nsPresContext.h
 +++ b/layout/base/nsPresContext.h
-@@ -548,6 +548,13 @@ public:
+@@ -467,6 +467,13 @@ public:
      }
    }
  
@@ -162,11 +176,11 @@ index ecd01d8..552a69a 100644
 +  PRBool FontUseCountReached(const nsFont &font);
 +  PRBool FontAttemptCountReached(const nsFont &font);
 +
-   PRInt32 MinFontSize() const {
-     return NS_MAX(mMinFontSize, mMinimumFontSizePref);
-   }
-@@ -1117,6 +1124,8 @@ protected:
-   PRUint32              mInterruptChecksToSkip;
+   /**
+    * Get the minimum font size for the specified language. If aLanguage
+    * is nullptr, then the document's language is used.
+@@ -1104,6 +1111,8 @@ protected:
+   uint32_t              mInterruptChecksToSkip;
  
    mozilla::TimeStamp    mReflowStartTime;
 +  PRInt32               mMaxFontAttempts;
@@ -174,32 +188,49 @@ index ecd01d8..552a69a 100644
  
    unsigned              mHasPendingInterrupt : 1;
    unsigned              mInterruptsEnabled : 1;
+diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
+index 37a19c4..30fd021 100644
+--- a/layout/style/nsCSSParser.cpp
++++ b/layout/style/nsCSSParser.cpp
+@@ -8719,6 +8719,7 @@ CSSParserImpl::ParseFontSrc(nsCSSValue& aValue)
+         return false;
+       }
+ 
++      // XXX: Getting closer...
+       // the style parameters to the nsFont constructor are ignored,
+       // because it's only being used to call EnumerateFamilies
+       nsFont font(family, 0, 0, 0, 0, 0, 0);
 diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
-index 27336bf..827585a 100644
+index 64504fb..33ce21e 100644
 --- a/layout/style/nsRuleNode.cpp
 +++ b/layout/style/nsRuleNode.cpp
-@@ -3091,6 +3091,7 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+@@ -2954,6 +2954,7 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
+     aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
+                                  aFont->mLanguage);
+ 
++  // XXX: Bleh. Disable these somehow?
+   // -moz-system-font: enum (never inherit!)
+   MOZ_STATIC_ASSERT(
+     NS_STYLE_FONT_CAPTION        == LookAndFeel::eFont_Caption &&
+@@ -3439,14 +3440,15 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
  
-   // See if there is a minimum font-size constraint to honor
-   nscoord minimumFontSize = mPresContext->MinFontSize();
-+  PRBool isXUL = PR_FALSE;
+   bool useDocumentFonts =
+     mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
++  bool isXUL = PR_FALSE;
  
-   if (minimumFontSize < 0)
-     minimumFontSize = 0;
-@@ -3102,10 +3103,10 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+   // See if we are in the chrome
    // We only need to know this to determine if we have to use the
-   // document fonts (overriding the useDocumentFonts flag), or to
-   // determine if we have to override the minimum font-size constraint.
--  if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
+   // document fonts (overriding the useDocumentFonts flag).
+-  if (!useDocumentFonts && mPresContext->IsChrome()) {
 +  if (mPresContext->IsChrome()) {
      // if we are not using document fonts, but this is a XUL document,
      // then we use the document fonts anyway
 -    useDocumentFonts = true;
-+    isXUL = PR_TRUE;
-     minimumFontSize = 0;
++    isXUL = true;
    }
  
-@@ -3120,9 +3121,13 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+   // Figure out if we are a generic font
+@@ -3460,9 +3462,13 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
      // generic?
      nsFont::GetGenericID(font->mFont.name, &generic);
  
@@ -214,8 +245,8 @@ index 27336bf..827585a 100644
        // Extract the generic from the specified font family...
        nsAutoString genericName;
        if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
-@@ -3158,6 +3163,8 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
-                                minimumFontSize, font);
+@@ -3498,6 +3504,8 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+                                font);
    }
  
 +  if (font->mGenericID == kGenericFont_NONE)
diff --git a/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch b/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch
index e627238..6fc03f6 100644
--- a/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch
+++ b/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch
@@ -1,7 +1,7 @@
-From 5820fc300fe1cae27752673e8721a19e70bf727c Mon Sep 17 00:00:00 2001
-From: Erinn Clark <erinn at torproject.org>
-Date: Wed, 25 Apr 2012 09:14:00 -0300
-Subject: [PATCH 12/24] Rebrand Firefox to TorBrowser
+From e0675863770a2a33fef70079a73233a9e78a3c48 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Tue, 28 Aug 2012 18:05:11 -0700
+Subject: [PATCH 12/26] Rebrand Firefox to TorBrowser
 
 This patch does some basic renaming of Firefox to TorBrowser. The rest of the
 branding is done by images and icons.
@@ -12,18 +12,24 @@ branding is done by images and icons.
  3 files changed, 7 insertions(+), 7 deletions(-)
 
 diff --git a/browser/branding/official/configure.sh b/browser/branding/official/configure.sh
-index 4d3d297..e9b3738 100644
+index 55f3f18..33102b0 100644
 --- a/browser/branding/official/configure.sh
 +++ b/browser/branding/official/configure.sh
-@@ -1,2 +1,2 @@
+@@ -2,5 +2,5 @@
+ # 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/.
+ 
 -MOZ_APP_DISPLAYNAME=Firefox
 +MOZ_APP_DISPLAYNAME=TorBrowser
  MOZ_UA_BUILDID=20100101
 diff --git a/browser/branding/official/locales/en-US/brand.dtd b/browser/branding/official/locales/en-US/brand.dtd
-index 142d79b..c137e04 100644
+index 8e7f6c9..76e405d 100644
 --- a/browser/branding/official/locales/en-US/brand.dtd
 +++ b/browser/branding/official/locales/en-US/brand.dtd
-@@ -1,4 +1,4 @@
+@@ -2,7 +2,7 @@
+    - 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/. -->
+ 
 -<!ENTITY  brandShortName        "Firefox">
 -<!ENTITY  brandFullName         "Mozilla Firefox">
 -<!ENTITY  vendorShortName       "Mozilla">
@@ -32,10 +38,13 @@ index 142d79b..c137e04 100644
 +<!ENTITY  vendorShortName       "Tor Project">
  <!ENTITY  trademarkInfo.part1   "Firefox and the Firefox logos are trademarks of the Mozilla Foundation.">
 diff --git a/browser/branding/official/locales/en-US/brand.properties b/browser/branding/official/locales/en-US/brand.properties
-index 5f3ad54..62ac2fd 100644
+index 4a67c55..9ae168e 100644
 --- a/browser/branding/official/locales/en-US/brand.properties
 +++ b/browser/branding/official/locales/en-US/brand.properties
-@@ -1,6 +1,6 @@
+@@ -2,9 +2,9 @@
+ # 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/.
+ 
 -brandShortName=Firefox
 -brandFullName=Mozilla Firefox
 -vendorShortName=Mozilla
diff --git a/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch b/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch
index 1ad0972..f9f938f 100644
--- a/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch
+++ b/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch
@@ -1,7 +1,7 @@
-From 28178fb406d86b317b13b16ade3b06e5e1500c7e Mon Sep 17 00:00:00 2001
+From 2b0cc620b5d9af06262c9fdfc1ef8f34b5682859 Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 25 Apr 2012 13:39:35 -0700
-Subject: [PATCH 13/24] Make Download manager memory only.
+Date: Tue, 4 Dec 2012 16:05:55 -0800
+Subject: [PATCH 13/26] Make Download manager memory only.
 
 Solves https://trac.torproject.org/projects/tor/ticket/4017.
 
@@ -18,10 +18,10 @@ this breaks enough times in conflict.
  2 files changed, 3 insertions(+), 3 deletions(-)
 
 diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
-index 00a6e7d..2e83f61 100644
+index 024686f..7845544 100644
 --- a/toolkit/components/downloads/nsDownloadManager.cpp
 +++ b/toolkit/components/downloads/nsDownloadManager.cpp
-@@ -1992,7 +1992,7 @@ nsDownloadManager::Observe(nsISupports *aSubject,
+@@ -2002,7 +2002,7 @@ nsDownloadManager::Observe(nsISupports *aSubject,
      if (NS_LITERAL_STRING("memory").Equals(aData))
        return SwitchDatabaseTypeTo(DATABASE_MEMORY);
      else if (NS_LITERAL_STRING("disk").Equals(aData))
@@ -30,7 +30,7 @@ index 00a6e7d..2e83f61 100644
    }
    else if (strcmp(aTopic, "alertclickcallback") == 0) {
      nsCOMPtr<nsIDownloadManagerUI> dmui =
-@@ -2069,7 +2069,7 @@ nsDownloadManager::OnLeavePrivateBrowsingMode()
+@@ -2079,7 +2079,7 @@ nsDownloadManager::OnLeavePrivateBrowsingMode()
    (void)ResumeAllDownloads(false);
  
    // Switch back to the on-disk DB again
@@ -40,10 +40,10 @@ index 00a6e7d..2e83f61 100644
    mInPrivateBrowsing = false;
  }
 diff --git a/toolkit/components/downloads/nsDownloadManager.h b/toolkit/components/downloads/nsDownloadManager.h
-index 54312e4..cb63b52 100644
+index bbe7f39..6bdad89 100644
 --- a/toolkit/components/downloads/nsDownloadManager.h
 +++ b/toolkit/components/downloads/nsDownloadManager.h
-@@ -90,7 +90,7 @@ public:
+@@ -54,7 +54,7 @@ public:
  
    virtual ~nsDownloadManager();
    nsDownloadManager() :
@@ -51,7 +51,7 @@ index 54312e4..cb63b52 100644
 +      mDBType(DATABASE_MEMORY)
      , mInPrivateBrowsing(false)
  #ifdef DOWNLOAD_SCANNER
-     , mScanner(nsnull)
+     , mScanner(nullptr)
 -- 
 1.7.5.4
 
diff --git a/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch b/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch
index adbd3d4..4cb626f 100644
--- a/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch
+++ b/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch
@@ -1,7 +1,7 @@
-From 2a80e84755c97cf4ff3ab63bda1bd5f0936d9594 Mon Sep 17 00:00:00 2001
+From a2de75def3f8ac88a5f5092ab9bd6815d088e7d5 Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
 Date: Wed, 25 Apr 2012 15:03:46 -0700
-Subject: [PATCH 14/24] Add DDG and StartPage to Omnibox.
+Subject: [PATCH 14/26] Add DDG and StartPage to Omnibox.
 
 You mean there are search engines that don't require captchas if you don't
 have a cookie? Holy crap. Get those in there now.
diff --git a/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch b/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch
index 93a989b..87547a7 100644
--- a/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch
+++ b/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch
@@ -1,36 +1,33 @@
-From 20c94cb890a8872c07ba13686e293ca147b85cd6 Mon Sep 17 00:00:00 2001
+From 0d030acc527aa206582e3f19219f4fa128f98bef Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Tue, 1 May 2012 15:02:03 -0700
-Subject: [PATCH 15/24] Make nsICacheService.EvictEntries synchronous
+Date: Tue, 4 Dec 2012 16:25:52 -0800
+Subject: [PATCH 15/26] Make nsICacheService.EvictEntries synchronous
 
 This fixes a race condition that allows cache-based EverCookies to persist for
 a brief time (on the order of minutes?) after cache clearing/"New Identity".
 
 https://trac.torproject.org/projects/tor/ticket/5715
 ---
- netwerk/cache/nsCacheService.cpp |   15 +++++++++++++--
- 1 files changed, 13 insertions(+), 2 deletions(-)
+ netwerk/cache/nsCacheService.cpp |   14 +++++++++++++-
+ 1 files changed, 13 insertions(+), 1 deletions(-)
 
 diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp
-index 83ce887..e9f1a76 100644
+index e88de40..4225742 100644
 --- a/netwerk/cache/nsCacheService.cpp
 +++ b/netwerk/cache/nsCacheService.cpp
-@@ -1316,10 +1316,21 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
-     return NS_OK;
- }
+@@ -1555,7 +1555,19 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
  
--
  NS_IMETHODIMP nsCacheService::EvictEntries(nsCacheStoragePolicy storagePolicy)
  {
--    return  EvictEntriesForClient(nsnull, storagePolicy);
+-    return  EvictEntriesForClient(nullptr, storagePolicy);
 +    NS_IMETHODIMP r;
-+    r = EvictEntriesForClient(nsnull, storagePolicy);
++    r = EvictEntriesForClient(nullptr, storagePolicy);
 +
 +    // XXX: Bloody hack until we get this notifier in FF14.0:
 +    // https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsICacheListener#onCacheEntryDoomed%28%29
 +    if (storagePolicy == nsICache::STORE_ANYWHERE &&
 +            NS_IsMainThread() && gService && gService->mInitialized) {
-+        nsCacheServiceAutoLock lock;
++        nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_EVICTENTRIESFORCLIENT));
 +        gService->DoomActiveEntries();
 +        gService->ClearDoomList();
 +        (void) SyncWithCacheIOThread();
diff --git a/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch b/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch
index bb70b17..ef61b59 100644
--- a/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch
+++ b/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch
@@ -1,7 +1,7 @@
-From 976f0d4fabb6b0b50c83192d622827357c761bd3 Mon Sep 17 00:00:00 2001
+From ac25d901493198966643d88d0541eaa2735b122f Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 2 May 2012 17:44:39 -0700
-Subject: [PATCH 16/24] Prevent WebSocket DNS leak.
+Date: Tue, 28 Aug 2012 18:07:37 -0700
+Subject: [PATCH 16/26] Prevent WebSocket DNS leak.
 
 This is due to an improper implementation of the WebSocket spec by Mozilla.
 
@@ -29,10 +29,10 @@ bug can't turn up in other components or due to 3rd party addons.
  3 files changed, 30 insertions(+), 3 deletions(-)
 
 diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp
-index 68ad8a5..1253b2f 100644
+index 114af2e..4d66dc5 100644
 --- a/netwerk/dns/nsDNSService2.cpp
 +++ b/netwerk/dns/nsDNSService2.cpp
-@@ -383,6 +383,7 @@ nsDNSService::Init()
+@@ -374,6 +374,7 @@ nsDNSService::Init()
      bool     enableIDN        = true;
      bool     disableIPv6      = false;
      bool     disablePrefetch  = false;
@@ -40,7 +40,7 @@ index 68ad8a5..1253b2f 100644
      int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
      
      nsAdoptingCString ipv4OnlyDomains;
-@@ -404,6 +405,10 @@ nsDNSService::Init()
+@@ -399,6 +400,10 @@ nsDNSService::Init()
  
          // If a manual proxy is in use, disable prefetch implicitly
          prefs->GetIntPref("network.proxy.type", &proxyType);
@@ -51,7 +51,7 @@ index 68ad8a5..1253b2f 100644
      }
  
      if (mFirstTime) {
-@@ -420,7 +425,7 @@ nsDNSService::Init()
+@@ -419,7 +424,7 @@ nsDNSService::Init()
  
              // Monitor these to see if there is a change in proxy configuration
              // If a manual proxy is in use, disable prefetch implicitly
@@ -68,7 +68,7 @@ index 68ad8a5..1253b2f 100644
  
          // Disable prefetching either by explicit preference or if a manual proxy is configured 
          mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
-@@ -547,6 +553,14 @@ nsDNSService::AsyncResolve(const nsACString  &hostname,
+@@ -573,6 +579,14 @@ nsDNSService::AsyncResolve(const nsACString  &hostname,
          if (mDisablePrefetch && (flags & RESOLVE_SPECULATE))
              return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
  
@@ -82,37 +82,38 @@ index 68ad8a5..1253b2f 100644
 +
          res = mResolver;
          idn = mIDN;
-     }
-@@ -597,6 +611,14 @@ nsDNSService::Resolve(const nsACString &hostname,
-         MutexAutoLock lock(mLock);
-         res = mResolver;
-         idn = mIDN;
-+
-+        PRNetAddr tempAddr;
-+        if (mDisableDNS) {
-+            // Allow IP lookups through, but nothing else.
-+            if (PR_StringToNetAddr(hostname.BeginReading(), &tempAddr) != PR_SUCCESS) {
-+                return NS_ERROR_UNKNOWN_PROXY_HOST; // XXX: NS_ERROR_NOT_IMPLEMENTED?
-+            }
-+        }
+         localDomain = mLocalDomains.GetEntry(hostname);
+@@ -669,6 +683,14 @@ nsDNSService::Resolve(const nsACString &hostname,
      }
      NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
  
++    PRNetAddr tempAddr;
++    if (mDisableDNS) {
++        // Allow IP lookups through, but nothing else.
++        if (PR_StringToNetAddr(hostname.BeginReading(), &tempAddr) != PR_SUCCESS) {
++            return NS_ERROR_UNKNOWN_PROXY_HOST; // XXX: NS_ERROR_NOT_IMPLEMENTED?
++        }
++    }
++
+     const nsACString *hostPtr = &hostname;
+ 
+     if (localDomain) {
 diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h
-index 1749b41..3ec8eba 100644
+index 26d0939..c62c9dd 100644
 --- a/netwerk/dns/nsDNSService2.h
 +++ b/netwerk/dns/nsDNSService2.h
-@@ -70,4 +70,5 @@ private:
+@@ -41,5 +41,6 @@ private:
      bool                      mDisableIPv6;
      bool                      mDisablePrefetch;
      bool                      mFirstTime;
 +    bool                      mDisableDNS;
+     nsTHashtable<nsCStringHashKey> mLocalDomains;
  };
 diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp
-index 9e446e9..42aa6ca 100644
+index 56a71ab..345df6e 100644
 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp
 +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
-@@ -1698,8 +1698,12 @@ WebSocketChannel::ApplyForAdmission()
+@@ -2157,8 +2157,12 @@ WebSocketChannel::ApplyForAdmission()
    LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
    nsCOMPtr<nsIThread> mainThread;
    NS_GetMainThread(getter_AddRefs(mainThread));
@@ -121,8 +122,8 @@ index 9e446e9..42aa6ca 100644
 +  rv = dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mDNSRequest));
 +  if (NS_FAILED(rv)) {
 +      // Fall back to hostname on dispatch failure
-+      mDNSRequest = nsnull;
-+      OnLookupComplete(nsnull, nsnull, rv);
++      mDNSRequest = nullptr;
++      OnLookupComplete(nullptr, nullptr, rv);
 +  }
  
    return NS_OK;
diff --git a/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch b/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch
index f1814e7..118c5d6 100644
--- a/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch
+++ b/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch
@@ -1,7 +1,7 @@
-From 36f826e64411a74912ba1adebd1a30b84716bf84 Mon Sep 17 00:00:00 2001
+From 53ec410990f8616d5c3cf3bfbb9feaa4a83ff722 Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git at torproject.org>
-Date: Wed, 6 Jun 2012 11:08:56 -0700
-Subject: [PATCH 17/24] Randomize HTTP request order and pipeline depth.
+Date: Tue, 4 Dec 2012 17:38:51 -0800
+Subject: [PATCH 17/26] Randomize HTTP request order and pipeline depth.
 
 This is an experimental defense against
 http://lorre.uni.lu/~andriy/papers/acmccs-wpes11-fingerprinting.pdf
@@ -11,241 +11,149 @@ https://blog.torproject.org/blog/experimental-defense-website-traffic-fingerprin
 
 This defense has been improved since that blog post to additionally randomize
 the order and concurrency of non-pipelined HTTP requests.
+
+This patch is also different from the 10.x ESR patch, as the pipelining
+code has changed. We may want to set network.http.pipelining.aggressive to get
+similar behavior...
+
+The good news is we now randomize SPDY request order as well as pipeline
+request order (though SPDY is still disabled by default in TBB).
 ---
- netwerk/protocol/http/nsHttpConnectionMgr.cpp |  136 ++++++++++++++++++++++++-
- netwerk/protocol/http/nsHttpConnectionMgr.h   |    5 +
- 2 files changed, 136 insertions(+), 5 deletions(-)
+ netwerk/protocol/http/nsHttpConnectionMgr.cpp |   67 +++++++++++++++++++++++--
+ netwerk/protocol/http/nsHttpConnectionMgr.h   |    3 +
+ 2 files changed, 65 insertions(+), 5 deletions(-)
 
 diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
-index 23ef893..788368f 100644
+index 526df93..abae041 100644
 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
 +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
-@@ -94,6 +94,12 @@ nsHttpConnectionMgr::nsHttpConnectionMgr()
- {
-     LOG(("Creating nsHttpConnectionMgr @%x\n", this));
-     mCT.Init();
+@@ -20,6 +20,8 @@
+ #include "prnetdb.h"
+ #include "mozilla/Telemetry.h"
+ 
++#include <stdlib.h>
 +
-+    nsresult rv;
-+    mRandomGenerator = do_GetService("@mozilla.org/security/random-generator;1", &rv);
-+    if (NS_FAILED(rv)) {
-+        mRandomGenerator = nsnull;
-+    }
- }
+ using namespace mozilla;
+ using namespace mozilla::net;
  
- nsHttpConnectionMgr::~nsHttpConnectionMgr()
-@@ -342,8 +348,12 @@ nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline *pipeline)
-         nsConnectionEntry *ent = mCT.Get(ci->HashKey());
-         if (ent) {
-             // search for another request to pipeline...
--            PRInt32 i, count = ent->mPendingQ.Length();
--            for (i=0; i<count; ++i) {
-+            PRInt32 i, h, count = ent->mPendingQ.Length();
-+            PRInt32* ind = new PRInt32[count];
-+            ShuffleRequestOrder((PRUint32*)ind, (PRUint32)count);
-+       
-+            for (h=0; h<count; ++h) {
-+                i = ind[h]; // random request sequence
-                 nsHttpTransaction *trans = ent->mPendingQ[i];
-                 if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
-                     pipeline->AddTransaction(trans);
-@@ -354,6 +364,8 @@ nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline *pipeline)
-                     break;
-                 }
-             }
+@@ -39,15 +41,46 @@ InsertTransactionSorted(nsTArray<nsHttpTransaction*> &pendingQ, nsHttpTransactio
+     // insert into queue with smallest valued number first.  search in reverse
+     // order under the assumption that many of the existing transactions will
+     // have the same priority (usually 0).
++    uint32_t len = pendingQ.Length();
++    uint32_t begin = 0, end = len+1;
++    int found_begin = 0;
+ 
+-    for (int32_t i=pendingQ.Length()-1; i>=0; --i) {
++    if (pendingQ.IsEmpty()) {
++        pendingQ.InsertElementAt(0, trans);
++        return;
++    }
 +
-+            delete [] ind;
++// #define PRESERVE_PRIORITY_ORDER 
++#ifdef PRESERVE_PRIORITY_ORDER
++    // XXX: Untested
++    for (uint32_t i=0; i < len; ++i) {
+         nsHttpTransaction *t = pendingQ[i];
+-        if (trans->Priority() >= t->Priority()) {
+-            pendingQ.InsertElementAt(i+1, trans);
+-            return;
++
++        /* As soon as we see a priority >= us, our insertion
++         * range starts there */
++        if (!found_begin && t->Priority() >= trans->Priority()) {
++            begin = i;
++            found_begin = 1;
++        }
++        /* As soon as we see a priority > us, our insertion
++         * range ends there */
++        if (t->Priority() > trans->Priority()) {
++            end = i;
++            break;
          }
      }
+-    pendingQ.InsertElementAt(0, trans);
++
++    // XXX Verify that begin..end are all == trans->Priority()
++#endif
++
++    // Choose random destination begin..end
++    uint32_t count = end - begin;
++    if (count == 0) count = 1;
++
++    // FIXME: rand() is not crypto-secure.. but meh, this code will probably
++    // change like 2 dozen more times before merge, and rand() is probably 
++    // good enough for our purposes anyways.
++    pendingQ.InsertElementAt(begin + (rand()%count), trans);
  }
-@@ -585,12 +597,17 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
-     LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry [ci=%s]\n",
-         ent->mConnInfo->HashKey().get()));
  
--    PRInt32 i, count = ent->mPendingQ.Length();
-+    PRUint32 h, i = 0, count = ent->mPendingQ.Length();
-     if (count > 0) {
-         LOG(("  pending-count=%u\n", count));
-         nsHttpTransaction *trans = nsnull;
-         nsHttpConnection *conn = nsnull;
--        for (i=0; i<count; ++i) {
+ //-----------------------------------------------------------------------------
+@@ -68,6 +101,12 @@ nsHttpConnectionMgr::nsHttpConnectionMgr()
+     mCT.Init();
+     mAlternateProtocolHash.Init(16);
+     mSpdyPreferredHash.Init();
 +
-+        PRUint32* ind = new PRUint32[count];
-+        ShuffleRequestOrder(ind, count);
-+       
-+        for (h=0; h<count; ++h) {
-+            i = ind[h]; // random request sequence
-             trans = ent->mPendingQ[i];
++    nsresult rv;
++    mRandomGenerator = do_GetService("@mozilla.org/security/random-generator;1", &rv);
++    if (NS_FAILED(rv)) {
++        mRandomGenerator = nullptr;
++    }
+ }
  
-             // When this transaction has already established a half-open
-@@ -610,6 +627,7 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
-             if (conn)
-                 break;
-         }
-+        delete [] ind;
-         if (conn) {
-             LOG(("  dispatching pending transaction...\n"));
+ nsHttpConnectionMgr::~nsHttpConnectionMgr()
+@@ -1120,6 +1159,19 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, uint8_t cap
  
-@@ -694,6 +712,19 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, PRUint8 cap
-         maxPersistConns = mMaxPersistConnsPerHost;
-     }
+     LOG(("   connection count = %d, limit %d\n", totalCount, maxPersistConns));
  
 +    // Fuzz maxConns for website fingerprinting attack
 +    // We create a range of maxConns/5 up to 6*maxConns/5 
 +    // because this function is called repeatedly, and we'll
-+    // end up converging to the high side of concurrent connections
++    // end up converging on the high side of concurrent connections
 +    // after a short while. 
-+    PRUint8 *bytes = nsnull;
++    PRUint8 *bytes = nullptr;
 +    nsresult rv = mRandomGenerator->GenerateRandomBytes(1, &bytes);
 +    NS_ENSURE_SUCCESS(rv, rv);
 +
-+    bytes[0] = bytes[0] % (maxConns + 1);
-+    maxConns = (maxConns/5) + bytes[0];
++    bytes[0] = bytes[0] % (maxPersistConns + 1);
++    maxPersistConns = (maxPersistConns/5) + bytes[0];
 +    NS_Free(bytes);
 +
      // use >= just to be safe
-     return (totalCount >= maxConns) || ( (caps & NS_HTTP_ALLOW_KEEPALIVE) &&
-                                          (persistCount >= maxPersistConns) );
-@@ -865,7 +896,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
-     nsHttpPipeline *pipeline = nsnull;
-     if (conn->SupportsPipelining() && (caps & NS_HTTP_ALLOW_PIPELINING)) {
-         LOG(("  looking to build pipeline...\n"));
--        if (BuildPipeline(ent, trans, &pipeline))
-+        if (BuildRandomizedPipeline(ent, trans, &pipeline))
-             trans = pipeline;
-     }
+     bool result = (totalCount >= maxPersistConns);
+     LOG(("  result: %s", result ? "true" : "false"));
+@@ -1297,6 +1349,11 @@ nsHttpConnectionMgr::AddToShortestPipeline(nsConnectionEntry *ent,
  
-@@ -938,6 +969,101 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent,
-     return true;
- }
+     maxdepth = PR_MIN(maxdepth, depthLimit);
  
-+
-+// Generate a shuffled request ordering sequence 
-+void
-+nsHttpConnectionMgr::ShuffleRequestOrder(PRUint32 *ind, PRUint32 count)
-+{
-+   PRUint32 i;
-+   PRUint32 *rints;
-+
-+   for (i=0; i<count; ++i) {
-+       ind[i] = i;
-+   }
-+   nsresult rv = mRandomGenerator->GenerateRandomBytes(sizeof(PRUint32)*count,
-+                                                       (PRUint8**)&rints);
-+   if (NS_FAILED(rv))
-+       return; // Leave unshuffled if error
-+
-+   for (i=0; i < count; ++i) {
-+       PRInt32 temp = ind[i];
-+       ind[i] = ind[rints[i]%count]; 
-+       ind[rints[i]%count] = temp;
-+   }
-+   NS_Free(rints);
-+}
-+
-+bool
-+nsHttpConnectionMgr::BuildRandomizedPipeline(nsConnectionEntry *ent,
-+                                   nsAHttpTransaction *firstTrans,
-+                                   nsHttpPipeline **result)
-+{
-+    if (mRandomGenerator == nsnull)
-+        return BuildPipeline(ent, firstTrans, result);
-+    if (mMaxPipelinedRequests < 2)
-+        return PR_FALSE;
-+
-+    nsresult rv;
-+    PRUint8 *bytes = nsnull;
-+
-+    nsHttpPipeline *pipeline = nsnull;
-+    nsHttpTransaction *trans;
-+
-+    PRUint32 i = 0, numAdded = 0, numAllowed = 0;
-+    PRUint32 max = 0;
-+
-+    while (i < ent->mPendingQ.Length()) {
-+        if (ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING)
-+            numAllowed++;
-+        i++;
++    if (maxdepth/2 > 1) { 
++      // This is a crazy hack to randomize pipeline depth a bit more..
++      maxdepth = 1 + maxdepth/2 + (rand() % (maxdepth/2));
 +    }
 +
-+    rv = mRandomGenerator->GenerateRandomBytes(1, &bytes);
-+    NS_ENSURE_SUCCESS(rv, rv);
-+    // 4...12
-+    max = 4 + (bytes[0] % (mMaxPipelinedRequests + 1));
-+    NS_Free(bytes);
-+
-+    while (numAllowed > 0) {
-+        rv = mRandomGenerator->GenerateRandomBytes(1, &bytes);
-+        NS_ENSURE_SUCCESS(rv, rv);
-+        i = bytes[0] % ent->mPendingQ.Length();
-+        NS_Free(bytes);
-+
-+        trans = ent->mPendingQ[i];
-+
-+        if (!(ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING))
-+            continue;
-+
-+        if (numAdded == 0) {
-+            pipeline = new nsHttpPipeline;
-+            if (!pipeline)
-+                return PR_FALSE;
-+            pipeline->AddTransaction(firstTrans);
-+            numAdded = 1;
-+        }
-+        pipeline->AddTransaction(trans);
-+
-+        // remove transaction from pending queue
-+        ent->mPendingQ.RemoveElementAt(i);
-+        NS_RELEASE(trans);
-+
-+        numAllowed--;
-+
-+        if (++numAdded == max)
-+            break;
-+    }
-+
-+    //fprintf(stderr, "Yay!!! pipelined %u/%u transactions\n", numAdded, max);
-+    LOG(("  pipelined %u/%u transactions\n", numAdded, max));
-+
-+    if (numAdded == 0)
-+        return PR_FALSE;
-+
-+    NS_ADDREF(*result = pipeline);
-+    return PR_TRUE;
-+}
-+
- nsresult
- nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
- {
+     if (maxdepth < 2)
+         return false;
+ 
 diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h
-index cdf21a9..81b282a 100644
+index 580710a..b22c669 100644
 --- a/netwerk/protocol/http/nsHttpConnectionMgr.h
 +++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
-@@ -51,6 +51,7 @@
- 
+@@ -23,6 +23,7 @@
  #include "nsIObserver.h"
  #include "nsITimer.h"
+ #include "nsIX509Cert3.h"
 +#include "nsIRandomGenerator.h"
  
  class nsHttpPipeline;
  
-@@ -276,6 +277,8 @@ private:
-     nsresult DispatchTransaction(nsConnectionEntry *, nsAHttpTransaction *,
-                                  PRUint8 caps, nsHttpConnection *);
-     bool     BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
-+    bool     BuildRandomizedPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
-+    void     ShuffleRequestOrder(PRUint32 *, PRUint32);
-     nsresult ProcessNewTransaction(nsHttpTransaction *);
-     nsresult EnsureSocketThreadTargetIfOnline();
-     void     ClosePersistentConnections(nsConnectionEntry *ent);
-@@ -353,6 +356,8 @@ private:
-     PRUint64 mTimeOfNextWakeUp;
+@@ -585,6 +586,8 @@ private:
+     uint64_t mTimeOfNextWakeUp;
      // Timer for next pruning of dead connections.
      nsCOMPtr<nsITimer> mTimer;
 +    // Random number generator for reordering HTTP pipeline
 +    nsCOMPtr<nsIRandomGenerator>             mRandomGenerator;
  
-     //
-     // the connection table
+     // A 1s tick to call nsHttpConnection::ReadTimeoutTick on
+     // active http/1 connections and check for orphaned half opens.
 -- 
 1.7.5.4
 
diff --git a/src/current-patches/firefox/0018-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch b/src/current-patches/firefox/0018-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch
new file mode 100644
index 0000000..7c2ddee
--- /dev/null
+++ b/src/current-patches/firefox/0018-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch
@@ -0,0 +1,545 @@
+From 4541bfb12c40ed13871503f7bb46ba8e5f27a8ed Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Tue, 4 Dec 2012 17:48:53 -0800
+Subject: [PATCH 18/26] Adapt Steven Michaud's Mac crashfix patch
+
+Source is: https://bugzilla.mozilla.org/show_bug.cgi?id=715885#c35
+
+Some minor tweaks were needed to get it to apply and to compile on
+MacOS.
+---
+ widget/Makefile.in                        |    1 +
+ widget/cocoa/nsChildView.mm               |   28 +++++++++++------
+ widget/gtk2/nsDragService.cpp             |    9 +++--
+ widget/nsIDragService.idl                 |    4 +--
+ widget/nsPIDragService.idl                |   48 +++++++++++++++++++++++++++++
+ widget/qt/nsDragService.h                 |    2 +
+ widget/windows/Makefile.in                |    4 ++
+ widget/windows/nsDragService.cpp          |   13 +++++---
+ widget/windows/nsDragService.h            |   12 +++---
+ widget/windows/nsNativeDragSource.cpp     |    7 ++--
+ widget/windows/nsNativeDragTarget.cpp     |   28 ++++++++++------
+ widget/windows/nsPIDragServiceWindows.idl |   46 +++++++++++++++++++++++++++
+ widget/xpwidgets/nsBaseDragService.cpp    |   16 +++++++++-
+ widget/xpwidgets/nsBaseDragService.h      |    9 ++---
+ 14 files changed, 179 insertions(+), 48 deletions(-)
+ create mode 100644 widget/nsPIDragService.idl
+ create mode 100644 widget/windows/nsPIDragServiceWindows.idl
+
+diff --git a/widget/Makefile.in b/widget/Makefile.in
+index 4ab8a48..bc5aa5c 100644
+--- a/widget/Makefile.in
++++ b/widget/Makefile.in
+@@ -106,6 +106,7 @@ XPIDLSRCS	= \
+ 		nsIClipboardDragDropHooks.idl \
+ 		nsIClipboardDragDropHookList.idl \
+ 		nsIDragSession.idl \
++		nsPIDragService.idl \
+ 		nsIDragService.idl \
+ 		nsIFormatConverter.idl \
+ 		nsIClipboard.idl \
+diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm
+index aa919fa..d5fa58f 100644
+--- a/widget/cocoa/nsChildView.mm
++++ b/widget/cocoa/nsChildView.mm
+@@ -4518,11 +4518,12 @@ static int32_t RoundUp(double aDouble)
+   if (!dragService) {
+     dragService = do_GetService(kDragServiceContractID);
+   }
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(dragService);
+ 
+   if (dragService) {
+     NSPoint pnt = [NSEvent mouseLocation];
+     FlipCocoaScreenCoordinate(pnt);
+-    dragService->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
++    dragServicePriv->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
+   }
+ }
+ 
+@@ -4543,11 +4544,13 @@ static int32_t RoundUp(double aDouble)
+   }
+ 
+   if (mDragService) {
+-    // set the dragend point from the current mouse location
+-    nsDragService* dragService = static_cast<nsDragService *>(mDragService);
+-    NSPoint pnt = [NSEvent mouseLocation];
+-    FlipCocoaScreenCoordinate(pnt);
+-    dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y)));
++    nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
++    if (dragServicePriv) {
++      // set the dragend point from the current mouse location
++      NSPoint pnt = [NSEvent mouseLocation];
++      FlipCocoaScreenCoordinate(pnt);
++      dragServicePriv->SetDragEndPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
++    }
+ 
+     // XXX: dropEffect should be updated per |operation|. 
+     // As things stand though, |operation| isn't well handled within "our"
+@@ -4558,10 +4561,15 @@ static int32_t RoundUp(double aDouble)
+     // value for NSDragOperationGeneric that is passed by other applications.
+     // All that said, NSDragOperationNone is still reliable.
+     if (operation == NSDragOperationNone) {
+-      nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
+-      dragService->GetDataTransfer(getter_AddRefs(dataTransfer));
+-      if (dataTransfer)
+-        dataTransfer->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
++      nsCOMPtr<nsIDragSession> dragSession;
++      mDragService->GetCurrentSession(getter_AddRefs(dragSession));
++      if (dragSession) {
++        nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
++        dragSession->GetDataTransfer(getter_AddRefs(dataTransfer));
++        if (dataTransfer) {
++            dataTransfer->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
++        }
++      }
+     }
+ 
+     mDragService->EndDragSession(true);
+diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp
+index 10985cc..bac4160 100644
+--- a/widget/gtk2/nsDragService.cpp
++++ b/widget/gtk2/nsDragService.cpp
+@@ -234,8 +234,8 @@ OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+         // Update the cursor position.  The last of these recorded gets used for
+         // the NS_DRAGDROP_END event.
+         nsDragService *dragService = static_cast<nsDragService*>(user_data);
+-        dragService->SetDragEndPoint(nsIntPoint(event->motion.x_root,
+-                                                event->motion.y_root));
++        dragService->SetDragEndPoint(event->motion.x_root,
++                                     event->motion.y_root);
+     } else if (sMotionEvent && (event->type != GDK_KEY_PRESS ||
+                                 event->type != GDK_KEY_RELEASE)) {
+         // Update modifier state from keypress events.
+@@ -1343,7 +1343,7 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext,
+         GdkDisplay* display = gdk_display_get_default();
+         if (display) {
+             gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+-            SetDragEndPoint(nsIntPoint(x, y));
++            SetDragEndPoint(x, y);
+         }
+     }
+ 
+@@ -1760,8 +1760,9 @@ nsDragService::ScheduleDropEvent(nsWindow *aWindow,
+         NS_WARNING("Additional drag drop ignored");
+         return FALSE;        
+     }
++    nsIntPoint pt = aWindowPoint + aWindow->WidgetToScreenOffset();
+ 
+-    SetDragEndPoint(aWindowPoint + aWindow->WidgetToScreenOffset());
++    SetDragEndPoint(pt.x, pt.y);
+ 
+     // We'll reply with gtk_drag_finish().
+     return TRUE;
+diff --git a/widget/nsIDragService.idl b/widget/nsIDragService.idl
+index 196761e..c0565bb 100644
+--- a/widget/nsIDragService.idl
++++ b/widget/nsIDragService.idl
+@@ -15,7 +15,7 @@ interface nsIDOMDragEvent;
+ interface nsIDOMDataTransfer;
+ interface nsISelection;
+ 
+-[scriptable, uuid(82B58ADA-F490-4C3D-B737-1057C4F1D052), builtinclass]
++[scriptable, uuid(82B58ADA-F490-4C3D-B737-1057C4F1D052)]
+ interface nsIDragService : nsISupports
+ {
+   const long DRAGDROP_ACTION_NONE = 0;
+@@ -112,8 +112,6 @@ interface nsIDragService : nsISupports
+    */
+   void suppress();
+   void unsuppress();
+-
+-  [noscript] void dragMoved(in long aX, in long aY);
+ };
+ 
+ 
+diff --git a/widget/nsPIDragService.idl b/widget/nsPIDragService.idl
+new file mode 100644
+index 0000000..7a703c1
+--- /dev/null
++++ b/widget/nsPIDragService.idl
+@@ -0,0 +1,48 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is mozilla.org code.
++ *
++ * The Initial Developer of the Original Code is
++ * The Mozilla Foundation.
++ * Portions created by the Initial Developer are Copyright (C) 2012
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *   Steven Michaud <smichaud at pobox.com>
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include "nsISupports.idl"
++
++[scriptable, uuid(FAD8C90B-8E1D-446A-9B6C-241486A85CBD)]
++interface nsPIDragService : nsISupports
++{
++  void dragMoved(in long aX, in long aY);
++
++  uint16_t getInputSource();
++
++  void setDragEndPoint(in long aX, in long aY);
++};
+diff --git a/widget/qt/nsDragService.h b/widget/qt/nsDragService.h
+index ee145ad..b03b74e 100644
+--- a/widget/qt/nsDragService.h
++++ b/widget/qt/nsDragService.h
+@@ -17,6 +17,8 @@ public:
+     NS_DECL_ISUPPORTS
+     NS_DECL_NSIDRAGSERVICE
+ 
++    NS_IMETHOD DragMoved(PRInt32 aX, PRInt32 aY);
++
+     nsDragService();
+ 
+ private:
+diff --git a/widget/windows/Makefile.in b/widget/windows/Makefile.in
+index ec383bd..7000ec0 100644
+--- a/widget/windows/Makefile.in
++++ b/widget/windows/Makefile.in
+@@ -88,6 +88,10 @@ ifdef MOZ_ENABLE_D3D10_LAYER
+ DEFINES		+= -DMOZ_ENABLE_D3D10_LAYER
+ endif
+ 
++XPIDLSRCS	+= \
++		nsPIDragServiceWindows.idl \
++		$(NULL)
++
+ SHARED_LIBRARY_LIBS = \
+   ../xpwidgets/$(LIB_PREFIX)xpwidgets_s.$(LIB_SUFFIX) \
+   $(NULL)
+diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp
+index 899154a..9511457 100644
+--- a/widget/windows/nsDragService.cpp
++++ b/widget/windows/nsDragService.cpp
+@@ -60,6 +60,8 @@ nsDragService::~nsDragService()
+   NS_IF_RELEASE(mDataObject);
+ }
+ 
++NS_IMPL_ISUPPORTS_INHERITED1(nsDragService, nsBaseDragService, nsPIDragServiceWindows)
++
+ bool
+ nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
+                                nsIScriptableRegion *aRegion,
+@@ -305,7 +307,7 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
+   POINT cpos;
+   cpos.x = GET_X_LPARAM(pos);
+   cpos.y = GET_Y_LPARAM(pos);
+-  SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
++  SetDragEndPoint(cpos.x, cpos.y);
+   EndDragSession(true);
+ 
+   mDoingDrag = false;
+@@ -426,25 +428,26 @@ nsDragService::GetData(nsITransferable * aTransferable, uint32_t anItem)
+ 
+ //---------------------------------------------------------
+ NS_IMETHODIMP
+-nsDragService::SetIDataObject(IDataObject * aDataObj)
++nsDragService::SetIDataObject(nsISupports * aDataObj)
+ {
++  IDataObject *dataObj = (IDataObject*) aDataObj;
+   // When the native drag starts the DragService gets
+   // the IDataObject that is being dragged
+   NS_IF_RELEASE(mDataObject);
+-  mDataObject = aDataObj;
++  mDataObject = dataObj;
+   NS_IF_ADDREF(mDataObject);
+ 
+   return NS_OK;
+ }
+ 
+ //---------------------------------------------------------
+-void
++NS_IMETHODIMP
+ nsDragService::SetDroppedLocal()
+ {
+   // Sent from the native drag handler, letting us know
+   // a drop occurred within the application vs. outside of it.
+   mSentLocalDropEvent = true;
+-  return;
++  return NS_OK;
+ }
+ 
+ //-------------------------------------------------------------------------
+diff --git a/widget/windows/nsDragService.h b/widget/windows/nsDragService.h
+index 236910a..e83167d 100644
+--- a/widget/windows/nsDragService.h
++++ b/widget/windows/nsDragService.h
+@@ -7,6 +7,7 @@
+ #define nsDragService_h__
+ 
+ #include "nsBaseDragService.h"
++#include "nsPIDragServiceWindows.h"
+ #include <windows.h>
+ #include <shlobj.h>
+ 
+@@ -20,12 +21,15 @@ class  nsString;
+  * Native Win32 DragService wrapper
+  */
+ 
+-class nsDragService : public nsBaseDragService
++class nsDragService : public nsBaseDragService, public nsPIDragServiceWindows
+ {
+ public:
+   nsDragService();
+   virtual ~nsDragService();
+-  
++
++  NS_DECL_ISUPPORTS_INHERITED
++  NS_DECL_NSPIDRAGSERVICEWINDOWS
++
+   // nsIDragService
+   NS_IMETHOD InvokeDragSession(nsIDOMNode *aDOMNode,
+                                nsISupportsArray *anArrayTransferables,
+@@ -39,13 +43,9 @@ public:
+   NS_IMETHOD EndDragSession(bool aDoneDrag);
+ 
+   // native impl.
+-  NS_IMETHOD SetIDataObject(IDataObject * aDataObj);
+   NS_IMETHOD StartInvokingDragSession(IDataObject * aDataObj,
+                                       uint32_t aActionType);
+ 
+-  // A drop occurred within the application vs. outside of it.
+-  void SetDroppedLocal();
+-
+ protected:
+   nsDataObjCollection* GetDataObjCollection(IDataObject * aDataObj);
+ 
+diff --git a/widget/windows/nsNativeDragSource.cpp b/widget/windows/nsNativeDragSource.cpp
+index 3acee30..3662c18 100644
+--- a/widget/windows/nsNativeDragSource.cpp
++++ b/widget/windows/nsNativeDragSource.cpp
+@@ -10,7 +10,7 @@
+ #include "nsIServiceManager.h"
+ #include "nsToolkit.h"
+ #include "nsWidgetsCID.h"
+-#include "nsIDragService.h"
++#include "nsDragService.h"
+ 
+ static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
+ 
+@@ -69,9 +69,10 @@ STDMETHODIMP
+ nsNativeDragSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState)
+ {
+   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
+-  if (dragService) {
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(dragService);
++  if (dragServicePriv) {
+     DWORD pos = ::GetMessagePos();
+-    dragService->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
++    dragServicePriv->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
+   }
+ 
+   if (fEsc) {
+diff --git a/widget/windows/nsNativeDragTarget.cpp b/widget/windows/nsNativeDragTarget.cpp
+index ec12f8e..8b72f6d 100644
+--- a/widget/windows/nsNativeDragTarget.cpp
++++ b/widget/windows/nsNativeDragTarget.cpp
+@@ -174,7 +174,11 @@ nsNativeDragTarget::DispatchDragDropEvent(uint32_t aEventType, POINTL aPT)
+   ModifierKeyState modifierKeyState;
+   modifierKeyState.InitInputEvent(event);
+ 
+-  event.inputSource = static_cast<nsBaseDragService*>(mDragService)->GetInputSource();
++  event.inputSource = 0;
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
++  if (dragServicePriv) {
++    dragServicePriv->GetInputSource(&event.inputSource);
++  }
+ 
+   mWidget->DispatchEvent(&event, status);
+ }
+@@ -261,9 +265,8 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
+   // This cast is ok because in the constructor we created a
+   // the actual implementation we wanted, so we know this is
+   // a nsDragService. It should be a private interface, though.
+-  nsDragService * winDragService =
+-    static_cast<nsDragService *>(mDragService);
+-  winDragService->SetIDataObject(pIDataSource);
++  nsCOMPtr<nsPIDragServiceWindows> winDragService = do_QueryInterface(mDragService);
++  winDragService->SetIDataObject((nsISupports*)pIDataSource);
+ 
+   // Now process the native drag state and then dispatch the event
+   ProcessDrag(NS_DRAGDROP_ENTER, grfKeyState, ptl, pdwEffect);
+@@ -401,8 +404,8 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
+   // This cast is ok because in the constructor we created a
+   // the actual implementation we wanted, so we know this is
+   // a nsDragService (but it should still be a private interface)
+-  nsDragService* winDragService = static_cast<nsDragService*>(mDragService);
+-  winDragService->SetIDataObject(pData);
++  nsCOMPtr<nsPIDragServiceWindows> winDragService = do_QueryInterface(mDragService);
++  winDragService->SetIDataObject((nsISupports*)pData);
+ 
+   // NOTE: ProcessDrag spins the event loop which may destroy arbitrary objects.
+   // We use strong refs to prevent it from destroying these:
+@@ -426,11 +429,14 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
+   // tell the drag service we're done with the session
+   // Use GetMessagePos to get the position of the mouse at the last message
+   // seen by the event loop. (Bug 489729)
+-  DWORD pos = ::GetMessagePos();
+-  POINT cpos;
+-  cpos.x = GET_X_LPARAM(pos);
+-  cpos.y = GET_Y_LPARAM(pos);
+-  winDragService->SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
++  if (dragServicePriv) {
++    DWORD pos = ::GetMessagePos();
++    POINT cpos;
++    cpos.x = GET_X_LPARAM(pos);
++    cpos.y = GET_Y_LPARAM(pos);
++    dragServicePriv->SetDragEndPoint(cpos.x, cpos.y);
++  }
+   serv->EndDragSession(true);
+ 
+   // release the ref that was taken in DragEnter
+diff --git a/widget/windows/nsPIDragServiceWindows.idl b/widget/windows/nsPIDragServiceWindows.idl
+new file mode 100644
+index 0000000..c8a46dd
+--- /dev/null
++++ b/widget/windows/nsPIDragServiceWindows.idl
+@@ -0,0 +1,46 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is mozilla.org code.
++ *
++ * The Initial Developer of the Original Code is
++ * The Mozilla Foundation.
++ * Portions created by the Initial Developer are Copyright (C) 2012
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *   Steven Michaud <smichaud at pobox.com>
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include "nsISupports.idl"
++
++[scriptable, uuid(6FC2117D-5EB4-441A-9C12-62A783BEBC0C)]
++interface nsPIDragServiceWindows : nsISupports
++{
++  void setIDataObject(in nsISupports aDataObj);
++
++  void setDroppedLocal();
++};
+diff --git a/widget/xpwidgets/nsBaseDragService.cpp b/widget/xpwidgets/nsBaseDragService.cpp
+index 805d83f..9b69793 100644
+--- a/widget/xpwidgets/nsBaseDragService.cpp
++++ b/widget/xpwidgets/nsBaseDragService.cpp
+@@ -55,7 +55,7 @@ nsBaseDragService::~nsBaseDragService()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS2(nsBaseDragService, nsIDragService, nsIDragSession)
++NS_IMPL_ISUPPORTS3(nsBaseDragService, nsIDragService, nsPIDragService, nsIDragSession)
+ 
+ //---------------------------------------------------------
+ NS_IMETHODIMP
+@@ -403,6 +403,20 @@ nsBaseDragService::DragMoved(int32_t aX, int32_t aY)
+   return NS_OK;
+ }
+ 
++NS_IMETHODIMP
++nsBaseDragService::SetDragEndPoint(PRInt32 aX, PRInt32 aY)
++{
++  mEndDragPoint = nsIntPoint(aX, aY);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++nsBaseDragService::GetInputSource(PRUint16* aInputSource)
++{
++  *aInputSource = mInputSource;
++  return NS_OK;
++}
++
+ static nsIPresShell*
+ GetPresShellForContent(nsIDOMNode* aDOMNode)
+ {
+diff --git a/widget/xpwidgets/nsBaseDragService.h b/widget/xpwidgets/nsBaseDragService.h
+index cb00f8e..741c287 100644
+--- a/widget/xpwidgets/nsBaseDragService.h
++++ b/widget/xpwidgets/nsBaseDragService.h
+@@ -7,6 +7,7 @@
+ #define nsBaseDragService_h__
+ 
+ #include "nsIDragService.h"
++#include "nsPIDragService.h"
+ #include "nsIDragSession.h"
+ #include "nsITransferable.h"
+ #include "nsISupportsArray.h"
+@@ -32,6 +33,7 @@ class nsICanvasElementExternal;
+  */
+ 
+ class nsBaseDragService : public nsIDragService,
++                          public nsPIDragService,
+                           public nsIDragSession
+ {
+ 
+@@ -42,14 +44,11 @@ public:
+   //nsISupports
+   NS_DECL_ISUPPORTS
+ 
+-  //nsIDragSession and nsIDragService
++  //nsIDragSession, nsIDragService and nsPIDragService
+   NS_DECL_NSIDRAGSERVICE
++  NS_DECL_NSPIDRAGSERVICE
+   NS_DECL_NSIDRAGSESSION
+ 
+-  void SetDragEndPoint(nsIntPoint aEndDragPoint) { mEndDragPoint = aEndDragPoint; }
+-
+-  uint16_t GetInputSource() { return mInputSource; }
+-
+ protected:
+ 
+   /**
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0018-Add-HTTP-auth-headers-before-the-modify-request-obse.patch b/src/current-patches/firefox/0018-Add-HTTP-auth-headers-before-the-modify-request-obse.patch
deleted file mode 100644
index 46cf611..0000000
--- a/src/current-patches/firefox/0018-Add-HTTP-auth-headers-before-the-modify-request-obse.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From c1e26c8a294abe426fd6fb84508db6074ef23379 Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at fscked.org>
-Date: Fri, 2 Sep 2011 15:33:20 -0700
-Subject: [PATCH 18/24] Add HTTP auth headers before the modify-request
- observer.
-
-Otherwise, how are we supposed to modify them?
-
-Thanks to Georg Koppen for spotting both the problem and this fix.
----
- netwerk/protocol/http/nsHttpChannel.cpp |   11 +++++++----
- 1 files changed, 7 insertions(+), 4 deletions(-)
-
-diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
-index 97bd84c..6205d62 100644
---- a/netwerk/protocol/http/nsHttpChannel.cpp
-+++ b/netwerk/protocol/http/nsHttpChannel.cpp
-@@ -316,9 +316,6 @@ nsHttpChannel::Connect(bool firstTime)
-         return NS_ERROR_DOCUMENT_NOT_CACHED;
-     }
- 
--    // check to see if authorization headers should be included
--    mAuthProvider->AddAuthorizationHeaders();
--
-     if (mLoadFlags & LOAD_NO_NETWORK_IO) {
-         return NS_ERROR_DOCUMENT_NOT_CACHED;
-     }
-@@ -3707,6 +3704,9 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
- 
-     AddCookiesToRequest();
- 
-+    // check to see if authorization headers should be included
-+    mAuthProvider->AddAuthorizationHeaders();
-+
-     // notify "http-on-modify-request" observers
-     gHttpHandler->OnModifyRequest(this);
- 
-@@ -4817,7 +4817,10 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn)
-     // this authentication attempt (bug 84794).
-     // TODO: save cookies from auth response and send them here (bug 572151).
-     AddCookiesToRequest();
--    
-+   
-+    // check to see if authorization headers should be included
-+    mAuthProvider->AddAuthorizationHeaders();
-+ 
-     // notify "http-on-modify-request" observers
-     gHttpHandler->OnModifyRequest(this);
- 
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0019-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch b/src/current-patches/firefox/0019-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch
deleted file mode 100644
index 7f3869c..0000000
--- a/src/current-patches/firefox/0019-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch
+++ /dev/null
@@ -1,532 +0,0 @@
-From 49cccdba3e6fc10e0e376d423b3ba1b6135f62e1 Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at torproject.org>
-Date: Thu, 7 Jun 2012 16:25:48 -0700
-Subject: [PATCH 19/24] Adapt Steven Michaud's Mac crashfix patch
-
-Source is: https://bugzilla.mozilla.org/show_bug.cgi?id=715885#c35
-
-Some minor tweaks were needed to get it to apply and to compile on
-MacOS.
----
- widget/public/Makefile.in                  |    2 +
- widget/public/nsIDragService.idl           |    1 -
- widget/public/nsPIDragService.idl          |   48 ++++++++++++++++++++++++++++
- widget/public/nsPIDragServiceWindows.idl   |   46 ++++++++++++++++++++++++++
- widget/src/cocoa/nsChildView.mm            |   35 +++++++++++++-------
- widget/src/gtk2/nsDragService.cpp          |    2 +-
- widget/src/gtk2/nsWindow.cpp               |    2 +-
- widget/src/qt/nsDragService.h              |    2 +
- widget/src/windows/Makefile.in             |    1 -
- widget/src/windows/nsDragService.cpp       |   13 +++++---
- widget/src/windows/nsDragService.h         |   12 +++---
- widget/src/windows/nsNativeDragSource.cpp  |    7 ++--
- widget/src/windows/nsNativeDragTarget.cpp  |   28 ++++++++++------
- widget/src/xpwidgets/nsBaseDragService.cpp |   16 +++++++++-
- widget/src/xpwidgets/nsBaseDragService.h   |    9 ++---
- 15 files changed, 176 insertions(+), 48 deletions(-)
- create mode 100644 widget/public/nsPIDragService.idl
- create mode 100644 widget/public/nsPIDragServiceWindows.idl
-
-diff --git a/widget/public/Makefile.in b/widget/public/Makefile.in
-index a70e65a..8a9b73d 100644
---- a/widget/public/Makefile.in
-+++ b/widget/public/Makefile.in
-@@ -110,6 +110,8 @@ XPIDLSRCS	= \
- 		nsIClipboardDragDropHooks.idl \
- 		nsIClipboardDragDropHookList.idl \
- 		nsIDragSession.idl \
-+		nsPIDragService.idl \
-+		nsPIDragServiceWindows.idl \
- 		nsIDragService.idl \
- 		nsIFormatConverter.idl \
- 		nsIClipboard.idl \
-diff --git a/widget/public/nsIDragService.idl b/widget/public/nsIDragService.idl
-index 6863a88..c4a1e26 100644
---- a/widget/public/nsIDragService.idl
-+++ b/widget/public/nsIDragService.idl
-@@ -146,7 +146,6 @@ interface nsIDragService : nsISupports
-   void suppress();
-   void unsuppress();
- 
--  [noscript] void dragMoved(in long aX, in long aY);
- };
- 
- 
-diff --git a/widget/public/nsPIDragService.idl b/widget/public/nsPIDragService.idl
-new file mode 100644
-index 0000000..93a144d
---- /dev/null
-+++ b/widget/public/nsPIDragService.idl
-@@ -0,0 +1,48 @@
-+/* ***** BEGIN LICENSE BLOCK *****
-+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-+ *
-+ * The contents of this file are subject to the Mozilla Public License Version
-+ * 1.1 (the "License"); you may not use this file except in compliance with
-+ * the License. You may obtain a copy of the License at
-+ * http://www.mozilla.org/MPL/
-+ *
-+ * Software distributed under the License is distributed on an "AS IS" basis,
-+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-+ * for the specific language governing rights and limitations under the
-+ * License.
-+ *
-+ * The Original Code is mozilla.org code.
-+ *
-+ * The Initial Developer of the Original Code is
-+ * The Mozilla Foundation.
-+ * Portions created by the Initial Developer are Copyright (C) 2012
-+ * the Initial Developer. All Rights Reserved.
-+ *
-+ * Contributor(s):
-+ *   Steven Michaud <smichaud at pobox.com>
-+ *
-+ * Alternatively, the contents of this file may be used under the terms of
-+ * either the GNU General Public License Version 2 or later (the "GPL"), or
-+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-+ * in which case the provisions of the GPL or the LGPL are applicable instead
-+ * of those above. If you wish to allow use of your version of this file only
-+ * under the terms of either the GPL or the LGPL, and not to allow others to
-+ * use your version of this file under the terms of the MPL, indicate your
-+ * decision by deleting the provisions above and replace them with the notice
-+ * and other provisions required by the GPL or the LGPL. If you do not delete
-+ * the provisions above, a recipient may use your version of this file under
-+ * the terms of any one of the MPL, the GPL or the LGPL.
-+ *
-+ * ***** END LICENSE BLOCK ***** */
-+
-+#include "nsISupports.idl"
-+
-+[scriptable, uuid(FAD8C90B-8E1D-446A-9B6C-241486A85CBD)]
-+interface nsPIDragService : nsISupports
-+{
-+  void dragMoved(in long aX, in long aY);
-+
-+  PRUint16 getInputSource();
-+
-+  void setDragEndPoint(in long aX, in long aY);
-+};
-diff --git a/widget/public/nsPIDragServiceWindows.idl b/widget/public/nsPIDragServiceWindows.idl
-new file mode 100644
-index 0000000..c8a46dd
---- /dev/null
-+++ b/widget/public/nsPIDragServiceWindows.idl
-@@ -0,0 +1,46 @@
-+/* ***** BEGIN LICENSE BLOCK *****
-+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-+ *
-+ * The contents of this file are subject to the Mozilla Public License Version
-+ * 1.1 (the "License"); you may not use this file except in compliance with
-+ * the License. You may obtain a copy of the License at
-+ * http://www.mozilla.org/MPL/
-+ *
-+ * Software distributed under the License is distributed on an "AS IS" basis,
-+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-+ * for the specific language governing rights and limitations under the
-+ * License.
-+ *
-+ * The Original Code is mozilla.org code.
-+ *
-+ * The Initial Developer of the Original Code is
-+ * The Mozilla Foundation.
-+ * Portions created by the Initial Developer are Copyright (C) 2012
-+ * the Initial Developer. All Rights Reserved.
-+ *
-+ * Contributor(s):
-+ *   Steven Michaud <smichaud at pobox.com>
-+ *
-+ * Alternatively, the contents of this file may be used under the terms of
-+ * either the GNU General Public License Version 2 or later (the "GPL"), or
-+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-+ * in which case the provisions of the GPL or the LGPL are applicable instead
-+ * of those above. If you wish to allow use of your version of this file only
-+ * under the terms of either the GPL or the LGPL, and not to allow others to
-+ * use your version of this file under the terms of the MPL, indicate your
-+ * decision by deleting the provisions above and replace them with the notice
-+ * and other provisions required by the GPL or the LGPL. If you do not delete
-+ * the provisions above, a recipient may use your version of this file under
-+ * the terms of any one of the MPL, the GPL or the LGPL.
-+ *
-+ * ***** END LICENSE BLOCK ***** */
-+
-+#include "nsISupports.idl"
-+
-+[scriptable, uuid(6FC2117D-5EB4-441A-9C12-62A783BEBC0C)]
-+interface nsPIDragServiceWindows : nsISupports
-+{
-+  void setIDataObject(in nsISupports aDataObj);
-+
-+  void setDroppedLocal();
-+};
-diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm
-index 64336e3..b2ab6bc 100644
---- a/widget/src/cocoa/nsChildView.mm
-+++ b/widget/src/cocoa/nsChildView.mm
-@@ -4513,11 +4513,12 @@ NSEvent* gLastDragMouseDownEvent = nil;
-   if (!dragService) {
-     dragService = do_GetService(kDragServiceContractID);
-   }
-+  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(dragService);
- 
-   if (dragService) {
-     NSPoint pnt = [NSEvent mouseLocation];
-     FlipCocoaScreenCoordinate(pnt);
--    dragService->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
-+    dragServicePriv->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
-   }
- }
- 
-@@ -4538,11 +4539,13 @@ NSEvent* gLastDragMouseDownEvent = nil;
-   }
- 
-   if (mDragService) {
--    // set the dragend point from the current mouse location
--    nsDragService* dragService = static_cast<nsDragService *>(mDragService);
--    NSPoint pnt = [NSEvent mouseLocation];
--    FlipCocoaScreenCoordinate(pnt);
--    dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y)));
-+    nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
-+    if (dragServicePriv) {
-+      // set the dragend point from the current mouse location
-+      NSPoint pnt = [NSEvent mouseLocation];
-+      FlipCocoaScreenCoordinate(pnt);
-+      dragServicePriv->SetDragEndPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
-+    }
- 
-     // XXX: dropEffect should be updated per |operation|. 
-     // As things stand though, |operation| isn't well handled within "our"
-@@ -4553,13 +4556,19 @@ NSEvent* gLastDragMouseDownEvent = nil;
-     // value for NSDragOperationGeneric that is passed by other applications.
-     // All that said, NSDragOperationNone is still reliable.
-     if (operation == NSDragOperationNone) {
--      nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
--      dragService->GetDataTransfer(getter_AddRefs(dataTransfer));
--      nsCOMPtr<nsIDOMNSDataTransfer> dataTransferNS =
--        do_QueryInterface(dataTransfer);
--
--      if (dataTransferNS)
--        dataTransferNS->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
-+      nsCOMPtr<nsIDragSession> dragSession;
-+      mDragService->GetCurrentSession(getter_AddRefs(dragSession));
-+      if (dragSession) {
-+        nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
-+        dragSession->GetDataTransfer(getter_AddRefs(dataTransfer));
-+        if (dataTransfer) {
-+          nsCOMPtr<nsIDOMNSDataTransfer> dataTransferNS =
-+                do_QueryInterface(dataTransfer);
-+          if (dataTransferNS) {
-+            dataTransferNS->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
-+          }
-+        }
-+      }
-     }
- 
-     mDragService->EndDragSession(true);
-diff --git a/widget/src/gtk2/nsDragService.cpp b/widget/src/gtk2/nsDragService.cpp
-index ca5a42c..876fd55 100644
---- a/widget/src/gtk2/nsDragService.cpp
-+++ b/widget/src/gtk2/nsDragService.cpp
-@@ -1334,7 +1334,7 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext,
-     GdkDisplay* display = gdk_display_get_default();
-     if (display) {
-       gdk_display_get_pointer(display, NULL, &x, &y, NULL);
--      SetDragEndPoint(nsIntPoint(x, y));
-+      SetDragEndPoint(x, y);
-     }
- 
-     // Either the drag was aborted or the drop occurred outside the app.
-diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp
-index 2fd6f64..a2e27e1 100644
---- a/widget/src/gtk2/nsWindow.cpp
-+++ b/widget/src/gtk2/nsWindow.cpp
-@@ -3738,7 +3738,7 @@ nsWindow::OnDragDropEvent(GtkWidget *aWidget,
-     if (display) {
-       // get the current cursor position
-       gdk_display_get_pointer(display, NULL, &x, &y, NULL);
--      ((nsDragService *)dragService.get())->SetDragEndPoint(nsIntPoint(x, y));
-+      ((nsDragService *)dragService.get())->SetDragEndPoint(x, y);
-     }
-     dragService->EndDragSession(true);
- 
-diff --git a/widget/src/qt/nsDragService.h b/widget/src/qt/nsDragService.h
-index 5a3e5bb..50dcfac 100644
---- a/widget/src/qt/nsDragService.h
-+++ b/widget/src/qt/nsDragService.h
-@@ -50,6 +50,8 @@ public:
-     NS_DECL_ISUPPORTS
-     NS_DECL_NSIDRAGSERVICE
- 
-+    NS_IMETHOD DragMoved(PRInt32 aX, PRInt32 aY);
-+
-     nsDragService();
- 
- private:
-diff --git a/widget/src/windows/Makefile.in b/widget/src/windows/Makefile.in
-index 53277ea..d7ff7ce 100644
---- a/widget/src/windows/Makefile.in
-+++ b/widget/src/windows/Makefile.in
-@@ -115,7 +115,6 @@ ifdef MOZ_ENABLE_D3D10_LAYER
- DEFINES		+= -DMOZ_ENABLE_D3D10_LAYER
- endif
- 
--
- EXPORTS		= nsdefs.h WindowHook.h
- EXPORTS_NAMESPACES = mozilla/widget
- EXPORTS_mozilla/widget = AudioSession.h
-diff --git a/widget/src/windows/nsDragService.cpp b/widget/src/windows/nsDragService.cpp
-index 2dcede3..3d8af21 100644
---- a/widget/src/windows/nsDragService.cpp
-+++ b/widget/src/windows/nsDragService.cpp
-@@ -97,6 +97,8 @@ nsDragService::~nsDragService()
-   NS_IF_RELEASE(mDataObject);
- }
- 
-+NS_IMPL_ISUPPORTS_INHERITED1(nsDragService, nsBaseDragService, nsPIDragServiceWindows)
-+
- bool
- nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
-                                nsIScriptableRegion *aRegion,
-@@ -350,7 +352,7 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
-   POINT cpos;
-   cpos.x = GET_X_LPARAM(pos);
-   cpos.y = GET_Y_LPARAM(pos);
--  SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
-+  SetDragEndPoint(cpos.x, cpos.y);
-   EndDragSession(true);
- 
-   mDoingDrag = false;
-@@ -468,25 +470,26 @@ nsDragService::GetData(nsITransferable * aTransferable, PRUint32 anItem)
- 
- //---------------------------------------------------------
- NS_IMETHODIMP
--nsDragService::SetIDataObject(IDataObject * aDataObj)
-+nsDragService::SetIDataObject(nsISupports * aDataObj)
- {
-+  IDataObject *dataObj = (IDataObject*) aDataObj;
-   // When the native drag starts the DragService gets
-   // the IDataObject that is being dragged
-   NS_IF_RELEASE(mDataObject);
--  mDataObject = aDataObj;
-+  mDataObject = dataObj;
-   NS_IF_ADDREF(mDataObject);
- 
-   return NS_OK;
- }
- 
- //---------------------------------------------------------
--void
-+NS_IMETHODIMP
- nsDragService::SetDroppedLocal()
- {
-   // Sent from the native drag handler, letting us know
-   // a drop occurred within the application vs. outside of it.
-   mSentLocalDropEvent = true;
--  return;
-+  return NS_OK;
- }
- 
- //-------------------------------------------------------------------------
-diff --git a/widget/src/windows/nsDragService.h b/widget/src/windows/nsDragService.h
-index 067bcf2..2699e47 100644
---- a/widget/src/windows/nsDragService.h
-+++ b/widget/src/windows/nsDragService.h
-@@ -39,6 +39,7 @@
- #define nsDragService_h__
- 
- #include "nsBaseDragService.h"
-+#include "nsPIDragServiceWindows.h"
- #include <windows.h>
- #include <shlobj.h>
- 
-@@ -52,12 +53,15 @@ class  nsString;
-  * Native Win32 DragService wrapper
-  */
- 
--class nsDragService : public nsBaseDragService
-+class nsDragService : public nsBaseDragService, public nsPIDragServiceWindows
- {
- public:
-   nsDragService();
-   virtual ~nsDragService();
--  
-+
-+  NS_DECL_ISUPPORTS_INHERITED
-+  NS_DECL_NSPIDRAGSERVICEWINDOWS
-+
-   // nsIDragService
-   NS_IMETHOD InvokeDragSession(nsIDOMNode *aDOMNode,
-                                nsISupportsArray *anArrayTransferables,
-@@ -71,13 +75,9 @@ public:
-   NS_IMETHOD EndDragSession(bool aDoneDrag);
- 
-   // native impl.
--  NS_IMETHOD SetIDataObject(IDataObject * aDataObj);
-   NS_IMETHOD StartInvokingDragSession(IDataObject * aDataObj,
-                                       PRUint32 aActionType);
- 
--  // A drop occurred within the application vs. outside of it.
--  void SetDroppedLocal();
--
- protected:
-   nsDataObjCollection* GetDataObjCollection(IDataObject * aDataObj);
- 
-diff --git a/widget/src/windows/nsNativeDragSource.cpp b/widget/src/windows/nsNativeDragSource.cpp
-index e51101e..0fe6ffe 100644
---- a/widget/src/windows/nsNativeDragSource.cpp
-+++ b/widget/src/windows/nsNativeDragSource.cpp
-@@ -42,7 +42,7 @@
- #include "nsIServiceManager.h"
- #include "nsToolkit.h"
- #include "nsWidgetsCID.h"
--#include "nsIDragService.h"
-+#include "nsDragService.h"
- 
- static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
- 
-@@ -101,9 +101,10 @@ STDMETHODIMP
- nsNativeDragSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState)
- {
-   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
--  if (dragService) {
-+  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(dragService);
-+  if (dragServicePriv) {
-     DWORD pos = ::GetMessagePos();
--    dragService->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
-+    dragServicePriv->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
-   }
- 
-   if (fEsc) {
-diff --git a/widget/src/windows/nsNativeDragTarget.cpp b/widget/src/windows/nsNativeDragTarget.cpp
-index cf6196b..82ad3c6 100644
---- a/widget/src/windows/nsNativeDragTarget.cpp
-+++ b/widget/src/windows/nsNativeDragTarget.cpp
-@@ -209,7 +209,11 @@ nsNativeDragTarget::DispatchDragDropEvent(PRUint32 aEventType, POINTL aPT)
-   event.isControl = IsKeyDown(NS_VK_CONTROL);
-   event.isMeta    = false;
-   event.isAlt     = IsKeyDown(NS_VK_ALT);
--  event.inputSource = static_cast<nsBaseDragService*>(mDragService)->GetInputSource();
-+  event.inputSource = 0;
-+  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
-+  if (dragServicePriv) {
-+    dragServicePriv->GetInputSource(&event.inputSource);
-+  }
- 
-   mWindow->DispatchEvent(&event, status);
- }
-@@ -296,9 +300,8 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
-   // This cast is ok because in the constructor we created a
-   // the actual implementation we wanted, so we know this is
-   // a nsDragService. It should be a private interface, though.
--  nsDragService * winDragService =
--    static_cast<nsDragService *>(mDragService);
--  winDragService->SetIDataObject(pIDataSource);
-+  nsCOMPtr<nsPIDragServiceWindows> winDragService = do_QueryInterface(mDragService);
-+  winDragService->SetIDataObject((nsISupports*)pIDataSource);
- 
-   // Now process the native drag state and then dispatch the event
-   ProcessDrag(NS_DRAGDROP_ENTER, grfKeyState, ptl, pdwEffect);
-@@ -436,8 +439,8 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
-   // This cast is ok because in the constructor we created a
-   // the actual implementation we wanted, so we know this is
-   // a nsDragService (but it should still be a private interface)
--  nsDragService* winDragService = static_cast<nsDragService*>(mDragService);
--  winDragService->SetIDataObject(pData);
-+  nsCOMPtr<nsPIDragServiceWindows> winDragService = do_QueryInterface(mDragService);
-+  winDragService->SetIDataObject((nsISupports*)pData);
- 
-   // NOTE: ProcessDrag spins the event loop which may destroy arbitrary objects.
-   // We use strong refs to prevent it from destroying these:
-@@ -461,11 +464,14 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
-   // tell the drag service we're done with the session
-   // Use GetMessagePos to get the position of the mouse at the last message
-   // seen by the event loop. (Bug 489729)
--  DWORD pos = ::GetMessagePos();
--  POINT cpos;
--  cpos.x = GET_X_LPARAM(pos);
--  cpos.y = GET_Y_LPARAM(pos);
--  winDragService->SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
-+  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
-+  if (dragServicePriv) {
-+    DWORD pos = ::GetMessagePos();
-+    POINT cpos;
-+    cpos.x = GET_X_LPARAM(pos);
-+    cpos.y = GET_Y_LPARAM(pos);
-+    dragServicePriv->SetDragEndPoint(cpos.x, cpos.y);
-+  }
-   serv->EndDragSession(true);
- 
-   // release the ref that was taken in DragEnter
-diff --git a/widget/src/xpwidgets/nsBaseDragService.cpp b/widget/src/xpwidgets/nsBaseDragService.cpp
-index 52efb7e..1c35673 100644
---- a/widget/src/xpwidgets/nsBaseDragService.cpp
-+++ b/widget/src/xpwidgets/nsBaseDragService.cpp
-@@ -89,7 +89,7 @@ nsBaseDragService::~nsBaseDragService()
- {
- }
- 
--NS_IMPL_ISUPPORTS2(nsBaseDragService, nsIDragService, nsIDragSession)
-+NS_IMPL_ISUPPORTS3(nsBaseDragService, nsIDragService, nsPIDragService, nsIDragSession)
- 
- //---------------------------------------------------------
- NS_IMETHODIMP
-@@ -443,6 +443,20 @@ nsBaseDragService::DragMoved(PRInt32 aX, PRInt32 aY)
-   return NS_OK;
- }
- 
-+NS_IMETHODIMP
-+nsBaseDragService::SetDragEndPoint(PRInt32 aX, PRInt32 aY)
-+{
-+  mEndDragPoint = nsIntPoint(aX, aY);
-+  return NS_OK;
-+}
-+
-+NS_IMETHODIMP
-+nsBaseDragService::GetInputSource(PRUint16* aInputSource)
-+{
-+  *aInputSource = mInputSource;
-+  return NS_OK;
-+}
-+
- static nsIPresShell*
- GetPresShellForContent(nsIDOMNode* aDOMNode)
- {
-diff --git a/widget/src/xpwidgets/nsBaseDragService.h b/widget/src/xpwidgets/nsBaseDragService.h
-index 290c0cb..2ceac2b 100644
---- a/widget/src/xpwidgets/nsBaseDragService.h
-+++ b/widget/src/xpwidgets/nsBaseDragService.h
-@@ -39,6 +39,7 @@
- #define nsBaseDragService_h__
- 
- #include "nsIDragService.h"
-+#include "nsPIDragService.h"
- #include "nsIDragSession.h"
- #include "nsITransferable.h"
- #include "nsISupportsArray.h"
-@@ -64,6 +65,7 @@ class nsICanvasElementExternal;
-  */
- 
- class nsBaseDragService : public nsIDragService,
-+                          public nsPIDragService,
-                           public nsIDragSession
- {
- 
-@@ -74,14 +76,11 @@ public:
-   //nsISupports
-   NS_DECL_ISUPPORTS
- 
--  //nsIDragSession and nsIDragService
-+  //nsIDragSession, nsIDragService and nsPIDragService
-   NS_DECL_NSIDRAGSERVICE
-+  NS_DECL_NSPIDRAGSERVICE
-   NS_DECL_NSIDRAGSESSION
- 
--  void SetDragEndPoint(nsIntPoint aEndDragPoint) { mEndDragPoint = aEndDragPoint; }
--
--  PRUint16 GetInputSource() { return mInputSource; }
--
- protected:
- 
-   /**
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0019-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch b/src/current-patches/firefox/0019-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
new file mode 100644
index 0000000..ab855cf
--- /dev/null
+++ b/src/current-patches/firefox/0019-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
@@ -0,0 +1,154 @@
+From 4ea73b19b21764c10019e9af1cc68664ed7f7394 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade at pearlcrescent.com>
+Date: Wed, 28 Nov 2012 17:08:29 -0500
+Subject: [PATCH 19/26] Add mozIThirdPartyUtil.getFirstPartyURI API
+
+API allows you to get the url bar URI for a channel or nsIDocument.
+---
+ content/base/src/ThirdPartyUtil.cpp        |   58 ++++++++++++++++++++++++++++
+ content/base/src/ThirdPartyUtil.h          |    2 +
+ netwerk/base/public/mozIThirdPartyUtil.idl |   21 ++++++++++
+ 3 files changed, 81 insertions(+), 0 deletions(-)
+
+diff --git a/content/base/src/ThirdPartyUtil.cpp b/content/base/src/ThirdPartyUtil.cpp
+index 97a000e..ae4fa70 100644
+--- a/content/base/src/ThirdPartyUtil.cpp
++++ b/content/base/src/ThirdPartyUtil.cpp
+@@ -7,6 +7,9 @@
+ #include "nsIServiceManager.h"
+ #include "nsIHttpChannelInternal.h"
+ #include "nsIDOMWindow.h"
++#include "nsICookiePermission.h"
++#include "nsIDOMDocument.h"
++#include "nsIDocument.h"
+ #include "nsILoadContext.h"
+ #include "nsIPrincipal.h"
+ #include "nsIScriptObjectPrincipal.h"
+@@ -21,6 +24,7 @@ ThirdPartyUtil::Init()
+ 
+   nsresult rv;
+   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
++  mCookiePermissions = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
+   return rv;
+ }
+ 
+@@ -282,3 +286,57 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
+ 
+   return NS_OK;
+ }
++
++NS_IMETHODIMP
++ThirdPartyUtil::GetFirstPartyURI(nsIChannel *aChannel,
++                                 nsIDocument *aDoc,
++                                 nsIURI **aOutput)
++{
++  nsresult rv = NS_ERROR_NULL_POINTER;
++
++  if (!aChannel && aDoc) {
++    aChannel = aDoc->GetChannel();
++  }
++
++  // If aChannel is specified or available, use the official route
++  // for sure
++  if (aChannel) {
++    rv = mCookiePermissions->GetOriginatingURI(aChannel, aOutput);
++  }
++
++  // If the channel was missing, closed or broken, try the
++  // window hierarchy directly.
++  //
++  // This might fail to work for first-party loads themselves, but
++  // we don't need this codepath for that case.
++  if (NS_FAILED(rv) && aDoc) {
++    nsCOMPtr<nsIDOMWindow> top;
++    nsCOMPtr<nsIDOMDocument> topDDoc;
++
++    if (aDoc->GetWindow()) {
++      aDoc->GetWindow()->GetTop(getter_AddRefs(top));
++      top->GetDocument(getter_AddRefs(topDDoc));
++
++      nsCOMPtr<nsIDocument> topDoc(do_QueryInterface(topDDoc));
++      *aOutput = topDoc->GetOriginalURI();
++    } else {
++      // XXX: Chrome callers (such as NoScript) can end up here
++      // through getImageData/canvas usage with no document state
++      // (no Window and a document URI of about:blank). Propogate
++      // rv fail (by doing nothing), and hope caller recovers.
++    }
++
++    if (*aOutput)
++      rv = NS_OK;
++  }
++
++  // TODO: We could provide a route through the loadgroup + notification
++  // callbacks too, but either channel or document was always available
++  // in the cases where this function was originally needed (the image cache).
++  // The notification callbacks also appear to suffers from the same limitation
++  // as the document path. See nsICookiePermissions.GetOriginatingURI() for
++  // details.
++
++  return rv;
++}
++
+diff --git a/content/base/src/ThirdPartyUtil.h b/content/base/src/ThirdPartyUtil.h
+index 3f50ac3..fe7b214 100644
+--- a/content/base/src/ThirdPartyUtil.h
++++ b/content/base/src/ThirdPartyUtil.h
+@@ -9,6 +9,7 @@
+ #include "nsString.h"
+ #include "mozIThirdPartyUtil.h"
+ #include "nsIEffectiveTLDService.h"
++#include "nsICookiePermission.h"
+ #include "mozilla/Attributes.h"
+ 
+ class nsIURI;
+@@ -29,6 +30,7 @@ private:
+   static already_AddRefed<nsIURI> GetURIFromWindow(nsIDOMWindow* aWin);
+ 
+   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
++  nsCOMPtr<nsICookiePermission> mCookiePermissions;
+ };
+ 
+ #endif
+diff --git a/netwerk/base/public/mozIThirdPartyUtil.idl b/netwerk/base/public/mozIThirdPartyUtil.idl
+index 578d8db..963385c 100644
+--- a/netwerk/base/public/mozIThirdPartyUtil.idl
++++ b/netwerk/base/public/mozIThirdPartyUtil.idl
+@@ -7,6 +7,7 @@
+ interface nsIURI;
+ interface nsIDOMWindow;
+ interface nsIChannel;
++interface nsIDocument;
+ 
+ /**
+  * Utility functions for determining whether a given URI, channel, or window
+@@ -140,6 +141,26 @@ interface mozIThirdPartyUtil : nsISupports
+    * @return the base domain.
+    */
+   AUTF8String getBaseDomain(in nsIURI aHostURI);
++
++
++  /**
++   * getFirstPartyURI
++   *
++   * Obtain the top-level url bar URI for either a channel or a document.
++   * Either parameter may be null (but not both).
++   *
++   * @param aChannel
++   *        An arbitrary channel for some content element of a first party
++   *        load. Can be null.
++   *
++   * @param aDoc
++   *        An arbitrary third party document. Can be null.
++   *
++   * @return the first party url bar URI for the load.
++   */
++  nsIURI getFirstPartyURI(in nsIChannel aChannel,
++                          in nsIDocument aDoc);
++
+ };
+ 
+ %{ C++
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0020-Add-canvas-image-extraction-prompt.patch b/src/current-patches/firefox/0020-Add-canvas-image-extraction-prompt.patch
new file mode 100644
index 0000000..802dc3f
--- /dev/null
+++ b/src/current-patches/firefox/0020-Add-canvas-image-extraction-prompt.patch
@@ -0,0 +1,548 @@
+From 924f0fb25804b75289f18fe5b5cfe02667aad58f Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade at pearlcrescent.com>
+Date: Tue, 27 Nov 2012 13:13:40 -0500
+Subject: [PATCH 20/26] Add canvas image extraction prompt.
+
+---
+ browser/base/content/browser.js                    |  102 ++++++++++++++++++++
+ browser/base/content/browser.xul                   |    1 +
+ .../en-US/chrome/browser/browser.properties        |    7 ++
+ browser/themes/gnomestripe/browser.css             |    2 +
+ browser/themes/pinstripe/browser.css               |    2 +
+ browser/themes/winstripe/browser.css               |    2 +
+ content/canvas/src/CanvasUtils.cpp                 |   65 +++++++++++++
+ content/canvas/src/CanvasUtils.h                   |    2 +
+ content/canvas/src/nsCanvasRenderingContext2D.cpp  |   16 +++
+ .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |   16 +++
+ content/html/content/public/nsHTMLCanvasElement.h  |    3 +
+ content/html/content/src/Makefile.in               |    1 +
+ content/html/content/src/nsHTMLCanvasElement.cpp   |   40 ++++++--
+ 13 files changed, 249 insertions(+), 10 deletions(-)
+
+diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
+index 1fc137c..e95cebc 100644
+--- a/browser/base/content/browser.js
++++ b/browser/base/content/browser.js
+@@ -1282,6 +1282,7 @@ var gBrowserInit = {
+     BrowserOffline.init();
+     OfflineApps.init();
+     IndexedDBPromptHelper.init();
++    CanvasPermissionPromptHelper.init();
+     gFormSubmitObserver.init();
+     SocialUI.init();
+     AddonManager.addAddonListener(AddonsMgrListener);
+@@ -1639,6 +1640,7 @@ var gBrowserInit = {
+       BrowserOffline.uninit();
+       OfflineApps.uninit();
+       IndexedDBPromptHelper.uninit();
++      CanvasPermissionPromptHelper.uninit();
+       AddonManager.removeAddonListener(AddonsMgrListener);
+       SocialUI.uninit();
+     }
+@@ -6129,6 +6131,106 @@ var IndexedDBPromptHelper = {
+   }
+ };
+ 
++var CanvasPermissionPromptHelper = {
++  _permissionsPrompt: "canvas-permissions-prompt",
++  _notificationIcon: "canvas-notification-icon",
++
++  init:
++  function CanvasPermissionPromptHelper_init() {
++    Services.obs.addObserver(this, this._permissionsPrompt, false);
++  },
++
++  uninit:
++  function CanvasPermissionPromptHelper_uninit() {
++    Services.obs.removeObserver(this, this._permissionsPrompt, false);
++  },
++
++  // aSubject is an nsIDOMWindow.
++  // aData is an URL string.
++  observe:
++  function CanvasPermissionPromptHelper_observe(aSubject, aTopic, aData) {
++    if ((aTopic != this._permissionsPrompt) || !aData)
++      throw new Error("Unexpected topic or missing URL");
++
++    var uri = makeURI(aData);
++    var contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
++    var contentDocument = contentWindow.document;
++    var browserWindow =
++      OfflineApps._getBrowserWindowForContentWindow(contentWindow);
++
++    if (browserWindow != window) {
++      // Must belong to some other window.
++      return;
++    }
++
++    // If canvas prompt is already displayed, just return.  This is OK (and
++    // more efficient) since this permission is associated with the top
++    // browser's URL.
++    if (PopupNotifications.getNotification(aTopic, browser))
++      return;
++
++    var bundleSvc = Cc["@mozilla.org/intl/stringbundle;1"].
++                        getService(Ci.nsIStringBundleService);
++    var torBtnBundle;
++    try {
++      torBtnBundle = bundleSvc.createBundle(
++                             "chrome://torbutton/locale/torbutton.properties");
++    } catch (e) {}
++
++    var message = getLocalizedString("canvas.siteprompt", [ uri.asciiHost ]);
++
++    var mainAction = {
++      label: getLocalizedString("canvas.allow"),
++      accessKey: getLocalizedString("canvas.allowAccessKey"),
++      callback: function() {
++          setCanvasPermission(uri, Ci.nsIPermissionManager.ALLOW_ACTION);
++      }
++    };
++
++    var secondaryActions = [
++      {
++        label: getLocalizedString("canvas.never"),
++        accessKey: getLocalizedString("canvas.neverAccessKey"),
++        callback: function() {
++          setCanvasPermission(uri, Ci.nsIPermissionManager.DENY_ACTION);
++        }
++      }
++    ];
++
++    // Since we have a process in place to perform localization for the
++    // Torbutton extension, get our strings from the extension if possible.
++    function getLocalizedString(aID, aParams) {
++      var s;
++      if (torBtnBundle) try {
++        if (aParams)
++          s = torBtnBundle.formatStringFromName(aID, aParams, aParams.length);
++        else
++          s = torBtnBundle.GetStringFromName(aID);
++      } catch (e) {}
++
++      if (!s) {
++        if (aParams)
++          s = gNavigatorBundle.getFormattedString(aID, aParams);
++        else
++          s = gNavigatorBundle.getString(aID);
++      }
++
++      return s;
++    }
++
++    function setCanvasPermission(aURI, aPerm) {
++      Services.perms.add(aURI, "canvas/extractData", aPerm,
++                         Ci.nsIPermissionManager.EXPIRE_NEVER);
++    }
++
++    var browser = OfflineApps._getBrowserForContentWindow(browserWindow,
++                                                          contentWindow);
++    notification = PopupNotifications.show(browser, aTopic, message,
++                                           this._notificationIcon, mainAction,
++                                           secondaryActions, null);
++  }
++};
++
+ function WindowIsClosing()
+ {
+   if (TabView.isVisible()) {
+diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
+index 5bf156e..8699a62 100644
+--- a/browser/base/content/browser.xul
++++ b/browser/base/content/browser.xul
+@@ -573,6 +573,7 @@
+             <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
++            <image id="canvas-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
+diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties
+index 1a9f457..4e61cb9 100644
+--- a/browser/locales/en-US/chrome/browser/browser.properties
++++ b/browser/locales/en-US/chrome/browser/browser.properties
+@@ -218,6 +218,13 @@ offlineApps.usage=This website (%S) is now storing more than %SMB of data on you
+ offlineApps.manageUsage=Show settings
+ offlineApps.manageUsageAccessKey=S
+ 
++# Canvas permission prompt
++canvas.siteprompt=This website (%S) attempted to access image data on a canvas. Since canvas image data can be used to discover information about your computer, blank image data was returned this time.
++canvas.allow=Allow in the Future
++canvas.allowAccessKey=A
++canvas.never=Never for This Site
++canvas.neverAccessKey=e
++
+ # LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
+ # %2$S a number of megabytes.
+ indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
+diff --git a/browser/themes/gnomestripe/browser.css b/browser/themes/gnomestripe/browser.css
+index aff8ae1..f69f553 100644
+--- a/browser/themes/gnomestripe/browser.css
++++ b/browser/themes/gnomestripe/browser.css
+@@ -1185,6 +1185,7 @@ toolbar[iconsize="small"] #feed-button {
+   list-style-image: url("moz-icon://stock/gtk-cancel?size=menu");
+ }
+ 
++.popup-notification-icon[popupid="canvas-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
+   list-style-image: url(chrome://global/skin/icons/question-64.png);
+@@ -1250,6 +1251,7 @@ toolbar[iconsize="small"] #feed-button {
+   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
+ }
+ 
++#canvas-notification-icon,
+ #indexedDB-notification-icon {
+   list-style-image: url(chrome://global/skin/icons/question-16.png);
+ }
+diff --git a/browser/themes/pinstripe/browser.css b/browser/themes/pinstripe/browser.css
+index a44c6b9..ff581ab 100644
+--- a/browser/themes/pinstripe/browser.css
++++ b/browser/themes/pinstripe/browser.css
+@@ -2403,10 +2403,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
+   -moz-image-region: rect(0px, 48px, 16px, 32px);
+ }
+ 
++#canvas-notification-icon,
+ #indexedDB-notification-icon {
+   list-style-image: url(chrome://global/skin/icons/question-16.png);
+ }
+ 
++.popup-notification-icon[popupid="canvas-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
+   list-style-image: url(chrome://global/skin/icons/question-64.png);
+diff --git a/browser/themes/winstripe/browser.css b/browser/themes/winstripe/browser.css
+index 470c344..770245b 100644
+--- a/browser/themes/winstripe/browser.css
++++ b/browser/themes/winstripe/browser.css
+@@ -2319,6 +2319,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
+   -moz-image-region: rect(32px, 32px, 48px, 16px);
+ }
+ 
++.popup-notification-icon[popupid="canvas-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
+   list-style-image: url(chrome://global/skin/icons/question-64.png);
+@@ -2382,6 +2383,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
+   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
+ }
+ 
++#canvas-notification-icon,
+ #indexedDB-notification-icon {
+   list-style-image: url(chrome://global/skin/icons/question-16.png);
+ }
+diff --git a/content/canvas/src/CanvasUtils.cpp b/content/canvas/src/CanvasUtils.cpp
+index 4173891..2ec463f 100644
+--- a/content/canvas/src/CanvasUtils.cpp
++++ b/content/canvas/src/CanvasUtils.cpp
+@@ -24,9 +24,74 @@
+ #include "CanvasUtils.h"
+ #include "mozilla/gfx/Matrix.h"
+ 
++#include "nsIScriptObjectPrincipal.h"
++#include "nsIPermissionManager.h"
++#include "nsIObserverService.h"
++#include "mozilla/Services.h"
++#include "mozIThirdPartyUtil.h"
++#include "nsContentUtils.h"
++#include "nsUnicharUtils.h"
++
++#define TOPIC_CANVAS_PERMISSIONS_PROMPT "canvas-permissions-prompt"
++#define PERMISSION_CANVAS_EXTRACT_DATA "canvas/extractData"
++
+ namespace mozilla {
+ namespace CanvasUtils {
+ 
++// Check site-specific permission and display prompt if appropriate.
++bool
++IsImageExtractionAllowed(nsIDocument *aDocument)
++{
++  if (!aDocument)
++    return false;
++
++  nsPIDOMWindow *win = aDocument->GetWindow();
++  nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
++  if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal()))
++    return true;
++
++  bool isAllowed = false;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
++                                do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  nsCOMPtr<nsIPermissionManager> permissionManager =
++                          do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
++  if (thirdPartyUtil && permissionManager) {
++    nsCOMPtr<nsIURI> uri;
++    nsresult rv = thirdPartyUtil->GetFirstPartyURI(NULL, aDocument,
++                                                   getter_AddRefs(uri));
++    uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
++    if (NS_SUCCEEDED(rv)) {
++      // Allow local files to access canvas data; check content permissions
++      // for remote pages.
++      bool isFileURL = false;
++      (void)uri->SchemeIs("file", &isFileURL);
++      if (isFileURL)
++        permission = nsIPermissionManager::ALLOW_ACTION;
++      else {
++        rv = permissionManager->TestPermission(uri,
++                                PERMISSION_CANVAS_EXTRACT_DATA, &permission);
++      }
++    }
++
++    if (NS_SUCCEEDED(rv)) {
++      isAllowed = (permission == nsIPermissionManager::ALLOW_ACTION);
++
++      if (!isAllowed && (permission != nsIPermissionManager::DENY_ACTION)) {
++        // Send notification so that a prompt is displayed.
++        nsCString spec;
++        rv = uri->GetSpec(spec);
++        NS_ENSURE_SUCCESS(rv, rv);
++        nsCOMPtr<nsIObserverService> obs =
++                                    mozilla::services::GetObserverService();
++        obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT,
++                             NS_ConvertUTF8toUTF16(spec).get());
++      }
++    }
++  }
++
++  return isAllowed;
++}
++
+ void
+ DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
+                          nsIPrincipal *aPrincipal,
+diff --git a/content/canvas/src/CanvasUtils.h b/content/canvas/src/CanvasUtils.h
+index d464d0b..f266de6 100644
+--- a/content/canvas/src/CanvasUtils.h
++++ b/content/canvas/src/CanvasUtils.h
+@@ -45,6 +45,8 @@ void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
+                               bool forceWriteOnly,
+                               bool CORSUsed);
+ 
++bool IsImageExtractionAllowed(nsIDocument *aDocument);
++
+ // Make a double out of |v|, treating undefined values as 0.0 (for
+ // the sake of sparse arrays).  Return true iff coercion
+ // succeeded.
+diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+index 1ee7a02..0dec654 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+@@ -3946,6 +3946,22 @@ nsCanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
+ 
+     uint8_t* data = JS_GetUint8ClampedArrayData(darray, aCx);
+ 
++    // Check for site-specific permission and return all-white, opaque pixel
++    // data if no permission.  This check is not needed if the canvas was
++    // created with a docshell (that is only done for special internal uses).
++    bool usePlaceholder = false;
++    if (mCanvasElement) {
++      nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
++      usePlaceholder = !ownerDoc ||
++                          !CanvasUtils::IsImageExtractionAllowed(ownerDoc);
++    }
++
++    if (usePlaceholder) {
++      memset(data, 0xFF, len.value());
++      *aRetval = darray;
++      return NS_OK;
++    }
++
+     /* Copy the surface contents to the buffer */
+     nsRefPtr<gfxImageSurface> tmpsurf =
+         new gfxImageSurface(data,
+diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+index 07b5236..d86ba32 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+@@ -4251,6 +4251,22 @@ nsCanvasRenderingContext2DAzure::GetImageDataArray(JSContext* aCx,
+ 
+   uint8_t* data = JS_GetUint8ClampedArrayData(darray, aCx);
+ 
++  // Check for site-specific permission and return all-white, opaque pixel
++  // data if no permission.  This check is not needed if the canvas was
++  // created with a docshell (that is only done for special internal uses).
++  bool usePlaceholder = false;
++  if (mCanvasElement) {
++    nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
++    usePlaceholder = !ownerDoc ||
++                        !CanvasUtils::IsImageExtractionAllowed(ownerDoc);
++  }
++
++  if (usePlaceholder) {
++    memset(data, 0xFF, len.value());
++    *aRetval = darray;
++    return NS_OK;
++  }
++
+   IntRect srcRect(0, 0, mWidth, mHeight);
+   IntRect destRect(aX, aY, aWidth, aHeight);
+ 
+diff --git a/content/html/content/public/nsHTMLCanvasElement.h b/content/html/content/public/nsHTMLCanvasElement.h
+index 2c11600..65da344 100644
+--- a/content/html/content/public/nsHTMLCanvasElement.h
++++ b/content/html/content/public/nsHTMLCanvasElement.h
+@@ -157,13 +157,16 @@ protected:
+   nsresult UpdateContext(nsIPropertyBag *aNewContextOptions = nullptr);
+   nsresult ExtractData(const nsAString& aType,
+                        const nsAString& aOptions,
++                       bool aUsePlaceholder,
+                        nsIInputStream** aStream,
+                        bool& aFellBackToPNG);
+   nsresult ToDataURLImpl(const nsAString& aMimeType,
+                          nsIVariant* aEncoderOptions,
++                         bool aUsePlaceholder,
+                          nsAString& aDataURL);
+   nsresult MozGetAsFileImpl(const nsAString& aName,
+                             const nsAString& aType,
++                            bool aUsePlaceholder,
+                             nsIDOMFile** aResult);
+   nsresult GetContextHelper(const nsAString& aContextId,
+                             bool aForceThebes,
+diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in
+index 9466587..86368a2 100644
+--- a/content/html/content/src/Makefile.in
++++ b/content/html/content/src/Makefile.in
+@@ -113,6 +113,7 @@ INCLUDES	+= \
+ 		-I$(srcdir)/../../../events/src \
+ 		-I$(srcdir)/../../../xbl/src \
+ 		-I$(srcdir)/../../../xul/content/src \
++		-I$(srcdir)/../../../canvas/src/ \
+ 		-I$(srcdir)/../../../../layout/forms \
+ 		-I$(srcdir)/../../../../layout/style \
+ 		-I$(srcdir)/../../../../layout/tables \
+diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp
+index 961ebf1..13a6910 100644
+--- a/content/html/content/src/nsHTMLCanvasElement.cpp
++++ b/content/html/content/src/nsHTMLCanvasElement.cpp
+@@ -31,6 +31,8 @@
+ 
+ #include "nsIWritablePropertyBag2.h"
+ 
++#include "CanvasUtils.h"
++
+ #define DEFAULT_CANVAS_WIDTH 300
+ #define DEFAULT_CANVAS_HEIGHT 150
+ 
+@@ -184,7 +186,10 @@ nsHTMLCanvasElement::ToDataURL(const nsAString& aType, nsIVariant* aParams,
+     return NS_ERROR_DOM_SECURITY_ERR;
+   }
+ 
+-  return ToDataURLImpl(aType, aParams, aDataURL);
++  // Check site-specific permission and display prompt if appropriate.
++  // If no permission, return all-white, opaque image data.
++  bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc());
++  return ToDataURLImpl(aType, aParams, usePlaceholder, aDataURL);
+ }
+ 
+ // nsHTMLCanvasElement::mozFetchAsStream
+@@ -200,7 +205,7 @@ nsHTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
+   bool fellBackToPNG = false;
+   nsCOMPtr<nsIInputStream> inputData;
+ 
+-  rv = ExtractData(aType, EmptyString(), getter_AddRefs(inputData), fellBackToPNG);
++  rv = ExtractData(aType, EmptyString(), false, getter_AddRefs(inputData), fellBackToPNG);
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv);
+@@ -220,19 +225,26 @@ nsHTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
+ nsresult
+ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
+                                  const nsAString& aOptions,
++                                 bool aUsePlaceholder,
+                                  nsIInputStream** aStream,
+                                  bool& aFellBackToPNG)
+ {
+   // note that if we don't have a current context, the spec says we're
+   // supposed to just return transparent black pixels of the canvas
+   // dimensions.
++  // If placeholder data was requested, return all-white, opaque image data.
+   nsRefPtr<gfxImageSurface> emptyCanvas;
+   nsIntSize size = GetWidthHeight();
+-  if (!mCurrentContext) {
++  if (aUsePlaceholder || !mCurrentContext) {
+     emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
+     if (emptyCanvas->CairoStatus()) {
+       return NS_ERROR_INVALID_ARG;
+     }
++
++    if (aUsePlaceholder) {
++      int32_t dataSize = emptyCanvas->GetDataSize();
++      memset(emptyCanvas->Data(), 0xFF, dataSize);
++    }
+   }
+ 
+   nsresult rv;
+@@ -242,12 +254,13 @@ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
+   NS_ConvertUTF16toUTF8 encoderType(aType);
+ 
+  try_again:
+-  if (mCurrentContext) {
++  if (!aUsePlaceholder && mCurrentContext) {
+     rv = mCurrentContext->GetInputStream(encoderType.get(),
+                                          nsPromiseFlatString(aOptions).get(),
+                                          getter_AddRefs(imgStream));
+   } else {
+-    // no context, so we have to encode the empty image we created above
++    // Using placeholder or we have no context:  encode the empty/white image
++    // we created above.
+     nsCString enccid("@mozilla.org/image/encoder;2?type=");
+     enccid += encoderType;
+ 
+@@ -285,6 +298,7 @@ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
+ nsresult
+ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
+                                    nsIVariant* aEncoderOptions,
++                                   bool aUsePlaceholder,
+                                    nsAString& aDataURL)
+ {
+   bool fallbackToPNG = false;
+@@ -340,13 +354,15 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
+   }
+ 
+   nsCOMPtr<nsIInputStream> stream;
+-  rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
++  rv = ExtractData(type, params, aUsePlaceholder,
++                   getter_AddRefs(stream), fallbackToPNG);
+ 
+   // If there are unrecognized custom parse options, we should fall back to 
+   // the default values for the encoder without any options at all.
+   if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
+     fallbackToPNG = false;
+-    rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
++    rv = ExtractData(type, EmptyString(), aUsePlaceholder,
++                     getter_AddRefs(stream), fallbackToPNG);
+   }
+ 
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -378,19 +394,23 @@ nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
+     return NS_ERROR_DOM_SECURITY_ERR;
+   }
+ 
+-  return MozGetAsFileImpl(aName, aType, aResult);
++  // Check site-speciifc permission and display prompt if appropriate.
++  // If no permission, return all-white, opaque image data.
++  bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc());
++  return MozGetAsFileImpl(aName, aType, usePlaceholder, aResult);
+ }
+ 
+ nsresult
+ nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
+                                       const nsAString& aType,
++                                      bool aUsePlaceholder,
+                                       nsIDOMFile** aResult)
+ {
+   bool fallbackToPNG = false;
+ 
+   nsCOMPtr<nsIInputStream> stream;
+-  nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
+-                            fallbackToPNG);
++  nsresult rv = ExtractData(aType, EmptyString(), aUsePlaceholder,
++                            getter_AddRefs(stream), fallbackToPNG);
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   nsAutoString type(aType);
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch b/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
deleted file mode 100644
index 114301d..0000000
--- a/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From 36d57455893bcf6dc08e91a2784970f285c5e84b Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git at torproject.org>
-Date: Tue, 28 Aug 2012 18:35:33 -0700
-Subject: [PATCH 20/24] Add mozIThirdPartyUtil.getFirstPartyURI API
-
-API allows you to get the url bar URI for a channel or nsIDocument.
----
- content/base/src/ThirdPartyUtil.cpp        |   59 ++++++++++++++++++++++++++++
- content/base/src/ThirdPartyUtil.h          |    2 +
- netwerk/base/public/mozIThirdPartyUtil.idl |   21 ++++++++++
- 3 files changed, 82 insertions(+), 0 deletions(-)
-
-diff --git a/content/base/src/ThirdPartyUtil.cpp b/content/base/src/ThirdPartyUtil.cpp
-index 6a415e9..52b3dab 100644
---- a/content/base/src/ThirdPartyUtil.cpp
-+++ b/content/base/src/ThirdPartyUtil.cpp
-@@ -40,6 +40,9 @@
- #include "nsIServiceManager.h"
- #include "nsIHttpChannelInternal.h"
- #include "nsIDOMWindow.h"
-+#include "nsICookiePermission.h"
-+#include "nsIDOMDocument.h"
-+#include "nsIDocument.h"
- #include "nsILoadContext.h"
- #include "nsIPrincipal.h"
- #include "nsIScriptObjectPrincipal.h"
-@@ -54,6 +57,7 @@ ThirdPartyUtil::Init()
- 
-   nsresult rv;
-   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
-+  mCookiePermissions = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
-   return rv;
- }
- 
-@@ -315,3 +319,58 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
- 
-   return NS_OK;
- }
-+
-+NS_IMETHODIMP
-+ThirdPartyUtil::GetFirstPartyURI(nsIChannel *aChannel,
-+                                 nsIDocument *aDoc,
-+                                 nsIURI **aOutput)
-+{
-+  nsresult rv = NS_ERROR_NULL_POINTER;
-+
-+  if (!aChannel && aDoc) {
-+    aChannel = aDoc->GetChannel();
-+  }
-+
-+  // If aChannel is specified or available, use the official route
-+  // for sure
-+  if (aChannel) {
-+    rv = mCookiePermissions->GetOriginatingURI(aChannel, aOutput);
-+  }
-+
-+  // If the channel was missing, closed or broken, try the
-+  // window hierarchy directly. 
-+  //
-+  // This might fail to work for first-party loads themselves, but 
-+  // we don't need this codepath for that case.
-+  if (NS_FAILED(rv) && aDoc) {
-+    nsCOMPtr<nsIDOMWindow> top;
-+    nsCOMPtr<nsIDOMDocument> topDDoc;
-+   
-+    if (aDoc->GetWindow()) {
-+      aDoc->GetWindow()->GetTop(getter_AddRefs(top));
-+      top->GetDocument(getter_AddRefs(topDDoc));
-+
-+      nsCOMPtr<nsIDocument> topDoc(do_QueryInterface(topDDoc));
-+      *aOutput = topDoc->GetOriginalURI();
-+    } else {
-+      // XXX: Chrome callers (such as NoScript) can end up here
-+      // through getImageData/canvas usage with no document state
-+      // (no Window and a document URI of about:blank). Propogate
-+      // rv fail (by doing nothing), and hope caller recovers.
-+    }
-+
-+    if (*aOutput)
-+      rv = NS_OK;
-+  }
-+
-+  // TODO: We could provide a route through the loadgroup + notification
-+  // callbacks too, but either channel or document was always available
-+  // in the cases where this function was originally needed (the image cache).
-+  // The notification callbacks also appear to suffers from the same limitation
-+  // as the document path. See nsICookiePermissions.GetOriginatingURI() for
-+  // details.
-+
-+  return rv;
-+}
-+
-+
-diff --git a/content/base/src/ThirdPartyUtil.h b/content/base/src/ThirdPartyUtil.h
-index 58ddb15..c8eab11 100644
---- a/content/base/src/ThirdPartyUtil.h
-+++ b/content/base/src/ThirdPartyUtil.h
-@@ -42,6 +42,7 @@
- #include "nsString.h"
- #include "mozIThirdPartyUtil.h"
- #include "nsIEffectiveTLDService.h"
-+#include "nsICookiePermission.h"
- 
- class nsIURI;
- class nsIChannel;
-@@ -61,6 +62,7 @@ private:
-   static already_AddRefed<nsIURI> GetURIFromWindow(nsIDOMWindow* aWin);
- 
-   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
-+  nsCOMPtr<nsICookiePermission> mCookiePermissions;
- };
- 
- #endif
-diff --git a/netwerk/base/public/mozIThirdPartyUtil.idl b/netwerk/base/public/mozIThirdPartyUtil.idl
-index ad41985..fd2cb38 100644
---- a/netwerk/base/public/mozIThirdPartyUtil.idl
-+++ b/netwerk/base/public/mozIThirdPartyUtil.idl
-@@ -40,6 +40,7 @@
- interface nsIURI;
- interface nsIDOMWindow;
- interface nsIChannel;
-+interface nsIDocument;
- 
- /**
-  * Utility functions for determining whether a given URI, channel, or window
-@@ -173,6 +174,26 @@ interface mozIThirdPartyUtil : nsISupports
-    * @return the base domain.
-    */
-   AUTF8String getBaseDomain(in nsIURI aHostURI);
-+
-+
-+  /**
-+   * getFirstPartyURI
-+   *
-+   * Obtain the top-level url bar URI for either a channel or a document.
-+   * Either parameter may be null (but not both).
-+   * 
-+   * @param aChannel
-+   *        An arbitrary channel for some content element of a first party
-+   *        load. Can be null.
-+   *
-+   * @param aDoc
-+   *        An arbitrary third party document. Can be null.
-+   *
-+   * @return the first party url bar URI for the load.
-+   */ 
-+  nsIURI getFirstPartyURI(in nsIChannel aChannel,
-+                          in nsIDocument aDoc);
-+
- };
- 
- %{ C++
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0021-Add-canvas-image-extraction-prompt.patch b/src/current-patches/firefox/0021-Add-canvas-image-extraction-prompt.patch
deleted file mode 100644
index cf5dd61..0000000
--- a/src/current-patches/firefox/0021-Add-canvas-image-extraction-prompt.patch
+++ /dev/null
@@ -1,551 +0,0 @@
-From 29ce940434ebbb8e54c0d9b8f84ccf6ec6bd71bc Mon Sep 17 00:00:00 2001
-From: Kathleen Brade <brade at pearlcrescent.com>
-Date: Tue, 9 Oct 2012 11:21:06 -0400
-Subject: [PATCH 21/24] Add canvas image extraction prompt.
-
----
- browser/base/content/browser.css                   |    1 +
- browser/base/content/browser.js                    |  102 ++++++++++++++++++++
- browser/base/content/browser.xul                   |    1 +
- .../en-US/chrome/browser/browser.properties        |    7 ++
- browser/themes/gnomestripe/browser/browser.css     |    2 +
- browser/themes/pinstripe/browser/browser.css       |    2 +
- browser/themes/winstripe/browser/browser.css       |    2 +
- content/canvas/src/CanvasUtils.cpp                 |   63 ++++++++++++
- content/canvas/src/CanvasUtils.h                   |    2 +
- content/canvas/src/nsCanvasRenderingContext2D.cpp  |   15 +++
- .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |   15 +++
- content/html/content/public/nsHTMLCanvasElement.h  |    3 +
- content/html/content/src/Makefile.in               |    1 +
- content/html/content/src/nsHTMLCanvasElement.cpp   |   39 ++++++--
- 14 files changed, 246 insertions(+), 9 deletions(-)
-
-diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
-index f033c2b..c709631 100644
---- a/browser/base/content/browser.css
-+++ b/browser/base/content/browser.css
-@@ -440,6 +440,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
-    created with a null anchorID, so in that case use a default anchor icon. */
- #notification-popup-box[anchorid="notification-popup-box"] > #default-notification-icon,
- #notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
-+#notification-popup-box[anchorid="canvas-notification-icon"] > #canvas-notification-icon,
- #notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
- #notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
- #notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon {
-diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
-index 20e3666..0c6bd46 100644
---- a/browser/base/content/browser.js
-+++ b/browser/base/content/browser.js
-@@ -1522,6 +1522,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
-   BrowserOffline.init();
-   OfflineApps.init();
-   IndexedDBPromptHelper.init();
-+  CanvasPermissionPromptHelper.init();
-   gFormSubmitObserver.init();
-   AddonManager.addAddonListener(AddonsMgrListener);
- 
-@@ -1834,6 +1835,7 @@ function BrowserShutdown() {
-     BrowserOffline.uninit();
-     OfflineApps.uninit();
-     IndexedDBPromptHelper.uninit();
-+    CanvasPermissionPromptHelper.uninit();
-     AddonManager.removeAddonListener(AddonsMgrListener);
-   }
- 
-@@ -6656,6 +6658,106 @@ var IndexedDBPromptHelper = {
-   }
- };
- 
-+var CanvasPermissionPromptHelper = {
-+  _permissionsPrompt: "canvas-permissions-prompt",
-+  _notificationIcon: "canvas-notification-icon",
-+
-+  init:
-+  function CanvasPermissionPromptHelper_init() {
-+    Services.obs.addObserver(this, this._permissionsPrompt, false);
-+  },
-+
-+  uninit:
-+  function CanvasPermissionPromptHelper_uninit() {
-+    Services.obs.removeObserver(this, this._permissionsPrompt, false);
-+  },
-+
-+  // aSubject is an nsIDOMWindow.
-+  // aData is an URL string.
-+  observe:
-+  function CanvasPermissionPromptHelper_observe(aSubject, aTopic, aData) {
-+    if ((aTopic != this._permissionsPrompt) || !aData)
-+      throw new Error("Unexpected topic or missing URL");
-+
-+    var uri = makeURI(aData);
-+    var contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
-+    var contentDocument = contentWindow.document;
-+    var browserWindow =
-+      OfflineApps._getBrowserWindowForContentWindow(contentWindow);
-+
-+    if (browserWindow != window) {
-+      // Must belong to some other window.
-+      return;
-+    }
-+
-+    // If canvas prompt is already displayed, just return.  This is OK (and
-+    // more efficient) since this permission is associated with the top
-+    // browser's URL.
-+    if (PopupNotifications.getNotification(aTopic, browser))
-+      return;
-+
-+    var bundleSvc = Cc["@mozilla.org/intl/stringbundle;1"].
-+                        getService(Ci.nsIStringBundleService);
-+    var torBtnBundle;
-+    try {
-+      torBtnBundle = bundleSvc.createBundle(
-+                             "chrome://torbutton/locale/torbutton.properties");
-+    } catch (e) {}
-+
-+    var message = getLocalizedString("canvas.siteprompt", [ uri.asciiHost ]);
-+
-+    var mainAction = {
-+      label: getLocalizedString("canvas.allow"),
-+      accessKey: getLocalizedString("canvas.allowAccessKey"),
-+      callback: function() {
-+          setCanvasPermission(uri, Ci.nsIPermissionManager.ALLOW_ACTION);
-+      }
-+    };
-+
-+    var secondaryActions = [
-+      {
-+        label: getLocalizedString("canvas.never"),
-+        accessKey: getLocalizedString("canvas.neverAccessKey"),
-+        callback: function() {
-+          setCanvasPermission(uri, Ci.nsIPermissionManager.DENY_ACTION);
-+        }
-+      }
-+    ];
-+
-+    // Since we have a process in place to perform localization for the
-+    // Torbutton extension, get our strings from the extension if possible.
-+    function getLocalizedString(aID, aParams) {
-+      var s;
-+      if (torBtnBundle) try {
-+        if (aParams)
-+          s = torBtnBundle.formatStringFromName(aID, aParams, aParams.length);
-+        else
-+          s = torBtnBundle.GetStringFromName(aID);
-+      } catch (e) {}
-+
-+      if (!s) {
-+        if (aParams)
-+          s = gNavigatorBundle.getFormattedString(aID, aParams);
-+        else
-+          s = gNavigatorBundle.getString(aID);
-+      }
-+
-+      return s;
-+    }
-+
-+    function setCanvasPermission(aURI, aPerm) {
-+      Services.perms.add(aURI, "canvas/extractData", aPerm,
-+                         Ci.nsIPermissionManager.EXPIRE_NEVER);
-+    }
-+
-+    var browser = OfflineApps._getBrowserForContentWindow(browserWindow,
-+                                                          contentWindow);
-+    notification = PopupNotifications.show(browser, aTopic, message,
-+                                           this._notificationIcon, mainAction,
-+                                           secondaryActions, null);
-+  }
-+};
-+
- function WindowIsClosing()
- {
-   if (TabView.isVisible()) {
-diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
-index ba2a7cb..1acea43 100644
---- a/browser/base/content/browser.xul
-+++ b/browser/base/content/browser.xul
-@@ -520,6 +520,7 @@
-             <image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
-             <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
-             <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
-+            <image id="canvas-notification-icon" class="notification-anchor-icon" role="button"/>
-             <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
-             <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
-           </box>
-diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties
-index 380e3c3..98154d1 100644
---- a/browser/locales/en-US/chrome/browser/browser.properties
-+++ b/browser/locales/en-US/chrome/browser/browser.properties
-@@ -197,6 +197,13 @@ offlineApps.usage=This website (%S) is now storing more than %SMB of data on you
- offlineApps.manageUsage=Show settings
- offlineApps.manageUsageAccessKey=S
- 
-+# Canvas permission prompt
-+canvas.siteprompt=This website (%S) attempted to access image data on a canvas.  Blank (white) image data was returned this time.
-+canvas.allow=Allow in the Future
-+canvas.allowAccessKey=A
-+canvas.never=Never for This Site
-+canvas.neverAccessKey=e
-+
- # LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
- # %2$S a number of megabytes.
- indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
-diff --git a/browser/themes/gnomestripe/browser/browser.css b/browser/themes/gnomestripe/browser/browser.css
-index edc0b72..8ba057e 100644
---- a/browser/themes/gnomestripe/browser/browser.css
-+++ b/browser/themes/gnomestripe/browser/browser.css
-@@ -1227,6 +1227,7 @@ toolbar[iconsize="small"] #feed-button {
-   list-style-image: url("moz-icon://stock/gtk-cancel?size=menu");
- }
- 
-+.popup-notification-icon[popupid="canvas-permissions-prompt"],
- .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
- .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
-   list-style-image: url(chrome://global/skin/icons/question-64.png);
-@@ -1281,6 +1282,7 @@ toolbar[iconsize="small"] #feed-button {
-   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
- }
- 
-+#canvas-notification-icon,
- #indexedDB-notification-icon {
-   list-style-image: url(chrome://global/skin/icons/question-16.png);
- }
-diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css
-index 2a96556..f94a6f2 100644
---- a/browser/themes/pinstripe/browser/browser.css
-+++ b/browser/themes/pinstripe/browser/browser.css
-@@ -2404,10 +2404,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
-   -moz-image-region: rect(0px, 48px, 16px, 32px);
- }
- 
-+#canvas-notification-icon,
- #indexedDB-notification-icon {
-   list-style-image: url(chrome://global/skin/icons/question-16.png);
- }
- 
-+.popup-notification-icon[popupid="canvas-permissions-prompt"],
- .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
- .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
-   list-style-image: url(chrome://global/skin/icons/question-64.png);
-diff --git a/browser/themes/winstripe/browser/browser.css b/browser/themes/winstripe/browser/browser.css
-index 0103c79..d352790 100644
---- a/browser/themes/winstripe/browser/browser.css
-+++ b/browser/themes/winstripe/browser/browser.css
-@@ -2294,6 +2294,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
-   -moz-image-region: rect(32px, 32px, 48px, 16px);
- }
- 
-+.popup-notification-icon[popupid="canvas-permissions-prompt"],
- .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
- .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
-   list-style-image: url(chrome://global/skin/icons/question-64.png);
-@@ -2346,6 +2347,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
-   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
- }
- 
-+#canvas-notification-icon,
- #indexedDB-notification-icon {
-   list-style-image: url(chrome://global/skin/icons/question-16.png);
- }
-diff --git a/content/canvas/src/CanvasUtils.cpp b/content/canvas/src/CanvasUtils.cpp
-index 2f822eb..d7d0591 100644
---- a/content/canvas/src/CanvasUtils.cpp
-+++ b/content/canvas/src/CanvasUtils.cpp
-@@ -59,6 +59,15 @@
- #include "CanvasUtils.h"
- #include "mozilla/gfx/Matrix.h"
- 
-+#include "nsIScriptObjectPrincipal.h"
-+#include "nsIPermissionManager.h"
-+#include "mozIThirdPartyUtil.h"
-+#include "nsContentUtils.h"
-+#include "nsUnicharUtils.h"
-+
-+#define TOPIC_CANVAS_PERMISSIONS_PROMPT "canvas-permissions-prompt"
-+#define PERMISSION_CANVAS_EXTRACT_DATA "canvas/extractData"
-+
- namespace mozilla {
- namespace CanvasUtils {
- 
-@@ -101,6 +110,60 @@ DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
-     aCanvasElement->SetWriteOnly();
- }
- 
-+// Check site-specific permission and display prompt if appropriate.
-+bool
-+IsImageExtractionAllowed(nsIDocument *aDocument)
-+{
-+  if (!aDocument)
-+    return false;
-+
-+  nsPIDOMWindow *win = aDocument->GetWindow();
-+  nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
-+  if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal()))
-+    return true;
-+
-+  bool isAllowed = false;
-+  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
-+                                do_GetService(THIRDPARTYUTIL_CONTRACTID);
-+  nsCOMPtr<nsIPermissionManager> permissionManager =
-+                          do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-+  if (thirdPartyUtil && permissionManager) {
-+    nsCOMPtr<nsIURI> uri;
-+    nsresult rv = thirdPartyUtil->GetFirstPartyURI(NULL, aDocument,
-+                                                   getter_AddRefs(uri));
-+    uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
-+    if (NS_SUCCEEDED(rv)) {
-+      // Allow local files to access canvas data; check content permissions
-+      // for remote pages.
-+      bool isFileURL = false;
-+      (void)uri->SchemeIs("file", &isFileURL);
-+      if (isFileURL)
-+        permission = nsIPermissionManager::ALLOW_ACTION;
-+      else {
-+        rv = permissionManager->TestPermission(uri,
-+                                PERMISSION_CANVAS_EXTRACT_DATA, &permission);
-+      }
-+    }
-+
-+    if (NS_SUCCEEDED(rv)) {
-+      isAllowed = (permission == nsIPermissionManager::ALLOW_ACTION);
-+
-+      if (!isAllowed && (permission != nsIPermissionManager::DENY_ACTION)) {
-+        // Send notification so that a prompt is displayed.
-+        nsCString spec;
-+        rv = uri->GetSpec(spec);
-+        NS_ENSURE_SUCCESS(rv, rv);
-+        nsCOMPtr<nsIObserverService> obs =
-+                                    mozilla::services::GetObserverService();
-+        obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT,
-+                             NS_ConvertUTF8toUTF16(spec).get());
-+      }
-+    }
-+  }
-+
-+  return isAllowed;
-+}
-+
- void
- LogMessage (const nsCString& errorString)
- {
-diff --git a/content/canvas/src/CanvasUtils.h b/content/canvas/src/CanvasUtils.h
-index 36186dd..067ee46 100644
---- a/content/canvas/src/CanvasUtils.h
-+++ b/content/canvas/src/CanvasUtils.h
-@@ -77,6 +77,8 @@ void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
-                               bool forceWriteOnly,
-                               bool CORSUsed);
- 
-+bool IsImageExtractionAllowed(nsIDocument *aDocument);
-+
- void LogMessage (const nsCString& errorString);
- void LogMessagef (const char *fmt, ...);
- 
-diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
-index 36389b0..0cf97ce 100644
---- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
-+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
-@@ -3886,6 +3886,21 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
-     if (!rightMost.valid() || !bottomMost.valid())
-         return NS_ERROR_DOM_SYNTAX_ERR;
- 
-+    // Check for site-specific permission and return all-white, opaque pixel
-+    // data if no permission.  This check is not needed if the canvas was
-+    // created with a docshell (that is only done for special internal uses).
-+    bool usePlaceholder = false;
-+    if (mCanvasElement) {
-+      nsCOMPtr<nsIDocument> ownerDoc = HTMLCanvasElement()->OwnerDoc();
-+      usePlaceholder = !ownerDoc ||
-+                          !CanvasUtils::IsImageExtractionAllowed(ownerDoc);
-+    }
-+
-+    if (usePlaceholder) {
-+      memset(aData, 0xFF, aDataLen);
-+      return NS_OK;
-+    }
-+
-     /* Copy the surface contents to the buffer */
-     nsRefPtr<gfxImageSurface> tmpsurf =
-         new gfxImageSurface(aData,
-diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
-index 13baaa5..e8dfb1e 100644
---- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
-+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
-@@ -4038,6 +4038,21 @@ nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRU
-     return NS_OK;
-   }
- 
-+  // Check for site-specific permission and return all-white, opaque pixel
-+  // data if no permission.  This check is not needed if the canvas was
-+  // created with a docshell (that is only done for special internal uses).
-+  bool usePlaceholder = false;
-+  if (mCanvasElement) {
-+    nsCOMPtr<nsIDocument> ownerDoc = HTMLCanvasElement()->OwnerDoc();
-+    usePlaceholder = !ownerDoc ||
-+                        !CanvasUtils::IsImageExtractionAllowed(ownerDoc);
-+  }
-+
-+  if (usePlaceholder) {
-+    memset(aData, 0xFF, aDataLen);
-+    return NS_OK;
-+  }
-+
-   IntRect srcRect(0, 0, mWidth, mHeight);
-   IntRect destRect(x, y, w, h);
- 
-diff --git a/content/html/content/public/nsHTMLCanvasElement.h b/content/html/content/public/nsHTMLCanvasElement.h
-index 86202a8..66176f2 100644
---- a/content/html/content/public/nsHTMLCanvasElement.h
-+++ b/content/html/content/public/nsHTMLCanvasElement.h
-@@ -188,13 +188,16 @@ protected:
-   nsresult UpdateContext(nsIPropertyBag *aNewContextOptions = nsnull);
-   nsresult ExtractData(const nsAString& aType,
-                        const nsAString& aOptions,
-+                       bool aUsePlaceholder,
-                        nsIInputStream** aStream,
-                        bool& aFellBackToPNG);
-   nsresult ToDataURLImpl(const nsAString& aMimeType,
-                          nsIVariant* aEncoderOptions,
-+                         bool aUsePlaceholder,
-                          nsAString& aDataURL);
-   nsresult MozGetAsFileImpl(const nsAString& aName,
-                             const nsAString& aType,
-+                            bool aUsePlaceholder,
-                             nsIDOMFile** aResult);
-   nsresult GetContextHelper(const nsAString& aContextId,
-                             bool aForceThebes,
-diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in
-index 019d297..3db4f7c 100644
---- a/content/html/content/src/Makefile.in
-+++ b/content/html/content/src/Makefile.in
-@@ -138,6 +138,7 @@ INCLUDES	+= \
- 		-I$(srcdir)/../../../events/src \
- 		-I$(srcdir)/../../../xbl/src \
- 		-I$(srcdir)/../../../xul/content/src \
-+		-I$(srcdir)/../../../canvas/src/ \
- 		-I$(srcdir)/../../../../layout/forms \
- 		-I$(srcdir)/../../../../layout/style \
- 		-I$(srcdir)/../../../../layout/tables \
-diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp
-index a302f67..572a81b 100644
---- a/content/html/content/src/nsHTMLCanvasElement.cpp
-+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
-@@ -60,6 +60,8 @@
- 
- #include "nsIWritablePropertyBag2.h"
- 
-+#include "CanvasUtils.h"
-+
- #define DEFAULT_CANVAS_WIDTH 300
- #define DEFAULT_CANVAS_HEIGHT 150
- 
-@@ -213,25 +215,36 @@ nsHTMLCanvasElement::ToDataURL(const nsAString& aType, nsIVariant* aParams,
-     return NS_ERROR_DOM_SECURITY_ERR;
-   }
- 
--  return ToDataURLImpl(aType, aParams, aDataURL);
-+  // Check site-specific permission and display prompt if appropriate.
-+  // If no permission, return all-white, opaque image data.
-+  bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc());
-+  return ToDataURLImpl(aType, aParams, usePlaceholder, aDataURL);
- }
- 
-+// TODO: on FF trunk, we also need to patch mozFetchAsStream().
- nsresult
- nsHTMLCanvasElement::ExtractData(const nsAString& aType,
-                                  const nsAString& aOptions,
-+                                 bool aUsePlaceholder,
-                                  nsIInputStream** aStream,
-                                  bool& aFellBackToPNG)
- {
-   // note that if we don't have a current context, the spec says we're
-   // supposed to just return transparent black pixels of the canvas
-   // dimensions.
-+  // If placeholder data was requested, return all-white, opaque image data.
-   nsRefPtr<gfxImageSurface> emptyCanvas;
-   nsIntSize size = GetWidthHeight();
--  if (!mCurrentContext) {
-+  if (aUsePlaceholder || !mCurrentContext) {
-     emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
-     if (emptyCanvas->CairoStatus()) {
-       return NS_ERROR_INVALID_ARG;
-     }
-+
-+    if (aUsePlaceholder) {
-+      int32_t dataSize = emptyCanvas->GetDataSize();
-+      memset(emptyCanvas->Data(), 0xFF, dataSize);
-+    }
-   }
- 
-   nsresult rv;
-@@ -241,12 +254,13 @@ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
-   NS_ConvertUTF16toUTF8 encoderType(aType);
- 
-  try_again:
--  if (mCurrentContext) {
-+  if (!aUsePlaceholder && mCurrentContext) {
-     rv = mCurrentContext->GetInputStream(encoderType.get(),
-                                          nsPromiseFlatString(aOptions).get(),
-                                          getter_AddRefs(imgStream));
-   } else {
--    // no context, so we have to encode the empty image we created above
-+    // Using placeholder or we have no context:  encode the empty/white image
-+    // we created above.
-     nsCString enccid("@mozilla.org/image/encoder;2?type=");
-     enccid += encoderType;
- 
-@@ -284,6 +298,7 @@ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
- nsresult
- nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
-                                    nsIVariant* aEncoderOptions,
-+                                   bool aUsePlaceholder,
-                                    nsAString& aDataURL)
- {
-   bool fallbackToPNG = false;
-@@ -339,13 +354,15 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
-   }
- 
-   nsCOMPtr<nsIInputStream> stream;
--  rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
-+  rv = ExtractData(type, params, aUsePlaceholder,
-+                   getter_AddRefs(stream), fallbackToPNG);
- 
-   // If there are unrecognized custom parse options, we should fall back to 
-   // the default values for the encoder without any options at all.
-   if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
-     fallbackToPNG = false;
--    rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
-+    rv = ExtractData(type, EmptyString(), aUsePlaceholder,
-+                     getter_AddRefs(stream), fallbackToPNG);
-   }
- 
-   NS_ENSURE_SUCCESS(rv, rv);
-@@ -376,19 +393,23 @@ nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
-     return NS_ERROR_DOM_SECURITY_ERR;
-   }
- 
--  return MozGetAsFileImpl(aName, aType, aResult);
-+  // Check site-speciifc permission and display prompt if appropriate.
-+  // If no permission, return all-white, opaque image data.
-+  bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc());
-+  return MozGetAsFileImpl(aName, aType, usePlaceholder, aResult);
- }
- 
- nsresult
- nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
-                                       const nsAString& aType,
-+                                      bool aUsePlaceholder,
-                                       nsIDOMFile** aResult)
- {
-   bool fallbackToPNG = false;
- 
-   nsCOMPtr<nsIInputStream> stream;
--  nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
--                            fallbackToPNG);
-+  nsresult rv = ExtractData(aType, EmptyString(), aUsePlaceholder,
-+                            getter_AddRefs(stream), fallbackToPNG);
-   NS_ENSURE_SUCCESS(rv, rv);
- 
-   nsAutoString type(aType);
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0021-Return-client-window-coordinates-for-mouse-event-scr.patch b/src/current-patches/firefox/0021-Return-client-window-coordinates-for-mouse-event-scr.patch
new file mode 100644
index 0000000..d927f02
--- /dev/null
+++ b/src/current-patches/firefox/0021-Return-client-window-coordinates-for-mouse-event-scr.patch
@@ -0,0 +1,77 @@
+From 5db96e68af26dfbfa2085d76efab8ddc09aaa45c Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade at pearlcrescent.com>
+Date: Wed, 28 Nov 2012 10:49:09 -0500
+Subject: [PATCH 21/26] Return client window coordinates for mouse event
+ screenX/Y (for dragend, 0,0 is returned).
+
+---
+ content/events/src/nsDOMMouseEvent.cpp |   22 ++++++++++++++++++++++
+ content/events/src/nsDOMTouchEvent.cpp |    6 ++++--
+ 2 files changed, 26 insertions(+), 2 deletions(-)
+
+diff --git a/content/events/src/nsDOMMouseEvent.cpp b/content/events/src/nsDOMMouseEvent.cpp
+index c1784c9..9718a90 100644
+--- a/content/events/src/nsDOMMouseEvent.cpp
++++ b/content/events/src/nsDOMMouseEvent.cpp
+@@ -301,6 +301,20 @@ nsDOMMouseEvent::GetMozMovementY(int32_t* aMovementY)
+ NS_METHOD nsDOMMouseEvent::GetScreenX(int32_t* aScreenX)
+ {
+   NS_ENSURE_ARG_POINTER(aScreenX);
++  bool isChrome = nsContentUtils::IsCallerChrome();
++  if (!isChrome)
++  {
++    // For non-chrome callers, return client coordinates instead.
++    // For some events, the result will be zero; specifically, for dragend
++    // events (there is no widget associated with dragend events, which
++    // causes GetClientX() to return zero).  Since dragend is for the drag
++    // originator and not for the receiver, it is probably not widely used
++    // (receivers get a drop event).  Therefore, returning 0 should not break
++    // many web pages.  Also, a few years ago Firefox returned 0.
++    // See:  https://bugzilla.mozilla.org/show_bug.cgi?id=466379
++    return GetClientX(aScreenX);
++  }
++
+   *aScreenX = nsDOMEvent::GetScreenCoords(mPresContext,
+                                           mEvent,
+                                           mEvent->refPoint).x;
+@@ -311,6 +325,14 @@ NS_IMETHODIMP
+ nsDOMMouseEvent::GetScreenY(int32_t* aScreenY)
+ {
+   NS_ENSURE_ARG_POINTER(aScreenY);
++  bool isChrome = nsContentUtils::IsCallerChrome();
++  if (!isChrome)
++  {
++    // For non-chrome callers, return client coordinates instead.
++    // See also the comment in nsDOMMouseEvent::GetScreenX().
++    return GetClientY(aScreenY);
++  }
++
+   *aScreenY = nsDOMEvent::GetScreenCoords(mPresContext,
+                                           mEvent,
+                                           mEvent->refPoint).y;
+diff --git a/content/events/src/nsDOMTouchEvent.cpp b/content/events/src/nsDOMTouchEvent.cpp
+index ccf4864..64ab0e8 100644
+--- a/content/events/src/nsDOMTouchEvent.cpp
++++ b/content/events/src/nsDOMTouchEvent.cpp
+@@ -44,14 +44,16 @@ nsDOMTouch::GetTarget(nsIDOMEventTarget** aTarget)
+ NS_IMETHODIMP
+ nsDOMTouch::GetScreenX(int32_t* aScreenX)
+ {
+-  *aScreenX = mScreenPoint.x;
++  bool isChrome = nsContentUtils::IsCallerChrome();
++  *aScreenX = isChrome ? mScreenPoint.x : mClientPoint.x;
+   return NS_OK;
+ }
+ 
+ NS_IMETHODIMP
+ nsDOMTouch::GetScreenY(int32_t* aScreenY)
+ {
+-  *aScreenY = mScreenPoint.y;
++  bool isChrome = nsContentUtils::IsCallerChrome();
++  *aScreenY = isChrome ? mScreenPoint.y : mClientPoint.y;
+   return NS_OK;
+ }
+ 
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0022-Do-not-expose-physical-screen-info.-via-window-and-w.patch b/src/current-patches/firefox/0022-Do-not-expose-physical-screen-info.-via-window-and-w.patch
new file mode 100644
index 0000000..13551af
--- /dev/null
+++ b/src/current-patches/firefox/0022-Do-not-expose-physical-screen-info.-via-window-and-w.patch
@@ -0,0 +1,310 @@
+From c4e1460f46fc04d81ec643fa9680b8fad8bc2b29 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade at pearlcrescent.com>
+Date: Wed, 28 Nov 2012 11:25:14 -0500
+Subject: [PATCH 22/26] Do not expose physical screen info. via window and
+ window.screen.
+
+---
+ dom/base/nsGlobalWindow.cpp |   46 ++++++++++++++++++++++
+ dom/base/nsGlobalWindow.h   |    2 +
+ dom/base/nsScreen.cpp       |   90 +++++++++++++++++++++++++++++++++++++++++++
+ dom/base/nsScreen.h         |    3 +
+ 4 files changed, 141 insertions(+), 0 deletions(-)
+
+diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
+index 6acd80a..3a370c9 100644
+--- a/dom/base/nsGlobalWindow.cpp
++++ b/dom/base/nsGlobalWindow.cpp
+@@ -3742,6 +3742,10 @@ nsGlobalWindow::GetOuterWidth(int32_t* aOuterWidth)
+ {
+   FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, return inner width to prevent fingerprinting.
++  if (!IsChrome())
++    return GetInnerWidth(aOuterWidth);
++
+   nsIntSize sizeCSSPixels;
+   nsresult rv = GetOuterSize(&sizeCSSPixels);
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -3755,6 +3759,10 @@ nsGlobalWindow::GetOuterHeight(int32_t* aOuterHeight)
+ {
+   FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, return inner height to prevent fingerprinting.
++  if (!IsChrome())
++    return GetInnerHeight(aOuterHeight);
++
+   nsIntSize sizeCSSPixels;
+   nsresult rv = GetOuterSize(&sizeCSSPixels);
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -3817,6 +3825,12 @@ nsGlobalWindow::GetScreenX(int32_t* aScreenX)
+ {
+   FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenX = 0;
++    return NS_OK;
++  }
++
+   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
+   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
+   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
+@@ -3858,6 +3872,12 @@ nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
+ {
+   FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenX = 0;
++    return NS_OK;
++  }
++
+   nsRect r = GetInnerScreenRect();
+   *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
+   return NS_OK;
+@@ -3868,6 +3888,12 @@ nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
+ {
+   FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenY = 0;
++    return NS_OK;
++  }
++
+   nsRect r = GetInnerScreenRect();
+   *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
+   return NS_OK;
+@@ -4025,6 +4051,12 @@ nsGlobalWindow::GetScreenY(int32_t* aScreenY)
+ {
+   FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenY = 0;
++    return NS_OK;
++  }
++
+   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
+   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
+   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
+@@ -4071,6 +4103,20 @@ nsGlobalWindow::SetScreenY(int32_t aScreenY)
+   return NS_OK;
+ }
+ 
++bool
++nsGlobalWindow::IsChrome()
++{
++  bool isChrome = false;
++
++  if (mDocShell) {
++    nsRefPtr<nsPresContext> presContext;
++    mDocShell->GetPresContext(getter_AddRefs(presContext));
++    isChrome = (presContext && presContext->IsChrome());
++  }
++
++  return isChrome;
++}
++
+ // NOTE: Arguments to this function should have values scaled to
+ // CSS pixels, not device pixels.
+ nsresult
+diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
+index 9acc1ea..4cb6938 100644
+--- a/dom/base/nsGlobalWindow.h
++++ b/dom/base/nsGlobalWindow.h
+@@ -827,6 +827,8 @@ protected:
+   nsresult SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth);
+   nsRect GetInnerScreenRect();
+ 
++  bool IsChrome();
++
+   bool IsFrame()
+   {
+     return GetParentInternal() != nullptr;
+diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp
+index 41c32ad..4f3904d 100644
+--- a/dom/base/nsScreen.cpp
++++ b/dom/base/nsScreen.cpp
+@@ -115,6 +115,12 @@ NS_IMPL_EVENT_HANDLER(nsScreen, mozorientationchange)
+ NS_IMETHODIMP
+ nsScreen::GetTop(int32_t* aTop)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aTop = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -127,6 +133,12 @@ nsScreen::GetTop(int32_t* aTop)
+ NS_IMETHODIMP
+ nsScreen::GetLeft(int32_t* aLeft)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aLeft = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -139,6 +151,14 @@ nsScreen::GetLeft(int32_t* aLeft)
+ NS_IMETHODIMP
+ nsScreen::GetWidth(int32_t* aWidth)
+ {
++  // For non-chrome callers, return content width to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerWidth(aWidth);
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -150,6 +170,14 @@ nsScreen::GetWidth(int32_t* aWidth)
+ NS_IMETHODIMP
+ nsScreen::GetHeight(int32_t* aHeight)
+ {
++  // For non-chrome callers, return content height to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerHeight(aHeight);
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -161,6 +189,12 @@ nsScreen::GetHeight(int32_t* aHeight)
+ NS_IMETHODIMP
+ nsScreen::GetPixelDepth(int32_t* aPixelDepth)
+ {
++  // For non-chrome callers, always return 24 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aPixelDepth = 24;
++    return NS_OK;
++  }
++
+   nsDeviceContext* context = GetDeviceContext();
+ 
+   if (!context) {
+@@ -186,6 +220,14 @@ nsScreen::GetColorDepth(int32_t* aColorDepth)
+ NS_IMETHODIMP
+ nsScreen::GetAvailWidth(int32_t* aAvailWidth)
+ {
++  // For non-chrome callers, return content width to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerWidth(aAvailWidth);
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -197,6 +239,14 @@ nsScreen::GetAvailWidth(int32_t* aAvailWidth)
+ NS_IMETHODIMP
+ nsScreen::GetAvailHeight(int32_t* aAvailHeight)
+ {
++  // For non-chrome callers, return content height to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerHeight(aAvailHeight);
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -208,6 +258,12 @@ nsScreen::GetAvailHeight(int32_t* aAvailHeight)
+ NS_IMETHODIMP
+ nsScreen::GetAvailLeft(int32_t* aAvailLeft)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aAvailLeft = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -219,6 +275,12 @@ nsScreen::GetAvailLeft(int32_t* aAvailLeft)
+ NS_IMETHODIMP
+ nsScreen::GetAvailTop(int32_t* aAvailTop)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aAvailTop = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -458,3 +520,31 @@ nsScreen::FullScreenEventListener::HandleEvent(nsIDOMEvent* aEvent)
+ 
+   return NS_OK;
+ }
++
++bool
++nsScreen::IsChrome()
++{
++  bool isChrome = false;
++  nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
++  if (owner)
++    isChrome = IsChromeType(owner->GetDocShell());
++
++  return isChrome;
++}
++
++nsresult
++nsScreen::GetDOMWindow(nsIDOMWindow **aResult)
++{
++  NS_ENSURE_ARG_POINTER(aResult);
++  *aResult = NULL;
++
++  nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
++  if (!owner)
++    return NS_ERROR_FAILURE;
++
++  nsCOMPtr<nsIDOMWindow> win = do_QueryInterface(owner);
++  NS_ENSURE_STATE(win);
++  win.swap(*aResult);
++
++  return NS_OK;
++}
+diff --git a/dom/base/nsScreen.h b/dom/base/nsScreen.h
+index 869d4fd..de18504 100644
+--- a/dom/base/nsScreen.h
++++ b/dom/base/nsScreen.h
+@@ -16,6 +16,7 @@
+ 
+ class nsIDocShell;
+ class nsDeviceContext;
++class nsIDOMWindow;
+ struct nsRect;
+ 
+ // Script "screen" object
+@@ -41,6 +42,8 @@ protected:
+   nsDeviceContext* GetDeviceContext();
+   nsresult GetRect(nsRect& aRect);
+   nsresult GetAvailRect(nsRect& aRect);
++  bool IsChrome();
++  nsresult GetDOMWindow(nsIDOMWindow **aResult);
+ 
+   mozilla::dom::ScreenOrientation mOrientation;
+ 
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0022-Return-client-window-coordinates-for-mouse-event-scr.patch b/src/current-patches/firefox/0022-Return-client-window-coordinates-for-mouse-event-scr.patch
deleted file mode 100644
index 6da9c72..0000000
--- a/src/current-patches/firefox/0022-Return-client-window-coordinates-for-mouse-event-scr.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 74215e38ba60b74df59216122c4f2cc068e33216 Mon Sep 17 00:00:00 2001
-From: Kathleen Brade <brade at pearlcrescent.com>
-Date: Tue, 9 Oct 2012 11:13:45 -0400
-Subject: [PATCH 22/24] Return client window coordinates for mouse event
- screenX/Y (for dragend, 0,0 is returned).
-
----
- content/events/src/nsDOMUIEvent.cpp |   15 +++++++++++++++
- 1 files changed, 15 insertions(+), 0 deletions(-)
-
-diff --git a/content/events/src/nsDOMUIEvent.cpp b/content/events/src/nsDOMUIEvent.cpp
-index fe57f52..d641f0d 100644
---- a/content/events/src/nsDOMUIEvent.cpp
-+++ b/content/events/src/nsDOMUIEvent.cpp
-@@ -135,10 +135,25 @@ nsDOMUIEvent::GetScreenPoint()
-     return nsIntPoint(0, 0);
-   }
- 
-+  bool isChrome = nsContentUtils::IsCallerChrome();
-+
-   if (!((nsGUIEvent*)mEvent)->widget ) {
-+    // For non-chrome callers, return 0,0 if there is no widget associated
-+    // with this event, e.g., for dragend events.  Since dragend is for the
-+    // drag originator and not for the receiver, it is probably not widely
-+    // used (receivers get a drop event).  Therefore, returning 0,0 should
-+    // not break many web pages.  Also, a few years ago Firefox returned 0,0.
-+    // See:  https://bugzilla.mozilla.org/show_bug.cgi?id=466379
-+    if (!isChrome)
-+      return nsIntPoint(0, 0);
-+
-     return mEvent->refPoint;
-   }
- 
-+  // For non-chrome callers, return client area coordinates instead.
-+  if (!isChrome)
-+    return GetClientPoint();
-+
-   nsIntPoint offset = mEvent->refPoint + 
-     ((nsGUIEvent*)mEvent)->widget->WidgetToScreenOffset();
-   nscoord factor = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0023-Do-not-expose-physical-screen-info.-via-window-and-w.patch b/src/current-patches/firefox/0023-Do-not-expose-physical-screen-info.-via-window-and-w.patch
deleted file mode 100644
index 1b925e0..0000000
--- a/src/current-patches/firefox/0023-Do-not-expose-physical-screen-info.-via-window-and-w.patch
+++ /dev/null
@@ -1,312 +0,0 @@
-From d944531b020848e09ac280af11d039d992ab6461 Mon Sep 17 00:00:00 2001
-From: Kathleen Brade <brade at pearlcrescent.com>
-Date: Wed, 3 Oct 2012 17:06:48 -0400
-Subject: [PATCH 23/24] Do not expose physical screen info. via window and
- window.screen.
-
----
- dom/base/nsGlobalWindow.cpp |   46 +++++++++++++++++++++
- dom/base/nsGlobalWindow.h   |    2 +
- dom/base/nsScreen.cpp       |   92 +++++++++++++++++++++++++++++++++++++++++++
- dom/base/nsScreen.h         |    3 +
- 4 files changed, 143 insertions(+), 0 deletions(-)
-
-diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
-index 2c99571..982d931 100644
---- a/dom/base/nsGlobalWindow.cpp
-+++ b/dom/base/nsGlobalWindow.cpp
-@@ -3817,6 +3817,10 @@ nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
- {
-   FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
- 
-+  // For non-chrome callers, return inner width to prevent fingerprinting.
-+  if (!IsChrome())
-+    return GetInnerWidth(aOuterWidth);
-+
-   nsIntSize sizeCSSPixels;
-   nsresult rv = GetOuterSize(&sizeCSSPixels);
-   NS_ENSURE_SUCCESS(rv, rv);
-@@ -3830,6 +3834,10 @@ nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
- {
-   FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
- 
-+  // For non-chrome callers, return inner height to prevent fingerprinting.
-+  if (!IsChrome())
-+    return GetInnerHeight(aOuterHeight);
-+
-   nsIntSize sizeCSSPixels;
-   nsresult rv = GetOuterSize(&sizeCSSPixels);
-   NS_ENSURE_SUCCESS(rv, rv);
-@@ -3892,6 +3900,12 @@ nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
- {
-   FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
- 
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aScreenX = 0;
-+    return NS_OK;
-+  }
-+
-   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
-   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
-   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
-@@ -3933,6 +3947,12 @@ nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
- {
-   FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
- 
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aScreenX = 0;
-+    return NS_OK;
-+  }
-+
-   nsRect r = GetInnerScreenRect();
-   *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
-   return NS_OK;
-@@ -3943,6 +3963,12 @@ nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
- {
-   FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
- 
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aScreenY = 0;
-+    return NS_OK;
-+  }
-+
-   nsRect r = GetInnerScreenRect();
-   *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
-   return NS_OK;
-@@ -4064,6 +4090,12 @@ nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
- {
-   FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
- 
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aScreenY = 0;
-+    return NS_OK;
-+  }
-+
-   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
-   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
-   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
-@@ -4110,6 +4142,20 @@ nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
-   return NS_OK;
- }
- 
-+bool
-+nsGlobalWindow::IsChrome()
-+{
-+  bool isChrome = false;
-+
-+  if (mDocShell) {
-+    nsRefPtr<nsPresContext> presContext;
-+    mDocShell->GetPresContext(getter_AddRefs(presContext));
-+    isChrome = (presContext && presContext->IsChrome());
-+  }
-+
-+  return isChrome;
-+}
-+
- // NOTE: Arguments to this function should have values scaled to
- // CSS pixels, not device pixels.
- nsresult
-diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
-index 2ffe4a7..863329c 100644
---- a/dom/base/nsGlobalWindow.h
-+++ b/dom/base/nsGlobalWindow.h
-@@ -744,6 +744,8 @@ protected:
-   nsresult SetOuterSize(PRInt32 aLengthCSSPixels, bool aIsWidth);
-   nsRect GetInnerScreenRect();
- 
-+  bool IsChrome();
-+
-   bool IsFrame()
-   {
-     return GetParentInternal() != nsnull;
-diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp
-index 33a03dc..29a3598 100644
---- a/dom/base/nsScreen.cpp
-+++ b/dom/base/nsScreen.cpp
-@@ -82,6 +82,12 @@ nsScreen::SetDocShell(nsIDocShell* aDocShell)
- NS_IMETHODIMP
- nsScreen::GetTop(PRInt32* aTop)
- {
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aTop = 0;
-+    return NS_OK;
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetRect(rect);
- 
-@@ -94,6 +100,12 @@ nsScreen::GetTop(PRInt32* aTop)
- NS_IMETHODIMP
- nsScreen::GetLeft(PRInt32* aLeft)
- {
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aLeft = 0;
-+    return NS_OK;
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetRect(rect);
- 
-@@ -106,6 +118,14 @@ nsScreen::GetLeft(PRInt32* aLeft)
- NS_IMETHODIMP
- nsScreen::GetWidth(PRInt32* aWidth)
- {
-+  // For non-chrome callers, return content width to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    nsCOMPtr<nsIDOMWindow> win;
-+    nsresult rv = GetDOMWindow(getter_AddRefs(win));
-+    NS_ENSURE_SUCCESS(rv, rv);
-+    return win->GetInnerWidth(aWidth);
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetRect(rect);
- 
-@@ -117,6 +137,14 @@ nsScreen::GetWidth(PRInt32* aWidth)
- NS_IMETHODIMP
- nsScreen::GetHeight(PRInt32* aHeight)
- {
-+  // For non-chrome callers, return content height to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    nsCOMPtr<nsIDOMWindow> win;
-+    nsresult rv = GetDOMWindow(getter_AddRefs(win));
-+    NS_ENSURE_SUCCESS(rv, rv);
-+    return win->GetInnerHeight(aHeight);
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetRect(rect);
- 
-@@ -128,6 +156,12 @@ nsScreen::GetHeight(PRInt32* aHeight)
- NS_IMETHODIMP
- nsScreen::GetPixelDepth(PRInt32* aPixelDepth)
- {
-+  // For non-chrome callers, always return 24 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aPixelDepth = 24;
-+    return NS_OK;
-+  }
-+
-   nsDeviceContext* context = GetDeviceContext();
- 
-   if (!context) {
-@@ -153,6 +187,14 @@ nsScreen::GetColorDepth(PRInt32* aColorDepth)
- NS_IMETHODIMP
- nsScreen::GetAvailWidth(PRInt32* aAvailWidth)
- {
-+  // For non-chrome callers, return content width to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    nsCOMPtr<nsIDOMWindow> win;
-+    nsresult rv = GetDOMWindow(getter_AddRefs(win));
-+    NS_ENSURE_SUCCESS(rv, rv);
-+    return win->GetInnerWidth(aAvailWidth);
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetAvailRect(rect);
- 
-@@ -164,6 +206,14 @@ nsScreen::GetAvailWidth(PRInt32* aAvailWidth)
- NS_IMETHODIMP
- nsScreen::GetAvailHeight(PRInt32* aAvailHeight)
- {
-+  // For non-chrome callers, return content height to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    nsCOMPtr<nsIDOMWindow> win;
-+    nsresult rv = GetDOMWindow(getter_AddRefs(win));
-+    NS_ENSURE_SUCCESS(rv, rv);
-+    return win->GetInnerHeight(aAvailHeight);
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetAvailRect(rect);
- 
-@@ -175,6 +225,12 @@ nsScreen::GetAvailHeight(PRInt32* aAvailHeight)
- NS_IMETHODIMP
- nsScreen::GetAvailLeft(PRInt32* aAvailLeft)
- {
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aAvailLeft = 0;
-+    return NS_OK;
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetAvailRect(rect);
- 
-@@ -186,6 +242,12 @@ nsScreen::GetAvailLeft(PRInt32* aAvailLeft)
- NS_IMETHODIMP
- nsScreen::GetAvailTop(PRInt32* aAvailTop)
- {
-+  // For non-chrome callers, always return 0 to prevent fingerprinting.
-+  if (!IsChrome()) {
-+    *aAvailTop = 0;
-+    return NS_OK;
-+  }
-+
-   nsRect rect;
-   nsresult rv = GetAvailRect(rect);
- 
-@@ -237,3 +299,33 @@ nsScreen::GetAvailRect(nsRect& aRect)
- 
-   return NS_OK;
- }
-+
-+bool
-+nsScreen::IsChrome()
-+{
-+  bool isChrome = false;
-+  if (mDocShell) {
-+    nsRefPtr<nsPresContext> presContext;
-+    mDocShell->GetPresContext(getter_AddRefs(presContext));
-+    if (presContext)
-+      isChrome = presContext->IsChrome();
-+  }
-+
-+  return isChrome;
-+}
-+
-+nsresult
-+nsScreen::GetDOMWindow(nsIDOMWindow **aResult)
-+{
-+  NS_ENSURE_ARG_POINTER(aResult);
-+  *aResult = NULL;
-+
-+  if (!mDocShell)
-+    return NS_ERROR_FAILURE;
-+
-+  nsCOMPtr<nsIDOMWindow> win = do_GetInterface(mDocShell);
-+  NS_ENSURE_STATE(win);
-+  win.swap(*aResult);
-+
-+  return NS_OK;
-+}
-diff --git a/dom/base/nsScreen.h b/dom/base/nsScreen.h
-index 52eab29..d4edaa3 100644
---- a/dom/base/nsScreen.h
-+++ b/dom/base/nsScreen.h
-@@ -44,6 +44,7 @@
- 
- class nsIDocShell;
- class nsDeviceContext;
-+class nsIDOMWindow;
- struct nsRect;
- 
- // Script "screen" object
-@@ -62,6 +63,8 @@ protected:
-   nsDeviceContext* GetDeviceContext();
-   nsresult GetRect(nsRect& aRect);
-   nsresult GetAvailRect(nsRect& aRect);
-+  bool IsChrome();
-+  nsresult GetDOMWindow(nsIDOMWindow **aResult);
- 
-   nsIDocShell* mDocShell; // Weak Reference
- };
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0023-Do-not-expose-system-colors-to-CSS-or-canvas.patch b/src/current-patches/firefox/0023-Do-not-expose-system-colors-to-CSS-or-canvas.patch
new file mode 100644
index 0000000..ea6ee8f
--- /dev/null
+++ b/src/current-patches/firefox/0023-Do-not-expose-system-colors-to-CSS-or-canvas.patch
@@ -0,0 +1,466 @@
+From 0b97e36981bb26406087bbd502a4d9e91e33a150 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade at pearlcrescent.com>
+Date: Wed, 28 Nov 2012 15:08:40 -0500
+Subject: [PATCH 23/26] Do not expose system colors to CSS or canvas.
+
+---
+ content/canvas/src/nsCanvasRenderingContext2D.cpp  |   28 +++-
+ .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |   34 +++-
+ .../canvas/src/nsCanvasRenderingContext2DAzure.h   |    5 +-
+ layout/style/nsRuleNode.cpp                        |    5 +-
+ widget/LookAndFeel.h                               |    9 +
+ widget/xpwidgets/nsXPLookAndFeel.cpp               |  173 +++++++++++++++++++-
+ widget/xpwidgets/nsXPLookAndFeel.h                 |    5 +-
+ 7 files changed, 239 insertions(+), 20 deletions(-)
+
+diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+index 0dec654..7132e4f 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+@@ -32,6 +32,7 @@
+ #include "nsCSSParser.h"
+ #include "mozilla/css/StyleRule.h"
+ #include "mozilla/css/Declaration.h"
++#include "mozilla/css/Loader.h"
+ #include "nsComputedDOMStyle.h"
+ #include "nsStyleSet.h"
+ 
+@@ -159,8 +160,9 @@ class nsCanvasGradient MOZ_FINAL : public nsIDOMCanvasGradient
+ public:
+     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
+ 
+-    nsCanvasGradient(gfxPattern* pat)
+-        : mPattern(pat)
++    nsCanvasGradient(mozilla::css::Loader* aLoader, gfxPattern* pat)
++        : mCSSLoader(aLoader)
++        , mPattern(pat)
+     {
+     }
+ 
+@@ -181,8 +183,17 @@ public:
+             return NS_ERROR_DOM_SYNTAX_ERR;
+         }
+ 
++        nsIPresShell* presShell = nullptr;
++        if (mCSSLoader) {
++          nsIDocument *doc = mCSSLoader->GetDocument();
++          if (doc)
++            presShell = doc->GetShell();
++        }
++
+         nscolor color;
+-        if (!nsRuleNode::ComputeColor(value, nullptr, nullptr, color)) {
++        if (!nsRuleNode::ComputeColor(value,
++                           presShell ? presShell->GetPresContext() : nullptr,
++                           nullptr, color)) {
+             return NS_ERROR_DOM_SYNTAX_ERR;
+         }
+ 
+@@ -194,6 +205,7 @@ public:
+     NS_DECL_ISUPPORTS
+ 
+ protected:
++    mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
+     nsRefPtr<gfxPattern> mPattern;
+ };
+ 
+@@ -1814,7 +1826,10 @@ nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, f
+     if (!gradpat)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+-    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
++    nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
++    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
++    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
++                                                               gradpat);
+     if (!grad)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+@@ -1836,7 +1851,10 @@ nsCanvasRenderingContext2D::CreateRadialGradient(float x0, float y0, float r0, f
+     if (!gradpat)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+-    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
++    nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
++    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
++    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
++                                                               gradpat);
+     if (!grad)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+index d86ba32..84c1927 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+@@ -31,6 +31,7 @@
+ #include "nsCSSParser.h"
+ #include "mozilla/css/StyleRule.h"
+ #include "mozilla/css/Declaration.h"
++#include "mozilla/css/Loader.h"
+ #include "nsComputedDOMStyle.h"
+ #include "nsStyleSet.h"
+ 
+@@ -140,9 +141,10 @@ NS_MEMORY_REPORTER_IMPLEMENT(CanvasAzureMemory,
+ class nsCanvasRadialGradientAzure : public nsCanvasGradientAzure
+ {
+ public:
+-  nsCanvasRadialGradientAzure(const Point &aBeginOrigin, Float aBeginRadius,
++  nsCanvasRadialGradientAzure(mozilla::css::Loader* aLoader,
++                              const Point &aBeginOrigin, Float aBeginRadius,
+                               const Point &aEndOrigin, Float aEndRadius)
+-    : nsCanvasGradientAzure(RADIAL)
++    : nsCanvasGradientAzure(aLoader, RADIAL)
+     , mCenter1(aBeginOrigin)
+     , mCenter2(aEndOrigin)
+     , mRadius1(aBeginRadius)
+@@ -159,8 +161,9 @@ public:
+ class nsCanvasLinearGradientAzure : public nsCanvasGradientAzure
+ {
+ public:
+-  nsCanvasLinearGradientAzure(const Point &aBegin, const Point &aEnd)
+-    : nsCanvasGradientAzure(LINEAR)
++  nsCanvasLinearGradientAzure(mozilla::css::Loader* aLoader,
++                              const Point &aBegin, const Point &aEnd)
++    : nsCanvasGradientAzure(aLoader, LINEAR)
+     , mBegin(aBegin)
+     , mEnd(aEnd)
+   {
+@@ -363,8 +366,17 @@ nsCanvasGradientAzure::AddColorStop(float offset, const nsAString& colorstr)
+     return NS_ERROR_DOM_SYNTAX_ERR;
+   }
+ 
++  nsIPresShell* presShell = nullptr;
++  if (mCSSLoader) {
++    nsIDocument *doc = mCSSLoader->GetDocument();
++    if (doc)
++      presShell = doc->GetShell();
++  }
++
+   nscolor color;
+-  if (!nsRuleNode::ComputeColor(value, nullptr, nullptr, color)) {
++  if (!nsRuleNode::ComputeColor(value,
++                          presShell ? presShell->GetPresContext() : nullptr,
++                          nullptr, color)) {
+     return NS_ERROR_DOM_SYNTAX_ERR;
+   }
+ 
+@@ -1788,8 +1800,10 @@ nsCanvasRenderingContext2DAzure::CreateLinearGradient(double x0, double y0, doub
+     return nullptr;
+   }
+ 
+-  nsRefPtr<nsIDOMCanvasGradient> grad =
+-    new nsCanvasLinearGradientAzure(Point(x0, y0), Point(x1, y1));
++  nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
++  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
++  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasLinearGradientAzure(
++                                     cssLoader, Point(x0, y0), Point(x1, y1));
+ 
+   return grad.forget();
+ }
+@@ -1818,8 +1832,10 @@ nsCanvasRenderingContext2DAzure::CreateRadialGradient(double x0, double y0, doub
+     return nullptr;
+   }
+ 
+-  nsRefPtr<nsIDOMCanvasGradient> grad =
+-    new nsCanvasRadialGradientAzure(Point(x0, y0), r0, Point(x1, y1), r1);
++  nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
++  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
++  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasRadialGradientAzure(
++                            cssLoader, Point(x0, y0), r0, Point(x1, y1), r1);
+ 
+   return grad.forget();
+ }
+diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.h b/content/canvas/src/nsCanvasRenderingContext2DAzure.h
+index 05ccf61..629d78a 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.h
++++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.h
+@@ -71,11 +71,14 @@ public:
+   NS_IMETHOD AddColorStop(float offset, const nsAString& colorstr);
+ 
+ protected:
+-  nsCanvasGradientAzure(Type aType) : mType(aType)
++  nsCanvasGradientAzure(mozilla::css::Loader* aLoader, Type aType)
++      : mCSSLoader(aLoader)
++      , mType(aType)
+   {}
+ 
+   nsTArray<mozilla::gfx::GradientStop> mRawStops;
+   mozilla::RefPtr<mozilla::gfx::GradientStops> mStops;
++  mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
+   Type mType;
+   virtual ~nsCanvasGradientAzure() {}
+ };
+diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
+index 33ce21e..078af3e 100644
+--- a/layout/style/nsRuleNode.cpp
++++ b/layout/style/nsRuleNode.cpp
+@@ -746,7 +746,10 @@ static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
+     int32_t intValue = aValue.GetIntValue();
+     if (0 <= intValue) {
+       LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
+-      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) {
++      bool useStandinsForNativeColors = aPresContext &&
++                                        !aPresContext->IsChrome();
++      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
++                                    useStandinsForNativeColors, &aResult))) {
+         result = true;
+       }
+     }
+diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h
+index e46bb13..59f00f5 100644
+--- a/widget/LookAndFeel.h
++++ b/widget/LookAndFeel.h
+@@ -446,6 +446,15 @@ public:
+   static nsresult GetColor(ColorID aID, nscolor* aResult);
+ 
+   /**
++   * This variant of GetColor() take an extra Boolean parameter that allows
++   * the caller to ask that hard-coded color values be substituted for
++   * native colors (used when it is desireable to hide system colors to
++   * avoid system fingerprinting).
++   */
++  static nsresult GetColor(ColorID aID, bool aUseStandinsForNativeColors,
++                           nscolor* aResult);
++
++  /**
+    * GetInt() and GetFloat() return a int or float value for aID.  The result
+    * might be distance, time, some flags or a int value which has particular
+    * meaning.  See each document at definition of each ID for the detail.
+diff --git a/widget/xpwidgets/nsXPLookAndFeel.cpp b/widget/xpwidgets/nsXPLookAndFeel.cpp
+index 50c2c86..20ccfef 100644
+--- a/widget/xpwidgets/nsXPLookAndFeel.cpp
++++ b/widget/xpwidgets/nsXPLookAndFeel.cpp
+@@ -476,6 +476,155 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
+   return false;
+ }
+ 
++bool
++nsXPLookAndFeel::ColorIsNotCSSAccessible(ColorID aID)
++{
++  bool result = false;
++
++  switch (aID) {
++    case eColorID_WindowBackground:
++    case eColorID_WindowForeground:
++    case eColorID_WidgetBackground:
++    case eColorID_WidgetForeground:
++    case eColorID_WidgetSelectBackground:
++    case eColorID_WidgetSelectForeground:
++    case eColorID_Widget3DHighlight:
++    case eColorID_Widget3DShadow:
++    case eColorID_TextBackground:
++    case eColorID_TextForeground:
++    case eColorID_TextSelectBackground:
++    case eColorID_TextSelectForeground:
++    case eColorID_TextSelectBackgroundDisabled:
++    case eColorID_TextSelectBackgroundAttention:
++    case eColorID_TextHighlightBackground:
++    case eColorID_TextHighlightForeground:
++    case eColorID_IMERawInputBackground:
++    case eColorID_IMERawInputForeground:
++    case eColorID_IMERawInputUnderline:
++    case eColorID_IMESelectedRawTextBackground:
++    case eColorID_IMESelectedRawTextForeground:
++    case eColorID_IMESelectedRawTextUnderline:
++    case eColorID_IMEConvertedTextBackground:
++    case eColorID_IMEConvertedTextForeground:
++    case eColorID_IMEConvertedTextUnderline:
++    case eColorID_IMESelectedConvertedTextBackground:
++    case eColorID_IMESelectedConvertedTextForeground:
++    case eColorID_IMESelectedConvertedTextUnderline:
++    case eColorID_SpellCheckerUnderline:
++      result = true;
++      break;
++    default:
++      break;
++  }
++
++  return result;
++}
++
++nscolor
++nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID)
++{
++  nscolor result = NS_RGB(0xFF, 0xFF, 0xFF);
++
++  // The stand-in colors are taken from the Windows 7 Aero theme
++  // except Mac-specific colors which are taken from Mac OS 10.7.
++  switch (aID) {
++    // CSS 2 colors:
++    case eColorID_activeborder:      result = NS_RGB(0xB4, 0xB4, 0xB4); break;
++    case eColorID_activecaption:     result = NS_RGB(0x99, 0xB4, 0xD1); break;
++    case eColorID_appworkspace:      result = NS_RGB(0xAB, 0xAB, 0xAB); break;
++    case eColorID_background:        result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_buttonface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID_buttonhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_buttonshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
++    case eColorID_buttontext:        result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_captiontext:       result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_graytext:          result = NS_RGB(0x6D, 0x6D, 0x6D); break;
++    case eColorID_highlight:         result = NS_RGB(0x33, 0x99, 0xFF); break;
++    case eColorID_highlighttext:     result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_inactiveborder:    result = NS_RGB(0xF4, 0xF7, 0xFC); break;
++    case eColorID_inactivecaption:   result = NS_RGB(0xBF, 0xCD, 0xDB); break;
++    case eColorID_inactivecaptiontext:
++      result = NS_RGB(0x43, 0x4E, 0x54); break;
++    case eColorID_infobackground:    result = NS_RGB(0xFF, 0xFF, 0xE1); break;
++    case eColorID_infotext:          result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_menu:              result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID_menutext:          result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_scrollbar:         result = NS_RGB(0xC8, 0xC8, 0xC8); break;
++    case eColorID_threeddarkshadow:  result = NS_RGB(0x69, 0x69, 0x69); break;
++    case eColorID_threedface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID_threedhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_threedlightshadow: result = NS_RGB(0xE3, 0xE3, 0xE3); break;
++    case eColorID_threedshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
++    case eColorID_window:            result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_windowframe:       result = NS_RGB(0x64, 0x64, 0x64); break;
++    case eColorID_windowtext:        result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_buttondefault:
++      result = NS_RGB(0x69, 0x69, 0x69); break;
++    case eColorID__moz_field:        result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_fieldtext:    result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_dialog:       result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID__moz_dialogtext:   result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_dragtargetzone:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_cellhighlight:
++      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID__moz_cellhighlighttext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_html_cellhighlight:
++      result = NS_RGB(0x33, 0x99, 0xFF); break;
++    case eColorID__moz_html_cellhighlighttext:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_buttonhoverface:
++      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID__moz_buttonhovertext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_menuhover:
++      result = NS_RGB(0x33, 0x99, 0xFF); break;
++    case eColorID__moz_menuhovertext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_menubartext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_menubarhovertext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_oddtreerow:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_mac_chrome_active:
++      result = NS_RGB(0xB2, 0xB2, 0xB2); break;
++    case eColorID__moz_mac_chrome_inactive:
++      result = NS_RGB(0xE1, 0xE1, 0xE1); break;
++    case eColorID__moz_mac_focusring:
++      result = NS_RGB(0x60, 0x9D, 0xD7); break;
++    case eColorID__moz_mac_menuselect:
++      result = NS_RGB(0x38, 0x75, 0xD7); break;
++    case eColorID__moz_mac_menushadow:
++      result = NS_RGB(0xA3, 0xA3, 0xA3); break;
++    case eColorID__moz_mac_menutextdisable:
++      result = NS_RGB(0x88, 0x88, 0x88); break;
++    case eColorID__moz_mac_menutextselect:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_mac_disabledtoolbartext:
++      result = NS_RGB(0x3F, 0x3F, 0x3F); break;
++    case eColorID__moz_mac_alternateprimaryhighlight:
++      result = NS_RGB(0x38, 0x75, 0xD7); break;
++    case eColorID__moz_mac_secondaryhighlight:
++      result = NS_RGB(0xD4, 0xD4, 0xD4); break;
++    case eColorID__moz_win_mediatext:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_win_communicationstext:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_nativehyperlinktext:
++      result = NS_RGB(0x00, 0x66, 0xCC); break;
++    case eColorID__moz_comboboxtext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_combobox:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    default:
++      break;
++  }
++
++  return result;
++}
++
+ //
+ // All these routines will return NS_OK if they have a value,
+ // in which case the nsLookAndFeel should use that value;
+@@ -483,7 +632,8 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
+ // platform-specific nsLookAndFeel should use its own values instead.
+ //
+ nsresult
+-nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
++nsXPLookAndFeel::GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
++                              nscolor &aResult)
+ {
+   if (!sInitialized)
+     Init();
+@@ -569,7 +719,10 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
+   }
+ #endif // DEBUG_SYSTEM_COLOR_USE
+ 
+-  if (IS_COLOR_CACHED(aID)) {
++  if (aUseStandinsForNativeColors && ColorIsNotCSSAccessible(aID))
++    aUseStandinsForNativeColors = false;
++
++  if (!aUseStandinsForNativeColors && IS_COLOR_CACHED(aID)) {
+     aResult = sCachedColors[aID];
+     return NS_OK;
+   }
+@@ -603,6 +756,12 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
+     return NS_OK;
+   }
+ 
++  if (sUseNativeColors && aUseStandinsForNativeColors)
++  {
++    aResult = GetStandinForNativeColor(aID);
++    return NS_OK;
++  }
++
+   if (sUseNativeColors && NS_SUCCEEDED(NativeGetColor(aID, aResult))) {
+     if ((gfxPlatform::GetCMSMode() == eCMSMode_All) &&
+          !IsSpecialColor(aID, aResult)) {
+@@ -693,7 +852,15 @@ namespace mozilla {
+ nsresult
+ LookAndFeel::GetColor(ColorID aID, nscolor* aResult)
+ {
+-  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, *aResult);
++  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, false, *aResult);
++}
++
++nsresult
++LookAndFeel::GetColor(ColorID aID, bool aUseStandinsForNativeColors,
++                      nscolor* aResult)
++{
++  return nsLookAndFeel::GetInstance()->GetColorImpl(aID,
++                                       aUseStandinsForNativeColors, *aResult);
+ }
+ 
+ // static
+diff --git a/widget/xpwidgets/nsXPLookAndFeel.h b/widget/xpwidgets/nsXPLookAndFeel.h
+index 69627d2..2729803 100644
+--- a/widget/xpwidgets/nsXPLookAndFeel.h
++++ b/widget/xpwidgets/nsXPLookAndFeel.h
+@@ -52,7 +52,8 @@ public:
+   // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
+   // platform-specific nsLookAndFeel should use its own values instead.
+   //
+-  nsresult GetColorImpl(ColorID aID, nscolor &aResult);
++  nsresult GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
++                        nscolor &aResult);
+   virtual nsresult GetIntImpl(IntID aID, int32_t &aResult);
+   virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
+ 
+@@ -89,6 +90,8 @@ protected:
+   void InitColorFromPref(int32_t aIndex);
+   virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult) = 0;
+   bool IsSpecialColor(ColorID aID, nscolor &aColor);
++  bool ColorIsNotCSSAccessible(ColorID aID);
++  nscolor GetStandinForNativeColor(ColorID aID);
+ 
+   static int OnPrefChanged(const char* aPref, void* aClosure);
+ 
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0024-Do-not-expose-system-colors-to-CSS-or-canvas.patch b/src/current-patches/firefox/0024-Do-not-expose-system-colors-to-CSS-or-canvas.patch
deleted file mode 100644
index 629a759..0000000
--- a/src/current-patches/firefox/0024-Do-not-expose-system-colors-to-CSS-or-canvas.patch
+++ /dev/null
@@ -1,537 +0,0 @@
-From 38a469e05779315cb2990be60c13fb167812e54d Mon Sep 17 00:00:00 2001
-From: Kathleen Brade <brade at pearlcrescent.com>
-Date: Thu, 4 Oct 2012 14:53:13 -0400
-Subject: [PATCH 24/24] Do not expose system colors to CSS or canvas.
-
----
- content/canvas/src/nsCanvasRenderingContext2D.cpp  |   36 +++-
- .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |   51 ++++--
- layout/style/nsCSSParser.cpp                       |   19 ++-
- layout/style/nsRuleNode.cpp                        |    4 +-
- widget/public/LookAndFeel.h                        |    9 +
- widget/src/xpwidgets/nsXPLookAndFeel.cpp           |  173 +++++++++++++++++++-
- widget/src/xpwidgets/nsXPLookAndFeel.h             |    5 +-
- 7 files changed, 269 insertions(+), 28 deletions(-)
-
-diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
-index 0cf97ce..6c47821 100644
---- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
-+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
-@@ -186,8 +186,9 @@ class nsCanvasGradient : public nsIDOMCanvasGradient
- public:
-     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
- 
--    nsCanvasGradient(gfxPattern* pat)
--        : mPattern(pat)
-+    nsCanvasGradient(mozilla::css::Loader* aLoader, gfxPattern* pat)
-+        : mCSSLoader(aLoader)
-+        , mPattern(pat)
-     {
-     }
- 
-@@ -203,7 +204,7 @@ public:
-             return NS_ERROR_DOM_INDEX_SIZE_ERR;
- 
-         nscolor color;
--        nsCSSParser parser;
-+        nsCSSParser parser(mCSSLoader);
-         nsresult rv = parser.ParseColorString(nsString(colorstr),
-                                               nsnull, 0, &color);
-         if (NS_FAILED(rv))
-@@ -217,6 +218,7 @@ public:
-     NS_DECL_ISUPPORTS
- 
- protected:
-+    mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
-     nsRefPtr<gfxPattern> mPattern;
- };
- 
-@@ -875,7 +877,9 @@ nsCanvasRenderingContext2D::SetStyleFromStringOrInterface(const nsAString& aStr,
-                                 HTMLCanvasElement()->OwnerDoc() : nsnull;
- 
-         // Pass the CSS Loader object to the parser, to allow parser error
--        // reports to include the outer window ID.
-+        // reports to include the outer window ID.  The parser also uses it to
-+        // detect whether the caller is chrome in order to avoid exposing
-+        // system colors.
-         nsCSSParser parser(document ? document->CSSLoader() : nsnull);
-         rv = parser.ParseColorString(aStr, nsnull, 0, &color);
-         if (NS_FAILED(rv)) {
-@@ -1778,7 +1782,14 @@ nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, f
-     if (!gradpat)
-         return NS_ERROR_OUT_OF_MEMORY;
- 
--    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
-+    // Pass the CSS Loader object to the parser, to allow parser error reports
-+    // to include the outer window ID.  The parser also uses it to detect
-+    // whether the caller is chrome in order to avoid exposing system colors.
-+    nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
-+                                      : nsnull;
-+    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
-+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
-+                                                               gradpat);
-     if (!grad)
-         return NS_ERROR_OUT_OF_MEMORY;
- 
-@@ -1800,7 +1811,14 @@ nsCanvasRenderingContext2D::CreateRadialGradient(float x0, float y0, float r0, f
-     if (!gradpat)
-         return NS_ERROR_OUT_OF_MEMORY;
- 
--    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
-+    // Pass the CSS Loader object to the parser, to allow parser error reports
-+    // to include the outer window ID.  The parser also uses it to detect
-+    // whether the caller is chrome in order to avoid exposing system colors.
-+    nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
-+                                      : nsnull;
-+    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
-+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
-+                                                               gradpat);
-     if (!grad)
-         return NS_ERROR_OUT_OF_MEMORY;
- 
-@@ -1922,7 +1940,8 @@ nsCanvasRenderingContext2D::SetShadowColor(const nsAString& colorstr)
-                             HTMLCanvasElement()->OwnerDoc() : nsnull;
- 
-     // Pass the CSS Loader object to the parser, to allow parser error reports
--    // to include the outer window ID.
-+    // to include the outer window ID.  The parser also uses it to detect
-+    // whether the caller is chrome in order to avoid exposing system colors.
-     nsCSSParser parser(document ? document->CSSLoader() : nsnull);
-     nscolor color;
-     nsresult rv = parser.ParseColorString(colorstr, nsnull, 0, &color);
-@@ -3694,7 +3713,8 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
-                               HTMLCanvasElement()->OwnerDoc() : nsnull;
- 
-     // Pass the CSS Loader object to the parser, to allow parser error reports
--    // to include the outer window ID.
-+    // to include the outer window ID.  The parser also uses it to detect
-+    // whether the caller is chrome in order to avoid exposing system colors.
-     nsCSSParser parser(elementDoc ? elementDoc->CSSLoader() : nsnull);
-     nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor),
-                                           nsnull, 0, &bgColor);
-diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
-index e8dfb1e..cb5a5f5 100644
---- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
-+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
-@@ -201,7 +201,10 @@ public:
-     }
- 
-     nscolor color;
--    nsCSSParser parser;
-+    // Pass the CSS Loader object to the parser, to allow parser error reports
-+    // to include the outer window ID.  The parser also uses it to detect
-+    // whether the caller is chrome in order to avoid exposing system colors.
-+    nsCSSParser parser(mCSSLoader);;
-     nsresult rv = parser.ParseColorString(nsString(colorstr),
-                                           nsnull, 0, &color);
-     if (NS_FAILED(rv)) {
-@@ -221,20 +224,24 @@ public:
-   }
- 
- protected:
--  nsCanvasGradientAzure(Type aType) : mType(aType)
-+  nsCanvasGradientAzure(mozilla::css::Loader* aLoader, Type aType)
-+      : mCSSLoader(aLoader)
-+      , mType(aType)
-   {}
- 
-   nsTArray<GradientStop> mRawStops;
-   RefPtr<GradientStops> mStops;
-+  mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
-   Type mType;
- };
- 
- class nsCanvasRadialGradientAzure : public nsCanvasGradientAzure
- {
- public:
--  nsCanvasRadialGradientAzure(const Point &aBeginOrigin, Float aBeginRadius,
-+  nsCanvasRadialGradientAzure(mozilla::css::Loader* aLoader,
-+                              const Point &aBeginOrigin, Float aBeginRadius,
-                               const Point &aEndOrigin, Float aEndRadius)
--    : nsCanvasGradientAzure(RADIAL)
-+    : nsCanvasGradientAzure(aLoader, RADIAL)
-     , mCenter1(aBeginOrigin)
-     , mCenter2(aEndOrigin)
-     , mRadius1(aBeginRadius)
-@@ -251,8 +258,9 @@ public:
- class nsCanvasLinearGradientAzure : public nsCanvasGradientAzure
- {
- public:
--  nsCanvasLinearGradientAzure(const Point &aBegin, const Point &aEnd)
--    : nsCanvasGradientAzure(LINEAR)
-+  nsCanvasLinearGradientAzure(mozilla::css::Loader* aLoader,
-+                              const Point &aBegin, const Point &aEnd)
-+    : nsCanvasGradientAzure(aLoader, LINEAR)
-     , mBegin(aBegin)
-     , mEnd(aEnd)
-   {
-@@ -1066,8 +1074,9 @@ nsCanvasRenderingContext2DAzure::SetStyleFromStringOrInterface(const nsAString&
-     nsIDocument* document = mCanvasElement ?
-                             HTMLCanvasElement()->OwnerDoc() : nsnull;
- 
--    // Pass the CSS Loader object to the parser, to allow parser error
--    // reports to include the outer window ID.
-+    // Pass the CSS Loader object to the parser, to allow parser error reports
-+    // to include the outer window ID.  The parser also uses it to detect
-+    // whether the caller is chrome in order to avoid exposing system colors.
-     nsCSSParser parser(document ? document->CSSLoader() : nsnull);
-     rv = parser.ParseColorString(aStr, nsnull, 0, &color);
-     if (NS_FAILED(rv)) {
-@@ -1855,8 +1864,14 @@ nsCanvasRenderingContext2DAzure::CreateLinearGradient(float x0, float y0, float
-     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-   }
- 
--  nsRefPtr<nsIDOMCanvasGradient> grad =
--    new nsCanvasLinearGradientAzure(Point(x0, y0), Point(x1, y1));
-+  // Pass the CSS Loader object to the parser, to allow parser error reports
-+  // to include the outer window ID.  The parser also uses it to detect
-+  // whether the caller is chrome in order to avoid exposing system colors.
-+  nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
-+                                    : nsnull;
-+  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
-+  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasLinearGradientAzure(
-+                                     cssLoader, Point(x0, y0), Point(x1, y1));
- 
-   *_retval = grad.forget().get();
-   return NS_OK;
-@@ -1875,8 +1890,14 @@ nsCanvasRenderingContext2DAzure::CreateRadialGradient(float x0, float y0, float
-     return NS_ERROR_DOM_INDEX_SIZE_ERR;
-   }
- 
--  nsRefPtr<nsIDOMCanvasGradient> grad =
--    new nsCanvasRadialGradientAzure(Point(x0, y0), r0, Point(x1, y1), r1);
-+  // Pass the CSS Loader object to the parser, to allow parser error reports
-+  // to include the outer window ID.  The parser also uses it to detect
-+  // whether the caller is chrome in order to avoid exposing system colors.
-+  nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
-+                                    : nsnull;
-+  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
-+  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasRadialGradientAzure(
-+                            cssLoader, Point(x0, y0), r0, Point(x1, y1), r1);
- 
-   *_retval = grad.forget().get();
-   return NS_OK;
-@@ -2024,7 +2045,8 @@ nsCanvasRenderingContext2DAzure::SetShadowColor(const nsAString& colorstr)
-                           HTMLCanvasElement()->OwnerDoc() : nsnull;
- 
-   // Pass the CSS Loader object to the parser, to allow parser error reports
--  // to include the outer window ID.
-+  // to include the outer window ID.  The parser also uses it to detect
-+  // whether the caller is chrome in order to avoid exposing system colors.
-   nsCSSParser parser(document ? document->CSSLoader() : nsnull);
-   nscolor color;
-   nsresult rv = parser.ParseColorString(colorstr, nsnull, 0, &color);
-@@ -3847,7 +3869,8 @@ nsCanvasRenderingContext2DAzure::DrawWindow(nsIDOMWindow* aWindow, float aX, flo
-                             HTMLCanvasElement()->OwnerDoc() : nsnull;
- 
-   // Pass the CSS Loader object to the parser, to allow parser error reports
--  // to include the outer window ID.
-+  // to include the outer window ID.  The parser also uses it to detect
-+  // whether the caller is chrome in order to avoid exposing system colors.
-   nsCSSParser parser(elementDoc ? elementDoc->CSSLoader() : nsnull);
-   nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor),
-                                         nsnull, 0, &bgColor);
-diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
-index ae1a474..30e179c 100644
---- a/layout/style/nsCSSParser.cpp
-+++ b/layout/style/nsCSSParser.cpp
-@@ -1216,8 +1216,25 @@ CSSParserImpl::ParseColorString(const nsSubstring& aBuffer,
-       // Should remove this limitation at some point.
-       return NS_ERROR_FAILURE;
-     }
-+
-+    // We do not want to expose system/native colors to content.  All callers
-+    // who are working with content should ensure that they set the CSS
-+    // loader (mChildLoader) so we can check here if the content is chrome.
-+    bool isChrome = true;
-+    if (mChildLoader) {
-+      nsIDocument *doc = mChildLoader->GetDocument();
-+      if (doc) {
-+        nsIPresShell *presShell = doc->GetShell();
-+        if (presShell) {
-+          nsPresContext* presCtxt = presShell->GetPresContext();
-+          if (presCtxt)
-+            isChrome = presCtxt->IsChrome();
-+        }
-+      }
-+    }
-     nscolor rgba;
--    nsresult rv = LookAndFeel::GetColor(LookAndFeel::ColorID(val), &rgba);
-+    nsresult rv = LookAndFeel::GetColor(LookAndFeel::ColorID(val), !isChrome,
-+                                        &rgba);
-     if (NS_FAILED(rv)) {
-       return rv;
-     }
-diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
-index 827585a..d19524e 100644
---- a/layout/style/nsRuleNode.cpp
-+++ b/layout/style/nsRuleNode.cpp
-@@ -768,7 +768,9 @@ static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
-     PRInt32 intValue = aValue.GetIntValue();
-     if (0 <= intValue) {
-       LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
--      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) {
-+      bool useStandinsForNativeColors = !aPresContext->IsChrome();
-+      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
-+                                    useStandinsForNativeColors, &aResult))) {
-         result = true;
-       }
-     }
-diff --git a/widget/public/LookAndFeel.h b/widget/public/LookAndFeel.h
-index aae3b28..bb7be3c 100644
---- a/widget/public/LookAndFeel.h
-+++ b/widget/public/LookAndFeel.h
-@@ -445,6 +445,15 @@ public:
-   static nsresult GetColor(ColorID aID, nscolor* aResult);
- 
-   /**
-+   * This variant of GetColor() take an extra Boolean parameter that allows
-+   * the caller to ask that hard-coded color values be substituted for
-+   * native colors (used when it is desireable to hide system colors to
-+   * avoid system fingerprinting).
-+   */
-+  static nsresult GetColor(ColorID aID, bool aUseStandinsForNativeColors,
-+                           nscolor* aResult);
-+
-+  /**
-    * GetInt() and GetFloat() return a int or float value for aID.  The result
-    * might be distance, time, some flags or a int value which has particular
-    * meaning.  See each document at definition of each ID for the detail.
-diff --git a/widget/src/xpwidgets/nsXPLookAndFeel.cpp b/widget/src/xpwidgets/nsXPLookAndFeel.cpp
-index 8053432..96937ac 100644
---- a/widget/src/xpwidgets/nsXPLookAndFeel.cpp
-+++ b/widget/src/xpwidgets/nsXPLookAndFeel.cpp
-@@ -502,6 +502,155 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
-   return false;
- }
- 
-+bool
-+nsXPLookAndFeel::ColorIsNotCSSAccessible(ColorID aID)
-+{
-+  bool result = false;
-+
-+  switch (aID) {
-+    case eColorID_WindowBackground:
-+    case eColorID_WindowForeground:
-+    case eColorID_WidgetBackground:
-+    case eColorID_WidgetForeground:
-+    case eColorID_WidgetSelectBackground:
-+    case eColorID_WidgetSelectForeground:
-+    case eColorID_Widget3DHighlight:
-+    case eColorID_Widget3DShadow:
-+    case eColorID_TextBackground:
-+    case eColorID_TextForeground:
-+    case eColorID_TextSelectBackground:
-+    case eColorID_TextSelectForeground:
-+    case eColorID_TextSelectBackgroundDisabled:
-+    case eColorID_TextSelectBackgroundAttention:
-+    case eColorID_TextHighlightBackground:
-+    case eColorID_TextHighlightForeground:
-+    case eColorID_IMERawInputBackground:
-+    case eColorID_IMERawInputForeground:
-+    case eColorID_IMERawInputUnderline:
-+    case eColorID_IMESelectedRawTextBackground:
-+    case eColorID_IMESelectedRawTextForeground:
-+    case eColorID_IMESelectedRawTextUnderline:
-+    case eColorID_IMEConvertedTextBackground:
-+    case eColorID_IMEConvertedTextForeground:
-+    case eColorID_IMEConvertedTextUnderline:
-+    case eColorID_IMESelectedConvertedTextBackground:
-+    case eColorID_IMESelectedConvertedTextForeground:
-+    case eColorID_IMESelectedConvertedTextUnderline:
-+    case eColorID_SpellCheckerUnderline:
-+      result = true;
-+      break;
-+    default:
-+      break;
-+  }
-+
-+  return result;
-+}
-+
-+nscolor
-+nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID)
-+{
-+  nscolor result = NS_RGB(0xFF, 0xFF, 0xFF);
-+
-+  // The stand-in colors are taken from the Windows 7 Aero theme
-+  // except Mac-specific colors which are taken from Mac OS 10.7.
-+  switch (aID) {
-+    // CSS 2 colors:
-+    case eColorID_activeborder:      result = NS_RGB(0xB4, 0xB4, 0xB4); break;
-+    case eColorID_activecaption:     result = NS_RGB(0x99, 0xB4, 0xD1); break;
-+    case eColorID_appworkspace:      result = NS_RGB(0xAB, 0xAB, 0xAB); break;
-+    case eColorID_background:        result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID_buttonface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
-+    case eColorID_buttonhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID_buttonshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
-+    case eColorID_buttontext:        result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID_captiontext:       result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID_graytext:          result = NS_RGB(0x6D, 0x6D, 0x6D); break;
-+    case eColorID_highlight:         result = NS_RGB(0x33, 0x99, 0xFF); break;
-+    case eColorID_highlighttext:     result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID_inactiveborder:    result = NS_RGB(0xF4, 0xF7, 0xFC); break;
-+    case eColorID_inactivecaption:   result = NS_RGB(0xBF, 0xCD, 0xDB); break;
-+    case eColorID_inactivecaptiontext:
-+      result = NS_RGB(0x43, 0x4E, 0x54); break;
-+    case eColorID_infobackground:    result = NS_RGB(0xFF, 0xFF, 0xE1); break;
-+    case eColorID_infotext:          result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID_menu:              result = NS_RGB(0xF0, 0xF0, 0xF0); break;
-+    case eColorID_menutext:          result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID_scrollbar:         result = NS_RGB(0xC8, 0xC8, 0xC8); break;
-+    case eColorID_threeddarkshadow:  result = NS_RGB(0x69, 0x69, 0x69); break;
-+    case eColorID_threedface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
-+    case eColorID_threedhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID_threedlightshadow: result = NS_RGB(0xE3, 0xE3, 0xE3); break;
-+    case eColorID_threedshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
-+    case eColorID_window:            result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID_windowframe:       result = NS_RGB(0x64, 0x64, 0x64); break;
-+    case eColorID_windowtext:        result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_buttondefault:
-+      result = NS_RGB(0x69, 0x69, 0x69); break;
-+    case eColorID__moz_field:        result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_fieldtext:    result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_dialog:       result = NS_RGB(0xF0, 0xF0, 0xF0); break;
-+    case eColorID__moz_dialogtext:   result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_dragtargetzone:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_cellhighlight:
-+      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
-+    case eColorID__moz_cellhighlighttext:
-+      result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_html_cellhighlight:
-+      result = NS_RGB(0x33, 0x99, 0xFF); break;
-+    case eColorID__moz_html_cellhighlighttext:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_buttonhoverface:
-+      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
-+    case eColorID__moz_buttonhovertext:
-+      result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_menuhover:
-+      result = NS_RGB(0x33, 0x99, 0xFF); break;
-+    case eColorID__moz_menuhovertext:
-+      result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_menubartext:
-+      result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_menubarhovertext:
-+      result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_oddtreerow:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_mac_chrome_active:
-+      result = NS_RGB(0xB2, 0xB2, 0xB2); break;
-+    case eColorID__moz_mac_chrome_inactive:
-+      result = NS_RGB(0xE1, 0xE1, 0xE1); break;
-+    case eColorID__moz_mac_focusring:
-+      result = NS_RGB(0x60, 0x9D, 0xD7); break;
-+    case eColorID__moz_mac_menuselect:
-+      result = NS_RGB(0x38, 0x75, 0xD7); break;
-+    case eColorID__moz_mac_menushadow:
-+      result = NS_RGB(0xA3, 0xA3, 0xA3); break;
-+    case eColorID__moz_mac_menutextdisable:
-+      result = NS_RGB(0x88, 0x88, 0x88); break;
-+    case eColorID__moz_mac_menutextselect:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_mac_disabledtoolbartext:
-+      result = NS_RGB(0x3F, 0x3F, 0x3F); break;
-+    case eColorID__moz_mac_alternateprimaryhighlight:
-+      result = NS_RGB(0x38, 0x75, 0xD7); break;
-+    case eColorID__moz_mac_secondaryhighlight:
-+      result = NS_RGB(0xD4, 0xD4, 0xD4); break;
-+    case eColorID__moz_win_mediatext:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_win_communicationstext:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    case eColorID__moz_nativehyperlinktext:
-+      result = NS_RGB(0x00, 0x66, 0xCC); break;
-+    case eColorID__moz_comboboxtext:
-+      result = NS_RGB(0x00, 0x00, 0x00); break;
-+    case eColorID__moz_combobox:
-+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
-+    default:
-+      break;
-+  }
-+
-+  return result;
-+}
-+
- //
- // All these routines will return NS_OK if they have a value,
- // in which case the nsLookAndFeel should use that value;
-@@ -509,7 +658,8 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
- // platform-specific nsLookAndFeel should use its own values instead.
- //
- nsresult
--nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
-+nsXPLookAndFeel::GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
-+                              nscolor &aResult)
- {
-   if (!sInitialized)
-     Init();
-@@ -595,7 +745,10 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
-   }
- #endif // DEBUG_SYSTEM_COLOR_USE
- 
--  if (IS_COLOR_CACHED(aID)) {
-+  if (aUseStandinsForNativeColors && ColorIsNotCSSAccessible(aID))
-+    aUseStandinsForNativeColors = false;
-+
-+  if (!aUseStandinsForNativeColors && IS_COLOR_CACHED(aID)) {
-     aResult = sCachedColors[aID];
-     return NS_OK;
-   }
-@@ -629,6 +782,12 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
-     return NS_OK;
-   }
- 
-+  if (sUseNativeColors && aUseStandinsForNativeColors)
-+  {
-+    aResult = GetStandinForNativeColor(aID);
-+    return NS_OK;
-+  }
-+
-   if (sUseNativeColors && NS_SUCCEEDED(NativeGetColor(aID, aResult))) {
-     if ((gfxPlatform::GetCMSMode() == eCMSMode_All) &&
-          !IsSpecialColor(aID, aResult)) {
-@@ -719,7 +878,15 @@ namespace mozilla {
- nsresult
- LookAndFeel::GetColor(ColorID aID, nscolor* aResult)
- {
--  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, *aResult);
-+  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, false, *aResult);
-+}
-+
-+nsresult
-+LookAndFeel::GetColor(ColorID aID, bool aUseStandinsForNativeColors,
-+                      nscolor* aResult)
-+{
-+  return nsLookAndFeel::GetInstance()->GetColorImpl(aID,
-+                                       aUseStandinsForNativeColors, *aResult);
- }
- 
- // static
-diff --git a/widget/src/xpwidgets/nsXPLookAndFeel.h b/widget/src/xpwidgets/nsXPLookAndFeel.h
-index ce06575..c0ecc32 100644
---- a/widget/src/xpwidgets/nsXPLookAndFeel.h
-+++ b/widget/src/xpwidgets/nsXPLookAndFeel.h
-@@ -84,7 +84,8 @@ public:
-   // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
-   // platform-specific nsLookAndFeel should use its own values instead.
-   //
--  nsresult GetColorImpl(ColorID aID, nscolor &aResult);
-+  nsresult GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
-+                        nscolor &aResult);
-   virtual nsresult GetIntImpl(IntID aID, PRInt32 &aResult);
-   virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
- 
-@@ -111,6 +112,8 @@ protected:
-   void InitColorFromPref(PRInt32 aIndex);
-   virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult) = 0;
-   bool IsSpecialColor(ColorID aID, nscolor &aColor);
-+  bool ColorIsNotCSSAccessible(ColorID aID);
-+  nscolor GetStandinForNativeColor(ColorID aID);
- 
-   static int OnPrefChanged(const char* aPref, void* aClosure);
- 
--- 
-1.7.5.4
-
diff --git a/src/current-patches/firefox/0024-Isolate-the-Image-Cache-per-url-bar-domain.patch b/src/current-patches/firefox/0024-Isolate-the-Image-Cache-per-url-bar-domain.patch
new file mode 100644
index 0000000..0f1a702
--- /dev/null
+++ b/src/current-patches/firefox/0024-Isolate-the-Image-Cache-per-url-bar-domain.patch
@@ -0,0 +1,912 @@
+From 56d3f40086757ecefe1efbeca00b285a13bde5d4 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Thu, 6 Dec 2012 14:19:34 -0800
+Subject: [PATCH 24/26] Isolate the Image Cache per url bar domain.
+
+The image cache maintains its own table outside of the main cache, and does
+not obey cacheKeys by default.
+---
+ content/base/src/nsContentUtils.cpp                |   13 +-
+ embedding/browser/webBrowser/nsContextMenuInfo.cpp |   27 ++-
+ extensions/cookie/nsCookiePermission.cpp           |    3 +
+ image/public/imgILoader.idl                        |    4 +-
+ image/src/imgLoader.cpp                            |  256 +++++++++++++-------
+ image/src/imgLoader.h                              |   20 +-
+ image/src/imgRequest.cpp                           |   11 +-
+ image/src/imgRequest.h                             |    3 +
+ layout/generic/nsImageFrame.cpp                    |   14 +-
+ netwerk/cookie/nsICookiePermission.idl             |    1 +
+ toolkit/system/gnome/nsAlertsIconListener.cpp      |    3 +-
+ widget/cocoa/nsMenuItemIconX.mm                    |    9 +-
+ 12 files changed, 246 insertions(+), 118 deletions(-)
+
+diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp
+index fe3c8a0..43f8f69 100644
+--- a/content/base/src/nsContentUtils.cpp
++++ b/content/base/src/nsContentUtils.cpp
+@@ -121,6 +121,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
+ #include "nsIWebNavigation.h"
+ #include "nsTextFragment.h"
+ #include "mozilla/Selection.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #ifdef IBMBIDI
+ #include "nsIBidiKeyboard.h"
+@@ -2743,8 +2744,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
+   nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
+   NS_ASSERTION(loadGroup, "Could not get loadgroup; onload may fire too early");
+ 
+-  nsIURI *documentURI = aLoadingDocument->GetDocumentURI();
+-
+   // check for a Content Security Policy to pass down to the channel that
+   // will get created to load the image
+   nsCOMPtr<nsIChannelPolicy> channelPolicy;
+@@ -2761,11 +2760,15 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
+     
+   // Make the URI immutable so people won't change it under us
+   NS_TryToSetImmutable(aURI);
++ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++                               = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  thirdPartySvc->GetFirstPartyURI(nullptr, aLoadingDocument,
++                                  getter_AddRefs(firstPartyURI));
+ 
+-  // XXXbz using "documentURI" for the initialDocumentURI is not quite
+-  // right, but the best we can do here...
+   return imgLoader->LoadImage(aURI,                 /* uri to load */
+-                              documentURI,          /* initialDocumentURI */
++                              firstPartyURI,        /* firstPartyURI */
+                               aReferrer,            /* referrer */
+                               aLoadingPrincipal,    /* loading principal */
+                               loadGroup,            /* loadgroup */
+diff --git a/embedding/browser/webBrowser/nsContextMenuInfo.cpp b/embedding/browser/webBrowser/nsContextMenuInfo.cpp
+index 0a99427..02cd634 100644
+--- a/embedding/browser/webBrowser/nsContextMenuInfo.cpp
++++ b/embedding/browser/webBrowser/nsContextMenuInfo.cpp
+@@ -26,6 +26,7 @@
+ #include "nsIChannelPolicy.h"
+ #include "nsIContentSecurityPolicy.h"
+ #include "nsIContentPolicy.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ //*****************************************************************************
+ // class nsContextMenuInfo
+@@ -269,15 +270,15 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIR
+   nsCOMPtr<nsIPrincipal> principal;
+   nsCOMPtr<nsIChannelPolicy> channelPolicy;
+   nsCOMPtr<nsIContentSecurityPolicy> csp;
+-  if (doc) {
+-    principal = doc->NodePrincipal();
+-    nsresult rv = principal->GetCsp(getter_AddRefs(csp));
+-    NS_ENSURE_SUCCESS(rv, rv);
+-    if (csp) {
+-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
+-      channelPolicy->SetContentSecurityPolicy(csp);
+-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
+-    }
++  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
++
++  principal = doc->NodePrincipal();
++  nsresult rv = principal->GetCsp(getter_AddRefs(csp));
++  NS_ENSURE_SUCCESS(rv, rv);
++  if (csp) {
++    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
++    channelPolicy->SetContentSecurityPolicy(csp);
++    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
+   }
+   
+   while (true) {
+@@ -305,7 +306,13 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIR
+                                     "@mozilla.org/image/loader;1"));
+           NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
+ 
+-          return il->LoadImage(bgUri, nullptr, nullptr, principal, nullptr,
++          nsCOMPtr<nsIURI> firstPartyURI;
++          nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++              = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++          thirdPartySvc->GetFirstPartyURI(nullptr, doc,
++                                          getter_AddRefs(firstPartyURI));
++
++          return il->LoadImage(bgUri, firstPartyURI, nullptr, principal, nullptr,
+                                nullptr, nullptr, nsIRequest::LOAD_NORMAL, nullptr,
+                                nullptr, channelPolicy, aRequest);
+         }
+diff --git a/extensions/cookie/nsCookiePermission.cpp b/extensions/cookie/nsCookiePermission.cpp
+index befa81a..e0b6e12 100644
+--- a/extensions/cookie/nsCookiePermission.cpp
++++ b/extensions/cookie/nsCookiePermission.cpp
+@@ -407,6 +407,9 @@ nsCookiePermission::GetOriginatingURI(nsIChannel  *aChannel,
+ 
+       return NS_OK;
+     }
++
++    // TODO: Why don't we just use this here:
++    // httpChannelInternal->GetDocumentURI(aURI);
+   }
+ 
+   // find the associated window and its top window
+diff --git a/image/public/imgILoader.idl b/image/public/imgILoader.idl
+index da26463..ecff309 100644
+--- a/image/public/imgILoader.idl
++++ b/image/public/imgILoader.idl
+@@ -38,7 +38,7 @@ interface imgILoader : nsISupports
+   /**
+    * Start the load and decode of an image.
+    * @param aURI the URI to load
+-   * @param aInitialDocumentURI the URI that 'initiated' the load -- used for 3rd party cookie blocking
++   * @param aFirstPartyURI the urlbar URI that 'initiated' the load -- used for 3rd party blocking
+    * @param aReferrerURI the 'referring' URI
+    * @param aLoadingPrincipal the principal of the loading document
+    * @param aLoadGroup Loadgroup to put the image load into
+@@ -57,7 +57,7 @@ interface imgILoader : nsISupports
+    * goes away.
+    */
+   imgIRequest loadImage(in nsIURI aURI,
+-                        in nsIURI aInitialDocumentURL,
++                        in nsIURI aFirstPartyURI,
+                         in nsIURI aReferrerURI,
+                         in nsIPrincipal aLoadingPrincipal,
+                         in nsILoadGroup aLoadGroup,
+diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
+index ea51e8d..88e367c 100644
+--- a/image/src/imgLoader.cpp
++++ b/image/src/imgLoader.cpp
+@@ -39,6 +39,7 @@
+ #include "nsCRT.h"
+ #include "nsIDocument.h"
+ #include "nsPIDOMWindow.h"
++#include "nsIConsoleService.h"
+ 
+ #include "netCore.h"
+ 
+@@ -58,6 +59,7 @@
+ #include "nsIHttpChannelInternal.h"  
+ #include "nsIContentSecurityPolicy.h"
+ #include "nsIChannelPolicy.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #include "nsContentUtils.h"
+ 
+@@ -432,7 +434,7 @@ static nsresult NewImageChannel(nsIChannel **aResult,
+                                 // aLoadingPrincipal and false otherwise.
+                                 bool *aForcePrincipalCheckForCacheEntry,
+                                 nsIURI *aURI,
+-                                nsIURI *aInitialDocumentURI,
++                                nsIURI *aFirstPartyURI,
+                                 nsIURI *aReferringURI,
+                                 nsILoadGroup *aLoadGroup,
+                                 const nsCString& aAcceptHeader,
+@@ -484,7 +486,7 @@ static nsresult NewImageChannel(nsIChannel **aResult,
+ 
+     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal = do_QueryInterface(newHttpChannel);
+     NS_ENSURE_TRUE(httpChannelInternal, NS_ERROR_UNEXPECTED);
+-    httpChannelInternal->SetDocumentURI(aInitialDocumentURI);
++    httpChannelInternal->SetDocumentURI(aFirstPartyURI);
+     newHttpChannel->SetReferrer(aReferringURI);
+   }
+ 
+@@ -925,34 +927,62 @@ NS_IMETHODIMP imgLoader::ClearCache(bool chrome)
+ /* void removeEntry(in nsIURI uri); */
+ NS_IMETHODIMP imgLoader::RemoveEntry(nsIURI *uri)
+ {
+-  if (RemoveFromCache(uri))
++  if (RemoveMatchingUrlsFromCache(uri))
+     return NS_OK;
+ 
+   return NS_ERROR_NOT_AVAILABLE;
+ }
+ 
++static PLDHashOperator EnumAllEntries(const nsACString&, 
++                                        nsRefPtr<imgCacheEntry> &aData,
++                                        void *data)
++{
++  nsTArray<nsRefPtr<imgCacheEntry> > *entries = 
++    reinterpret_cast<nsTArray<nsRefPtr<imgCacheEntry> > *>(data);
++
++  entries->AppendElement(aData);
++
++  return PL_DHASH_NEXT;
++}
++
+ /* imgIRequest findEntry(in nsIURI uri); */
+ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retval)
+ {
+   nsRefPtr<imgCacheEntry> entry;
+-  nsCAutoString spec;
+   imgCacheTable &cache = GetCache(uri);
+-
+-  uri->GetSpec(spec);
+   *_retval = nullptr;
+ 
+-  if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+-    if (gCacheTracker && entry->HasNoProxies())
+-      gCacheTracker->MarkUsed(entry);
++  // We must traverse the whole cache in O(N) looking for the first
++  // matching URI.
++  //
++  // TODO: For now, it's ok to pick at random here. The images should be
++  // identical unless there is a cache-tracking attack. And even if they
++  // are not identical due to attack, this code is only used for save
++  // dialogs at this point, so no differentiating info is leaked to
++  // content.
++  nsTArray<nsRefPtr<imgCacheEntry> > entries;
++  cache.Enumerate(EnumAllEntries, &entries);
+ 
+-    nsRefPtr<imgRequest> request = getter_AddRefs(entry->GetRequest());
++  for (uint32_t i = 0; i < entries.Length(); ++i) {
++    bool isEqual = false;
++
++    nsRefPtr<imgRequest> request = getter_AddRefs(entries[i]->GetRequest());
+     if (request) {
+-      *_retval = request->Properties();
+-      NS_ADDREF(*_retval);
++      request->mURI->Equals(uri, &isEqual);
++      if (isEqual) {
++        if (gCacheTracker && entries[i]->HasNoProxies())
++          gCacheTracker->MarkUsed(entries[i]);
++
++        *_retval = request->Properties();
++        NS_ADDREF(*_retval);
++      }
+     }
+   }
+ 
+-  return NS_OK;
++  if (*_retval)
++    return NS_OK;
++  
++  return NS_ERROR_NOT_AVAILABLE;
+ }
+ 
+ void imgLoader::Shutdown()
+@@ -980,20 +1010,18 @@ void imgLoader::MinimizeCaches()
+   EvictEntries(sChromeCacheQueue);
+ }
+ 
+-bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
++bool imgLoader::PutIntoCache(nsCAutoString key, 
++                             imgCacheEntry *entry)
+ {
+-  imgCacheTable &cache = GetCache(key);
+-
+-  nsCAutoString spec;
+-  key->GetSpec(spec);
+-
+-  LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::PutIntoCache", "uri", spec.get());
++  LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::PutIntoCache", "uri", key.get());
++  imgCacheTable &cache = GetCache(entry->mRequest->mURI);
++  imgCacheQueue &queue = GetCacheQueue(entry->mRequest->mURI);
+ 
+   // Check to see if this request already exists in the cache and is being
+   // loaded on a different thread. If so, don't allow this entry to be added to
+   // the cache.
+   nsRefPtr<imgCacheEntry> tmpCacheEntry;
+-  if (cache.Get(spec, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) {
++  if (cache.Get(key, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) {
+     PR_LOG(gImgLog, PR_LOG_DEBUG,
+            ("[this=%p] imgLoader::PutIntoCache -- Element already in the cache", nullptr));
+     nsRefPtr<imgRequest> tmpRequest = getter_AddRefs(tmpCacheEntry->GetRequest());
+@@ -1003,13 +1031,13 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
+     PR_LOG(gImgLog, PR_LOG_DEBUG,
+            ("[this=%p] imgLoader::PutIntoCache -- Replacing cached element", nullptr));
+ 
+-    RemoveFromCache(key);
++    RemoveKeyFromCache(cache, queue, key);
+   } else {
+     PR_LOG(gImgLog, PR_LOG_DEBUG,
+            ("[this=%p] imgLoader::PutIntoCache -- Element NOT already in the cache", nullptr));
+   }
+ 
+-  cache.Put(spec, entry);
++  cache.Put(key, entry);
+ 
+   // We can be called to resurrect an evicted entry.
+   if (entry->Evicted())
+@@ -1024,7 +1052,6 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
+       addrv = gCacheTracker->AddObject(entry);
+ 
+     if (NS_SUCCEEDED(addrv)) {
+-      imgCacheQueue &queue = GetCacheQueue(key);
+       queue.Push(entry);
+     }
+   }
+@@ -1035,11 +1062,11 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
+   return true;
+ }
+ 
+-bool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry)
++bool imgLoader::SetHasNoProxies(nsIURI *imgURI, imgCacheEntry *entry)
+ {
+ #if defined(PR_LOGGING)
+   nsCAutoString spec;
+-  key->GetSpec(spec);
++  imgURI->GetSpec(spec);
+ 
+   LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::SetHasNoProxies", "uri", spec.get());
+ #endif
+@@ -1047,7 +1074,7 @@ bool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry)
+   if (entry->Evicted())
+     return false;
+ 
+-  imgCacheQueue &queue = GetCacheQueue(key);
++  imgCacheQueue &queue = GetCacheQueue(imgURI);
+ 
+   nsresult addrv = NS_OK;
+ 
+@@ -1059,26 +1086,27 @@ bool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry)
+     entry->SetHasNoProxies(true);
+   }
+ 
+-  imgCacheTable &cache = GetCache(key);
++  imgCacheTable &cache = GetCache(imgURI);
+   CheckCacheLimits(cache, queue);
+ 
+   return true;
+ }
+ 
+-bool imgLoader::SetHasProxies(nsIURI *key)
++bool imgLoader::SetHasProxies(nsIURI *firstPartyURI, nsIURI *imgURI)
+ {
+   VerifyCacheSizes();
+ 
+-  imgCacheTable &cache = GetCache(key);
++  imgCacheTable &cache = GetCache(imgURI);
+ 
+   nsCAutoString spec;
+-  key->GetSpec(spec);
++  imgURI->GetSpec(spec);
+ 
+   LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::SetHasProxies", "uri", spec.get());
+ 
++  nsCAutoString key = GetCacheKey(firstPartyURI, imgURI);
+   nsRefPtr<imgCacheEntry> entry;
+-  if (cache.Get(spec, getter_AddRefs(entry)) && entry && entry->HasNoProxies()) {
+-    imgCacheQueue &queue = GetCacheQueue(key);
++  if (cache.Get(key, getter_AddRefs(entry)) && entry && entry->HasNoProxies()) {
++    imgCacheQueue &queue = GetCacheQueue(imgURI);
+     queue.Remove(entry);
+ 
+     if (gCacheTracker)
+@@ -1130,7 +1158,7 @@ void imgLoader::CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue)
+ 
+ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
+                                                 nsIURI *aURI,
+-                                                nsIURI *aInitialDocumentURI,
++                                                nsIURI *aFirstPartyURI,
+                                                 nsIURI *aReferrerURI,
+                                                 nsILoadGroup *aLoadGroup,
+                                                 imgIDecoderObserver *aObserver,
+@@ -1182,7 +1210,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
+     rv = NewImageChannel(getter_AddRefs(newChannel),
+                          &forcePrincipalCheck,
+                          aURI,
+-                         aInitialDocumentURI,
++                         aFirstPartyURI,
+                          aReferrerURI,
+                          aLoadGroup,
+                          mAcceptHeader,
+@@ -1251,7 +1279,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
+ 
+ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
+                                 nsIURI *aURI,
+-                                nsIURI *aInitialDocumentURI,
++                                nsIURI *aFirstPartyURI,
+                                 nsIURI *aReferrerURI,
+                                 nsILoadGroup *aLoadGroup,
+                                 imgIDecoderObserver *aObserver,
+@@ -1357,7 +1385,7 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
+   if (validateRequest && aCanMakeNewChannel) {
+     LOG_SCOPE(gImgLog, "imgLoader::ValidateRequest |cache hit| must validate");
+ 
+-    return ValidateRequestWithNewChannel(request, aURI, aInitialDocumentURI,
++    return ValidateRequestWithNewChannel(request, aURI, aFirstPartyURI,
+                                          aReferrerURI, aLoadGroup, aObserver,
+                                          aCX, aLoadFlags, aExistingRequest,
+                                          aProxyRequest, aPolicy,
+@@ -1367,22 +1395,40 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
+   return !validateRequest;
+ }
+ 
+-
+-bool imgLoader::RemoveFromCache(nsIURI *aKey)
++bool imgLoader::RemoveMatchingUrlsFromCache(nsIURI *aImgURI)
+ {
+-  if (!aKey) return false;
++  if (!aImgURI) return false;
+ 
+-  imgCacheTable &cache = GetCache(aKey);
+-  imgCacheQueue &queue = GetCacheQueue(aKey);
++  bool rv = true;
++  imgCacheTable &cache = GetCache(aImgURI);
+ 
+-  nsCAutoString spec;
+-  aKey->GetSpec(spec);
++  // We have to make a temporary, since RemoveFromCache removes the element
++  // from the queue, invalidating iterators.
++  nsTArray<nsRefPtr<imgCacheEntry> > entries;
++  cache.Enumerate(EnumAllEntries, &entries);
++
++  for (uint32_t i = 0; i < entries.Length(); ++i) {
++    bool isEqual = false;
++
++    entries[i]->mRequest->mURI->Equals(aImgURI, &isEqual);
++    if (isEqual && !RemoveFromCache(entries[i]))
++      rv = false;
++  }
++
++  return rv;
++}
+ 
+-  LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveFromCache", "uri", spec.get());
++bool imgLoader::RemoveKeyFromCache(imgCacheTable &cache, 
++                                   imgCacheQueue &queue,
++                                   nsCAutoString key)
++{
++  if (key.IsEmpty()) return false;
++
++  LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveKeyFromCache", "uri", key.get());
+ 
+   nsRefPtr<imgCacheEntry> entry;
+-  if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+-    cache.Remove(spec);
++  if (cache.Get(key, getter_AddRefs(entry)) && entry) {
++    cache.Remove(key);
+ 
+     NS_ABORT_IF_FALSE(!entry->Evicted(), "Evicting an already-evicted cache entry!");
+ 
+@@ -1410,12 +1456,13 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
+ 
+   nsRefPtr<imgRequest> request(getter_AddRefs(entry->GetRequest()));
+   if (request) {
+-    nsCOMPtr<nsIURI> key;
+-    if (NS_SUCCEEDED(request->GetURI(getter_AddRefs(key))) && key) {
+-      imgCacheTable &cache = GetCache(key);
+-      imgCacheQueue &queue = GetCacheQueue(key);
+-      nsCAutoString spec;
+-      key->GetSpec(spec);
++    nsCOMPtr<nsIURI> imgURI = request->mURI;
++    nsCOMPtr<nsIURI> firstPartyURI = request->mFirstPartyURI;
++
++    if (imgURI && firstPartyURI) {
++      imgCacheTable &cache = GetCache(imgURI);
++      imgCacheQueue &queue = GetCacheQueue(imgURI);
++      nsCAutoString spec = GetCacheKey(firstPartyURI, imgURI);
+ 
+       LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveFromCache", "entry's uri", spec.get());
+ 
+@@ -1438,18 +1485,6 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
+   return false;
+ }
+ 
+-static PLDHashOperator EnumEvictEntries(const nsACString&, 
+-                                        nsRefPtr<imgCacheEntry> &aData,
+-                                        void *data)
+-{
+-  nsTArray<nsRefPtr<imgCacheEntry> > *entries = 
+-    reinterpret_cast<nsTArray<nsRefPtr<imgCacheEntry> > *>(data);
+-
+-  entries->AppendElement(aData);
+-
+-  return PL_DHASH_NEXT;
+-}
+-
+ nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear)
+ {
+   LOG_STATIC_FUNC(gImgLog, "imgLoader::EvictEntries table");
+@@ -1457,7 +1492,7 @@ nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear)
+   // We have to make a temporary, since RemoveFromCache removes the element
+   // from the queue, invalidating iterators.
+   nsTArray<nsRefPtr<imgCacheEntry> > entries;
+-  aCacheToClear.Enumerate(EnumEvictEntries, &entries);
++  aCacheToClear.Enumerate(EnumAllEntries, &entries);
+ 
+   for (uint32_t i = 0; i < entries.Length(); ++i)
+     if (!RemoveFromCache(entries[i]))
+@@ -1490,11 +1525,10 @@ nsresult imgLoader::EvictEntries(imgCacheQueue &aQueueToClear)
+                                   nsIRequest::VALIDATE_NEVER |    \
+                                   nsIRequest::VALIDATE_ONCE_PER_SESSION)
+ 
+-
+-/* imgIRequest loadImage (in nsIURI aURI, in nsIURI initialDocumentURI, in nsIPrincipal loadingPrincipal, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in imgIRequest aRequest); */
++/* imgIRequest loadImage (in nsIURI aURI, in nsIURI aUrlBarURI, in nsIPrincipal loadingPrincipal, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in imgIRequest aRequest); */
+ 
+ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, 
+-                                   nsIURI *aInitialDocumentURI,
++                                   nsIURI *aFirstPartyURI,
+                                    nsIURI *aReferrerURI,
+                                    nsIPrincipal* aLoadingPrincipal,
+                                    nsILoadGroup *aLoadGroup,
+@@ -1513,8 +1547,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+   if (!aURI)
+     return NS_ERROR_NULL_POINTER;
+ 
+-  nsCAutoString spec;
+-  aURI->GetSpec(spec);
++  nsCAutoString spec = GetCacheKey(aFirstPartyURI, aURI);
++
+   LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI", spec.get());
+ 
+   *_retval = nullptr;
+@@ -1566,7 +1600,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+   imgCacheTable &cache = GetCache(aURI);
+ 
+   if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+-    if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
++    if (ValidateEntry(entry, aURI, aFirstPartyURI, aReferrerURI,
+                       aLoadGroup, aObserver, aCX, requestFlags, true,
+                       aRequest, _retval, aPolicy, aLoadingPrincipal, corsmode)) {
+       request = getter_AddRefs(entry->GetRequest());
+@@ -1605,7 +1639,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+     rv = NewImageChannel(getter_AddRefs(newChannel),
+                          &forcePrincipalCheck,
+                          aURI,
+-                         aInitialDocumentURI,
++                         aFirstPartyURI,
+                          aReferrerURI,
+                          aLoadGroup,
+                          mAcceptHeader,
+@@ -1627,8 +1661,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+         do_CreateInstance(NS_LOADGROUP_CONTRACTID);
+     newChannel->SetLoadGroup(loadGroup);
+ 
+-    request->Init(aURI, aURI, loadGroup, newChannel, entry, aCX,
+-                  aLoadingPrincipal, corsmode);
++    request->Init(aURI, aURI, aFirstPartyURI, loadGroup, newChannel, entry,
++                  aCX, aLoadingPrincipal, corsmode);
+ 
+     // Pass the inner window ID of the loading document, if possible.
+     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
+@@ -1676,7 +1710,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+     }
+ 
+     // Try to add the new request into the cache.
+-    PutIntoCache(aURI, entry);
++    PutIntoCache(spec, entry);
+   } else {
+     LOG_MSG_WITH_PARAM(gImgLog, 
+                        "imgLoader::LoadImage |cache hit|", "request", request);
+@@ -1736,6 +1770,48 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+   return NS_OK;
+ }
+ 
++nsCAutoString imgLoader::GetCacheKey(nsIURI *firstPartyURI, nsIURI *imgURI)
++{
++  NS_ASSERTION(imgURI, "imgLoader::GetCacheKey -- NULL imgURI");
++
++  nsCAutoString spec, hostKey;
++  if (imgURI)
++    imgURI->GetSpec(spec);
++
++#if 0
++  bool isChrome = false;
++  if (imgURI)
++    imgURI->SchemeIs("chrome", &isChrome);
++  if (isChrome)
++    return spec;  // No partitioning needed for chrome; just use a simple key.
++#endif
++
++  // FIXME: Should we use mozIThirdPartyUtil to get a domain from this?
++  if (firstPartyURI)
++    firstPartyURI->GetHost(hostKey);
++  else {
++    hostKey = "--NoFirstParty--";
++    nsCOMPtr<nsIConsoleService> consoleSvc =
++                                do_GetService(NS_CONSOLESERVICE_CONTRACTID);
++    if (consoleSvc) {
++      nsAutoString msg(NS_LITERAL_STRING("imgLoader::GetCacheKey:  NULL"
++                       " firstPartyURI for ").get());
++      msg.AppendASCII(spec.get());
++      consoleSvc->LogStringMessage(msg.get());
++    }
++
++#ifdef DEBUG
++    printf("imgLoader::GetCacheKey: NULL firstPartyURI for %s\n", spec.get());
++#endif
++  }
++
++  // Make a new key using host
++  // FIXME: This might involve a couple more copies than necessary.. 
++  // But man, 18 string types? Who knows which one I need to use to do
++  // this cheaply..
++  return hostKey + nsCAutoString("&") + spec;
++}
++
+ /* imgIRequest loadImageWithChannel(in nsIChannel channel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener); */
+ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderObserver *aObserver, nsISupports *aCX, nsIStreamListener **listener, imgIRequest **_retval)
+ {
+@@ -1746,22 +1822,27 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
+   nsCOMPtr<nsIURI> uri;
+   channel->GetURI(getter_AddRefs(uri));
+ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++                               = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  thirdPartySvc->GetFirstPartyURI(channel, nullptr,
++                                  getter_AddRefs(firstPartyURI));
++
+   nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
+   channel->GetLoadFlags(&requestFlags);
+ 
+   nsRefPtr<imgCacheEntry> entry;
++  imgCacheTable &cache = GetCache(uri);
++  nsCAutoString spec = GetCacheKey(firstPartyURI, uri);
+ 
+   if (requestFlags & nsIRequest::LOAD_BYPASS_CACHE) {
+-    RemoveFromCache(uri);
++    imgCacheQueue &queue = GetCacheQueue(uri);
++    RemoveKeyFromCache(cache, queue, spec);
+   } else {
+     // Look in the cache for our URI, and then validate it.
+     // XXX For now ignore aCacheKey. We will need it in the future
+     // for correctly dealing with image load requests that are a result
+     // of post data.
+-    imgCacheTable &cache = GetCache(uri);
+-    nsCAutoString spec;
+-
+-    uri->GetSpec(spec);
+ 
+     if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+       // We don't want to kick off another network load. So we ask
+@@ -1833,7 +1914,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
+     channel->GetOriginalURI(getter_AddRefs(originalURI));
+ 
+     // No principal specified here, because we're not passed one.
+-    request->Init(originalURI, uri, channel, channel, entry,
++    request->Init(originalURI, uri, firstPartyURI, channel, channel, entry,
+                   aCX, nullptr, imgIRequest::CORS_NONE);
+ 
+     ProxyListener *pl = new ProxyListener(static_cast<nsIStreamListener *>(request.get()));
+@@ -1845,7 +1926,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
+     NS_RELEASE(pl);
+ 
+     // Try to add the new request into the cache.
+-    PutIntoCache(originalURI, entry);
++    PutIntoCache(GetCacheKey(originalURI, firstPartyURI), entry);
+ 
+     rv = CreateNewProxyForRequest(request, loadGroup, aObserver,
+                                   requestFlags, nullptr, _retval);
+@@ -2132,6 +2213,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
+ 
+   int32_t corsmode = mRequest->GetCORSMode();
+   nsCOMPtr<nsIPrincipal> loadingPrincipal = mRequest->GetLoadingPrincipal();
++  nsCOMPtr<nsIURI> firstPartyURI = mRequest->mFirstPartyURI;
+ 
+   // Doom the old request's cache entry
+   mRequest->RemoveFromCache();
+@@ -2142,16 +2224,16 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
+   // We use originalURI here to fulfil the imgIRequest contract on GetURI.
+   nsCOMPtr<nsIURI> originalURI;
+   channel->GetOriginalURI(getter_AddRefs(originalURI));
+-  mNewRequest->Init(originalURI, uri, aRequest, channel, mNewEntry,
+-                    mContext, loadingPrincipal,
+-                    corsmode);
++  mNewRequest->Init(originalURI, uri, firstPartyURI, aRequest, channel,
++                    mNewEntry, mContext, loadingPrincipal, corsmode);
+ 
+   mDestListener = new ProxyListener(mNewRequest);
+ 
+   // Try to add the new request into the cache. Note that the entry must be in
+   // the cache before the proxies' ownership changes, because adding a proxy
+   // changes the caching behaviour for imgRequests.
+-  sImgLoader.PutIntoCache(originalURI, mNewEntry);
++  sImgLoader.PutIntoCache(imgLoader::GetCacheKey(firstPartyURI, originalURI),
++                          mNewEntry);
+ 
+   uint32_t count = mProxies.Count();
+   for (int32_t i = count-1; i>=0; i--) {
+diff --git a/image/src/imgLoader.h b/image/src/imgLoader.h
+index 64d3563..c275d83 100644
+--- a/image/src/imgLoader.h
++++ b/image/src/imgLoader.h
+@@ -227,10 +227,11 @@ public:
+ 
+   static nsresult InitCache();
+ 
+-  static bool RemoveFromCache(nsIURI *aKey);
++  static nsCAutoString GetCacheKey(nsIURI *firstPartyURI,
++                                   nsIURI *imgURI);
+   static bool RemoveFromCache(imgCacheEntry *entry);
+-
+-  static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
++  static bool PutIntoCache(nsCAutoString key, imgCacheEntry *entry);
++  static bool RemoveMatchingUrlsFromCache(nsIURI *aKey);
+ 
+   // Returns true if we should prefer evicting cache entry |two| over cache
+   // entry |one|.
+@@ -269,14 +270,14 @@ public:
+   // HasObservers(). The request's cache entry will be re-set before this
+   // happens, by calling imgRequest::SetCacheEntry() when an entry with no
+   // observers is re-requested.
+-  static bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
+-  static bool SetHasProxies(nsIURI *key);
++  static bool SetHasProxies(nsIURI *firstPartyURI, nsIURI *imgURI);
++  static bool SetHasNoProxies(nsIURI *imgURI, imgCacheEntry *entry);
+ 
+ private: // methods
+ 
+ 
+-  bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aKey,
+-                       nsIURI *aInitialDocumentURI, nsIURI *aReferrerURI, 
++  bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aURI,
++                       nsIURI *aFirstPartyURI, nsIURI *aReferrerURI, 
+                        nsILoadGroup *aLoadGroup,
+                        imgIDecoderObserver *aObserver, nsISupports *aCX,
+                        nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
+@@ -315,9 +316,14 @@ private: // methods
+   static void CacheEntriesChanged(nsIURI *aURI, int32_t sizediff = 0);
+   static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
+ 
++  static bool RemoveKeyFromCache(imgCacheTable &cache, 
++                                 imgCacheQueue &queue,
++                                 nsCAutoString key);
++
+ private: // data
+   friend class imgCacheEntry;
+   friend class imgMemoryReporter;
++  friend class imgRequest;
+ 
+   static imgCacheTable sCache;
+   static imgCacheQueue sCacheQueue;
+diff --git a/image/src/imgRequest.cpp b/image/src/imgRequest.cpp
+index e89e05a..71afe2c 100644
+--- a/image/src/imgRequest.cpp
++++ b/image/src/imgRequest.cpp
+@@ -103,6 +103,7 @@ imgRequest::~imgRequest()
+ 
+ nsresult imgRequest::Init(nsIURI *aURI,
+                           nsIURI *aCurrentURI,
++                          nsIURI *aFirstPartyURI,
+                           nsIRequest *aRequest,
+                           nsIChannel *aChannel,
+                           imgCacheEntry *aCacheEntry,
+@@ -124,6 +125,7 @@ nsresult imgRequest::Init(nsIURI *aURI,
+ 
+   mURI = aURI;
+   mCurrentURI = aCurrentURI;
++  mFirstPartyURI = aFirstPartyURI;
+   mRequest = aRequest;
+   mChannel = aChannel;
+   mTimedChannel = do_QueryInterface(mChannel);
+@@ -178,7 +180,7 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy)
+   // proxies.
+   if (mObservers.IsEmpty()) {
+     NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri.");
+-    imgLoader::SetHasProxies(mURI);
++    imgLoader::SetHasProxies(mFirstPartyURI, mURI);
+   }
+ 
+   // If we don't have any current observers, we should restart any animation.
+@@ -329,8 +331,11 @@ void imgRequest::RemoveFromCache()
+     // mCacheEntry is nulled out when we have no more observers.
+     if (mCacheEntry)
+       imgLoader::RemoveFromCache(mCacheEntry);
+-    else
+-      imgLoader::RemoveFromCache(mURI);
++    else {
++      imgLoader::RemoveKeyFromCache(imgLoader::GetCache(mURI),
++                                    imgLoader::GetCacheQueue(mURI),
++                                    imgLoader::GetCacheKey(mFirstPartyURI, mURI));
++    }
+   }
+ 
+   mCacheEntry = nullptr;
+diff --git a/image/src/imgRequest.h b/image/src/imgRequest.h
+index 424631b..7e1180f 100644
+--- a/image/src/imgRequest.h
++++ b/image/src/imgRequest.h
+@@ -57,6 +57,7 @@ public:
+ 
+   nsresult Init(nsIURI *aURI,
+                 nsIURI *aCurrentURI,
++                nsIURI *aFirstPartyURI,
+                 nsIRequest *aRequest,
+                 nsIChannel *aChannel,
+                 imgCacheEntry *aCacheEntry,
+@@ -189,6 +190,8 @@ private:
+   nsCOMPtr<nsIURI> mURI;
+   // The URI of the resource we ended up loading after all redirects, etc.
+   nsCOMPtr<nsIURI> mCurrentURI;
++  // The first party that triggered the load -- for cookie + cache isolation
++  nsCOMPtr<nsIURI> mFirstPartyURI;
+   // The principal of the document which loaded this image. Used when validating for CORS.
+   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
+   // The principal of this image.
+diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
+index 748107d..3ecb1e9 100644
+--- a/layout/generic/nsImageFrame.cpp
++++ b/layout/generic/nsImageFrame.cpp
+@@ -63,6 +63,7 @@
+ #include "nsError.h"
+ #include "nsBidiUtils.h"
+ #include "nsBidiPresUtils.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #include "gfxRect.h"
+ #include "ImageLayers.h"
+@@ -1777,6 +1778,7 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
+ {
+   nsresult rv = NS_OK;
+   NS_PRECONDITION(!aSpec.IsEmpty(), "What happened??");
++  NS_PRECONDITION(aPresContext, "NULL PresContext");
+ 
+   if (!sIOService) {
+     rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
+@@ -1794,9 +1796,17 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
+ 
+   // For icon loads, we don't need to merge with the loadgroup flags
+   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
+-
++ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++      = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  // XXX: Should we pass the loadgroup, too? Is document ever likely
++  // to be unset?
++  thirdPartySvc->GetFirstPartyURI(nullptr, aPresContext->Document(),
++                                 getter_AddRefs(firstPartyURI));
++ 
+   return il->LoadImage(realURI,     /* icon URI */
+-                       nullptr,      /* initial document URI; this is only
++                       firstPartyURI, /* initial document URI; this is only
+                                        relevant for cookies, so does not
+                                        apply to icons. */
+                        nullptr,      /* referrer (not relevant for icons) */
+diff --git a/netwerk/cookie/nsICookiePermission.idl b/netwerk/cookie/nsICookiePermission.idl
+index 379695c..7ad3f3b 100644
+--- a/netwerk/cookie/nsICookiePermission.idl
++++ b/netwerk/cookie/nsICookiePermission.idl
+@@ -7,6 +7,7 @@
+ interface nsICookie2;
+ interface nsIURI;
+ interface nsIChannel;
++interface nsIDocument;
+ 
+ typedef long nsCookieAccess;
+ 
+diff --git a/toolkit/system/gnome/nsAlertsIconListener.cpp b/toolkit/system/gnome/nsAlertsIconListener.cpp
+index bfc43d1..37e93c3 100644
+--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
++++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
+@@ -261,7 +261,8 @@ nsAlertsIconListener::StartRequest(const nsAString & aImageUrl)
+   if (!il)
+     return ShowAlert(NULL);
+ 
+-  return il->LoadImage(imageUri, nullptr, nullptr, nullptr, nullptr, this,
++  // XXX: Hrmm.... Bypass cache, or isolate to imageUrl?
++  return il->LoadImage(imageUri, imageUri, nullptr, nullptr, nullptr, this,
+                        nullptr, nsIRequest::LOAD_NORMAL, nullptr, nullptr,
+                        nullptr, getter_AddRefs(mIconRequest));
+ }
+diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm
+index e0c07c4..368df5f 100644
+--- a/widget/cocoa/nsMenuItemIconX.mm
++++ b/widget/cocoa/nsMenuItemIconX.mm
+@@ -29,6 +29,7 @@
+ #include "gfxImageSurface.h"
+ #include "imgIContainer.h"
+ #include "nsCocoaUtils.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ static const uint32_t kIconWidth = 16;
+ static const uint32_t kIconHeight = 16;
+@@ -304,9 +305,15 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
+       [mNativeMenuItem setImage:sPlaceholderIconImage];
+   }
+ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++                               = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  thirdPartySvc->GetFirstPartyURI(nullptr, document,
++                                  getter_AddRefs(firstPartyURI));
++
+   // Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is
+   // not exposed to web content
+-  rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this,
++  rv = loader->LoadImage(aIconURI, firstPartyURI, nullptr, nullptr, loadGroup, this,
+                          nullptr, nsIRequest::LOAD_NORMAL, nullptr, nullptr,
+                          nullptr, getter_AddRefs(mIconRequest));
+   if (NS_FAILED(rv)) return rv;
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0025-nsIHTTPChannel.redirectTo-API.patch b/src/current-patches/firefox/0025-nsIHTTPChannel.redirectTo-API.patch
new file mode 100644
index 0000000..1d81164
--- /dev/null
+++ b/src/current-patches/firefox/0025-nsIHTTPChannel.redirectTo-API.patch
@@ -0,0 +1,474 @@
+From 87461432d5e55eee144ed18e8551b637f7919950 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Mon, 14 Jan 2013 19:36:14 -0800
+Subject: [PATCH 25/26] nsIHTTPChannel.redirectTo API.
+
+Provides an API for HTTPS-Everywhere to perform redirects to https
+in a more secure and reliable way.
+---
+ netwerk/protocol/http/HttpBaseChannel.cpp          |   13 +++++
+ netwerk/protocol/http/HttpBaseChannel.h            |   10 ++++
+ netwerk/protocol/http/HttpChannelChild.cpp         |   34 ++++++++----
+ netwerk/protocol/http/HttpChannelParent.cpp        |   12 ++++-
+ netwerk/protocol/http/HttpChannelParent.h          |    4 +-
+ netwerk/protocol/http/PHttpChannel.ipdl            |    4 +-
+ netwerk/protocol/http/nsHttpChannel.cpp            |   57 ++++++++++++++++---
+ netwerk/protocol/http/nsHttpChannel.h              |    8 ++-
+ netwerk/protocol/http/nsIHttpChannel.idl           |   14 +++++-
+ .../protocol/viewsource/nsViewSourceChannel.cpp    |   10 +++-
+ 10 files changed, 139 insertions(+), 27 deletions(-)
+
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+index ec58de6..2926428 100644
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -37,6 +37,7 @@ HttpBaseChannel::HttpBaseChannel()
+   , mIsPending(false)
+   , mWasOpened(false)
+   , mResponseHeadersModified(false)
++  , mRequestObserversCalled(false)
+   , mAllowPipelining(true)
+   , mForceAllowThirdPartyCookie(false)
+   , mUploadStreamHasHeaders(false)
+@@ -1119,6 +1120,18 @@ HttpBaseChannel::GetRequestSucceeded(bool *aValue)
+   return NS_OK;
+ }
+ 
++NS_IMETHODIMP
++HttpBaseChannel::RedirectTo(nsIURI *newURI)
++{
++  // We can only redirect unopened channels
++  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
++
++  // The redirect is stored internally for use in AsyncOpen
++  mAPIRedirectToURI = newURI;
++
++  return NS_OK;
++}
++
+ //-----------------------------------------------------------------------------
+ // HttpBaseChannel::nsIHttpChannelInternal
+ //-----------------------------------------------------------------------------
+diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h
+index 971958c..125734d 100644
+--- a/netwerk/protocol/http/HttpBaseChannel.h
++++ b/netwerk/protocol/http/HttpBaseChannel.h
+@@ -17,6 +17,7 @@
+ #include "nsHttpConnectionInfo.h"
+ #include "nsIEncodedChannel.h"
+ #include "nsIHttpChannel.h"
++#include "nsHttpHandler.h"
+ #include "nsIHttpChannelInternal.h"
+ #include "nsIUploadChannel.h"
+ #include "nsIUploadChannel2.h"
+@@ -117,6 +118,7 @@ public:
+   NS_IMETHOD GetResponseStatus(uint32_t *aValue);
+   NS_IMETHOD GetResponseStatusText(nsACString& aValue);
+   NS_IMETHOD GetRequestSucceeded(bool *aValue);
++  NS_IMETHOD RedirectTo(nsIURI *newURI);
+ 
+   // nsIHttpChannelInternal
+   NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI);
+@@ -199,6 +201,12 @@ protected:
+                                            nsIChannel *,
+                                            bool preserveMethod);
+ 
++  // bundle calling OMR observers and marking flag into one function
++  inline void CallOnModifyRequestObservers() {
++    gHttpHandler->OnModifyRequest(this);
++    mRequestObserversCalled = true;
++  }
++
+   // Helper function to simplify getting notification callbacks.
+   template <class T>
+   void GetCallback(nsCOMPtr<T> &aResult)
+@@ -252,6 +260,7 @@ protected:
+   uint32_t                          mIsPending                  : 1;
+   uint32_t                          mWasOpened                  : 1;
+   uint32_t                          mResponseHeadersModified    : 1;
++  uint32_t                          mRequestObserversCalled     : 1;
+   uint32_t                          mAllowPipelining            : 1;
+   uint32_t                          mForceAllowThirdPartyCookie : 1;
+   uint32_t                          mUploadStreamHasHeaders     : 1;
+@@ -268,6 +277,7 @@ protected:
+   // Current suspension depth for this channel object
+   uint32_t                          mSuspendCount;
+ 
++  nsCOMPtr<nsIURI>                  mAPIRedirectToURI;
+   nsAutoPtr<nsTArray<nsCString> >   mRedirectedCachekeys;
+ };
+ 
+diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp
+index 5d82f7e..35697be 100644
+--- a/netwerk/protocol/http/HttpChannelChild.cpp
++++ b/netwerk/protocol/http/HttpChannelChild.cpp
+@@ -854,6 +854,7 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
+ NS_IMETHODIMP
+ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
+ {
++  OptionalURIParams redirectURI;
+   nsCOMPtr<nsIHttpChannel> newHttpChannel =
+       do_QueryInterface(mRedirectChannelChild);
+ 
+@@ -872,13 +873,25 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
+     newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples);
+   }
+ 
+-  // After we verify redirect, nsHttpChannel may hit the network: must give
+-  // "http-on-modify-request" observers the chance to cancel before that.
+-  if (NS_SUCCEEDED(result))
+-    gHttpHandler->OnModifyRequest(newHttpChannel);
+-
+-  if (mIPCOpen)
+-    SendRedirect2Verify(result, *headerTuples);
++  if (NS_SUCCEEDED(result)) {
++    // we know this is an HttpChannelChild
++    HttpChannelChild* base =
++      static_cast<HttpChannelChild*>(mRedirectChannelChild.get());
++    // After we verify redirect, nsHttpChannel may hit the network: must give
++    // "http-on-modify-request" observers the chance to cancel before that.
++    base->CallOnModifyRequestObservers();
++
++    /* If there was an API redirect of this redirect, we need to send it
++     * down here, since it can't get sent via SendAsyncOpen. */
++    SerializeURI(base->mAPIRedirectToURI, redirectURI);
++  } else {
++    /* If the redirect was canceled, bypass OMR and send an empty API
++     * redirect URI */
++    SerializeURI(nullptr, redirectURI);
++  }
++ 
++   if (mIPCOpen)
++    SendRedirect2Verify(result, *headerTuples, redirectURI);
+ 
+   return NS_OK;
+ }
+@@ -985,7 +998,7 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
+   //
+ 
+   // notify "http-on-modify-request" observers
+-  gHttpHandler->OnModifyRequest(this);
++  CallOnModifyRequestObservers();
+ 
+   mIsPending = true;
+   mWasOpened = true;
+@@ -1042,15 +1055,16 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
+   URIParams uri;
+   SerializeURI(mURI, uri);
+ 
+-  OptionalURIParams originalURI, documentURI, referrer;
++  OptionalURIParams originalURI, documentURI, referrer, redirectURI;
+   SerializeURI(mOriginalURI, originalURI);
+   SerializeURI(mDocumentURI, documentURI);
+   SerializeURI(mReferrer, referrer);
++  SerializeURI(mAPIRedirectToURI, redirectURI);
+ 
+   OptionalInputStreamParams uploadStream;
+   SerializeInputStream(mUploadStream, uploadStream);
+ 
+-  SendAsyncOpen(uri, originalURI, documentURI, referrer, mLoadFlags,
++  SendAsyncOpen(uri, originalURI, documentURI, referrer, redirectURI, mLoadFlags,
+                 mClientSetRequestHeaders, mRequestHead.Method(), uploadStream,
+                 mUploadStreamHasHeaders, mPriority, mRedirectionLimit,
+                 mAllowPipelining, mForceAllowThirdPartyCookie, mSendResumeAt,
+diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp
+index 0a9ccc4..d01f162 100644
+--- a/netwerk/protocol/http/HttpChannelParent.cpp
++++ b/netwerk/protocol/http/HttpChannelParent.cpp
+@@ -110,6 +110,7 @@ HttpChannelParent::RecvAsyncOpen(const URIParams&           aURI,
+                                  const OptionalURIParams&   aOriginalURI,
+                                  const OptionalURIParams&   aDocURI,
+                                  const OptionalURIParams&   aReferrerURI,
++                                 const OptionalURIParams&   aAPIRedirectToURI,
+                                  const uint32_t&            loadFlags,
+                                  const RequestHeaderTuples& requestHeaders,
+                                  const nsHttpAtom&          requestMethod,
+@@ -131,6 +132,7 @@ HttpChannelParent::RecvAsyncOpen(const URIParams&           aURI,
+   nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
+   nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
+   nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
++  nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
+ 
+   nsCString uriSpec;
+   uri->GetSpec(uriSpec);
+@@ -161,6 +163,8 @@ HttpChannelParent::RecvAsyncOpen(const URIParams&           aURI,
+     httpChan->SetDocumentURI(docUri);
+   if (referrerUri)
+     httpChan->SetReferrerInternal(referrerUri);
++  if (apiRedirectToUri)
++    httpChan->RedirectTo(apiRedirectToUri);
+   if (loadFlags != nsIRequest::LOAD_NORMAL)
+     httpChan->SetLoadFlags(loadFlags);
+ 
+@@ -315,13 +319,19 @@ HttpChannelParent::RecvUpdateAssociatedContentSecurity(const int32_t& high,
+ 
+ bool
+ HttpChannelParent::RecvRedirect2Verify(const nsresult& result, 
+-                                       const RequestHeaderTuples& changedHeaders)
++                                       const RequestHeaderTuples& changedHeaders,
++                                       const OptionalURIParams&   aAPIRedirectURI)
+ {
+   if (NS_SUCCEEDED(result)) {
+     nsCOMPtr<nsIHttpChannel> newHttpChannel =
+         do_QueryInterface(mRedirectChannel);
+ 
+     if (newHttpChannel) {
++      nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI);
++
++      if (apiRedirectUri)
++        newHttpChannel->RedirectTo(apiRedirectUri);
++
+       for (uint32_t i = 0; i < changedHeaders.Length(); i++) {
+         newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
+                                          changedHeaders[i].mValue,
+diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h
+index e869d63..96f3f3c 100644
+--- a/netwerk/protocol/http/HttpChannelParent.h
++++ b/netwerk/protocol/http/HttpChannelParent.h
+@@ -47,6 +47,7 @@ protected:
+                              const OptionalURIParams&   originalUri,
+                              const OptionalURIParams&   docUri,
+                              const OptionalURIParams&   referrerUri,
++                             const OptionalURIParams&   internalRedirectUri,
+                              const uint32_t&            loadFlags,
+                              const RequestHeaderTuples& requestHeaders,
+                              const nsHttpAtom&          requestMethod,
+@@ -71,7 +72,8 @@ protected:
+   virtual bool RecvResume();
+   virtual bool RecvCancel(const nsresult& status);
+   virtual bool RecvRedirect2Verify(const nsresult& result,
+-                                   const RequestHeaderTuples& changedHeaders);
++                                   const RequestHeaderTuples& changedHeaders,
++                                   const OptionalURIParams&   apiRedirectUri);
+   virtual bool RecvUpdateAssociatedContentSecurity(const int32_t& high,
+                                                    const int32_t& low,
+                                                    const int32_t& broken,
+diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl
+index c13c969..e16afd6 100644
+--- a/netwerk/protocol/http/PHttpChannel.ipdl
++++ b/netwerk/protocol/http/PHttpChannel.ipdl
+@@ -37,6 +37,7 @@ parent:
+             OptionalURIParams   original,
+             OptionalURIParams   doc,
+             OptionalURIParams   referrer,
++            OptionalURIParams   apiRedirectTo,
+             uint32_t            loadFlags,
+             RequestHeaderTuples requestHeaders,
+             nsHttpAtom          requestMethod,
+@@ -72,7 +73,8 @@ parent:
+   Cancel(nsresult status);
+ 
+   // Reports approval/veto of redirect by child process redirect observers
+-  Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders);
++  Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders,
++                  OptionalURIParams apiRedirectTo);
+ 
+   // For document loads we keep this protocol open after child's
+   // OnStopRequest, and send this msg (instead of __delete__) to allow
+diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
+index 9223d08..6bf11a1 100644
+--- a/netwerk/protocol/http/nsHttpChannel.cpp
++++ b/netwerk/protocol/http/nsHttpChannel.cpp
+@@ -1580,18 +1580,17 @@ nsHttpChannel::HandleAsyncRedirectChannelToHttps()
+         return;
+     }
+ 
+-    nsresult rv = AsyncRedirectChannelToHttps();
++    nsresult rv = StartRedirectChannelToHttps();
+     if (NS_FAILED(rv))
+-        ContinueAsyncRedirectChannelToHttps(rv);
++        ContinueAsyncRedirectChannelToURI(rv);
+ }
+ 
+ nsresult
+-nsHttpChannel::AsyncRedirectChannelToHttps()
++nsHttpChannel::StartRedirectChannelToHttps()
+ {
+     nsresult rv = NS_OK;
+     LOG(("nsHttpChannel::HandleAsyncRedirectChannelToHttps() [STS]\n"));
+ 
+-    nsCOMPtr<nsIChannel> newChannel;
+     nsCOMPtr<nsIURI> upgradedURI;
+ 
+     rv = mURI->Clone(getter_AddRefs(upgradedURI));
+@@ -1613,6 +1612,36 @@ nsHttpChannel::AsyncRedirectChannelToHttps()
+     else
+         upgradedURI->SetPort(oldPort);
+ 
++    return StartRedirectChannelToURI(upgradedURI);
++}
++
++void
++nsHttpChannel::HandleAsyncAPIRedirect()
++{
++    NS_PRECONDITION(!mCallOnResume, "How did that happen?");
++    NS_PRECONDITION(mAPIRedirectToURI, "How did that happen?");
++
++    if (mSuspendCount) {
++        LOG(("Waiting until resume to do async API redirect [this=%p]\n", this));
++        mCallOnResume = &nsHttpChannel::HandleAsyncAPIRedirect;
++        return;
++    }
++
++    nsresult rv = StartRedirectChannelToURI(mAPIRedirectToURI);
++    if (NS_FAILED(rv))
++        ContinueAsyncRedirectChannelToURI(rv);
++
++    return;
++}
++
++nsresult
++nsHttpChannel::StartRedirectChannelToURI(nsIURI *upgradedURI)
++{
++    nsresult rv = NS_OK;
++    LOG(("nsHttpChannel::StartRedirectChannelToURI()\n"));
++
++    nsCOMPtr<nsIChannel> newChannel;
++
+     nsCOMPtr<nsIIOService> ioService;
+     rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
+     NS_ENSURE_SUCCESS(rv, rv);
+@@ -1628,7 +1657,7 @@ nsHttpChannel::AsyncRedirectChannelToHttps()
+     uint32_t flags = nsIChannelEventSink::REDIRECT_PERMANENT;
+ 
+     PushRedirectAsyncFunc(
+-        &nsHttpChannel::ContinueAsyncRedirectChannelToHttps);
++        &nsHttpChannel::ContinueAsyncRedirectChannelToURI);
+     rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, flags);
+ 
+     if (NS_SUCCEEDED(rv))
+@@ -1636,15 +1665,19 @@ nsHttpChannel::AsyncRedirectChannelToHttps()
+ 
+     if (NS_FAILED(rv)) {
+         AutoRedirectVetoNotifier notifier(this);
++
++        /* Remove the async call to ContinueAsyncRedirectChannelToURI().
++         * It is called directly by our callers upon return (to clean up
++         * the failed redirect). */
+         PopRedirectAsyncFunc(
+-            &nsHttpChannel::ContinueAsyncRedirectChannelToHttps);
++            &nsHttpChannel::ContinueAsyncRedirectChannelToURI);
+     }
+ 
+     return rv;
+ }
+ 
+ nsresult
+-nsHttpChannel::ContinueAsyncRedirectChannelToHttps(nsresult rv)
++nsHttpChannel::ContinueAsyncRedirectChannelToURI(nsresult rv)
+ {
+     AutoRedirectVetoNotifier notifier(this);
+ 
+@@ -4374,7 +4407,7 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
+     mAuthProvider->AddAuthorizationHeaders();
+ 
+     // notify "http-on-modify-request" observers
+-    gHttpHandler->OnModifyRequest(this);
++    CallOnModifyRequestObservers();
+ 
+     // Adjust mCaps according to our request headers:
+     //  - If "Connection: close" is set as a request header, then do not bother
+@@ -4401,6 +4434,12 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
+     if (mLoadGroup)
+         mLoadGroup->AddRequest(this, nullptr);
+ 
++    // Check to see if we should redirect this channel elsewhere by
++    // nsIHttpChannel.redirectTo API request
++    if (mAPIRedirectToURI) {
++        return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
++    }
++
+     // Collect mAsyncOpenTime after we have called all obsrevers like
+     // "http-on-modify-request" and load group observers that may set
+     // mTimingEnabled flag.
+@@ -5531,7 +5570,7 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn)
+     AddCookiesToRequest();
+     
+     // notify "http-on-modify-request" observers
+-    gHttpHandler->OnModifyRequest(this);
++    CallOnModifyRequestObservers();
+ 
+     mIsPending = true;
+ 
+diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
+index 5b4ddb9..1c0c6b7 100644
+--- a/netwerk/protocol/http/nsHttpChannel.h
++++ b/netwerk/protocol/http/nsHttpChannel.h
+@@ -174,12 +174,14 @@ private:
+ 
+     // redirection specific methods
+     void     HandleAsyncRedirect();
++    void     HandleAsyncAPIRedirect();
+     nsresult ContinueHandleAsyncRedirect(nsresult);
+     void     HandleAsyncNotModified();
+     void     HandleAsyncFallback();
+     nsresult ContinueHandleAsyncFallback(nsresult);
+     nsresult PromptTempRedirect();
+-    virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, bool preserveMethod);
++    nsresult StartRedirectChannelToURI(nsIURI *);
++    virtual  nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, bool preserveMethod);
+ 
+     // proxy specific methods
+     nsresult ProxyFailover();
+@@ -236,8 +238,8 @@ private:
+     nsresult DoAuthRetry(nsAHttpConnection *);
+ 
+     void     HandleAsyncRedirectChannelToHttps();
+-    nsresult AsyncRedirectChannelToHttps();
+-    nsresult ContinueAsyncRedirectChannelToHttps(nsresult rv);
++    nsresult StartRedirectChannelToHttps();
++    nsresult ContinueAsyncRedirectChannelToURI(nsresult rv);
+ 
+     /**
+      * A function that takes care of reading STS headers and enforcing STS 
+diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl
+index c541df1..7037f95 100644
+--- a/netwerk/protocol/http/nsIHttpChannel.idl
++++ b/netwerk/protocol/http/nsIHttpChannel.idl
+@@ -14,7 +14,7 @@ interface nsIHttpHeaderVisitor;
+  * the inspection of the resulting HTTP response status and headers when they
+  * become available.
+  */
+-[scriptable, uuid(9277fe09-f0cc-4cd9-bbce-581dd94b0260)]
++[scriptable, uuid(a01362a0-5c45-11e2-bcfd-0800200c9a66)]
+ interface nsIHttpChannel : nsIChannel
+ {
+     /**************************************************************************
+@@ -257,4 +257,16 @@ interface nsIHttpChannel : nsIChannel
+      *         has been received (before onStartRequest).
+      */
+     boolean isNoCacheResponse();
++
++    /**
++     * Instructs the channel to immediately redirect to a new destination.
++     * Can only be called on channels not yet opened.
++     *
++     * This method provides no explicit conflict resolution. The last
++     * caller to call it wins.
++     *
++     * @throws NS_ERROR_ALREADY_OPENED if called after the channel
++     *         has been opened.
++     */
++    void redirectTo(in nsIURI aNewURI);
+ };
+diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+index 643ed0e..c63c2a5 100644
+--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
++++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+@@ -671,4 +671,12 @@ nsViewSourceChannel::IsNoCacheResponse(bool *_retval)
+ {
+     return !mHttpChannel ? NS_ERROR_NULL_POINTER :
+         mHttpChannel->IsNoCacheResponse(_retval);
+-} 
++}
++
++NS_IMETHODIMP
++nsViewSourceChannel::RedirectTo(nsIURI *uri)
++{
++    return !mHttpChannel ? NS_ERROR_NULL_POINTER :
++        mHttpChannel->RedirectTo(uri);
++}
++
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0026-Isolate-DOM-storage-to-first-party-URI.patch b/src/current-patches/firefox/0026-Isolate-DOM-storage-to-first-party-URI.patch
new file mode 100644
index 0000000..89f4ed6
--- /dev/null
+++ b/src/current-patches/firefox/0026-Isolate-DOM-storage-to-first-party-URI.patch
@@ -0,0 +1,776 @@
+From 69a8f50fc6d4881e48f29ef783e6246d6b7fbee4 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade at pearlcrescent.com>
+Date: Tue, 15 Jan 2013 14:18:43 -0800
+Subject: [PATCH 26/26] Isolate DOM storage to first party URI
+
+Also prevents DOM storage from writing to disk (hardcoded).
+---
+ docshell/base/nsDocShell.cpp                       |   78 ++++++++++++++++++-
+ docshell/base/nsDocShell.h                         |    6 +-
+ docshell/base/nsIDocShell.idl                      |   33 ++++++++-
+ dom/base/nsGlobalWindow.cpp                        |   13 +++-
+ dom/interfaces/storage/nsIDOMStorageManager.idl    |   11 +++-
+ dom/interfaces/storage/nsPIDOMStorage.h            |    8 +-
+ dom/src/storage/StorageChild.cpp                   |    6 +-
+ dom/src/storage/StorageChild.h                     |    3 +-
+ dom/src/storage/nsDOMStorage.cpp                   |   44 ++++++++---
+ dom/src/storage/nsDOMStorage.h                     |   14 +++-
+ dom/src/storage/nsDOMStorageDBWrapper.cpp          |   41 ++++++++---
+ dom/src/storage/nsDOMStorageDBWrapper.h            |   14 ++-
+ dom/src/storage/nsDOMStorageMemoryDB.cpp           |   21 +++++-
+ dom/src/storage/nsDOMStoragePersistentDB.cpp       |    8 ++-
+ .../windowwatcher/src/nsWindowWatcher.cpp          |    5 +-
+ 15 files changed, 255 insertions(+), 50 deletions(-)
+
+diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
+index 7a141d9..84a0043 100644
+--- a/docshell/base/nsDocShell.cpp
++++ b/docshell/base/nsDocShell.cpp
+@@ -184,6 +184,7 @@
+ #include "nsIChannelPolicy.h"
+ #include "nsIContentSecurityPolicy.h"
+ #include "nsSandboxFlags.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #include "nsXULAppAPI.h"
+ 
+@@ -2395,6 +2396,17 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
+                                           bool aCreate,
+                                           nsIDOMStorage** aStorage)
+ {
++    return GetSessionStorageForFirstParty(nullptr, aPrincipal, aDocumentURI,
++                                          aCreate, aStorage);
++}
++
++NS_IMETHODIMP
++nsDocShell::GetSessionStorageForFirstParty(nsIURI *aFirstPartyURI,
++                                           nsIPrincipal* aPrincipal,
++                                           const nsAString& aDocumentURI,
++                                           bool aCreate,
++                                           nsIDOMStorage** aStorage)
++{
+     NS_ENSURE_ARG_POINTER(aStorage);
+     *aStorage = nullptr;
+ 
+@@ -2426,7 +2438,11 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
+     if (origin.IsEmpty())
+         return NS_OK;
+ 
+-    if (!mStorages.Get(origin, aStorage) && aCreate) {
++    nsXPIDLCString key;
++    rv = GetSessionStorageKey(aFirstPartyURI, origin, key);
++    NS_ENSURE_SUCCESS(rv, rv);
++
++    if (!mStorages.Get(key, aStorage) && aCreate) {
+         nsCOMPtr<nsIDOMStorage> newstorage =
+             do_CreateInstance("@mozilla.org/dom/storage;2");
+         if (!newstorage)
+@@ -2440,7 +2456,7 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
+         if (NS_FAILED(rv))
+             return rv;
+ 
+-        mStorages.Put(origin, newstorage);
++        mStorages.Put(key, newstorage);
+ 
+         newstorage.swap(*aStorage);
+ #if defined(PR_LOGGING) && defined(DEBUG)
+@@ -2454,7 +2470,7 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
+         if (piStorage) {
+             nsCOMPtr<nsIPrincipal> storagePrincipal = piStorage->Principal();
+ 
+-            // The origin string used to map items in the hash table is 
++            // The key string used to map items in the hash table is 
+             // an implicit security check. That check is double-confirmed 
+             // by checking the principal a storage was demanded for 
+             // really is the principal for which that storage was originally 
+@@ -2513,6 +2529,14 @@ nsresult
+ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
+                               nsIDOMStorage* aStorage)
+ {
++    return AddSessionStorageForFirstParty(nullptr, aPrincipal, aStorage);
++}
++
++nsresult
++nsDocShell::AddSessionStorageForFirstParty(nsIURI* aFirstPartyURI,
++                                           nsIPrincipal* aPrincipal,
++                                           nsIDOMStorage* aStorage)
++{
+     NS_ENSURE_ARG_POINTER(aStorage);
+ 
+     if (!aPrincipal)
+@@ -2534,8 +2558,12 @@ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
+             if (origin.IsEmpty())
+                 return NS_ERROR_FAILURE;
+ 
++            nsXPIDLCString key;
++            rv = GetSessionStorageKey(aFirstPartyURI, origin, key);
++            NS_ENSURE_SUCCESS(rv, rv);
++
+             // Do not replace an existing session storage.
+-            if (mStorages.GetWeak(origin))
++            if (mStorages.GetWeak(key))
+                 return NS_ERROR_NOT_AVAILABLE;
+ 
+ #if defined(PR_LOGGING) && defined(DEBUG)
+@@ -2543,7 +2571,7 @@ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
+                    ("nsDocShell[%p]: was added a sessionStorage %p",
+                     this, aStorage));
+ #endif
+-            mStorages.Put(origin, aStorage);
++            mStorages.Put(key, aStorage);
+         }
+         else {
+             return topDocShell->AddSessionStorage(aPrincipal, aStorage);
+@@ -2568,6 +2596,10 @@ CloneSessionStorages(nsCStringHashKey::KeyType aKey, nsIDOMStorage* aStorage,
+     return PL_DHASH_NEXT;
+ }
+ 
++// CloneSessionStoragesTo() copies all session storage data from aDocShell to
++// this doc shell.  It does not check if that is an appropriate thing to do,
++// e.g., by verifying that the first party URIs are the same.  For now that is
++// okay because no Firefox code uses this method.
+ NS_IMETHODIMP
+ nsDocShell::CloneSessionStoragesTo(nsIDocShell* aDocShell)
+ {
+@@ -12389,3 +12421,39 @@ nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
+     *aOut = false;
+     return NS_OK;
+ }
++
++nsresult
++nsDocShell::GetSessionStorageKey(nsIURI *aFirstPartyURI,
++                                 nsXPIDLCString& aOrigin,
++                                 nsXPIDLCString& aResult)
++{
++    aResult.Truncate();
++
++    if (!aOrigin)
++        return NS_ERROR_FAILURE;
++
++    aResult.Append(aOrigin);
++
++    nsCOMPtr<nsIURI> firstPartyURI = aFirstPartyURI;
++    if (!firstPartyURI) {
++        nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
++                                do_GetService(THIRDPARTYUTIL_CONTRACTID);
++        if (!thirdPartyUtil)
++          return NS_ERROR_FAILURE;
++
++        nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
++        nsresult rv = thirdPartyUtil->GetFirstPartyURI(nullptr, doc,
++                                               getter_AddRefs(firstPartyURI));
++        NS_ENSURE_SUCCESS(rv, rv);
++    }
++
++    nsCAutoString host;
++    nsresult rv = firstPartyURI->GetHost(host);
++    if (NS_SUCCEEDED(rv) && (host.Length() > 0)) {
++        aResult.AppendLiteral("&");
++        aResult.Append(host);
++    }
++
++    return NS_OK;
++}
++
+diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
+index 225a636..aeb00c9 100644
+--- a/docshell/base/nsDocShell.h
++++ b/docshell/base/nsDocShell.h
+@@ -679,7 +679,7 @@ protected:
+     FrameType GetInheritedFrameType();
+     FrameType GetFrameType();
+ 
+-    // hash of session storages, keyed by domain
++    // hash of session storages, keyed by domain&firstPartyHost
+     nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
+ 
+     // Dimensions of the docshell
+@@ -846,6 +846,10 @@ private:
+     static unsigned long gNumberOfDocShells;
+ #endif /* DEBUG */
+ 
++    nsresult GetSessionStorageKey(nsIURI *aFirstPartyURI,
++                                  nsXPIDLCString& aOrigin,
++                                  nsXPIDLCString& aResult);
++
+ public:
+     class InterfaceRequestorProxy : public nsIInterfaceRequestor {
+     public:
+diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
+index 986f4b4..4f26a04 100644
+--- a/docshell/base/nsIDocShell.idl
++++ b/docshell/base/nsIDocShell.idl
+@@ -39,7 +39,7 @@ interface nsIWebBrowserPrint;
+ interface nsIVariant;
+ interface nsIPrivacyTransitionObserver;
+ 
+-[scriptable, builtinclass, uuid(9b283337-097d-4fa8-a2da-916318eaf828)]
++[scriptable, builtinclass, uuid(5289f25a-1175-4b01-bc56-b1628ef097b9)]
+ interface nsIDocShell : nsISupports
+ {
+   /**
+@@ -416,6 +416,24 @@ interface nsIDocShell : nsISupports
+                                               in boolean create);
+ 
+   /*
++   * A variant of getSessionStorageForPrincipal that is used when cloning
++   * session storage during creation of new windows/tabs (the first party URI
++   * of the new window/tab must be used to generate the key that is used to
++   * access the session data).
++   *
++   * @param firstPartyURI the URL bar URI
++   * @param principal returns a storage for this principal
++   * @param documentURI new storage will be created with reference to this
++   *                    document.documentURI that will appear in storage event
++   * @param create If true and a session storage object doesn't
++   *               already exist, a new one will be created.
++   */
++  nsIDOMStorage getSessionStorageForFirstParty(in nsIURI firstPartyURI,
++                                               in nsIPrincipal principal,
++                                               in DOMString documentURI,
++                                               in boolean create);
++
++  /*
+    * Add a WebApps session storage object to the docshell.
+    *
+    * @param principal the principal the storage object is associated with
+@@ -423,6 +441,19 @@ interface nsIDocShell : nsISupports
+    */
+   void addSessionStorage(in nsIPrincipal principal, in nsIDOMStorage storage);
+ 
++  /*
++   * A variant of addSessionStorage that is used when cloning session storage
++   * during creation of new windows/tabs (the cloning must occur before the
++   * document load begins).
++   *
++   * @param firstPartyURI the URL bar URI
++   * @param principal the principal the storage object is associated with
++   * @param storage the storage object to add
++   */
++  void addSessionStorageForFirstParty(in nsIURI firstPartyURI,
++                                      in nsIPrincipal principal,
++                                      in nsIDOMStorage storage);
++
+   /**
+    * Clones all session storage objects and attaches them to the given docshell.
+    * Useful when duplicating tabs and their states.
+diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
+index 3a370c9..201a0a2 100644
+--- a/dom/base/nsGlobalWindow.cpp
++++ b/dom/base/nsGlobalWindow.cpp
+@@ -8382,7 +8382,18 @@ nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
+     nsIDocShell* docShell = GetDocShell();
+     nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+ 
+-    rv = storageManager->GetLocalStorageForPrincipal(principal,
++    nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
++                                do_GetService(THIRDPARTYUTIL_CONTRACTID);
++    if (!thirdPartyUtil)
++      return NS_ERROR_FAILURE;
++ 
++    nsCOMPtr<nsIURI> firstPartyURI;
++    nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
++    rv = thirdPartyUtil->GetFirstPartyURI(NULL, doc, 
++                                          getter_AddRefs(firstPartyURI));
++    NS_ENSURE_SUCCESS(rv, rv);
++
++    rv = storageManager->GetLocalStorageForFirstParty(firstPartyURI, principal,
+                                                      documentURI,
+                                                      loadContext && loadContext->UsePrivateBrowsing(),
+                                                      getter_AddRefs(mLocalStorage));
+diff --git a/dom/interfaces/storage/nsIDOMStorageManager.idl b/dom/interfaces/storage/nsIDOMStorageManager.idl
+index 94b8789..21bedf0 100644
+--- a/dom/interfaces/storage/nsIDOMStorageManager.idl
++++ b/dom/interfaces/storage/nsIDOMStorageManager.idl
+@@ -7,8 +7,9 @@
+ 
+ interface nsIDOMStorage;
+ interface nsIPrincipal;
++interface nsIURI;
+ 
+-[scriptable, uuid(1541da6c-a9fb-4a8f-af9d-4493c981491d)]
++[scriptable, uuid(682edebf-7bbe-4b4b-b5f8-752cacfb2afa)]
+ interface nsIDOMStorageManager : nsISupports
+ {
+   /**
+@@ -35,4 +36,12 @@ interface nsIDOMStorageManager : nsISupports
+   nsIDOMStorage getLocalStorageForPrincipal(in nsIPrincipal aPrincipal,
+                                             in DOMString aDocumentURI,
+                                             [optional] in bool aPrivate);
++
++  /**
++   * Returns instance of localStorage object.
++   */
++  nsIDOMStorage getLocalStorageForFirstParty(in nsIURI aFirstPartyURI,
++                                             in nsIPrincipal aPrincipal,
++                                             in DOMString aDocumentURI,
++                                             [optional] in bool aPrivate);
+ };
+diff --git a/dom/interfaces/storage/nsPIDOMStorage.h b/dom/interfaces/storage/nsPIDOMStorage.h
+index fabb5cc..9f8de6b 100644
+--- a/dom/interfaces/storage/nsPIDOMStorage.h
++++ b/dom/interfaces/storage/nsPIDOMStorage.h
+@@ -15,8 +15,8 @@ class nsIURI;
+ class nsIPrincipal;
+ 
+ #define NS_PIDOMSTORAGE_IID \
+-{ 0x86dfe3c4, 0x4286, 0x4648, \
+-  { 0xb2, 0x09, 0x55, 0x27, 0x50, 0x59, 0x26, 0xac } }
++{ 0x0db5e488, 0x08f4, 0x4155, \
++  { 0x81, 0x9b, 0x2b, 0x5a, 0x44, 0xaa, 0xa2, 0x45 } }
+ 
+ class nsPIDOMStorage : public nsISupports
+ {
+@@ -31,7 +31,9 @@ public:
+ 
+   virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                         bool aPrivate) = 0;
+-  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
++  virtual nsresult InitAsLocalStorage(nsIURI *aFirstPartyURI,
++                                      nsIPrincipal *aPrincipal,
++                                      const nsSubstring &aDocumentURI,
+                                       bool aPrivate) = 0;
+ 
+   virtual already_AddRefed<nsIDOMStorage> Clone() = 0;
+diff --git a/dom/src/storage/StorageChild.cpp b/dom/src/storage/StorageChild.cpp
+index 6754fde..5d24973 100644
+--- a/dom/src/storage/StorageChild.cpp
++++ b/dom/src/storage/StorageChild.cpp
+@@ -95,9 +95,11 @@ StorageChild::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
+ }
+ 
+ void
+-StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate)
++StorageChild::InitAsLocalStorage(nsIURI* aFirstPartyURI, nsIURI* aDomainURI,
++                                 bool aCanUseChromePersist, bool aPrivate)
+ {
+-  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist, aPrivate);
++  DOMStorageBase::InitAsLocalStorage(aFirstPartyURI, aDomainURI,
++                                     aCanUseChromePersist, aPrivate);
+   InitRemote();
+ }
+ 
+diff --git a/dom/src/storage/StorageChild.h b/dom/src/storage/StorageChild.h
+index 297f093..81ddabe 100644
+--- a/dom/src/storage/StorageChild.h
++++ b/dom/src/storage/StorageChild.h
+@@ -27,7 +27,8 @@ public:
+   StorageChild(nsDOMStorage* aOwner, StorageChild& aOther);
+ 
+   virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
+-  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
++  virtual void InitAsLocalStorage(nsIURI* aFirstPartyURI, nsIURI* aDomainURI,
++                                  bool aCanUseChromePersist, bool aPrivate);
+ 
+   virtual bool CacheStoragePermissions();
+   
+diff --git a/dom/src/storage/nsDOMStorage.cpp b/dom/src/storage/nsDOMStorage.cpp
+index 2dd0fbc..23e8739 100644
+--- a/dom/src/storage/nsDOMStorage.cpp
++++ b/dom/src/storage/nsDOMStorage.cpp
+@@ -496,6 +496,17 @@ nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal,
+                                                  bool aPrivate,
+                                                  nsIDOMStorage **aResult)
+ {
++  return GetLocalStorageForFirstParty(nullptr, aPrincipal, aDocumentURI,
++                                     aPrivate, aResult);
++}
++
++NS_IMETHODIMP
++nsDOMStorageManager::GetLocalStorageForFirstParty(nsIURI *aFirstPartyURI,
++                                               nsIPrincipal *aPrincipal,
++                                               const nsSubstring &aDocumentURI,
++                                               bool aPrivate,
++                                               nsIDOMStorage **aResult)
++{
+   NS_ENSURE_ARG_POINTER(aPrincipal);
+   *aResult = nullptr;
+ 
+@@ -505,7 +516,8 @@ nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal,
+   if (!storage)
+     return NS_ERROR_OUT_OF_MEMORY;
+ 
+-  rv = storage->InitAsLocalStorage(aPrincipal, aDocumentURI, aPrivate);
++  rv = storage->InitAsLocalStorage(aFirstPartyURI, aPrincipal, aDocumentURI,
++                                   aPrivate);
+   if (NS_FAILED(rv))
+     return rv;
+ 
+@@ -622,7 +634,8 @@ DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
+ }
+ 
+ void
+-DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
++DOMStorageBase::InitAsLocalStorage(nsIURI* aFirstPartyURI,
++                                   nsIURI* aDomainURI,
+                                    bool aCanUseChromePersist,
+                                    bool aPrivate)
+ {
+@@ -634,7 +647,8 @@ DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
+   // mPrincipal in bug 455070. It is not even used for localStorage.
+   aDomainURI->GetAsciiHost(mDomain);
+ 
+-  nsDOMStorageDBWrapper::CreateOriginScopeDBKey(aDomainURI, mScopeDBKey);
++  nsDOMStorageDBWrapper::CreateOriginScopeDBKey(aFirstPartyURI, aDomainURI,
++                                                mScopeDBKey);
+ 
+   // XXX Bug 357323, we have to solve the issue how to define
+   // origin for file URLs. In that case CreateOriginScopeDBKey
+@@ -642,9 +656,9 @@ DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
+   // in that case because it produces broken entries w/o owner.
+   mUseDB = !mScopeDBKey.IsEmpty();
+ 
+-  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
++  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aFirstPartyURI, mDomain,
+                                                 true, false, mQuotaDomainDBKey);
+-  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
++  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aFirstPartyURI, mDomain,
+                                                 true, true, mQuotaETLDplus1DomainDBKey);
+   mCanUseChromePersist = aCanUseChromePersist;
+   mStorageType = nsPIDOMStorage::LocalStorage;
+@@ -763,11 +777,13 @@ DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
+ }
+ 
+ void
+-DOMStorageImpl::InitAsLocalStorage(nsIURI* aDomainURI,
++DOMStorageImpl::InitAsLocalStorage(nsIURI *aFirstPartyURI,
++                                   nsIURI* aDomainURI,
+                                    bool aCanUseChromePersist,
+                                    bool aPrivate)
+ {
+-  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist, aPrivate);
++  DOMStorageBase::InitAsLocalStorage(aFirstPartyURI, aDomainURI,
++                                     aCanUseChromePersist, aPrivate);
+ }
+ 
+ bool
+@@ -1352,7 +1368,9 @@ nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &
+ }
+ 
+ nsresult
+-nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
++nsDOMStorage::InitAsLocalStorage(nsIURI *aFirstPartyURI,
++                                 nsIPrincipal *aPrincipal,
++                                 const nsSubstring &aDocumentURI,
+                                  bool aPrivate)
+ {
+   nsCOMPtr<nsIURI> domainURI;
+@@ -1370,7 +1388,8 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aD
+     canUseChromePersist = URICanUseChromePersist(URI);
+   }
+   
+-  mStorageImpl->InitAsLocalStorage(domainURI, canUseChromePersist, aPrivate);
++  mStorageImpl->InitAsLocalStorage(aFirstPartyURI, domainURI,
++                                   canUseChromePersist, aPrivate);
+   return NS_OK;
+ }
+ 
+@@ -1782,7 +1801,9 @@ nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring
+ }
+ 
+ nsresult
+-nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
++nsDOMStorage2::InitAsLocalStorage(nsIURI *aFirstPartyURI,
++                                  nsIPrincipal *aPrincipal,
++                                  const nsSubstring &aDocumentURI,
+                                   bool aPrivate)
+ {
+   mStorage = new nsDOMStorage();
+@@ -1792,7 +1813,8 @@ nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &a
+   mPrincipal = aPrincipal;
+   mDocumentURI = aDocumentURI;
+ 
+-  return mStorage->InitAsLocalStorage(aPrincipal, aDocumentURI, aPrivate);
++  return mStorage->InitAsLocalStorage(aFirstPartyURI, aPrincipal,
++                                      aDocumentURI, aPrivate);
+ }
+ 
+ already_AddRefed<nsIDOMStorage>
+diff --git a/dom/src/storage/nsDOMStorage.h b/dom/src/storage/nsDOMStorage.h
+index 7add846..b795397 100644
+--- a/dom/src/storage/nsDOMStorage.h
++++ b/dom/src/storage/nsDOMStorage.h
+@@ -114,7 +114,8 @@ public:
+   DOMStorageBase(DOMStorageBase&);
+ 
+   virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
+-  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
++  virtual void InitAsLocalStorage(nsIURI* aFirstPartyURI, nsIURI* aDomainURI,
++                                  bool aCanUseChromePersist, bool aPrivate);
+ 
+   virtual nsTArray<nsString>* GetKeys(bool aCallerSecure) = 0;
+   virtual nsresult GetLength(bool aCallerSecure, uint32_t* aLength) = 0;
+@@ -221,7 +222,8 @@ public:
+   ~DOMStorageImpl();
+ 
+   virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
+-  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
++  virtual void InitAsLocalStorage(nsIURI *aFirstPartyURI, nsIURI* aDomainURI,
++                                  bool aCanUseChromePersist, bool aPrivate);
+ 
+   bool SessionOnly() {
+     return mSessionOnly;
+@@ -336,7 +338,9 @@ public:
+   // nsPIDOMStorage
+   virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                         bool aPrivate);
+-  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
++  virtual nsresult InitAsLocalStorage(nsIURI *aFirstPartyURI,
++                                      nsIPrincipal *aPrincipal,
++                                      const nsSubstring &aDocumentURI,
+                                       bool aPrivate);
+   virtual already_AddRefed<nsIDOMStorage> Clone();
+   virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI);
+@@ -411,7 +415,9 @@ public:
+   // nsPIDOMStorage
+   virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                         bool aPrivate);
+-  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
++  virtual nsresult InitAsLocalStorage(nsIURI *aFirstPartyURI,
++                                      nsIPrincipal *aPrincipal,
++                                      const nsSubstring &aDocumentURI,
+                                       bool aPrivate);
+   virtual already_AddRefed<nsIDOMStorage> Clone();
+   virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI);
+diff --git a/dom/src/storage/nsDOMStorageDBWrapper.cpp b/dom/src/storage/nsDOMStorageDBWrapper.cpp
+index bd2581b..048738a 100644
+--- a/dom/src/storage/nsDOMStorageDBWrapper.cpp
++++ b/dom/src/storage/nsDOMStorageDBWrapper.cpp
+@@ -47,7 +47,6 @@ nsDOMStorageDBWrapper::~nsDOMStorageDBWrapper()
+ void
+ nsDOMStorageDBWrapper::Close()
+ {
+-  mPersistentDB.Close();
+   mChromePersistentDB.Close();
+ }
+ 
+@@ -56,13 +55,13 @@ nsDOMStorageDBWrapper::Init()
+ {
+   nsresult rv;
+ 
+-  rv = mPersistentDB.Init(NS_LITERAL_STRING("webappsstore.sqlite"));
++  rv = mPersistentDB.Init();
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   rv = mChromePersistentDB.Init(NS_LITERAL_STRING("chromeappsstore.sqlite"));
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+-  rv = mSessionOnlyDB.Init(&mPersistentDB);
++  rv = mSessionOnlyDB.Init();
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   rv = mPrivateBrowsingDB.Init();
+@@ -74,16 +73,14 @@ nsDOMStorageDBWrapper::Init()
+ nsresult
+ nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTables(bool force)
+ {
+-  nsresult rv1, rv2;
++  nsresult rv1;
+   rv1 = mChromePersistentDB.FlushTemporaryTables(force);
+-  rv2 = mPersistentDB.FlushTemporaryTables(force);
+ 
+   // Everything flushed?  Then no need for a timer.
+-  if (!mChromePersistentDB.mTempTableLoads.Count() && 
+-      !mPersistentDB.mTempTableLoads.Count())
++  if (!mChromePersistentDB.mTempTableLoads.Count())
+     StopTempTableFlushTimer();
+ 
+-  return NS_FAILED(rv1) ? rv1 : rv2;
++  return rv1;
+ }
+ 
+ #define IMPL_FORWARDER_GUTS(_return, _code)                                \
+@@ -243,7 +240,8 @@ nsDOMStorageDBWrapper::GetUsage(const nsACString& aDomain,
+ }
+ 
+ nsresult
+-nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
++nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI *aFirstPartyURI,
++                                              nsIURI* aUri, nsACString& aKey)
+ {
+   nsresult rv;
+ 
+@@ -264,6 +262,17 @@ nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
+     aKey.Append(nsPrintfCString("%d", port));
+   }
+ 
++  // Isolate scope keys to the URL bar domain by appending &firstPartyHost
++  // if available.
++  if (aFirstPartyURI) {
++    nsCAutoString host;
++    rv = aFirstPartyURI->GetHost(host);
++    if (NS_SUCCEEDED(rv) && (host.Length() > 0)) {
++      aKey.AppendLiteral("&");
++      aKey.Append(host);
++    }
++  }
++
+   return NS_OK;
+ }
+ 
+@@ -317,7 +326,8 @@ nsDOMStorageDBWrapper::CreateDomainScopeDBKey(const nsACString& aAsciiDomain,
+ }
+ 
+ nsresult
+-nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
++nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(nsIURI *aFirstPartyURI,
++                                              const nsACString& aAsciiDomain,
+                                               bool aIncludeSubDomains,
+                                               bool aEffectiveTLDplus1Only,
+                                               nsACString& aKey)
+@@ -351,6 +361,17 @@ nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
+   if (!aIncludeSubDomains)
+     subdomainsDBKey.AppendLiteral(":");
+ 
++  // Isolate quota keys to the URL bar domain by appending &firstPartyHost
++  // if available.
++  if (aFirstPartyURI) {
++    nsCAutoString host;
++    rv = aFirstPartyURI->GetHost(host);
++    if (NS_SUCCEEDED(rv) && (host.Length() > 0)) {
++      subdomainsDBKey.AppendLiteral("&");
++      subdomainsDBKey.Append(host);
++    }
++  }
++
+   aKey.Assign(subdomainsDBKey);
+   return NS_OK;
+ }
+diff --git a/dom/src/storage/nsDOMStorageDBWrapper.h b/dom/src/storage/nsDOMStorageDBWrapper.h
+index 94d28af..60a4f91 100644
+--- a/dom/src/storage/nsDOMStorageDBWrapper.h
++++ b/dom/src/storage/nsDOMStorageDBWrapper.h
+@@ -178,9 +178,11 @@ public:
+   /**
+     * Turns "http://foo.bar.com:80" to "moc.rab.oof.:http:80",
+     * i.e. reverses the host, appends a dot, appends the schema
+-    * and a port number.
++    * and a port number.  If aFirstPartyURI is present, the first party
++    * host is appended, e.g., "moc.rab.oof.:http:80:example.com"
+     */
+-  static nsresult CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey);
++  static nsresult CreateOriginScopeDBKey(nsIURI *aFirstPartyURI,
++                                         nsIURI* aUri, nsACString& aKey);
+ 
+   /**
+     * Turns "http://foo.bar.com" to "moc.rab.oof.",
+@@ -192,9 +194,11 @@ public:
+   /**
+     * Turns "foo.bar.com" to "moc.rab.",
+     * i.e. extracts eTLD+1 from the host, reverses the result
+-    * and appends a dot.
++    * and appends a dot.  If aFirstPartyURI is present, the first party
++    * host is appended, e.g., "moc.rab.:example.com"
+     */
+-  static nsresult CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
++  static nsresult CreateQuotaDomainDBKey(nsIURI *aFirstPartyURI,
++                                         const nsACString& aAsciiDomain,
+                                          bool aIncludeSubDomains, bool aETLDplus1Only,
+                                          nsACString& aKey);
+ 
+@@ -222,7 +226,7 @@ public:
+ 
+ protected:
+   nsDOMStoragePersistentDB mChromePersistentDB;
+-  nsDOMStoragePersistentDB mPersistentDB;
++  nsDOMStorageMemoryDB mPersistentDB; // No longer an nsDOMStoragePersistentDB
+   nsDOMStorageMemoryDB mSessionOnlyDB;
+   nsDOMStorageMemoryDB mPrivateBrowsingDB;
+ 
+diff --git a/dom/src/storage/nsDOMStorageMemoryDB.cpp b/dom/src/storage/nsDOMStorageMemoryDB.cpp
+index 5cc2e5d..639f516 100644
+--- a/dom/src/storage/nsDOMStorageMemoryDB.cpp
++++ b/dom/src/storage/nsDOMStorageMemoryDB.cpp
+@@ -382,7 +382,12 @@ nsDOMStorageMemoryDB::GetUsage(const nsACString& aDomain,
+   nsresult rv;
+ 
+   nsCAutoString quotadomainDBKey;
+-  rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
++  // This GetUsage() call is only used to report usage totals in the
++  // preferences and page info. UI, and only for sites that have been
++  // granted "offline application" permission.  Since we pass nullptr
++  // for the firstPartURI, the usage total returned will not be
++  // partitioned by first party, which is OK for the UI.
++  rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(nullptr, aDomain,
+                                                      aIncludeSubDomains,
+                                                      false,
+                                                      quotadomainDBKey);
+@@ -395,6 +400,7 @@ struct GetUsageEnumStruc
+ {
+   int32_t mUsage;
+   int32_t mExcludeOfflineFromUsage;
++  nsCString mFirstPartyHostSuffix;	// e.g., &example.com
+   nsCString mSubdomain;
+ };
+ 
+@@ -405,7 +411,9 @@ GetUsageEnum(const nsACString& key,
+ {
+   GetUsageEnumStruc* struc = (GetUsageEnumStruc*)closure;
+ 
+-  if (StringBeginsWith(key, struc->mSubdomain)) {
++  if (StringBeginsWith(key, struc->mSubdomain) &&
++      ((0 == struc->mFirstPartyHostSuffix.Length()) ||
++       StringEndsWith(key, struc->mFirstPartyHostSuffix))) {
+     if (struc->mExcludeOfflineFromUsage) {
+       nsCAutoString domain;
+       nsresult rv = nsDOMStorageDBWrapper::GetDomainFromScopeKey(key, domain);
+@@ -428,6 +436,15 @@ nsDOMStorageMemoryDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
+   struc.mUsage = 0;
+   struc.mExcludeOfflineFromUsage = aExcludeOfflineFromUsage;
+   struc.mSubdomain = aQuotaDomainDBKey;
++  nsCAutoString tmpQuotaKey(aQuotaDomainDBKey);
++  int32_t idx = tmpQuotaKey.RFindChar('&');
++  if (idx > 0) {
++    const nsDependentCSubstring& tmpStr = Substring(tmpQuotaKey, idx);
++    if (tmpStr.Length() > 1) {
++      struc.mFirstPartyHostSuffix = tmpStr;
++      struc.mSubdomain = Substring(tmpQuotaKey, 0, idx - 1);
++    }
++  }
+ 
+   if (mPreloadDB) {
+     nsresult rv;
+diff --git a/dom/src/storage/nsDOMStoragePersistentDB.cpp b/dom/src/storage/nsDOMStoragePersistentDB.cpp
+index 93ad303..7814a60 100644
+--- a/dom/src/storage/nsDOMStoragePersistentDB.cpp
++++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp
+@@ -813,7 +813,13 @@ nsDOMStoragePersistentDB::GetUsage(const nsACString& aDomain,
+   nsresult rv;
+ 
+   nsCAutoString quotadomainDBKey;
+-  rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
++  // This GetUsage() call is only used to report usage totals in the
++  // preferences and page info. UI, and only for sites that have been
++  // granted "offline application" permission.  Since we pass nullptr
++  // for the firstPartURI, the usage total returned will not be
++  // partitioned by first party, which is OK for the UI.
++  // Also, Tor does not use currently use nsDOMStoragePersistentDB.
++  rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(nullptr, aDomain,
+                                                      aIncludeSubDomains,
+                                                      false,
+                                                      quotadomainDBKey);
+diff --git a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+index 6abbed7..0bad9ed 100644
+--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
++++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+@@ -963,14 +963,15 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow *aParent,
+ 
+   if (subjectPrincipal && parentDocShell) {
+     nsCOMPtr<nsIDOMStorage> storage;
+-    parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal,
++    parentDocShell->GetSessionStorageForFirstParty(uriToLoad, subjectPrincipal,
+                                                   EmptyString(), false,
+                                                   getter_AddRefs(storage));
+     nsCOMPtr<nsPIDOMStorage> piStorage =
+       do_QueryInterface(storage);
+     if (piStorage){
+       storage = piStorage->Clone();
+-      newDocShell->AddSessionStorage(
++      newDocShell->AddSessionStorageForFirstParty(
++        uriToLoad,
+         piStorage->Principal(),
+         storage);
+     }
+-- 
+1.7.5.4
+





More information about the tor-commits mailing list