Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 14 Nov 2014 17:32:39 -0500
changeset 215857 acbd7b68fa8c7c8cfa542adf9a9adeca2df9e46c
parent 215795 dfe8756ccd9431e85c86c0a14a7b0623afee76c6 (current diff)
parent 215856 647ec1593edb4ef1fe148db1813ea5f635d52796 (diff)
child 215858 ed228c0b353fdee1925134a89f8f0ddd61b021d7
child 215863 7fb233e1b1c4459395ee4c43ff4b5ce8fadd7e32
child 215900 f5c3c0341072988936a492691538b48e28eb87cf
child 215917 dc47e33ebd166db61549381fe0b7e21cfa62de17
push id27827
push userryanvm@gmail.com
push dateFri, 14 Nov 2014 22:48:07 +0000
treeherdermozilla-central@acbd7b68fa8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
acbd7b68fa8c / 36.0a1 / 20141115030205 / files
nightly linux64
acbd7b68fa8c / 36.0a1 / 20141115030205 / files
nightly mac
acbd7b68fa8c / 36.0a1 / 20141115030205 / files
nightly win32
acbd7b68fa8c / 36.0a1 / 20141115030205 / files
nightly win64
acbd7b68fa8c / 36.0a1 / 20141115030205 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
js/ipc/WrapperOwner.cpp
js/xpconnect/src/xpcprivate.h
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -428,17 +428,16 @@ pref("browser.link.open_newwindow.restri
 // work), but make in-process browser frames the default.
 pref("dom.mozBrowserFramesEnabled", true);
 
 // Enable a (virtually) unlimited number of mozbrowser processes.
 // We'll run out of PIDs on UNIX-y systems before we hit this limit.
 pref("dom.ipc.processCount", 100000);
 
 pref("dom.ipc.browser_frames.oop_by_default", false);
-pref("dom.browser_frames.useAsyncPanZoom", true);
 
 // SMS/MMS
 pref("dom.sms.enabled", true);
 
 //The waiting time in network manager.
 pref("network.gonk.ms-release-mms-connection", 30000);
 
 // WebContacts
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -505,20 +505,16 @@ let settingsToObserve = {
     defaultValue: ''
   },
   'accessibility.screenreader_quicknav_index': {
     prefName: 'accessibility.accessfu.quicknav_index',
     resetToPref: true,
     defaultValue: 0
   },
   'app.update.interval': 86400,
-  'apz.force-enable': {
-    prefName: 'dom.browser_frames.useAsyncPanZoom',
-    defaultValue: false
-  },
   'apz.overscroll.enabled': true,
   'debug.fps.enabled': {
     prefName: 'layers.acceleration.draw-fps',
     defaultValue: false
   },
   'debug.log-animations.enabled': {
     prefName: 'layers.offmainthreadcomposition.log-animations',
     defaultValue: false
--- a/browser/devtools/inspector/test/browser_inspector_delete-selected-node-03.js
+++ b/browser/devtools/inspector/test/browser_inspector_delete-selected-node-03.js
@@ -12,14 +12,16 @@ add_task(function* () {
   let { inspector } = yield openInspectorForURL(TEST_URL);
 
   let iframe = yield getNodeFront("iframe", inspector);
   let node = yield getNodeFrontInFrame("span", iframe, inspector);
   yield selectNode(node, inspector);
 
   info("Removing iframe.");
   yield inspector.walker.removeNode(iframe);
+  yield inspector.selection.once("detached-front");
 
   let body = yield getNodeFront("body", inspector);
+
   is(inspector.selection.nodeFront, body, "Selection is now the body node");
 
   yield inspector.once("inspector-updated");
 });
--- a/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js
+++ b/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js
@@ -1,11 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+Components.utils.import("resource://gre/modules/Promise.jsm", this);
+
 const RELATIVE_DIR = "browser/extensions/pdfjs/test/";
 const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
 
 const TESTS = [
   {
     action: {
       selector: "button#zoomIn",
       event: "click"
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -327,17 +327,17 @@ nsScriptSecurityManager::GetChannelResul
             nsRefPtr<nsNullPrincipal> prin =
               nsNullPrincipal::CreateWithInheritedAttributes(loadInfo->LoadingPrincipal());
             NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
             prin.forget(aPrincipal);
             return NS_OK;
         }
 
         if (loadInfo->GetForceInheritPrincipal()) {
-            NS_ADDREF(*aPrincipal = loadInfo->LoadingPrincipal());
+            NS_ADDREF(*aPrincipal = loadInfo->TriggeringPrincipal());
             return NS_OK;
         }
     }
     return GetChannelURIPrincipal(aChannel, aPrincipal);
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
--- a/docshell/base/LoadInfo.cpp
+++ b/docshell/base/LoadInfo.cpp
@@ -9,51 +9,68 @@
 #include "mozilla/Assertions.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsISupportsImpl.h"
 #include "nsISupportsUtils.h"
 
 namespace mozilla {
 
-LoadInfo::LoadInfo(nsIPrincipal* aPrincipal,
+LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
+                   nsIPrincipal* aTriggeringPrincipal,
                    nsINode* aLoadingContext,
                    nsSecurityFlags aSecurityFlags,
                    nsContentPolicyType aContentPolicyType,
                    nsIURI* aBaseURI)
-  : mPrincipal(aPrincipal)
+  : mLoadingPrincipal(aLoadingPrincipal)
+  , mTriggeringPrincipal(aTriggeringPrincipal ?
+                         aTriggeringPrincipal : aLoadingPrincipal)
   , mLoadingContext(do_GetWeakReference(aLoadingContext))
   , mSecurityFlags(aSecurityFlags)
   , mContentPolicyType(aContentPolicyType)
   , mBaseURI(aBaseURI)
 {
-  MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(aLoadingPrincipal);
+  MOZ_ASSERT(mTriggeringPrincipal);
   // if the load is sandboxed, we can not also inherit the principal
   if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
     mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 }
 
 LoadInfo::~LoadInfo()
 {
 }
 
 NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo)
 
 NS_IMETHODIMP
-LoadInfo::GetLoadingPrincipal(nsIPrincipal** aPrincipal)
+LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal)
 {
-  NS_ADDREF(*aPrincipal = mPrincipal);
+  NS_ADDREF(*aLoadingPrincipal = mLoadingPrincipal);
   return NS_OK;
 }
 
 nsIPrincipal*
 LoadInfo::LoadingPrincipal()
 {
-  return mPrincipal;
+  return mLoadingPrincipal;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
+{
+  NS_ADDREF(*aTriggeringPrincipal = mTriggeringPrincipal);
+  return NS_OK;
+}
+
+nsIPrincipal*
+LoadInfo::TriggeringPrincipal()
+{
+  return mTriggeringPrincipal;
 }
 
 NS_IMETHODIMP
 LoadInfo::GetLoadingDocument(nsIDOMDocument** outLoadingDocument)
 {
   nsCOMPtr<nsINode> node = do_QueryReferent(mLoadingContext);
   if (node) {
     nsCOMPtr<nsIDOMDocument> context = do_QueryInterface(node->OwnerDoc());
--- a/docshell/base/LoadInfo.h
+++ b/docshell/base/LoadInfo.h
@@ -21,27 +21,29 @@ namespace mozilla {
  * Class that provides an nsILoadInfo implementation.
  */
 class MOZ_EXPORT LoadInfo MOZ_FINAL : public nsILoadInfo
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSILOADINFO
 
-  // aPrincipal MUST NOT BE NULL.
-  LoadInfo(nsIPrincipal* aPrincipal,
+  // aLoadingPrincipal MUST NOT BE NULL.
+  LoadInfo(nsIPrincipal* aLoadingPrincipal,
+           nsIPrincipal* aTriggeringPrincipal,
            nsINode* aLoadingContext,
            nsSecurityFlags aSecurityFlags,
            nsContentPolicyType aContentPolicyType,
            nsIURI* aBaseURI = nullptr);
 
 private:
   ~LoadInfo();
 
-  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsWeakPtr              mLoadingContext;
   nsSecurityFlags        mSecurityFlags;
   nsContentPolicyType    mContentPolicyType;
   nsCOMPtr<nsIURI>       mBaseURI;
 };
 
 } // namespace mozilla
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10259,50 +10259,52 @@ nsDocShell::DoURILoad(nsIURI * aURI,
     if (mScriptGlobal) {
       requestingNode = mScriptGlobal->GetFrameElementInternal();
       if (!requestingNode) {
         requestingNode = mScriptGlobal->GetExtantDoc();
       }
     }
 
     bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
-    // only inherit if we have a requestingPrincipal
+    // only inherit if we have a triggeringPrincipal
     bool inherit = false;
 
-    nsCOMPtr<nsIPrincipal> requestingPrincipal = do_QueryInterface(aOwner);
-    if (requestingPrincipal) {
-      inherit = nsContentUtils::ChannelShouldInheritPrincipal(requestingPrincipal,
+    nsCOMPtr<nsIPrincipal> triggeringPrincipal = do_QueryInterface(aOwner);
+    if (triggeringPrincipal) {
+      inherit = nsContentUtils::ChannelShouldInheritPrincipal(triggeringPrincipal,
                                                               aURI,
                                                               true, // aInheritForAboutBlank
                                                               isSrcdoc);
     }
-    else if (!requestingPrincipal && aReferrerURI) {
+    else if (!triggeringPrincipal && aReferrerURI) {
       rv = CreatePrincipalFromReferrer(aReferrerURI,
-                                       getter_AddRefs(requestingPrincipal));
+                                       getter_AddRefs(triggeringPrincipal));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
-      requestingPrincipal = nsContentUtils::GetSystemPrincipal();
+      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
     }
 
     nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
     if (inherit) {
       securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
     }
     if (isSandBoxed) {
       securityFlags |= nsILoadInfo::SEC_SANDBOXED;
     }
 
     if (!isSrcdoc) {
       nsCOMPtr<nsILoadInfo> loadInfo =
-        new mozilla::LoadInfo(requestingPrincipal,
-                              requestingNode,
-                              securityFlags,
-                              aContentPolicyType,
-                              aBaseURI);
+        new LoadInfo(requestingNode ?
+                       requestingNode->NodePrincipal() : triggeringPrincipal.get(),
+                     triggeringPrincipal,
+                     requestingNode,
+                     securityFlags,
+                     aContentPolicyType,
+                     aBaseURI);
         rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                    aURI,
                                    loadInfo,
                                    nullptr,   // loadGroup
                                    static_cast<nsIInterfaceRequestor*>(this),
                                    loadFlags);
 
         if (NS_FAILED(rv)) {
@@ -10330,30 +10332,34 @@ nsDocShell::DoURILoad(nsIURI * aURI,
 
         if (isViewSource) {
             nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance();
             NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE);
 
             rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, getter_AddRefs(channel));
             NS_ENSURE_SUCCESS(rv, rv);
             nsCOMPtr<nsILoadInfo> loadInfo =
-              new LoadInfo(requestingPrincipal,
+              new LoadInfo(requestingNode ?
+                             requestingNode->NodePrincipal() : triggeringPrincipal.get(),
+                           triggeringPrincipal,
                            requestingNode,
                            securityFlags,
                            aContentPolicyType,
                            aBaseURI);
             channel->SetLoadInfo(loadInfo);
         }
         else {
             rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
                                                   aURI,
                                                   aSrcdoc,
                                                   NS_LITERAL_CSTRING("text/html"),
                                                   requestingNode,
-                                                  requestingPrincipal,
+                                                  requestingNode ?
+                                                    requestingNode->NodePrincipal() : triggeringPrincipal.get(),
+                                                  triggeringPrincipal,
                                                   securityFlags,
                                                   aContentPolicyType,
                                                   true,
                                                   aBaseURI);
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
 
@@ -11579,17 +11585,17 @@ nsDocShell::AddToSessionHistory(nsIURI *
             nsCOMPtr<nsILoadInfo> loadInfo;
             aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
             if (loadInfo) {
                 // For now keep storing just the principal in the SHEntry.
                 if (loadInfo->GetLoadingSandboxed()) {
                     owner = nsNullPrincipal::CreateWithInheritedAttributes(loadInfo->LoadingPrincipal());
                     NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
                 } else if (loadInfo->GetForceInheritPrincipal()) {
-                    owner = loadInfo->LoadingPrincipal();
+                    owner = loadInfo->TriggeringPrincipal();
                 }
             }
         }
     }
 
     //Title is set in nsDocShell::SetTitle()
     entry->Create(aURI,              // uri
                   EmptyString(),     // Title
--- a/docshell/base/nsILoadInfo.idl
+++ b/docshell/base/nsILoadInfo.idl
@@ -12,17 +12,17 @@ interface nsINode;
 interface nsIPrincipal;
 interface nsIURI;
 
 typedef unsigned long nsSecurityFlags;
 
 /**
  * An nsILoadOwner represents per-load information about who started the load.
  */
-[scriptable, builtinclass, uuid(b22b8ee7-047a-4351-a749-13c6d39f6b17)]
+[scriptable, builtinclass, uuid(da363267-236d-49bf-83a2-33da8d892728)]
 interface nsILoadInfo : nsISupports
 {
   /**
    * No special security flags:
    */
   const unsigned long SEC_NORMAL = 0;
 
   /**
@@ -67,16 +67,35 @@ interface nsILoadInfo : nsISupports
   readonly attribute nsIPrincipal loadingPrincipal;
 
   /**
    * A C++-friendly version of loadingPrincipal.
    */
   [noscript, notxpcom, nostdcall, binaryname(LoadingPrincipal)]
   nsIPrincipal binaryLoadingPrincipal();
 
+  /**
+   * The triggeringPrincipal is the principal that triggerd the load.
+   * Most likely the triggeringPrincipal and the loadingPrincipal are the same,
+   * in which case triggeringPrincipal returns the loadingPrincipal.
+   * In some cases the loadingPrincipal and the triggeringPrincipal are different
+   * however, e.g. a stylesheet may import a subresource. In that case the
+   * stylesheet principal is the triggeringPrincipal and the document that loads
+   * the stylesheet provides a loadingContext and hence the loadingPrincipal.
+   *
+   * If triggeringPrincipal and loadingPrincipal are the same, then
+   * triggeringPrincipal returns loadingPrincipal.
+   */
+  readonly attribute nsIPrincipal triggeringPrincipal;
+
+  /**
+   * A C++-friendly version of triggeringPrincipal.
+   */
+  [noscript, notxpcom, nostdcall, binaryname(TriggeringPrincipal)]
+  nsIPrincipal binaryTriggeringPrincipal();
 
   /**
    * The loadingDocument of the channel.
    *
    * The loadingDocument of a channel is the document that requested the
    * load of the resource. It is *not* the resource itself, it's the
    * resource's caller or requester in which the load is happening.
    *
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -512,20 +512,24 @@ AutoJSAPI::StealException(JS::MutableHan
 AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
                                  bool aIsMainThread,
                                  JSContext* aCx)
   : AutoJSAPI(aGlobalObject, aIsMainThread,
               aCx ? aCx : FindJSContext(aGlobalObject))
   , ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
   , mWebIDLCallerPrincipal(nullptr)
   , mDocShellForJSRunToCompletion(nullptr)
+  , mIsMainThread(aIsMainThread)
 {
   MOZ_ASSERT(aGlobalObject);
   MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
   MOZ_ASSERT_IF(aCx && aIsMainThread, aCx == FindJSContext(aGlobalObject));
+  if (aIsMainThread) {
+    nsContentUtils::EnterMicroTask();
+  }
 
   if (aIsMainThread && gRunToCompletionListeners > 0) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobalObject);
     if (window) {
         mDocShellForJSRunToCompletion = window->GetDocShell();
     }
   }
 
@@ -535,16 +539,20 @@ AutoEntryScript::AutoEntryScript(nsIGlob
 }
 
 AutoEntryScript::~AutoEntryScript()
 {
   if (mDocShellForJSRunToCompletion) {
     mDocShellForJSRunToCompletion->NotifyJSRunToCompletionStop();
   }
 
+  if (mIsMainThread) {
+    nsContentUtils::LeaveMicroTask();
+  }
+
   // GC when we pop a script entry point. This is a useful heuristic that helps
   // us out on certain (flawed) benchmarks like sunspider, because it lets us
   // avoid GCing during the timing loop.
   JS_MaybeGC(cx());
 }
 
 AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
   : ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ false)
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -339,16 +339,18 @@ private:
   // the aIsJSImplementedWebIDL case.  And in that case, the subject principal
   // is the principal of the callee function that is part of the CallArgs just a
   // bit up the stack, and which will outlive us.  So we know the principal
   // can't go away until then either.
   nsIPrincipal* mWebIDLCallerPrincipal;
   friend nsIPrincipal* GetWebIDLCallerPrincipal();
 
   nsIDocShell* mDocShellForJSRunToCompletion;
+
+  bool mIsMainThread;
 };
 
 /*
  * A class that can be used to force a particular incumbent script on the stack.
  */
 class AutoIncumbentScript : protected ScriptSettingsStackEntry {
 public:
   explicit AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1465,17 +1465,19 @@ WebSocketImpl::InitializeConnection()
   // was not set during channel creation.
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mOriginDocument);
 
   // mOriginDocument has to be release on main-thread because WeakReferences
   // are not thread-safe.
   mOriginDocument = nullptr;
 
   nsCOMPtr<nsILoadInfo> loadInfo =
-    new LoadInfo(mPrincipal,
+    new LoadInfo(doc ?
+                   doc->NodePrincipal() : mPrincipal.get(),
+                 mPrincipal,
                  doc,
                  nsILoadInfo::SEC_NORMAL,
                  nsIContentPolicy::TYPE_WEBSOCKET);
   rv = wsChannel->SetLoadInfo(loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mRequestedProtocolList.IsEmpty()) {
     rv = wsChannel->SetProtocol(mRequestedProtocolList);
--- a/dom/base/nsCrossSiteListenerProxy.cpp
+++ b/dom/base/nsCrossSiteListenerProxy.cpp
@@ -1122,25 +1122,24 @@ NS_StartCORSPreflight(nsIChannel* aReque
     rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel),
                                uri,
                                loadInfo,
                                loadGroup,
                                nullptr,   // aCallbacks
                                loadFlags);
   }
   else {
-    rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel),
-                               uri,
-                               nullptr, // aRequestingNode,
-                               nsContentUtils::GetSystemPrincipal(),
-                               nsILoadInfo::SEC_NORMAL,
-                               nsIContentPolicy::TYPE_OTHER,
-                               loadGroup,
-                               nullptr,   // aCallbacks
-                               loadFlags);
+    rv = NS_NewChannel(getter_AddRefs(preflightChannel),
+                       uri,
+                       nsContentUtils::GetSystemPrincipal(),
+                       nsILoadInfo::SEC_NORMAL,
+                       nsIContentPolicy::TYPE_OTHER,
+                       loadGroup,
+                       nullptr,   // aCallbacks
+                       loadFlags);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIHttpChannel> preHttp = do_QueryInterface(preflightChannel);
   NS_ASSERTION(preHttp, "Failed to QI to nsIHttpChannel!");
 
   rv = preHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS"));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2098,17 +2098,17 @@ nsFrameLoader::TryRemoteBrowser()
   PROFILER_LABEL("nsFrameLoader", "CreateRemoteBrowser",
     js::ProfileEntry::Category::OTHER);
 
   MutableTabContext context;
   nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
   nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
   ScrollingBehavior scrollingBehavior = DEFAULT_SCROLLING;
 
-  if (Preferences::GetBool("dom.browser_frames.useAsyncPanZoom", false) ||
+  if (Preferences::GetBool("layers.async-pan-zoom.enabled", false) ||
       mOwnerContent->AttrValueIs(kNameSpaceID_None,
                                  nsGkAtoms::mozasyncpanzoom,
                                  nsGkAtoms::_true,
                                  eCaseMatters)) {
     scrollingBehavior = ASYNC_PAN_ZOOM;
   }
 
   bool rv = true;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -615,18 +615,16 @@ public:
                               JS::MutableHandle<JSPropertyDescriptor> desc)
                               const MOZ_OVERRIDE;
   virtual bool ownPropertyKeys(JSContext *cx,
                                JS::Handle<JSObject*> proxy,
                                JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id,
                        bool *bp) const MOZ_OVERRIDE;
-  virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
-                         JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool preventExtensions(JSContext *cx,
                                  JS::Handle<JSObject*> proxy,
                                  bool *succeeded) const MOZ_OVERRIDE;
   virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
                             const MOZ_OVERRIDE;
   virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
                    JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
   virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
@@ -644,16 +642,18 @@ public:
                                      JS::Handle<JSObject*> proxy,
                                      JS::Handle<jsid> id,
                                      JS::MutableHandle<JSPropertyDescriptor> desc)
                                      const MOZ_OVERRIDE;
   virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
                       JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
   virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
                                             JS::AutoIdVector &props) const MOZ_OVERRIDE;
+  virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
+                                         JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
                        unsigned flags,
                        JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
   virtual const char *className(JSContext *cx,
                                 JS::Handle<JSObject*> wrapper) const MOZ_OVERRIDE;
 
   virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
 
@@ -825,32 +825,16 @@ nsOuterWindowProxy::delete_(JSContext *c
     *bp = true;
     return true;
   }
 
   return js::Wrapper::delete_(cx, proxy, id, bp);
 }
 
 bool
-nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
-                              JS::AutoIdVector &props) const
-{
-  // Just our indexed stuff followed by our "normal" own property names.
-  if (!AppendIndexedPropertyNames(cx, proxy, props)) {
-    return false;
-  }
-
-  JS::AutoIdVector innerProps(cx);
-  if (!js::Wrapper::enumerate(cx, proxy, innerProps)) {
-    return false;
-  }
-  return js::AppendUnique(cx, props, innerProps);
-}
-
-bool
 nsOuterWindowProxy::preventExtensions(JSContext *cx,
                                       JS::Handle<JSObject*> proxy,
                                       bool *succeeded) const
 {
   // If [[Extensible]] could be false, then navigating a window could navigate
   // to a window that's [[Extensible]] after being at one that wasn't: an
   // invariant violation.  So never change a window's extensibility.
   *succeeded = false;
@@ -938,16 +922,33 @@ nsOuterWindowProxy::getOwnEnumerableProp
                                                  JS::AutoIdVector &props) const
 {
   // BaseProxyHandler::keys seems to do what we want here: call
   // ownPropertyKeys and then filter out the non-enumerable properties.
   return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
 }
 
 bool
+nsOuterWindowProxy::getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
+                                              JS::AutoIdVector &props) const
+{
+  // Just our indexed stuff followed by our "normal" own property names.
+  if (!AppendIndexedPropertyNames(cx, proxy, props)) {
+    return false;
+  }
+
+  JS::AutoIdVector innerProps(cx);
+  if (!js::Wrapper::getEnumerablePropertyKeys(cx, proxy, innerProps)) {
+    return false;
+  }
+  return js::AppendUnique(cx, props, innerProps);
+}
+
+
+bool
 nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
                             unsigned flags, JS::MutableHandle<JS::Value> vp) const
 {
   // BaseProxyHandler::iterate seems to do what we want here: fall
   // back on the property names returned from keys() and enumerate().
   return js::BaseProxyHandler::iterate(cx, proxy, flags, vp);
 }
 
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -203,17 +203,16 @@ nsJSUtils::EvaluateString(JSContext* aCx
   // Unfortunately, the JS engine actually compiles scripts with a return value
   // in a different, less efficient way.  Furthermore, it can't JIT them in many
   // cases.  So we need to be explicitly told whether the caller cares about the
   // return value.  Callers can do this by calling the other overload of
   // EvaluateString() which calls this function with aEvaluateOptions.needResult
   // set to false.
   aRetValue.setUndefined();
 
-  nsAutoMicroTask mt;
   nsresult rv = NS_OK;
 
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   NS_ENSURE_TRUE(ssm->ScriptAllowed(aEvaluationGlobal), NS_OK);
 
   mozilla::Maybe<AutoDontReportUncaught> dontReport;
   if (!aEvaluateOptions.reportUncaught) {
     // We need to prevent AutoLastFrameCheck from reporting and clearing
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -52,20 +52,16 @@ CallbackObject::CallSetup::CallSetup(Cal
                                      JSCompartment* aCompartment,
                                      bool aIsJSImplementedWebIDL)
   : mCx(nullptr)
   , mCompartment(aCompartment)
   , mErrorResult(aRv)
   , mExceptionHandling(aExceptionHandling)
   , mIsMainThread(NS_IsMainThread())
 {
-  if (mIsMainThread) {
-    nsContentUtils::EnterMicroTask();
-  }
-
   // Compute the caller's subject principal (if necessary) early, before we
   // do anything that might perturb the relevant state.
   nsIPrincipal* webIDLCallerPrincipal = nullptr;
   if (aIsJSImplementedWebIDL) {
     webIDLCallerPrincipal = nsContentUtils::SubjectPrincipal();
   }
 
   // We need to produce a useful JSContext here.  Ideally one that the callback
@@ -269,22 +265,16 @@ CallbackObject::CallSetup::~CallSetup()
       if (saved) {
         JS_RestoreFrameChain(mCx);
       }
     }
   }
 
   mAutoIncumbentScript.reset();
   mAutoEntryScript.reset();
-
-  // It is important that this is the last thing we do, after leaving the
-  // compartment and undoing all our entry/incumbent script changes
-  if (mIsMainThread) {
-    nsContentUtils::LeaveMicroTask();
-  }
 }
 
 already_AddRefed<nsISupports>
 CallbackObjectHolderBase::ToXPCOMCallback(CallbackObject* aCallback,
                                           const nsIID& aIID) const
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!aCallback) {
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -263,28 +263,16 @@ DOMProxyHandler::delete_(JSContext* cx, 
     return JS_DeletePropertyById2(cx, expando, id, bp);
   }
 
   *bp = true;
   return true;
 }
 
 bool
-BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
-                               AutoIdVector& props) const
-{
-  JS::Rooted<JSObject*> proto(cx);
-  if (!JS_GetPrototype(cx, proxy, &proto))  {
-    return false;
-  }
-  return getOwnEnumerablePropertyKeys(cx, proxy, props) &&
-         (!proto || js::GetPropertyKeys(cx, proto, 0, &props));
-}
-
-bool
 BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                            JS::Handle<JSObject*> callable) const
 {
   return js::WatchGuts(cx, proxy, id, callable);
 }
 
 bool
 BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const
@@ -304,16 +292,29 @@ bool
 BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
                                                   JS::Handle<JSObject*> proxy,
                                                   JS::AutoIdVector& props) const
 {
   return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool
+BaseDOMProxyHandler::getEnumerablePropertyKeys(JSContext* cx,
+                                               JS::Handle<JSObject*> proxy,
+                                               AutoIdVector& props) const
+{
+  JS::Rooted<JSObject*> proto(cx);
+  if (!JS_GetPrototype(cx, proxy, &proto))  {
+    return false;
+  }
+  return getOwnEnumerablePropertyKeys(cx, proxy, props) &&
+         (!proto || js::GetPropertyKeys(cx, proto, 0, &props));
+}
+
+bool
 DOMProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) const
 {
   if (!hasOwn(cx, proxy, id, bp)) {
     return false;
   }
 
   if (*bp) {
     // We have the property ourselves; no need to worry about our prototype
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -52,30 +52,30 @@ public:
 
   // Implementations of methods that can be implemented in terms of
   // other lower-level methods.
   bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
                                 JS::Handle<jsid> id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
   virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
                                JS::AutoIdVector &props) const MOZ_OVERRIDE;
-  bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
-                 JS::AutoIdVector& props) const MOZ_OVERRIDE;
 
   bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
                              JS::Handle<jsid> id,
                              JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
 
 
   // We override getOwnEnumerablePropertyKeys() and implement it directly
   // instead of using the default implementation, which would call
   // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
   // unnecessary work during enumeration.
   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
                                             JS::AutoIdVector &props) const MOZ_OVERRIDE;
+  bool getEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                 JS::AutoIdVector& props) const MOZ_OVERRIDE;
 
   bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
              JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
   bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
                JS::Handle<jsid> id) const MOZ_OVERRIDE;
 
 protected:
   // Hook for subclasses to implement shared ownPropertyKeys()/keys()
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -133,21 +133,20 @@ ToJSValue(JSContext* aCx,
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setObject(*aArgument.Callback());
 
   return MaybeWrapValue(aCx, aValue);
 }
 
-// Accept objects that inherit from nsWrapperCache and nsISupports (e.g. most
+// Accept objects that inherit from nsWrapperCache (e.g. most
 // DOM objects).
 template <class T>
-typename EnableIf<IsBaseOf<nsWrapperCache, T>::value &&
-                  IsBaseOf<nsISupports, T>::value, bool>::Type
+typename EnableIf<IsBaseOf<nsWrapperCache, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           T& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
   // Make sure non-webidl objects don't sneak in here
   MOZ_ASSERT(aArgument.IsDOMBinding());
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -152,17 +152,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
     // Get principal of code for execution
     nsCOMPtr<nsISupports> owner;
     aChannel->GetOwner(getter_AddRefs(owner));
     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner);
     if (!principal) {
         nsCOMPtr<nsILoadInfo> loadInfo;
         aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
         if (loadInfo && loadInfo->GetForceInheritPrincipal()) {
-            principal = loadInfo->LoadingPrincipal();
+            principal = loadInfo->TriggeringPrincipal();
         } else {
             // No execution without a principal!
             NS_ASSERTION(!owner, "Non-principal owner?");
             NS_WARNING("No principal to execute JS with");
             return NS_ERROR_DOM_RETVAL_UNDEFINED;
         }
     }
 
--- a/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
@@ -17,17 +17,16 @@ typedef mp4_demuxer::MP4Sample MP4Sample
 namespace mozilla
 {
 
 FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
-  , mConfig(aConfig)
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
   mExtraData.append(aConfig.audio_specific_config.begin(),
                     aConfig.audio_specific_config.length());
 }
 
 nsresult
 FFmpegAudioDecoder<LIBAV_VER>::Init()
--- a/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
@@ -30,14 +30,13 @@ public:
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   static AVCodecID GetCodecId(const char* aMimeType);
 
 private:
   void DecodePacket(mp4_demuxer::MP4Sample* aSample);
 
   MediaDataDecoderCallback* mCallback;
-  const mp4_demuxer::AudioDecoderConfig& mConfig;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegAACDecoder_h__
--- a/dom/media/gmp-plugin/Makefile.in
+++ b/dom/media/gmp-plugin/Makefile.in
@@ -2,11 +2,12 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 INSTALL_TARGETS += FAKE_GMP_PLUGIN
 FAKE_GMP_PLUGIN_DEST = $(DEPTH)/dist/bin/gmp-fake/1.0
 FAKE_GMP_PLUGIN_FILES = \
   $(SHARED_LIBRARY) \
-  $(srcdir)/fake.info
+  $(srcdir)/fake.info \
+  $(srcdir)/fake.voucher
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp-plugin/fake.voucher
@@ -0,0 +1,1 @@
+gmp-fake placeholder voucher
\ No newline at end of file
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -397,17 +397,17 @@ extern "C" {
   GMPGetAPI (const char* aApiName, void* aHostAPI, void** aPluginApi) {
     if (!strcmp (aApiName, "decode-video")) {
       *aPluginApi = new FakeVideoDecoder (static_cast<GMPVideoHost*> (aHostAPI));
       return GMPNoErr;
     } else if (!strcmp (aApiName, "encode-video")) {
       *aPluginApi = new FakeVideoEncoder (static_cast<GMPVideoHost*> (aHostAPI));
       return GMPNoErr;
     } else if (!strcmp (aApiName, "eme-decrypt")) {
-      *aPluginApi = new FakeDecryptor();
+      *aPluginApi = new FakeDecryptor(static_cast<GMPDecryptorHost*> (aHostAPI));
       return GMPNoErr;
     } else if (!strcmp (aApiName, "async-shutdown")) {
       *aPluginApi = new TestAsyncShutdown(static_cast<GMPAsyncShutdownHost*> (aHostAPI));
       return GMPNoErr;
     }
     return GMPGenericErr;
   }
 
--- a/dom/media/gmp-plugin/gmp-test-decryptor.cpp
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.cpp
@@ -29,18 +29,19 @@ static bool sMultiClientTest = false;
 void
 MaybeFinish()
 {
   if (sFinishedTruncateTest && sFinishedReplaceTest && sMultiClientTest) {
     FakeDecryptor::Message("test-storage complete");
   }
 }
 
-FakeDecryptor::FakeDecryptor()
+FakeDecryptor::FakeDecryptor(GMPDecryptorHost* aHost)
   : mCallback(nullptr)
+  , mHost(aHost)
 {
   MOZ_ASSERT(!sInstance);
   sInstance = this;
 }
 
 void FakeDecryptor::DecryptingComplete()
 {
   sInstance = nullptr;
@@ -323,16 +324,22 @@ FakeDecryptor::UpdateSession(uint32_t aP
       sShutdownMode = ShutdownStoreToken;
       sShutdownToken = tokens[2];
       Message("shutdown-token received " + sShutdownToken);
     }
   } else if (task == "retrieve-shutdown-token") {
     ReadRecord("shutdown-token", new ReportReadRecordContinuation("shutdown-token"));
   } else if (task == "test-op-apis") {
     mozilla::gmptest::TestOuputProtectionAPIs();
+  } else if (task == "retrieve-plugin-voucher") {
+    const uint8_t* rawVoucher = nullptr;
+    uint32_t length = 0;
+    mHost->GetPluginVoucher(&rawVoucher, &length);
+    std::string voucher((const char*)rawVoucher, (const char*)(rawVoucher + length));
+    Message("retrieved plugin-voucher: " + voucher);
   }
 }
 
 class CompleteShutdownTask : public GMPTask {
 public:
   explicit CompleteShutdownTask(GMPAsyncShutdownHost* aHost)
     : mHost(aHost)
   {
--- a/dom/media/gmp-plugin/gmp-test-decryptor.h
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.h
@@ -9,17 +9,17 @@
 #include "gmp-decryption.h"
 #include "gmp-async-shutdown.h"
 #include <string>
 #include "mozilla/Attributes.h"
 
 class FakeDecryptor : public GMPDecryptor {
 public:
 
-  FakeDecryptor();
+  FakeDecryptor(GMPDecryptorHost* aHost);
 
   virtual void Init(GMPDecryptorCallback* aCallback) MOZ_OVERRIDE {
     mCallback = aCallback;
   }
 
   virtual void CreateSession(uint32_t aPromiseId,
                              const char* aInitDataType,
                              uint32_t aInitDataTypeSize,
@@ -71,16 +71,17 @@ public:
 private:
 
   virtual ~FakeDecryptor() {}
   static FakeDecryptor* sInstance;
 
   void TestStorage();
 
   GMPDecryptorCallback* mCallback;
+  GMPDecryptorHost* mHost;
 };
 
 class TestAsyncShutdown : public GMPAsyncShutdown {
 public:
   explicit TestAsyncShutdown(GMPAsyncShutdownHost* aHost)
     : mHost(aHost)
   {
   }
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -1,71 +1,59 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPChild.h"
+#include "GMPProcessChild.h"
+#include "GMPLoader.h"
 #include "GMPVideoDecoderChild.h"
 #include "GMPVideoEncoderChild.h"
 #include "GMPAudioDecoderChild.h"
 #include "GMPDecryptorChild.h"
 #include "GMPVideoHost.h"
 #include "nsDebugImpl.h"
 #include "nsIFile.h"
 #include "nsXULAppAPI.h"
 #include "gmp-video-decode.h"
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
 #include "mozilla/dom/CrashReporterChild.h"
 #ifdef XP_WIN
-#include <fstream>
 #include "nsCRT.h"
 #endif
+#include <fstream>
 
 using mozilla::dom::CrashReporterChild;
 
+static const int MAX_PLUGIN_VOUCHER_LENGTH = 50000;
+
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #else
 #include <unistd.h> // for _exit()
 #endif
 
-#if defined(XP_WIN)
-// In order to provide EME plugins with a "device binding" capability,
-// in the parent we generate and store some random bytes as salt for every
-// (origin, urlBarOrigin) pair that uses EME. We store these bytes so
-// that every time we revisit the same origin we get the same salt.
-// We send this salt to the child on startup. The child collects some
-// device specific data and munges that with the salt to create the
-// "node id" that we expose to EME plugins. It then overwrites the device
-// specific data, and activates the sandbox.
-#define HASH_NODE_ID_WITH_DEVICE_ID 1
-#include "rlz/lib/machine_id.h"
-#include "rlz/lib/string_utils.h"
-#include "mozilla/SHA1.h"
-#endif
-
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #elif defined (MOZ_GMP_SANDBOX)
 #if defined(XP_LINUX) || defined(XP_MACOSX)
 #include "mozilla/Sandbox.h"
 #endif
 #endif
 
 namespace mozilla {
 namespace gmp {
 
 GMPChild::GMPChild()
   : mAsyncShutdown(nullptr)
-  , mLib(nullptr)
-  , mGetAPIFunc(nullptr)
   , mGMPMessageLoop(MessageLoop::current())
+  , mGMPLoader(nullptr)
 {
   nsDebugImpl::SetMultiprocessMode("GMP");
 }
 
 GMPChild::~GMPChild()
 {
 }
 
@@ -278,63 +266,30 @@ GMPChild::Init(const std::string& aPlugi
 
   mPluginPath = aPluginPath;
   return true;
 }
 
 bool
 GMPChild::RecvSetNodeId(const nsCString& aNodeId)
 {
-#ifdef HASH_NODE_ID_WITH_DEVICE_ID
-  if (!aNodeId.IsEmpty() && !aNodeId.EqualsLiteral("null")) {
-    string16 deviceId;
-    int volumeId;
-    if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) {
-      return false;
-    }
-
-    // TODO: Switch to SHA256.
-    mozilla::SHA1Sum hash;
-    hash.update(deviceId.c_str(), deviceId.size() * sizeof(string16::value_type));
-    hash.update(aNodeId.get(), aNodeId.Length());
-    hash.update(&volumeId, sizeof(int));
-    uint8_t digest[mozilla::SHA1Sum::kHashSize];
-    hash.finish(digest);
-    if (!rlz_lib::BytesToString(digest, mozilla::SHA1Sum::kHashSize, &mNodeId)) {
-      return false;
-    }
-
-    // Overwrite device id as it could potentially identify the user, so
-    // there's no chance a GMP can read it and use it for identity tracking.
-    volumeId = 0;
-    memset(&deviceId.front(), '*', sizeof(string16::value_type) * deviceId.size());
-    deviceId = L"";
-  } else {
-    mNodeId = "null";
-  }
-#else
+  // Store the per origin salt for the node id. Note: we do this in a
+  // separate message than RecvStartPlugin() so that the string is not
+  // sitting in a string on the IPC code's call stack.
   mNodeId = std::string(aNodeId.BeginReading(), aNodeId.EndReading());
-#endif
   return true;
 }
 
-bool
-GMPChild::RecvStartPlugin()
+GMPErr
+GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI)
 {
-#ifdef XP_WIN
-  PreLoadLibraries(mPluginPath);
-#endif
-
-#if defined(MOZ_SANDBOX) && defined(XP_WIN)
-  mozilla::SandboxTarget::Instance()->StartSandbox();
-#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-  StartMacSandbox();
-#endif
-
-  return LoadPluginLibrary(mPluginPath);
+  if (!mGMPLoader) {
+    return GMPGenericErr;
+  }
+  return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI);
 }
 
 #ifdef XP_WIN
 // Pre-load DLLs that need to be used by the EME plugin but that can't be
 // loaded after the sandbox has started
 bool
 GMPChild::PreLoadLibraries(const std::string& aPluginPath)
 {
@@ -387,74 +342,117 @@ GMPChild::PreLoadLibraries(const std::st
       break;
     }
   } while (!stream.eof());
 
   return true;
 }
 #endif
 
+#if defined(MOZ_GMP_SANDBOX)
+
+#if defined(XP_LINUX)
+class LinuxSandboxStarter : public SandboxStarter {
+public:
+  LinuxSandboxStarter(const std::string& aLibPath)
+    : mLibPath(aLibPath)
+  {}
+  virtual void Start() MOZ_OVERRIDE {
+    if (mozilla::MediaPluginSandboxStatus() != mozilla::kSandboxingWouldFail) {
+      mozilla::SetMediaPluginSandbox(mLibPath.c_str());
+    } else {
+      printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n",
+                    mLibPath.c_str());
+    }
+  }
+private:
+  std::string mLibPath;
+};
+#endif
+
+#if defined(XP_MACOSX)
+class MacOSXSandboxStarter : public SandboxStarter {
+public:
+  MacOSXSandboxStarter(GMPChild* aGMPChild)
+    : mGMPChild(aGMPChild)
+  {}
+  virtual void Start() MOZ_OVERRIDE {
+    mGMPChild->StartMacSandbox();
+  }
+private:
+  GMPChild* mGMPChild;
+};
+#endif
+
+#endif // MOZ_GMP_SANDBOX
+
 bool
-GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
+GMPChild::GetLibPath(nsACString& aOutLibPath)
 {
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-  nsAutoCString nativePath;
-  nativePath.Assign(mPluginBinaryPath);
-
-  mLib = PR_LoadLibrary(nativePath.get());
+  nsAutoCString pluginDirectoryPath, pluginFilePath;
+  if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
+    MOZ_CRASH("Error scanning plugin path");
+  }
+  aOutLibPath.Assign(pluginFilePath);
+  return true;
 #else
   nsCOMPtr<nsIFile> libFile;
-  if (!GetPluginFile(aPluginPath, libFile)) {
+  if (!GetPluginFile(mPluginPath, libFile)) {
     return false;
   }
-#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
-  nsAutoCString nativePath;
-  libFile->GetNativePath(nativePath);
+  return NS_SUCCEEDED(libFile->GetNativePath(aOutLibPath));
+#endif
+}
 
-  // Enable sandboxing here -- we know the plugin file's path, but
-  // this process's execution hasn't been affected by its content yet.
-  if (mozilla::MediaPluginSandboxStatus() != mozilla::kSandboxingWouldFail) {
-    mozilla::SetMediaPluginSandbox(nativePath.get());
-  } else {
-    printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n",
-                  nativePath.get());
-  }
-#endif // XP_LINUX && MOZ_GMP_SANDBOX
+bool
+GMPChild::RecvStartPlugin()
+{
+#if defined(XP_WIN)
+  PreLoadLibraries(mPluginPath);
+#endif
+  PreLoadPluginVoucher(mPluginPath);
 
-  libFile->Load(&mLib);
-#endif // XP_MACOSX && MOZ_GMP_SANDBOX
-
-  if (!mLib) {
-    NS_WARNING("Failed to link Gecko Media Plugin library.");
-    return false;
-  }
-
-  GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
-  if (!initFunc) {
-    NS_WARNING("Failed to link Gecko Media Plugin Init function.");
+  nsCString libPath;
+  if (!GetLibPath(libPath)) {
     return false;
   }
 
   auto platformAPI = new GMPPlatformAPI();
   InitPlatformAPI(*platformAPI, this);
 
-  if (initFunc(platformAPI) != GMPNoErr) {
-    NS_WARNING("Gecko Media Plugin failed to initialize.");
+  mGMPLoader = GMPProcessChild::GetGMPLoader();
+  if (!mGMPLoader) {
+    NS_WARNING("Failed to get GMPLoader");
     return false;
   }
 
-  mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
-  if (!mGetAPIFunc) {
-    NS_WARNING("Failed to link Gecko Media Plugin GetAPI function.");
+#if defined(MOZ_GMP_SANDBOX)
+#if defined(XP_MACOSX)
+  nsAutoPtr<SandboxStarter> starter(new MacOSXSandboxStarter(this));
+  mGMPLoader->SetStartSandboxStarter(starter);
+#elif defined(XP_LINUX)
+  nsAutoPtr<SandboxStarter> starter(new
+    LinuxSandboxStarter(std::string(libPath.get(), libPath.get()+libPath.Length())));
+  mGMPLoader->SetStartSandboxStarter(starter);
+#endif
+#endif // MOZ_GMP_SANDBOX
+
+  if (!mGMPLoader->Load(libPath.get(),
+                        libPath.Length(),
+                        &mNodeId[0],
+                        mNodeId.size(),
+                        platformAPI)) {
+    NS_WARNING("Failed to load GMP");
     return false;
   }
 
   void* sh = nullptr;
   GMPAsyncShutdownHost* host = static_cast<GMPAsyncShutdownHost*>(this);
-  GMPErr err = mGetAPIFunc("async-shutdown", host, &sh);
+  GMPErr err = GetAPI("async-shutdown", host, &sh);
   if (err == GMPNoErr && sh) {
     mAsyncShutdown = reinterpret_cast<GMPAsyncShutdown*>(sh);
     SendAsyncShutdownRequired();
   }
 
   return true;
 }
 
@@ -462,23 +460,19 @@ MessageLoop*
 GMPChild::GMPMessageLoop()
 {
   return mGMPMessageLoop;
 }
 
 void
 GMPChild::ActorDestroy(ActorDestroyReason aWhy)
 {
-  if (mLib) {
-    GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
-    if (shutdownFunc) {
-      shutdownFunc();
-    }
+  if (mGMPLoader) {
+    mGMPLoader->Shutdown();
   }
-
   if (AbnormalShutdown == aWhy) {
     NS_WARNING("Abnormal shutdown of GMP process!");
     _exit(0);
   }
 
   XRE_ShutdownChildProcess();
 }
 
@@ -542,17 +536,17 @@ GMPChild::DeallocPGMPVideoDecoderChild(P
 {
   delete aActor;
   return true;
 }
 
 PGMPDecryptorChild*
 GMPChild::AllocPGMPDecryptorChild()
 {
-  GMPDecryptorChild* actor = new GMPDecryptorChild(this, mNodeId);
+  GMPDecryptorChild* actor = new GMPDecryptorChild(this, mPluginVoucher);
   actor->AddRef();
   return actor;
 }
 
 bool
 GMPChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
 {
   static_cast<GMPDecryptorChild*>(aActor)->Release();
@@ -560,17 +554,17 @@ GMPChild::DeallocPGMPDecryptorChild(PGMP
 }
 
 bool
 GMPChild::RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor)
 {
   auto vdc = static_cast<GMPAudioDecoderChild*>(aActor);
 
   void* vd = nullptr;
-  GMPErr err = mGetAPIFunc("decode-audio", &vdc->Host(), &vd);
+  GMPErr err = GetAPI("decode-audio", &vdc->Host(), &vd);
   if (err != GMPNoErr || !vd) {
     return false;
   }
 
   vdc->Init(static_cast<GMPAudioDecoder*>(vd));
 
   return true;
 }
@@ -589,34 +583,34 @@ GMPChild::DeallocPGMPVideoEncoderChild(P
 }
 
 bool
 GMPChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor)
 {
   auto vdc = static_cast<GMPVideoDecoderChild*>(aActor);
 
   void* vd = nullptr;
-  GMPErr err = mGetAPIFunc("decode-video", &vdc->Host(), &vd);
+  GMPErr err = GetAPI("decode-video", &vdc->Host(), &vd);
   if (err != GMPNoErr || !vd) {
     NS_WARNING("GMPGetAPI call failed trying to construct decoder.");
     return false;
   }
 
   vdc->Init(static_cast<GMPVideoDecoder*>(vd));
 
   return true;
 }
 
 bool
 GMPChild::RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor)
 {
   auto vec = static_cast<GMPVideoEncoderChild*>(aActor);
 
   void* ve = nullptr;
-  GMPErr err = mGetAPIFunc("encode-video", &vec->Host(), &ve);
+  GMPErr err = GetAPI("encode-video", &vec->Host(), &ve);
   if (err != GMPNoErr || !ve) {
     NS_WARNING("GMPGetAPI call failed trying to construct encoder.");
     return false;
   }
 
   vec->Init(static_cast<GMPVideoEncoder*>(ve));
 
   return true;
@@ -624,17 +618,17 @@ GMPChild::RecvPGMPVideoEncoderConstructo
 
 bool
 GMPChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
 {
   GMPDecryptorChild* child = static_cast<GMPDecryptorChild*>(aActor);
   GMPDecryptorHost* host = static_cast<GMPDecryptorHost*>(child);
 
   void* session = nullptr;
-  GMPErr err = mGetAPIFunc("eme-decrypt", host, &session);
+  GMPErr err = GetAPI("eme-decrypt", host, &session);
   if (err != GMPNoErr || !session) {
     return false;
   }
 
   child->Init(static_cast<GMPDecryptor*>(session));
 
   return true;
 }
@@ -713,10 +707,61 @@ GMPChild::RecvBeginAsyncShutdown()
 
 void
 GMPChild::ShutdownComplete()
 {
   MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
   SendAsyncShutdownComplete();
 }
 
+static bool
+GetPluginVoucherFile(const std::string& aPluginPath,
+                     nsCOMPtr<nsIFile>& aOutVoucherFile)
+{
+  nsAutoString baseName;
+#if defined(XP_MACOSX)
+  nsCOMPtr<nsIFile> libDir;
+  GetFileBase(aPluginPath, aOutVoucherFile, libDir, baseName);
+#else
+  GetFileBase(aPluginPath, aOutVoucherFile, baseName);
+#endif
+  nsAutoString infoFileName = baseName + NS_LITERAL_STRING(".voucher");
+  aOutVoucherFile->AppendRelativePath(infoFileName);
+  return true;
+}
+
+bool
+GMPChild::PreLoadPluginVoucher(const std::string& aPluginPath)
+{
+  nsCOMPtr<nsIFile> voucherFile;
+  GetPluginVoucherFile(aPluginPath, voucherFile);
+
+  nsString path;
+  voucherFile->GetPath(path);
+
+  std::ifstream stream;
+  stream.open(NS_ConvertUTF16toUTF8(path).get(), std::ios::binary);
+  if (!stream.good()) {
+    return false;
+  }
+
+  std::streampos start = stream.tellg();
+  stream.seekg (0, std::ios::end);
+  std::streampos end = stream.tellg();
+  stream.seekg (0, std::ios::beg);
+  auto length = end - start;
+  if (length > MAX_PLUGIN_VOUCHER_LENGTH) {
+    NS_WARNING("Plugin voucher file too big!");
+    return false;
+  }
+
+  mPluginVoucher.SetLength(length);
+  stream.read((char*)mPluginVoucher.Elements(), length);
+  if (!stream) {
+    NS_WARNING("Failed to read plugin voucher file!");
+    return false;
+  }
+
+  return true;
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -5,16 +5,17 @@
 
 #ifndef GMPChild_h_
 #define GMPChild_h_
 
 #include "mozilla/gmp/PGMPChild.h"
 #include "GMPSharedMemManager.h"
 #include "GMPTimerChild.h"
 #include "GMPStorageChild.h"
+#include "GMPLoader.h"
 #include "gmp-async-shutdown.h"
 #include "gmp-entrypoints.h"
 #include "prlink.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPChild : public PGMPChild
@@ -24,38 +25,41 @@ class GMPChild : public PGMPChild
 public:
   GMPChild();
   virtual ~GMPChild();
 
   bool Init(const std::string& aPluginPath,
             base::ProcessHandle aParentProcessHandle,
             MessageLoop* aIOLoop,
             IPC::Channel* aChannel);
-  bool LoadPluginLibrary(const std::string& aPluginPath);
 #ifdef XP_WIN
   bool PreLoadLibraries(const std::string& aPluginPath);
 #endif
   MessageLoop* GMPMessageLoop();
 
   // Main thread only.
   GMPTimerChild* GetGMPTimers();
   GMPStorageChild* GetGMPStorage();
 
   // GMPSharedMem
   virtual void CheckThread() MOZ_OVERRIDE;
 
   // GMPAsyncShutdownHost
   void ShutdownComplete() MOZ_OVERRIDE;
 
-private:
-
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   void StartMacSandbox();
 #endif
 
+private:
+
+  bool PreLoadPluginVoucher(const std::string& aPluginPath);
+
+  bool GetLibPath(nsACString& aOutLibPath);
+
   virtual bool RecvSetNodeId(const nsCString& aNodeId) MOZ_OVERRIDE;
   virtual bool RecvStartPlugin() MOZ_OVERRIDE;
 
   virtual PCrashReporterChild* AllocPCrashReporterChild(const NativeThreadId& aThread) MOZ_OVERRIDE;
   virtual bool DeallocPCrashReporterChild(PCrashReporterChild*) MOZ_OVERRIDE;
 
   virtual PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() MOZ_OVERRIDE;
   virtual bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
@@ -80,26 +84,28 @@ private:
   virtual bool DeallocPGMPStorageChild(PGMPStorageChild* aActor) MOZ_OVERRIDE;
 
   virtual bool RecvCrashPluginNow() MOZ_OVERRIDE;
   virtual bool RecvBeginAsyncShutdown() MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
 
+  GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI);
+
   GMPAsyncShutdown* mAsyncShutdown;
   nsRefPtr<GMPTimerChild> mTimerChild;
   nsRefPtr<GMPStorageChild> mStorage;
 
-  PRLibrary* mLib;
-  GMPGetAPIFunc mGetAPIFunc;
   MessageLoop* mGMPMessageLoop;
   std::string mPluginPath;
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   nsCString mPluginBinaryPath;
 #endif
   std::string mNodeId;
+  GMPLoader* mGMPLoader;
+  nsTArray<uint8_t> mPluginVoucher;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPChild_h_
--- a/dom/media/gmp/GMPDecryptorChild.cpp
+++ b/dom/media/gmp/GMPDecryptorChild.cpp
@@ -21,20 +21,21 @@
         FROM_HERE, NewRunnableMethod(this, &GMPDecryptorChild::_func, __VA_ARGS__) \
       ); \
     } \
   } while(false)
 
 namespace mozilla {
 namespace gmp {
 
-GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin, const std::string& aNodeId)
+GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin,
+                                     const nsTArray<uint8_t>& aPluginVoucher)
   : mSession(nullptr)
   , mPlugin(aPlugin)
-  , mNodeId(aNodeId)
+  , mPluginVoucher(aPluginVoucher)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPDecryptorChild::~GMPDecryptorChild()
 {
 }
 
@@ -169,39 +170,36 @@ GMPDecryptorChild::Decrypted(GMPBuffer* 
 
 void
 GMPDecryptorChild::SetCapabilities(uint64_t aCaps)
 {
   CALL_ON_GMP_THREAD(SendSetCaps, aCaps);
 }
 
 void
-GMPDecryptorChild::GetNodeId(const char** aOutNodeId,
-                             uint32_t* aOutNodeIdLength)
+GMPDecryptorChild::GetSandboxVoucher(const uint8_t** aVoucher,
+                                     uint32_t* aVoucherLength)
 {
-  *aOutNodeId = mNodeId.c_str();
-  *aOutNodeIdLength = mNodeId.size();
-}
-
-void
-GMPDecryptorChild::GetSandboxVoucher(const uint8_t** aVoucher,
-                                     uint8_t* aVoucherLength)
-{
+  if (!aVoucher || !aVoucherLength) {
+    return;
+  }
   const char* voucher = "placeholder_sandbox_voucher.";
   *aVoucher = (uint8_t*)voucher;
   *aVoucherLength = strlen(voucher);
 }
 
 void
 GMPDecryptorChild::GetPluginVoucher(const uint8_t** aVoucher,
-                                    uint8_t* aVoucherLength)
+                                    uint32_t* aVoucherLength)
 {
-  const char* voucher = "placeholder_plugin_voucher.";
-  *aVoucher = (uint8_t*)voucher;
-  *aVoucherLength = strlen(voucher);
+  if (!aVoucher || !aVoucherLength) {
+    return;
+  }
+  *aVoucher = mPluginVoucher.Elements();
+  *aVoucherLength = mPluginVoucher.Length();
 }
 
 bool
 GMPDecryptorChild::RecvInit()
 {
   if (!mSession) {
     return false;
   }
--- a/dom/media/gmp/GMPDecryptorChild.h
+++ b/dom/media/gmp/GMPDecryptorChild.h
@@ -19,17 +19,18 @@ class GMPChild;
 
 class GMPDecryptorChild : public GMPDecryptorCallback
                         , public GMPDecryptorHost
                         , public PGMPDecryptorChild
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
 
-  explicit GMPDecryptorChild(GMPChild* aPlugin, const std::string& aNodeId);
+  explicit GMPDecryptorChild(GMPChild* aPlugin,
+                             const nsTArray<uint8_t>& aPluginVoucher);
 
   void Init(GMPDecryptor* aSession);
 
   // GMPDecryptorCallback
   virtual void ResolveNewSessionPromise(uint32_t aPromiseId,
                                         const char* aSessionId,
                                         uint32_t aSessionIdLength) MOZ_OVERRIDE;
   virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
@@ -72,24 +73,21 @@ public:
                               const uint8_t* aKeyId,
                               uint32_t aKeyIdLength) MOZ_OVERRIDE;
 
   virtual void SetCapabilities(uint64_t aCaps) MOZ_OVERRIDE;
 
   virtual void Decrypted(GMPBuffer* aBuffer, GMPErr aResult) MOZ_OVERRIDE;
 
   // GMPDecryptorHost
-  virtual void GetNodeId(const char** aOutNodeId,
-                         uint32_t* aOutNodeIdLength) MOZ_OVERRIDE;
-
   virtual void GetSandboxVoucher(const uint8_t** aVoucher,
-                                 uint8_t* aVoucherLength) MOZ_OVERRIDE;
+                                 uint32_t* aVoucherLength) MOZ_OVERRIDE;
 
   virtual void GetPluginVoucher(const uint8_t** aVoucher,
-                                uint8_t* aVoucherLength) MOZ_OVERRIDE;
+                                uint32_t* aVoucherLength) MOZ_OVERRIDE;
 private:
   ~GMPDecryptorChild();
 
   // GMPDecryptorChild
   virtual bool RecvInit() MOZ_OVERRIDE;
 
   virtual bool RecvCreateSession(const uint32_t& aPromiseId,
                                  const nsCString& aInitDataType,
@@ -119,15 +117,16 @@ private:
 
   virtual bool RecvDecryptingComplete() MOZ_OVERRIDE;
 
   // GMP's GMPDecryptor implementation.
   // Only call into this on the (GMP process) main thread.
   GMPDecryptor* mSession;
   GMPChild* mPlugin;
 
-  const std::string mNodeId;
+  // Reference to the voucher owned by the GMPChild.
+  const nsTArray<uint8_t>& mPluginVoucher;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPDecryptorChild_h_
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GMPLoader.h"
+#include <stdio.h>
+#include "mozilla/Attributes.h"
+#include "mozilla/NullPtr.h"
+#include "gmp-entrypoints.h"
+#include "prlink.h"
+
+#include <string>
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+#include "mozilla/sandboxTarget.h"
+#include "windows.h"
+#include <intrin.h>
+#include <assert.h>
+#endif
+
+#if defined(HASH_NODE_ID_WITH_DEVICE_ID)
+// In order to provide EME plugins with a "device binding" capability,
+// in the parent we generate and store some random bytes as salt for every
+// (origin, urlBarOrigin) pair that uses EME. We store these bytes so
+// that every time we revisit the same origin we get the same salt.
+// We send this salt to the child on startup. The child collects some
+// device specific data and munges that with the salt to create the
+// "node id" that we expose to EME plugins. It then overwrites the device
+// specific data, and activates the sandbox.
+#include "rlz/lib/machine_id.h"
+#include "rlz/lib/string_utils.h"
+#include "sha256.h"
+#endif
+
+namespace mozilla {
+namespace gmp {
+
+class GMPLoaderImpl : public GMPLoader {
+public:
+  explicit GMPLoaderImpl(SandboxStarter* aStarter)
+    : mSandboxStarter(aStarter)
+  {}
+  virtual ~GMPLoaderImpl() {}
+
+  virtual bool Load(const char* aLibPath,
+                    uint32_t aLibPathLen,
+                    char* aOriginSalt,
+                    uint32_t aOriginSaltLen,
+                    const GMPPlatformAPI* aPlatformAPI) MOZ_OVERRIDE;
+
+  virtual GMPErr GetAPI(const char* aAPIName,
+                        void* aHostAPI,
+                        void** aPluginAPI) MOZ_OVERRIDE;
+
+  virtual void Shutdown() MOZ_OVERRIDE;
+
+#ifdef SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER
+  virtual void SetStartSandboxStarter(SandboxStarter* aStarter) MOZ_OVERRIDE {
+    mSandboxStarter = aStarter;
+  }
+#endif
+
+private:
+  PRLibrary* mLib;
+  GMPGetAPIFunc mGetAPIFunc;
+  SandboxStarter* mSandboxStarter;
+};
+
+GMPLoader* CreateGMPLoader(SandboxStarter* aStarter) {
+  return static_cast<GMPLoader*>(new GMPLoaderImpl(aStarter));
+}
+
+#if defined(XP_WIN)
+MOZ_NEVER_INLINE
+static bool
+GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom)
+{
+  // "Top" of the free space on the stack is directly after the memory
+  // holding our return address.
+  uint8_t* top = (uint8_t*)_AddressOfReturnAddress();
+
+  // Look down the stack until we find the guard page...
+  MEMORY_BASIC_INFORMATION memInfo = {0};
+  uint8_t* bottom = top;
+  while (1) {
+    if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
+      return false;
+    }
+    if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) {
+      bottom = (uint8_t*)memInfo.BaseAddress + memInfo.RegionSize;
+#ifdef DEBUG
+      if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
+        return false;
+      }
+      assert(!(memInfo.Protect & PAGE_GUARD)); // Should have found boundary.
+#endif
+      break;
+    } else if (memInfo.State != MEM_COMMIT ||
+               (memInfo.AllocationProtect & PAGE_READWRITE) != PAGE_READWRITE) {
+      return false;
+    }
+    bottom = (uint8_t*)memInfo.BaseAddress - 1;
+  }
+  *aOutTop = top;
+  *aOutBottom = bottom;
+  return true;
+}
+#endif
+
+bool
+GMPLoaderImpl::Load(const char* aLibPath,
+                    uint32_t aLibPathLen,
+                    char* aOriginSalt,
+                    uint32_t aOriginSaltLen,
+                    const GMPPlatformAPI* aPlatformAPI)
+{
+  std::string nodeId;
+#ifdef HASH_NODE_ID_WITH_DEVICE_ID
+  if (aOriginSaltLen > 0) {
+    string16 deviceId;
+    int volumeId;
+    if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) {
+      return false;
+    }
+
+    SHA256Context ctx;
+    SHA256_Begin(&ctx);
+    SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen);
+    SHA256_Update(&ctx, (const uint8_t*)deviceId.c_str(), deviceId.size() * sizeof(string16::value_type));
+    SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int));
+    uint8_t digest[SHA256_LENGTH] = {0};
+    unsigned int digestLen = 0;
+    SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH);
+
+    // Overwrite all data involved in calculation as it could potentially
+    // identify the user, so there's no chance a GMP can read it and use
+    // it for identity tracking.
+    memset(&ctx, 0, sizeof(ctx));
+    memset(aOriginSalt, 0, aOriginSaltLen);
+    volumeId = 0;
+    memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size());
+    deviceId = L"";
+
+    if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) {
+      return false;
+    }
+    // We've successfully bound the origin salt to node id.
+    // rlz_lib::GetRawMachineId and/or the system functions it
+    // called could have left user identifiable data on the stack,
+    // so carefully zero the stack down to the guard page.
+    uint8_t* top;
+    uint8_t* bottom;
+    if (!GetStackAfterCurrentFrame(&top, &bottom)) {
+      return false;
+    }
+    assert(top >= bottom);
+    SecureZeroMemory(bottom, (top - bottom));
+  } else
+#endif
+  {
+    nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen);
+  }
+
+#if defined(MOZ_GMP_SANDBOX)
+  // Start the sandbox now that we've generated the device bound node id.
+  // This must happen after the node id is bound to the device id, as
+  // generating the device id requires privileges.
+  if (mSandboxStarter) {
+    mSandboxStarter->Start();
+  }
+#endif
+
+  // Load the GMP.
+  PRLibSpec libSpec;
+  libSpec.value.pathname = aLibPath;
+  libSpec.type = PR_LibSpec_Pathname;
+  mLib = PR_LoadLibraryWithFlags(libSpec, 0);
+  if (!mLib) {
+    return false;
+  }
+
+  GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
+  if (!initFunc) {
+    return false;
+  }
+
+  if (initFunc(aPlatformAPI) != GMPNoErr) {
+    return false;
+  }
+
+  GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId"));
+  if (setNodeIdFunc) {
+    setNodeIdFunc(nodeId.c_str(), nodeId.size());
+  }
+
+  mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
+  if (!mGetAPIFunc) {
+    return false;
+  }
+
+  return true;
+}
+
+GMPErr
+GMPLoaderImpl::GetAPI(const char* aAPIName,
+                      void* aHostAPI,
+                      void** aPluginAPI)
+{
+  return mGetAPIFunc ? mGetAPIFunc(aAPIName, aHostAPI, aPluginAPI)
+                     : GMPGenericErr;
+}
+
+void
+GMPLoaderImpl::Shutdown()
+{
+  if (mLib) {
+    GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
+    if (shutdownFunc) {
+      shutdownFunc();
+    }
+    PR_UnloadLibrary(mLib);
+    mLib = nullptr;
+  }
+}
+
+} // namespace gmp
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/GMPLoader.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMP_LOADER_H__
+#define GMP_LOADER_H__
+
+#include <stdint.h>
+#include "gmp-entrypoints.h"
+
+namespace mozilla {
+namespace gmp {
+
+class SandboxStarter {
+public:
+  virtual ~SandboxStarter() {}
+  virtual void Start() = 0;
+};
+
+#if (defined(XP_LINUX) || defined(XP_MACOSX))
+#define SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER 1
+#endif
+
+// Encapsulates generating the device-bound node id, activating the sandbox,
+// loading the GMP, and passing the node id to the GMP (in that order).
+//
+// In Desktop Gecko, the implementation of this lives in plugin-container,
+// and is passed into XUL code from on startup. The GMP IPC child protocol actor
+// uses this interface to load and retrieve interfaces from the GMPs.
+//
+// In Desktop Gecko the implementation lives in the plugin-container so that
+// it can be covered by DRM vendor's voucher.
+//
+// On Android the GMPLoader implementation lives in libxul (because for the time
+// being GMPLoader relies upon NSPR, which we can't use in plugin-container
+// on Android).
+//
+// There is exactly one GMPLoader per GMP child process, and only one GMP
+// per child process (so the GMPLoader only loads one GMP).
+class GMPLoader {
+public:
+  virtual ~GMPLoader() {}
+
+  // Calculates the device-bound node id, then activates the sandbox,
+  // then loads the GMP library and (if applicable) passes the bound node id
+  // to the GMP.
+  virtual bool Load(const char* aLibPath,
+                    uint32_t aLibPathLen,
+                    char* aOriginSalt,
+                    uint32_t aOriginSaltLen,
+                    const GMPPlatformAPI* aPlatformAPI) = 0;
+
+  // Retrieves an interface pointer from the GMP.
+  virtual GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) = 0;
+
+  // Calls the GMPShutdown function exported by the GMP lib, and unloads the
+  // plugin library.
+  virtual void Shutdown() = 0;
+
+#ifdef SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER
+  // Encapsulates starting the sandbox on Linux and MacOSX.
+  // TODO: Remove this, and put sandbox in plugin-container on all platforms.
+  virtual void SetStartSandboxStarter(SandboxStarter* aStarter) = 0;
+#endif
+};
+
+// On Desktop, this function resides in plugin-container.
+// On Mobile, this function resides in XUL.
+GMPLoader* CreateGMPLoader(SandboxStarter* aStarter);
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // GMP_LOADER_H__
--- a/dom/media/gmp/GMPProcessChild.cpp
+++ b/dom/media/gmp/GMPProcessChild.cpp
@@ -54,10 +54,26 @@ GMPProcessChild::Init()
 }
 
 void
 GMPProcessChild::CleanUp()
 {
   BackgroundHangMonitor::Shutdown();
 }
 
+GMPLoader* GMPProcessChild::mLoader = nullptr;
+
+/* static */
+void
+GMPProcessChild::SetGMPLoader(GMPLoader* aLoader)
+{
+  mLoader = aLoader;
+}
+
+/* static */
+GMPLoader*
+GMPProcessChild::GetGMPLoader()
+{
+  return mLoader;
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPProcessChild.h
+++ b/dom/media/gmp/GMPProcessChild.h
@@ -7,29 +7,37 @@
 #define GMPProcessChild_h_
 
 #include "mozilla/ipc/ProcessChild.h"
 #include "GMPChild.h"
 
 namespace mozilla {
 namespace gmp {
 
+class GMPLoader;
+
 class GMPProcessChild MOZ_FINAL : public mozilla::ipc::ProcessChild {
 protected:
   typedef mozilla::ipc::ProcessChild ProcessChild;
 
 public:
   explicit GMPProcessChild(ProcessHandle parentHandle);
   ~GMPProcessChild();
 
   virtual bool Init() MOZ_OVERRIDE;
   virtual void CleanUp() MOZ_OVERRIDE;
 
+  // Set/get the GMPLoader singleton for this child process.
+  // Note: The GMPLoader is not deleted by this object, the caller of
+  // SetGMPLoader() must manage the GMPLoader's lifecycle.
+  static void SetGMPLoader(GMPLoader* aHost);
+  static GMPLoader* GetGMPLoader();
+
 private:
   GMPChild mPlugin;
-
+  static GMPLoader* mLoader;
   DISALLOW_COPY_AND_ASSIGN(GMPProcessChild);
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPProcessChild_h_
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -177,32 +177,21 @@ public:
 
   // Returns decrypted buffer to Gecko, or reports failure.
   virtual void Decrypted(GMPBuffer* aBuffer, GMPErr aResult) = 0;
 };
 
 // Host interface, passed to GetAPIFunc(), with "decrypt".
 class GMPDecryptorHost {
 public:
-
-  // Returns an origin specific string uniquely identifying the device.
-  // The node id contains a random component, and is consistent between
-  // plugin instantiations, unless the user clears it.
-  // Different origins have different node ids.
-  // The node id pointer returned here remains valid for the until shutdown
-  // begins.
-  // *aOutNodeId is null terminated.
-  virtual void GetNodeId(const char** aOutNodeId,
-                         uint32_t* aOutNodeIdLength) = 0;
-
   virtual void GetSandboxVoucher(const uint8_t** aVoucher,
-                                 uint8_t* aVoucherLength) = 0;
+                                 uint32_t* aVoucherLength) = 0;
 
   virtual void GetPluginVoucher(const uint8_t** aVoucher,
-                                uint8_t* aVoucherLength) = 0;
+                                uint32_t* aVoucherLength) = 0;
 };
 
 enum GMPSessionType {
   kGMPTemporySession = 0,
   kGMPPersistentSession = 1,
   kGMPSessionInvalid = 2 // Must always be last.
 };
 
--- a/dom/media/gmp/gmp-api/gmp-entrypoints.h
+++ b/dom/media/gmp/gmp-api/gmp-entrypoints.h
@@ -58,9 +58,15 @@ typedef GMPErr (*GMPInitFunc)(const GMPP
 //   API object is defined by the API.
 typedef GMPErr (*GMPGetAPIFunc)(const char* aAPIName, void* aHostAPI, void** aPluginAPI);
 
 // GMPShutdown
 // - Called once before exiting process (unloading library).
 // - Called on main thread.
 typedef void   (*GMPShutdownFunc)(void);
 
+// GMPSetNodeId
+// - Optional, not required to be implemented. Only useful for EME plugins.
+// - Called after GMPInit to set the device-bound origin-specific node id
+//   that this GMP instance is running under.
+typedef void   (*GMPSetNodeIdFunc)(const char* aNodeId, uint32_t aLength);
+
 #endif // GMP_ENTRYPOINTS_h_
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -34,16 +34,17 @@ EXPORTS += [
     'GMPAudioDecoderProxy.h',
     'GMPAudioHost.h',
     'GMPCallbackBase.h',
     'GMPChild.h',
     'GMPDecryptorChild.h',
     'GMPDecryptorParent.h',
     'GMPDecryptorProxy.h',
     'GMPEncryptedBufferDataImpl.h',
+    'GMPLoader.h',
     'GMPMessageUtils.h',
     'GMPParent.h',
     'GMPPlatform.h',
     'GMPProcessChild.h',
     'GMPProcessParent.h',
     'GMPService.h',
     'GMPSharedMemManager.h',
     'GMPStorageChild.h',
@@ -57,16 +58,23 @@ EXPORTS += [
     'GMPVideoEncoderChild.h',
     'GMPVideoEncoderParent.h',
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
 ]
 
+# We link GMPLoader into xul on B2G/Fennec as its code does not need to be
+# covered by a DRM vendor's voucher.
+if CONFIG['OS_TARGET'] == 'Android':
+    SOURCES += [
+      'GMPLoader.cpp',
+    ]
+
 UNIFIED_SOURCES += [
     'GMPAudioDecoderChild.cpp',
     'GMPAudioDecoderParent.cpp',
     'GMPAudioHost.cpp',
     'GMPChild.cpp',
     'GMPDecryptorChild.cpp',
     'GMPDecryptorParent.cpp',
     'GMPEncryptedBufferDataImpl.cpp',
--- a/dom/media/gmp/rlz/moz.build
+++ b/dom/media/gmp/rlz/moz.build
@@ -2,19 +2,20 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Note: build rlz in its own moz.build, so it doesn't pickup any of
 # Chromium IPC's headers used in the moz.build of the parent file.
 
+Library('rlz')
+FORCE_STATIC_LIB = True
+USE_STATIC_LIBS = True
+
 UNIFIED_SOURCES += [
     'lib/string_utils.cc',
     'win/lib/machine_id_win.cc',
 ]
 
-FINAL_LIBRARY = 'xul'
-FAIL_ON_WARNINGS = True
-
 LOCAL_INCLUDES += [
     '..',
 ]
\ No newline at end of file
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -566,16 +566,25 @@ class GMPStorageTest : public GMPDecrypt
                     false);
 
     Expect(NS_LITERAL_CSTRING("OP tests completed"),
            NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
     Update(NS_LITERAL_CSTRING("test-op-apis"));
   }
 #endif
 
+  void TestPluginVoucher() {
+    CreateDecryptor(NS_LITERAL_STRING("example17.com"),
+                    NS_LITERAL_STRING("example18.com"),
+                    false);
+    Expect(NS_LITERAL_CSTRING("retrieved plugin-voucher: gmp-fake placeholder voucher"),
+           NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
+    Update(NS_LITERAL_CSTRING("retrieve-plugin-voucher"));
+  }
+
   void Expect(const nsCString& aMessage, nsIRunnable* aContinuation) {
     mExpected.AppendElement(ExpectedMessage(aMessage, aContinuation));
   }
 
   void AwaitFinished() {
     while (!mFinished) {
       NS_ProcessNextEvent(nullptr, true);
     }
@@ -721,16 +730,21 @@ TEST(GeckoMediaPlugins, GMPStorageAsyncS
   runner->DoTest(&GMPStorageTest::TestAsyncShutdownTimeout);
 }
 
 TEST(GeckoMediaPlugins, GMPStorageAsyncShutdownStorage) {
   nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestAsyncShutdownStorage);
 }
 
+TEST(GeckoMediaPlugins, GMPPluginVoucher) {
+  nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::TestPluginVoucher);
+}
+
 #if defined(XP_WIN)
 TEST(GeckoMediaPlugins, GMPOutputProtection) {
   // Output Protection is not available pre-Vista.
   if (!IsVistaOrLater()) {
     return;
   }
 
   nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -31,16 +31,17 @@
 #include "ChannelSplitterNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "WaveShaperNode.h"
 #include "PeriodicWave.h"
 #include "ConvolverNode.h"
 #include "OscillatorNode.h"
 #include "nsNetUtil.h"
 #include "AudioStream.h"
+#include "mozilla/dom/Promise.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioContext)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDestination)
@@ -433,49 +434,63 @@ AudioListener*
 AudioContext::Listener()
 {
   if (!mListener) {
     mListener = new AudioListener(this);
   }
   return mListener;
 }
 
-void
+already_AddRefed<Promise>
 AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
-                              DecodeSuccessCallback& aSuccessCallback,
+                              const Optional<OwningNonNull<DecodeSuccessCallback> >& aSuccessCallback,
                               const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback)
 {
+  ErrorResult rv;
+  nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
+  nsRefPtr<Promise> promise;
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
   JSAutoCompartment ac(cx, aBuffer.Obj());
 
+  promise = Promise::Create(parentObject, rv);
+  if (rv.Failed()) {
+    return nullptr;
+  }
+
   aBuffer.ComputeLengthAndData();
 
   // Neuter the array buffer
   size_t length = aBuffer.Length();
   JS::RootedObject obj(cx, aBuffer.Obj());
 
   uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
 
   // Sniff the content of the media.
   // Failed type sniffing will be handled by AsyncDecodeMedia.
   nsAutoCString contentType;
   NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
 
   nsRefPtr<DecodeErrorCallback> failureCallback;
+  nsRefPtr<DecodeSuccessCallback> successCallback;
   if (aFailureCallback.WasPassed()) {
     failureCallback = &aFailureCallback.Value();
   }
+  if (aSuccessCallback.WasPassed()) {
+    successCallback = &aSuccessCallback.Value();
+  }
   nsRefPtr<WebAudioDecodeJob> job(
     new WebAudioDecodeJob(contentType, this,
-                          &aSuccessCallback, failureCallback));
+                          promise, successCallback, failureCallback));
   mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job);
   // Transfer the ownership to mDecodeJobs
   mDecodeJobs.AppendElement(job.forget());
+
+  return promise.forget();
 }
 
 void
 AudioContext::RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob)
 {
   mDecodeJobs.RemoveElement(aDecodeJob);
 }
 
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -56,16 +56,17 @@ class MediaElementAudioSourceNode;
 class GlobalObject;
 class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
 class OscillatorNode;
 class PannerNode;
 class ScriptProcessorNode;
 class WaveShaperNode;
 class PeriodicWave;
+class Promise;
 
 class AudioContext MOZ_FINAL : public DOMEventTargetHelper,
                                public nsIMemoryReporter
 {
   AudioContext(nsPIDOMWindow* aParentWindow,
                bool aIsOffline,
                AudioChannel aChannel,
                uint32_t aNumberOfChannels = 0,
@@ -179,19 +180,20 @@ public:
 
   already_AddRefed<OscillatorNode>
   CreateOscillator();
 
   already_AddRefed<PeriodicWave>
   CreatePeriodicWave(const Float32Array& aRealData, const Float32Array& aImagData,
                      ErrorResult& aRv);
 
-  void DecodeAudioData(const ArrayBuffer& aBuffer,
-                       DecodeSuccessCallback& aSuccessCallback,
-                       const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback);
+  already_AddRefed<Promise>
+  DecodeAudioData(const ArrayBuffer& aBuffer,
+                  const Optional<OwningNonNull<DecodeSuccessCallback> >& aSuccessCallback,
+                  const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback);
 
   // OfflineAudioContext methods
   void StartRendering(ErrorResult& aRv);
   IMPL_EVENT_HANDLER(complete)
 
   bool IsOffline() const { return mIsOffline; }
 
   MediaStreamGraph* Graph() const;
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -16,16 +16,17 @@
 #include "DecoderTraits.h"
 #include "AudioContext.h"
 #include "AudioBuffer.h"
 #include "nsAutoPtr.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsMimeTypes.h"
 #include "WebAudioUtils.h"
+#include "mozilla/dom/Promise.h"
 #ifdef XP_WIN
 #include "ThreadPoolCOMListener.h"
 #endif
 
 namespace mozilla {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WebAudioDecodeJob)
 
@@ -507,26 +508,27 @@ MediaBufferDecoder::Shutdown() {
     // loop nor wait until this has happened.
     mThreadPool->SetThreadLimit(0);
     mThreadPool = nullptr;
   }
 }
 
 WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
                                      AudioContext* aContext,
+                                     Promise* aPromise,
                                      DecodeSuccessCallback* aSuccessCallback,
                                      DecodeErrorCallback* aFailureCallback)
   : mContentType(aContentType)
   , mWriteIndex(0)
   , mContext(aContext)
+  , mPromise(aPromise)
   , mSuccessCallback(aSuccessCallback)
   , mFailureCallback(aFailureCallback)
 {
   MOZ_ASSERT(aContext);
-  MOZ_ASSERT(aSuccessCallback);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(WebAudioDecodeJob);
 }
 
 WebAudioDecodeJob::~WebAudioDecodeJob()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_DTOR(WebAudioDecodeJob);
@@ -536,17 +538,20 @@ void
 WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aErrorCode == NoError);
 
   // Ignore errors in calling the callback, since there is not much that we can
   // do about it here.
   ErrorResult rv;
-  mSuccessCallback->Call(*mOutput, rv);
+  if (mSuccessCallback) {
+    mSuccessCallback->Call(*mOutput, rv);
+  }
+  mPromise->MaybeResolve(mOutput);
 
   mContext->RemoveFromDecodeQueue(this);
 }
 
 void
 WebAudioDecodeJob::OnFailure(ErrorCode aErrorCode)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -584,16 +589,18 @@ WebAudioDecodeJob::OnFailure(ErrorCode a
 
   // Ignore errors in calling the callback, since there is not much that we can
   // do about it here.
   if (mFailureCallback) {
     ErrorResult rv;
     mFailureCallback->Call(rv);
   }
 
+  mPromise->MaybeReject(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
+
   mContext->RemoveFromDecodeQueue(this);
 }
 
 size_t
 WebAudioDecodeJob::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t amount = 0;
   amount += mContentType.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
--- a/dom/media/webaudio/MediaBufferDecoder.h
+++ b/dom/media/webaudio/MediaBufferDecoder.h
@@ -17,24 +17,26 @@
 
 namespace mozilla {
 
 namespace dom {
 class AudioBuffer;
 class AudioContext;
 class DecodeErrorCallback;
 class DecodeSuccessCallback;
+class Promise;
 }
 
 struct WebAudioDecodeJob MOZ_FINAL
 {
   // You may omit both the success and failure callback, or you must pass both.
   // The callbacks are only necessary for asynchronous operation.
   WebAudioDecodeJob(const nsACString& aContentType,
                     dom::AudioContext* aContext,
+                    dom::Promise* aPromise,
                     dom::DecodeSuccessCallback* aSuccessCallback = nullptr,
                     dom::DecodeErrorCallback* aFailureCallback = nullptr);
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebAudioDecodeJob)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebAudioDecodeJob)
 
   enum ErrorCode {
     NoError,
@@ -53,16 +55,17 @@ struct WebAudioDecodeJob MOZ_FINAL
   bool AllocateBuffer();
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   nsCString mContentType;
   uint32_t mWriteIndex;
   nsRefPtr<dom::AudioContext> mContext;
+  nsRefPtr<dom::Promise> mPromise;
   nsRefPtr<dom::DecodeSuccessCallback> mSuccessCallback;
   nsRefPtr<dom::DecodeErrorCallback> mFailureCallback; // can be null
   nsRefPtr<dom::AudioBuffer> mOutput;
   FallibleTArray<ChannelBuffer> mChannelBuffers;
 
 private:
   ~WebAudioDecodeJob();
 };
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -82,16 +82,17 @@ skip-if = toolkit == 'android' # bug 105
 [test_channelSplitterNodeWithVolume.html]
 [test_convolverNode.html]
 [test_convolverNode_mono_mono.html]
 [test_convolverNodeChannelCount.html]
 [test_convolverNodePassThrough.html]
 [test_convolverNodeWithGain.html]
 [test_currentTime.html]
 [test_decodeMultichannel.html]
+[test_decodeAudioDataPromise.html]
 [test_delayNode.html]
 [test_delayNodeAtMax.html]
 [test_delayNodeChannelChanges.html]
 skip-if = toolkit == 'android' # bug 1056706
 [test_delayNodeCycles.html]
 [test_delayNodePassThrough.html]
 [test_delayNodeSmallMaxDelay.html]
 [test_delayNodeTailIncrease.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/test/test_decodeAudioDataPromise.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the decodeAudioData API with Promise</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script src="webaudio.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+
+var finished = 0;
+
+function finish() {
+  if (++finished == 2) {
+    SimpleTest.finish();
+  }
+}
+
+var ac = new AudioContext();
+// Test that a the promise is rejected with an invalid source buffer.
+expectNoException(function() {
+  var p = ac.decodeAudioData(" ");
+  ok(p instanceof Promise, "AudioContext.decodeAudioData should return a Promise");
+  p.then(function(data) {
+    ok(false, "Promise should not resolve with an invalid source buffer.");
+    finish();
+  }).catch(function(e) {
+    ok(true, "Promise should be rejected with an invalid source buffer.");
+    ok(e.name == "TypeError", "The error should be TypeError");
+    finish();
+  })
+});
+
+// Test that a the promise is resolved with a valid source buffer.
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "ting-44.1k-1ch.ogg", true);
+xhr.responseType = "arraybuffer";
+xhr.onload = function() {
+  var p = ac.decodeAudioData(xhr.response);
+  ok(p instanceof Promise, "AudioContext.decodeAudioData should return a Promise");
+  p.then(function(data) {
+    ok(data instanceof AudioBuffer, "Promise should resolve, passing an AudioBuffer");
+    ok(true, "Promise should resolve with a valid source buffer.");
+    finish();
+  }).catch(function() {
+    ok(false, "Promise should not be rejected with a valid source buffer.");
+    finish();
+  });
+};
+xhr.send();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webaudio/test/test_mediaDecoding.html
+++ b/dom/media/webaudio/test/test_mediaDecoding.html
@@ -354,38 +354,14 @@ function loadTest(test, callback) {
 function loadNextTest() {
   if (files.length) {
     loadTest(files.shift(), loadNextTest);
   } else {
     SimpleTest.finish();
   }
 }
 
-// Run some simple tests first
-function callbackShouldNeverRun() {
-  ok(false, "callback should not fire");
-}
-(function() {
-  var cx = new AudioContext();
-  expectTypeError(function() {
-    cx.decodeAudioData(null, callbackShouldNeverRun, callbackShouldNeverRun);
-  });
-  expectTypeError(function() {
-    cx.decodeAudioData(undefined, callbackShouldNeverRun, callbackShouldNeverRun);
-  });
-  expectTypeError(function() {
-    cx.decodeAudioData(123, callbackShouldNeverRun, callbackShouldNeverRun);
-  });
-  expectTypeError(function() {
-    cx.decodeAudioData("buffer", callbackShouldNeverRun, callbackShouldNeverRun);
-  });
-  expectTypeError(function() {
-    cx.decodeAudioData(new Uint8Array(100), callbackShouldNeverRun, callbackShouldNeverRun);
-  });
-})();
-
-// Now, let's get real!
 loadNextTest();
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -3065,33 +3065,45 @@ nsresult nsPluginHost::NewPluginURLStrea
   nsRefPtr<nsPluginStreamListenerPeer> listenerPeer = new nsPluginStreamListenerPeer();
   if (!listenerPeer)
     return NS_ERROR_OUT_OF_MEMORY;
 
   rv = listenerPeer->Initialize(url, aInstance, aListener);
   if (NS_FAILED(rv))
     return rv;
 
-  if (!principal) {
-    principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
   // @arg loadgroup:
   // do not add this internal plugin's channel on the
   // load group otherwise this channel could be canceled
   // form |nsDocShell::OnLinkClickSync| bug 166613
   nsCOMPtr<nsIChannel> channel;
-  rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                             url,
-                             doc,
-                             principal,
-                             nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
-                             nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
-                             nullptr,  // aLoadGroup 
-                             listenerPeer);
+  nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
+  if (requestingNode) {
+    rv = NS_NewChannel(getter_AddRefs(channel),
+                       url,
+                       requestingNode,
+                       nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+                       nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
+                       nullptr,  // aLoadGroup
+                       listenerPeer);
+  }
+  else {
+    // in this else branch we really don't know where the load is coming
+    // from and in fact should use something better than just using
+    // a nullPrincipal as the loadingPrincipal.
+    principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = NS_NewChannel(getter_AddRefs(channel),
+                       url,
+                       principal,
+                       nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+                       nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
+                       nullptr,  // aLoadGroup
+                       listenerPeer);
+  }
 
   if (NS_FAILED(rv))
     return rv;
 
   if (doc) {
     // And if it's a script allow it to execute against the
     // document's script context.
     nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPluginStreamListenerPeer.h"
+#include "nsIDOMElement.h"
 #include "nsIStreamConverterService.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIFileChannel.h"
 #include "nsMimeTypes.h"
 #include "nsISupportsPrimitives.h"
 #include "nsNetCID.h"
 #include "nsPluginLogging.h"
@@ -635,40 +636,54 @@ nsPluginStreamListenerPeer::RequestRead(
   MakeByteRangeString(rangeList, rangeString, &numRequests);
 
   if (numRequests == 0)
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
 
   nsRefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
+  nsCOMPtr<nsIDOMElement> element;
   nsCOMPtr<nsIDocument> doc;
   if (owner) {
+    rv = owner->GetDOMElement(getter_AddRefs(element));
+    NS_ENSURE_SUCCESS(rv, rv);
     rv = owner->GetDocument(getter_AddRefs(doc));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
 
-  nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
-  if (!principal) {
-    principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIChannel> channel;
+  nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
+  if (requestingNode) {
+    rv = NS_NewChannel(getter_AddRefs(channel),
+                       mURL,
+                       requestingNode,
+                       nsILoadInfo::SEC_NORMAL,
+                       nsIContentPolicy::TYPE_OTHER,
+                       loadGroup,
+                       callbacks);
   }
-
-  nsCOMPtr<nsIChannel> channel;
-  rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                             mURL,
-                             doc,
-                             principal,
-                             nsILoadInfo::SEC_NORMAL,
-                             nsIContentPolicy::TYPE_OTHER,
-                             loadGroup,
-                             callbacks);
+  else {
+    // in this else branch we really don't know where the load is coming
+    // from and in fact should use something better than just using
+    // a nullPrincipal as the loadingPrincipal.
+    nsCOMPtr<nsIPrincipal> principal =
+      do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = NS_NewChannel(getter_AddRefs(channel),
+                       mURL,
+                       principal,
+                       nsILoadInfo::SEC_NORMAL,
+                       nsIContentPolicy::TYPE_OTHER,
+                       loadGroup,
+                       callbacks);
+  }
 
   if (NS_FAILED(rv))
     return rv;
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (!httpChannel)
     return NS_ERROR_FAILURE;
 
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -20,19 +20,19 @@ interface AudioContext : EventTarget {
     readonly attribute AudioDestinationNode destination;
     readonly attribute float sampleRate;
     readonly attribute double currentTime;
     readonly attribute AudioListener listener;
 
     [NewObject, Throws]
     AudioBuffer createBuffer(unsigned long numberOfChannels, unsigned long length, float sampleRate);
 
-    void decodeAudioData(ArrayBuffer audioData,
-                         DecodeSuccessCallback successCallback,
-                         optional DecodeErrorCallback errorCallback);
+    Promise<AudioBuffer> decodeAudioData(ArrayBuffer audioData,
+                                         optional DecodeSuccessCallback successCallback,
+                                         optional DecodeErrorCallback errorCallback);
 
     // AudioNode creation
     [NewObject]
     AudioBufferSourceNode createBufferSource();
 
     [NewObject, Throws]
     MediaStreamAudioDestinationNode createMediaStreamDestination();
 
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -387,18 +387,16 @@ nsXBLProtoImplField::InstallField(JS::Ha
 
   *aDidInstall = false;
 
   // Empty fields are treated as not actually present.
   if (IsEmpty()) {
     return NS_OK;
   }
 
-  nsAutoMicroTask mt;
-
   nsAutoCString uriSpec;
   aBindingDocURI->GetSpec(uriSpec);
 
   nsIGlobalObject* globalObject = xpc::WindowGlobalOrNull(aBoundNode);
   if (!globalObject) {
     return NS_OK;
   }
 
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -287,18 +287,16 @@ nsXBLProtoImplAnonymousMethod::Execute(n
   nsIDocument* document = aBoundElement->OwnerDoc();
 
   nsCOMPtr<nsIGlobalObject> global =
     do_QueryInterface(document->GetInnerWindow());
   if (!global) {
     return NS_OK;
   }
 
-  nsAutoMicroTask mt;
-
   // We are going to run script via JS::Call, so we need a script entry point,
   // but as this is XBL related it does not appear in the HTML spec.
   dom::AutoEntryScript aes(global);
   JSContext* cx = aes.cx();
 
   JS::Rooted<JSObject*> globalObject(cx, global->GetGlobalJSObject());
 
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, aAddonId));
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -1068,28 +1068,37 @@ nsXBLService::FetchBindingDocument(nsICo
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Open channel
   // Note: There are some cases where aOriginPrincipal and aBoundDocument are purposely
   // set to null (to bypass security checks) when calling LoadBindingDocumentInfo() which calls
   // FetchBindingDocument().  LoadInfo will end up with no principal or node in those cases,
   // so we use systemPrincipal.  This achieves the same result of bypassing security checks,
   // but it gives the wrong information to potential future consumers of loadInfo.
-  nsCOMPtr<nsIPrincipal> requestingPrincipal = aOriginPrincipal ? aOriginPrincipal
-                                                                : nsContentUtils::GetSystemPrincipal();
   nsCOMPtr<nsIChannel> channel;
-  // Note that we are calling NS_NewChannelInternal here with both a node and a principal.
-  // This is because the principal and node could be different.
-  rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                             aDocumentURI,
-                             aBoundDocument,
-                             requestingPrincipal,
-                             nsILoadInfo::SEC_NORMAL,
-                             nsIContentPolicy::TYPE_OTHER,
-                             loadGroup);
+
+  if (aOriginPrincipal) {
+    // if there is an originPrincipal we should also have aBoundDocument
+    NS_ASSERTION(aBoundDocument, "can not create a channel without aBoundDocument");
+    rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
+                                              aDocumentURI,
+                                              aBoundDocument,
+                                              aOriginPrincipal,
+                                              nsILoadInfo::SEC_NORMAL,
+                                              nsIContentPolicy::TYPE_OTHER,
+                                              loadGroup);
+  }
+  else {
+    rv = NS_NewChannel(getter_AddRefs(channel),
+                       aDocumentURI,
+                       nsContentUtils::GetSystemPrincipal(),
+                       nsILoadInfo::SEC_NORMAL,
+                       nsIContentPolicy::TYPE_OTHER,
+                       loadGroup);
+  }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker();
   NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
 
   channel->SetNotificationCallbacks(sameOriginChecker);
 
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -3568,19 +3568,17 @@ XULDocument::ExecuteScript(nsXULPrototyp
 
     nsresult rv;
     rv = mScriptGlobalObject->EnsureScriptEnvironment();
     NS_ENSURE_SUCCESS(rv, rv);
 
     JS::HandleScript scriptObject = aScript->GetScriptObject();
     NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
 
-    // Execute the precompiled script with the given version
-    nsAutoMicroTask mt;
-
+    // Execute the precompiled script with the given version.
     // We're about to run script via JS::CloneAndExecuteScript, so we need an
     // AutoEntryScript. This is Gecko specific and not in any spec.
     AutoEntryScript aes(mScriptGlobalObject);
     aes.TakeOwnershipOfErrorReporting();
     JSContext* cx = aes.cx();
     JS::Rooted<JSObject*> baseGlobal(cx, JS::CurrentGlobalOrNull(cx));
     NS_ENSURE_TRUE(nsContentUtils::GetSecurityManager()->ScriptAllowed(baseGlobal), NS_OK);
 
--- a/gfx/doc/AsyncPanZoom.md
+++ b/gfx/doc/AsyncPanZoom.md
@@ -184,73 +184,82 @@ The thread that invokes this is called t
 <li value="2">
 Conceptually the first thing that the APZCTreeManager does is to group these events into "input blocks".
 An input block is a contiguous set of events that get handled together.
 For example with touch events, all events following a touchstart up to but not including the next touchstart are in the same block.
 All of the events in a given block will go to the same APZC instance and will either all be processed or all be dropped.
 </li>
 <li value="3">
 Using the first event in the input block, the APZCTreeManager does a hit-test to see which APZC it hits.
+This hit-test uses the event regions populated on the layers, which may be larger than the true hit area of the layer.
 If no APZC is hit, the events are discarded and we jump to step 6.
-Otherwise, the input block is tagged with the APZC and put into a global APZ input queue.
+Otherwise, the input block is tagged with the hit APZC as a tentative target and put into a global APZ input queue.
 </li>
 <li value="4">
  <ol>
   <li value="i">
-   If the input events are not touch events, or if the APZC is for content without touch listeners, any available events in the input block are processed.
+   If the input events landed outside the dispatch-to-content event region for the layer, any available events in the input block are processed.
    These may trigger behaviours like scrolling or tap gestures.
   </li>
   <li value="ii">
-   If the input events are touch events and the APZC is for content with touch listeners, the events are left in the queue and a 300ms timeout is initiated.
-   If the timeout expires before step 9 is completed, the APZ assumes the input block was not cancelled and processes them as part of step 10.
+   If the input events landed inside the dispatch-to-content event region for the layer, the events are left in the queue and a 300ms timeout is initiated.
+   If the timeout expires before step 9 is completed, the APZ assumes the input block was not cancelled and the tentative target is correct, and processes them as part of step 10.
   </li>
  </ol>
 </li>
 <li value="5">
 The call stack unwinds back to APZCTreeManager::ReceiveInputEvent, which does an in-place modification of the input event so that any async transforms are removed.
 </li>
 <li value="6">
 The call stack unwinds back to the widget code that called ReceiveInputEvent.
 This code now has the event in the coordinate space Gecko is expecting, and so can dispatch it to the Gecko main thread.
 </li>
 <li value="7">
 Gecko performs its own usual hit-testing and event dispatching for the event.
 As part of this, it records whether any touch listeners cancelled the input block by calling preventDefault().
+It also activates inactive scrollframes that were hit by the input events.
 </li>
 <li value="8">
-The call stack unwinds back to the widget code, which sends a notification to the APZ code by calling APZCTreeManager::ContentReceivedTouch on the input thread.
-This happens only once per input block.
+The call stack unwinds back to the widget code, which sends two notifications to the APZ code on the input thread.
+The first notification is via APZCTreeManager::ContentReceivedTouch, and informs the APZ whether the input block was cancelled.
+The second notification is via APZCTreeManager::SetTargetAPZC, and informs the APZ the results of the Gecko hit-test during event dispatch.
+Note that Gecko may report that the input event did not hit any scrollable frame at all.
+These notifications happen only once per input block.
 </li>
 <li value="9">
  <ol>
   <li value="i">
-   If the events were processed as part of step 4(i), the call to ContentReceivedTouch is ignored and step 10 is skipped.
+   If the events were processed as part of step 4(i), the notifications from step 8 are ignored and step 10 is skipped.
   </li>
   <li value="ii">
-   If events were queued as part of step 4(ii), and steps 5-8 take less than 300ms, the ContentReceivedTouch call marks the input block ready for processing.
+   If events were queued as part of step 4(ii), and steps 5-8 take less than 300ms, the arrival of both notifications from step 8 will mark the input block ready for processing.
   </li>
   <li value="iii">
-   If events were queued as part of step 4(ii), but steps 5-8 take longer than 300ms, the ContentReceivedTouch will be ignored and step 10 will already have happened.
+   If events were queued as part of step 4(ii), but steps 5-8 take longer than 300ms, the notifications from step 8 will be ignored and step 10 will already have happened.
   </li>
  </ol>
 </li>
 <li value="10">
-If events were queued as part of step 4(ii) they are now either processed (if the input block was not cancelled, or if the timeout expired) or dropped (if it was cancelled).
+If events were queued as part of step 4(ii) they are now either processed (if the input block was not cancelled and Gecko detected a scrollframe under the input event, or if the timeout expired) or dropped (all other cases).
+Note that the APZC that processes the events may be different at this step than the tentative target from step 3, depending on the SetTargetAPZC notification.
 Processing the events may trigger behaviours like scrolling or tap gestures.
 </li>
 </ol>
 
 If the CSS touch-action property is enabled, the above steps are modified as follows:
 <ul>
 <li>
  In step 4, the APZC also requires the allowed touch-action behaviours for the input event. This is not available yet, so the events are always queued.
 </li>
 <li>
  In step 6, the widget code determines the content element at the point under the input element, and notifies the APZ code of the allowed touch-action behaviours.
- This is done via a call to APZCTreeManager::SetAllowedTouchBehavior on the input thread.
+ This notification is sent via a call to APZCTreeManager::SetAllowedTouchBehavior on the input thread.
+</li>
+<li>
+ In step 9(ii), the input block will only be marked ready for processing once all three notifications arrive.
 </li>
 </ul>
 
 #### Threading considerations
 
 The bulk of the input processing in the APZ code happens on what we call "the input thread".
 In practice the input thread could be the Gecko main thread, the compositor thread, or some other thread.
 There are obvious downsides to using the Gecko main thread - that is, "asynchronous" panning and zooming is not really asynchronous as input events can only be processed while Gecko is idle.
@@ -264,19 +273,23 @@ As a result, the APZ code itself does no
 #### Active vs. inactive scrollframes
 
 The number of scrollframes on a page is potentially unbounded.
 However, we do not want to create a separate layer for each scrollframe right away, as this would require large amounts of memory.
 Therefore, scrollframes as designated as either "active" or "inactive".
 Active scrollframes are the ones that do have their contents put on a separate layer (or set of layers), and inactive ones do not.
 
 Consider a page with a scrollframe that is initially inactive.
-When layout generates the layers for this page, it inserts a "scrollinfo" layer into the layer tree to let the APZ know that there is potentially scrollable content there.
-The scrollinfo layer is an empty ContainerLayer, which does not require much extra memory.
-The composition bounds of this scrollinfo layer are used on the compositor for hit-testing, and a "placeholder" APZC is created for this scrollframe.
-When the user starts interacting with that content, the hit-test in the APZ code finds the placeholder APZC and starts routing it the events as usual.
-The APZC eventually sends a repaint request to the main thread, and that repaint request sets a displayport on the scrollframe.
-Setting the displayport activates the scrollframe and causes it to get pushed onto a separate layer (or set of layers).
+When layout generates the layers for this page, the content of the scrollframe will be flattened into some other PaintedLayer (call it P).
+The layout code also adds the area (or bounding region in case of weird shapes) of the scrollframe to the dispatch-to-content region of P.
 
-This model imples that when the user initially attempts to scroll an inactive scrollframe, it will not initially scroll visually.
-(This is because although the APZC is tracking the events and updating scroll position, there is no layer to which it can apply the async scroll offset.)
-Only after the round-trip to the gecko thread is complete is there a layer for async scrolling to actually occur.
-At that point the scrollframe will visually "jump" to the correct scroll offset.
+When the user starts interacting with that content, the hit-test in the APZ code finds the dispatch-to-content region of P.
+The input block therefore has a tentative target of P when it goes into step 4(ii) in the flow above.
+When gecko processes the input event, it must detect the inactive scrollframe and activate it, as part of step 7.
+Finally, the widget code sends the SetTargetAPZC notification in step 8 to notify the APZ that the input block should really apply to this new layer.
+The issue here is that the layer transaction containing the new layer must reach the compositor and APZ before the SetTargetAPZC notification.
+If this does not occur within the 300ms timeout, the APZ code will be unable to update the tentative target, and will continue to use P for that input block.
+Input blocks that start after the layer transaction will get correctly routed to the new layer as there will now be a layer and APZC instance for the active scrollframe.
+
+This model implies that when the user initially attempts to scroll an inactive scrollframe, it may end up scrolling an ancestor scrollframe.
+(This is because in the absence of the SetTargetAPZC notification, the input events will get applied to the closest ancestor scrollframe's APZC.)
+Only after the round-trip to the gecko thread is complete is there a layer for async scrolling to actually occur on the scrollframe itself.
+At that point the scrollframe will start receiving new input blocks and will scroll normally.
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -15,17 +15,16 @@
 #include "gfxColor.h"
 #include "nsString.h"
 
 namespace IPC {
 template <typename T> struct ParamTraits;
 } // namespace IPC
 
 namespace mozilla {
-
 namespace layers {
 
 /**
  * The viewport and displayport metrics for the painted frame at the
  * time of a layer-tree transaction.  These metrics are especially
  * useful for shadow layers, because the metrics values are updated
  * atomically with new pixels.
  */
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -294,16 +294,26 @@ public:
     MOZ_ASSERT(IsValid());
 
     if (AtBottomLayer()) {
       return mLayer->GetTransform();
     }
     return gfx::Matrix4x4();
   }
 
+  EventRegions GetEventRegions() const
+  {
+    MOZ_ASSERT(IsValid());
+
+    if (AtBottomLayer()) {
+      return mLayer->GetEventRegions();
+    }
+    return EventRegions();
+  }
+
   RefLayer* AsRefLayer() const
   {
     MOZ_ASSERT(IsValid());
 
     if (AtBottomLayer()) {
       return mLayer->AsRefLayer();
     }
     return nullptr;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1471,21 +1471,18 @@ Layer::PrintInfo(std::stringstream& aStr
   if (!mLayerBounds.IsEmpty()) {
     AppendToString(aStream, mLayerBounds, " [bounds=", "]");
   }
   if (!mVisibleRegion.IsEmpty()) {
     AppendToString(aStream, mVisibleRegion, " [visible=", "]");
   } else {
     aStream << " [not visible]";
   }
-  if (!mEventRegions.mHitRegion.IsEmpty()) {
-    AppendToString(aStream, mEventRegions.mHitRegion, " [hitregion=", "]");
-  }
-  if (!mEventRegions.mDispatchToContentHitRegion.IsEmpty()) {
-    AppendToString(aStream, mEventRegions.mDispatchToContentHitRegion, " [dispatchtocontentregion=", "]");
+  if (!mEventRegions.IsEmpty()) {
+    AppendToString(aStream, mEventRegions, " ", "");
   }
   if (1.0 != mOpacity) {
     aStream << nsPrintfCString(" [opacity=%g]", mOpacity).get();
   }
   if (GetContentFlags() & CONTENT_OPAQUE) {
     aStream << " [opaqueContent]";
   }
   if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -120,16 +120,30 @@ AppendToString(std::stringstream& aStrea
     aStream << "; ";
   }
   aStream << ">";
 
   aStream << sfx;
 }
 
 void
+AppendToString(std::stringstream& aStream, const EventRegions& e,
+               const char* pfx, const char* sfx)
+{
+  aStream << pfx << "{";
+  if (!e.mHitRegion.IsEmpty()) {
+    AppendToString(aStream, e.mHitRegion, " hitregion=", "");
+  }
+  if (!e.mDispatchToContentHitRegion.IsEmpty()) {
+    AppendToString(aStream, e.mDispatchToContentHitRegion, " dispatchtocontentregion=", "");
+  }
+  aStream << "}" << sfx;
+}
+
+void
 AppendToString(std::stringstream& aStream, const nsIntSize& sz,
                const char* pfx, const char* sfx)
 {
   aStream << pfx;
   aStream << nsPrintfCString("(w=%d, h=%d)", sz.width, sz.height).get();
   aStream << sfx;
 }
 
--- a/gfx/layers/LayersLogging.h
+++ b/gfx/layers/LayersLogging.h
@@ -93,16 +93,20 @@ AppendToString(std::stringstream& aStrea
   aStream << sfx;
 }
 
 void
 AppendToString(std::stringstream& aStream, const nsIntRegion& r,
                const char* pfx="", const char* sfx="");
 
 void
+AppendToString(std::stringstream& aStream, const EventRegions& e,
+               const char* pfx="", const char* sfx="");
+
+void
 AppendToString(std::stringstream& aStream, const nsIntSize& sz,
                const char* pfx="", const char* sfx="");
 
 void
 AppendToString(std::stringstream& aStream, const FrameMetrics& m,
                const char* pfx="", const char* sfx="", bool detailed = false);
 
 void
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -157,26 +157,65 @@ MOZ_BEGIN_ENUM_CLASS(ScaleMode, int8_t)
   SENTINEL
 // Unimplemented - PRESERVE_ASPECT_RATIO_CONTAIN
 MOZ_END_ENUM_CLASS(ScaleMode)
 
 struct EventRegions {
   nsIntRegion mHitRegion;
   nsIntRegion mDispatchToContentHitRegion;
 
+  EventRegions()
+  {
+  }
+
+  explicit EventRegions(nsIntRegion aHitRegion)
+    : mHitRegion(aHitRegion)
+  {
+  }
+
   bool operator==(const EventRegions& aRegions) const
   {
     return mHitRegion == aRegions.mHitRegion &&
            mDispatchToContentHitRegion == aRegions.mDispatchToContentHitRegion;
   }
   bool operator!=(const EventRegions& aRegions) const
   {
     return !(*this == aRegions);
   }
 
+  void OrWith(const EventRegions& aOther)
+  {
+    mHitRegion.OrWith(aOther.mHitRegion);
+    mDispatchToContentHitRegion.OrWith(aOther.mDispatchToContentHitRegion);
+  }
+
+  void AndWith(const nsIntRegion& aRegion)
+  {
+    mHitRegion.AndWith(aRegion);
+    mDispatchToContentHitRegion.AndWith(aRegion);
+  }
+
+  void Sub(const EventRegions& aMinuend, const nsIntRegion& aSubtrahend)
+  {
+    mHitRegion.Sub(aMinuend.mHitRegion, aSubtrahend);
+    mDispatchToContentHitRegion.Sub(aMinuend.mDispatchToContentHitRegion, aSubtrahend);
+  }
+
+  void Transform(const gfx3DMatrix& aTransform)
+  {
+    mHitRegion.Transform(aTransform);
+    mDispatchToContentHitRegion.Transform(aTransform);
+  }
+
+  bool IsEmpty() const
+  {
+    return mHitRegion.IsEmpty()
+        && mDispatchToContentHitRegion.IsEmpty();
+  }
+
   nsCString ToString() const
   {
     nsCString result = mHitRegion.ToString();
     result.AppendLiteral(";dispatchToContent=");
     result.Append(mDispatchToContentHitRegion.ToString());
     return result;
   }
 };
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -54,32 +54,33 @@ struct APZCTreeManager::TreeBuildingStat
   CompositorParent* const mCompositor;
   const bool mIsFirstPaint;
   const uint64_t mOriginatingLayersId;
   const APZPaintLogHelper mPaintLogger;
 
   // State that is updated as we perform the tree build
   nsTArray< nsRefPtr<AsyncPanZoomController> > mApzcsToDestroy;
   std::map<ScrollableLayerGuid, AsyncPanZoomController*> mApzcMap;
+  nsTArray<EventRegions> mEventRegions;
 };
 
 /*static*/ const ScreenMargin
 APZCTreeManager::CalculatePendingDisplayPort(
   const FrameMetrics& aFrameMetrics,
   const ParentLayerPoint& aVelocity,
   double aEstimatedPaintDuration)
 {
   return AsyncPanZoomController::CalculatePendingDisplayPort(
     aFrameMetrics, aVelocity, aEstimatedPaintDuration);
 }
 
 APZCTreeManager::APZCTreeManager()
     : mInputQueue(new InputQueue()),
       mTreeLock("APZCTreeLock"),
-      mInOverscrolledApzc(false),
+      mHitResultForInputBlock(NoApzcHit),
       mRetainedTouchIdentifier(-1),
       mTouchCount(0),
       mApzcTreeLog("apzctree")
 {
   MOZ_ASSERT(NS_IsMainThread());
   AsyncPanZoomController::InitializeGlobalState();
   mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
 }
@@ -173,16 +174,17 @@ APZCTreeManager::UpdatePanZoomController
     mApzcTreeLog << "[start]\n";
     LayerMetricsWrapper root(aRoot);
     UpdatePanZoomControllerTree(state, root,
                                 // aCompositor is null in gtest scenarios
                                 aCompositor ? aCompositor->RootLayerTreeId() : 0,
                                 Matrix4x4(), nullptr, nullptr, nsIntRegion());
     mApzcTreeLog << "[end]\n";
   }
+  MOZ_ASSERT(state.mEventRegions.Length() == 0);
 
   for (size_t i = 0; i < state.mApzcsToDestroy.Length(); i++) {
     APZCTM_LOG("Destroying APZC at %p\n", state.mApzcsToDestroy[i].get());
     state.mApzcsToDestroy[i]->Destroy();
   }
 }
 
 static nsIntRegion
@@ -209,21 +211,18 @@ ComputeTouchSensitiveRegion(GeckoContent
     visible = visible.Intersect(touchSensitiveRegion
                                 * aMetrics.mDevPixelsPerCSSPixel
                                 * parentCumulativeResolution);
   }
 
   // Not sure what rounding option is the most correct here, but if we ever
   // figure it out we can change this. For now I'm rounding in to minimize
   // the chances of getting a complex region.
-  ParentLayerIntRect roundedVisible = RoundedIn(visible);
   nsIntRegion unobscured;
-  unobscured.Sub(nsIntRect(roundedVisible.x, roundedVisible.y,
-                           roundedVisible.width, roundedVisible.height),
-                 aObscured);
+  unobscured.Sub(ParentLayerIntRect::ToUntyped(RoundedIn(visible)), aObscured);
   return unobscured;
 }
 
 void
 APZCTreeManager::PrintAPZCInfo(const LayerMetricsWrapper& aLayer,
                                const AsyncPanZoomController* apzc)
 {
   const FrameMetrics& metrics = aLayer.Metrics();
@@ -321,18 +320,21 @@ APZCTreeManager::PrepareAPZCForLayer(con
       apzc->SetPrevSibling(nullptr);
       apzc->SetLastChild(nullptr);
     }
     APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
 
     apzc->NotifyLayersUpdated(aMetrics,
         aState.mIsFirstPaint && (aLayersId == aState.mOriginatingLayersId));
 
-    nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
-    apzc->SetLayerHitTestData(unobscured, aAncestorTransform);
+    nsIntRegion unobscured;
+    if (!gfxPrefs::LayoutEventRegionsEnabled()) {
+      unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
+    }
+    apzc->SetLayerHitTestData(EventRegions(unobscured), aAncestorTransform);
     APZCTM_LOG("Setting region %s as visible region for APZC %p\n",
         Stringify(unobscured).c_str(), apzc);
 
     PrintAPZCInfo(aLayer, apzc);
 
     // Bind the APZC instance into the tree of APZCs
     if (aNextSibling) {
       aNextSibling->SetPrevSibling(apzc);
@@ -385,24 +387,39 @@ APZCTreeManager::PrepareAPZCForLayer(con
     // Consider the case where we have three layers: A, B, and C. A is at the top in
     // z-order and C is at the bottom. A and C share a scrollid and scroll together; but
     // B has a different scrollid and scrolls independently. Depending on how B moves
     // and the async transform on it, a larger/smaller area of C may be unobscured.
     // However, when we combine the hit regions of A and C here we are ignoring the async
     // async transform and so we basically assume the same amount of C is always visible
     // on top of B. Fixing this doesn't appear to be very easy so I'm leaving it for
     // now in the hopes that we won't run into this problem a lot.
-    nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
-    apzc->AddHitTestRegion(unobscured);
-    APZCTM_LOG("Adding region %s to visible region of APZC %p\n", Stringify(unobscured).c_str(), apzc);
+    if (!gfxPrefs::LayoutEventRegionsEnabled()) {
+      nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
+      apzc->AddHitTestRegions(EventRegions(unobscured));
+      APZCTM_LOG("Adding region %s to visible region of APZC %p\n", Stringify(unobscured).c_str(), apzc);
+    }
   }
 
   return apzc;
 }
 
+static EventRegions
+EventRegionsFor(const LayerMetricsWrapper& aLayer)
+{
+  // This is a workaround for bug 1082594. We should be able to replace this
+  // with just a call to aLayer.GetEventRegions() once that bug is fixed.
+  if (aLayer.IsScrollInfoLayer()) {
+    EventRegions regions(ParentLayerIntRect::ToUntyped(RoundedIn(aLayer.Metrics().mCompositionBounds)));
+    regions.mDispatchToContentHitRegion = regions.mHitRegion;
+    return regions;
+  }
+  return aLayer.GetEventRegions();
+}
+
 AsyncPanZoomController*
 APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
                                              const LayerMetricsWrapper& aLayer,
                                              uint64_t aLayersId,
                                              const gfx::Matrix4x4& aAncestorTransform,
                                              AsyncPanZoomController* aParent,
                                              AsyncPanZoomController* aNextSibling,
                                              const nsIntRegion& aObscured)
@@ -455,33 +472,119 @@ APZCTreeManager::UpdatePanZoomController
   AsyncPanZoomController* next = aNextSibling;
   if (apzc) {
     // Otherwise, use this APZC as the parent going downwards, and start off
     // with its first child as the next sibling
     aParent = apzc;
     next = apzc->GetFirstChild();
   }
 
+  // In our recursive downward traversal, track event regions for layers once
+  // we encounter an APZC. Push a new empty region on the mEventRegions stack
+  // which will accumulate the hit area of descendants of aLayer. In general,
+  // the mEventRegions stack is used to accumulate event regions from descendant
+  // layers because the event regions for a layer don't include those of its
+  // children.
+  if (gfxPrefs::LayoutEventRegionsEnabled() && (apzc || aState.mEventRegions.Length() > 0)) {
+    aState.mEventRegions.AppendElement(EventRegions());
+  }
+
   for (LayerMetricsWrapper child = aLayer.GetLastChild(); child; child = child.GetPrevSibling()) {
     gfx::TreeAutoIndent indent(mApzcTreeLog);
     next = UpdatePanZoomControllerTree(aState, child, childLayersId,
                                        ancestorTransform, aParent, next,
                                        obscured);
 
     // Each layer obscures its previous siblings, so we augment the obscured
     // region as we loop backwards through the children.
-    nsIntRegion childRegion = child.GetVisibleRegion();
+    nsIntRegion childRegion;
+    if (gfxPrefs::LayoutEventRegionsEnabled()) {
+      childRegion = EventRegionsFor(child).mHitRegion;
+    } else {
+      childRegion = child.GetVisibleRegion();
+    }
     childRegion.Transform(gfx::To3DMatrix(child.GetTransform()));
     if (child.GetClipRect()) {
       childRegion.AndWith(*child.GetClipRect());
     }
 
     obscured.OrWith(childRegion);
   }
 
+  if (gfxPrefs::LayoutEventRegionsEnabled() && aState.mEventRegions.Length() > 0) {
+    // At this point in the code, aState.mEventRegions.LastElement() contains
+    // the accumulated regions of the non-APZC descendants of |aLayer|. This
+    // happened in the loop above while we iterated through the descendants of
+    // |aLayer|. Note that it only includes the non-APZC descendants, because
+    // if a layer has an APZC, we simply store the regions from that subtree on
+    // that APZC and don't propagate them upwards in the tree. Because of the
+    // way we do hit-testing (where the deepest matching APZC is used) it should
+    // still be ok if we did propagate those regions upwards and included them
+    // in all the ancestor APZCs.
+    //
+    // Also at this point in the code the |obscured| region includes the hit
+    // regions of children of |aLayer| as well as the hit regions of |aLayer|'s
+    // younger uncles (i.e. the next-sibling chain of |aLayer|'s parent).
+    // When we compute the unobscured regions below, we subtract off the
+    // |obscured| region, but it would also be ok to do this before the above
+    // loop. At that point |obscured| would only have the uncles' hit regions
+    // and not the children. The reason this is ok is again because of the way
+    // we do hit-testing (where the deepest APZC is used) it doesn't matter if
+    // we count the children as obscuring the parent or not.
+
+    EventRegions unobscured;
+    unobscured.Sub(EventRegionsFor(aLayer), obscured);
+    APZCTM_LOG("Picking up unobscured hit region %s from layer %p\n", Stringify(unobscured).c_str(), aLayer.GetLayer());
+
+    // Take the hit region of the |aLayer|'s subtree (which has already been
+    // transformed into the coordinate space of |aLayer|) and...
+    EventRegions subtreeEventRegions = aState.mEventRegions.LastElement();
+    aState.mEventRegions.RemoveElementAt(aState.mEventRegions.Length() - 1);
+    // ... combine it with the hit region for this layer, and then ...
+    subtreeEventRegions.OrWith(unobscured);
+    // ... transform it up to the parent layer's coordinate space.
+    subtreeEventRegions.Transform(To3DMatrix(aLayer.GetTransform()));
+    if (aLayer.GetClipRect()) {
+      subtreeEventRegions.AndWith(*aLayer.GetClipRect());
+    }
+
+    APZCTM_LOG("After processing layer %p the subtree hit region is %s\n", aLayer.GetLayer(), Stringify(subtreeEventRegions).c_str());
+
+    // If we have an APZC at this level, intersect the subtree hit region with
+    // the touch-sensitive region and add it to the APZ's hit test regions.
+    if (apzc) {
+      APZCTM_LOG("Adding region %s to visible region of APZC %p\n", Stringify(subtreeEventRegions).c_str(), apzc);
+      const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
+      MOZ_ASSERT(state);
+      MOZ_ASSERT(state->mController.get());
+      CSSRect touchSensitiveRegion;
+      if (state->mController->GetTouchSensitiveRegion(&touchSensitiveRegion)) {
+        // Here we assume 'touchSensitiveRegion' is in the CSS pixels of the
+        // parent frame. To convert it to ParentLayer pixels, we therefore need
+        // the cumulative resolution of the parent frame. We approximate this as
+        // the quotient of our cumulative resolution and our pres shell
+        // resolution; this approximation may not be accurate in the presence of
+        // a css-driven resolution.
+        LayoutDeviceToParentLayerScale parentCumulativeResolution =
+            aLayer.Metrics().mCumulativeResolution
+            / ParentLayerToLayerScale(aLayer.Metrics().mPresShellResolution);
+        subtreeEventRegions.AndWith(ParentLayerIntRect::ToUntyped(
+            RoundedIn(touchSensitiveRegion
+                    * aLayer.Metrics().mDevPixelsPerCSSPixel
+                    * parentCumulativeResolution)));
+      }
+      apzc->AddHitTestRegions(subtreeEventRegions);
+    } else {
+      // If we don't have an APZC at this level, carry the subtree hit region
+      // up to the parent.
+      MOZ_ASSERT(aState.mEventRegions.Length() > 0);
+      aState.mEventRegions.LastElement().OrWith(subtreeEventRegions);
+    }
+  }
+
   // Return the APZC that should be the sibling of other APZCs as we continue
   // moving towards the first child at this depth in the layer tree.
   // If this layer doesn't have an APZC, we promote any APZCs in the subtree
   // upwards. Otherwise we fall back to the aNextSibling that was passed in.
   if (apzc) {
     return apzc;
   }
   if (next) {
@@ -497,87 +600,99 @@ APZCTreeManager::ReceiveInputEvent(Input
 {
   // Initialize aOutInputBlockId to a sane value, and then later we overwrite
   // it if the input event goes into a block.
   if (aOutInputBlockId) {
     *aOutInputBlockId = InputBlockState::NO_BLOCK_ID;
   }
   nsEventStatus result = nsEventStatus_eIgnore;
   Matrix4x4 transformToApzc;
-  bool inOverscrolledApzc = false;
+  HitTestResult hitResult = NoApzcHit;
   switch (aEvent.mInputType) {
     case MULTITOUCH_INPUT: {
       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
       break;
     } case PANGESTURE_INPUT: {
       PanGestureInput& panInput = aEvent.AsPanGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
-                                                            &inOverscrolledApzc);
+                                                            &hitResult);
       if (apzc) {
+        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         panInput.mLocalPanStartPoint = TransformTo<ParentLayerPixel>(
             transformToApzc, panInput.mPanStartPoint);
         panInput.mLocalPanDisplacement = TransformVector<ParentLayerPixel>(
             transformToApzc, panInput.mPanDisplacement, panInput.mPanStartPoint);
-        result = mInputQueue->ReceiveInputEvent(apzc, panInput, aOutInputBlockId);
+        result = mInputQueue->ReceiveInputEvent(
+            apzc,
+            /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+            panInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 transformToGecko = transformToApzc * GetApzcToGeckoTransform(apzc);
         panInput.mPanStartPoint = TransformTo<ScreenPixel>(
             transformToGecko, panInput.mPanStartPoint);
         panInput.mPanDisplacement = TransformVector<ScreenPixel>(
             transformToGecko, panInput.mPanDisplacement, panInput.mPanStartPoint);
       }
       break;
     } case PINCHGESTURE_INPUT: {  // note: no one currently sends these
       PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint,
-                                                            &inOverscrolledApzc);
+                                                            &hitResult);
       if (apzc) {
+        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         pinchInput.mLocalFocusPoint = TransformTo<ParentLayerPixel>(
             transformToApzc, pinchInput.mFocusPoint);
-        result = mInputQueue->ReceiveInputEvent(apzc, pinchInput, aOutInputBlockId);
+        result = mInputQueue->ReceiveInputEvent(
+            apzc,
+            /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+            pinchInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 outTransform = transformToApzc * GetApzcToGeckoTransform(apzc);
         pinchInput.mFocusPoint = TransformTo<ScreenPixel>(
             outTransform, pinchInput.mFocusPoint);
       }
       break;
     } case TAPGESTURE_INPUT: {  // note: no one currently sends these
       TapGestureInput& tapInput = aEvent.AsTapGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(tapInput.mPoint,
-                                                            &inOverscrolledApzc);
+                                                            &hitResult);
       if (apzc) {
+        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         tapInput.mLocalPoint = TransformTo<ParentLayerPixel>(
             transformToApzc, tapInput.mPoint);
-        result = mInputQueue->ReceiveInputEvent(apzc, tapInput, aOutInputBlockId);
+        result = mInputQueue->ReceiveInputEvent(
+            apzc,
+            /* aTargetConfirmed = */ hitResult == ApzcHitRegion,
+            tapInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         Matrix4x4 outTransform = transformToApzc * GetApzcToGeckoTransform(apzc);
         tapInput.mPoint = TransformTo<ScreenPixel>(outTransform, tapInput.mPoint);
       }
       break;
     }
   }
-  if (inOverscrolledApzc) {
+  if (hitResult == OverscrolledApzc) {
     result = nsEventStatus_eConsumeNoDefault;
   }
   return result;
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
-                                        bool* aOutInOverscrolledApzc)
+                                        HitTestResult* aOutHitResult)
 {
   nsRefPtr<AsyncPanZoomController> apzc;
   if (aEvent.mTouches.Length() == 0) {
     return apzc.forget();
   }
 
   { // In this block we flush repaint requests for the entire APZ tree. We need to do this
     // at the start of an input block for a number of reasons. One of the reasons is so that
@@ -588,19 +703,19 @@ APZCTreeManager::GetTouchInputBlockAPZC(
     // the event we send to gecko because we don't know the layer to untransform with
     // respect to.
     MonitorAutoLock lock(mTreeLock);
     for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
       FlushRepaintsRecursively(apzc);
     }
   }
 
-  apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutInOverscrolledApzc);
+  apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutHitResult);
   for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
-    nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutInOverscrolledApzc);
+    nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutHitResult);
     apzc = CommonAncestor(apzc.get(), apzc2.get());
     APZCTM_LOG("Using APZC %p as the common ancestor\n", apzc.get());
     // For now, we only ever want to do pinching on the root APZC for a given layers id. So
     // when we find the common ancestor of multiple points, also walk up to the root APZC.
     apzc = RootAPZCForLayersId(apzc);
     APZCTM_LOG("Using APZC %p as the root APZC for multi-touch\n", apzc.get());
   }
 
@@ -622,25 +737,31 @@ APZCTreeManager::ProcessTouchInput(Multi
         mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
       }
       return nsEventStatus_eConsumeNoDefault;
     }
 
     // NS_TOUCH_START event contains all active touches of the current
     // session thus resetting mTouchCount.
     mTouchCount = aInput.mTouches.Length();
-    mInOverscrolledApzc = false;
-    nsRefPtr<AsyncPanZoomController> apzc = GetTouchInputBlockAPZC(aInput, &mInOverscrolledApzc);
+    mHitResultForInputBlock = NoApzcHit;
+    nsRefPtr<AsyncPanZoomController> apzc = GetTouchInputBlockAPZC(aInput, &mHitResultForInputBlock);
+    // XXX the following check assumes mHitResultForInputBlock == ApzcHitRegion
+    // (and that mApzcForInputBlock was the confirmed target of the previous
+    // input block). Eventually it would be better to move this into InputQueue
+    // and have it auto-generated when we start processing events in a new
+    // event block.
     if (apzc != mApzcForInputBlock) {
       // If we're moving to a different APZC as our input target, then send a cancel event
       // to the old one so that it clears its internal state. Otherwise it could get left
       // in the middle of a panning touch block (for example) and not clean up properly.
       if (mApzcForInputBlock) {
         MultiTouchInput cancel(MultiTouchInput::MULTITOUCH_CANCEL, 0, TimeStamp::Now(), 0);
-        mInputQueue->ReceiveInputEvent(mApzcForInputBlock, cancel, nullptr);
+        mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
+            /* aTargetConfirmed = */ true, cancel, nullptr);
       }
       mApzcForInputBlock = apzc;
     }
 
     if (mApzcForInputBlock) {
       // Cache apz transform so it can be used for future events in this block.
       mCachedTransformToApzcForInputBlock = GetScreenToApzcTransform(mApzcForInputBlock);
     } else {
@@ -670,41 +791,45 @@ APZCTreeManager::ProcessTouchInput(Multi
     }
     if (aInput.mTouches.IsEmpty()) {
       return nsEventStatus_eConsumeNoDefault;
     }
   }
 
   nsEventStatus result = nsEventStatus_eIgnore;
   if (mApzcForInputBlock) {
+    MOZ_ASSERT(mHitResultForInputBlock == ApzcHitRegion || mHitResultForInputBlock == ApzcContentRegion);
+
     mApzcForInputBlock->GetGuid(aOutTargetGuid);
     // For computing the input for the APZC, used the cached transform.
     // This ensures that the sequence of touch points an APZC sees in an
     // input block are all in the same coordinate space.
     Matrix4x4 transformToApzc = mCachedTransformToApzcForInputBlock;
     for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
       SingleTouchData& touchData = aInput.mTouches[i];
       touchData.mLocalScreenPoint = TransformTo<ParentLayerPixel>(
           transformToApzc, ScreenPoint(touchData.mScreenPoint));
     }
-    result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock, aInput, aOutInputBlockId);
+    result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
+        /* aTargetConfirmed = */ mHitResultForInputBlock == ApzcHitRegion,
+        aInput, aOutInputBlockId);
 
     // For computing the event to pass back to Gecko, use the up-to-date transforms.
     // This ensures that transformToApzc and transformToGecko are in sync
     // (note that transformToGecko isn't cached).
     transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
     Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
     Matrix4x4 outTransform = transformToApzc * transformToGecko;
     for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
       SingleTouchData& touchData = aInput.mTouches[i];
       touchData.mScreenPoint = TransformTo<ScreenPixel>(
           outTransform, touchData.mScreenPoint);
     }
   }
-  if (mInOverscrolledApzc) {
+  if (mHitResultForInputBlock == OverscrolledApzc) {
     result = nsEventStatus_eConsumeNoDefault;
   }
 
   if (aInput.mType == MultiTouchInput::MULTITOUCH_END) {
     if (mTouchCount >= aInput.mTouches.Length()) {
       // NS_TOUCH_END event contains only released touches thus decrementing.
       mTouchCount -= aInput.mTouches.Length();
     } else {
@@ -714,17 +839,17 @@ APZCTreeManager::ProcessTouchInput(Multi
   } else if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
     mTouchCount = 0;
   }
 
   // If it's the end of the touch sequence then clear out variables so we
   // don't keep dangling references and leak things.
   if (mTouchCount == 0) {
     mApzcForInputBlock = nullptr;
-    mInOverscrolledApzc = false;
+    mHitResultForInputBlock = NoApzcHit;
     mRetainedTouchIdentifier = -1;
   }
 
   return result;
 }
 
 void
 APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
@@ -745,27 +870,28 @@ APZCTreeManager::ProcessEvent(WidgetInpu
                               ScrollableLayerGuid* aOutTargetGuid,
                               uint64_t* aOutInputBlockId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsEventStatus result = nsEventStatus_eIgnore;
 
   // Transform the refPoint.
   // If the event hits an overscrolled APZC, instruct the caller to ignore it.
-  bool inOverscrolledApzc = false;
+  HitTestResult hitResult = NoApzcHit;
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y),
-                                                        &inOverscrolledApzc);
+                                                        &hitResult);
   if (apzc) {
+    MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
     apzc->GetGuid(aOutTargetGuid);
     Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
     Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
     Matrix4x4 outTransform = transformToApzc * transformToGecko;
     aEvent.refPoint = TransformTo<LayoutDevicePixel>(outTransform, aEvent.refPoint);
   }
-  if (inOverscrolledApzc) {
+  if (hitResult == OverscrolledApzc) {
     result = nsEventStatus_eConsumeNoDefault;
   }
   return result;
 }
 
 nsEventStatus
 APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent,
                                    ScrollableLayerGuid* aOutTargetGuid,
@@ -818,16 +944,24 @@ APZCTreeManager::ZoomToRect(const Scroll
 void
 APZCTreeManager::ContentReceivedTouch(uint64_t aInputBlockId,
                                       bool aPreventDefault)
 {
   mInputQueue->ContentReceivedTouch(aInputBlockId, aPreventDefault);
 }
 
 void
+APZCTreeManager::SetTargetAPZC(uint64_t aInputBlockId,
+                               const ScrollableLayerGuid& aGuid)
+{
+  nsRefPtr<AsyncPanZoomController> target = GetTargetAPZC(aGuid);
+  mInputQueue->SetConfirmedTargetApzc(aInputBlockId, target);
+}
+
+void
 APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
                                        const ZoomConstraints& aConstraints)
 {
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
   // For a given layers id, non-root APZCs inherit the zoom constraints
   // of their root.
   if (apzc && apzc->IsRootForLayersId()) {
     MonitorAutoLock lock(mTreeLock);
@@ -1032,34 +1166,34 @@ APZCTreeManager::GetTargetAPZC(const Scr
     if (target) {
       break;
     }
   }
   return target.forget();
 }
 
 already_AddRefed<AsyncPanZoomController>
-APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, bool* aOutInOverscrolledApzc)
+APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult)
 {
   MonitorAutoLock lock(mTreeLock);
   nsRefPtr<AsyncPanZoomController> target;
   // The root may have siblings, so check those too
-  bool inOverscrolledApzc = false;
+  HitTestResult hitResult = NoApzcHit;
   for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
-    target = GetAPZCAtPoint(apzc, aPoint.ToUnknownPoint(), &inOverscrolledApzc);
+    target = GetAPZCAtPoint(apzc, aPoint.ToUnknownPoint(), &hitResult);
     // If we hit an overscrolled APZC, 'target' will be nullptr but it's still
     // a hit so we don't search further siblings.
-    if (target || inOverscrolledApzc) {
+    if (target || (hitResult == OverscrolledApzc)) {
       break;
     }
   }
   // If we are in an overscrolled APZC, we should be returning nullptr.
-  MOZ_ASSERT(!(target && inOverscrolledApzc));
-  if (aOutInOverscrolledApzc) {
-    *aOutInOverscrolledApzc = inOverscrolledApzc;
+  MOZ_ASSERT(!(target && (hitResult == OverscrolledApzc)));
+  if (aOutHitResult) {
+    *aOutHitResult = hitResult;
   }
   return target.forget();
 }
 
 nsRefPtr<const OverscrollHandoffChain>
 APZCTreeManager::BuildOverscrollHandoffChain(const nsRefPtr<AsyncPanZoomController>& aInitialTarget)
 {
   // Scroll grabbing is a mechanism that allows content to specify that
@@ -1170,17 +1304,17 @@ APZCTreeManager::FindTargetAPZC(AsyncPan
     return aApzc;
   }
   return nullptr;
 }
 
 AsyncPanZoomController*
 APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
                                 const Point& aHitTestPoint,
-                                bool* aOutInOverscrolledApzc)
+                                HitTestResult* aOutHitResult)
 {
   mTreeLock.AssertCurrentThreadOwns();
 
   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
   // explained in the comment above GetScreenToApzcTransform. This function will recurse with aApzc at L and P, and the
   // comments explain what values are stored in the variables at these two levels. All the comments
   // use standard matrix notation where the leftmost matrix in a multiplication is applied first.
 
@@ -1208,39 +1342,43 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPan
            aHitTestPoint.x, aHitTestPoint.y,
            hitTestPointForChildLayers.x, hitTestPointForChildLayers.y, aApzc);
 
   AsyncPanZoomController* result = nullptr;
   // This walks the tree in depth-first, reverse order, so that it encounters
   // APZCs front-to-back on the screen.
   if (hitTestPointForChildLayers.HasPositiveWCoord()) {
     for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
-      AsyncPanZoomController* match = GetAPZCAtPoint(child, hitTestPointForChildLayers.As2DPoint(), aOutInOverscrolledApzc);
-      if (*aOutInOverscrolledApzc) {
+      AsyncPanZoomController* match = GetAPZCAtPoint(child, hitTestPointForChildLayers.As2DPoint(), aOutHitResult);
+      if (*aOutHitResult == OverscrolledApzc) {
         // We matched an overscrolled APZC, abort.
         return nullptr;
       }
       if (match) {
         result = match;
         break;
       }
     }
   }
-  if (!result && hitTestPointForThisLayer.HasPositiveWCoord() &&
-      aApzc->VisibleRegionContains(ParentLayerPoint::FromUnknownPoint(hitTestPointForThisLayer.As2DPoint()))) {
-    APZCTM_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n",
-             hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
-    result = aApzc;
+  if (!result && hitTestPointForThisLayer.HasPositiveWCoord()) {
+    ParentLayerPoint point = ParentLayerPoint::FromUnknownPoint(hitTestPointForThisLayer.As2DPoint());
+    if (aApzc->HitRegionContains(point)) {
+      APZCTM_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n",
+                 hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
+      result = aApzc;
+      // If event regions are disabled, *aOutHitResult will be ApzcHitRegion
+      *aOutHitResult = (aApzc->DispatchToContentRegionContains(point) ? ApzcContentRegion : ApzcHitRegion);
+    }
   }
 
   // If we are overscrolled, and the point matches us or one of our children,
   // the result is inside an overscrolled APZC, inform our caller of this
   // (callers typically ignore events targeted at overscrolled APZCs).
   if (result && aApzc->IsOverscrolled()) {
-    *aOutInOverscrolledApzc = true;
+    *aOutHitResult = OverscrolledApzc;
     result = nullptr;
   }
 
   return result;
 }
 
 /* The methods GetScreenToApzcTransform() and GetApzcToGeckoTransform() return
    some useful transformations that input events may need applied. This is best
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -209,16 +209,28 @@ public:
    * definitively whether or not content has preventDefaulted any touch events
    * that have come in. If |aPreventDefault| is true, any touch events in the
    * queue will be discarded.
    */
   void ContentReceivedTouch(uint64_t aInputBlockId,
                             bool aPreventDefault);
 
   /**
+   * When the event regions code is enabled, this function should be invoked to
+   * to confirm the target of the input block. This is only needed in cases
+   * where the initial input event of the block hit a dispatch-to-content region
+   * but is safe to call for all input blocks. This function should always be
+   * invoked on the controller thread.
+   * In the case where the input block has no target, or the target is not a
+   * scrollable frame, |aGuid.mScrollId| should be set to FrameMetrics::
+   * NULL_SCROLL_ID.
+   */
+  void SetTargetAPZC(uint64_t aInputBlockId, const ScrollableLayerGuid& aGuid);
+
+  /**
    * Updates any zoom constraints contained in the <meta name="viewport"> tag.
    */
   void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
                              const ZoomConstraints& aConstraints);
 
   /**
    * Cancels any currently running animation. Note that all this does is set the
    * state of the AsyncPanZoomController back to NOTHING, but it is the
@@ -368,32 +380,39 @@ protected:
 
 public:
   /* Some helper functions to find an APZC given some identifying input. These functions
      lock the tree of APZCs while they find the right one, and then return an addref'd
      pointer to it. This allows caller code to just use the target APZC without worrying
      about it going away. These are public for testing code and generally should not be
      used by other production code.
   */
+  enum HitTestResult {
+    NoApzcHit,
+    ApzcHitRegion,
+    ApzcContentRegion,
+    OverscrolledApzc,
+  };
+
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
-                                                         bool* aOutInOverscrolledApzc);
+                                                         HitTestResult* aOutHitResult);
   gfx::Matrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const;
   gfx::Matrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const;
 private:
   /* Helpers */
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
   AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc,
                                          const gfx::Point& aHitTestPoint,
-                                         bool* aOutInOverscrolledApzc);
+                                         HitTestResult* aOutHitResult);
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
   already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
-                                                                  bool* aOutInOverscrolledApzc);
+                                                                  HitTestResult* aOutHitResult);
   nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
                                   ScrollableLayerGuid* aOutTargetGuid,
                                   uint64_t* aOutInputBlockId);
   nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent,
                              ScrollableLayerGuid* aOutTargetGuid,
                              uint64_t* aOutInputBlockId);
   void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
                                         const ZoomConstraints& aConstraints);
@@ -445,20 +464,20 @@ private:
   mutable mozilla::Monitor mTreeLock;
   nsRefPtr<AsyncPanZoomController> mRootApzc;
   /* This tracks the APZC that should receive all inputs for the current input event block.
    * This allows touch points to move outside the thing they started on, but still have the
    * touch events delivered to the same initial APZC. This will only ever be touched on the
    * input delivery thread, and so does not require locking.
    */
   nsRefPtr<AsyncPanZoomController> mApzcForInputBlock;
-  /* Whether the current input event block is being ignored because the touch-start
-   * was inside an overscrolled APZC.
+  /* The hit result for the current input event block; this should always be in
+   * sync with mApzcForInputBlock.
    */
-  bool mInOverscrolledApzc;
+  HitTestResult mHitResultForInputBlock;
   /* Sometimes we want to ignore all touches except one. In such cases, this
    * is set to the identifier of the touch we are not ignoring; in other cases,
    * this is set to -1.
    */
   int32_t mRetainedTouchIdentifier;
   /* The number of touch points we are tracking that are currently on the screen. */
   uint32_t mTouchCount;
   /* The transform from root screen coordinates into mApzcForInputBlock's
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1497,17 +1497,17 @@ nsEventStatus AsyncPanZoomController::On
 nsEventStatus AsyncPanZoomController::OnPanBegin(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-begin in state %d\n", this, mState);
 
   if (mState == SMOOTH_SCROLL) {
     // SMOOTH_SCROLL scrolls are cancelled by pan gestures.
     CancelAnimation();
   }
 
-  mPanGestureState = MakeUnique<InputBlockState>(this);
+  mPanGestureState = MakeUnique<InputBlockState>(this, true);
 
   mX.StartTouch(aEvent.mLocalPanStartPoint.x, aEvent.mTime);
   mY.StartTouch(aEvent.mLocalPanStartPoint.y, aEvent.mTime);
 
   if (GetAxisLockMode() == FREE) {
     SetState(PANNING);
     return nsEventStatus_eConsumeNoDefault;
   }
@@ -1575,17 +1575,17 @@ nsEventStatus AsyncPanZoomController::On
 nsEventStatus AsyncPanZoomController::OnPanMomentumStart(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-momentumstart in state %d\n", this, mState);
 
   if (mState == SMOOTH_SCROLL) {
     // SMOOTH_SCROLL scrolls are cancelled by pan gestures.
     CancelAnimation();
   }
 
-  mPanGestureState = MakeUnique<InputBlockState>(this);
+  mPanGestureState = MakeUnique<InputBlockState>(this, true);
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnPanMomentumEnd(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-momentumend in state %d\n", this, mState);
 
   mPanGestureState = nullptr;
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -15,16 +15,17 @@
 #include "mozilla/Monitor.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Atomics.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "InputQueue.h"
+#include "LayersTypes.h"
 #include "TaskThrottler.h"
 #include "mozilla/gfx/Matrix.h"
 #include "nsRegion.h"
 
 #include "base/message_loop.h"
 
 namespace mozilla {
 
@@ -992,44 +993,49 @@ private:
 
 
   /* ===================================================================
    * The functions and members in this section are used to maintain the
    * area that this APZC instance is responsible for. This is used when
    * hit-testing to see which APZC instance should handle touch events.
    */
 public:
-  void SetLayerHitTestData(const nsIntRegion& aRegion, const Matrix4x4& aTransformToLayer) {
-    mVisibleRegion = aRegion;
+  void SetLayerHitTestData(const EventRegions& aRegions, const Matrix4x4& aTransformToLayer) {
+    mEventRegions = aRegions;
     mAncestorTransform = aTransformToLayer;
   }
 
-  void AddHitTestRegion(const nsIntRegion& aRegion) {
-    mVisibleRegion.OrWith(aRegion);
+  void AddHitTestRegions(const EventRegions& aRegions) {
+    mEventRegions.OrWith(aRegions);
   }
 
   Matrix4x4 GetAncestorTransform() const {
     return mAncestorTransform;
   }
 
-  bool VisibleRegionContains(const ParentLayerPoint& aPoint) const {
+  bool HitRegionContains(const ParentLayerPoint& aPoint) const {
     ParentLayerIntPoint point = RoundedToInt(aPoint);
-    return mVisibleRegion.Contains(point.x, point.y);
+    return mEventRegions.mHitRegion.Contains(point.x, point.y);
+  }
+
+  bool DispatchToContentRegionContains(const ParentLayerPoint& aPoint) const {
+    ParentLayerIntPoint point = RoundedToInt(aPoint);
+    return mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y);
   }
 
   bool IsOverscrolled() const {
     return mX.IsOverscrolled() || mY.IsOverscrolled();
   }
 
 private:
-  /* This is the union of the visible regions of the layers that this APZC
-   * corresponds to, in the screen pixels of those layers. (This is the same
-   * coordinate system in which this APZC receives events in
+  /* This is the union of the hit regions of the layers that this APZC
+   * corresponds to, in the local screen pixels of those layers. (This is the
+   * same coordinate system in which this APZC receives events in
    * ReceiveInputEvent()). */
-  nsIntRegion mVisibleRegion;
+  EventRegions mEventRegions;
   /* This is the cumulative CSS transform for all the layers from (and including)
    * the parent APZC down to (but excluding) this one. */
   Matrix4x4 mAncestorTransform;
 
 
   /* ===================================================================
    * The functions and members in this section are used for sharing the
    * FrameMetrics across processes for the progressive tiling code.
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -13,25 +13,41 @@
 #define TBS_LOG(...)
 // #define TBS_LOG(...) printf_stderr("TBS: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 static uint64_t sBlockCounter = InputBlockState::NO_BLOCK_ID + 1;
 
-InputBlockState::InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc)
+InputBlockState::InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
+                                 bool aTargetConfirmed)
   : mTargetApzc(aTargetApzc)
+  , mTargetConfirmed(aTargetConfirmed)
   , mBlockId(sBlockCounter++)
 {
   // We should never be constructed with a nullptr target.
   MOZ_ASSERT(mTargetApzc);
   mOverscrollHandoffChain = mTargetApzc->BuildOverscrollHandoffChain();
 }
 
+bool
+InputBlockState::SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc)
+{
+  if (mTargetConfirmed) {
+    return false;
+  }
+  mTargetConfirmed = true;
+
+  // note that aTargetApzc MAY be null here.
+  mTargetApzc = aTargetApzc;
+  mOverscrollHandoffChain = (mTargetApzc ? mTargetApzc->BuildOverscrollHandoffChain() : nullptr);
+  return true;
+}
+
 const nsRefPtr<AsyncPanZoomController>&
 InputBlockState::GetTargetApzc() const
 {
   return mTargetApzc;
 }
 
 const nsRefPtr<const OverscrollHandoffChain>&
 InputBlockState::GetOverscrollHandoffChain() const
@@ -40,18 +56,25 @@ InputBlockState::GetOverscrollHandoffCha
 }
 
 uint64_t
 InputBlockState::GetBlockId() const
 {
   return mBlockId;
 }
 
-TouchBlockState::TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc)
-  : InputBlockState(aTargetApzc)
+bool
+InputBlockState::IsTargetConfirmed() const
+{
+  return mTargetConfirmed;
+}
+
+TouchBlockState::TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
+                                 bool aTargetConfirmed)
+  : InputBlockState(aTargetApzc, aTargetConfirmed)
   , mAllowedTouchBehaviorSet(false)
   , mPreventDefault(false)
   , mContentResponded(false)
   , mContentResponseTimerExpired(false)
   , mSingleTapDisallowed(false)
   , mSingleTapOccurred(false)
 {
   TBS_LOG("Creating %p\n", this);
@@ -105,16 +128,19 @@ TouchBlockState::CopyAllowedTouchBehavio
   TBS_LOG("%p copying allowed touch behaviours from %p\n", this, &aOther);
   MOZ_ASSERT(aOther.mAllowedTouchBehaviorSet);
   return SetAllowedTouchBehaviors(aOther.mAllowedTouchBehaviors);
 }
 
 bool
 TouchBlockState::IsReadyForHandling() const
 {
+  if (!IsTargetConfirmed()) {
+    return false;
+  }
   // TODO: for long-tap blocks we probably don't need the touch behaviour?
   if (gfxPrefs::TouchActionEnabled() && !mAllowedTouchBehaviorSet) {
     return false;
   }
   if (!mContentResponded && !mContentResponseTimerExpired) {
     return false;
   }
   return true;
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -21,24 +21,30 @@ class OverscrollHandoffChain;
  * A base class that stores state common to various input blocks.
  * Currently, it just stores the overscroll handoff chain.
  */
 class InputBlockState
 {
 public:
   static const uint64_t NO_BLOCK_ID = 0;
 
-  explicit InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
+  explicit InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
+                           bool aTargetConfirmed);
 
+  bool SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
   const nsRefPtr<AsyncPanZoomController>& GetTargetApzc() const;
   const nsRefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
   uint64_t GetBlockId() const;
+
+protected:
+  bool IsTargetConfirmed() const;
 private:
   nsRefPtr<AsyncPanZoomController> mTargetApzc;
   nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
+  bool mTargetConfirmed;
   const uint64_t mBlockId;
 };
 
 /**
  * This class represents a single touch block. A touch block is
  * a set of touch events that can be cancelled by web content via
  * touch event listeners.
  *
@@ -68,17 +74,18 @@ private:
  * be populated with some latency. The mAllowedTouchBehaviorSet and
  * mAllowedTouchBehaviors variables track this information.
  */
 class TouchBlockState : public InputBlockState
 {
 public:
   typedef uint32_t TouchBehaviorFlags;
 
-  explicit TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
+  explicit TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
+                           bool aTargetConfirmed);
 
   /**
    * Record whether or not content cancelled this block of events.
    * @param aPreventDefault true iff the block is cancelled.
    * @return false if this block has already received a response from
    *         web content, true if not.
    */
   bool SetContentResponse(bool aPreventDefault);
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -21,49 +21,63 @@ InputQueue::InputQueue()
 {
 }
 
 InputQueue::~InputQueue() {
   mTouchBlockQueue.Clear();
 }
 
 nsEventStatus
-InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget, const InputData& aEvent, uint64_t* aOutInputBlockId) {
+InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
+                              bool aTargetConfirmed,
+                              const InputData& aEvent,
+                              uint64_t* aOutInputBlockId) {
   AsyncPanZoomController::AssertOnControllerThread();
 
   if (aEvent.mInputType != MULTITOUCH_INPUT) {
     // The return value for non-touch input is only used by tests, so just pass
     // through the return value for now. This can be changed later if needed.
+    // TODO (bug 1098430): we will eventually need to have smarter handling for
+    // non-touch events as well.
     return aTarget->HandleInputEvent(aEvent);
   }
 
   TouchBlockState* block = nullptr;
   if (aEvent.AsMultiTouchInput().mType == MultiTouchInput::MULTITOUCH_START) {
-    block = StartNewTouchBlock(aTarget, false);
+    block = StartNewTouchBlock(aTarget, aTargetConfirmed, false);
     INPQ_LOG("started new touch block %p for target %p\n", block, aTarget.get());
 
     // We want to cancel animations here as soon as possible (i.e. without waiting for
     // content responses) because a finger has gone down and we don't want to keep moving
     // the content under the finger. However, to prevent "future" touchstart events from
     // interfering with "past" animations (i.e. from a previous touch block that is still
     // being processed) we only do this animation-cancellation if there are no older
     // touch blocks still in the queue.
     if (block == CurrentTouchBlock()) {
+      // XXX using the chain from |block| here may be wrong in cases where the
+      // target isn't confirmed and the real target turns out to be something
+      // else. For now assume this is rare enough that it's not an issue.
       if (block->GetOverscrollHandoffChain()->HasFastMovingApzc()) {
         // If we're already in a fast fling, then we want the touch event to stop the fling
         // and to disallow the touch event from being used as part of a fling.
         block->DisallowSingleTap();
       }
       block->GetOverscrollHandoffChain()->CancelAnimations();
     }
 
-    if (aTarget->NeedToWaitForContent()) {
-      // Content may intercept the touch events and prevent-default them. So we schedule
-      // a timeout to give content time to do that.
-      ScheduleContentResponseTimeout(aTarget, block->GetBlockId());
+    bool waitForMainThread = !aTargetConfirmed;
+    if (!gfxPrefs::LayoutEventRegionsEnabled()) {
+      waitForMainThread |= aTarget->NeedToWaitForContent();
+    }
+    if (waitForMainThread) {
+      // We either don't know for sure if aTarget is the right APZC, or we may
+      // need to wait to give content the opportunity to prevent-default the
+      // touch events. Either way we schedule a timeout so the main thread stuff
+      // can run.
+      ScheduleMainThreadTimeout(aTarget, block->GetBlockId());
     } else {
       // Content won't prevent-default this, so we can just pretend like we scheduled
       // a timeout and it expired. Note that we will still receive a ContentReceivedTouch
       // callback for this block, and so we need to make sure we adjust the touch balance.
       INPQ_LOG("not waiting for content response on block %p\n", block);
       block->TimeoutContentResponse();
     }
   } else if (mTouchBlockQueue.IsEmpty()) {
@@ -76,49 +90,63 @@ InputQueue::ReceiveInputEvent(const nsRe
 
   if (!block) {
     return nsEventStatus_eIgnore;
   }
   if (aOutInputBlockId) {
     *aOutInputBlockId = block->GetBlockId();
   }
 
-  nsEventStatus result = aTarget->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())
-      ? nsEventStatus_eConsumeDoDefault
-      : nsEventStatus_eIgnore;
+  // Note that the |aTarget| the APZCTM sent us may contradict the confirmed
+  // target set on the block. In this case the confirmed target (which may be
+  // null) should take priority. This is equivalent to just always using the
+  // target (confirmed or not) from the block.
+  nsRefPtr<AsyncPanZoomController> target = block->GetTargetApzc();
+
+  nsEventStatus result = nsEventStatus_eIgnore;
+  // XXX calling ArePointerEventsConsumable on |target| may be wrong here if
+  // the target isn't confirmed and the real target turns out to be something
+  // else. For now assume this is rare enough that it's not an issue.
+  if (target && target->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())) {
+    result = nsEventStatus_eConsumeDoDefault;
+  }
 
   if (block == CurrentTouchBlock() && block->IsReadyForHandling()) {
-    INPQ_LOG("current touch block is ready with preventdefault %d\n",
-        block->IsDefaultPrevented());
-    if (block->IsDefaultPrevented()) {
+    INPQ_LOG("current touch block is ready with target %p preventdefault %d\n",
+        target.get(), block->IsDefaultPrevented());
+    if (!target || block->IsDefaultPrevented()) {
       return result;
     }
-    aTarget->HandleInputEvent(aEvent);
+    target->HandleInputEvent(aEvent);
     return result;
   }
 
   // Otherwise, add it to the queue for the touch block
   block->AddEvent(aEvent.AsMultiTouchInput());
   return result;
 }
 
 uint64_t
 InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
 {
-  TouchBlockState* block = StartNewTouchBlock(aTarget, true);
+  TouchBlockState* block = StartNewTouchBlock(aTarget,
+    /* aTargetConfirmed = */ true,
+    /* aCopyAllowedTouchBehaviorFromCurrent = */ true);
   INPQ_LOG("%p injecting new touch block with id %" PRIu64 " and target %p\n",
     this, block->GetBlockId(), aTarget);
-  ScheduleContentResponseTimeout(aTarget, block->GetBlockId());
+  ScheduleMainThreadTimeout(aTarget, block->GetBlockId());
   return block->GetBlockId();
 }
 
 TouchBlockState*
-InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget, bool aCopyAllowedTouchBehaviorFromCurrent)
+InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
+                               bool aTargetConfirmed,
+                               bool aCopyAllowedTouchBehaviorFromCurrent)
 {
-  TouchBlockState* newBlock = new TouchBlockState(aTarget);
+  TouchBlockState* newBlock = new TouchBlockState(aTarget, aTargetConfirmed);
   if (gfxPrefs::TouchActionEnabled() && aCopyAllowedTouchBehaviorFromCurrent) {
     newBlock->CopyAllowedTouchBehaviorsFrom(*CurrentTouchBlock());
   }
 
   // We're going to start a new block, so clear out any depleted blocks at the head of the queue.
   // See corresponding comment in ProcessPendingInputBlocks.
   while (!mTouchBlockQueue.IsEmpty()) {
     if (mTouchBlockQueue[0]->IsReadyForHandling() && !mTouchBlockQueue[0]->HasEvents()) {
@@ -145,32 +173,36 @@ InputQueue::CurrentTouchBlock() const
 
 bool
 InputQueue::HasReadyTouchBlock() const
 {
   return !mTouchBlockQueue.IsEmpty() && mTouchBlockQueue[0]->IsReadyForHandling();
 }
 
 void
-InputQueue::ScheduleContentResponseTimeout(const nsRefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId) {
-  INPQ_LOG("scheduling content response timeout for target %p\n", aTarget.get());
+InputQueue::ScheduleMainThreadTimeout(const nsRefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId) {
+  INPQ_LOG("scheduling main thread timeout for target %p\n", aTarget.get());
   aTarget->PostDelayedTask(
-    NewRunnableMethod(this, &InputQueue::ContentResponseTimeout, aInputBlockId),
+    NewRunnableMethod(this, &InputQueue::MainThreadTimeout, aInputBlockId),
     gfxPrefs::APZContentResponseTimeout());
 }
 
 void
-InputQueue::ContentResponseTimeout(const uint64_t& aInputBlockId) {
+InputQueue::MainThreadTimeout(const uint64_t& aInputBlockId) {
   AsyncPanZoomController::AssertOnControllerThread();
 
-  INPQ_LOG("got a content response timeout; block=%" PRIu64 "\n", aInputBlockId);
+  INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId);
   bool success = false;
   for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
     if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
+      // time out the touch-listener response and also confirm the existing
+      // target apzc in the case where the main thread doesn't get back to us
+      // fast enough.
       success = mTouchBlockQueue[i]->TimeoutContentResponse();
+      success |= mTouchBlockQueue[i]->SetConfirmedTargetApzc(mTouchBlockQueue[i]->GetTargetApzc());
       break;
     }
   }
   if (success) {
     ProcessPendingInputBlocks();
   }
 }
 
@@ -187,16 +219,35 @@ InputQueue::ContentReceivedTouch(uint64_
     }
   }
   if (success) {
     ProcessPendingInputBlocks();
   }
 }
 
 void
+InputQueue::SetConfirmedTargetApzc(uint64_t aInputBlockId, const nsRefPtr<AsyncPanZoomController>& aTargetApzc) {
+  AsyncPanZoomController::AssertOnControllerThread();
+
+  INPQ_LOG("got a target apzc; block=%" PRIu64 "\n", aInputBlockId);
+  bool success = false;
+  for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
+    if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
+      success = mTouchBlockQueue[i]->SetConfirmedTargetApzc(aTargetApzc);
+      break;
+    }
+  }
+  if (success) {
+    ProcessPendingInputBlocks();
+  } else {
+    NS_WARNING("INPQ received useless SetConfirmedTargetApzc");
+  }
+}
+
+void
 InputQueue::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
   AsyncPanZoomController::AssertOnControllerThread();
 
   INPQ_LOG("got allowed touch behaviours; block=%" PRIu64 "\n", aInputBlockId);
   bool success = false;
   for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
     if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
       success = mTouchBlockQueue[i]->SetAllowedTouchBehaviors(aBehaviors);
@@ -219,17 +270,21 @@ InputQueue::ProcessPendingInputBlocks() 
     if (!curBlock->IsReadyForHandling()) {
       break;
     }
 
     INPQ_LOG("processing input block %p; preventDefault %d target %p\n",
         curBlock, curBlock->IsDefaultPrevented(),
         curBlock->GetTargetApzc().get());
     nsRefPtr<AsyncPanZoomController> target = curBlock->GetTargetApzc();
-    if (curBlock->IsDefaultPrevented()) {
+    // target may be null here if the initial target was unconfirmed and then
+    // we later got a confirmed null target. in that case drop the events.
+    if (!target) {
+      curBlock->DropEvents();
+    } else if (curBlock->IsDefaultPrevented()) {
       curBlock->DropEvents();
       target->ResetInputState();
     } else {
       while (curBlock->HasEvents()) {
         target->HandleInputEvent(curBlock->RemoveFirstEvent());
       }
     }
     MOZ_ASSERT(!curBlock->HasEvents());
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -36,24 +36,35 @@ public:
   InputQueue();
 
   /**
    * Notifies the InputQueue of a new incoming input event. The APZC that the
    * input event was targeted to should be provided in the |aTarget| parameter.
    * See the documentation on APZCTreeManager::ReceiveInputEvent for info on
    * return values from this function, including |aOutInputBlockId|.
    */
-  nsEventStatus ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget, const InputData& aEvent, uint64_t* aOutInputBlockId);
+  nsEventStatus ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
+                                  bool aTargetConfirmed,
+                                  const InputData& aEvent,
+                                  uint64_t* aOutInputBlockId);
   /**
    * This function should be invoked to notify the InputQueue when web content
    * decides whether or not it wants to cancel a block of events. The block
    * id to which this applies should be provided in |aInputBlockId|.
    */
   void ContentReceivedTouch(uint64_t aInputBlockId, bool aPreventDefault);
   /**
+   * This function should be invoked to notify the InputQueue once the target
+   * APZC to handle an input block has been confirmed. In practice this should
+   * generally be decidable upon receipt of the input event, but in some cases
+   * we may need to query the layout engine to know for sure. The input block
+   * this applies to should be specified via the |aInputBlockId| parameter.
+   */
+  void SetConfirmedTargetApzc(uint64_t aInputBlockId, const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
+  /**
    * This function should be invoked to notify the InputQueue of the touch-
    * action properties for the different touch points in an input block. The
    * input block this applies to should be specified by the |aInputBlockId|
    * parameter. If touch-action is not enabled on the platform, this function
    * does nothing and need not be called.
    */
   void SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors);
   /**
@@ -71,19 +82,21 @@ public:
   /**
    * Returns true iff the touch block at the head of the queue is ready for
    * handling.
    */
   bool HasReadyTouchBlock() const;
 
 private:
   ~InputQueue();
-  TouchBlockState* StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget, bool aCopyAllowedTouchBehaviorFromCurrent);
-  void ScheduleContentResponseTimeout(const nsRefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId);
-  void ContentResponseTimeout(const uint64_t& aInputBlockId);
+  TouchBlockState* StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
+                                      bool aTargetConfirmed,
+                                      bool aCopyAllowedTouchBehaviorFromCurrent);
+  void ScheduleMainThreadTimeout(const nsRefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId);
+  void MainThreadTimeout(const uint64_t& aInputBlockId);
   void ProcessPendingInputBlocks();
 
 private:
   // The queue of touch blocks that have not yet been processed.
   // This member must only be accessed on the controller/UI thread.
   nsTArray<UniquePtr<TouchBlockState>> mTouchBlockQueue;
 };
 
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -138,17 +138,17 @@ public:
     // This is a function whose signature matches exactly the ReceiveInputEvent
     // on APZCTreeManager. This allows us to templates for functions like
     // TouchDown, TouchUp, etc so that we can reuse the code for dispatching
     // events into both APZC and APZCTM.
     return ReceiveInputEvent(aEvent, aOutInputBlockId);
   }
 
   nsEventStatus ReceiveInputEvent(const InputData& aEvent, uint64_t* aOutInputBlockId) {
-    return GetInputQueue()->ReceiveInputEvent(this, aEvent, aOutInputBlockId);
+    return GetInputQueue()->ReceiveInputEvent(this, true, aEvent, aOutInputBlockId);
   }
 
   void ContentReceivedTouch(uint64_t aInputBlockId, bool aPreventDefault) {
     GetInputQueue()->ContentReceivedTouch(aInputBlockId, aPreventDefault);
   }
   
   void SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
     GetInputQueue()->SetAllowedTouchBehavior(aInputBlockId, aBehaviors);
@@ -320,19 +320,20 @@ TouchUp(const nsRefPtr<InputReceiver>& a
 {
   MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, TimeStamp(), 0);
   mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
   return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
 }
 
 template<class InputReceiver> static void
 Tap(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, int& aTime, int aTapLength,
-    nsEventStatus (*aOutEventStatuses)[2] = nullptr)
+    nsEventStatus (*aOutEventStatuses)[2] = nullptr,
+    uint64_t* aOutInputBlockId = nullptr)
 {
-  nsEventStatus status = TouchDown(aTarget, aX, aY, aTime);
+  nsEventStatus status = TouchDown(aTarget, aX, aY, aTime, aOutInputBlockId);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[0] = status;
   }
   aTime += aTapLength;
   status = TouchUp(aTarget, aX, aY, aTime);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[1] = status;
   }
@@ -1661,16 +1662,22 @@ protected:
     nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
     metrics.mCompositionBounds = ParentLayerRect(layerBound.x, layerBound.y,
                                                  layerBound.width, layerBound.height);
     metrics.mScrollableRect = aScrollableRect;
     metrics.SetScrollOffset(CSSPoint(0, 0));
     aLayer->SetFrameMetrics(metrics);
   }
 
+  void SetScrollHandoff(Layer* aChild, Layer* aParent) {
+    FrameMetrics metrics = aChild->GetFrameMetrics(0);
+    metrics.SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId());
+    aChild->SetFrameMetrics(metrics);
+  }
+
   static TestAsyncPanZoomController* ApzcOf(Layer* aLayer) {
     EXPECT_EQ(1u, aLayer->GetFrameMetricsCount());
     return (TestAsyncPanZoomController*)aLayer->GetAsyncPanZoomController(0);
   }
 
   void CreateSimpleScrollingLayer() {
     const char* layerTreeSyntax = "t";
     nsIntRegion layerVisibleRegion[] = {
@@ -2124,22 +2131,16 @@ TEST_F(APZHitTestingTester, TestRepaintF
   mcc->RunThroughDelayedTasks();
 }
 
 class APZOverscrollHandoffTester : public APZCTreeManagerTester {
 protected:
   UniquePtr<ScopedLayerTreeRegistration> registration;
   TestAsyncPanZoomController* rootApzc;
 
-  void SetScrollHandoff(Layer* aChild, Layer* aParent) {
-    FrameMetrics metrics = aChild->GetFrameMetrics(0);
-    metrics.SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId());
-    aChild->SetFrameMetrics(metrics);
-  }
-
   void CreateOverscrollHandoffLayerTree1() {
     const char* layerTreeSyntax = "c(c)";
     nsIntRegion layerVisibleRegion[] = {
       nsIntRegion(nsIntRect(0, 0, 100, 100)),
       nsIntRegion(nsIntRect(0, 50, 100, 50))
     };
     root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
     SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
@@ -2380,16 +2381,134 @@ TEST_F(APZOverscrollHandoffTester, Scrol
   int time = 0;
   Pan(childApzc, time, 80, 70);
 
   // Check that it is the scrollgrab parent that's in a fling, not the child.
   rootApzc->AssertStateIsFling();
   childApzc->AssertStateIsReset();
 }
 
+class APZEventRegionsTester : public APZCTreeManagerTester {
+protected:
+  UniquePtr<ScopedLayerTreeRegistration> registration;
+  TestAsyncPanZoomController* rootApzc;
+
+  void CreateEventRegionsLayerTree1() {
+    const char* layerTreeSyntax = "c(tt)";
+    root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
+    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
+    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
+    SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 2);
+    SetScrollHandoff(layers[1], root);
+    SetScrollHandoff(layers[2], root);
+
+    // Set up the event regions over a 200x200 area. The root layer has the
+    // whole 200x200 as the hit region; layers[1] has the left half and
+    // layers[2] has the bottom half. The bottom-left 100x100 area is also
+    // in the d-t-c region for both layers[1] and layers[2] (but layers[2] is
+    // on top so it gets the events by default if the main thread doesn't
+    // respond).
+    EventRegions regions(nsIntRegion(nsIntRect(0, 0, 200, 200)));
+    root->SetEventRegions(regions);
+    regions.mDispatchToContentHitRegion = nsIntRegion(nsIntRect(0, 100, 100, 100));
+    regions.mHitRegion = nsIntRegion(nsIntRect(0, 0, 100, 200));
+    layers[1]->SetEventRegions(regions);
+    regions.mHitRegion = nsIntRegion(nsIntRect(0, 100, 200, 100));
+    layers[2]->SetEventRegions(regions);
+
+    registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
+    manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, 0);
+    rootApzc = ApzcOf(root);
+  }
+
+  void CreateEventRegionsLayerTree2() {
+    const char* layerTreeSyntax = "c(t)";
+    root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
+    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
+
+    // Set up the event regions so that the child thebes layer is positioned far
+    // away from the scrolling container layer.
+    EventRegions regions(nsIntRegion(nsIntRect(0, 0, 100, 100)));
+    root->SetEventRegions(regions);
+    regions.mHitRegion = nsIntRegion(nsIntRect(0, 150, 100, 100));
+    layers[1]->SetEventRegions(regions);
+
+    registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
+    manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, 0);
+    rootApzc = ApzcOf(root);
+  }
+};
+
+TEST_F(APZEventRegionsTester, HitRegionImmediateResponse) {
+  SCOPED_GFX_PREF(LayoutEventRegionsEnabled, bool, true);
+
+  CreateEventRegionsLayerTree1();
+
+  TestAsyncPanZoomController* root = ApzcOf(layers[0]);
+  TestAsyncPanZoomController* left = ApzcOf(layers[1]);
+  TestAsyncPanZoomController* bottom = ApzcOf(layers[2]);
+
+  MockFunction<void(std::string checkPointName)> check;
+  {
+    InSequence s;
+    EXPECT_CALL(*mcc, HandleSingleTap(_, _, left->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("Tapped on left"));
+    EXPECT_CALL(*mcc, HandleSingleTap(_, _, bottom->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("Tapped on bottom"));
+    EXPECT_CALL(*mcc, HandleSingleTap(_, _, root->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("Tapped on root"));
+    EXPECT_CALL(check, Call("Tap pending on d-t-c region"));
+    EXPECT_CALL(*mcc, HandleSingleTap(_, _, bottom->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("Tapped on bottom again"));
+    EXPECT_CALL(*mcc, HandleSingleTap(_, _, left->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("Tapped on left this time"));
+  }
+
+  int time = 0;
+  // Tap in the exposed hit regions of each of the layers once and ensure
+  // the clicks are dispatched right away
+  Tap(manager, 10, 10, time, 100);
+  mcc->RunThroughDelayedTasks();    // this runs the tap event
+  check.Call("Tapped on left");
+  Tap(manager, 110, 110, time, 100);
+  mcc->RunThroughDelayedTasks();    // this runs the tap event
+  check.Call("Tapped on bottom");
+  Tap(manager, 110, 10, time, 100);
+  mcc->RunThroughDelayedTasks();    // this runs the tap event
+  check.Call("Tapped on root");
+
+  // Now tap on the dispatch-to-content region where the layers overlap
+  Tap(manager, 10, 110, time, 100);
+  mcc->RunThroughDelayedTasks();    // this runs the main-thread timeout
+  check.Call("Tap pending on d-t-c region");
+  mcc->RunThroughDelayedTasks();    // this runs the tap event
+  check.Call("Tapped on bottom again");
+
+  // Now let's do that again, but simulate a main-thread response
+  uint64_t inputBlockId = 0;
+  Tap(manager, 10, 110, time, 100, nullptr, &inputBlockId);
+  manager->SetTargetAPZC(inputBlockId, left->GetGuid());
+  while (mcc->RunThroughDelayedTasks());    // this runs the tap event
+  check.Call("Tapped on left this time");
+}
+
+TEST_F(APZEventRegionsTester, HitRegionAccumulatesChildren) {
+  SCOPED_GFX_PREF(LayoutEventRegionsEnabled, bool, true);
+
+  CreateEventRegionsLayerTree2();
+
+  int time = 0;
+  // Tap in the area of the child layer that's not directly included in the
+  // parent layer's hit region. Verify that it comes out of the APZC's
+  // content controller, which indicates the input events got routed correctly
+  // to the APZC.
+  EXPECT_CALL(*mcc, HandleSingleTap(_, _, rootApzc->GetGuid())).Times(1);
+  Tap(manager, 10, 160, time, 100);
+  mcc->RunThroughDelayedTasks();    // this runs the tap event
+}
 
 class TaskRunMetrics {
 public:
   TaskRunMetrics()
     : mRunCount(0)
     , mCancelCount(0)
   {}
 
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -658,48 +658,65 @@ static nsresult NewImageChannel(nsIChann
   // Pass in a nullptr loadgroup because this is the underlying network
   // request. This request may be referenced by several proxy image requests
   // (possibly in different documents).
   // If all of the proxy requests are canceled then this request should be
   // canceled too.
   //
   aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
 
-  nsCOMPtr<nsIPrincipal> requestingPrincipal = aLoadingPrincipal;
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aLoadingPrincipal;
   bool isSandBoxed = false;
   // only inherit if we have a principal
   bool inherit = false;
-  if (requestingPrincipal) {
-    inherit = nsContentUtils::ChannelShouldInheritPrincipal(requestingPrincipal,
+  if (triggeringPrincipal) {
+    inherit = nsContentUtils::ChannelShouldInheritPrincipal(triggeringPrincipal,
                                                             aURI,
                                                             false,  // aInheritForAboutBlank
                                                             false); // aForceInherit
   }
   else {
-    requestingPrincipal = nsContentUtils::GetSystemPrincipal();
+    triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
   }
   nsCOMPtr<nsINode> requestingNode = do_QueryInterface(aRequestingContext);
   nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
   if (inherit) {
     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
-  // Note we are calling NS_NewChannelInternal() here with a node and a principal.
-  // This is for things like background images that are specified by user
-  // stylesheets, where the document is being styled, but the principal is that
-  // of the user stylesheet.
-  rv = NS_NewChannelInternal(aResult,
-                             aURI,
-                             requestingNode,
-                             requestingPrincipal,
-                             securityFlags,
-                             aPolicyType,
-                             nullptr,   // loadGroup
-                             callbacks,
-                             aLoadFlags);
+  // Note we are calling NS_NewChannelWithTriggeringPrincipal() here with a node
+  // and a principal. This is for things like background images that are specified
+  // by user stylesheets, where the document is being styled, but the principal
+  // is that of the user stylesheet.
+  if (requestingNode) {
+    rv = NS_NewChannelWithTriggeringPrincipal(aResult,
+                                              aURI,
+                                              requestingNode,
+                                              triggeringPrincipal,
+                                              securityFlags,
+                                              nsIContentPolicy::TYPE_IMAGE,
+                                              nullptr,   // loadGroup
+                                              callbacks,
+                                              aLoadFlags);
+  }
+  else {
+    // either we are loading something inside a document, in which case
+    // we should always have a requestingNode, or we are loading something
+    // outside a document, in which case the triggeringPrincipal
+    // should always be the systemPrincipal.
+    MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(triggeringPrincipal));
+    rv = NS_NewChannel(aResult,
+                       aURI,
+                       triggeringPrincipal,
+                       securityFlags,
+                       nsIContentPolicy::TYPE_IMAGE,
+                       nullptr,   // loadGroup
+                       callbacks,
+                       aLoadFlags);
+  }
 
   if (NS_FAILED(rv))
     return rv;
 
   *aForcePrincipalCheckForCacheEntry = inherit && !isSandBoxed;
 
   // Initialize HTTP-specific attributes
   newHttpChannel = do_QueryInterface(*aResult);
--- a/ipc/app/moz.build
+++ b/ipc/app/moz.build
@@ -28,31 +28,43 @@ else:
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/toolkit/xre',
     '/xpcom/base',
 ]
 
+# We link GMPLoader into plugin-container on desktop so that its code is
+# covered by the desktop DRM vendor's voucher.
+if CONFIG['OS_TARGET'] != 'Android':
+    SOURCES += [
+        '../../dom/media/gmp/GMPLoader.cpp',
+    ]
+
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
     # For sandbox includes and the include dependencies those have
     LOCAL_INCLUDES += [
         '/security',
         '/security/sandbox',
         '/security/sandbox/chromium',
     ]
     USE_LIBS += [
+        'rlz',
         'sandbox_staticruntime_s',
     ]
     DELAYLOAD_DLLS += [
         'mozalloc.dll',
         'nss3.dll',
         'xul.dll'
     ]
+    DEFINES['HASH_NODE_ID_WITH_DEVICE_ID'] = 1;
+    SOURCES += [
+        'sha256.c',
+    ]
 
 if CONFIG['_MSC_VER']:
     # Always enter a Windows program through wmain, whether or not we're
     # a console application.
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
 
 LDFLAGS += [CONFIG['MOZ_ALLOW_HEAP_EXECUTE_FLAGS']]
 
copy from security/nss/lib/freebl/sha512.c
copy to ipc/app/sha256.c
--- a/security/nss/lib/freebl/sha512.c
+++ b/ipc/app/sha256.c
@@ -1,29 +1,30 @@
-/*
- * sha512.c - implementation of SHA224, SHA256, SHA384 and SHA512
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifdef FREEBL_NO_DEPEND
-#include "stubs.h"
-#endif
+// Stripped down version of security/nss/lib/freebl/sha512.c
+// and related headers.
 
+#include "sha256.h"
+#include "string.h"
 #include "prcpucfg.h"
 #if defined(NSS_X86) || defined(SHA_NO_LONG_LONG)
 #define NOUNROLL512 1
 #undef HAVE_LONG_LONG
 #endif
-#include "prtypes.h"	/* for PRUintXX */
-#include "prlong.h"
-#include "secport.h"	/* for PORT_XXX */
-#include "blapi.h"
-#include "sha256.h"	/* for struct SHA256ContextStr */
+
+#define SHA256_BLOCK_LENGTH 64 /* bytes */ 
+
+typedef enum _SECStatus {
+    SECWouldBlock = -2,
+    SECFailure = -1,
+    SECSuccess = 0
+} SECStatus;
 
 /* ============= Common constants and defines ======================= */
 
 #define W ctx->u.w
 #define B ctx->u.b
 #define H ctx->h
 
 #define SHR(x,n) (x >> n)
@@ -140,32 +141,16 @@ static __inline__ PRUint32 swap4b(PRUint
 #endif
 
 /* Capitol Sigma and lower case sigma functions */
 #define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22))
 #define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25))
 #define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3))
 #define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10))
 
-SHA256Context *
-SHA256_NewContext(void)
-{
-    SHA256Context *ctx = PORT_New(SHA256Context);
-    return ctx;
-}
-
-void 
-SHA256_DestroyContext(SHA256Context *ctx, PRBool freeit)
-{
-    memset(ctx, 0, sizeof *ctx);
-    if (freeit) {
-        PORT_Free(ctx);
-    }
-}
-
 void 
 SHA256_Begin(SHA256Context *ctx)
 {
     memset(ctx, 0, sizeof *ctx);
     memcpy(H, H256, sizeof H256);
 }
 
 static void
@@ -499,1100 +484,8 @@ SHA256_HashBuf(unsigned char *dest, cons
 
     SHA256_Begin(&ctx);
     SHA256_Update(&ctx, src, src_length);
     SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH);
     memset(&ctx, 0, sizeof ctx);
 
     return SECSuccess;
 }
-
-
-SECStatus 
-SHA256_Hash(unsigned char *dest, const char *src)
-{
-    return SHA256_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
-}
-
-
-void SHA256_TraceState(SHA256Context *ctx) { }
-
-unsigned int 
-SHA256_FlattenSize(SHA256Context *ctx)
-{
-    return sizeof *ctx;
-}
-
-SECStatus 
-SHA256_Flatten(SHA256Context *ctx,unsigned char *space)
-{
-    PORT_Memcpy(space, ctx, sizeof *ctx);
-    return SECSuccess;
-}
-
-SHA256Context * 
-SHA256_Resurrect(unsigned char *space, void *arg)
-{
-    SHA256Context *ctx = SHA256_NewContext();
-    if (ctx) 
-	PORT_Memcpy(ctx, space, sizeof *ctx);
-    return ctx;
-}
-
-void SHA256_Clone(SHA256Context *dest, SHA256Context *src) 
-{
-    memcpy(dest, src, sizeof *dest);
-}
-
-/* ============= SHA224 implementation ================================== */
-
-/* SHA-224 initial hash values */
-static const PRUint32 H224[8] = {
-    0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 
-    0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
-};
-
-SHA224Context *
-SHA224_NewContext(void)
-{
-    return SHA256_NewContext();
-}
-
-void
-SHA224_DestroyContext(SHA224Context *ctx, PRBool freeit)
-{
-    SHA256_DestroyContext(ctx, freeit);
-}
-
-void
-SHA224_Begin(SHA224Context *ctx)
-{
-    memset(ctx, 0, sizeof *ctx);
-    memcpy(H, H224, sizeof H224);
-}
-
-void
-SHA224_Update(SHA224Context *ctx, const unsigned char *input,
-		    unsigned int inputLen)
-{
-    SHA256_Update(ctx, input, inputLen);
-}
-
-void
-SHA224_End(SHA256Context *ctx, unsigned char *digest,
-           unsigned int *digestLen, unsigned int maxDigestLen)
-{
-    unsigned int maxLen = SHA_MIN(maxDigestLen, SHA224_LENGTH);
-    SHA256_End(ctx, digest, digestLen, maxLen);
-}
-
-void
-SHA224_EndRaw(SHA256Context *ctx, unsigned char *digest,
-	      unsigned int *digestLen, unsigned int maxDigestLen)
-{
-    unsigned int maxLen = SHA_MIN(maxDigestLen, SHA224_LENGTH);
-    SHA256_EndRaw(ctx, digest, digestLen, maxLen);
-}
-
-SECStatus 
-SHA224_HashBuf(unsigned char *dest, const unsigned char *src,
-               PRUint32 src_length)
-{
-    SHA256Context ctx;
-    unsigned int outLen;
-
-    SHA224_Begin(&ctx);
-    SHA256_Update(&ctx, src, src_length);
-    SHA256_End(&ctx, dest, &outLen, SHA224_LENGTH);
-    memset(&ctx, 0, sizeof ctx);
-
-    return SECSuccess;
-}
-
-SECStatus
-SHA224_Hash(unsigned char *dest, const char *src)
-{
-    return SHA224_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
-}
-
-void SHA224_TraceState(SHA224Context *ctx) { }
-
-unsigned int
-SHA224_FlattenSize(SHA224Context *ctx)
-{
-    return SHA256_FlattenSize(ctx);
-}
-
-SECStatus
-SHA224_Flatten(SHA224Context *ctx, unsigned char *space)
-{
-    return SHA256_Flatten(ctx, space);
-}
-
-SHA224Context *
-SHA224_Resurrect(unsigned char *space, void *arg)
-{
-    return SHA256_Resurrect(space, arg);
-}
-
-void SHA224_Clone(SHA224Context *dest, SHA224Context *src) 
-{
-    SHA256_Clone(dest, src);
-}
-
-
-/* ======= SHA512 and SHA384 common constants and defines ================= */
-
-/* common #defines for SHA512 and SHA384 */
-#if defined(HAVE_LONG_LONG)
-#if defined(_MSC_VER)
-#pragma intrinsic(_rotr64,_rotl64)
-#define ROTR64(x,n) _rotr64(x,n)
-#define ROTL64(x,n) _rotl64(x,n)
-#else
-#define ROTR64(x,n) ((x >> n) | (x << (64 - n)))
-#define ROTL64(x,n) ((x << n) | (x >> (64 - n)))
-#endif
-
-#define S0(x) (ROTR64(x,28) ^ ROTR64(x,34) ^ ROTR64(x,39))
-#define S1(x) (ROTR64(x,14) ^ ROTR64(x,18) ^ ROTR64(x,41))
-#define s0(x) (t1 = x, ROTR64(t1, 1) ^ ROTR64(t1, 8) ^ SHR(t1,7))
-#define s1(x) (t2 = x, ROTR64(t2,19) ^ ROTR64(t2,61) ^ SHR(t2,6))
-
-#if PR_BYTES_PER_LONG == 8
-#define ULLC(hi,lo) 0x ## hi ## lo ## UL
-#elif defined(_MSC_VER)
-#define ULLC(hi,lo) 0x ## hi ## lo ## ui64
-#else
-#define ULLC(hi,lo) 0x ## hi ## lo ## ULL
-#endif
-
-#if defined(_MSC_VER)
-#pragma intrinsic(_byteswap_uint64)
-#define SHA_HTONLL(x) _byteswap_uint64(x)
-
-#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__x86_64))
-static __inline__ PRUint64 swap8b(PRUint64 value)
-{
-    __asm__("bswapq %0" : "+r" (value));
-    return (value);
-}
-#define SHA_HTONLL(x) swap8b(x)
-
-#else
-#define SHA_MASK16 ULLC(0000FFFF,0000FFFF)
-#define SHA_MASK8  ULLC(00FF00FF,00FF00FF)
-#define SHA_HTONLL(x) (t1 = x, \
-  t1 = ((t1 & SHA_MASK8 ) <<  8) | ((t1 >>  8) & SHA_MASK8 ), \
-  t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16), \
-  (t1 >> 32) | (t1 << 32))
-#endif
-#define BYTESWAP8(x)  x = SHA_HTONLL(x)
-
-#else /* no long long */
-
-#if defined(IS_LITTLE_ENDIAN)
-#define ULLC(hi,lo) { 0x ## lo ## U, 0x ## hi ## U }
-#else
-#define ULLC(hi,lo) { 0x ## hi ## U, 0x ## lo ## U }
-#endif
-
-#define SHA_HTONLL(x) ( BYTESWAP4(x.lo), BYTESWAP4(x.hi), \
-   x.hi ^= x.lo ^= x.hi ^= x.lo, x)
-#define BYTESWAP8(x)  do { PRUint32 tmp; BYTESWAP4(x.lo); BYTESWAP4(x.hi); \
-   tmp = x.lo; x.lo = x.hi; x.hi = tmp; } while (0)
-#endif
-
-/* SHA-384 and SHA-512 constants, K512. */
-static const PRUint64 K512[80] = {
-#if PR_BYTES_PER_LONG == 8
-     0x428a2f98d728ae22UL ,  0x7137449123ef65cdUL , 
-     0xb5c0fbcfec4d3b2fUL ,  0xe9b5dba58189dbbcUL ,
-     0x3956c25bf348b538UL ,  0x59f111f1b605d019UL , 
-     0x923f82a4af194f9bUL ,  0xab1c5ed5da6d8118UL ,
-     0xd807aa98a3030242UL ,  0x12835b0145706fbeUL , 
-     0x243185be4ee4b28cUL ,  0x550c7dc3d5ffb4e2UL ,
-     0x72be5d74f27b896fUL ,  0x80deb1fe3b1696b1UL , 
-     0x9bdc06a725c71235UL ,  0xc19bf174cf692694UL ,
-     0xe49b69c19ef14ad2UL ,  0xefbe4786384f25e3UL , 
-     0x0fc19dc68b8cd5b5UL ,  0x240ca1cc77ac9c65UL ,
-     0x2de92c6f592b0275UL ,  0x4a7484aa6ea6e483UL , 
-     0x5cb0a9dcbd41fbd4UL ,  0x76f988da831153b5UL ,
-     0x983e5152ee66dfabUL ,  0xa831c66d2db43210UL , 
-     0xb00327c898fb213fUL ,  0xbf597fc7beef0ee4UL ,
-     0xc6e00bf33da88fc2UL ,  0xd5a79147930aa725UL , 
-     0x06ca6351e003826fUL ,  0x142929670a0e6e70UL ,
-     0x27b70a8546d22ffcUL ,  0x2e1b21385c26c926UL , 
-     0x4d2c6dfc5ac42aedUL ,  0x53380d139d95b3dfUL ,
-     0x650a73548baf63deUL ,  0x766a0abb3c77b2a8UL , 
-     0x81c2c92e47edaee6UL ,  0x92722c851482353bUL ,
-     0xa2bfe8a14cf10364UL ,  0xa81a664bbc423001UL , 
-     0xc24b8b70d0f89791UL ,  0xc76c51a30654be30UL ,
-     0xd192e819d6ef5218UL ,  0xd69906245565a910UL , 
-     0xf40e35855771202aUL ,  0x106aa07032bbd1b8UL ,
-     0x19a4c116b8d2d0c8UL ,  0x1e376c085141ab53UL , 
-     0x2748774cdf8eeb99UL ,  0x34b0bcb5e19b48a8UL ,
-     0x391c0cb3c5c95a63UL ,  0x4ed8aa4ae3418acbUL , 
-     0x5b9cca4f7763e373UL ,  0x682e6ff3d6b2b8a3UL ,
-     0x748f82ee5defb2fcUL ,  0x78a5636f43172f60UL , 
-     0x84c87814a1f0ab72UL ,  0x8cc702081a6439ecUL ,
-     0x90befffa23631e28UL ,  0xa4506cebde82bde9UL , 
-     0xbef9a3f7b2c67915UL ,  0xc67178f2e372532bUL ,
-     0xca273eceea26619cUL ,  0xd186b8c721c0c207UL , 
-     0xeada7dd6cde0eb1eUL ,  0xf57d4f7fee6ed178UL ,
-     0x06f067aa72176fbaUL ,  0x0a637dc5a2c898a6UL , 
-     0x113f9804bef90daeUL ,  0x1b710b35131c471bUL ,
-     0x28db77f523047d84UL ,  0x32caab7b40c72493UL , 
-     0x3c9ebe0a15c9bebcUL ,  0x431d67c49c100d4cUL ,
-     0x4cc5d4becb3e42b6UL ,  0x597f299cfc657e2aUL , 
-     0x5fcb6fab3ad6faecUL ,  0x6c44198c4a475817UL 
-#else
-    ULLC(428a2f98,d728ae22), ULLC(71374491,23ef65cd), 
-    ULLC(b5c0fbcf,ec4d3b2f), ULLC(e9b5dba5,8189dbbc),
-    ULLC(3956c25b,f348b538), ULLC(59f111f1,b605d019), 
-    ULLC(923f82a4,af194f9b), ULLC(ab1c5ed5,da6d8118),
-    ULLC(d807aa98,a3030242), ULLC(12835b01,45706fbe), 
-    ULLC(243185be,4ee4b28c), ULLC(550c7dc3,d5ffb4e2),
-    ULLC(72be5d74,f27b896f), ULLC(80deb1fe,3b1696b1), 
-    ULLC(9bdc06a7,25c71235), ULLC(c19bf174,cf692694),
-    ULLC(e49b69c1,9ef14ad2), ULLC(efbe4786,384f25e3), 
-    ULLC(0fc19dc6,8b8cd5b5), ULLC(240ca1cc,77ac9c65),
-    ULLC(2de92c6f,592b0275), ULLC(4a7484aa,6ea6e483), 
-    ULLC(5cb0a9dc,bd41fbd4), ULLC(76f988da,831153b5),
-    ULLC(983e5152,ee66dfab), ULLC(a831c66d,2db43210), 
-    ULLC(b00327c8,98fb213f), ULLC(bf597fc7,beef0ee4),
-    ULLC(c6e00bf3,3da88fc2), ULLC(d5a79147,930aa725), 
-    ULLC(06ca6351,e003826f), ULLC(14292967,0a0e6e70),
-    ULLC(27b70a85,46d22ffc), ULLC(2e1b2138,5c26c926), 
-    ULLC(4d2c6dfc,5ac42aed), ULLC(53380d13,9d95b3df),
-    ULLC(650a7354,8baf63de), ULLC(766a0abb,3c77b2a8), 
-    ULLC(81c2c92e,47edaee6), ULLC(92722c85,1482353b),
-    ULLC(a2bfe8a1,4cf10364), ULLC(a81a664b,bc423001), 
-    ULLC(c24b8b70,d0f89791), ULLC(c76c51a3,0654be30),
-    ULLC(d192e819,d6ef5218), ULLC(d6990624,5565a910), 
-    ULLC(f40e3585,5771202a), ULLC(106aa070,32bbd1b8),
-    ULLC(19a4c116,b8d2d0c8), ULLC(1e376c08,5141ab53), 
-    ULLC(2748774c,df8eeb99), ULLC(34b0bcb5,e19b48a8),
-    ULLC(391c0cb3,c5c95a63), ULLC(4ed8aa4a,e3418acb), 
-    ULLC(5b9cca4f,7763e373), ULLC(682e6ff3,d6b2b8a3),
-    ULLC(748f82ee,5defb2fc), ULLC(78a5636f,43172f60), 
-    ULLC(84c87814,a1f0ab72), ULLC(8cc70208,1a6439ec),
-    ULLC(90befffa,23631e28), ULLC(a4506ceb,de82bde9), 
-    ULLC(bef9a3f7,b2c67915), ULLC(c67178f2,e372532b),
-    ULLC(ca273ece,ea26619c), ULLC(d186b8c7,21c0c207), 
-    ULLC(eada7dd6,cde0eb1e), ULLC(f57d4f7f,ee6ed178),
-    ULLC(06f067aa,72176fba), ULLC(0a637dc5,a2c898a6), 
-    ULLC(113f9804,bef90dae), ULLC(1b710b35,131c471b),
-    ULLC(28db77f5,23047d84), ULLC(32caab7b,40c72493), 
-    ULLC(3c9ebe0a,15c9bebc), ULLC(431d67c4,9c100d4c),
-    ULLC(4cc5d4be,cb3e42b6), ULLC(597f299c,fc657e2a), 
-    ULLC(5fcb6fab,3ad6faec), ULLC(6c44198c,4a475817)
-#endif
-};
-
-struct SHA512ContextStr {
-    union {
-	PRUint64 w[80];	    /* message schedule, input buffer, plus 64 words */
-	PRUint32 l[160];
-	PRUint8  b[640];
-    } u;
-    PRUint64 h[8];	    /* 8 state variables */
-    PRUint64 sizeLo;	    /* 64-bit count of hashed bytes. */
-};
-
-/* =========== SHA512 implementation ===================================== */
-
-/* SHA-512 initial hash values */
-static const PRUint64 H512[8] = {
-#if PR_BYTES_PER_LONG == 8
-     0x6a09e667f3bcc908UL ,  0xbb67ae8584caa73bUL , 
-     0x3c6ef372fe94f82bUL ,  0xa54ff53a5f1d36f1UL , 
-     0x510e527fade682d1UL ,  0x9b05688c2b3e6c1fUL , 
-     0x1f83d9abfb41bd6bUL ,  0x5be0cd19137e2179UL 
-#else
-    ULLC(6a09e667,f3bcc908), ULLC(bb67ae85,84caa73b), 
-    ULLC(3c6ef372,fe94f82b), ULLC(a54ff53a,5f1d36f1), 
-    ULLC(510e527f,ade682d1), ULLC(9b05688c,2b3e6c1f), 
-    ULLC(1f83d9ab,fb41bd6b), ULLC(5be0cd19,137e2179)
-#endif
-};
-
-
-SHA512Context *
-SHA512_NewContext(void)
-{
-    SHA512Context *ctx = PORT_New(SHA512Context);
-    return ctx;
-}
-
-void 
-SHA512_DestroyContext(SHA512Context *ctx, PRBool freeit)
-{
-    memset(ctx, 0, sizeof *ctx);
-    if (freeit) {
-        PORT_Free(ctx);
-    }
-}
-
-void 
-SHA512_Begin(SHA512Context *ctx)
-{
-    memset(ctx, 0, sizeof *ctx);
-    memcpy(H, H512, sizeof H512);
-}
-
-#if defined(SHA512_TRACE)
-#if defined(HAVE_LONG_LONG)
-#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %016lx, %s = %016lx\n", \
-			       n, #e, d, #a, h);
-#else
-#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %08x%08x, %s = %08x%08x\n", \
-			       n, #e, d.hi, d.lo, #a, h.hi, h.lo);
-#endif
-#else
-#define DUMP(n,a,d,e,h)
-#endif
-
-#if defined(HAVE_LONG_LONG)
-
-#define ADDTO(x,y) y += x
-
-#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
-
-#define ROUND(n,a,b,c,d,e,f,g,h) \
-    h += S1(e) + Ch(e,f,g) + K512[n] + W[n]; \
-    d += h; \
-    h += S0(a) + Maj(a,b,c); \
-    DUMP(n,a,d,e,h)
-
-#else /* use only 32-bit variables, and don't unroll loops */
-
-#undef  NOUNROLL512
-#define NOUNROLL512 1
-
-#define ADDTO(x,y) y.lo += x.lo; y.hi += x.hi + (x.lo > y.lo)
-
-#define ROTR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
-#define ROTR64A(x,n,lo,hi) (x.lo << (64-n) | x.hi >> (n-32))
-#define  SHR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
-
-/* Capitol Sigma and lower case sigma functions */
-#define s0lo(x) (ROTR64a(x,1,lo,hi) ^ ROTR64a(x,8,lo,hi) ^ SHR64a(x,7,lo,hi))
-#define s0hi(x) (ROTR64a(x,1,hi,lo) ^ ROTR64a(x,8,hi,lo) ^ (x.hi >> 7))
-
-#define s1lo(x) (ROTR64a(x,19,lo,hi) ^ ROTR64A(x,61,lo,hi) ^ SHR64a(x,6,lo,hi))
-#define s1hi(x) (ROTR64a(x,19,hi,lo) ^ ROTR64A(x,61,hi,lo) ^ (x.hi >> 6))
-
-#define S0lo(x)(ROTR64a(x,28,lo,hi) ^ ROTR64A(x,34,lo,hi) ^ ROTR64A(x,39,lo,hi))
-#define S0hi(x)(ROTR64a(x,28,hi,lo) ^ ROTR64A(x,34,hi,lo) ^ ROTR64A(x,39,hi,lo))
-
-#define S1lo(x)(ROTR64a(x,14,lo,hi) ^ ROTR64a(x,18,lo,hi) ^ ROTR64A(x,41,lo,hi))
-#define S1hi(x)(ROTR64a(x,14,hi,lo) ^ ROTR64a(x,18,hi,lo) ^ ROTR64A(x,41,hi,lo))
-
-/* 32-bit versions of Ch and Maj */
-#define Chxx(x,y,z,lo) ((x.lo & y.lo) ^ (~x.lo & z.lo))
-#define Majx(x,y,z,lo) ((x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo))
-
-#define INITW(t) \
-    do { \
-	PRUint32 lo, tm; \
-	PRUint32 cy = 0; \
-	lo = s1lo(W[t-2]); \
-	lo += (tm = W[t-7].lo);     if (lo < tm) cy++; \
-	lo += (tm = s0lo(W[t-15])); if (lo < tm) cy++; \
-	lo += (tm = W[t-16].lo);    if (lo < tm) cy++; \
-	W[t].lo = lo; \
-	W[t].hi = cy + s1hi(W[t-2]) + W[t-7].hi + s0hi(W[t-15]) + W[t-16].hi; \
-    } while (0)
-
-#define ROUND(n,a,b,c,d,e,f,g,h) \
-    { \
-	PRUint32 lo, tm, cy; \
-	lo  = S1lo(e); \
-	lo += (tm = Chxx(e,f,g,lo));    cy = (lo < tm); \
-	lo += (tm = K512[n].lo);	if (lo < tm) cy++; \
-	lo += (tm =    W[n].lo);	if (lo < tm) cy++; \
-	h.lo += lo;			if (h.lo < lo) cy++; \
-	h.hi += cy + S1hi(e) + Chxx(e,f,g,hi) + K512[n].hi + W[n].hi; \
-	d.lo += h.lo; \
-	d.hi += h.hi + (d.lo < h.lo); \
-	lo  = S0lo(a);  \
-	lo += (tm = Majx(a,b,c,lo));	cy = (lo < tm); \
-	h.lo += lo;			if (h.lo < lo) cy++; \
-	h.hi += cy + S0hi(a) + Majx(a,b,c,hi); \
-	DUMP(n,a,d,e,h) \
-    }
-#endif
-
-static void
-SHA512_Compress(SHA512Context *ctx)
-{
-#if defined(IS_LITTLE_ENDIAN)
-  {
-#if defined(HAVE_LONG_LONG)
-    PRUint64 t1;
-#else
-    PRUint32 t1;
-#endif
-    BYTESWAP8(W[0]);
-    BYTESWAP8(W[1]);
-    BYTESWAP8(W[2]);
-    BYTESWAP8(W[3]);
-    BYTESWAP8(W[4]);
-    BYTESWAP8(W[5]);
-    BYTESWAP8(W[6]);
-    BYTESWAP8(W[7]);
-    BYTESWAP8(W[8]);
-    BYTESWAP8(W[9]);
-    BYTESWAP8(W[10]);
-    BYTESWAP8(W[11]);
-    BYTESWAP8(W[12]);
-    BYTESWAP8(W[13]);
-    BYTESWAP8(W[14]);
-    BYTESWAP8(W[15]);
-  }
-#endif
-
-  {
-    PRUint64 t1, t2;
-#ifdef NOUNROLL512
-    {
-	/* prepare the "message schedule"   */
-	int t;
-	for (t = 16; t < 80; ++t) {
-	    INITW(t);
-	}
-    }
-#else
-    INITW(16);
-    INITW(17);
-    INITW(18);
-    INITW(19);
-
-    INITW(20);
-    INITW(21);
-    INITW(22);
-    INITW(23);
-    INITW(24);
-    INITW(25);
-    INITW(26);
-    INITW(27);
-    INITW(28);
-    INITW(29);
-
-    INITW(30);
-    INITW(31);
-    INITW(32);
-    INITW(33);
-    INITW(34);
-    INITW(35);
-    INITW(36);
-    INITW(37);
-    INITW(38);
-    INITW(39);
-
-    INITW(40);
-    INITW(41);
-    INITW(42);
-    INITW(43);
-    INITW(44);
-    INITW(45);
-    INITW(46);
-    INITW(47);
-    INITW(48);
-    INITW(49);
-
-    INITW(50);
-    INITW(51);
-    INITW(52);
-    INITW(53);
-    INITW(54);
-    INITW(55);
-    INITW(56);
-    INITW(57);
-    INITW(58);
-    INITW(59);
-
-    INITW(60);
-    INITW(61);
-    INITW(62);
-    INITW(63);
-    INITW(64);
-    INITW(65);
-    INITW(66);
-    INITW(67);
-    INITW(68);
-    INITW(69);
-
-    INITW(70);
-    INITW(71);
-    INITW(72);
-    INITW(73);
-    INITW(74);
-    INITW(75);
-    INITW(76);
-    INITW(77);
-    INITW(78);
-    INITW(79);
-#endif
-  }
-#ifdef SHA512_TRACE
-  {
-    int i;
-    for (i = 0; i < 80; ++i) {
-#ifdef HAVE_LONG_LONG
-	printf("W[%2d] = %016lx\n", i, W[i]);
-#else
-	printf("W[%2d] = %08x%08x\n", i, W[i].hi, W[i].lo);
-#endif
-    }
-  }
-#endif
-  {
-    PRUint64 a, b, c, d, e, f, g, h;
-
-    a = H[0];
-    b = H[1];
-    c = H[2];
-    d = H[3];
-    e = H[4];
-    f = H[5];
-    g = H[6];
-    h = H[7];
-
-#ifdef NOUNROLL512
-    {
-	int t;
-	for (t = 0; t < 80; t+= 8) {
-	    ROUND(t+0,a,b,c,d,e,f,g,h)
-	    ROUND(t+1,h,a,b,c,d,e,f,g)
-	    ROUND(t+2,g,h,a,b,c,d,e,f)
-	    ROUND(t+3,f,g,h,a,b,c,d,e)
-	    ROUND(t+4,e,f,g,h,a,b,c,d)
-	    ROUND(t+5,d,e,f,g,h,a,b,c)
-	    ROUND(t+6,c,d,e,f,g,h,a,b)
-	    ROUND(t+7,b,c,d,e,f,g,h,a)
-	}
-    }
-#else
-    ROUND( 0,a,b,c,d,e,f,g,h)
-    ROUND( 1,h,a,b,c,d,e,f,g)
-    ROUND( 2,g,h,a,b,c,d,e,f)
-    ROUND( 3,f,g,h,a,b,c,d,e)
-    ROUND( 4,e,f,g,h,a,b,c,d)
-    ROUND( 5,d,e,f,g,h,a,b,c)
-    ROUND( 6,c,d,e,f,g,h,a,b)
-    ROUND( 7,b,c,d,e,f,g,h,a)
-
-    ROUND( 8,a,b,c,d,e,f,g,h)
-    ROUND( 9,h,a,b,c,d,e,f,g)
-    ROUND(10,g,h,a,b,c,d,e,f)
-    ROUND(11,f,g,h,a,b,c,d,e)
-    ROUND(12,e,f,g,h,a,b,c,d)
-    ROUND(13,d,e,f,g,h,a,b,c)
-    ROUND(14,c,d,e,f,g,h,a,b)
-    ROUND(15,b,c,d,e,f,g,h,a)
-
-    ROUND(16,a,b,c,d,e,f,g,h)
-    ROUND(17,h,a,b,c,d,e,f,g)
-    ROUND(18,g,h,a,b,c,d,e,f)
-    ROUND(19,f,g,h,a,b,c,d,e)
-    ROUND(20,e,f,g,h,a,b,c,d)
-    ROUND(21,d,e,f,g,h,a,b,c)
-    ROUND(22,c,d,e,f,g,h,a,b)
-    ROUND(23,b,c,d,e,f,g,h,a)
-
-    ROUND(24,a,b,c,d,e,f,g,h)
-    ROUND(25,h,a,b,c,d,e,f,g)
-    ROUND(26,g,h,a,b,c,d,e,f)
-    ROUND(27,f,g,h,a,b,c,d,e)
-    ROUND(28,e,f,g,h,a,b,c,d)
-    ROUND(29,d,e,f,g,h,a,b,c)
-    ROUND(30,c,d,e,f,g,h,a,b)
-    ROUND(31,b,c,d,e,f,g,h,a)
-
-    ROUND(32,a,b,c,d,e,f,g,h)
-    ROUND(33,h,a,b,c,d,e,f,g)
-    ROUND(34,g,h,a,b,c,d,e,f)
-    ROUND(35,f,g,h,a,b,c,d,e)
-    ROUND(36,e,f,g,h,a,b,c,d)
-    ROUND(37,d,e,f,g,h,a,b,c)
-    ROUND(38,c,d,e,f,g,h,a,b)
-    ROUND(39,b,c,d,e,f,g,h,a)
-
-    ROUND(40,a,b,c,d,e,f,g,h)
-    ROUND(41,h,a,b,c,d,e,f,g)
-    ROUND(42,g,h,a,b,c,d,e,f)
-    ROUND(43,f,g,h,a,b,c,d,e)
-    ROUND(44,e,f,g,h,a,b,c,d)
-    ROUND(45,d,e,f,g,h,a,b,c)
-    ROUND(46,c,d,e,f,g,h,a,b)
-    ROUND(47,b,c,d,e,f,g,h,a)
-
-    ROUND(48,a,b,c,d,e,f,g,h)
-    ROUND(49,h,a,b,c,d,e,f,g)
-    ROUND(50,g,h,a,b,c,d,e,f)
-    ROUND(51,f,g,h,a,b,c,d,e)
-    ROUND(52,e,f,g,h,a,b,c,d)
-    ROUND(53,d,e,f,g,h,a,b,c)
-    ROUND(54,c,d,e,f,g,h,a,b)
-    ROUND(55,b,c,d,e,f,g,h,a)
-
-    ROUND(56,a,b,c,d,e,f,g,h)
-    ROUND(57,h,a,b,c,d,e,f,g)
-    ROUND(58,g,h,a,b,c,d,e,f)
-    ROUND(59,f,g,h,a,b,c,d,e)
-    ROUND(60,e,f,g,h,a,b,c,d)
-    ROUND(61,d,e,f,g,h,a,b,c)
-    ROUND(62,c,d,e,f,g,h,a,b)
-    ROUND(63,b,c,d,e,f,g,h,a)
-
-    ROUND(64,a,b,c,d,e,f,g,h)
-    ROUND(65,h,a,b,c,d,e,f,g)
-    ROUND(66,g,h,a,b,c,d,e,f)
-    ROUND(67,f,g,h,a,b,c,d,e)
-    ROUND(68,e,f,g,h,a,b,c,d)
-    ROUND(69,d,e,f,g,h,a,b,c)
-    ROUND(70,c,d,e,f,g,h,a,b)
-    ROUND(71,b,c,d,e,f,g,h,a)
-
-    ROUND(72,a,b,c,d,e,f,g,h)
-    ROUND(73,h,a,b,c,d,e,f,g)
-    ROUND(74,g,h,a,b,c,d,e,f)
-    ROUND(75,f,g,h,a,b,c,d,e)
-    ROUND(76,e,f,g,h,a,b,c,d)
-    ROUND(77,d,e,f,g,h,a,b,c)
-    ROUND(78,c,d,e,f,g,h,a,b)
-    ROUND(79,b,c,d,e,f,g,h,a)
-#endif
-
-    ADDTO(a,H[0]);
-    ADDTO(b,H[1]);
-    ADDTO(c,H[2]);
-    ADDTO(d,H[3]);
-    ADDTO(e,H[4]);
-    ADDTO(f,H[5]);
-    ADDTO(g,H[6]);
-    ADDTO(h,H[7]);
-  }
-}
-
-void 
-SHA512_Update(SHA512Context *ctx, const unsigned char *input,
-              unsigned int inputLen)
-{
-    unsigned int inBuf;
-    if (!inputLen)
-    	return;
-
-#if defined(HAVE_LONG_LONG)
-    inBuf = (unsigned int)ctx->sizeLo & 0x7f;
-    /* Add inputLen into the count of bytes processed, before processing */
-    ctx->sizeLo += inputLen;
-#else
-    inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f;
-    ctx->sizeLo.lo += inputLen;
-    if (ctx->sizeLo.lo < inputLen) ctx->sizeLo.hi++;
-#endif
-
-    /* if data already in buffer, attemp to fill rest of buffer */
-    if (inBuf) {
-    	unsigned int todo = SHA512_BLOCK_LENGTH - inBuf;
-	if (inputLen < todo)
-	    todo = inputLen;
-	memcpy(B + inBuf, input, todo);
-	input    += todo;
-	inputLen -= todo;
-	if (inBuf + todo == SHA512_BLOCK_LENGTH)
-	    SHA512_Compress(ctx);
-    }
-
-    /* if enough data to fill one or more whole buffers, process them. */
-    while (inputLen >= SHA512_BLOCK_LENGTH) {
-    	memcpy(B, input, SHA512_BLOCK_LENGTH);
-	input    += SHA512_BLOCK_LENGTH;
-	inputLen -= SHA512_BLOCK_LENGTH;
-	SHA512_Compress(ctx);
-    }
-    /* if data left over, fill it into buffer */
-    if (inputLen) 
-    	memcpy(B, input, inputLen);
-}
-
-void 
-SHA512_End(SHA512Context *ctx, unsigned char *digest,
-           unsigned int *digestLen, unsigned int maxDigestLen)
-{
-#if defined(HAVE_LONG_LONG)
-    unsigned int inBuf  = (unsigned int)ctx->sizeLo & 0x7f;
-    PRUint64 t1;
-#else
-    unsigned int inBuf  = (unsigned int)ctx->sizeLo.lo & 0x7f;
-    PRUint32 t1;
-#endif
-    unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
-    PRUint64 lo;
-    LL_SHL(lo, ctx->sizeLo, 3);
-
-    SHA512_Update(ctx, pad, padLen);
-
-#if defined(HAVE_LONG_LONG)
-    W[14] = 0;
-#else
-    W[14].lo = 0;
-    W[14].hi = 0;
-#endif
-
-    W[15] = lo;
-#if defined(IS_LITTLE_ENDIAN)
-    BYTESWAP8(W[15]);
-#endif
-    SHA512_Compress(ctx);
-
-    /* now output the answer */
-#if defined(IS_LITTLE_ENDIAN)
-    BYTESWAP8(H[0]);
-    BYTESWAP8(H[1]);
-    BYTESWAP8(H[2]);
-    BYTESWAP8(H[3]);
-    BYTESWAP8(H[4]);
-    BYTESWAP8(H[5]);
-    BYTESWAP8(H[6]);
-    BYTESWAP8(H[7]);
-#endif
-    padLen = PR_MIN(SHA512_LENGTH, maxDigestLen);
-    memcpy(digest, H, padLen);
-    if (digestLen)
-	*digestLen = padLen;
-}
-
-void
-SHA512_EndRaw(SHA512Context *ctx, unsigned char *digest,
-              unsigned int *digestLen, unsigned int maxDigestLen)
-{
-#if defined(HAVE_LONG_LONG)
-    PRUint64 t1;
-#else
-    PRUint32 t1;
-#endif
-    PRUint64 h[8];
-    unsigned int len;
-
-    memcpy(h, ctx->h, sizeof(h));
-
-#if defined(IS_LITTLE_ENDIAN)
-    BYTESWAP8(h[0]);
-    BYTESWAP8(h[1]);
-    BYTESWAP8(h[2]);
-    BYTESWAP8(h[3]);
-    BYTESWAP8(h[4]);
-    BYTESWAP8(h[5]);
-    BYTESWAP8(h[6]);
-    BYTESWAP8(h[7]);
-#endif
-    len = PR_MIN(SHA512_LENGTH, maxDigestLen);
-    memcpy(digest, h, len);
-    if (digestLen)
-	*digestLen = len;
-}
-
-SECStatus 
-SHA512_HashBuf(unsigned char *dest, const unsigned char *src, 
-               PRUint32 src_length)
-{
-    SHA512Context ctx;
-    unsigned int outLen;
-
-    SHA512_Begin(&ctx);
-    SHA512_Update(&ctx, src, src_length);
-    SHA512_End(&ctx, dest, &outLen, SHA512_LENGTH);
-    memset(&ctx, 0, sizeof ctx);
-
-    return SECSuccess;
-}
-
-
-SECStatus 
-SHA512_Hash(unsigned char *dest, const char *src)
-{
-    return SHA512_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
-}
-
-
-void SHA512_TraceState(SHA512Context *ctx) { }
-
-unsigned int 
-SHA512_FlattenSize(SHA512Context *ctx)
-{
-    return sizeof *ctx;
-}
-
-SECStatus 
-SHA512_Flatten(SHA512Context *ctx,unsigned char *space)
-{
-    PORT_Memcpy(space, ctx, sizeof *ctx);
-    return SECSuccess;
-}
-
-SHA512Context * 
-SHA512_Resurrect(unsigned char *space, void *arg)
-{
-    SHA512Context *ctx = SHA512_NewContext();
-    if (ctx) 
-	PORT_Memcpy(ctx, space, sizeof *ctx);
-    return ctx;
-}
-
-void SHA512_Clone(SHA512Context *dest, SHA512Context *src) 
-{
-    memcpy(dest, src, sizeof *dest);
-}
-
-/* ======================================================================= */
-/* SHA384 uses a SHA512Context as the real context. 
-** The only differences between SHA384 an SHA512 are:
-** a) the intialization values for the context, and
-** b) the number of bytes of data produced as output.
-*/
-
-/* SHA-384 initial hash values */
-static const PRUint64 H384[8] = {
-#if PR_BYTES_PER_LONG == 8
-     0xcbbb9d5dc1059ed8UL ,  0x629a292a367cd507UL , 
-     0x9159015a3070dd17UL ,  0x152fecd8f70e5939UL , 
-     0x67332667ffc00b31UL ,  0x8eb44a8768581511UL , 
-     0xdb0c2e0d64f98fa7UL ,  0x47b5481dbefa4fa4UL 
-#else
-    ULLC(cbbb9d5d,c1059ed8), ULLC(629a292a,367cd507), 
-    ULLC(9159015a,3070dd17), ULLC(152fecd8,f70e5939), 
-    ULLC(67332667,ffc00b31), ULLC(8eb44a87,68581511), 
-    ULLC(db0c2e0d,64f98fa7), ULLC(47b5481d,befa4fa4)
-#endif
-};
-
-SHA384Context *
-SHA384_NewContext(void)
-{
-    return SHA512_NewContext();
-}
-
-void 
-SHA384_DestroyContext(SHA384Context *ctx, PRBool freeit)
-{
-    SHA512_DestroyContext(ctx, freeit);
-}
-
-void 
-SHA384_Begin(SHA384Context *ctx)
-{
-    memset(ctx, 0, sizeof *ctx);
-    memcpy(H, H384, sizeof H384);
-}
-
-void 
-SHA384_Update(SHA384Context *ctx, const unsigned char *input,
-		    unsigned int inputLen)
-{
-    SHA512_Update(ctx, input, inputLen);
-}
-
-void 
-SHA384_End(SHA384Context *ctx, unsigned char *digest,
-		 unsigned int *digestLen, unsigned int maxDigestLen)
-{
-    unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH);
-    SHA512_End(ctx, digest, digestLen, maxLen);
-}
-
-void
-SHA384_EndRaw(SHA384Context *ctx, unsigned char *digest,
-	      unsigned int *digestLen, unsigned int maxDigestLen)
-{
-    unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH);
-    SHA512_EndRaw(ctx, digest, digestLen, maxLen);
-}
-
-SECStatus 
-SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
-	       PRUint32 src_length)
-{
-    SHA512Context ctx;
-    unsigned int outLen;
-
-    SHA384_Begin(&ctx);
-    SHA512_Update(&ctx, src, src_length);
-    SHA512_End(&ctx, dest, &outLen, SHA384_LENGTH);
-    memset(&ctx, 0, sizeof ctx);
-
-    return SECSuccess;
-}
-
-SECStatus 
-SHA384_Hash(unsigned char *dest, const char *src)
-{
-    return SHA384_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
-}
-
-void SHA384_TraceState(SHA384Context *ctx) { }
-
-unsigned int 
-SHA384_FlattenSize(SHA384Context *ctx)
-{
-    return sizeof(SHA384Context);
-}
-
-SECStatus 
-SHA384_Flatten(SHA384Context *ctx,unsigned char *space)
-{
-    return SHA512_Flatten(ctx, space);
-}
-
-SHA384Context * 
-SHA384_Resurrect(unsigned char *space, void *arg)
-{
-    return SHA512_Resurrect(space, arg);
-}
-
-void SHA384_Clone(SHA384Context *dest, SHA384Context *src) 
-{
-    memcpy(dest, src, sizeof *dest);
-}
-
-/* ======================================================================= */
-#ifdef SELFTEST
-#include <stdio.h>
-
-static const char abc[] = { "abc" };
-static const char abcdbc[] = { 
-    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-};
-static const char abcdef[] = { 
-    "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
-    "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" 
-};
-
-void
-dumpHash32(const unsigned char *buf, unsigned int bufLen)
-{
-    unsigned int i;
-    for (i = 0; i < bufLen; i += 4) {
-	printf(" %02x%02x%02x%02x", buf[i], buf[i+1], buf[i+2], buf[i+3]);
-    }
-    printf("\n");
-}
-
-void test256(void)
-{
-    unsigned char outBuf[SHA256_LENGTH];
-
-    printf("SHA256, input = %s\n", abc);
-    SHA256_Hash(outBuf, abc);
-    dumpHash32(outBuf, sizeof outBuf);
-
-    printf("SHA256, input = %s\n", abcdbc);
-    SHA256_Hash(outBuf, abcdbc);
-    dumpHash32(outBuf, sizeof outBuf);
-}
-
-void test224(void)
-{
-    SHA224Context ctx;
-    unsigned char a1000times[1000];
-    unsigned int outLen;
-    unsigned char outBuf[SHA224_LENGTH];
-    int i;
-
-    /* Test Vector 1 */
-    printf("SHA224, input = %s\n", abc);
-    SHA224_Hash(outBuf, abc);
-    dumpHash32(outBuf, sizeof outBuf);
-
-    /* Test Vector 2 */
-    printf("SHA224, input = %s\n", abcdbc);
-    SHA224_Hash(outBuf, abcdbc);
-    dumpHash32(outBuf, sizeof outBuf);
-
-    /* Test Vector 3 */
-
-    /* to hash one million 'a's perform 1000
-     * sha224 updates on a buffer with 1000 'a's 
-     */
-    memset(a1000times, 'a', 1000);
-    printf("SHA224, input = %s\n", "a one million times");
-    SHA224_Begin(&ctx);
-    for (i = 0; i < 1000; i++)
-        SHA224_Update(&ctx, a1000times, 1000);
-    SHA224_End(&ctx, outBuf, &outLen, SHA224_LENGTH);
-    dumpHash32(outBuf, sizeof outBuf);
-}
-
-void
-dumpHash64(const unsigned char *buf, unsigned int bufLen)
-{
-    unsigned int i;
-    for (i = 0; i < bufLen; i += 8) {
-    	if (i % 32 == 0)
-	    printf("\n");
-	printf(" %02x%02x%02x%02x%02x%02x%02x%02x", 
-	       buf[i  ], buf[i+1], buf[i+2], buf[i+3],
-	       buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
-    }
-    printf("\n");
-}
-
-void test512(void)
-{
-    unsigned char outBuf[SHA512_LENGTH];
-
-    printf("SHA512, input = %s\n", abc);
-    SHA512_Hash(outBuf, abc);
-    dumpHash64(outBuf, sizeof outBuf);
-
-    printf("SHA512, input = %s\n", abcdef);
-    SHA512_Hash(outBuf, abcdef);
-    dumpHash64(outBuf, sizeof outBuf);
-}
-
-void time512(void)
-{
-    unsigned char outBuf[SHA512_LENGTH];
-
-    SHA512_Hash(outBuf, abc);
-    SHA512_Hash(outBuf, abcdef);
-}
-
-void test384(void)
-{
-    unsigned char outBuf[SHA384_LENGTH];
-
-    printf("SHA384, input = %s\n", abc);
-    SHA384_Hash(outBuf, abc);
-    dumpHash64(outBuf, sizeof outBuf);
-
-    printf("SHA384, input = %s\n", abcdef);
-    SHA384_Hash(outBuf, abcdef);
-    dumpHash64(outBuf, sizeof outBuf);
-}
-
-int main (int argc, char *argv[], char *envp[])
-{
-    int i = 1;
-    if (argc > 1) {
-    	i = atoi(argv[1]);
-    }
-    if (i < 2) {
-	test224();
-	test256();
-	test384();
-	test512();
-    } else {
-    	while (i-- > 0) {
-	    time512();
-	}
-	printf("done\n");
-    }
-    return 0;
-}
-
-void *PORT_Alloc(size_t len) 		{ return malloc(len); }
-void PORT_Free(void *ptr)		{ free(ptr); }
-void PORT_ZFree(void *ptr, size_t len)  { memset(ptr, 0, len); free(ptr); }
-#endif
copy from security/nss/lib/freebl/blapi.h
copy to ipc/app/sha256.h
--- a/security/nss/lib/freebl/blapi.h
+++ b/ipc/app/sha256.h
@@ -1,1593 +1,46 @@
-/*
- * blapi.h - public prototypes for the freebl library
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef _BLAPI_H_
-#define _BLAPI_H_
-
-#include "blapit.h"
-#include "hasht.h"
-#include "alghmac.h"
-
-SEC_BEGIN_PROTOS
-
-/*
-** RSA encryption/decryption. When encrypting/decrypting the output
-** buffer must be at least the size of the public key modulus.
-*/
-
-extern SECStatus BL_Init(void);
-
-/*
-** Generate and return a new RSA public and private key.
-**	Both keys are encoded in a single RSAPrivateKey structure.
-**	"cx" is the random number generator context
-**	"keySizeInBits" is the size of the key to be generated, in bits.
-**	   512, 1024, etc.
-**	"publicExponent" when not NULL is a pointer to some data that
-**	   represents the public exponent to use. The data is a byte
-**	   encoded integer, in "big endian" order.
-*/
-extern RSAPrivateKey *RSA_NewKey(int         keySizeInBits,
-				 SECItem *   publicExponent);
-
-/*
-** Perform a raw public-key operation 
-**	Length of input and output buffers are equal to key's modulus len.
-*/
-extern SECStatus RSA_PublicKeyOp(RSAPublicKey *   key,
-				 unsigned char *  output,
-				 const unsigned char *  input);
-
-/*
-** Perform a raw private-key operation 
-**	Length of input and output buffers are equal to key's modulus len.
-*/
-extern SECStatus RSA_PrivateKeyOp(RSAPrivateKey *  key,
-				  unsigned char *  output,
-				  const unsigned char *  input);
-
-/*
-** Perform a raw private-key operation, and check the parameters used in
-** the operation for validity by performing a test operation first.
-**	Length of input and output buffers are equal to key's modulus len.
-*/
-extern SECStatus RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey *  key,
-				               unsigned char *  output,
-				               const unsigned char *  input);
-
-/*
-** Perform a check of private key parameters for consistency.
-*/
-extern SECStatus RSA_PrivateKeyCheck(const RSAPrivateKey *key);
-
-/*
-** Given only minimal private key parameters, fill in the rest of the
-** parameters.
-**
-**
-** All the entries, including those supplied by the caller, will be 
-** overwritten with data alocated out of the arena.
-**
-** If no arena is supplied, one will be created.
-**
-** The following fields must be supplied in order for this function
-** to succeed:
-**   one of either publicExponent or privateExponent
-**   two more of the following 5 parameters (not counting the above).
-**      modulus (n)
-**      prime1  (p)
-**      prime2  (q)
-**      publicExponent (e)
-**      privateExponent (d)
-**
-** NOTE: if only the publicExponent, privateExponent, and one prime is given,
-** then there may be more than one RSA key that matches that combination. If
-** we find 2 possible valid keys that meet this criteria, we return an error.
-** If we return the wrong key, and the original modulus is compared to the
-** new modulus, both can be factored by calculateing gcd(n_old,n_new) to get
-** the common prime.
-**
-** NOTE: in some cases the publicExponent must be less than 2^23 for this
-** function to work correctly. (The case where we have only one of: modulus
-** prime1 and prime2).
-**
-** All parameters will be replaced in the key structure with new parameters
-** allocated out of the arena. There is no attempt to free the old structures.
-** prime1 will always be greater than prime2 (even if the caller supplies the
-** smaller prime as prime1 or the larger prime as prime2). The parameters are
-** not overwritten on failure.
-**
-** While the remaining Chinese remainder theorem parameters (dp,dp, and qinv)
-** can also be used in reconstructing the private key, they are currently
-** ignored in this implementation.
-*/
-extern SECStatus RSA_PopulatePrivateKey(RSAPrivateKey *key);
-
-/********************************************************************
-** RSA algorithm
-*/
-
-/********************************************************************
-** Raw signing/encryption/decryption operations.
-**
-** No padding or formatting will be applied.
-** inputLen MUST be equivalent to the modulus size (in bytes).
-*/
-extern SECStatus
-RSA_SignRaw(RSAPrivateKey       * key,
-            unsigned char       * output,
-            unsigned int        * outputLen,
-            unsigned int          maxOutputLen,
-            const unsigned char * input,
-            unsigned int          inputLen);
-
-extern SECStatus
-RSA_CheckSignRaw(RSAPublicKey        * key,
-                 const unsigned char * sig,
-                 unsigned int          sigLen,
-                 const unsigned char * hash,
-                 unsigned int          hashLen);
-
-extern SECStatus
-RSA_CheckSignRecoverRaw(RSAPublicKey        * key,
-                        unsigned char       * data,
-                        unsigned int        * dataLen,
-                        unsigned int          maxDataLen,
-                        const unsigned char * sig,
-                        unsigned int          sigLen);
-
-extern SECStatus
-RSA_EncryptRaw(RSAPublicKey        * key,
-               unsigned char       * output,
-               unsigned int        * outputLen,
-               unsigned int          maxOutputLen,
-               const unsigned char * input,
-               unsigned int          inputLen);
-
-extern SECStatus
-RSA_DecryptRaw(RSAPrivateKey       * key,
-               unsigned char       * output,
-               unsigned int        * outputLen,
-               unsigned int          maxOutputLen,
-               const unsigned char * input,
-               unsigned int          inputLen);
-
-/********************************************************************
-** RSAES-OAEP encryption/decryption, as defined in RFC 3447, Section 7.1.
-**
-** Note: Only MGF1 is supported as the mask generation function. It will be
-** used with maskHashAlg as the inner hash function.
-**
-** Unless performing Known Answer Tests, "seed" should be NULL, indicating that
-** freebl should generate a random value. Otherwise, it should be an octet
-** string of seedLen bytes, which should be the same size as the output of
-** hashAlg.
-*/
-extern SECStatus
-RSA_EncryptOAEP(RSAPublicKey        * key,
-                HASH_HashType         hashAlg,
-                HASH_HashType         maskHashAlg,
-                const unsigned char * label,
-                unsigned int          labelLen,
-                const unsigned char * seed,
-                unsigned int          seedLen,
-                unsigned char       * output,
-                unsigned int        * outputLen,
-                unsigned int          maxOutputLen,
-                const unsigned char * input,
-                unsigned int          inputLen);
-
-extern SECStatus
-RSA_DecryptOAEP(RSAPrivateKey       * key,
-                HASH_HashType         hashAlg,
-                HASH_HashType         maskHashAlg,
-                const unsigned char * label,
-                unsigned int          labelLen,
-                unsigned char       * output,
-                unsigned int        * outputLen,
-                unsigned int          maxOutputLen,
-                const unsigned char * input,
-                unsigned int          inputLen);
-
-/********************************************************************
-** RSAES-PKCS1-v1_5 encryption/decryption, as defined in RFC 3447, Section 7.2.
-*/
-extern SECStatus
-RSA_EncryptBlock(RSAPublicKey        * key,
-                 unsigned char       * output,
-                 unsigned int        * outputLen,
-                 unsigned int          maxOutputLen,
-                 const unsigned char * input,
-                 unsigned int          inputLen);
-
-extern SECStatus
-RSA_DecryptBlock(RSAPrivateKey       * key,
-                 unsigned char       * output,
-                 unsigned int        * outputLen,
-                 unsigned int          maxOutputLen,
-                 const unsigned char * input,
-                 unsigned int          inputLen);
-
-/********************************************************************
-** RSASSA-PSS signing/verifying, as defined in RFC 3447, Section 8.1.
-**
-** Note: Only MGF1 is supported as the mask generation function. It will be
-** used with maskHashAlg as the inner hash function.
-**
-** Unless performing Known Answer Tests, "salt" should be NULL, indicating that
-** freebl should generate a random value.
-*/
-extern SECStatus
-RSA_SignPSS(RSAPrivateKey       * key,
-            HASH_HashType         hashAlg,
-            HASH_HashType         maskHashAlg,
-            const unsigned char * salt,
-            unsigned int          saltLen,
-            unsigned char       * output,
-            unsigned int        * outputLen,
-            unsigned int          maxOutputLen,
-            const unsigned char * input,
-            unsigned int          inputLen);
-
-extern SECStatus
-RSA_CheckSignPSS(RSAPublicKey        * key,
-                 HASH_HashType         hashAlg,
-                 HASH_HashType         maskHashAlg,
-                 unsigned int          saltLen,
-                 const unsigned char * sig,
-                 unsigned int          sigLen,
-                 const unsigned char * hash,
-                 unsigned int          hashLen);
-
-/********************************************************************
-** RSASSA-PKCS1-v1_5 signing/verifying, as defined in RFC 3447, Section 8.2.
-**
-** These functions expect as input to be the raw value to be signed. For most
-** cases using PKCS1-v1_5, this should be the value of T, the DER-encoded
-** DigestInfo structure defined in Section 9.2, Step 2.
-** Note: This can also be used for signatures that use PKCS1-v1_5 padding, such
-** as the signatures used in SSL/TLS, which sign a raw hash.
-*/
-extern SECStatus
-RSA_Sign(RSAPrivateKey       * key,
-         unsigned char       * output,
-         unsigned int        * outputLen,
-         unsigned int          maxOutputLen,
-         const unsigned char * data,
-         unsigned int          dataLen);
-
-extern SECStatus
-RSA_CheckSign(RSAPublicKey        * key,
-              const unsigned char * sig,
-              unsigned int          sigLen,
-              const unsigned char * data,
-              unsigned int          dataLen);
-
-extern SECStatus
-RSA_CheckSignRecover(RSAPublicKey        * key,
-                     unsigned char       * output,
-                     unsigned int        * outputLen,
-                     unsigned int          maxOutputLen,
-                     const unsigned char * sig,
-                     unsigned int          sigLen);
-
-/********************************************************************
-** DSA signing algorithm
-*/
-
-/* Generate a new random value within the interval [2, q-1].
-*/
-extern SECStatus DSA_NewRandom(PLArenaPool * arena, const SECItem * q,
-                               SECItem * random);
-
-/*
-** Generate and return a new DSA public and private key pair,
-**	both of which are encoded into a single DSAPrivateKey struct.
-**	"params" is a pointer to the PQG parameters for the domain
-**	Uses a random seed.
-*/
-extern SECStatus DSA_NewKey(const PQGParams *     params, 
-		            DSAPrivateKey **      privKey);
-
-/* signature is caller-supplied buffer of at least 20 bytes.
-** On input,  signature->len == size of buffer to hold signature.
-**            digest->len    == size of digest.
-** On output, signature->len == size of signature in buffer.
-** Uses a random seed.
-*/
-extern SECStatus DSA_SignDigest(DSAPrivateKey *   key,
-				SECItem *         signature,
-				const SECItem *   digest);
-
-/* signature is caller-supplied buffer of at least 20 bytes.
-** On input,  signature->len == size of buffer to hold signature.
-**            digest->len    == size of digest.
-*/
-extern SECStatus DSA_VerifyDigest(DSAPublicKey *  key,
-				  const SECItem * signature,
-				  const SECItem * digest);
-
-/* For FIPS compliance testing. Seed must be exactly 20 bytes long */
-extern SECStatus DSA_NewKeyFromSeed(const PQGParams *params, 
-                                    const unsigned char * seed,
-                                    DSAPrivateKey **privKey);
-
-/* For FIPS compliance testing. Seed must be exactly 20 bytes. */
-extern SECStatus DSA_SignDigestWithSeed(DSAPrivateKey * key,
-                                        SECItem *       signature,
-                                        const SECItem * digest,
-                                        const unsigned char * seed);
-
-/******************************************************
-** Diffie Helman key exchange algorithm 
-*/
-
-/* Generates parameters for Diffie-Helman key generation.
-**	primeLen is the length in bytes of prime P to be generated.
-*/
-extern SECStatus DH_GenParam(int primeLen, DHParams ** params);
-
-/* Generates a public and private key, both of which are encoded in a single
-**	DHPrivateKey struct. Params is input, privKey are output.  
-**	This is Phase 1 of Diffie Hellman.
-*/
-extern SECStatus DH_NewKey(DHParams *           params, 
-                           DHPrivateKey **	privKey);
-
-/* 
-** DH_Derive does the Diffie-Hellman phase 2 calculation, using the 
-** other party's publicValue, and the prime and our privateValue.
-** maxOutBytes is the requested length of the generated secret in bytes.  
-** A zero value means produce a value of any length up to the size of 
-** the prime.   If successful, derivedSecret->data is set 
-** to the address of the newly allocated buffer containing the derived 
-** secret, and derivedSecret->len is the size of the secret produced.
-** The size of the secret produced will depend on the value of outBytes.
-** If outBytes is 0, the key length will be all the significant bytes of
-** the derived secret (leading zeros are dropped). This length could be less
-** than the length of the prime. If outBytes is nonzero, the length of the
-** produced key will be outBytes long. If the key is truncated, the most
-** significant bytes are truncated. If it is expanded, zero bytes are added
-** at the beginning.
-** It is the caller's responsibility to free the allocated buffer 
-** containing the derived secret.
-*/
-extern SECStatus DH_Derive(SECItem *    publicValue, 
-		           SECItem *    prime, 
-			   SECItem *    privateValue, 
-			   SECItem *    derivedSecret,
-			   unsigned int outBytes);
-
-/* 
-** KEA_CalcKey returns octet string with the private key for a dual
-** Diffie-Helman  key generation as specified for government key exchange.
-*/
-extern SECStatus KEA_Derive(SECItem *prime, 
-                            SECItem *public1, 
-                            SECItem *public2, 
-			    SECItem *private1, 
-			    SECItem *private2,
-			    SECItem *derivedSecret);
-
-/*
- * verify that a KEA or DSA public key is a valid key for this prime and
- * subprime domain.
- */
-extern PRBool KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime);
-
-/****************************************
- * J-PAKE key transport
- */
+// Stripped down version of security/nss/lib/freebl/blapi.h
+// and related headers.
 
-/* Given gx == g^x, create a Schnorr zero-knowledge proof for the value x
- * using the specified hash algorithm and signer ID. The signature is
- * returned in the values gv and r. testRandom must be NULL for a PRNG
- * generated random committment to be used in the sigature. When testRandom
- * is non-NULL, that value must contain a value in the subgroup q; that
- * value will be used instead of a PRNG-generated committment in order to
- * facilitate known-answer tests.
- *
- * If gxIn is non-NULL then it must contain a pre-computed value of g^x that
- * will be used by the function; in this case, the gxOut parameter must be NULL.
- * If the gxIn parameter is NULL then gxOut must be non-NULL; in this case
- * gxOut will contain the value g^x on output.
- *
- * gx (if not supplied by the caller), gv, and r will be allocated in the arena.
- * The arena is *not* optional so do not pass NULL for the arena parameter.
- * The arena should be zeroed when it is freed.
- */
-SECStatus
-JPAKE_Sign(PLArenaPool * arena, const PQGParams * pqg, HASH_HashType hashType,
-           const SECItem * signerID, const SECItem * x,
-           const SECItem * testRandom, const SECItem * gxIn, SECItem * gxOut,
-           SECItem * gv, SECItem * r);
-
-/* Given gx == g^x, verify the Schnorr zero-knowledge proof (gv, r) for the
- * value x using the specified hash algorithm and signer ID.
- *
- * The arena is *not* optional so do not pass NULL for the arena parameter. 
- */
-SECStatus
-JPAKE_Verify(PLArenaPool * arena, const PQGParams * pqg,
-             HASH_HashType hashType, const SECItem * signerID,
-             const SECItem * peerID, const SECItem * gx,
-             const SECItem * gv, const SECItem * r);
-
-/* Call before round 2 with x2, s, and x2s all non-NULL. This will calculate
- * base = g^(x1+x3+x4) (mod p) and x2s = x2*s (mod q). The values to send in 
- * round 2 (A and the proof of knowledge of x2s) can then be calculated with
- * JPAKE_Sign using pqg->base = base and x = x2s.
- *
- * Call after round 2 with x2, s, and x2s all NULL, and passing (gx1, gx2, gx3)
- * instead of (gx1, gx3, gx4). This will calculate base = g^(x1+x2+x3). Then call
- * JPAKE_Verify with pqg->base = base and then JPAKE_Final.
- *
- * base and x2s will be allocated in the arena. The arena is *not* optional so
- * do not pass NULL for the arena parameter. The arena should be zeroed when it
- * is freed.
-*/
-SECStatus
-JPAKE_Round2(PLArenaPool * arena, const SECItem * p, const SECItem  *q,
-             const SECItem * gx1, const SECItem * gx3, const SECItem * gx4,
-             SECItem * base, const SECItem * x2, const SECItem * s, SECItem * x2s);
-
-/* K = (B/g^(x2*x4*s))^x2 (mod p)
- *
- * K will be allocated in the arena. The arena is *not* optional so do not pass
- * NULL for the arena parameter. The arena should be zeroed when it is freed.
- */
-SECStatus
-JPAKE_Final(PLArenaPool * arena, const SECItem * p, const SECItem  *q,
-            const SECItem * x2, const SECItem * gx4, const SECItem * x2s,
-            const SECItem * B, SECItem * K);
-
-/******************************************************
-** Elliptic Curve algorithms
-*/
-
-/* Generates a public and private key, both of which are encoded 
-** in a single ECPrivateKey struct. Params is input, privKey are
-** output.
-*/
-extern SECStatus EC_NewKey(ECParams *          params, 
-                           ECPrivateKey **     privKey);
-
-extern SECStatus EC_NewKeyFromSeed(ECParams *  params, 
-                           ECPrivateKey **     privKey,
-                           const unsigned char* seed,
-                           int                 seedlen);
-
-/* Validates an EC public key as described in Section 5.2.2 of
- * X9.62. Such validation prevents against small subgroup attacks
- * when the ECDH primitive is used with the cofactor.
- */
-extern SECStatus EC_ValidatePublicKey(ECParams * params, 
-                           SECItem *           publicValue);
-
-/* 
-** ECDH_Derive performs a scalar point multiplication of a point
-** representing a (peer's) public key and a large integer representing
-** a private key (its own). Both keys must use the same elliptic curve
-** parameters. If the withCofactor parameter is true, the
-** multiplication also uses the cofactor associated with the curve
-** parameters.  The output of this scheme is the x-coordinate of the
-** resulting point. If successful, derivedSecret->data is set to the
-** address of the newly allocated buffer containing the derived
-** secret, and derivedSecret->len is the size of the secret
-** produced. It is the caller's responsibility to free the allocated
-** buffer containing the derived secret.
-*/
-extern SECStatus ECDH_Derive(SECItem *       publicValue,
-                             ECParams *      params,
-                             SECItem *       privateValue,
-                             PRBool          withCofactor,
-                             SECItem *       derivedSecret);
-
-/* On input,  signature->len == size of buffer to hold signature.
-**            digest->len    == size of digest.
-** On output, signature->len == size of signature in buffer.
-** Uses a random seed.
-*/
-extern SECStatus ECDSA_SignDigest(ECPrivateKey  *key, 
-                                  SECItem       *signature, 
-                                  const SECItem *digest);
-
-/* On input,  signature->len == size of buffer to hold signature.
-**            digest->len    == size of digest.
-*/
-extern SECStatus ECDSA_VerifyDigest(ECPublicKey   *key, 
-                                    const SECItem *signature, 
-                                    const SECItem *digest);
-
-/* Uses the provided seed. */
-extern SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey        *key,
-                                          SECItem             *signature,
-                                          const SECItem       *digest,
-                                          const unsigned char *seed, 
-                                          const int           seedlen);
-
-/******************************************/
-/*
-** RC4 symmetric stream cypher
-*/
-
-/*
-** Create a new RC4 context suitable for RC4 encryption/decryption.
-**	"key" raw key data
-**	"len" the number of bytes of key data
-*/
-extern RC4Context *RC4_CreateContext(const unsigned char *key, int len);
-
-extern RC4Context *RC4_AllocateContext(void);
-extern SECStatus   RC4_InitContext(RC4Context *cx, 
-				   const unsigned char *key, 
-				   unsigned int keylen,
-				   const unsigned char *, 
-				   int, 
-				   unsigned int ,
-				   unsigned int );
-
-/*
-** Destroy an RC4 encryption/decryption context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void RC4_DestroyContext(RC4Context *cx, PRBool freeit);
-
-/*
-** Perform RC4 encryption.
-**	"cx" the context
-**	"output" the output buffer to store the encrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus RC4_Encrypt(RC4Context *cx, unsigned char *output,
-			    unsigned int *outputLen, unsigned int maxOutputLen,
-			    const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform RC4 decryption.
-**	"cx" the context
-**	"output" the output buffer to store the decrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
-			    unsigned int *outputLen, unsigned int maxOutputLen,
-			    const unsigned char *input, unsigned int inputLen);
-
-/******************************************/
-/*
-** RC2 symmetric block cypher
-*/
-
-/*
-** Create a new RC2 context suitable for RC2 encryption/decryption.
-** 	"key" raw key data
-** 	"len" the number of bytes of key data
-** 	"iv" is the CBC initialization vector (if mode is NSS_RC2_CBC)
-** 	"mode" one of NSS_RC2 or NSS_RC2_CBC
-**	"effectiveKeyLen" is the effective key length (as specified in 
-**	    RFC 2268) in bytes (not bits).
-**
-** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
-** chaining" mode.
-*/
-extern RC2Context *RC2_CreateContext(const unsigned char *key, unsigned int len,
-				     const unsigned char *iv, int mode, 
-				     unsigned effectiveKeyLen);
-extern RC2Context *RC2_AllocateContext(void);
-extern SECStatus   RC2_InitContext(RC2Context *cx,
-				   const unsigned char *key, 
-				   unsigned int keylen,
-				   const unsigned char *iv, 
-				   int mode, 
-				   unsigned int effectiveKeyLen,
-				   unsigned int );
-
-/*
-** Destroy an RC2 encryption/decryption context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void RC2_DestroyContext(RC2Context *cx, PRBool freeit);
-
-/*
-** Perform RC2 encryption.
-**	"cx" the context
-**	"output" the output buffer to store the encrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output,
-			    unsigned int *outputLen, unsigned int maxOutputLen,
-			    const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform RC2 decryption.
-**	"cx" the context
-**	"output" the output buffer to store the decrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output,
-			    unsigned int *outputLen, unsigned int maxOutputLen,
-			    const unsigned char *input, unsigned int inputLen);
-
-/******************************************/
-/*
-** RC5 symmetric block cypher -- 64-bit block size
-*/
-
-/*
-** Create a new RC5 context suitable for RC5 encryption/decryption.
-**      "key" raw key data
-**      "len" the number of bytes of key data
-**      "iv" is the CBC initialization vector (if mode is NSS_RC5_CBC)
-**      "mode" one of NSS_RC5 or NSS_RC5_CBC
-**
-** When mode is set to NSS_RC5_CBC the RC5 cipher is run in "cipher block
-** chaining" mode.
-*/
-extern RC5Context *RC5_CreateContext(const SECItem *key, unsigned int rounds,
-                     unsigned int wordSize, const unsigned char *iv, int mode);
-extern RC5Context *RC5_AllocateContext(void);
-extern SECStatus   RC5_InitContext(RC5Context *cx, 
-				   const unsigned char *key, 
-				   unsigned int keylen,
-				   const unsigned char *iv, 
-				   int mode,
-				   unsigned int rounds, 
-				   unsigned int wordSize);
-
-/*
-** Destroy an RC5 encryption/decryption context.
-**      "cx" the context
-**      "freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void RC5_DestroyContext(RC5Context *cx, PRBool freeit);
-
-/*
-** Perform RC5 encryption.
-**      "cx" the context
-**      "output" the output buffer to store the encrypted data.
-**      "outputLen" how much data is stored in "output". Set by the routine
-**         after some data is stored in output.
-**      "maxOutputLen" the maximum amount of data that can ever be
-**         stored in "output"
-**      "input" the input data
-**      "inputLen" the amount of input data
-*/
-extern SECStatus RC5_Encrypt(RC5Context *cx, unsigned char *output,
-                            unsigned int *outputLen, unsigned int maxOutputLen,
-                            const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform RC5 decryption.
-**      "cx" the context
-**      "output" the output buffer to store the decrypted data.
-**      "outputLen" how much data is stored in "output". Set by the routine
-**         after some data is stored in output.
-**      "maxOutputLen" the maximum amount of data that can ever be
-**         stored in "output"
-**      "input" the input data
-**      "inputLen" the amount of input data
-*/
-
-extern SECStatus RC5_Decrypt(RC5Context *cx, unsigned char *output,
-                            unsigned int *outputLen, unsigned int maxOutputLen,
-                            const unsigned char *input, unsigned int inputLen);
-
-
-
-/******************************************/
-/*
-** DES symmetric block cypher
-*/
-
-/*
-** Create a new DES context suitable for DES encryption/decryption.
-** 	"key" raw key data
-** 	"len" the number of bytes of key data
-** 	"iv" is the CBC initialization vector (if mode is NSS_DES_CBC or
-** 	   mode is DES_EDE3_CBC)
-** 	"mode" one of NSS_DES, NSS_DES_CBC, NSS_DES_EDE3 or NSS_DES_EDE3_CBC
-**	"encrypt" is PR_TRUE if the context will be used for encryption
-**
-** When mode is set to NSS_DES_CBC or NSS_DES_EDE3_CBC then the DES
-** cipher is run in "cipher block chaining" mode.
-*/
-extern DESContext *DES_CreateContext(const unsigned char *key, 
-                                     const unsigned char *iv,
-				     int mode, PRBool encrypt);
-extern DESContext *DES_AllocateContext(void);
-extern SECStatus   DES_InitContext(DESContext *cx,
-				   const unsigned char *key, 
-				   unsigned int keylen,
-				   const unsigned char *iv, 
-				   int mode,
-				   unsigned int encrypt,
-				   unsigned int );
-
-/*
-** Destroy an DES encryption/decryption context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void DES_DestroyContext(DESContext *cx, PRBool freeit);
-
-/*
-** Perform DES encryption.
-**	"cx" the context
-**	"output" the output buffer to store the encrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-**
-** NOTE: the inputLen must be a multiple of DES_KEY_LENGTH
-*/
-extern SECStatus DES_Encrypt(DESContext *cx, unsigned char *output,
-			    unsigned int *outputLen, unsigned int maxOutputLen,
-			    const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform DES decryption.
-**	"cx" the context
-**	"output" the output buffer to store the decrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-**
-** NOTE: the inputLen must be a multiple of DES_KEY_LENGTH
-*/
-extern SECStatus DES_Decrypt(DESContext *cx, unsigned char *output,
-			    unsigned int *outputLen, unsigned int maxOutputLen,
-			    const unsigned char *input, unsigned int inputLen);
-
-/******************************************/
-/* 
-** SEED symmetric block cypher		  
-*/
-extern SEEDContext *
-SEED_CreateContext(const unsigned char *key, const unsigned char *iv, 
-		   int mode, PRBool encrypt);
-extern SEEDContext *SEED_AllocateContext(void);
-extern SECStatus   SEED_InitContext(SEEDContext *cx, 
-				    const unsigned char *key, 
-				    unsigned int keylen, 
-				    const unsigned char *iv, 
-				    int mode, unsigned int encrypt, 
-				    unsigned int );
-extern void SEED_DestroyContext(SEEDContext *cx, PRBool freeit);
-extern SECStatus 
-SEED_Encrypt(SEEDContext *cx, unsigned char *output, 
-	     unsigned int *outputLen, unsigned int maxOutputLen, 
-	     const unsigned char *input, unsigned int inputLen);
-extern SECStatus 
-SEED_Decrypt(SEEDContext *cx, unsigned char *output, 
-	     unsigned int *outputLen, unsigned int maxOutputLen, 
-             const unsigned char *input, unsigned int inputLen);
+#ifndef _SHA256_H_
+#define _SHA256_H_
 
-/******************************************/
-/*
-** AES symmetric block cypher (Rijndael)
-*/
-
-/*
-** Create a new AES context suitable for AES encryption/decryption.
-** 	"key" raw key data
-** 	"keylen" the number of bytes of key data (16, 24, or 32)
-**      "blocklen" is the blocksize to use (16, 24, or 32)
-**                        XXX currently only blocksize==16 has been tested!
-*/
-extern AESContext *
-AES_CreateContext(const unsigned char *key, const unsigned char *iv, 
-                  int mode, int encrypt,
-                  unsigned int keylen, unsigned int blocklen);
-extern AESContext *AES_AllocateContext(void);
-extern SECStatus   AES_InitContext(AESContext *cx,
-				   const unsigned char *key, 
-				   unsigned int keylen, 
-				   const unsigned char *iv, 
-				   int mode, 
-				   unsigned int encrypt,
-				   unsigned int blocklen);
-
-/*
-** Destroy a AES encryption/decryption context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void 
-AES_DestroyContext(AESContext *cx, PRBool freeit);
-
-/*
-** Perform AES encryption.
-**	"cx" the context
-**	"output" the output buffer to store the encrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus 
-AES_Encrypt(AESContext *cx, unsigned char *output,
-            unsigned int *outputLen, unsigned int maxOutputLen,
-            const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform AES decryption.
-**	"cx" the context
-**	"output" the output buffer to store the decrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus 
-AES_Decrypt(AESContext *cx, unsigned char *output,
-            unsigned int *outputLen, unsigned int maxOutputLen,
-            const unsigned char *input, unsigned int inputLen);
-
-/******************************************/
-/*
-** AES key wrap algorithm, RFC 3394
-*/
-
-/*
-** Create a new AES context suitable for AES encryption/decryption.
-** 	"key" raw key data
-**      "iv"  The 8 byte "initial value"
-**      "encrypt", a boolean, true for key wrapping, false for unwrapping.
-** 	"keylen" the number of bytes of key data (16, 24, or 32)
-*/
-extern AESKeyWrapContext *
-AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, 
-                         int encrypt, unsigned int keylen);
-extern AESKeyWrapContext * AESKeyWrap_AllocateContext(void);
-extern SECStatus  
-     AESKeyWrap_InitContext(AESKeyWrapContext *cx, 
-				   const unsigned char *key, 
-				   unsigned int keylen,
-				   const unsigned char *iv, 
-				   int ,
-				   unsigned int encrypt,
-				   unsigned int );
-
-/*
-** Destroy a AES KeyWrap context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void 
-AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit);
-
-/*
-** Perform AES key wrap.
-**	"cx" the context
-**	"output" the output buffer to store the encrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus 
-AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
-            unsigned int *outputLen, unsigned int maxOutputLen,
-            const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform AES key unwrap.
-**	"cx" the context
-**	"output" the output buffer to store the decrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus 
-AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
-            unsigned int *outputLen, unsigned int maxOutputLen,
-            const unsigned char *input, unsigned int inputLen);
-
- /******************************************/
-/*
-** Camellia symmetric block cypher
-*/
-
-/*
-** Create a new Camellia context suitable for Camellia encryption/decryption.
-** 	"key" raw key data
-** 	"keylen" the number of bytes of key data (16, 24, or 32)
-*/
-extern CamelliaContext *
-Camellia_CreateContext(const unsigned char *key, const unsigned char *iv, 
-		       int mode, int encrypt, unsigned int keylen);
-
-extern CamelliaContext *Camellia_AllocateContext(void);
-extern SECStatus   Camellia_InitContext(CamelliaContext *cx,
-					const unsigned char *key, 
-					unsigned int keylen, 
-					const unsigned char *iv, 
-					int mode, 
-					unsigned int encrypt,
-					unsigned int unused);
-/*
-** Destroy a Camellia encryption/decryption context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void 
-Camellia_DestroyContext(CamelliaContext *cx, PRBool freeit);
-
-/*
-** Perform Camellia encryption.
-**	"cx" the context
-**	"output" the output buffer to store the encrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus 
-Camellia_Encrypt(CamelliaContext *cx, unsigned char *output,
-		 unsigned int *outputLen, unsigned int maxOutputLen,
-		 const unsigned char *input, unsigned int inputLen);
-
-/*
-** Perform Camellia decryption.
-**	"cx" the context
-**	"output" the output buffer to store the decrypted data.
-**	"outputLen" how much data is stored in "output". Set by the routine
-**	   after some data is stored in output.
-**	"maxOutputLen" the maximum amount of data that can ever be
-**	   stored in "output"
-**	"input" the input data
-**	"inputLen" the amount of input data
-*/
-extern SECStatus 
-Camellia_Decrypt(CamelliaContext *cx, unsigned char *output,
-		 unsigned int *outputLen, unsigned int maxOutputLen,
-		 const unsigned char *input, unsigned int inputLen);
-
-
-/******************************************/
-/*
-** MD5 secure hash function
-*/
-
-/*
-** Hash a null terminated string "src" into "dest" using MD5
-*/
-extern SECStatus MD5_Hash(unsigned char *dest, const char *src);
-
-/*
-** Hash a non-null terminated string "src" into "dest" using MD5
-*/
-extern SECStatus MD5_HashBuf(unsigned char *dest, const unsigned char *src,
-			     PRUint32 src_length);
-
-/*
-** Create a new MD5 context
-*/
-extern MD5Context *MD5_NewContext(void);
-
-
-/*
-** Destroy an MD5 secure hash context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void MD5_DestroyContext(MD5Context *cx, PRBool freeit);
-
-/*
-** Reset an MD5 context, preparing it for a fresh round of hashing
-*/
-extern void MD5_Begin(MD5Context *cx);
-
-/*
-** Update the MD5 hash function with more data.
-**	"cx" the context
-**	"input" the data to hash
-**	"inputLen" the amount of data to hash
-*/
-extern void MD5_Update(MD5Context *cx,
-		       const unsigned char *input, unsigned int inputLen);
-
-/*
-** Finish the MD5 hash function. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 16 bytes of digest data are stored
-**	"digestLen" where the digest length (16) is stored
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void MD5_End(MD5Context *cx, unsigned char *digest,
-		    unsigned int *digestLen, unsigned int maxDigestLen);
-
-/*
-** Export the current state of the MD5 hash without appending the standard
-** padding and length bytes. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 16 bytes of digest data are stored
-**	"digestLen" where the digest length (16) is stored (optional)
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void MD5_EndRaw(MD5Context *cx, unsigned char *digest,
-		       unsigned int *digestLen, unsigned int maxDigestLen);
-
-/*
- * Return the the size of a buffer needed to flatten the MD5 Context into
- *    "cx" the context
- *  returns size;
- */
-extern unsigned int MD5_FlattenSize(MD5Context *cx);
-
-/*
- * Flatten the MD5 Context into a buffer:
- *    "cx" the context
- *    "space" the buffer to flatten to
- *  returns status;
- */
-extern SECStatus MD5_Flatten(MD5Context *cx,unsigned char *space);
-
-/*
- * Resurrect a flattened context into a MD5 Context
- *    "space" the buffer of the flattend buffer
- *    "arg" ptr to void used by cryptographic resurrect
- *  returns resurected context;
- */
-extern MD5Context * MD5_Resurrect(unsigned char *space, void *arg);
-extern void MD5_Clone(MD5Context *dest, MD5Context *src);
-
-/*
-** trace the intermediate state info of the MD5 hash.
-*/
-extern void MD5_TraceState(MD5Context *cx);
-
-
-/******************************************/
-/*
-** MD2 secure hash function
-*/
-
-/*
-** Hash a null terminated string "src" into "dest" using MD2
-*/
-extern SECStatus MD2_Hash(unsigned char *dest, const char *src);
-
-/*
-** Create a new MD2 context
-*/
-extern MD2Context *MD2_NewContext(void);
-
-
-/*
-** Destroy an MD2 secure hash context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void MD2_DestroyContext(MD2Context *cx, PRBool freeit);
-
-/*
-** Reset an MD2 context, preparing it for a fresh round of hashing
-*/
-extern void MD2_Begin(MD2Context *cx);
-
-/*
-** Update the MD2 hash function with more data.
-**	"cx" the context
-**	"input" the data to hash
-**	"inputLen" the amount of data to hash
-*/
-extern void MD2_Update(MD2Context *cx,
-		       const unsigned char *input, unsigned int inputLen);
-
-/*
-** Finish the MD2 hash function. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 16 bytes of digest data are stored
-**	"digestLen" where the digest length (16) is stored
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void MD2_End(MD2Context *cx, unsigned char *digest,
-		    unsigned int *digestLen, unsigned int maxDigestLen);
-
-/*
- * Return the the size of a buffer needed to flatten the MD2 Context into
- *    "cx" the context
- *  returns size;
- */
-extern unsigned int MD2_FlattenSize(MD2Context *cx);
-
-/*
- * Flatten the MD2 Context into a buffer:
- *    "cx" the context
- *    "space" the buffer to flatten to
- *  returns status;
- */
-extern SECStatus MD2_Flatten(MD2Context *cx,unsigned char *space);
-
-/*
- * Resurrect a flattened context into a MD2 Context
- *    "space" the buffer of the flattend buffer
- *    "arg" ptr to void used by cryptographic resurrect
- *  returns resurected context;
- */
-extern MD2Context * MD2_Resurrect(unsigned char *space, void *arg);
-extern void MD2_Clone(MD2Context *dest, MD2Context *src);
-
-/******************************************/
-/*
-** SHA-1 secure hash function
-*/
-
-/*
-** Hash a null terminated string "src" into "dest" using SHA-1
-*/
-extern SECStatus SHA1_Hash(unsigned char *dest, const char *src);
-
-/*
-** Hash a non-null terminated string "src" into "dest" using SHA-1
-*/
-extern SECStatus SHA1_HashBuf(unsigned char *dest, const unsigned char *src,
-			      PRUint32 src_length);
-
-/*
-** Create a new SHA-1 context
-*/
-extern SHA1Context *SHA1_NewContext(void);
-
-
-/*
-** Destroy a SHA-1 secure hash context.
-**	"cx" the context
-**	"freeit" if PR_TRUE then free the object as well as its sub-objects
-*/
-extern void SHA1_DestroyContext(SHA1Context *cx, PRBool freeit);
-
-/*
-** Reset a SHA-1 context, preparing it for a fresh round of hashing
-*/
-extern void SHA1_Begin(SHA1Context *cx);
+#define SHA256_LENGTH 32 
 
-/*
-** Update the SHA-1 hash function with more data.
-**	"cx" the context
-**	"input" the data to hash
-**	"inputLen" the amount of data to hash
-*/
-extern void SHA1_Update(SHA1Context *cx, const unsigned char *input,
-			unsigned int inputLen);
-
-/*
-** Finish the SHA-1 hash function. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 16 bytes of digest data are stored
-**	"digestLen" where the digest length (20) is stored
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void SHA1_End(SHA1Context *cx, unsigned char *digest,
-		     unsigned int *digestLen, unsigned int maxDigestLen);
-
-/*
-** Export the current state of the SHA-1 hash without appending the standard
-** padding and length bytes. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 20 bytes of digest data are stored
-**	"digestLen" where the digest length (20) is stored (optional)
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void SHA1_EndRaw(SHA1Context *cx, unsigned char *digest,
-			unsigned int *digestLen, unsigned int maxDigestLen);
-
-/*
-** trace the intermediate state info of the SHA1 hash.
-*/
-extern void SHA1_TraceState(SHA1Context *cx);
-
-/*
- * Return the the size of a buffer needed to flatten the SHA-1 Context into
- *    "cx" the context
- *  returns size;
- */
-extern unsigned int SHA1_FlattenSize(SHA1Context *cx);
-
-/*
- * Flatten the SHA-1 Context into a buffer:
- *    "cx" the context
- *    "space" the buffer to flatten to
- *  returns status;
- */
-extern SECStatus SHA1_Flatten(SHA1Context *cx,unsigned char *space);
-
-/*
- * Resurrect a flattened context into a SHA-1 Context
- *    "space" the buffer of the flattend buffer
- *    "arg" ptr to void used by cryptographic resurrect
- *  returns resurected context;
- */
-extern SHA1Context * SHA1_Resurrect(unsigned char *space, void *arg);
-extern void SHA1_Clone(SHA1Context *dest, SHA1Context *src);
-
-/******************************************/
-
-extern SHA224Context *SHA224_NewContext(void);
-extern void SHA224_DestroyContext(SHA224Context *cx, PRBool freeit);
-extern void SHA224_Begin(SHA224Context *cx);
-extern void SHA224_Update(SHA224Context *cx, const unsigned char *input,
-			unsigned int inputLen);
-extern void SHA224_End(SHA224Context *cx, unsigned char *digest,
-		     unsigned int *digestLen, unsigned int maxDigestLen);
-/*
-** Export the current state of the SHA-224 hash without appending the standard
-** padding and length bytes. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 28 bytes of digest data are stored
-**	"digestLen" where the digest length (28) is stored (optional)
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void SHA224_EndRaw(SHA224Context *cx, unsigned char *digest,
-			  unsigned int *digestLen, unsigned int maxDigestLen);
-extern SECStatus SHA224_HashBuf(unsigned char *dest, const unsigned char *src,
-				PRUint32 src_length);
-extern SECStatus SHA224_Hash(unsigned char *dest, const char *src);
-extern void SHA224_TraceState(SHA224Context *cx);
-extern unsigned int SHA224_FlattenSize(SHA224Context *cx);
-extern SECStatus SHA224_Flatten(SHA224Context *cx,unsigned char *space);
-extern SHA224Context * SHA224_Resurrect(unsigned char *space, void *arg);
-extern void SHA224_Clone(SHA224Context *dest, SHA224Context *src);
-
-/******************************************/
-
-extern SHA256Context *SHA256_NewContext(void);
-extern void SHA256_DestroyContext(SHA256Context *cx, PRBool freeit);
-extern void SHA256_Begin(SHA256Context *cx);
-extern void SHA256_Update(SHA256Context *cx, const unsigned char *input,
-			unsigned int inputLen);
-extern void SHA256_End(SHA256Context *cx, unsigned char *digest,
-		     unsigned int *digestLen, unsigned int maxDigestLen);
-/*
-** Export the current state of the SHA-256 hash without appending the standard
-** padding and length bytes. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 32 bytes of digest data are stored
-**	"digestLen" where the digest length (32) is stored (optional)
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void SHA256_EndRaw(SHA256Context *cx, unsigned char *digest,
-			  unsigned int *digestLen, unsigned int maxDigestLen);
-extern SECStatus SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
-				PRUint32 src_length);
-extern SECStatus SHA256_Hash(unsigned char *dest, const char *src);
-extern void SHA256_TraceState(SHA256Context *cx);
-extern unsigned int SHA256_FlattenSize(SHA256Context *cx);
-extern SECStatus SHA256_Flatten(SHA256Context *cx,unsigned char *space);
-extern SHA256Context * SHA256_Resurrect(unsigned char *space, void *arg);
-extern void SHA256_Clone(SHA256Context *dest, SHA256Context *src);
-
-/******************************************/
-
-extern SHA512Context *SHA512_NewContext(void);
-extern void SHA512_DestroyContext(SHA512Context *cx, PRBool freeit);
-extern void SHA512_Begin(SHA512Context *cx);
-extern void SHA512_Update(SHA512Context *cx, const unsigned char *input,
-			unsigned int inputLen);
-/*
-** Export the current state of the SHA-512 hash without appending the standard
-** padding and length bytes. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 64 bytes of digest data are stored
-**	"digestLen" where the digest length (64) is stored (optional)
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void SHA512_EndRaw(SHA512Context *cx, unsigned char *digest,
-			  unsigned int *digestLen, unsigned int maxDigestLen);
-extern void SHA512_End(SHA512Context *cx, unsigned char *digest,
-		     unsigned int *digestLen, unsigned int maxDigestLen);
-extern SECStatus SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
-				PRUint32 src_length);
-extern SECStatus SHA512_Hash(unsigned char *dest, const char *src);
-extern void SHA512_TraceState(SHA512Context *cx);
-extern unsigned int SHA512_FlattenSize(SHA512Context *cx);
-extern SECStatus SHA512_Flatten(SHA512Context *cx,unsigned char *space);
-extern SHA512Context * SHA512_Resurrect(unsigned char *space, void *arg);
-extern void SHA512_Clone(SHA512Context *dest, SHA512Context *src);
-
-/******************************************/
-
-extern SHA384Context *SHA384_NewContext(void);
-extern void SHA384_DestroyContext(SHA384Context *cx, PRBool freeit);
-extern void SHA384_Begin(SHA384Context *cx);
-extern void SHA384_Update(SHA384Context *cx, const unsigned char *input,
-			unsigned int inputLen);
-extern void SHA384_End(SHA384Context *cx, unsigned char *digest,
-		     unsigned int *digestLen, unsigned int maxDigestLen);
-/*
-** Export the current state of the SHA-384 hash without appending the standard
-** padding and length bytes. Produce the digested results in "digest"
-**	"cx" the context
-**	"digest" where the 48 bytes of digest data are stored
-**	"digestLen" where the digest length (48) is stored (optional)
-**	"maxDigestLen" the maximum amount of data that can ever be
-**	   stored in "digest"
-*/
-extern void SHA384_EndRaw(SHA384Context *cx, unsigned char *digest,
-			  unsigned int *digestLen, unsigned int maxDigestLen);
-extern SECStatus SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
-				PRUint32 src_length);
-extern SECStatus SHA384_Hash(unsigned char *dest, const char *src);
-extern void SHA384_TraceState(SHA384Context *cx);
-extern unsigned int SHA384_FlattenSize(SHA384Context *cx);
-extern SECStatus SHA384_Flatten(SHA384Context *cx,unsigned char *space);
-extern SHA384Context * SHA384_Resurrect(unsigned char *space, void *arg);
-extern void SHA384_Clone(SHA384Context *dest, SHA384Context *src);
-
-/****************************************
- * implement TLS 1.0 Pseudo Random Function (PRF) and TLS P_hash function
- */
-
-extern SECStatus
-TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 
-         SECItem *result, PRBool isFIPS);
-
-extern SECStatus
-TLS_P_hash(HASH_HashType hashAlg, const SECItem *secret, const char *label,
-           SECItem *seed, SECItem *result, PRBool isFIPS);
-
-/******************************************/
-/*
-** Pseudo Random Number Generation.  FIPS compliance desirable.
-*/
+#include "prtypes.h"	/* for PRUintXX */
+#include "prlong.h"
 
-/*
-** Initialize the global RNG context and give it some seed input taken
-** from the system.  This function is thread-safe and will only allow
-** the global context to be initialized once.  The seed input is likely
-** small, so it is imperative that RNG_RandomUpdate() be called with
-** additional seed data before the generator is used.  A good way to
-** provide the generator with additional entropy is to call
-** RNG_SystemInfoForRNG().  Note that NSS_Init() does exactly that.
-*/
-extern SECStatus RNG_RNGInit(void);
-
-/*
-** Update the global random number generator with more seeding
-** material
-*/
-extern SECStatus RNG_RandomUpdate(const void *data, size_t bytes);
-
-/*
-** Generate some random bytes, using the global random number generator
-** object.
-*/
-extern SECStatus RNG_GenerateGlobalRandomBytes(void *dest, size_t len);
-
-/* Destroy the global RNG context.  After a call to RNG_RNGShutdown()
-** a call to RNG_RNGInit() is required in order to use the generator again,
-** along with seed data (see the comment above RNG_RNGInit()).
-*/
-extern void  RNG_RNGShutdown(void);
-
-extern void RNG_SystemInfoForRNG(void);
-
-/*
- * FIPS 186-2 Change Notice 1 RNG Algorithm 1, used both to
- * generate the DSA X parameter and as a generic purpose RNG.
- *
- * The following two FIPS186Change functions are needed for
- * NIST RNG Validation System.
- */
-
-/*
- * FIPS186Change_GenerateX is now deprecated. It will return SECFailure with
- * the error set to PR_NOT_IMPLEMENTED_ERROR.
- */
-extern SECStatus
-FIPS186Change_GenerateX(unsigned char *XKEY,
-                        const unsigned char *XSEEDj,
-                        unsigned char *x_j);
-
-/*
- * When generating the DSA X parameter, we generate 2*GSIZE bytes
- * of random output and reduce it mod q.
- *
- * Input: w, 2*GSIZE bytes
- *        q, DSA_SUBPRIME_LEN bytes
- * Output: xj, DSA_SUBPRIME_LEN bytes
- */
-extern SECStatus
-FIPS186Change_ReduceModQForDSA(const unsigned char *w,
-                               const unsigned char *q,
-                               unsigned char *xj);
-
-/*
- * The following functions are for FIPS poweron self test and FIPS algorithm
- * testing.
- */
-extern SECStatus
-PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, 
-		const PRUint8 *nonce, unsigned int nonce_len,
-		const PRUint8 *personal_string, unsigned int ps_len);
-
-extern SECStatus
-PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, 
-		  const PRUint8 *additional, unsigned int additional_len);
-
-extern SECStatus
-PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, 
-		  const PRUint8 *additional, unsigned int additional_len);
-
-extern SECStatus
-PRNGTEST_Uninstantiate(void);
-
-extern SECStatus
-PRNGTEST_RunHealthTests(void);
-
-/* Generate PQGParams and PQGVerify structs.
- * Length of seed and length of h both equal length of P. 
- * All lengths are specified by "j", according to the table above.
- *
- * The verify parameters will conform to FIPS186-1.
- */
-extern SECStatus
-PQG_ParamGen(unsigned int j, 	   /* input : determines length of P. */
-             PQGParams **pParams,  /* output: P Q and G returned here */
-	     PQGVerify **pVfy);    /* output: counter and seed. */
-
-/* Generate PQGParams and PQGVerify structs.
- * Length of P specified by j.  Length of h will match length of P.
- * Length of SEED in bytes specified in seedBytes.
- * seedBbytes must be in the range [20..255] or an error will result.
- *
- * The verify parameters will conform to FIPS186-1.
- */
-extern SECStatus
-PQG_ParamGenSeedLen(
-             unsigned int j, 	     /* input : determines length of P. */
-	     unsigned int seedBytes, /* input : length of seed in bytes.*/
-             PQGParams **pParams,    /* output: P Q and G returned here */
-	     PQGVerify **pVfy);      /* output: counter and seed. */
-
-/* Generate PQGParams and PQGVerify structs.
- * Length of P specified by L in bits.  
- * Length of Q specified by N in bits.  
- * Length of SEED in bytes specified in seedBytes.
- * seedBbytes must be in the range [N..L*2] or an error will result.
- *
- * Not that J uses the above table, L is the length exact. L and N must
- * match the table below or an error will result:
- *
- *  L            N
- * 1024         160
- * 2048         224
- * 2048         256
- * 3072         256
- *
- * If N or seedBytes are set to zero, then PQG_ParamGenSeedLen will
- * pick a default value (typically the smallest secure value for these
- * variables).
- *
- * The verify parameters will conform to FIPS186-3 using the smallest 
- * permissible hash for the key strength.
- */
-extern SECStatus
-PQG_ParamGenV2(
-             unsigned int L, 	     /* input : determines length of P. */
-             unsigned int N, 	     /* input : determines length of Q. */
-	     unsigned int seedBytes, /* input : length of seed in bytes.*/
-             PQGParams **pParams,    /* output: P Q and G returned here */
-	     PQGVerify **pVfy);      /* output: counter and seed. */
-
-
-/*  Test PQGParams for validity as DSS PQG values.
- *  If vfy is non-NULL, test PQGParams to make sure they were generated
- *       using the specified seed, counter, and h values.
- *
- *  Return value indicates whether Verification operation ran successfully
- *  to completion, but does not indicate if PQGParams are valid or not.
- *  If return value is SECSuccess, then *pResult has these meanings:
- *       SECSuccess: PQGParams are valid.
- *       SECFailure: PQGParams are invalid.
- *
- * Verify the PQG againts the counter, SEED and h.
- * These tests are specified in FIPS 186-3 Appendix A.1.1.1, A.1.1.3, and A.2.2
- * PQG_VerifyParams will automatically choose the appropriate test.
- */
-
-extern SECStatus   PQG_VerifyParams(const PQGParams *params, 
-                                    const PQGVerify *vfy, SECStatus *result);
-
-extern void PQG_DestroyParams(PQGParams *params);
-
-extern void PQG_DestroyVerify(PQGVerify *vfy);
-
-
-/*
- * clean-up any global tables freebl may have allocated after it starts up.
- * This function is not thread safe and should be called only after the
- * library has been quiessed.
- */
-extern void BL_Cleanup(void);
-
-/* unload freebl shared library from memory */
-extern void BL_Unload(void);
-
-/**************************************************************************
- *  Verify a given Shared library signature                               *
- **************************************************************************/
-PRBool BLAPI_SHVerify(const char *name, PRFuncPtr addr);
-
-/**************************************************************************
- *  Verify a given filename's signature                               *
- **************************************************************************/
-PRBool BLAPI_SHVerifyFile(const char *shName);
-
-/**************************************************************************
- *  Verify Are Own Shared library signature                               *
- **************************************************************************/
-PRBool BLAPI_VerifySelf(const char *name);
-
-/*********************************************************************/
-extern const SECHashObject * HASH_GetRawHashObject(HASH_HashType hashType);
-
-extern void BL_SetForkState(PRBool forked);
-
-#ifndef NSS_DISABLE_ECC
-/*
-** pepare an ECParam structure from DEREncoded params
- */
-extern SECStatus EC_FillParams(PLArenaPool *arena,
-                               const SECItem *encodedParams, ECParams *params);
-extern SECStatus EC_DecodeParams(const SECItem *encodedParams,
-                                 ECParams **ecparams);
-extern SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
-                               const ECParams *srcParams);
+#ifdef __cplusplus 
+extern "C" {
 #endif
 
-SEC_END_PROTOS
+struct SHA256Context {
+  union {
+    PRUint32 w[64];	    /* message schedule, input buffer, plus 48 words */
+    PRUint8  b[256];
+  } u;
+  PRUint32 h[8];		/* 8 state variables */
+  PRUint32 sizeHi,sizeLo;	/* 64-bit count of hashed bytes. */
+};
+
+typedef struct SHA256Context SHA256Context;
+
+extern void
+SHA256_Begin(SHA256Context *ctx);
 
-#endif /* _BLAPI_H_ */
+extern void 
+SHA256_Update(SHA256Context *ctx, const unsigned char *input,
+		    unsigned int inputLen);
+
+extern void
+SHA256_End(SHA256Context *ctx, unsigned char *digest,
+           unsigned int *digestLen, unsigned int maxDigestLen);
+
+#ifdef __cplusplus 
+} /* extern C */
+#endif
+
+#endif /* _SHA256_H_ */
--- a/ipc/contentproc/plugin-container.cpp
+++ b/ipc/contentproc/plugin-container.cpp
@@ -1,31 +1,34 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: sw=4 ts=4 et :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXPCOM.h"
 #include "nsXULAppAPI.h"
+#include "nsAutoPtr.h"
 
 // FIXME/cjones testing
 #if !defined(OS_WIN)
 #include <unistd.h>
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 // we want a wmain entry point
 // but we don't want its DLL load protection, because we'll handle it here
 #define XRE_DONT_PROTECT_DLL_LOAD
 #include "nsWindowsWMain.cpp"
 #include "nsSetDllDirectory.h"
 #endif
 
+#include "GMPLoader.h"
+
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "sandbox/chromium/base/basictypes.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "mozilla/sandboxTarget.h"
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/warnonlysandbox/wosCallbacks.h"
@@ -77,18 +80,39 @@ static bool gIsSandboxEnabled = false;
 void StartSandboxCallback()
 {
     if (gIsSandboxEnabled) {
         sandbox::TargetServices* target_service =
             sandbox::SandboxFactory::GetTargetServices();
         target_service->LowerToken();
     }
 }
+
+class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
+public:
+    virtual void Start() MOZ_OVERRIDE {
+        StartSandboxCallback();
+    }
+};
 #endif
 
+mozilla::gmp::SandboxStarter*
+MakeSandboxStarter()
+{
+    // Note: Linux and MacOSX create their SandboxStarters inside xul code,
+    // they need to change to statically link their sandbox code into
+    // plugin-container. Once they do that, we can create SandboxStarters for
+    // them here.
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+    return new WinSandboxStarter();
+#else
+    return nullptr;
+#endif
+}
+
 int
 content_process_main(int argc, char* argv[])
 {
     // Check for the absolute minimum number of args we need to move
     // forward here. We expect the last arg to be the child process type.
     if (argc < 1) {
       return 3;
     }
@@ -149,14 +173,22 @@ content_process_main(int argc, char* arg
         mozilla::SandboxTarget::Instance()->SetStartSandboxCallback(StartSandboxCallback);
 
 #if defined(MOZ_CONTENT_SANDBOX)
         mozilla::warnonlysandbox::PrepareForInit();
 #endif
     }
 #endif
 #endif
-
-    nsresult rv = XRE_InitChildProcess(argc, argv);
+    nsAutoPtr<mozilla::gmp::GMPLoader> loader;
+#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK)
+    // On desktop, the GMPLoader lives in plugin-container, so that its
+    // code can be covered by an EME/GMP vendor's voucher.
+    nsAutoPtr<mozilla::gmp::SandboxStarter> starter(MakeSandboxStarter());
+    if (XRE_GetProcessType() == GeckoProcessType_GMPlugin) {
+        loader = mozilla::gmp::CreateGMPLoader(starter);
+    }
+#endif
+    nsresult rv = XRE_InitChildProcess(argc, argv, loader);
     NS_ENSURE_SUCCESS(rv, 1);
 
     return 0;
 }
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -88,32 +88,33 @@ class CPOWProxyHandler : public BaseProx
 
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
                      JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
 
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool hasInstance(JSContext *cx, HandleObject proxy,
                              MutableHandleValue v, bool *bp) const MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue,
                                JSContext *cx) const MOZ_OVERRIDE;
     virtual const char* className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
     virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
     virtual void objectMoved(JSObject *proxy, const JSObject *old) const MOZ_OVERRIDE;
@@ -258,28 +259,16 @@ WrapperOwner::delete_(JSContext *cx, Han
         return ipcfail(cx);
 
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
-CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
-{
-    FORWARD(enumerate, (cx, proxy, props));
-}
-
-bool
-WrapperOwner::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    return getPropertyKeys(cx, proxy, 0, props);
-}
-
-bool
 CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
 {
     FORWARD(has, (cx, proxy, id, bp));
 }
 
 bool
 WrapperOwner::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
@@ -474,16 +463,28 @@ CPOWProxyHandler::getOwnEnumerableProper
 
 bool
 WrapperOwner::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool
+CPOWProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+{
+    FORWARD(getEnumerablePropertyKeys, (cx, proxy, props));
+}
+
+bool
+WrapperOwner::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return getPropertyKeys(cx, proxy, 0, props);
+}
+
+bool
 CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const
 {
     FORWARD(preventExtensions, (cx, proxy, succeeded));
 }
 
 bool
 WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded)
 {
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -34,33 +34,34 @@ class WrapperOwner : public virtual Java
     // Standard internal methods.
     // (The traps should be in the same order like js/src/jsproxy.h)
     bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                   JS::MutableHandle<JSPropertyDescriptor> desc);
     bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                         JS::MutableHandle<JSPropertyDescriptor> desc);
     bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
     bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
-    bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
     bool preventExtensions(JSContext *cx, JS::HandleObject proxy, bool *succeeded);
     bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
     bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
              JS::HandleId id, JS::MutableHandleValue vp);
     bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
              JS::HandleId id, bool strict, JS::MutableHandleValue vp);
     bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
                          bool construct);
 
     // SpiderMonkey extensions.
     bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                JS::MutableHandle<JSPropertyDescriptor> desc);
     bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy,
                                       JS::AutoIdVector &props);
+    bool getEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy,
+                                   JS::AutoIdVector &props);
     // We use "iterate" provided by the base class here.
     bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
     bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
     const char* className(JSContext *cx, JS::HandleObject proxy);
     bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
 
     nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
 
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -196,17 +196,17 @@ JS_CallUnbarrieredScriptTracer(JSTracer 
 template <typename HashSetEnum>
 inline void
 JS_CallHashSetObjectTracer(JSTracer *trc, HashSetEnum &e, JSObject *const &key, const char *name)
 {
     JSObject *updated = key;
     trc->setTracingLocation(reinterpret_cast<void *>(&const_cast<JSObject *&>(key)));
     JS_CallUnbarrieredObjectTracer(trc, &updated, name);
     if (updated != key)
-        e.rekeyFront(key, updated);
+        e.rekeyFront(updated);
 }
 
 // Trace an object that is known to always be tenured.  No post barriers are
 // required in this case.
 extern JS_PUBLIC_API(void)
 JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name);
 
 extern JS_PUBLIC_API(void)
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -319,17 +319,17 @@ enum { REG_EIP = 14 };
 #endif
 
 static uint8_t **
 ContextToPC(CONTEXT *context)
 {
     return reinterpret_cast<uint8_t**>(&PC_sig(context));
 }
 
-#if defined(JS_CPU_X64)
+#if defined(JS_CODEGEN_X64)
 template <class T>
 static void
 SetXMMRegToNaN(bool isFloat32, T *xmm_reg)
 {
     if (isFloat32) {
         JS_STATIC_ASSERT(sizeof(T) == 4 * sizeof(float));
         float *floats = reinterpret_cast<float*>(xmm_reg);
         floats[0] = GenericNaN();
@@ -386,17 +386,17 @@ SetRegisterToCoercedUndefined(CONTEXT *c
           case X86Registers::r13: R13_sig(context) = 0; break;
           case X86Registers::r14: R14_sig(context) = 0; break;
           case X86Registers::r15: R15_sig(context) = 0; break;
           default: MOZ_CRASH();
         }
     }
 }
 # endif  // !XP_MACOSX
-#endif // JS_CPU_X64
+#endif // JS_CODEGEN_X64
 
 #if defined(XP_WIN)
 
 static bool
 HandleFault(PEXCEPTION_POINTERS exception)
 {
     EXCEPTION_RECORD *record = exception->ExceptionRecord;
     CONTEXT *context = exception->ContextRecord;
@@ -420,17 +420,17 @@ HandleFault(PEXCEPTION_POINTERS exceptio
     AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsFunctionPC(pc))
         return false;
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     void *faultingAddress = (void*)record->ExceptionInformation[1];
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
     {
         return false;
@@ -479,17 +479,17 @@ ContextToPC(x86_thread_state_t &state)
     JS_STATIC_ASSERT(sizeof(state.uts.ts64.__rip) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&state.uts.ts64.__rip);
 # else
     JS_STATIC_ASSERT(sizeof(state.uts.ts32.__eip) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&state.uts.ts32.__eip);
 # endif
 }
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
 static bool
 SetRegisterToCoercedUndefined(mach_port_t rtThread, x86_thread_state64_t &state,
                               const AsmJSHeapAccess &heapAccess)
 {
     if (heapAccess.loadedReg().isFloat()) {
         kern_return_t kret;
 
         x86_float_state64_t fstate;
@@ -813,17 +813,17 @@ HandleFault(int signum, siginfo_t *info,
     AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsFunctionPC(pc))
         return false;
 
-# if defined(JS_CPU_X64)
+# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     void *faultingAddress = info->si_addr;
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
     {
         return false;
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/BaselineCompiler.h"
 
+#include "mozilla/UniquePtr.h"
+
 #include "jit/BaselineHelpers.h"
 #include "jit/BaselineIC.h"
 #include "jit/BaselineJIT.h"
 #include "jit/FixedList.h"
 #include "jit/IonAnalysis.h"
 #include "jit/IonLinker.h"
 #include "jit/JitcodeMap.h"
 #include "jit/JitSpewer.h"
@@ -175,33 +177,34 @@ BaselineCompiler::compile()
     prologueOffset_.fixup(&masm);
     epilogueOffset_.fixup(&masm);
     spsPushToggleOffset_.fixup(&masm);
     postDebugPrologueOffset_.fixup(&masm);
 
     // Note: There is an extra entry in the bytecode type map for the search hint, see below.
     size_t bytecodeTypeMapEntries = script->nTypeSets() + 1;
 
-    BaselineScript *baselineScript = BaselineScript::New(script, prologueOffset_.offset(),
-                                                         epilogueOffset_.offset(),
-                                                         spsPushToggleOffset_.offset(),
-                                                         postDebugPrologueOffset_.offset(),
-                                                         icEntries_.length(),
-                                                         pcMappingIndexEntries.length(),
-                                                         pcEntries.length(),
-                                                         bytecodeTypeMapEntries,
-                                                         yieldOffsets_.length());
+    mozilla::UniquePtr<BaselineScript, JS::DeletePolicy<BaselineScript> > baselineScript(
+        BaselineScript::New(script, prologueOffset_.offset(),
+                            epilogueOffset_.offset(),
+                            spsPushToggleOffset_.offset(),
+                            postDebugPrologueOffset_.offset(),
+                            icEntries_.length(),
+                            pcMappingIndexEntries.length(),
+                            pcEntries.length(),
+                            bytecodeTypeMapEntries,
+                            yieldOffsets_.length()));
     if (!baselineScript)
         return Method_Error;
 
     baselineScript->setMethod(code);
     baselineScript->setTemplateScope(templateScope);
 
     JitSpew(JitSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d",
-            (void *) baselineScript, (void *) code->raw(),
+            (void *) baselineScript.get(), (void *) code->raw(),
             script->filename(), script->lineno());
 
 #ifdef JS_ION_PERF
     writePerfSpewerBaselineProfile(script, code);
 #endif
 
     MOZ_ASSERT(pcMappingIndexEntries.length() > 0);
     baselineScript->copyPCMappingIndexEntries(&pcMappingIndexEntries[0]);
@@ -248,29 +251,29 @@ BaselineCompiler::compile()
     baselineScript->copyYieldEntries(script, yieldOffsets_);
 
     if (compileDebugInstrumentation_)
         baselineScript->setHasDebugInstrumentation();
 
     // Register a native => bytecode mapping entry for this script if needed.
     if (cx->runtime()->jitRuntime()->isNativeToBytecodeMapEnabled(cx->runtime())) {
         JitSpew(JitSpew_Profiling, "Added JitcodeGlobalEntry for baseline script %s:%d (%p)",
-                    script->filename(), script->lineno(), baselineScript);
+                    script->filename(), script->lineno(), baselineScript.get());
         JitcodeGlobalEntry::BaselineEntry entry;
         entry.init(code->raw(), code->raw() + code->instructionsSize(), script);
 
         JitcodeGlobalTable *globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
         if (!globalTable->addEntry(entry))
             return Method_Error;
 
         // Mark the jitcode as having a bytecode map.
         code->setHasBytecodeMap();
     }
 
-    script->setBaselineScript(cx, baselineScript);
+    script->setBaselineScript(cx, baselineScript.release());
 
     return Method_Compiled;
 }
 
 void
 BaselineCompiler::emitInitializeLocals(size_t n, const Value &v)
 {
     MOZ_ASSERT(frame.nlocals() > 0 && n <= frame.nlocals());
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3702,16 +3702,21 @@ class MCompare
     bool isDoubleComparison() const {
         return compareType() == Compare_Double ||
                compareType() == Compare_DoubleMaybeCoerceLHS ||
                compareType() == Compare_DoubleMaybeCoerceRHS;
     }
     bool isFloat32Comparison() const {
         return compareType() == Compare_Float32;
     }
+    bool isNumericComparison() const {
+        return isInt32Comparison() ||
+               isDoubleComparison() ||
+               isFloat32Comparison();
+    }
     void setCompareType(CompareType type) {
         compareType_ = type;
     }
     MIRType inputType();
 
     JSOp jsop() const {
         return jsop_;
     }
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -242,19 +242,29 @@ RangeAnalysis::addBetaNodes()
                     bound = intbound;
             }
             comp.setDouble(bound, conservativeUpper);
 
             // Negative zero is not greater than zero.
             if (bound == 0)
                 comp.refineToExcludeNegativeZero();
             break;
+          case JSOP_STRICTEQ:
+            // A strict comparison can test for things other than numeric value.
+            if (!compare->isNumericComparison())
+                continue;
+            // Otherwise fall through to handle JSOP_STRICTEQ the same as JSOP_EQ.
           case JSOP_EQ:
             comp.setDouble(bound, bound);
             break;
+          case JSOP_STRICTNE:
+            // A strict comparison can test for things other than numeric value.
+            if (!compare->isNumericComparison())
+                continue;
+            // Otherwise fall through to handle JSOP_STRICTNE the same as JSOP_NE.
           case JSOP_NE:
             // Negative zero is not not-equal to zero.
             if (bound == 0) {
                 comp.refineToExcludeNegativeZero();
                 break;
             }
             continue; // well, we could have
                       // [-\inf, bound-1] U [bound+1, \inf] but we only use contiguous ranges.
--- a/js/src/jit/none/Architecture-none.h
+++ b/js/src/jit/none/Architecture-none.h
@@ -10,17 +10,17 @@
 // JitSpewer.h is included through MacroAssembler implementations for other
 // platforms, so include it here to avoid inadvertent build bustage.
 #include "jit/JitSpewer.h"
 
 namespace js {
 namespace jit {
 
 static const bool SupportsSimd = false;
-static const uint32_t SimdStackAlignment = 0;
+static const uint32_t SimdStackAlignment = 4; // Make it 4 to avoid a bunch of div-by-zero warnings
 static const uint32_t AsmJSStackAlignment = 4;
 
 class Registers
 {
   public:
     typedef uint8_t Code;
     typedef uint8_t SetType;
 
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -175,16 +175,17 @@ class MacroAssemblerNone : public Assemb
     uint32_t currentOffset() { MOZ_CRASH(); }
     uint32_t actualOffset(uint32_t) { MOZ_CRASH(); }
     uint32_t labelOffsetToPatchOffset(uint32_t) { MOZ_CRASH(); }
     CodeOffsetLabel labelForPatch() { MOZ_CRASH(); }
 
     template <typename T> void call(T) { MOZ_CRASH(); }
     template <typename T, typename S> void call(T, S) { MOZ_CRASH(); }
     template <typename T> void callWithABI(T, MoveOp::Type v = MoveOp::GENERAL) { MOZ_CRASH(); }
+    void callAndPushReturnAddress(Label *label) { MOZ_CRASH(); }
 
     void setupAlignedABICall(uint32_t) { MOZ_CRASH(); }
     void setupUnalignedABICall(uint32_t, Register) { MOZ_CRASH(); }
     template <typename T> void passABIArg(T, MoveOp::Type v = MoveOp::GENERAL) { MOZ_CRASH(); }
 
     void callWithExitFrame(Label *) { MOZ_CRASH(); }
     void callWithExitFrame(JitCode *) { MOZ_CRASH(); }
     void callWithExitFrame(JitCode *, Register) { MOZ_CRASH(); }
--- a/js/src/jsapi-tests/testJitRangeAnalysis.cpp
+++ b/js/src/jsapi-tests/testJitRangeAnalysis.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/ArrayUtils.h"
+
 #include "jit/IonAnalysis.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MIRGraph.h"
 #include "jit/RangeAnalysis.h"
 
 #include "jsapi-tests/testJitMinimalFunc.h"
 #include "jsapi-tests/tests.h"
 
@@ -204,8 +206,72 @@ BEGIN_TEST(testJitRangeAnalysis_MathSign
 
     // Otherwise, p may be NaN.
     CHECK(elseElseAdd->range()->isUnknown());
     CHECK(!elseElseSign->range());
 
     return true;
 }
 END_TEST(testJitRangeAnalysis_MathSignBeta)
+
+BEGIN_TEST(testJitRangeAnalysis_StrictCompareBeta)
+{
+    MinimalFunc func;
+
+    MBasicBlock *entry = func.createEntryBlock();
+    MBasicBlock *thenBlock = func.createBlock(entry);
+    MBasicBlock *elseBlock = func.createBlock(entry);
+
+    // if (p === 0)
+    MParameter *p = func.createParameter();
+    entry->add(p);
+    MConstant *c0 = MConstant::New(func.alloc, DoubleValue(0.0));
+    entry->add(c0);
+    MCompare *cmp = MCompare::New(func.alloc, p, c0, JSOP_STRICTEQ);
+    entry->add(cmp);
+    entry->end(MTest::New(func.alloc, cmp, thenBlock, elseBlock));
+
+    // {
+    //   return p + -0;
+    // }
+    MConstant *cm0 = MConstant::New(func.alloc, DoubleValue(-0.0));
+    thenBlock->add(cm0);
+    MAdd *thenAdd = MAdd::NewAsmJS(func.alloc, p, cm0, MIRType_Double);
+    thenBlock->add(thenAdd);
+    MReturn *thenRet = MReturn::New(func.alloc, thenAdd);
+    thenBlock->end(thenRet);
+
+    // else
+    // {
+    //   return 0;
+    // }
+    MReturn *elseRet = MReturn::New(func.alloc, c0);
+    elseBlock->end(elseRet);
+
+    // If range analysis inserts a beta node for p, it will be able to compute
+    // a meaningful range for p + -0.
+
+    // We can't do beta node insertion with STRICTEQ and a non-numeric
+    // comparison though.
+    MCompare::CompareType nonNumerics[] = {
+        MCompare::Compare_Unknown,
+        MCompare::Compare_Object,
+        MCompare::Compare_Value,
+        MCompare::Compare_String
+    };
+    for (size_t i = 0; i < mozilla::ArrayLength(nonNumerics); ++i) {
+        cmp->setCompareType(nonNumerics[i]);
+        if (!func.runRangeAnalysis())
+            return false;
+        CHECK(!thenAdd->range() || thenAdd->range()->isUnknown());
+        ClearDominatorTree(func.graph);
+    }
+
+    // We can do it with a numeric comparison.
+    cmp->setCompareType(MCompare::Compare_Double);
+    if (!func.runRangeAnalysis())
+        return false;
+    CHECK(EquivalentRanges(thenAdd->range(),
+                           Range::NewDoubleRange(func.alloc, 0.0, 0.0)));
+
+    return true;
+}
+END_TEST(testJitRangeAnalysis_StrictCompareBeta)
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -300,17 +300,17 @@ Snapshot(JSContext *cx, HandleObject pob
                         // will filter out unwanted keys, per the flags.
                         if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps))
                             return false;
                     } else {
                         if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps))
                             return false;
                     }
                 } else {
-                    if (!Proxy::enumerate(cx, pobj, proxyProps))
+                    if (!Proxy::getEnumerablePropertyKeys(cx, pobj, proxyProps))
                         return false;
                 }
 
                 for (size_t n = 0, len = proxyProps.length(); n < len; n++) {
                     if (!Enumerate(cx, pobj, proxyProps[n], true, flags, ht, props))
                         return false;
                 }
 
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -250,17 +250,16 @@ class JS_FRIEND_API(BaseProxyHandler)
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const = 0;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const = 0;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const = 0;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0;
-    virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0;
 
     /*
      * These methods are standard, but the engine does not normally call them.
      * They're opt-in. See "Proxy prototype chains" above.
      *
      * getPrototypeOf() crashes if called. setPrototypeOf() throws a TypeError.
      */
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const;
@@ -301,16 +300,18 @@ class JS_FRIEND_API(BaseProxyHandler)
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const = 0;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                           AutoIdVector &props) const = 0;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                          MutableHandleValue vp) const;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const;
     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const;
     virtual const char *className(JSContext *cx, HandleObject proxy) const;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const;
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const;
@@ -362,18 +363,16 @@ class JS_PUBLIC_API(DirectProxyHandler) 
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject proxy,
-                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
                                 MutableHandleObject protop) const MOZ_OVERRIDE;
     virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
                                 bool *bp) const MOZ_OVERRIDE;
     virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
                                        bool *succeeded) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
@@ -388,16 +387,18 @@ class JS_PUBLIC_API(DirectProxyHandler) 
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
                         bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                          MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
                              bool *bp) const MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
                                JSContext *cx) const MOZ_OVERRIDE;
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -116,17 +116,16 @@ class JS_FRIEND_API(CrossCompartmentWrap
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper,
                                  AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
                                 MutableHandleObject protop) const MOZ_OVERRIDE;
     virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
                                 bool *bp) const MOZ_OVERRIDE;
     virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
                                        bool *succeeded) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
@@ -139,16 +138,18 @@ class JS_FRIEND_API(CrossCompartmentWrap
     virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+                                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
                          MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
                              bool *bp) const MOZ_OVERRIDE;
     virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -200,17 +200,17 @@ bool
 BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                           MutableHandleValue vp) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
 
     AutoIdVector props(cx);
     if ((flags & JSITER_OWNONLY)
         ? !getOwnEnumerablePropertyKeys(cx, proxy, props)
-        : !enumerate(cx, proxy, props)) {
+        : !getEnumerablePropertyKeys(cx, proxy, props)) {
         return false;
     }
 
     return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
 }
 
 bool
 BaseProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -73,25 +73,16 @@ CrossCompartmentWrapper::delete_(JSConte
 {
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::delete_(cx, wrapper, id, bp),
            NOTHING);
 }
 
 bool
-CrossCompartmentWrapper::enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const
-{
-    PIERCE(cx, wrapper,
-           NOTHING,
-           Wrapper::enumerate(cx, wrapper, props),
-           NOTHING);
-}
-
-bool
 CrossCompartmentWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper,
                                         MutableHandleObject protop) const
 {
     {
         RootedObject wrapped(cx, wrappedObject(wrapper));
         AutoCompartment call(cx, wrapped);
         if (!JSObject::getProto(cx, wrapped, protop))
             return false;
@@ -192,16 +183,26 @@ CrossCompartmentWrapper::getOwnEnumerabl
                                                       AutoIdVector &props) const
 {
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::getOwnEnumerablePropertyKeys(cx, wrapper, props),
            NOTHING);
 }
 
+bool
+CrossCompartmentWrapper::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+                                                   AutoIdVector &props) const
+{
+    PIERCE(cx, wrapper,
+           NOTHING,
+           Wrapper::getEnumerablePropertyKeys(cx, wrapper, props),
+           NOTHING);
+}
+
 /*
  * We can reify non-escaping iterator objects instead of having to wrap them. This
  * allows fast iteration over objects across a compartment boundary.
  */
 static bool
 CanReify(HandleValue vp)
 {
     JSObject *obj;
--- a/js/src/proxy/DeadObjectProxy.cpp
+++ b/js/src/proxy/DeadObjectProxy.cpp
@@ -49,17 +49,18 @@ DeadObjectProxy::ownPropertyKeys(JSConte
 bool
 DeadObjectProxy::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
-DeadObjectProxy::enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const
+DeadObjectProxy::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+                                           AutoIdVector &props) const
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const
 {
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -21,27 +21,28 @@ class DeadObjectProxy : public BaseProxy
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper,
                                  AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
                                 MutableHandleObject protop) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+                                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
                              bool *bp) const MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
                                JSContext *cx) const MOZ_OVERRIDE;
     virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -63,26 +63,16 @@ bool
 DirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
 {
     assertEnteredPolicy(cx, proxy, id, SET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return JSObject::deleteGeneric(cx, target, id, bp);
 }
 
 bool
-DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy,
-                              AutoIdVector &props) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
-    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetPropertyKeys(cx, target, 0, &props);
-}
-
-bool
 DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
     RootedValue target(cx, proxy->as<ProxyObject>().private_());
     return Invoke(cx, args.thisv(), target, args.length(), args.array(), args.rval());
 }
 
 bool
@@ -248,16 +238,26 @@ DirectProxyHandler::getOwnEnumerableProp
                                                  AutoIdVector &props) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
 }
 
 bool
+DirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                              AutoIdVector &props) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetPropertyKeys(cx, target, 0, &props);
+}
+
+bool
 DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                             MutableHandleValue vp) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return GetIterator(cx, target, flags, vp);
 }
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -201,34 +201,16 @@ js::AppendUnique(JSContext *cx, AutoIdVe
             }
         }
         if (unique)
             uniqueOthers.append(others[i]);
     }
     return base.appendAll(uniqueOthers);
 }
 
-bool
-Proxy::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    JS_CHECK_RECURSION(cx, return false);
-    const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
-    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
-    if (!policy.allowed())
-        return policy.returnValue();
-    if (!handler->hasPrototype())
-        return proxy->as<ProxyObject>().handler()->enumerate(cx, proxy, props);
-    if (!handler->getOwnEnumerablePropertyKeys(cx, proxy, props))
-        return false;
-    AutoIdVector protoProps(cx);
-    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
-                        GetPropertyKeys(cx, proto, 0, &protoProps) &&
-                        AppendUnique(cx, props, protoProps));
-}
-
 /* static */ bool
 Proxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject proto)
 {
     MOZ_ASSERT(proxy->hasLazyPrototype());
     JS_CHECK_RECURSION(cx, return false);
     return proxy->as<ProxyObject>().handler()->getPrototypeOf(cx, proxy, proto);
 }
 
@@ -380,16 +362,34 @@ Proxy::getOwnEnumerablePropertyKeys(JSCo
     const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
     if (!policy.allowed())
         return policy.returnValue();
     return handler->getOwnEnumerablePropertyKeys(cx, proxy, props);
 }
 
 bool
+Proxy::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    JS_CHECK_RECURSION(cx, return false);
+    const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
+    if (!policy.allowed())
+        return policy.returnValue();
+    if (!handler->hasPrototype())
+        return proxy->as<ProxyObject>().handler()->getEnumerablePropertyKeys(cx, proxy, props);
+    if (!handler->getOwnEnumerablePropertyKeys(cx, proxy, props))
+        return false;
+    AutoIdVector protoProps(cx);
+    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
+                        GetPropertyKeys(cx, proto, 0, &protoProps) &&
+                        AppendUnique(cx, props, protoProps));
+}
+
+bool
 Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     vp.setUndefined(); // default result if we refuse to perform this action
     if (!handler->hasPrototype()) {
         AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                                BaseProxyHandler::ENUMERATE, true);
@@ -401,17 +401,17 @@ Proxy::iterate(JSContext *cx, HandleObje
                    EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
         }
         return handler->iterate(cx, proxy, flags, vp);
     }
     AutoIdVector props(cx);
     // The other Proxy::foo methods do the prototype-aware work for us here.
     if ((flags & JSITER_OWNONLY)
         ? !Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props)
-        : !Proxy::enumerate(cx, proxy, props)) {
+        : !Proxy::getEnumerablePropertyKeys(cx, proxy, props)) {
         return false;
     }
     return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
 }
 
 bool
 Proxy::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
 {
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -29,17 +29,16 @@ class Proxy
     static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                          MutableHandle<JSPropertyDescriptor> desc);
     static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                          MutableHandleValue vp);
     static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                MutableHandle<JSPropertyDescriptor> desc);
     static bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
-    static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
     static bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded);
     static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
     static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
     static bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded);
     static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                     MutableHandleValue vp);
@@ -51,16 +50,17 @@ class Proxy
     /* SpiderMonkey extensions. */
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                       MutableHandle<JSPropertyDescriptor> desc);
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                       MutableHandleValue vp);
     static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                              AutoIdVector &props);
+    static bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
     static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
     static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
     static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
     static const char *className(JSContext *cx, HandleObject proxy);
     static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
     static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
     static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp);
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -756,17 +756,17 @@ ScriptedDirectProxyHandler::delete_(JSCo
 
     // step 11
     *bp = false;
     return true;
 }
 
 // ES6 (22 May, 2014) 9.5.11 Proxy.[[Enumerate]]
 bool
-ScriptedDirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
 {
     // step 1
     RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
 
     // step 2
     if (!handler) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
         return false;
@@ -777,17 +777,17 @@ ScriptedDirectProxyHandler::enumerate(JS
 
     // step 4-5
     RootedValue trap(cx);
     if (!JSObject::getProperty(cx, handler, handler, cx->names().enumerate, &trap))
         return false;
 
     // step 6
     if (trap.isUndefined())
-        return DirectProxyHandler::enumerate(cx, proxy, props);
+        return DirectProxyHandler::getEnumerablePropertyKeys(cx, proxy, props);
 
     // step 7-8
     Value argv[] = {
         ObjectOrNullValue(target)
     };
     RootedValue trapResult(cx);
     if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
         return false;
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -21,17 +21,16 @@ class ScriptedDirectProxyHandler : publi
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
 
     /* These two are standard internal methods but aren't implemented to spec yet. */
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
                                 MutableHandleObject protop) const MOZ_OVERRIDE;
     virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
                                 bool *bp) const MOZ_OVERRIDE;
     /* Non-standard, but needed to handle revoked proxies. */
     virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
@@ -58,16 +57,18 @@ class ScriptedDirectProxyHandler : publi
 
     // Kick getOwnEnumerablePropertyKeys out to ownPropertyKeys and then
     // filter. [[GetOwnProperty]] could potentially change the enumerability of
     // the target's properties.
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE {
         return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
     }
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                          MutableHandleValue vp) const MOZ_OVERRIDE;
 
     virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
     virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
         // For now we maintain the broken behavior that a scripted proxy is constructable if it's
         // callable. See bug 929467.
         return isCallable(obj);
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -222,26 +222,16 @@ ScriptedIndirectProxyHandler::delete_(JS
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().delete_, &fval) &&
            Trap1(cx, handler, fval, id, &value) &&
            ValueToBool(value, bp);
 }
 
 bool
-ScriptedIndirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
-{
-    RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
-    RootedValue fval(cx), value(cx);
-    return GetFundamentalTrap(cx, handler, cx->names().enumerate, &fval) &&
-           Trap(cx, handler, fval, 0, nullptr, &value) &&
-           ArrayToIdVector(cx, value, props);
-}
-
-bool
 ScriptedIndirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     if (!GetDerivedTrap(cx, handler, cx->names().has, &fval))
         return false;
     if (!IsCallable(fval))
         return BaseProxyHandler::has(cx, proxy, id, bp);
@@ -311,16 +301,27 @@ ScriptedIndirectProxyHandler::getOwnEnum
         return false;
     if (!IsCallable(value))
         return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
     return Trap(cx, handler, value, 0, nullptr, &value) &&
            ArrayToIdVector(cx, value, props);
 }
 
 bool
+ScriptedIndirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                                        AutoIdVector &props) const
+{
+    RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
+    RootedValue fval(cx), value(cx);
+    return GetFundamentalTrap(cx, handler, cx->names().enumerate, &fval) &&
+           Trap(cx, handler, fval, 0, nullptr, &value) &&
+           ArrayToIdVector(cx, value, props);
+}
+
+bool
 ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                                       MutableHandleValue vp) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue value(cx);
     if (!GetDerivedTrap(cx, handler, cx->names().iterate, &value))
         return false;
     if (!IsCallable(value))
--- a/js/src/proxy/ScriptedIndirectProxyHandler.h
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.h
@@ -22,31 +22,32 @@ class ScriptedIndirectProxyHandler : pub
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                      MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                      bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+                                           AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                          MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
     virtual bool isScripted() const MOZ_OVERRIDE { return true; }
 
     static const char family;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1750,17 +1750,17 @@ class DebugScopeProxy : public BaseProxy
         return true;
     }
 
     bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE
     {
         return getScopePropertyNames(cx, proxy, props, JSITER_OWNONLY);
     }
 
-    bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE
+    bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE
     {
         return getScopePropertyNames(cx, proxy, props, 0);
     }
 
     bool has(JSContext *cx, HandleObject proxy, HandleId id_, bool *bp) const MOZ_OVERRIDE
     {
         RootedId id(cx, id_);
         ScopeObject &scopeObj = proxy->as<DebugScopeObject>().scope();
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1142,18 +1142,21 @@ public:
         JS::AssertGCThingMustBeTenured(expando);
         if (!mDOMExpandoSet) {
             mDOMExpandoSet = new DOMExpandoSet();
             mDOMExpandoSet->init(8);
         }
         return mDOMExpandoSet->put(expando);
     }
     void RemoveDOMExpandoObject(JSObject *expando) {
-        if (mDOMExpandoSet)
-            mDOMExpandoSet->remove(expando);
+        if (mDOMExpandoSet) {
+            DOMExpandoSet::Ptr p = mDOMExpandoSet->lookup(expando);
+            MOZ_ASSERT(p.found());
+            mDOMExpandoSet->remove(p);
+        }
     }
 
     typedef js::HashMap<JSAddonId *,
                         nsCOMPtr<nsIAddonInterposition>,
                         js::PointerHasher<JSAddonId *, 3>,
                         js::SystemAllocPolicy> InterpositionMap;
 
     static bool SetAddonInterposition(JSAddonId *addonId,
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -97,37 +97,38 @@ FilteringWrapper<Base, Policy>::ownPrope
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
     return Base::ownPropertyKeys(cx, wrapper, props) &&
            Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool
-FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, HandleObject wrapper,
-                                          AutoIdVector &props) const
-{
-    assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
-    return Base::enumerate(cx, wrapper, props) &&
-           Filter<Policy>(cx, wrapper, props);
-}
-
-template <typename Base, typename Policy>
-bool
 FilteringWrapper<Base, Policy>::getOwnEnumerablePropertyKeys(JSContext *cx,
                                                              HandleObject wrapper,
                                                              AutoIdVector &props) const
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
     return Base::getOwnEnumerablePropertyKeys(cx, wrapper, props) &&
            Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool
+FilteringWrapper<Base, Policy>::getEnumerablePropertyKeys(JSContext *cx,
+                                                          HandleObject wrapper,
+                                                          AutoIdVector &props) const
+{
+    assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
+    return Base::getEnumerablePropertyKeys(cx, wrapper, props) &&
+           Filter<Policy>(cx, wrapper, props);
+}
+
+template <typename Base, typename Policy>
+bool
 FilteringWrapper<Base, Policy>::iterate(JSContext *cx, HandleObject wrapper,
                                         unsigned flags, MutableHandleValue vp) const
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
     // We refuse to trigger the iterator hook across chrome wrappers because
     // we don't know how to censor custom iterator objects. Instead we trigger
     // the default proxy iterate trap, which will ask enumerate() for the list
     // of (censored) ids.
@@ -233,17 +234,17 @@ CrossOriginXrayWrapper::getOwnPropertyDe
 
 bool
 CrossOriginXrayWrapper::ownPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                         JS::AutoIdVector &props) const
 {
     // All properties on cross-origin objects are supposed |own|, despite what
     // the underlying native object may report. Override the inherited trap to
     // avoid passing JSITER_OWNONLY as a flag.
-    return SecurityXrayDOM::enumerate(cx, wrapper, JSITER_HIDDEN, props);
+    return SecurityXrayDOM::getPropertyKeys(cx, wrapper, JSITER_HIDDEN, props);
 }
 
 bool
 CrossOriginXrayWrapper::defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const
 {
     JS_ReportError(cx, "Permission denied to define property on cross-origin object");
@@ -254,18 +255,18 @@ bool
 CrossOriginXrayWrapper::delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                 JS::Handle<jsid> id, bool *bp) const
 {
     JS_ReportError(cx, "Permission denied to delete property on cross-origin object");
     return false;
 }
 
 bool
-CrossOriginXrayWrapper::enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                                  JS::AutoIdVector &props) const
+CrossOriginXrayWrapper::getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
+                                                  JS::AutoIdVector &props) const
 {
     // Cross-origin properties are non-enumerable.
     return true;
 }
 
 #define XOW FilteringWrapper<CrossOriginXrayWrapper, CrossOriginAccessiblePropertiesOnly>
 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -28,24 +28,24 @@ class FilteringWrapper : public Base {
     virtual bool enter(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                        js::Wrapper::Action act, bool *bp) const MOZ_OVERRIDE;
 
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                           JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                  JS::AutoIdVector &props) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                           JS::AutoIdVector &props) const MOZ_OVERRIDE;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
+                                           JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
                          JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
 
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const MOZ_OVERRIDE;
 
@@ -75,19 +75,19 @@ class CrossOriginXrayWrapper : public Se
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                 JS::Handle<jsid> id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                  JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                           JS::AutoIdVector &props) const MOZ_OVERRIDE;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
+                                           JS::AutoIdVector &props) const MOZ_OVERRIDE;
 };
 
 }
 
 #endif /* __FilteringWrapper_h__ */
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -2034,17 +2034,17 @@ XrayWrapper<Base, Traits>::definePropert
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::ownPropertyKeys(JSContext *cx, HandleObject wrapper,
                                            AutoIdVector &props) const
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
-    return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
+    return getPropertyKeys(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::delete_(JSContext *cx, HandleObject wrapper,
                                    HandleId id, bool *bp) const
 {
     assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET);
@@ -2060,47 +2060,16 @@ XrayWrapper<Base, Traits>::delete_(JSCon
         return JS_DeletePropertyById2(cx, expando, id, bp);
     }
 
     return Traits::singleton.delete_(cx, wrapper, id, bp);
 }
 
 template <typename Base, typename Traits>
 bool
-XrayWrapper<Base, Traits>::enumerate(JSContext *cx, HandleObject wrapper, unsigned flags,
-                                     AutoIdVector &props) const
-{
-    assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
-
-    // Enumerate expando properties first. Note that the expando object lives
-    // in the target compartment.
-    RootedObject target(cx, Traits::singleton.getTargetObject(wrapper));
-    RootedObject expando(cx);
-    if (!Traits::singleton.getExpandoObject(cx, target, wrapper, &expando))
-        return false;
-
-    if (expando) {
-        JSAutoCompartment ac(cx, expando);
-        if (!js::GetPropertyKeys(cx, expando, flags, &props))
-            return false;
-    }
-
-    return Traits::singleton.enumerateNames(cx, wrapper, flags, props);
-}
-
-template <typename Base, typename Traits>
-bool
-XrayWrapper<Base, Traits>::enumerate(JSContext *cx, HandleObject wrapper,
-                                    AutoIdVector &props) const
-{
-    return enumerate(cx, wrapper, 0, props);
-}
-
-template <typename Base, typename Traits>
-bool
 XrayWrapper<Base, Traits>::get(JSContext *cx, HandleObject wrapper,
                                HandleObject receiver, HandleId id,
                                MutableHandleValue vp) const
 {
     // Skip our Base if it isn't already ProxyHandler.
     // NB: None of the functions we call are prepared for the receiver not
     // being the wrapper, so ignore the receiver here.
     return js::BaseProxyHandler::get(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, vp);
@@ -2144,16 +2113,24 @@ XrayWrapper<Base, Traits>::getOwnEnumera
                                                         AutoIdVector &props) const
 {
     // Skip our Base if it isn't already ProxyHandler.
     return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props);
 }
 
 template <typename Base, typename Traits>
 bool
+XrayWrapper<Base, Traits>::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+                                                     AutoIdVector &props) const
+{
+    return getPropertyKeys(cx, wrapper, 0, props);
+}
+
+template <typename Base, typename Traits>
+bool
 XrayWrapper<Base, Traits>::iterate(JSContext *cx, HandleObject wrapper,
                                    unsigned flags, MutableHandleValue vp) const
 {
     // Skip our Base if it isn't already ProxyHandler.
     return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
 }
 
 template <typename Base, typename Traits>
@@ -2261,16 +2238,39 @@ XrayWrapper<Base, Traits>::setImmutableP
     // For now, lacking an obvious place to store a bit, prohibit making an
     // Xray's [[Prototype]] immutable.  We can revisit this (or maybe give all
     // Xrays immutable [[Prototype]], because who does this, really?) later if
     // necessary.
     *succeeded = false;
     return true;
 }
 
+template <typename Base, typename Traits>
+bool
+XrayWrapper<Base, Traits>::getPropertyKeys(JSContext *cx, HandleObject wrapper, unsigned flags,
+                                           AutoIdVector &props) const
+{
+    assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
+
+    // Enumerate expando properties first. Note that the expando object lives
+    // in the target compartment.
+    RootedObject target(cx, Traits::singleton.getTargetObject(wrapper));
+    RootedObject expando(cx);
+    if (!Traits::singleton.getExpandoObject(cx, target, wrapper, &expando))
+        return false;
+
+    if (expando) {
+        JSAutoCompartment ac(cx, expando);
+        if (!js::GetPropertyKeys(cx, expando, flags, &props))
+            return false;
+    }
+
+    return Traits::singleton.enumerateNames(cx, wrapper, flags, props);
+}
+
 /*
  * The Permissive / Security variants should be used depending on whether the
  * compartment of the wrapper is guranteed to subsume the compartment of the
  * wrapped object (i.e. - whether it is safe from a security perspective to
  * unwrap the wrapper).
  */
 
 template<>
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -408,17 +408,16 @@ class XrayWrapper : public Base {
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool ownPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                  JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
                                 JS::MutableHandleObject protop) const MOZ_OVERRIDE;
     virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
                                 JS::HandleObject proto, bool *bp) const MOZ_OVERRIDE;
     virtual bool setImmutablePrototype(JSContext *cx, JS::HandleObject wrapper,
                                        bool *succeeded) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *extensible) const MOZ_OVERRIDE;
@@ -435,16 +434,18 @@ class XrayWrapper : public Base {
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                         bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
+    virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
+                                           JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
                          JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
 
     virtual const char *className(JSContext *cx, JS::HandleObject proxy) const MOZ_OVERRIDE;
     virtual bool defaultValue(JSContext *cx, JS::HandleObject wrapper,
                               JSType hint, JS::MutableHandleValue vp)
                               const MOZ_OVERRIDE;
 
@@ -468,18 +469,18 @@ class XrayWrapper : public Base {
     bool getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
                               JS::HandleObject target, JS::MutableHandleObject protop) const
     {
         return getPrototypeOfHelper<Traits::HasPrototype>(cx, wrapper, target,
                                                           protop);
     }
 
   protected:
-    bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
-                   JS::AutoIdVector &props) const;
+    bool getPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
+                         JS::AutoIdVector &props) const;
 };
 
 #define PermissiveXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::XPCWrappedNativeXrayTraits>
 #define SecurityXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::XPCWrappedNativeXrayTraits>
 #define PermissiveXrayDOM xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
 #define SecurityXrayDOM xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::DOMXrayTraits>
 #define PermissiveXrayJS xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::JSXrayTraits>
 #define PermissiveXrayOpaque xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::OpaqueXrayTraits>
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -22,28 +22,17 @@ template <typename T>
 struct IsPixel : FalseType {};
 
 // See struct decleration for a description of each unit type
 struct CSSPixel;
 struct LayoutDevicePixel;
 struct LayerPixel;
 struct RenderTargetPixel;
 struct ScreenPixel;
-// The layer coordinates of the parent frame.
-// This can be arrived at in three ways:
-//   - Start with the CSS coordinates of the parent frame, multiply by the
-//     device scale and the cumulative resolution of the parent frame.
-//   - Start with the CSS coordinates of current frame, multiply by the device
-//     scale, the cumulative resolution of the current frame, and the scales
-//     from the CSS and async transforms of the current frame.
-//   - Start with global screen coordinates and unapply all CSS and async
-//     transforms from the root down to and including the parent.
-// It's helpful to look at https://wiki.mozilla.org/Platform/GFX/APZ#Coordinate_systems
-// to get a picture of how the various coordinate systems relate to each other.
-struct ParentLayerPixel {};
+struct ParentLayerPixel;
 
 template<> struct IsPixel<CSSPixel>          : TrueType {};
 template<> struct IsPixel<LayoutDevicePixel> : TrueType {};
 template<> struct IsPixel<LayerPixel>        : TrueType {};
 template<> struct IsPixel<RenderTargetPixel> : TrueType {};
 template<> struct IsPixel<ScreenPixel>       : TrueType {};
 template<> struct IsPixel<ParentLayerPixel>  : TrueType {};
 
@@ -334,16 +323,34 @@ struct RenderTargetPixel {
  * generally be represented in ScreenPixel units.
  */
 struct ScreenPixel {
   static ScreenIntPoint FromUntyped(const nsIntPoint& aPoint) {
     return ScreenIntPoint(aPoint.x, aPoint.y);
   }
 };
 
+/* The layer coordinates of the parent frame.
+ * This can be arrived at in three ways:
+ *   - Start with the CSS coordinates of the parent frame, multiply by the
+ *     device scale and the cumulative resolution of the parent frame.
+ *   - Start with the CSS coordinates of current frame, multiply by the device
+ *     scale, the cumulative resolution of the current frame, and the scales
+ *     from the CSS and async transforms of the current frame.
+ *   - Start with global screen coordinates and unapply all CSS and async
+ *     transforms from the root down to and including the parent.
+ * It's helpful to look at https://wiki.mozilla.org/Platform/GFX/APZ#Coordinate_systems
+ * to get a picture of how the various coordinate systems relate to each other.
+ */
+struct ParentLayerPixel {
+  static nsIntRect ToUntyped(const ParentLayerIntRect& aRect) {
+    return nsIntRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+};
+
 // Operators to apply ScaleFactors directly to Coords, Points, Rects, Sizes and Margins
 
 template<class src, class dst>
 gfx::CoordTyped<dst> operator*(const gfx::CoordTyped<src>& aCoord, const gfx::ScaleFactor<src, dst>& aScale) {
   return gfx::CoordTyped<dst>(aCoord.value * aScale.scale);
 }
 
 template<class src, class dst>
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -728,18 +728,25 @@ nsDisplayScrollLayer::ComputeFrameMetric
   } else {
     metrics.mPresShellResolution = 1.0f;
   }
   // The cumulative resolution is the resolution at which the scroll frame's
   // content is actually rendered. It includes the pres shell resolutions of
   // all the pres shells from here up to the root, as well as any css-driven
   // resolution. We don't need to compute it as it's already stored in the
   // container parameters.
-  metrics.mCumulativeResolution = LayoutDeviceToLayerScale(aContainerParameters.mXScale,
-                                                           aContainerParameters.mYScale);
+  // TODO: On Fennec, the container parameters do not appear to contain the
+  // cumulative resolution the way they do on B2G, and using them breaks
+  // rendering for normal pages (no CSS transform involves). As a temporary
+  // workaround, use the same value as the resolution-to-screen; this will make
+  // the "extra resolution" 1, and pages with CSS transforms may not be
+  // rendered correctly, but normal pages will.
+  metrics.mCumulativeResolution = LayoutDeviceToLayerScale(
+      presShell->GetCumulativeResolution().width
+    * nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame ? aScrollFrame : aForFrame).width);
 
   LayoutDeviceToScreenScale resolutionToScreen(
       presShell->GetCumulativeResolution().width
     * nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame ? aScrollFrame : aForFrame).width);
   metrics.SetExtraResolution(metrics.mCumulativeResolution / resolutionToScreen);
 
   metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(
     (float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel);
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -384,27 +384,27 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
   nsIPresShell* ps = mPresContext->PresShell();
   if (!ps)
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIStreamLoader> streamLoader;
   nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
 
   nsCOMPtr<nsIChannel> channel;
-  // Note we are calling NS_NewChannelInternal() with both a node and a
-  // principal.  This is because the document where the font is being loaded
-  // might have a different origin from the principal of the stylesheet
-  // that initiated the font load.
-  rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                             aFontFaceSrc->mURI,
-                             ps->GetDocument(),
-                             aUserFontEntry->GetPrincipal(),
-                             nsILoadInfo::SEC_NORMAL,
-                             nsIContentPolicy::TYPE_FONT,
-                             loadGroup);
+  // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
+  // node and a principal.  This is because the document where the font is
+  // being loaded might have a different origin from the principal of the
+  // stylesheet that initiated the font load.
+  rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
+                                            aFontFaceSrc->mURI,
+                                            ps->GetDocument(),
+                                            aUserFontEntry->GetPrincipal(),
+                                            nsILoadInfo::SEC_NORMAL,
+                                            nsIContentPolicy::TYPE_FONT,
+                                            loadGroup);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<nsFontFaceLoader> fontLoader =
     new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI, this, channel);
 
   if (!fontLoader)
     return NS_ERROR_OUT_OF_MEMORY;
@@ -1180,26 +1180,26 @@ FontFaceSet::SyncLoadFontData(gfxUserFon
 {
   nsresult rv;
 
   nsCOMPtr<nsIChannel> channel;
   nsIPresShell* ps = mPresContext->PresShell();
   if (!ps) {
     return NS_ERROR_FAILURE;
   }
-  // Note we are calling NS_NewChannelInternal() with both a node and a
-  // principal.  This is because the document where the font is being loaded
-  // might have a different origin from the principal of the stylesheet
-  // that initiated the font load.
-  rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                             aFontFaceSrc->mURI,
-                             ps->GetDocument(),
-                             aFontToLoad->GetPrincipal(),
-                             nsILoadInfo::SEC_NORMAL,
-                             nsIContentPolicy::TYPE_FONT);
+  // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
+  // node and a principal.  This is because the document where the font is
+  // being loaded might have a different origin from the principal of the
+  // stylesheet that initiated the font load.
+  rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
+                                            aFontFaceSrc->mURI,
+                                            ps->GetDocument(),
+                                            aFontToLoad->GetPrincipal(),
+                                            nsILoadInfo::SEC_NORMAL,
+                                            nsIContentPolicy::TYPE_FONT);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // blocking stream is OK for data URIs
   nsCOMPtr<nsIInputStream> stream;
   rv = channel->Open(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1419,29 +1419,29 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
   if (!mDocument && !aLoadData->mIsNonDocumentSheet) {
     // No point starting the load; just release all the data and such.
     LOG_WARN(("  No document and not non-document sheet; pre-dropping load"));
     SheetComplete(aLoadData, NS_BINDING_ABORTED);
     return NS_BINDING_ABORTED;
   }
 
   bool inherit = false;
-  nsIPrincipal* requestingPrincipal = aLoadData->mLoaderPrincipal;
-  if (requestingPrincipal) {
+  nsIPrincipal* triggeringPrincipal = aLoadData->mLoaderPrincipal;
+  if (triggeringPrincipal) {
     rv = NS_URIChainHasFlags(aLoadData->mURI,
                              nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                              &inherit);
     inherit =
       ((NS_SUCCEEDED(rv) && inherit) ||
        (nsContentUtils::URIIsLocalFile(aLoadData->mURI) &&
         NS_SUCCEEDED(aLoadData->mLoaderPrincipal->
                      CheckMayLoad(aLoadData->mURI, false, false))));
   }
   else {
-    requestingPrincipal = nsContentUtils::GetSystemPrincipal();
+    triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
   }
 
   if (aLoadData->mSyncLoad) {
     LOG(("  Synchronous load"));
     NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
     NS_ASSERTION(aSheetState == eSheetNeedsParser,
                  "Sync loads can't reuse existing async loads");
 
@@ -1464,27 +1464,46 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
 
     // Just load it
     nsCOMPtr<nsIInputStream> stream;
     nsCOMPtr<nsIChannel> channel;
     // Note that we are calling NS_OpenURIInternal() with both a node and a
     // principal.  This is because of a case where the node is the document
     // being styled and the principal is the stylesheet (perhaps from a
     // different origin)  that is applying the styles.
-    rv = NS_OpenURIInternal(getter_AddRefs(stream),
-                            aLoadData->mURI,
-                            aLoadData->mRequestingNode,
-                            requestingPrincipal,
-                            nsILoadInfo::SEC_NORMAL,
-                            nsIContentPolicy::TYPE_OTHER,
-                            nullptr,   // aLoadGroup
-                            nullptr,   // aCallbacks
-                            nsIRequest::LOAD_NORMAL,
-                            nullptr,   // aIoService
-                            getter_AddRefs(channel));
+    if (aLoadData->mRequestingNode) {
+      rv = NS_OpenURIWithTriggeringPrincipal(getter_AddRefs(stream),
+                                             aLoadData->mURI,
+                                             aLoadData->mRequestingNode,
+                                             triggeringPrincipal,
+                                             nsILoadInfo::SEC_NORMAL,
+                                             nsIContentPolicy::TYPE_OTHER,
+                                             nullptr,   // aLoadGroup
+                                             nullptr,   // aCallbacks
+                                             nsIRequest::LOAD_NORMAL,
+                                             nullptr,   // aIoService
+                                             getter_AddRefs(channel));
+    }
+    else {
+      // either we are loading something inside a document, in which case
+      // we should always have a requestingNode, or we are loading something
+      // outside a document, in which case the triggeringPrincipal
+      // should always be the systemPrincipal.
+      MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(triggeringPrincipal));
+      rv = NS_OpenURI(getter_AddRefs(stream),
+                      aLoadData->mURI,
+                      triggeringPrincipal,
+                      nsILoadInfo::SEC_NORMAL,
+                      nsIContentPolicy::TYPE_OTHER,
+                      nullptr,   // aLoadGroup
+                      nullptr,   // aCallbacks
+                      nsIRequest::LOAD_NORMAL,
+                      nullptr,   // aIoService
+                      getter_AddRefs(channel));
+    }
 
     if (NS_FAILED(rv)) {
       LOG_ERROR(("  Failed to open URI synchronously"));
       SheetComplete(aLoadData, rv);
       return rv;
     }
 
     NS_ASSERTION(channel, "NS_OpenURI lied?");
@@ -1555,30 +1574,48 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
   }
 
   nsLoadFlags securityFlags = nsILoadInfo::SEC_NORMAL;
   if (inherit) {
     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
   nsCOMPtr<nsIChannel> channel;
-  // Note we are calling NS_NewChannelInternal here with a node and a principal.
-  // This is because of a case where the node is the document being styled and
-  // the principal is the stylesheet (perhaps from a different origin)  that is
-  // applying the styles.
-  rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                             aLoadData->mURI,
-                             aLoadData->mRequestingNode,
-                             requestingPrincipal,
-                             securityFlags,
-                             nsIContentPolicy::TYPE_STYLESHEET,
-                             loadGroup,
-                             nullptr,   // aCallbacks
-                             nsIChannel::LOAD_NORMAL |
-                             nsIChannel::LOAD_CLASSIFY_URI);
+  // Note we are calling NS_NewChannelWithTriggeringPrincipal here with a node
+  // and a principal. This is because of a case where the node is the document
+  // being styled and the principal is the stylesheet (perhaps from a different
+  // origin)  that is applying the styles.
+  if (aLoadData->mRequestingNode) {
+    rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
+                                              aLoadData->mURI,
+                                              aLoadData->mRequestingNode,
+                                              triggeringPrincipal,
+                                              securityFlags,
+                                              nsIContentPolicy::TYPE_STYLESHEET,
+                                              loadGroup,
+                                              nullptr,   // aCallbacks
+                                              nsIChannel::LOAD_NORMAL |
+                                              nsIChannel::LOAD_CLASSIFY_URI);
+  }
+  else {
+    // either we are loading something inside a document, in which case
+    // we should always have a requestingNode, or we are loading something
+    // outside a document, in which case the triggeringPrincipal
+    // should always be the systemPrincipal.
+    MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(triggeringPrincipal));
+    rv = NS_NewChannel(getter_AddRefs(channel),
+                       aLoadData->mURI,
+                       triggeringPrincipal,
+                       securityFlags,
+                       nsIContentPolicy::TYPE_STYLESHEET,
+                       loadGroup,
+                       nullptr,   // aCallbacks
+                       nsIChannel::LOAD_NORMAL |
+                       nsIChannel::LOAD_CLASSIFY_URI);
+  }
 
   if (NS_FAILED(rv)) {
 #ifdef DEBUG
     mSyncCallback = false;
 #endif
     LOG_ERROR(("  Failed to create channel"));
     SheetComplete(aLoadData, rv);
     return rv;
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -48,16 +48,18 @@
 #include "nsStyleSet.h"
 #include "mozilla/dom/Element.h"
 #include "nsNthIndexCache.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Likely.h"
+#include "mozilla/TypedEnum.h"
+#include "mozilla/TypedEnumBits.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
 
 static bool gSupportVisitedPseudo = true;
 
@@ -1424,16 +1426,40 @@ struct NodeMatchContext {
 
   NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink)
     : mStateMask(aStateMask)
     , mIsRelevantLink(aIsRelevantLink)
   {
   }
 };
 
+/**
+ * Additional information about a selector (without combinators) that is
+ * being matched.
+ */
+MOZ_BEGIN_ENUM_CLASS(SelectorMatchesFlags, uint8_t)
+  NONE = 0,
+
+  // The selector's flags are unknown.  This happens when you don't know
+  // if you're starting from the top of a selector.  Only used in cases
+  // where it's acceptable for matching to return a false positive.
+  // (It's not OK to return a false negative.)
+  UNKNOWN = 1 << 0,
+
+  // The selector is part of a compound selector which has been split in
+  // half, where the other half is a pseudo-element.  The current
+  // selector is not a pseudo-element itself.
+  HAS_PSEUDO_ELEMENT = 1 << 1,
+
+  // The selector is part of an argument to a functional pseudo-class or
+  // pseudo-element.
+  IS_PSEUDO_CLASS_ARGUMENT = 1 << 2
+MOZ_END_ENUM_CLASS(SelectorMatchesFlags)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorMatchesFlags)
+
 static bool ValueIncludes(const nsSubstring& aValueList,
                             const nsSubstring& aValue,
                             const nsStringComparator& aComparator)
 {
   const char16_t *p = aValueList.BeginReading(),
               *p_end = aValueList.EndReading();
 
   while (p < p_end) {
@@ -1453,28 +1479,43 @@ static bool ValueIncludes(const nsSubstr
         aValue.Equals(Substring(val_start, val_end), aComparator))
       return true;
 
     ++p; // we know the next character is not whitespace
   }
   return false;
 }
 
-// Return whether we should apply a "global" (i.e., universal-tag)
-// selector for event states in quirks mode.  Note that
-// |IsLink()| is checked separately by the caller, so we return
-// false for |nsGkAtoms::a|, which here means a named anchor.
-inline bool IsQuirkEventSensitive(nsIAtom *aContentTag)
+// Return whether the selector matches conditions for the :active and
+// :hover quirk.
+static inline bool ActiveHoverQuirkMatches(nsCSSSelector* aSelector,
+                                           SelectorMatchesFlags aSelectorFlags)
 {
-  return bool ((nsGkAtoms::button == aContentTag) ||
-                 (nsGkAtoms::img == aContentTag)    ||
-                 (nsGkAtoms::input == aContentTag)  ||
-                 (nsGkAtoms::label == aContentTag)  ||
-                 (nsGkAtoms::select == aContentTag) ||
-                 (nsGkAtoms::textarea == aContentTag));
+  if (aSelector->HasTagSelector() || aSelector->mAttrList ||
+      aSelector->mIDList || aSelector->mClassList ||
+      aSelector->IsPseudoElement() ||
+      // Having this quirk means that some selectors will no longer match,
+      // so it's better to return false when we aren't sure (i.e., the
+      // flags are unknown).
+      aSelectorFlags & (SelectorMatchesFlags::UNKNOWN |
+                        SelectorMatchesFlags::HAS_PSEUDO_ELEMENT |
+                        SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
+    return false;
+  }
+
+  // No pseudo-class other than :active and :hover.
+  for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
+       pseudoClass; pseudoClass = pseudoClass->mNext) {
+    if (pseudoClass->mType != nsCSSPseudoClasses::ePseudoClass_hover &&
+        pseudoClass->mType != nsCSSPseudoClasses::ePseudoClass_active) {
+      return false;
+    }
+  }
+
+  return true;
 }
 
 
 static inline bool
 IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
                    bool aWhitespaceIsSignificant)
 {
   return nsStyleUtil::IsSignificantChild(aChild, aTextIsSignificant,
@@ -1661,41 +1702,32 @@ static_assert(MOZ_ARRAY_LENGTH(sPseudoCl
               "ePseudoClass_NotPseudoClass is no longer at the end of"
               "sPseudoClassStates");
 
 static bool
 StateSelectorMatches(Element* aElement,
                      nsCSSSelector* aSelector,
                      NodeMatchContext& aNodeMatchContext,
                      TreeMatchContext& aTreeMatchContext,
+                     SelectorMatchesFlags aSelectorFlags,
                      bool* const aDependence,
                      EventStates aStatesToCheck)
 {
   NS_PRECONDITION(!aStatesToCheck.IsEmpty(),
                   "should only need to call StateSelectorMatches if "
                   "aStatesToCheck is not empty");
 
-  const bool isNegated = aDependence != nullptr;
-
   // Bit-based pseudo-classes
-  if (aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE) &&
+  if (aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE |
+                                           NS_EVENT_STATE_HOVER) &&
       aTreeMatchContext.mCompatMode == eCompatibility_NavQuirks &&
-      // global selector:
-      !aSelector->HasTagSelector() && !aSelector->mIDList &&
-      !aSelector->mClassList && !aSelector->mAttrList &&
-      // This (or the other way around) both make :not() asymmetric
-      // in quirks mode (and it's hard to work around since we're
-      // testing the current mNegations, not the first
-      // (unnegated)). This at least makes it closer to the spec.
-      !isNegated &&
-      // important for |IsQuirkEventSensitive|:
-      aElement->IsHTML() && !nsCSSRuleProcessor::IsLink(aElement) &&
-      !IsQuirkEventSensitive(aElement->Tag())) {
-    // In quirks mode, only make certain elements sensitive to
-    // selectors ":hover" and ":active".
+      ActiveHoverQuirkMatches(aSelector, aSelectorFlags) &&
+      aElement->IsHTML() && !nsCSSRuleProcessor::IsLink(aElement)) {
+    // In quirks mode, only make links sensitive to selectors ":active"
+    // and ":hover".
     return false;
   }
 
   if (aTreeMatchContext.mForStyling &&
       aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER)) {
     // Mark the element as having :hover-dependent style
     aElement->SetHasRelevantHoverRules();
   }
@@ -1718,41 +1750,43 @@ StateSelectorMatches(Element* aElement,
 
   return true;
 }
 
 static bool
 StateSelectorMatches(Element* aElement,
                      nsCSSSelector* aSelector,
                      NodeMatchContext& aNodeMatchContext,
-                     TreeMatchContext& aTreeMatchContext)
+                     TreeMatchContext& aTreeMatchContext,
+                     SelectorMatchesFlags aSelectorFlags)
 {
   for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
        pseudoClass; pseudoClass = pseudoClass->mNext) {
     EventStates statesToCheck = sPseudoClassStates[pseudoClass->mType];
     if (!statesToCheck.IsEmpty() &&
         !StateSelectorMatches(aElement, aSelector, aNodeMatchContext,
-                              aTreeMatchContext, nullptr, statesToCheck)) {
+                              aTreeMatchContext, aSelectorFlags, nullptr,
+                              statesToCheck)) {
       return false;
     }
   }
   return true;
 }
 
 // |aDependence| has two functions:
 //  * when non-null, it indicates that we're processing a negation,
 //    which is done only when SelectorMatches calls itself recursively
 //  * what it points to should be set to true whenever a test is skipped
 //    because of aNodeMatchContent.mStateMask
 static bool SelectorMatches(Element* aElement,
-                              nsCSSSelector* aSelector,
-                              NodeMatchContext& aNodeMatchContext,
-                              TreeMatchContext& aTreeMatchContext,
-                              bool* const aDependence = nullptr)
-
+                            nsCSSSelector* aSelector,
+                            NodeMatchContext& aNodeMatchContext,
+                            TreeMatchContext& aTreeMatchContext,
+                            SelectorMatchesFlags aSelectorFlags,
+                            bool* const aDependence = nullptr)
 {
   NS_PRECONDITION(!aSelector->IsPseudoElement(),
                   "Pseudo-element snuck into SelectorMatches?");
   NS_ABORT_IF_FALSE(aTreeMatchContext.mForStyling ||
                     !aNodeMatchContext.mIsRelevantLink,
                     "mIsRelevantLink should be set to false when mForStyling "
                     "is false since we don't know how to set it correctly in "
                     "Has(Attribute|State)DependentStyle");
@@ -1957,18 +1991,19 @@ static bool SelectorMatches(Element* aEl
 
       case nsCSSPseudoClasses::ePseudoClass_any:
         {
           nsCSSSelectorList *l;
           for (l = pseudoClass->u.mSelectors; l; l = l->mNext) {
             nsCSSSelector *s = l->mSelectors;
             NS_ABORT_IF_FALSE(!s->mNext && !s->IsPseudoElement(),
                               "parser failed");
-            if (SelectorMatches(aElement, s, aNodeMatchContext,
-                                aTreeMatchContext)) {
+            if (SelectorMatches(
+                  aElement, s, aNodeMatchContext, aTreeMatchContext,
+                  SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
               break;
             }
           }
           if (!l) {
             return false;
           }
         }
         break;
@@ -2220,17 +2255,17 @@ static bool SelectorMatches(Element* aEl
         }
         break;
 
       default:
         NS_ABORT_IF_FALSE(false, "How did that happen?");
       }
     } else {
       if (!StateSelectorMatches(aElement, aSelector, aNodeMatchContext,
-                                aTreeMatchContext, aDependence,
+                                aTreeMatchContext, aSelectorFlags, aDependence,
                                 statesToCheck)) {
         return false;
       }
     }
   }
 
   bool result = true;
   if (aSelector->mAttrList) {
@@ -2310,17 +2345,19 @@ static bool SelectorMatches(Element* aEl
   }
 
   // apply SelectorMatches to the negated selectors in the chain
   if (!isNegated) {
     for (nsCSSSelector *negation = aSelector->mNegations;
          result && negation; negation = negation->mNegations) {
       bool dependence = false;
       result = !SelectorMatches(aElement, negation, aNodeMatchContext,
-                                aTreeMatchContext, &dependence);
+                                aTreeMatchContext,
+                                SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT,
+                                &dependence);
       // If the selector does match due to the dependence on
       // aNodeMatchContext.mStateMask, then we want to keep result true
       // so that the final result of SelectorMatches is true.  Doing so
       // tells StateEnumFunc that there is a dependence on the state.
       result = result || dependence;
     }
   }
   return result;
@@ -2418,17 +2455,18 @@ static bool SelectorMatchesTree(Element*
       // constructor call above).
       // Since we are still matching against selectors that contain
       // :visited (they'll just fail), we will always find such a node
       // during the selector matching process if there is a relevant
       // link that can influence selector matching.
       aLookForRelevantLink = false;
       aTreeMatchContext.SetHaveRelevantLink();
     }
-    if (SelectorMatches(element, selector, nodeContext, aTreeMatchContext)) {
+    if (SelectorMatches(element, selector, nodeContext, aTreeMatchContext,
+                        SelectorMatchesFlags::NONE)) {
       // to avoid greedy matching, we need to recur if this is a
       // descendant or general sibling combinator and the next
       // combinator is different, but we can make an exception for
       // sibling, then parent, since a sibling's parent is always the
       // same.
       if (NS_IS_GREEDY_OPERATOR(selector->mOperator) &&
           selector->mNext &&
           selector->mNext->mOperator != selector->mOperator &&
@@ -2500,23 +2538,29 @@ void ContentEnumFunc(const RuleValue& va
       //     pseudo-element in the document, like ::-moz-placeholder:hover; and
       //   * aElt does not have such a pseudo-element.
       //
       // We know that the selector can't match, since there is no element for
       // the user action pseudo-class to match against.
       return;
     }
     if (!StateSelectorMatches(pdata->mPseudoElement, aSelector, nodeContext,
-                              data->mTreeMatchContext)) {
+                              data->mTreeMatchContext,
+                              SelectorMatchesFlags::NONE)) {
       return;
     }
     selector = selector->mNext;
   }
+
+  SelectorMatchesFlags selectorFlags = SelectorMatchesFlags::NONE;
+  if (aSelector->IsPseudoElement()) {
+    selectorFlags |= SelectorMatchesFlags::HAS_PSEUDO_ELEMENT;
+  }
   if (SelectorMatches(data->mElement, selector, nodeContext,
-                      data->mTreeMatchContext)) {
+                      data->mTreeMatchContext, selectorFlags)) {
     nsCSSSelector *next = selector->mNext;
     if (!next || SelectorMatchesTree(data->mElement, next,
                                      data->mTreeMatchContext,
                                      !nodeContext.mIsRelevantLink)) {
       css::StyleRule *rule = value.mRule;
       rule->RuleMatched();
       data->mRuleWalker->Forward(rule);
       // nsStyleSet will deal with the !important rule
@@ -2651,16 +2695,17 @@ nsCSSRuleProcessor::HasStateDependentSty
         if (selector->PseudoType() != aPseudoType) {
           continue;
         }
         selectorForPseudo = selector;
         selector = selector->mNext;
       }
 
       nsRestyleHint possibleChange = RestyleHintForOp(selector->mOperator);
+      SelectorMatchesFlags selectorFlags = SelectorMatchesFlags::UNKNOWN;
 
       // If hint already includes all the bits of possibleChange,
       // don't bother calling SelectorMatches, since even if it returns false
       // hint won't change.
       // Also don't bother calling SelectorMatches if none of the
       // states passed in are relevant here.
       if ((possibleChange & ~hint) &&
           states.HasAtLeastOneOfStates(aStateMask) &&
@@ -2680,19 +2725,19 @@ nsCSSRuleProcessor::HasStateDependentSty
            (selector->mPseudoClassList &&
             (selector->mPseudoClassList->mNext ||
              selector->mPseudoClassList->mType !=
                nsCSSPseudoClasses::ePseudoClass_hover)) ||
            selector->mAttrList || selector->mNegations) &&
           (!isPseudoElement ||
            StateSelectorMatches(aStatefulElement, selectorForPseudo,
                                 nodeContext, aData->mTreeMatchContext,
-                                nullptr, aStateMask)) &&
+                                selectorFlags, nullptr, aStateMask)) &&
           SelectorMatches(aData->mElement, selector, nodeContext,
-                          aData->mTreeMatchContext) &&
+                          aData->mTreeMatchContext, selectorFlags) &&
           SelectorMatchesTree(aData->mElement, selector->mNext,
                               aData->mTreeMatchContext,
                               false))
       {
         hint = nsRestyleHint(hint | possibleChange);
       }
     }
   }
@@ -2749,17 +2794,17 @@ AttributeEnumFunc(nsCSSSelector* aSelect
   nsRestyleHint possibleChange = RestyleHintForOp(aSelector->mOperator);
 
   // If enumData->change already includes all the bits of possibleChange, don't
   // bother calling SelectorMatches, since even if it returns false
   // enumData->change won't change.
   NodeMatchContext nodeContext(EventStates(), false);
   if ((possibleChange & ~(aData->change)) &&
       SelectorMatches(data->mElement, aSelector, nodeContext,
-                      data->mTreeMatchContext) &&
+                      data->mTreeMatchContext, SelectorMatchesFlags::UNKNOWN) &&
       SelectorMatchesTree(data->mElement, aSelector->mNext,
                           data->mTreeMatchContext, false)) {
     aData->change = nsRestyleHint(aData->change | possibleChange);
   }
 }
 
 static MOZ_ALWAYS_INLINE void
 EnumerateSelectors(nsTArray<nsCSSSelector*>& aSelectors, AttributeEnumData* aData)
@@ -3566,17 +3611,18 @@ nsCSSRuleProcessor::SelectorListMatches(
              "mCurrentStyleScope will need to be saved and restored after the "
              "SelectorMatchesTree call");