merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Tue, 03 Oct 2017 11:43:52 +0200
changeset 426748 11fe0a2895aab26c57bcfe61b3041d7837e954cd
parent 426746 14841c4d8a9783ad55a0c560ec9312ba16200ac1 (current diff)
parent 426680 c3729a7809983b9b69b1e3b79a0582345398ef93 (diff)
child 426749 bbd10924359c0d1c262c35a7d0e58637a9d32b30
child 426789 f38e89957937e4ef742302cd31927a077b3d3ba9
child 426830 b2d7d2ca373dcc0a8b77f6755d33a3f2b6c7e517
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersmerge, merge
milestone58.0a1
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: IRW0W7LuIM7
dom/plugins/test/mochitest/test_pluginstream_asfile.html
dom/plugins/test/mochitest/test_pluginstream_asfileonly.html
dom/plugins/test/mochitest/test_twostreams.html
--- a/accessible/ipc/win/COMPtrTypes.h
+++ b/accessible/ipc/win/COMPtrTypes.h
@@ -3,24 +3,72 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_COMPtrTypes_h
 #define mozilla_a11y_COMPtrTypes_h
 
 #include "mozilla/a11y/AccessibleHandler.h"
+#include "mozilla/a11y/Compatibility.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/mscom/ActivationContext.h"
 #include "mozilla/mscom/COMPtrHolder.h"
 #include "mozilla/NotNull.h"
 
 #include <oleacc.h>
 
 namespace mozilla {
 namespace a11y {
 
+class MOZ_RAII IAccessibleEnvironment : public mscom::ProxyStream::Environment
+{
+public:
+  IAccessibleEnvironment() = default;
+
+  bool Push() override
+  {
+    mActCtxRgn = GetActCtx();
+    return !!mActCtxRgn;
+  }
+
+  bool Pop() override
+  {
+    return mActCtxRgn.Deactivate();
+  }
+
+private:
+  static const mscom::ActivationContext& GetActCtx()
+  {
+    static const mscom::ActivationContext
+      sActCtx(Compatibility::GetActCtxResourceId());
+    MOZ_DIAGNOSTIC_ASSERT(sActCtx);
+    return sActCtx;
+  }
+
+private:
+  mscom::ActivationContextRegion mActCtxRgn;
+};
+
+} // namespace a11y
+
+namespace mscom {
+namespace detail {
+
+template<>
+struct EnvironmentSelector<IAccessible>
+{
+  typedef a11y::IAccessibleEnvironment Type;
+};
+
+} // namespace detail
+} // namespace mscom
+
+namespace a11y {
+
 typedef mozilla::mscom::COMPtrHolder<IAccessible, IID_IAccessible> IAccessibleHolder;
 typedef mozilla::mscom::COMPtrHolder<IDispatch, IID_IDispatch> IDispatchHolder;
 
 class Accessible;
 
 IAccessibleHolder
 CreateHolderFromAccessible(NotNull<Accessible*> aAccToWrap);
 
--- a/browser/base/content/test/newtab/browser.ini
+++ b/browser/base/content/test/newtab/browser.ini
@@ -26,16 +26,17 @@ skip-if = (os == "mac" || os == "win") &
 [browser_newtab_disable.js]
 [browser_newtab_drag_drop.js]
 [browser_newtab_drag_drop_ext.js]
 # temporary until determine why more intermittent on VM
 subsuite = clipboard
 [browser_newtab_drop_preview.js]
 [browser_newtab_focus.js]
 [browser_newtab_fullscreen_focus.js]
+skip-if = os == "mac" && debug # bug 1394963
 [browser_newtab_perwindow_private_browsing.js]
 [browser_newtab_reflow_load.js]
 support-files =
   content-reflows.js
 [browser_newtab_search.js]
 support-files =
   searchEngineNoLogo.xml
   searchEngineFavicon.xml
--- a/browser/components/migration/tests/unit/xpcshell.ini
+++ b/browser/components/migration/tests/unit/xpcshell.ini
@@ -13,15 +13,15 @@ skip-if = os != "win"
 [test_Chrome_cookies.js]
 skip-if = os != "mac" # Relies on ULibDir
 [test_Chrome_passwords.js]
 skip-if = os != "win"
 [test_Edge_db_migration.js]
 skip-if = os != "win"
 [test_fx_telemetry.js]
 [test_IE_bookmarks.js]
-skip-if = os != "win"
+skip-if = true # bug 1392396
 [test_IE_cookies.js]
 skip-if = os != "win"
 [test_IE7_passwords.js]
 skip-if = os != "win"
 [test_Safari_bookmarks.js]
 skip-if = os != "mac"
--- a/browser/components/newtab/tests/browser/browser.ini
+++ b/browser/components/newtab/tests/browser/browser.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 support-files =
   dummy_page.html
 
 [browser_remotenewtab_pageloads.js]
 [browser_newtab_overrides.js]
+skip-if = true # bug 1399854
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1722,56 +1722,17 @@ NPError
     default:
       return NPERR_GENERIC_ERROR;
   }
 }
 
 NPError
 _requestread(NPStream *pstream, NPByteRange *rangeList)
 {
-  if (!NS_IsMainThread()) {
-    NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n"));
-    return NPERR_INVALID_PARAM;
-  }
-  NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n",
-                                     (void*)pstream));
-
-#ifdef PLUGIN_LOGGING
-  for(NPByteRange * range = rangeList; range != nullptr; range = range->next)
-    MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY,
-    ("%i-%i", range->offset, range->offset + range->length - 1));
-
-  MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n"));
-  PR_LogFlush();
-#endif
-
-  if (!pstream || !rangeList || !pstream->ndata)
-    return NPERR_INVALID_PARAM;
-
-  nsNPAPIStreamWrapper* streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
-  nsNPAPIPluginStreamListener* streamlistener = streamWrapper->GetStreamListener();
-  if (!streamlistener) {
-    return NPERR_GENERIC_ERROR;
-  }
-
-  int32_t streamtype = NP_NORMAL;
-
-  streamlistener->GetStreamType(&streamtype);
-
-  if (streamtype != NP_SEEK)
-    return NPERR_STREAM_NOT_SEEKABLE;
-
-  if (!streamlistener->mStreamListenerPeer)
-    return NPERR_GENERIC_ERROR;
-
-  nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList);
-  if (NS_FAILED(rv))
-    return NPERR_GENERIC_ERROR;
-
-  return NPERR_NO_ERROR;
+  return NPERR_STREAM_NOT_SEEKABLE;
 }
 
 // Deprecated, only stubbed out
 void* /* OJI type: JRIEnv* */
 _getJavaEnv()
 {
   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n"));
   return nullptr;
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
@@ -41,17 +41,16 @@ NS_IMPL_ISUPPORTS(nsNPAPIPluginStreamLis
 nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst,
                                                          void* notifyData,
                                                          const char* aURL)
   : mStreamBuffer(nullptr)
   , mNotifyURL(aURL ? PL_strdup(aURL) : nullptr)
   , mInst(inst)
   , mStreamBufferSize(0)
   , mStreamBufferByteCount(0)
-  , mStreamType(NP_NORMAL)
   , mStreamState(eStreamStopped)
   , mStreamCleanedUp(false)
   , mCallNotify(notifyData ? true : false)
   , mIsSuspended(false)
   , mIsPluginInitJSStream(mInst->mInPluginInitCall &&
                           aURL && strncmp(aURL, "javascript:",
                                           sizeof("javascript:") - 1) == 0)
   , mRedirectDenied(false)
@@ -110,21 +109,16 @@ nsNPAPIPluginStreamListener::CleanUpStre
   StopDataPump();
 
   // Release any outstanding redirect callback.
   if (mHTTPRedirectCallback) {
     mHTTPRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
     mHTTPRedirectCallback = nullptr;
   }
 
-  // Seekable streams have an extra addref when they are created which must
-  // be matched here.
-  if (NP_SEEK == mStreamType && mStreamState == eStreamTypeSet)
-    NS_RELEASE_THIS();
-
   if (mStreamListenerPeer) {
     mStreamListenerPeer->CancelRequests(NS_BINDING_ABORTED);
     mStreamListenerPeer = nullptr;
   }
 
   if (!mInst || !mInst->CanFireNotifications())
     return rv;
 
@@ -207,98 +201,53 @@ nsNPAPIPluginStreamListener::OnStartBind
   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
 
   if (!pluginFunctions->newstream)
     return NS_ERROR_FAILURE;
 
   NPP npp;
   mInst->GetNPP(&npp);
 
-  bool seekable;
   char* contentType;
   uint16_t streamType = NP_NORMAL;
   NPError error;
 
   streamPeer->GetURL(&mNPStreamWrapper->mNPStream.url);
   streamPeer->GetLength((uint32_t*)&(mNPStreamWrapper->mNPStream.end));
   streamPeer->GetLastModified((uint32_t*)&(mNPStreamWrapper->mNPStream.lastmodified));
-  streamPeer->IsSeekable(&seekable);
   streamPeer->GetContentType(&contentType);
 
   if (!mResponseHeaders.IsEmpty()) {
     mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
     mNPStreamWrapper->mNPStream.headers = mResponseHeaderBuf;
   }
 
   mStreamListenerPeer = streamPeer;
 
   NPPAutoPusher nppPusher(npp);
 
-  NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, seekable, &streamType), mInst,
+  NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, false, &streamType), mInst,
                           NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
 
   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                  ("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
-                  this, npp, (char *)contentType, seekable, streamType, error, mNPStreamWrapper->mNPStream.url));
+                  this, npp, (char *)contentType, false, streamType, error, mNPStreamWrapper->mNPStream.url));
 
   if (error != NPERR_NO_ERROR)
     return NS_ERROR_FAILURE;
 
   mStreamState = eNewStreamCalled;
 
-  if (!SetStreamType(streamType, false)) {
+  if (streamType != NP_NORMAL) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-bool
-nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
-{
-  switch(aType)
-  {
-    case NP_NORMAL:
-      mStreamType = NP_NORMAL;
-      break;
-    case NP_ASFILEONLY:
-      mStreamType = NP_ASFILEONLY;
-      break;
-    case NP_ASFILE:
-      mStreamType = NP_ASFILE;
-      break;
-    case NP_SEEK:
-      mStreamType = NP_SEEK;
-      // Seekable streams should continue to exist even after OnStopRequest
-      // is fired, so we AddRef ourself an extra time and Release when the
-      // plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
-      // calls NPN_DestroyStream the stream will be destroyed before the plugin
-      // instance is destroyed.
-      NS_ADDREF_THIS();
-      break;
-    case nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN:
-      MOZ_ASSERT(!aNeedsResume);
-      mStreamType = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
-      SuspendRequest();
-      mStreamStopMode = eDoDeferredStop;
-      // In this case we do not want to execute anything else in this function.
-      return true;
-    default:
-      return false;
-  }
-  mStreamState = eStreamTypeSet;
-  if (aNeedsResume) {
-    if (mStreamListenerPeer) {
-      mStreamListenerPeer->OnStreamTypeSet(mStreamType);
-    }
-    ResumeRequest();
-  }
-  return true;
-}
-
 void
 nsNPAPIPluginStreamListener::SuspendRequest()
 {
   NS_ASSERTION(!mIsSuspended,
                "Suspending a request that's already suspended!");
 
   nsresult rv = StartDataPump();
   if (NS_FAILED(rv))
@@ -704,35 +653,17 @@ nsNPAPIPluginStreamListener::OnStopBindi
 
   NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE;
   if (mRedirectDenied || status == NS_BINDING_ABORTED) {
     reason = NPRES_USER_BREAK;
   }
 
   // The following code can result in the deletion of 'this'. Don't
   // assume we are alive after this!
-  //
-  // Delay cleanup if the stream is of type NP_SEEK and status isn't
-  // NS_BINDING_ABORTED (meaning the plugin hasn't called NPN_DestroyStream).
-  // This is because even though we're done delivering data the plugin may
-  // want to seek. Eventually either the plugin will call NPN_DestroyStream
-  // or we'll perform cleanup when the instance goes away. See bug 91140.
-  if (mStreamType != NP_SEEK ||
-      (NP_SEEK == mStreamType && NS_BINDING_ABORTED == status)) {
-    return CleanUpStream(reason);
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsNPAPIPluginStreamListener::GetStreamType(int32_t *result)
-{
-  *result = mStreamType;
-  return NS_OK;
+  return CleanUpStream(reason);
 }
 
 bool
 nsNPAPIPluginStreamListener::MaybeRunStopBinding()
 {
   if (mIsSuspended || mStreamStopMode != eStopPending) {
     return false;
   }
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.h
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.h
@@ -60,18 +60,16 @@ public:
   nsresult OnStartBinding(nsPluginStreamListenerPeer* streamPeer);
   nsresult OnDataAvailable(nsPluginStreamListenerPeer* streamPeer,
                            nsIInputStream* input,
                            uint32_t length);
   nsresult OnFileAvailable(nsPluginStreamListenerPeer* streamPeer,
                            const char* fileName);
   nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
                          nsresult status);
-  nsresult GetStreamType(int32_t *result);
-  bool SetStreamType(uint16_t aType, bool aNeedsResume = true);
 
   bool IsStarted();
   nsresult CleanUpStream(NPReason reason);
   void CallURLNotify(NPReason reason);
   void SetCallNotify(bool aCallNotify) { mCallNotify = aCallNotify; }
   void SuspendRequest();
   void ResumeRequest();
   nsresult StartDataPump();
@@ -107,17 +105,16 @@ protected:
   bool MaybeRunStopBinding();
 
   char* mStreamBuffer;
   char* mNotifyURL;
   RefPtr<nsNPAPIPluginInstance> mInst;
   nsNPAPIStreamWrapper *mNPStreamWrapper;
   uint32_t mStreamBufferSize;
   int32_t mStreamBufferByteCount;
-  int32_t mStreamType;
   StreamState mStreamState;
   bool mStreamCleanedUp;
   bool mCallNotify;
   bool mIsSuspended;
   bool mIsPluginInitJSStream;
   bool mRedirectDenied;
   nsCString mResponseHeaders;
   char* mResponseHeaderBuf;
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -15,297 +15,65 @@
 #include "nsMimeTypes.h"
 #include "nsISupportsPrimitives.h"
 #include "nsNetCID.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsPluginLogging.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsPluginHost.h"
-#include "nsIByteRangeRequest.h"
 #include "nsIMultiPartChannel.h"
 #include "nsIInputStreamTee.h"
 #include "nsPrintfCString.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocument.h"
 #include "nsIWebNavigation.h"
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsPluginNativeWindow.h"
 #include "GeckoProfiler.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsDataHashtable.h"
 #include "NullPrincipal.h"
 
-#define BYTERANGE_REQUEST_CONTEXT 0x01020304
-
-// nsPluginByteRangeStreamListener
-
-class nsPluginByteRangeStreamListener
-  : public nsIStreamListener
-  , public nsIInterfaceRequestor
-{
-public:
-  explicit nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIREQUESTOBSERVER
-  NS_DECL_NSISTREAMLISTENER
-  NS_DECL_NSIINTERFACEREQUESTOR
-
-private:
-  virtual ~nsPluginByteRangeStreamListener();
-
-  nsCOMPtr<nsIStreamListener> mStreamConverter;
-  nsWeakPtr mWeakPtrPluginStreamListenerPeer;
-  bool mRemoveByteRangeRequest;
-};
-
-NS_IMPL_ISUPPORTS(nsPluginByteRangeStreamListener,
-                  nsIRequestObserver,
-                  nsIStreamListener,
-                  nsIInterfaceRequestor)
-
-nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr)
-{
-  mWeakPtrPluginStreamListenerPeer = aWeakPtr;
-  mRemoveByteRangeRequest = false;
-}
-
-nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
-{
-  mStreamConverter = nullptr;
-  mWeakPtrPluginStreamListenerPeer = nullptr;
-}
-
-/**
- * Unwrap any byte-range requests so that we can check whether the base channel
- * is being tracked properly.
- */
-static nsCOMPtr<nsIRequest>
-GetBaseRequest(nsIRequest* r)
-{
-  nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(r);
-  if (!mp)
-    return r;
-
-  nsCOMPtr<nsIChannel> base;
-  mp->GetBaseChannel(getter_AddRefs(base));
-  return already_AddRefed<nsIRequest>(base.forget());
-}
-
-NS_IMETHODIMP
-nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
-  if (!finalStreamListener)
-    return NS_ERROR_FAILURE;
-
-  nsPluginStreamListenerPeer *pslp =
-    static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
-
-#ifdef DEBUG
-  nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
-#endif
-  NS_ASSERTION(pslp->mRequests.IndexOfObject(baseRequest) != -1,
-               "Untracked byte-range request?");
-
-  nsCOMPtr<nsIStreamConverterService> serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
-  if (NS_SUCCEEDED(rv)) {
-    rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
-                                "*/*",
-                                finalStreamListener,
-                                nullptr,
-                                getter_AddRefs(mStreamConverter));
-    if (NS_SUCCEEDED(rv)) {
-      rv = mStreamConverter->OnStartRequest(request, ctxt);
-      if (NS_SUCCEEDED(rv))
-        return rv;
-    }
-  }
-  mStreamConverter = nullptr;
-
-  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
-  if (!httpChannel) {
-    return NS_ERROR_FAILURE;
-  }
-
-  uint32_t responseCode = 0;
-  rv = httpChannel->GetResponseStatus(&responseCode);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (responseCode != 200) {
-    uint32_t wantsAllNetworkStreams = 0;
-    rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
-                                                       &wantsAllNetworkStreams);
-    // If the call returned an error code make sure we still use our default value.
-    if (NS_FAILED(rv)) {
-      wantsAllNetworkStreams = 0;
-    }
-
-    if (!wantsAllNetworkStreams){
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
-  // reset this seekable stream & try serve it to plugin instance as a file
-  mStreamConverter = finalStreamListener;
-  mRemoveByteRangeRequest = true;
-
-  rv = pslp->ServeStreamAsFile(request, ctxt);
-  return rv;
-}
-
-NS_IMETHODIMP
-nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
-                                               nsresult status)
-{
-  if (!mStreamConverter)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
-  if (!finalStreamListener)
-    return NS_ERROR_FAILURE;
-
-  nsPluginStreamListenerPeer *pslp =
-    static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
-  bool found = pslp->mRequests.RemoveObject(request);
-  if (!found) {
-    NS_ERROR("OnStopRequest received for untracked byte-range request!");
-  }
-
-  if (mRemoveByteRangeRequest) {
-    // remove byte range request from container
-    nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(ctxt);
-    if (container) {
-      uint32_t byteRangeRequest = 0;
-      container->GetData(&byteRangeRequest);
-      if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
-        // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
-        // set it to something that is not the byte range request.
-        container->SetData(0);
-      }
-    } else {
-      NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
-    }
-  }
-
-  return mStreamConverter->OnStopRequest(request, ctxt, status);
-}
-
-// CachedFileHolder
-
-CachedFileHolder::CachedFileHolder(nsIFile* cacheFile)
-: mFile(cacheFile)
-{
-  NS_ASSERTION(mFile, "Empty CachedFileHolder");
-}
-
-CachedFileHolder::~CachedFileHolder()
-{
-  mFile->Remove(false);
-}
-
-void
-CachedFileHolder::AddRef()
-{
-  ++mRefCnt;
-  NS_LOG_ADDREF(this, mRefCnt, "CachedFileHolder", sizeof(*this));
-}
-
-void
-CachedFileHolder::Release()
-{
-  --mRefCnt;
-  NS_LOG_RELEASE(this, mRefCnt, "CachedFileHolder");
-  if (0 == mRefCnt)
-    delete this;
-}
-
-
-NS_IMETHODIMP
-nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
-                                                 nsIInputStream *inStr,
-                                                 uint64_t sourceOffset,
-                                                 uint32_t count)
-{
-  if (!mStreamConverter)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
-  if (!finalStreamListener)
-    return NS_ERROR_FAILURE;
-
-  return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
-}
-
-NS_IMETHODIMP
-nsPluginByteRangeStreamListener::GetInterface(const nsIID& aIID, void** result)
-{
-  // Forward interface requests to our parent
-  nsCOMPtr<nsIInterfaceRequestor> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
-  if (!finalStreamListener)
-    return NS_ERROR_FAILURE;
-
-  return finalStreamListener->GetInterface(aIID, result);
-}
-
 // nsPluginStreamListenerPeer
 
 NS_IMPL_ISUPPORTS(nsPluginStreamListenerPeer,
                   nsIStreamListener,
                   nsIRequestObserver,
                   nsIHttpHeaderVisitor,
                   nsISupportsWeakReference,
                   nsIInterfaceRequestor,
                   nsIChannelEventSink)
 
 nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
 {
   mStreamType = NP_NORMAL;
   mStartBinding = false;
-  mAbort = false;
   mRequestFailed = false;
 
   mPendingRequests = 0;
   mHaveFiredOnStartRequest = false;
-  mDataForwardToRequest = nullptr;
 
   mUseLocalCache = false;
-  mSeekable = false;
   mModified = 0;
   mStreamOffset = 0;
   mStreamComplete = 0;
 }
 
 nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
 {
 #ifdef PLUGIN_LOGGING
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
          ("nsPluginStreamListenerPeer::dtor this=%p, url=%s\n",this, mURLSpec.get()));
 #endif
 
   if (mPStreamListener) {
     mPStreamListener->SetStreamListenerPeer(nullptr);
   }
-
-  // close FD of mFileCacheOutputStream if it's still open
-  // or we won't be able to remove the cache file
-  if (mFileCacheOutputStream)
-    mFileCacheOutputStream = nullptr;
-
-  delete mDataForwardToRequest;
-
-  if (mPluginInstance)
-    mPluginInstance->FileCachedStreamListeners()->RemoveElement(this);
 }
 
 // Called as a result of GetURL and PostURL, or by the host in the case of the
 // initial plugin stream.
 nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
                                                 nsNPAPIPluginInstance *aInstance,
                                                 nsNPAPIPluginStreamListener* aListener)
 {
@@ -333,110 +101,27 @@ nsresult nsPluginStreamListenerPeer::Ini
   // SetUpStreamListener
   if (aListener) {
     mPStreamListener = aListener;
     mPStreamListener->SetStreamListenerPeer(this);
   }
 
   mPendingRequests = 1;
 
-  mDataForwardToRequest = new nsDataHashtable<nsUint32HashKey, uint32_t>();
-
   return NS_OK;
 }
 
-// SetupPluginCacheFile is called if we have to save the stream to disk.
-//
-// These files will be deleted when the host is destroyed.
-//
-// TODO? What if we fill up the the dest dir?
-nsresult
-nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
-{
-  nsresult rv = NS_OK;
-
-  bool useExistingCacheFile = false;
-  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
-
-  // Look for an existing cache file for the URI.
-  nsTArray< RefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
-  for (uint32_t i = 0; i < instances->Length(); i++) {
-    // most recent streams are at the end of list
-    nsTArray<nsPluginStreamListenerPeer*> *streamListeners = instances->ElementAt(i)->FileCachedStreamListeners();
-    for (int32_t i = streamListeners->Length() - 1; i >= 0; --i) {
-      nsPluginStreamListenerPeer *lp = streamListeners->ElementAt(i);
-      if (lp && lp->mLocalCachedFileHolder) {
-        useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
-        if (useExistingCacheFile) {
-          mLocalCachedFileHolder = lp->mLocalCachedFileHolder;
-          break;
-        }
-      }
-      if (useExistingCacheFile)
-        break;
-    }
-  }
-
-  // Create a new cache file if one could not be found.
-  if (!useExistingCacheFile) {
-    nsCOMPtr<nsIFile> pluginTmp;
-    rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // Get the filename from the channel
-    nsCOMPtr<nsIURI> uri;
-    rv = channel->GetURI(getter_AddRefs(uri));
-    if (NS_FAILED(rv)) return rv;
-
-    nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
-    if (!url)
-      return NS_ERROR_FAILURE;
-
-    nsAutoCString filename;
-    url->GetFileName(filename);
-    if (NS_FAILED(rv))
-      return rv;
-
-    // Create a file to save our stream into. Should we scramble the name?
-    filename.InsertLiteral("plugin-", 0);
-    rv = pluginTmp->AppendNative(filename);
-    if (NS_FAILED(rv))
-      return rv;
-
-    // Yes, make it unique.
-    rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
-    if (NS_FAILED(rv))
-      return rv;
-
-    // create a file output stream to write to...
-    rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
-    if (NS_FAILED(rv))
-      return rv;
-
-    // save the file.
-    mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
-  }
-
-  // add this listenerPeer to list of stream peers for this instance
-  mPluginInstance->FileCachedStreamListeners()->AppendElement(this);
-
-  return rv;
-}
-
 NS_IMETHODIMP
 nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
                                            nsISupports* aContext)
 {
   nsresult rv = NS_OK;
   AUTO_PROFILER_LABEL("nsPluginStreamListenerPeer::OnStartRequest", OTHER);
 
-  nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
-  if (mRequests.IndexOfObject(baseRequest) == -1) {
+  if (mRequests.IndexOfObject(request) == -1) {
     NS_ASSERTION(mRequests.Count() == 0,
                  "Only our initial stream should be unknown!");
     TrackRequest(request);
   }
 
   if (mHaveFiredOnStartRequest) {
     return NS_OK;
   }
@@ -593,23 +278,16 @@ nsresult
 nsPluginStreamListenerPeer::GetContentType(char** result)
 {
   *result = const_cast<char*>(mContentType.get());
   return NS_OK;
 }
 
 
 nsresult
-nsPluginStreamListenerPeer::IsSeekable(bool* result)
-{
-  *result = mSeekable;
-  return NS_OK;
-}
-
-nsresult
 nsPluginStreamListenerPeer::GetLength(uint32_t* result)
 {
   *result = mLength;
   return NS_OK;
 }
 
 nsresult
 nsPluginStreamListenerPeer::GetLastModified(uint32_t* result)
@@ -620,51 +298,16 @@ nsPluginStreamListenerPeer::GetLastModif
 
 nsresult
 nsPluginStreamListenerPeer::GetURL(const char** result)
 {
   *result = mURLSpec.get();
   return NS_OK;
 }
 
-void
-nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
-                                                int32_t *numRequests)
-{
-  rangeRequest.Truncate();
-  *numRequests  = 0;
-  //the string should look like this: bytes=500-700,601-999
-  if (!aRangeList)
-    return;
-
-  int32_t requestCnt = 0;
-  nsAutoCString string("bytes=");
-
-  for (NPByteRange * range = aRangeList; range != nullptr; range = range->next) {
-    // XXX zero length?
-    if (!range->length)
-      continue;
-
-    // XXX needs to be fixed for negative offsets
-    string.AppendInt(range->offset);
-    string.Append('-');
-    string.AppendInt(range->offset + range->length - 1);
-    if (range->next)
-      string.Append(',');
-
-    requestCnt++;
-  }
-
-  // get rid of possible trailing comma
-  string.Trim(",", false);
-
-  rangeRequest = string;
-  *numRequests  = requestCnt;
-}
-
 // XXX: Converting the channel within nsPluginStreamListenerPeer
 // to use asyncOpen2() and do not want to touch the fragile logic
 // of byte range requests. Hence we just introduce this lightweight
 // wrapper to proxy the context.
 class PluginContextProxy final : public nsIStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
@@ -713,284 +356,66 @@ private:
   ~PluginContextProxy() {}
   nsCOMPtr<nsIStreamListener> mListener;
   nsCOMPtr<nsISupports> mContext;
 };
 
 NS_IMPL_ISUPPORTS(PluginContextProxy, nsIStreamListener)
 
 nsresult
-nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
-{
-  nsAutoCString rangeString;
-  int32_t numRequests;
-
-  MakeByteRangeString(rangeList, rangeString, &numRequests);
-
-  if (numRequests == 0)
-    return NS_ERROR_FAILURE;
-
-  nsresult rv = NS_OK;
-
-  RefPtr<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<nsIChannel> channel;
-  nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
-  if (requestingNode) {
-    rv = NS_NewChannel(getter_AddRefs(channel),
-                       mURL,
-                       requestingNode,
-                       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-                       nsIContentPolicy::TYPE_OTHER,
-                       loadGroup,
-                       callbacks,
-                       nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
-  }
-  else {
-    // In this else branch we really don't know where the load is coming
-    // from. Let's fall back to using the SystemPrincipal for such Plugins.
-    rv = NS_NewChannel(getter_AddRefs(channel),
-                       mURL,
-                       nsContentUtils::GetSystemPrincipal(),
-                       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-                       nsIContentPolicy::TYPE_OTHER,
-                       loadGroup,
-                       callbacks,
-                       nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
-  }
-
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
-  if (!httpChannel)
-    return NS_ERROR_FAILURE;
-
-  rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-
-  mAbort = true; // instruct old stream listener to cancel
-  // the request on the next ODA.
-
-  nsCOMPtr<nsIStreamListener> converter;
-
-  if (numRequests == 1) {
-    converter = this;
-    // set current stream offset equal to the first offset in the range list
-    // it will work for single byte range request
-    // for multy range we'll reset it in ODA
-    SetStreamOffset(rangeList->offset);
-  } else {
-    nsWeakPtr weakpeer =
-    do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
-    converter = new nsPluginByteRangeStreamListener(weakpeer);
-  }
-
-  mPendingRequests += numRequests;
-
-  nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = container->SetData(BYTERANGE_REQUEST_CONTEXT);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  RefPtr<PluginContextProxy> pluginContextProxy =
-    new PluginContextProxy(converter, container);
-  rv = channel->AsyncOpen2(pluginContextProxy);
-  NS_ENSURE_SUCCESS(rv, rv);
-  TrackRequest(channel);
-  return NS_OK;
-}
-
-nsresult
 nsPluginStreamListenerPeer::GetStreamOffset(int32_t* result)
 {
   *result = mStreamOffset;
   return NS_OK;
 }
 
 nsresult
 nsPluginStreamListenerPeer::SetStreamOffset(int32_t value)
 {
   mStreamOffset = value;
   return NS_OK;
 }
 
-nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
-                                                       nsISupports* aContext)
-{
-  if (!mPluginInstance)
-    return NS_ERROR_FAILURE;
-
-  // mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
-  mPluginInstance->Stop();
-  mPluginInstance->Start();
-  RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
-  if (owner) {
-    NPWindow* window = nullptr;
-    owner->GetWindow(window);
-#if (MOZ_WIDGET_GTK == 2)
-    // Should call GetPluginPort() here.
-    // This part is copied from nsPluginInstanceOwner::GetPluginPort().
-    nsCOMPtr<nsIWidget> widget;
-    ((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
-    if (widget) {
-      window->window = widget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
-    }
-#endif
-    owner->CallSetWindow();
-  }
-
-  mSeekable = false;
-  mPStreamListener->OnStartBinding(this);
-  mStreamOffset = 0;
-
-  // force the plugin to use stream as file
-  mStreamType = NP_ASFILE;
-
-  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
-  if (channel) {
-    SetupPluginCacheFile(channel);
-  }
-
-  // unset mPendingRequests
-  mPendingRequests = 0;
-
-  return NS_OK;
-}
-
-bool
-nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
-{
-  NS_ENSURE_TRUE(psi, false);
-
-  if (psi->mLength == mLength &&
-      psi->mModified == mModified &&
-      mStreamComplete &&
-      mURLSpec.Equals(psi->mURLSpec))
-  {
-    return true;
-  }
-  return false;
-}
-
 NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
                                                           nsISupports* aContext,
                                                           nsIInputStream *aIStream,
                                                           uint64_t sourceOffset,
                                                           uint32_t aLength)
 {
-  nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
-  if (mRequests.IndexOfObject(baseRequest) == -1) {
+  if (mRequests.IndexOfObject(request) == -1) {
     MOZ_ASSERT(false, "Received OnDataAvailable for untracked request.");
     return NS_ERROR_UNEXPECTED;
   }
 
   if (mRequestFailed)
     return NS_ERROR_FAILURE;
 
-  if (mAbort) {
-    uint32_t byteRangeRequest = 0;  // set it to something that is not the byte range request.
-    nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
-    if (container)
-      container->GetData(&byteRangeRequest);
-
-    if (byteRangeRequest != BYTERANGE_REQUEST_CONTEXT) {
-      // this is not one of our range requests
-      mAbort = false;
-      return NS_BINDING_ABORTED;
-    }
-  }
-
   nsresult rv = NS_OK;
 
   if (!mPStreamListener)
     return NS_ERROR_FAILURE;
 
   const char * url = nullptr;
   GetURL(&url);
 
   PLUGIN_LOG(PLUGIN_LOG_NOISY,
              ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%" PRIu64 ", length=%u, url=%s\n",
               this, request, sourceOffset, aLength, url ? url : "no url set"));
 
-  // if the plugin has requested an AsFileOnly stream, then don't
-  // call OnDataAvailable
-  if (mStreamType != NP_ASFILEONLY) {
-    // get the absolute offset of the request, if one exists.
-    nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
-    if (brr) {
-      if (!mDataForwardToRequest)
-        return NS_ERROR_FAILURE;
-
-      int64_t absoluteOffset64 = 0;
-      brr->GetStartRange(&absoluteOffset64);
-
-      // XXX handle 64-bit for real
-      int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
-
-      // we need to track how much data we have forwarded to the
-      // plugin.
-
-      // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
-      //
-      // Why couldn't this be tracked on the plugin info, and not in a
-      // *hash table*?
-      int32_t amtForwardToPlugin = mDataForwardToRequest->Get(absoluteOffset);
-      mDataForwardToRequest->Put(absoluteOffset, (amtForwardToPlugin + aLength));
-
-      SetStreamOffset(absoluteOffset + amtForwardToPlugin);
-    }
-
-    nsCOMPtr<nsIInputStream> stream = aIStream;
+  nsCOMPtr<nsIInputStream> stream = aIStream;
+  rv = mPStreamListener->OnDataAvailable(this,
+                                         stream,
+                                         aLength);
 
-    // if we are caching the file ourselves to disk, we want to 'tee' off
-    // the data as the plugin read from the stream.  We do this by the magic
-    // of an input stream tee.
-
-    if (mFileCacheOutputStream) {
-      rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
-      if (NS_FAILED(rv))
-        return rv;
-    }
-
-    rv =  mPStreamListener->OnDataAvailable(this,
-                                            stream,
-                                            aLength);
+  // if a plugin returns an error, the peer must kill the stream
+  //   else the stream and PluginStreamListener leak
+  if (NS_FAILED(rv)) {
+    request->Cancel(rv);
+  }
 
-    // if a plugin returns an error, the peer must kill the stream
-    //   else the stream and PluginStreamListener leak
-    if (NS_FAILED(rv))
-      request->Cancel(rv);
-  }
-  else
-  {
-    // if we don't read from the stream, OnStopRequest will never be called
-    char* buffer = new char[aLength];
-    uint32_t amountRead, amountWrote = 0;
-    rv = aIStream->Read(buffer, aLength, &amountRead);
-
-    // if we are caching this to disk ourselves, lets write the bytes out.
-    if (mFileCacheOutputStream) {
-      while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
-        rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
-      }
-    }
-    delete [] buffer;
-  }
   return rv;
 }
 
 NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
                                                         nsISupports* aContext,
                                                         nsresult aStatus)
 {
   nsresult rv = NS_OK;
@@ -1002,53 +427,20 @@ NS_IMETHODIMP nsPluginStreamListenerPeer
       NS_ERROR("Received OnStopRequest for untracked request.");
     }
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NOISY,
              ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%" PRIu32 " request=%p\n",
               this, static_cast<uint32_t>(aStatus), request));
 
-  // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
-  nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
-  if (brr) {
-    int64_t absoluteOffset64 = 0;
-    brr->GetStartRange(&absoluteOffset64);
-    // XXX support 64-bit offsets
-    int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
-
-    // remove the request from our data forwarding count hash.
-    mDataForwardToRequest->Remove(absoluteOffset);
-
-
-    PLUGIN_LOG(PLUGIN_LOG_NOISY,
-               ("                          ::OnStopRequest for ByteRangeRequest Started=%d\n",
-                absoluteOffset));
-  } else {
-    // if this is not byte range request and
-    // if we are writting the stream to disk ourselves,
-    // close & tear it down here
-    mFileCacheOutputStream = nullptr;
-  }
-
   // if we still have pending stuff to do, lets not close the plugin socket.
   if (--mPendingRequests > 0)
     return NS_OK;
 
-  // we keep our connections around...
-  nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
-  if (container) {
-    uint32_t byteRangeRequest = 0;  // something other than the byte range request.
-    container->GetData(&byteRangeRequest);
-    if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
-      // this is one of our range requests
-      return NS_OK;
-    }
-  }
-
   if (!mPStreamListener)
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
   if (!channel)
     return NS_ERROR_FAILURE;
   // Set the content type to ensure we don't pass null to the plugin
   nsAutoCString aContentType;
@@ -1065,34 +457,16 @@ NS_IMETHODIMP nsPluginStreamListenerPeer
 
   if (NS_FAILED(aStatus)) {
     // on error status cleanup the stream
     // and return w/o OnFileAvailable()
     mPStreamListener->OnStopBinding(this, aStatus);
     return NS_OK;
   }
 
-  // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
-  if (mStreamType >= NP_ASFILE) {
-    nsCOMPtr<nsIFile> localFile;
-    if (mLocalCachedFileHolder)
-      localFile = mLocalCachedFileHolder->file();
-    else {
-      // see if it is a file channel.
-      nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
-      if (fileChannel) {
-        fileChannel->GetFile(getter_AddRefs(localFile));
-      }
-    }
-
-    if (localFile) {
-      OnFileAvailable(localFile);
-    }
-  }
-
   if (mStartBinding) {
     // On start binding has been called
     mPStreamListener->OnStopBinding(this, aStatus);
   } else {
     // OnStartBinding hasn't been called, so complete the action.
     mPStreamListener->OnStartBinding(this);
     mPStreamListener->OnStopBinding(this, aStatus);
   }
@@ -1171,42 +545,16 @@ nsresult nsPluginStreamListenerPeer::Set
                              statusText.get());
       static_cast<nsIHTTPHeaderListener*>(mPStreamListener)->StatusLine(status.get());
     }
 
     // Also provide all HTTP response headers to our listener.
     rv = httpChannel->VisitResponseHeaders(this);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-    mSeekable = false;
-    // first we look for a content-encoding header. If we find one, we tell the
-    // plugin that stream is not seekable, because the plugin always sees
-    // uncompressed data, so it can't make meaningful range requests on a
-    // compressed entity.  Also, we force the plugin to use
-    // nsPluginStreamType_AsFile stream type and we have to save decompressed
-    // file into local plugin cache, because necko cache contains original
-    // compressed file.
-    nsAutoCString contentEncoding;
-    if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
-                                                    contentEncoding))) {
-      mUseLocalCache = true;
-    } else {
-      // set seekability (seekable if the stream has a known length and if the
-      // http server accepts byte ranges).
-      uint32_t length;
-      GetLength(&length);
-      if (length) {
-        nsAutoCString range;
-        if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
-            range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
-          mSeekable = true;
-        }
-      }
-    }
-
     // we require a content len
     // get Last-Modified header for plugin info
     nsAutoCString lastModified;
     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), lastModified)) &&
         !lastModified.IsEmpty()) {
       PRTime time64;
       PR_ParseTimeString(lastModified.get(), true, &time64);  //convert string time to integer time
 
@@ -1221,66 +569,19 @@ nsresult nsPluginStreamListenerPeer::Set
 
   rv = mPStreamListener->OnStartBinding(this);
 
   mStartBinding = true;
 
   if (NS_FAILED(rv))
     return rv;
 
-  int32_t streamType = NP_NORMAL;
-  mPStreamListener->GetStreamType(&streamType);
-
-  if (streamType != STREAM_TYPE_UNKNOWN) {
-    OnStreamTypeSet(streamType);
-  }
-
   return NS_OK;
 }
 
-void
-nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
-{
-  MOZ_ASSERT(aStreamType != STREAM_TYPE_UNKNOWN);
-  MOZ_ASSERT(mRequest);
-  mStreamType = aStreamType;
-  if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
-    // check it out if this is not a file channel.
-    nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
-    if (!fileChannel) {
-      mUseLocalCache = true;
-    }
-  }
-
-  if (mUseLocalCache) {
-    nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
-    SetupPluginCacheFile(channel);
-  }
-}
-
-nsresult
-nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
-{
-  nsresult rv;
-  if (!mPStreamListener)
-    return NS_ERROR_FAILURE;
-
-  nsAutoCString path;
-  rv = aFile->GetNativePath(path);
-  if (NS_FAILED(rv)) return rv;
-
-  if (path.IsEmpty()) {
-    NS_WARNING("empty path");
-    return NS_OK;
-  }
-
-  rv = mPStreamListener->OnFileAvailable(this, path.get());
-  return rv;
-}
-
 NS_IMETHODIMP
 nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
 {
   return mPStreamListener->NewResponseHeader(PromiseFlatCString(header).get(),
                                              PromiseFlatCString(value).get());
 }
 
 nsresult
--- a/dom/plugins/base/nsPluginStreamListenerPeer.h
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.h
@@ -58,39 +58,27 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIHTTPHEADERVISITOR
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSICHANNELEVENTSINK
 
-  // Called by RequestRead
-  void
-  MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, int32_t *numRequests);
-
-  bool UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi);
-
   // Called by GetURL and PostURL (via NewStream) or by the host in the case of
   // the initial plugin stream.
   nsresult Initialize(nsIURI *aURL,
                       nsNPAPIPluginInstance *aInstance,
                       nsNPAPIPluginStreamListener *aListener);
 
-  nsresult OnFileAvailable(nsIFile* aFile);
-
-  nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
-
   nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; }
 
-  nsresult RequestRead(NPByteRange* rangeList);
   nsresult GetLength(uint32_t* result);
   nsresult GetURL(const char** result);
   nsresult GetLastModified(uint32_t* result);
-  nsresult IsSeekable(bool* result);
   nsresult GetContentType(char** result);
   nsresult GetStreamOffset(int32_t* result);
   nsresult SetStreamOffset(int32_t value);
 
   void TrackRequest(nsIRequest* request)
   {
     mRequests.AppendObject(request);
   }
@@ -123,26 +111,18 @@ public:
   }
 
   void ResumeRequests() {
     nsCOMArray<nsIRequest> requestsCopy(mRequests);
     for (int32_t i = 0; i < requestsCopy.Count(); ++i)
       requestsCopy[i]->Resume();
   }
 
-  // Called by nsNPAPIPluginStreamListener
-  void OnStreamTypeSet(const int32_t aStreamType);
-
-  enum {
-    STREAM_TYPE_UNKNOWN = UINT16_MAX
-  };
-
 private:
   nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
-  nsresult SetupPluginCacheFile(nsIChannel* channel);
   nsresult GetInterfaceGlobal(const nsIID& aIID, void** result);
 
   nsCOMPtr<nsIURI> mURL;
   nsCString mURLSpec; // Have to keep this member because GetURL hands out char*
   RefPtr<nsNPAPIPluginStreamListener> mPStreamListener;
 
   // Set to true if we request failed (like with a HTTP response of 404)
   bool                    mRequestFailed;
@@ -154,32 +134,24 @@ private:
    * been called.
    */
   bool              mStartBinding;
   bool              mHaveFiredOnStartRequest;
   // these get passed to the plugin stream listener
   uint32_t                mLength;
   int32_t                 mStreamType;
 
-  // local cached file, we save the content into local cache if browser cache is not available,
-  // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
-  RefPtr<CachedFileHolder> mLocalCachedFileHolder;
-  nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
-  nsDataHashtable<nsUint32HashKey, uint32_t>* mDataForwardToRequest;
-
   nsCString mContentType;
   bool mUseLocalCache;
   nsCOMPtr<nsIRequest> mRequest;
-  bool mSeekable;
   uint32_t mModified;
   RefPtr<nsNPAPIPluginInstance> mPluginInstance;
   int32_t mStreamOffset;
   bool mStreamComplete;
 
 public:
-  bool                    mAbort;
   int32_t                 mPendingRequests;
   nsWeakPtr               mWeakPtrChannelCallbacks;
   nsWeakPtr               mWeakPtrChannelLoadGroup;
   nsCOMArray<nsIRequest> mRequests;
 };
 
 #endif // nsPluginStreamListenerPeer_h_
--- a/dom/plugins/ipc/BrowserStreamChild.cpp
+++ b/dom/plugins/ipc/BrowserStreamChild.cpp
@@ -17,17 +17,16 @@ BrowserStreamChild::BrowserStreamChild(P
                                        const uint32_t& length,
                                        const uint32_t& lastmodified,
                                        StreamNotifyChild* notifyData,
                                        const nsCString& headers)
   : mInstance(instance)
   , mStreamStatus(kStreamOpen)
   , mDestroyPending(NOT_DESTROYED)
   , mNotifyPending(false)
-  , mStreamAsFilePending(false)
   , mInstanceDying(false)
   , mState(CONSTRUCTING)
   , mURL(url)
   , mHeaders(headers)
   , mStreamNotify(notifyData)
   , mDeliveryTracker(this)
 {
   PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s)", FULLFUNCTION,
@@ -55,16 +54,25 @@ BrowserStreamChild::StreamConstructed(
             uint16_t* stype)
 {
   NPError rv = NPERR_NO_ERROR;
 
   *stype = NP_NORMAL;
   rv = mInstance->mPluginIface->newstream(
     &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
     &mStream, seekable, stype);
+
+  // NP_NORMAL is the only permissible stream type
+  if (*stype != NP_NORMAL) {
+    rv = NPERR_INVALID_PARAM;
+    // The plugin thinks the stream is alive, so we kill it explicitly
+    (void) mInstance->mPluginIface
+      ->destroystream(&mInstance->mData, &mStream, NPRES_NETWORK_ERR);
+  }
+
   if (rv != NPERR_NO_ERROR) {
     mState = DELETING;
     if (mStreamNotify) {
       mStreamNotify->SetAssociatedStream(nullptr);
       mStreamNotify = nullptr;
     }
   }
   else {
@@ -104,36 +112,16 @@ BrowserStreamChild::RecvWrite(const int3
   newdata->curpos = 0;
 
   EnsureDeliveryPending();
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-BrowserStreamChild::RecvNPP_StreamAsFile(const nsCString& fname)
-{
-  PLUGIN_LOG_DEBUG(("%s (fname=%s)", FULLFUNCTION, fname.get()));
-
-  AssertPluginThread();
-
-  if (ALIVE != mState)
-    MOZ_CRASH("Unexpected state: received file after NPP_DestroyStream?");
-
-  if (kStreamOpen != mStreamStatus)
-    return IPC_OK();
-
-  mStreamAsFilePending = true;
-  mStreamAsFileName = fname;
-  EnsureDeliveryPending();
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 BrowserStreamChild::RecvNPP_DestroyStream(const NPReason& reason)
 {
   PLUGIN_LOG_DEBUG_METHOD;
 
   if (ALIVE != mState)
     MOZ_CRASH("Unexpected state: recevied NPP_DestroyStream twice?");
 
   mState = DYING;
@@ -151,37 +139,16 @@ BrowserStreamChild::Recv__delete__()
   AssertPluginThread();
 
   if (DELETING != mState)
     MOZ_CRASH("Bad state, not DELETING");
 
   return IPC_OK();
 }
 
-NPError
-BrowserStreamChild::NPN_RequestRead(NPByteRange* aRangeList)
-{
-  PLUGIN_LOG_DEBUG_FUNCTION;
-
-  AssertPluginThread();
-
-  if (ALIVE != mState || kStreamOpen != mStreamStatus)
-    return NPERR_GENERIC_ERROR;
-
-  IPCByteRanges ranges;
-  for (; aRangeList; aRangeList = aRangeList->next) {
-    IPCByteRange br = {aRangeList->offset, aRangeList->length};
-    ranges.AppendElement(br);
-  }
-
-  NPError result;
-  CallNPN_RequestRead(ranges, &result);
-  return result;
-}
-
 void
 BrowserStreamChild::EnsureDeliveryPending()
 {
   MessageLoop::current()->PostTask(
     mDeliveryTracker.NewRunnableMethod(&BrowserStreamChild::Deliver));
 }
 
 void
@@ -194,30 +161,16 @@ BrowserStreamChild::Deliver()
     }
   }
   ClearSuspendedTimer();
 
   NS_ASSERTION(kStreamOpen != mStreamStatus || 0 == mPendingData.Length(),
                "Exit out of the data-delivery loop with pending data");
   mPendingData.Clear();
 
-  // NPP_StreamAsFile() is documented (at MDN) to be called "when the stream
-  // is complete" -- i.e. after all calls to NPP_WriteReady() and NPP_Write()
-  // have finished.  We make these calls asynchronously (from
-  // DeliverPendingData()).  So we need to make sure all the "pending data"
-  // has been "delivered" before calling NPP_StreamAsFile() (also
-  // asynchronously).  Doing this resolves bug 687610, bug 670036 and possibly
-  // also other bugs.
-  if (mStreamAsFilePending) {
-    if (mStreamStatus == kStreamOpen)
-      mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
-                                      mStreamAsFileName.get());
-    mStreamAsFilePending = false;
-  }
-
   if (DESTROY_PENDING == mDestroyPending) {
     mDestroyPending = DESTROYED;
     if (mState != DYING)
       MOZ_CRASH("mDestroyPending but state not DYING");
 
     NS_ASSERTION(NPRES_DONE != mStreamStatus, "Success status set too early!");
     if (kStreamOpen == mStreamStatus)
       mStreamStatus = NPRES_DONE;
--- a/dom/plugins/ipc/BrowserStreamChild.h
+++ b/dom/plugins/ipc/BrowserStreamChild.h
@@ -33,33 +33,30 @@ public:
   NPError StreamConstructed(
             const nsCString& mimeType,
             const bool& seekable,
             uint16_t* stype);
 
   virtual mozilla::ipc::IPCResult RecvWrite(const int32_t& offset,
                                             const uint32_t& newsize,
                                             const Buffer& data) override;
-  virtual mozilla::ipc::IPCResult RecvNPP_StreamAsFile(const nsCString& fname) override;
   virtual mozilla::ipc::IPCResult RecvNPP_DestroyStream(const NPReason& reason) override;
   virtual mozilla::ipc::IPCResult Recv__delete__() override;
 
   void EnsureCorrectInstance(PluginInstanceChild* i)
   {
     if (i != mInstance)
       MOZ_CRASH("Incorrect stream instance");
   }
   void EnsureCorrectStream(NPStream* s)
   {
     if (s != &mStream)
       MOZ_CRASH("Incorrect stream data");
   }
 
-  NPError NPN_RequestRead(NPByteRange* aRangeList);
-
   void NotifyPending() {
     NS_ASSERTION(!mNotifyPending, "Pending twice?");
     mNotifyPending = true;
     EnsureDeliveryPending();
   }
 
   /**
    * During instance destruction, artificially cancel all outstanding streams.
@@ -125,18 +122,16 @@ private:
    * all data has been delivered.
    */
   enum {
     NOT_DESTROYED, // NPP_DestroyStream not yet received
     DESTROY_PENDING, // NPP_DestroyStream received, not yet delivered
     DESTROYED // NPP_DestroyStream delivered, NPP_URLNotify may still be pending
   } mDestroyPending;
   bool mNotifyPending;
-  bool mStreamAsFilePending;
-  nsCString mStreamAsFileName;
 
   // When NPP_Destroy is called for our instance (manager), this flag is set
   // cancels the stream and avoids sending StreamDestroyed.
   bool mInstanceDying;
 
   enum {
     CONSTRUCTING,
     ALIVE,
--- a/dom/plugins/ipc/BrowserStreamParent.cpp
+++ b/dom/plugins/ipc/BrowserStreamParent.cpp
@@ -38,58 +38,16 @@ BrowserStreamParent::~BrowserStreamParen
 }
 
 void
 BrowserStreamParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Implement me! Bug 1005159
 }
 
-mozilla::ipc::IPCResult
-BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges,
-                                           NPError* result)
-{
-  PLUGIN_LOG_DEBUG_FUNCTION;
-
-  switch (mState) {
-  case INITIALIZING:
-    NS_ERROR("Requesting a read before initialization has completed");
-    *result = NPERR_GENERIC_ERROR;
-    return IPC_FAIL_NO_REASON(this);
-
-  case ALIVE:
-    break;
-
-  case DYING:
-    *result = NPERR_GENERIC_ERROR;
-    return IPC_OK();
-
-  default:
-    NS_ERROR("Unexpected state");
-    return IPC_FAIL_NO_REASON(this);
-  }
-
-  if (!mStream)
-    return IPC_FAIL_NO_REASON(this);
-
-  if (ranges.Length() > INT32_MAX)
-    return IPC_FAIL_NO_REASON(this);
-
-  UniquePtr<NPByteRange[]> rp(new NPByteRange[ranges.Length()]);
-  for (uint32_t i = 0; i < ranges.Length(); ++i) {
-    rp[i].offset = ranges[i].offset;
-    rp[i].length = ranges[i].length;
-    rp[i].next = &rp[i + 1];
-  }
-  rp[ranges.Length() - 1].next = nullptr;
-
-  *result = mNPP->mNPNIface->requestread(mStream, rp.get());
-  return IPC_OK();
-}
-
 void
 BrowserStreamParent::NPP_DestroyStream(NPReason reason)
 {
   NS_ASSERTION(ALIVE == mState || INITIALIZING == mState,
                "NPP_DestroyStream called twice?");
   bool stillInitializing = INITIALIZING == mState;
   if (stillInitializing) {
     mState = DEFERRING_DESTROY;
@@ -140,29 +98,10 @@ BrowserStreamParent::Write(int32_t offse
     len = kSendDataChunk;
 
   return SendWrite(offset,
                    mStream->end,
                    nsCString(static_cast<char*>(buffer), len)) ?
     len : -1;
 }
 
-void
-BrowserStreamParent::StreamAsFile(const char* fname)
-{
-  PLUGIN_LOG_DEBUG_FUNCTION;
-
-  NS_ASSERTION(ALIVE == mState,
-               "Calling streamasfile after NPP_DestroyStream?");
-
-  // Make sure our stream survives until the plugin process tells us we've
-  // been destroyed (until RecvStreamDestroyed() is called).  Since we retain
-  // mStreamPeer at most once, we won't get in trouble if StreamAsFile() is
-  // called more than once.
-  if (!mStreamPeer) {
-    nsNPAPIPlugin::RetainStream(mStream, getter_AddRefs(mStreamPeer));
-  }
-
-  Unused << SendNPP_StreamAsFile(nsCString(fname));
-}
-
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/ipc/BrowserStreamParent.h
+++ b/dom/plugins/ipc/BrowserStreamParent.h
@@ -25,24 +25,20 @@ public:
   BrowserStreamParent(PluginInstanceParent* npp,
                       NPStream* stream);
   virtual ~BrowserStreamParent();
 
   virtual bool IsBrowserStream() override { return true; }
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
-  virtual mozilla::ipc::IPCResult AnswerNPN_RequestRead(const IPCByteRanges& ranges,
-                                                        NPError* result) override;
-
   virtual mozilla::ipc::IPCResult RecvStreamDestroyed() override;
 
   int32_t WriteReady();
   int32_t Write(int32_t offset, int32_t len, void* buffer);
-  void StreamAsFile(const char* fname);
 
   void NPP_DestroyStream(NPReason reason);
 
   void SetAlive()
   {
     if (mState == INITIALIZING) {
       mState = ALIVE;
     }
--- a/dom/plugins/ipc/PBrowserStream.ipdl
+++ b/dom/plugins/ipc/PBrowserStream.ipdl
@@ -21,47 +21,22 @@ namespace plugins {
 
 intr protocol PBrowserStream
 {
   manager PPluginInstance;
 
 child:
   async Write(int32_t offset, uint32_t newlength,
               Buffer data);
-  async NPP_StreamAsFile(nsCString fname);
 
   /**
    * NPP_DestroyStream may race with other messages: the child acknowledges
    * the message with StreamDestroyed before this actor is deleted.
    */
   async NPP_DestroyStream(NPReason reason);
   async __delete__();
 
 parent:
-  intr NPN_RequestRead(IPCByteRanges ranges)
-    returns (NPError result);
   async StreamDestroyed();
-
-/*
-  TODO: turn on state machine.
-
-  // need configurable start state: if the constructor
-  // returns an error in result, start state should
-  // be DELETING.
-start state ALIVE:
-  send Write goto ALIVE;
-  call NPP_StreamAsFile goto ALIVE;
-  send NPP_DestroyStream goto ALIVE;
-  answer NPN_RequestRead goto ALIVE;
-  recv NPN_DestroyStream goto DYING;
-
-state DYING:
-  answer NPN_RequestRead goto DYING;
-  recv NPN_DestroyStream goto DYING;
-  recv StreamDestroyed goto DELETING;
-
-state DELETING:
-  send __delete__;
-*/
 };
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1040,23 +1040,17 @@ InstCast(NPP aNPP)
 namespace mozilla {
 namespace plugins {
 namespace child {
 
 NPError
 _requestread(NPStream* aStream,
              NPByteRange* aRangeList)
 {
-    PLUGIN_LOG_DEBUG_FUNCTION;
-    ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
-
-    BrowserStreamChild* bs =
-        static_cast<BrowserStreamChild*>(static_cast<AStream*>(aStream->ndata));
-    bs->EnsureCorrectStream(aStream);
-    return bs->NPN_RequestRead(aRangeList);
+    return NPERR_STREAM_NOT_SEEKABLE;
 }
 
 NPError
 _geturlnotify(NPP aNPP,
               const char* aRelativeURL,
               const char* aTarget,
               void* aNotifyData)
 {
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1693,17 +1693,16 @@ PluginModuleParent::SetPluginFuncs(NPPlu
     aFuncs->newp = nullptr;
     aFuncs->clearsitedata = nullptr;
     aFuncs->getsiteswithdata = nullptr;
 
     aFuncs->destroy = NPP_Destroy;
     aFuncs->setwindow = NPP_SetWindow;
     aFuncs->newstream = NPP_NewStream;
     aFuncs->destroystream = NPP_DestroyStream;
-    aFuncs->asfile = NPP_StreamAsFile;
     aFuncs->writeready = NPP_WriteReady;
     aFuncs->write = NPP_Write;
     aFuncs->print = NPP_Print;
     aFuncs->event = NPP_HandleEvent;
     aFuncs->urlnotify = NPP_URLNotify;
     aFuncs->getvalue = NPP_GetValue;
     aFuncs->setvalue = NPP_SetValue;
     aFuncs->gotfocus = nullptr;
@@ -1789,28 +1788,16 @@ PluginModuleParent::NPP_Write(NPP instan
     BrowserStreamParent* s = StreamCast(instance, stream);
     if (!s)
         return -1;
 
     return s->Write(offset, len, buffer);
 }
 
 void
-PluginModuleParent::NPP_StreamAsFile(NPP instance,
-                                     NPStream* stream,
-                                     const char* fname)
-{
-    BrowserStreamParent* s = StreamCast(instance, stream);
-    if (!s)
-        return;
-
-    s->StreamAsFile(fname);
-}
-
-void
 PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint)
 {
 
     PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
     return pip ? pip->NPP_Print(platformPrint) : (void)0;
 }
 
 int16_t
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -217,18 +217,16 @@ protected:
     static NPError NPP_SetWindow(NPP instance, NPWindow* window);
     static NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
                                  NPBool seekable, uint16_t* stype);
     static NPError NPP_DestroyStream(NPP instance,
                                      NPStream* stream, NPReason reason);
     static int32_t NPP_WriteReady(NPP instance, NPStream* stream);
     static int32_t NPP_Write(NPP instance, NPStream* stream,
                              int32_t offset, int32_t len, void* buffer);
-    static void NPP_StreamAsFile(NPP instance,
-                                 NPStream* stream, const char* fname);
     static void NPP_Print(NPP instance, NPPrint* platformPrint);
     static int16_t NPP_HandleEvent(NPP instance, void* event);
     static void NPP_URLNotify(NPP instance, const char* url,
                               NPReason reason, void* notifyData);
     static NPError NPP_GetValue(NPP instance,
                                 NPPVariable variable, void *ret_value);
     static NPError NPP_SetValue(NPP instance, NPNVariable variable,
                                 void *value);
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -106,18 +106,16 @@ skip-if = !crashreporter || e10s
 skip-if = toolkit == 'android' # needs plugin support
 [test_painting.html]
 skip-if = (toolkit == "cocoa" && e10s) # bug 1252230
 [test_plugin_scroll_invalidation.html]
 skip-if = toolkit != "gtk2"
 support-files = plugin_scroll_invalidation.html
 [test_plugin_scroll_painting.html]
 skip-if = true # Bug 596491
-[test_pluginstream_asfile.html]
-[test_pluginstream_asfileonly.html]
 [test_pluginstream_err.html]
 [test_pluginstream_geturl.html]
 skip-if = true # Bug 1267432
 [test_pluginstream_geturlnotify.html]
 skip-if = true # Bug 1267432
 [test_pluginstream_post.html]
 [test_pluginstream_poststream.html]
 [test_pluginstream_referer.html]
@@ -135,17 +133,16 @@ skip-if = (toolkit != "cocoa") || (os !=
 [test_redirect_handling.html]
 [test_refresh_navigator_plugins.html]
 skip-if = e10s # Bug 1090576
 [test_secondPlugin.html]
 [test_src_url_change.html]
 [test_streamatclose.html]
 [test_streamNotify.html]
 [test_stringHandling.html]
-[test_twostreams.html]
 [test_visibility.html]
 skip-if = toolkit == "cocoa"
 [test_windowed_invalidate.html]
 skip-if = os != "win"
 [test_windowless_flash.html]
 skip-if = !(os == "win" && processor == "x86_64")
 [test_windowless_ime.html]
 skip-if = os != "win"
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_pluginstream_asfile.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<html>
-<head>
-  <title>NPAPI NP_ASFILE NPStream Test</title>
-  <script type="text/javascript" 
-          src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" 
-          src="pluginstream.js"></script>
-  <script type="text/javascript" src="plugin-utils.js"></script>
-  <script type="text/javascript">
-    setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
-  </script>
-  <link rel="stylesheet" type="text/css" 
-        href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-  <p id="display"></p>
-
-  <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
-
-  <!--
-   - Similar to the above tests, but NPP_NewStream sets the stream mode
-   - to NP_ASFILE.  In this test, stream data is written in a series of
-   - NPP_Write calls, as per NP_NORMAL, and also written to a file whose
-   - path is passed to NPP_StreamAsFile.  The plugin compares the file
-   - and the stream to verify they're indentical, then passes the stream
-   - back to the browser via NPN_GetURL as above.
-   -->
-  <embed src="loremipsum_file.txt" streammode="asfile"
-         frame="testframe"
-         id="embedtest" style="width: 400px; height: 100px;"
-         type="application/x-test"></embed>
- </body>
- </html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_pluginstream_asfileonly.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<html>
-<head>
-  <title>NPAPI NP_ASFILEONLY NPStream Test</title>
-  <script type="text/javascript" 
-          src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" 
-          src="pluginstream.js"></script>
-  <script type="text/javascript" src="plugin-utils.js"></script>
-  <script type="text/javascript">
-    setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
-  </script>
-  <link rel="stylesheet" type="text/css" 
-        href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-  <p id="display"></p>
-
-  <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
-
-  <!--
-   - Similar to above, but NPP_NewStream sets to the stream mode
-   - to NP_ASFILEONLY, so the entire stream is written to a file
-   - and the file is read by the plugin when NPP_StreamAsFile is called.
-   -->
-  <embed src="loremipsum_file.txt" streammode="asfileonly"
-         frame="testframe"
-         id="embedtest" style="width: 400px; height: 100px;"
-         type="application/x-test"></embed>
- </body>
- </html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_twostreams.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<html>
-<head>
-  <title>Dual NPAPI NP_ASFILEONLY NPStream Test</title>
-  <script type="text/javascript" 
-          src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="plugin-utils.js"></script>
-  <link rel="stylesheet" type="text/css" 
-        href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-  <p id="display"></p>
-
-  <script type="text/javascript">
-  SimpleTest.expectAssertions(0, 2);
-
-  SimpleTest.waitForExplicitFinish();
-  setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
-
-  var framesToLoad = 2;
-  function frameLoaded(id) {
-    var frame = document.getElementById('testframe' + id);
-    // We have to use SpecialPowers because nptest.cpp prepends
-    // data: whichs makes the frame cross origin with the including page.
-    var wrappedDoc = SpecialPowers.wrap(frame).contentDocument;
-
-    if (!wrappedDoc.body.innerHTML.length)
-      return;
-
-    --framesToLoad;
-    if (0 == framesToLoad) {
-      var frame1 = document.getElementById('testframe1');
-      var frame2 = document.getElementById('testframe2');
-      var wrappedDocFrame1 = SpecialPowers.wrap(frame1).contentDocument;
-      var wrappedDocFrame2 = SpecialPowers.wrap(frame2).contentDocument;
-
-      is(wrappedDocFrame1.body.innerHTML, wrappedDocFrame2.body.innerHTML,
-         "Frame contents should match");
-      SimpleTest.finish();
-    }
-  }
-  </script>
-
-  <iframe id="testframe1" name="testframe1" onload="frameLoaded(1)"></iframe>
-  <iframe id="testframe2" name="testframe2" onload="frameLoaded(2)"></iframe>
-
-  <embed src="loremipsum_nocache.txt" streammode="asfileonly"
-         frame="testframe1"
-         id="embedtest" style="width: 400px; height: 100px;"
-         type="application/x-test"></embed>
-  <embed src="loremipsum_nocache.txt" streammode="asfileonly"
-	 frame="testframe2"
-	 id="embedtest2" style="width: 400px; height: 100px;"
-	 type="application/x-test"></embed>
-
--- a/dom/plugins/test/testplugin/README
+++ b/dom/plugins/test/testplugin/README
@@ -297,20 +297,16 @@ is specified) send the data from that st
 stream, whereupon it will be displayed in the specified frame.  If some
 error occurs during stream processing, an error message will appear in the
 frame instead of the stream data. If no "frame" attribute is present, a 
 stream can still be received by the plugin, but the plugin will do nothing
 with it.
 
 The attributes which control stream tests are:
 
-"streammode": one of "normal", "asfile", "asfileonly", "seek". Sets the
-  stream mode to the specified mode in any call to NPP_NewStream.
-  Defaults to "asfileonly".
-
 "streamchunksize": the number of bytes the plugin reports it can accept
   in calls to NPP_WriteReady.  Defaults to 1,024.
 
 "src": a url.  If specified, the browser will call NPP_NewStream for
   this url as soon as the plugin is initialized.
 
 "geturl": a url.  If specified, the plugin will request this url
   from the browser when the plugin is initialized, via a call to
@@ -328,25 +324,16 @@ The attributes which control stream test
   element which instantiated the plugin. For any of the preceding three
   attributes, a stream is received by the plugin via calls to NPP_NewStream,
   NPP_WriteReady, NPP_Write, and NPP_DestroyStream.  When NPP_DestroyStream
   is called (or NPP_UrlNotify, in the case of "geturlnotify"), and a 
   "frame" attribute is present, the data from the stream is converted into a
   data: url, and sent back to the browser in another stream via a call to
   NPN_GetURL, whereupon it should be displayed in the specified frame.
 
-"range": one or more byte ranges, in the format "offset,length;offset,length".
-  Only valid when "streammode" = "seek".  When "range" is present, the plugin
-  will request the specified byte ranges from the stream via a call to
-  NPN_RequestRead, which it makes after the browser makes its final call to
-  NPP_Write.  The plugin verifies that the browser makes additional calls
-  to NPP_Write according to the requested byte ranges, and that the data
-  received is correct.  Any errors will appear in the test "frame", if
-  specified.
-
 "posturl": a url.  After the plugin receives a stream, and NPP_DestroyStream
   is called, if "posturl" is specified, the plugin will post the contents
   of the stream to the specified url via NPN_PostURL.  See "postmode" for
   additional details.
 
 "postmode": either "frame" or "stream".  If "frame", and a "frame" attribute
   is present, the plugin will pass the frame name to calls to NPN_PostURL,
   so that the HTTP response from that operation will be displayed in the
@@ -363,20 +350,16 @@ The attributes which control stream test
 "functiontofail": one of "npp_newstream", "npp_write", "npp_destroystream".
   When specified, the given function will return an error code (-1 for
   NPP_Write, or else the value of the "failurecode" attribute) the first time
   it is called by the browser.
 
 "failurecode": one of the NPError constants.  Used to specify the error
   that will be returned by the "functiontofail".
 
-If the plugin is instantiated as a full-page plugin, the following defaults
-are used:
-  streammode="seek" frame="testframe" range="100,100"
-
 * streamTest(url, doPost, postData, writeCallback, notifyCallback, redirectCallback, allowRedirects, postFile = false)
 This will test how NPN_GetURLNotify and NPN_PostURLNotify behave when they are
 called with arbitrary (malformed) URLs. The function will return `true` if
 NPN_[Get/Post]URLNotify succeeds, and `false` if it fails.
 @url url to request
 @param doPost whether to call NPN_PostURLNotify
 @param postData null, or a string to send a postdata
 @writeCallback will be called when data is received for the stream
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -421,49 +421,23 @@ static void clearIdentifiers()
   memset(sPluginMethodIdentifiers, 0,
       MOZ_ARRAY_LENGTH(sPluginMethodIdentifiers) * sizeof(NPIdentifier));
   memset(sPluginPropertyIdentifiers, 0,
       MOZ_ARRAY_LENGTH(sPluginPropertyIdentifiers) * sizeof(NPIdentifier));
 
   sIdentifiersInitialized = false;
 }
 
-static void addRange(InstanceData* instanceData, const char* range)
-{
-  /*
-  increased rangestr size from 16 to 17, the 17byte is only for
-  null terminated value, maybe for actual capacity it needs 16 bytes
-  */
-  char rangestr[17];
-  memset(rangestr, 0, sizeof(rangestr));
-  strncpy(rangestr, range, sizeof(rangestr) - sizeof(char));
-  const char* str1 = strtok(rangestr, ",");
-  const char* str2 = str1 ? strtok(nullptr, ",") : nullptr;
-  if (str1 && str2) {
-    TestRange* byterange = new TestRange;
-    byterange->offset = atoi(str1);
-    byterange->length = atoi(str2);
-    byterange->waiting = true;
-    byterange->next = instanceData->testrange;
-    instanceData->testrange = byterange;
-  }
-}
-
 static void sendBufferToFrame(NPP instance)
 {
   InstanceData* instanceData = (InstanceData*)(instance->pdata);
   string outbuf;
   if (!instanceData->npnNewStream) outbuf = "data:text/html,";
   const char* buf = reinterpret_cast<char *>(instanceData->streamBuf);
   int32_t bufsize = instanceData->streamBufSize;
-  if (instanceData->streamMode == NP_ASFILE ||
-      instanceData->streamMode == NP_ASFILEONLY) {
-    buf = reinterpret_cast<char *>(instanceData->fileBuf);
-    bufsize = instanceData->fileBufSize;
-  }
   if (instanceData->err.str().length() > 0) {
     outbuf.append(instanceData->err.str());
   }
   else if (bufsize > 0) {
     outbuf.append(buf);
   }
   else {
     outbuf.append("Error: no data in buffer");
@@ -667,17 +641,16 @@ static bool fillPluginFunctionTable(NPPl
   if (pFuncs->size < (offsetof(NPPluginFuncs, getsiteswithdata) + sizeof(void*)))
     return false;
 
   pFuncs->newp = NPP_New;
   pFuncs->destroy = NPP_Destroy;
   pFuncs->setwindow = NPP_SetWindow;
   pFuncs->newstream = NPP_NewStream;
   pFuncs->destroystream = NPP_DestroyStream;
-  pFuncs->asfile = NPP_StreamAsFile;
   pFuncs->writeready = NPP_WriteReady;
   pFuncs->write = NPP_Write;
   pFuncs->print = NPP_Print;
   pFuncs->event = NPP_HandleEvent;
   pFuncs->urlnotify = NPP_URLNotify;
   pFuncs->getvalue = NPP_GetValue;
   pFuncs->setvalue = NPP_SetValue;
   pFuncs->urlredirectnotify = NPP_URLRedirectNotify;
@@ -773,30 +746,26 @@ NPP_New(NPMIMEType pluginType, NPP insta
   if (!browserSupportsWindowless && !pluginSupportsWindowMode()) {
     printf("Windowless mode not supported by the browser, windowed mode not supported by the plugin!\n");
     return NPERR_GENERIC_ERROR;
   }
 
   // set up our our instance data
   InstanceData* instanceData = new InstanceData;
   instanceData->npp = instance;
-  instanceData->streamMode = NP_ASFILEONLY;
   instanceData->testFunction = FUNCTION_NONE;
   instanceData->functionToFail = FUNCTION_NONE;
   instanceData->failureCode = 0;
   instanceData->callOnDestroy = nullptr;
   instanceData->streamChunkSize = 1024;
   instanceData->streamBuf = nullptr;
   instanceData->streamBufSize = 0;
-  instanceData->fileBuf = nullptr;
-  instanceData->fileBufSize = 0;
   instanceData->throwOnNextInvoke = false;
   instanceData->runScriptOnPaint = false;
   instanceData->dontTouchElement = false;
-  instanceData->testrange = nullptr;
   instanceData->hasWidget = false;
   instanceData->npnNewStream = false;
   instanceData->invalidateDuringPaint = false;
   instanceData->slowPaint = false;
   instanceData->playingAudio = false;
   instanceData->audioMuted = false;
   instanceData->writeCount = 0;
   instanceData->writeReadyCount = 0;
@@ -851,31 +820,16 @@ NPP_New(NPMIMEType pluginType, NPP insta
     }
     else if (strcmp(argn[i], "asyncmodel") == 0) {
       if (strcmp(argv[i], "bitmap") == 0) {
         requestAsyncDrawing = AD_BITMAP;
       } else if (strcmp(argv[i], "dxgi") == 0) {
         requestAsyncDrawing = AD_DXGI;
       }
     }
-    if (strcmp(argn[i], "streammode") == 0) {
-      if (strcmp(argv[i], "normal") == 0) {
-        instanceData->streamMode = NP_NORMAL;
-      }
-      else if ((strcmp(argv[i], "asfile") == 0) &&
-                strlen(argv[i]) == strlen("asfile")) {
-        instanceData->streamMode = NP_ASFILE;
-      }
-      else if (strcmp(argv[i], "asfileonly") == 0) {
-        instanceData->streamMode = NP_ASFILEONLY;
-      }
-      else if (strcmp(argv[i], "seek") == 0) {
-        instanceData->streamMode = NP_SEEK;
-      }
-    }
     if (strcmp(argn[i], "streamchunksize") == 0) {
       instanceData->streamChunkSize = atoi(argv[i]);
     }
     if (strcmp(argn[i], "failurecode") == 0) {
       instanceData->failureCode = atoi(argv[i]);
     }
     if (strcmp(argn[i], "functiontofail") == 0) {
       instanceData->functionToFail = getFuncFromString(argv[i]);
@@ -898,30 +852,16 @@ NPP_New(NPMIMEType pluginType, NPP insta
       }
       else if (strcmp(argv[i], "stream") == 0) {
         instanceData->postMode = POSTMODE_STREAM;
       }
     }
     if (strcmp(argn[i], "frame") == 0) {
       instanceData->frame = argv[i];
     }
-    if (strcmp(argn[i], "range") == 0) {
-      string range = argv[i];
-      size_t semicolon = range.find(';');
-      while (semicolon != string::npos) {
-        addRange(instanceData, range.substr(0, semicolon).c_str());
-        if (semicolon == range.length()) {
-          range = "";
-          break;
-        }
-        range = range.substr(semicolon + 1);
-        semicolon = range.find(';');
-      }
-      if (range.length()) addRange(instanceData, range.c_str());
-    }
     if (strcmp(argn[i], "newstream") == 0 &&
         strcmp(argv[i], "true") == 0) {
       instanceData->npnNewStream = true;
     }
     if (strcmp(argn[i], "newcrash") == 0) {
       IntentionalCrash();
     }
     if (strcmp(argn[i], "paintscript") == 0) {
@@ -956,25 +896,16 @@ NPP_New(NPMIMEType pluginType, NPP insta
       if (alreadyHasSalign) {
         // If salign came before this parameter, error out now.
         return NPERR_GENERIC_ERROR;
       }
     }
     if (strcmp(argn[i], "salign") == 0) {
       alreadyHasSalign = true;
     }
-
-    // We don't support NP_FULL any more, but name="plugin" is an indication
-    // that we're a full-page plugin. We use default seek parameters for
-    // test_fullpage.html
-    if (strcmp(argn[i], "name") == 0 && strcmp(argv[i], "plugin") == 0) {
-      instanceData->streamMode = NP_SEEK;
-      instanceData->frame = "testframe";
-      addRange(instanceData, "100,100");
-    }
   }
 
   if (!browserSupportsWindowless || !pluginSupportsWindowlessMode()) {
     requestWindow = true;
   } else if (!pluginSupportsWindowMode()) {
     requestWindow = false;
   }
   if (requestWindow) {
@@ -1091,27 +1022,16 @@ NPP_Destroy(NPP instance, NPSavedData** 
     NPN_InvokeDefault(instance, instanceData->callOnDestroy, nullptr, 0, &result);
     NPN_ReleaseVariantValue(&result);
     NPN_ReleaseObject(instanceData->callOnDestroy);
   }
 
   if (instanceData->streamBuf) {
     free(instanceData->streamBuf);
   }
-  if (instanceData->fileBuf) {
-    free(instanceData->fileBuf);
-  }
-
-  TestRange* currentrange = instanceData->testrange;
-  TestRange* nextrange;
-  while (currentrange != nullptr) {
-    nextrange = reinterpret_cast<TestRange*>(currentrange->next);
-    delete currentrange;
-    currentrange = nextrange;
-  }
 
   if (instanceData->frontBuffer) {
     NPN_SetCurrentAsyncSurface(instance, nullptr, nullptr);
     NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
     NPN_MemFree(instanceData->frontBuffer);
   }
   if (instanceData->backBuffer) {
     NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
@@ -1216,17 +1136,17 @@ NPP_NewStream(NPP instance, NPMIMEType t
   }
 
   if (stream->notifyData &&
       static_cast<URLNotifyData*>(stream->notifyData) != &kNotifyData) {
     // stream from streamTest
     *stype = NP_NORMAL;
   }
   else {
-    *stype = instanceData->streamMode;
+    *stype = NP_NORMAL;
 
     if (instanceData->streamBufSize) {
       free(instanceData->streamBuf);
       instanceData->streamBufSize = 0;
       if (instanceData->testFunction == FUNCTION_NPP_POSTURL &&
           instanceData->postMode == POSTMODE_STREAM) {
         instanceData->testFunction = FUNCTION_NPP_GETURL;
       }
@@ -1264,36 +1184,16 @@ NPP_DestroyStream(NPP instance, NPStream
     return instanceData->failureCode;
   }
 
   URLNotifyData* nd = static_cast<URLNotifyData*>(stream->notifyData);
   if (nd && nd != &kNotifyData) {
     return NPERR_NO_ERROR;
   }
 
-  if (instanceData->streamMode == NP_ASFILE &&
-      instanceData->functionToFail == FUNCTION_NONE) {
-    if (!instanceData->streamBuf) {
-      instanceData->err <<
-        "Error: no data written with NPP_Write";
-      return NPERR_GENERIC_ERROR;
-    }
-
-    if (!instanceData->fileBuf) {
-      instanceData->err <<
-        "Error: no data written with NPP_StreamAsFile";
-      return NPERR_GENERIC_ERROR;
-    }
-
-    if (strcmp(reinterpret_cast<char *>(instanceData->fileBuf),
-               reinterpret_cast<char *>(instanceData->streamBuf))) {
-      instanceData->err <<
-        "Error: data passed to NPP_Write and NPP_StreamAsFile differed";
-    }
-  }
   if (instanceData->frame.length() > 0 &&
       instanceData->testFunction != FUNCTION_NPP_GETURLNOTIFY &&
       instanceData->testFunction != FUNCTION_NPP_POSTURL) {
     sendBufferToFrame(instance);
   }
   if (instanceData->testFunction == FUNCTION_NPP_POSTURL) {
     NPError err = NPN_PostURL(instance, instanceData->testUrl.c_str(),
       instanceData->postMode == POSTMODE_FRAME ? instanceData->frame.c_str() : nullptr,
@@ -1365,50 +1265,26 @@ NPP_Write(NPP instance, NPStream* stream
 
   if (nd && nd != &kNotifyData) {
     uint32_t newsize = nd->size + len;
     nd->data = (char*) realloc(nd->data, newsize);
     memcpy(nd->data + nd->size, buffer, len);
     nd->size = newsize;
     return len;
   }
-  if (instanceData->streamMode == NP_SEEK &&
-      stream->end != 0 &&
-      stream->end == ((uint32_t)instanceData->streamBufSize + len)) {
-    // If the complete stream has been written, and we're doing a seek test,
-    // then call NPN_RequestRead.
-    // prevent recursion
-    instanceData->streamMode = NP_NORMAL;
-
-    if (instanceData->testrange != nullptr) {
-      NPError err = NPN_RequestRead(stream, instanceData->testrange);
-      if (err != NPERR_NO_ERROR) {
-        instanceData->err << "NPN_RequestRead returned error %d" << err;
-      }
-      printf("called NPN_RequestRead, return %d\n", err);
-    }
-  }
 
   char* streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
   if (offset + len <= instanceData->streamBufSize) {
     if (memcmp(buffer, streamBuf + offset, len)) {
       instanceData->err <<
-          "Error: data written from NPN_RequestRead doesn't match";
+          "Error: data written doesn't match";
     }
     else {
       printf("data matches!\n");
     }
-    TestRange* range = instanceData->testrange;
-    while(range != nullptr) {
-      if (offset == range->offset &&
-        (uint32_t)len == range->length) {
-        range->waiting = false;
-      }
-      range = reinterpret_cast<TestRange*>(range->next);
-    }
   }
   else {
     if (instanceData->streamBufSize == 0) {
       instanceData->streamBuf = malloc(len + 1);
       streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
     }
     else {
       instanceData->streamBuf =
@@ -1419,53 +1295,16 @@ NPP_Write(NPP instance, NPStream* stream
     memcpy(streamBuf + instanceData->streamBufSize, buffer, len);
     instanceData->streamBufSize = instanceData->streamBufSize + len;
     streamBuf[instanceData->streamBufSize] = '\0';
   }
   return len;
 }
 
 void
-NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
-{
-  size_t size;
-
-  InstanceData* instanceData = (InstanceData*)(instance->pdata);
-
-  if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM ||
-      instanceData->functionToFail == FUNCTION_NPP_WRITE) {
-    instanceData->err << "NPP_StreamAsFile called";
-  }
-
-  if (!fname)
-    return;
-
-  FILE *file = fopen(fname, "rb");
-  if (file) {
-    fseek(file, 0, SEEK_END);
-    size = ftell(file);
-    instanceData->fileBuf = malloc((int32_t)size + 1);
-    char* buf = reinterpret_cast<char *>(instanceData->fileBuf);
-    fseek(file, 0, SEEK_SET);
-    size_t sizeRead = fread(instanceData->fileBuf, 1, size, file);
-    if (sizeRead != size) {
-      printf("Unable to read data from file\n");
-      instanceData->err << "Unable to read data from file " << fname;
-    }
-    fclose(file);
-    buf[size] = '\0';
-    instanceData->fileBufSize = (int32_t)size;
-  }
-  else {
-    printf("Unable to open file\n");
-    instanceData->err << "Unable to open file " << fname;
-  }
-}
-
-void
 NPP_Print(NPP instance, NPPrint* platformPrint)
 {
 }
 
 int16_t
 NPP_HandleEvent(NPP instance, void* event)
 {
   InstanceData* instanceData = (InstanceData*)(instance->pdata);
@@ -1819,22 +1658,16 @@ NPN_GetURLNotify(NPP instance, const cha
 
 NPError
 NPN_GetURL(NPP instance, const char* url, const char* target)
 {
   return sBrowserFuncs->geturl(instance, url, target);
 }
 
 NPError
-NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
-{
-  return sBrowserFuncs->requestread(stream, rangeList);
-}
-
-NPError
 NPN_PostURLNotify(NPP instance, const char* url,
                   const char* target, uint32_t len,
                   const char* buf, NPBool file, void* notifyData)
 {
   return sBrowserFuncs->posturlnotify(instance, url, target, len, buf, file, notifyData);
 }
 
 NPError
--- a/dom/plugins/test/testplugin/nptest.h
+++ b/dom/plugins/test/testplugin/nptest.h
@@ -86,20 +86,16 @@ typedef enum {
 typedef struct TestNPObject : NPObject {
   NPP npp;
   DrawMode drawMode;
   uint32_t drawColor; // 0xAARRGGBB
 } TestNPObject;
 
 typedef struct _PlatformData PlatformData;
 
-typedef struct TestRange : NPByteRange {
-  bool waiting;
-} TestRange;
-
 typedef struct InstanceData {
   NPP npp;
   NPWindow window;
   TestNPObject* scriptableObject;
   PlatformData* platformData;
   int32_t instanceCountWatchGeneration;
   bool lastReportedPrivateModeState;
   bool hasWidget;
@@ -125,23 +121,19 @@ typedef struct InstanceData {
   TestFunction functionToFail;
   NPError failureCode;
   NPObject* callOnDestroy;
   PostMode postMode;
   std::string testUrl;
   std::string frame;
   std::string timerTestScriptCallback;
   std::ostringstream err;
-  uint16_t streamMode;
   int32_t streamChunkSize;
   int32_t streamBufSize;
-  int32_t fileBufSize;
-  TestRange* testrange;
   void* streamBuf;
-  void* fileBuf;
   bool crashOnDestroy;
   bool cleanupWidget;
   ActivationState topLevelWindowActivationState;
   int32_t topLevelWindowActivationEventCount;
   ActivationState focusState;
   int32_t focusEventCount;
   int32_t eventModel;
   bool closeStream;
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -514,16 +514,19 @@ public:
     MappedSurface mMap;
     bool mIsMapped;
   };
 
   virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
   /** @deprecated
    * Get the raw bitmap data of the surface.
    * Can return null if there was OOM allocating surface data.
+   *
+   * Deprecated means you shouldn't be using this!! Use Map instead.
+   * Please deny any reviews which add calls to this!
    */
   virtual uint8_t *GetData() = 0;
 
   /** @deprecated
    * Stride of the surface, distance in bytes between the start of the image
    * data belonging to row y and row y+1. This may be negative.
    * Can return 0 if there was OOM allocating surface data.
    */
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -12,16 +12,17 @@
 #include "skia/include/core/SkData.h"
 #include "mozilla/CheckedInt.h"
 
 namespace mozilla {
 namespace gfx {
 
 SourceSurfaceSkia::SourceSurfaceSkia()
   : mDrawTarget(nullptr)
+  , mChangeMutex("SourceSurfaceSkia::mChangeMutex")
 {
 }
 
 SourceSurfaceSkia::~SourceSurfaceSkia()
 {
   if (mDrawTarget) {
     mDrawTarget->SnapshotDestroyed();
     mDrawTarget = nullptr;
@@ -35,16 +36,24 @@ SourceSurfaceSkia::GetSize() const
 }
 
 SurfaceFormat
 SourceSurfaceSkia::GetFormat() const
 {
   return mFormat;
 }
 
+sk_sp<SkImage>
+SourceSurfaceSkia::GetImage()
+{
+  MutexAutoLock lock(mChangeMutex);
+  sk_sp<SkImage> image = mImage;
+  return image;
+}
+
 static sk_sp<SkData>
 MakeSkData(void* aData, int32_t aHeight, size_t aStride)
 {
   CheckedInt<size_t> size = aStride;
   size *= aHeight;
   if (size.isValid()) {
     void* mem = sk_malloc_flags(size.value(), 0);
     if (mem) {
@@ -150,19 +159,38 @@ SourceSurfaceSkia::GetData()
 #endif
   SkPixmap pixmap;
   if (!mImage->peekPixels(&pixmap)) {
     gfxCriticalError() << "Failed accessing pixels for Skia raster image";
   }
   return reinterpret_cast<uint8_t*>(pixmap.writable_addr());
 }
 
+bool
+SourceSurfaceSkia::Map(MapType, MappedSurface *aMappedSurface)
+{
+  mChangeMutex.Lock();
+  aMappedSurface->mData = GetData();
+  aMappedSurface->mStride = Stride();
+  mIsMapped = !!aMappedSurface->mData;
+  return mIsMapped;
+}
+
+void
+SourceSurfaceSkia::Unmap()
+{
+  mChangeMutex.Unlock();
+  MOZ_ASSERT(mIsMapped);
+  mIsMapped = false;
+}
+
 void
 SourceSurfaceSkia::DrawTargetWillChange()
 {
+  MutexAutoLock lock(mChangeMutex);
   if (mDrawTarget) {
     // Raster snapshots do not use Skia's internal copy-on-write mechanism,
     // so we need to do an explicit copy here.
     // GPU snapshots, for which peekPixels is false, will already be dealt
     // with automatically via the internal copy-on-write mechanism, so we
     // don't need to do anything for them here.
     SkPixmap pixmap;
     if (mImage->peekPixels(&pixmap)) {
--- a/gfx/2d/SourceSurfaceSkia.h
+++ b/gfx/2d/SourceSurfaceSkia.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_SOURCESURFACESKIA_H_
 #define MOZILLA_GFX_SOURCESURFACESKIA_H_
 
 #include "2D.h"
 #include <vector>
+#include "mozilla/Mutex.h"
 #include "skia/include/core/SkCanvas.h"
 #include "skia/include/core/SkImage.h"
 
 namespace mozilla {
 
 namespace gfx {
 
 class DrawTargetSkia;
@@ -23,39 +24,47 @@ public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceSkia)
   SourceSurfaceSkia();
   ~SourceSurfaceSkia();
 
   virtual SurfaceType GetType() const { return SurfaceType::SKIA; }
   virtual IntSize GetSize() const;
   virtual SurfaceFormat GetFormat() const;
 
-  sk_sp<SkImage>& GetImage() { return mImage; }
+  sk_sp<SkImage> GetImage();
 
   bool InitFromData(unsigned char* aData,
                     const IntSize &aSize,
                     int32_t aStride,
                     SurfaceFormat aFormat);
 
   bool InitFromImage(const sk_sp<SkImage>& aImage,
                      SurfaceFormat aFormat = SurfaceFormat::UNKNOWN,
                      DrawTargetSkia* aOwner = nullptr);
 
   virtual uint8_t* GetData();
 
+  /**
+   * The caller is responsible for ensuring aMappedSurface is not null.
+   */
+  virtual bool Map(MapType, MappedSurface *aMappedSurface);
+
+  virtual void Unmap();
+
   virtual int32_t Stride() { return mStride; }
 
 private:
   friend class DrawTargetSkia;
 
   void DrawTargetWillChange();
 
   sk_sp<SkImage> mImage;
   SurfaceFormat mFormat;
   IntSize mSize;
   int32_t mStride;
   RefPtr<DrawTargetSkia> mDrawTarget;
+  Mutex mChangeMutex;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_SOURCESURFACESKIA_H_ */
--- a/gfx/tests/mochitest/test_acceleration.html
+++ b/gfx/tests/mochitest/test_acceleration.html
@@ -27,26 +27,29 @@ var Ci = SpecialPowers.Ci;
 
 var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
 var xr = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
 
 var windows = SpecialPowers.Services.ww.getWindowEnumerator();
 var windowutils;
 var acceleratedWindows = 0;
 var advancedLayersWindows = 0;
+var layerManagerLog = [];
 while (windows.hasMoreElements()) {
   windowutils = windows.getNext().QueryInterface(Ci.nsIInterfaceRequestor)
                                  .getInterface(Ci.nsIDOMWindowUtils);
   try {
     if (windowutils.layerManagerType != "Basic") {
       acceleratedWindows++;
     }
     if (windowutils.usingAdvancedLayers) {
       advancedLayersWindows++;
     }
+    layerManagerLog.push(windowutils.layerManagerType + ":" +
+                         windowutils.usingAdvancedLayers);
   } catch (e) {
     // The window may not have a layer manager, in which case we get an error.
     // Don't count it as an accelerated window.
   }
 }
 
 var osName = sysInfo.getProperty("name");
 switch(osName)
@@ -107,17 +110,18 @@ switch(osName)
       advancedLayersEnabled = SpecialPowers.getBoolPref("layers.mlgpu.enabled");
       advancedLayersEnabledOnWin7 = SpecialPowers.getBoolPref("layers.mlgpu.enable-on-windows7");
     } catch (e) {}
     var shouldGetAL = advancedLayersEnabled;
     if (version < 6.2) {
       shouldGetAL &= advancedLayersEnabledOnWin7;
     }
     if (shouldGetAL) {
-      isnot(advancedLayersWindows, 0, "Advanced Layers enabled on Windows");
+      isnot(advancedLayersWindows, 0, "Advanced Layers enabled on Windows; "
+                                      + layerManagerLog.join(","));
     } else {
       is(advancedLayersWindows, 0, "Advanced Layers disabled on Windows");
     }
     break;
 
   case "Linux":
     todo(false, "Acceleration supported on Linux, but only on taskcluster instances (bug 1296086)");
     break;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2561,55 +2561,49 @@ gfxPlatform::InitWebRenderConfig()
                                                  WR_DEBUG_PREF);
     }
   }
 }
 
 void
 gfxPlatform::InitOMTPConfig()
 {
-  bool prefEnabled = Preferences::GetBool("layers.omtp.enabled", false);
-
-  // We don't want to report anything for this feature when turned off, as it is still early in development
-  if (!prefEnabled) {
-    return;
-  }
-
-  ScopedGfxFeatureReporter reporter("OMTP", prefEnabled);
+  ScopedGfxFeatureReporter reporter("OMTP");
+
+  FeatureState& omtp = gfxConfig::GetFeature(Feature::OMTP);
 
   if (!XRE_IsParentProcess()) {
     // The parent process runs through all the real decision-making code
     // later in this function. For other processes we still want to report
     // the state of the feature for crash reports.
     if (gfxVars::UseOMTP()) {
       reporter.SetSuccessful();
     }
     return;
   }
 
-  FeatureState& featureOMTP = gfxConfig::GetFeature(Feature::OMTP);
-
-  featureOMTP.DisableByDefault(
-      FeatureStatus::OptIn,
-      "OMTP is an opt-in feature",
-      NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
-
-  featureOMTP.UserEnable("Enabled by pref");
+  omtp.SetDefaultFromPref(
+    "layers.omtp.enabled",
+    true,
+    Preferences::GetDefaultBool("layers.omtp.enabled", false));
 
   if (mContentBackend == BackendType::CAIRO) {
-    featureOMTP.ForceDisable(FeatureStatus::Broken, "OMTP is not supported when using cairo",
+    omtp.ForceDisable(FeatureStatus::Broken, "OMTP is not supported when using cairo",
       NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
   }
 
   if (InSafeMode()) {
-    featureOMTP.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode",
-                         NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
+    omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode",
+                      NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
+  } else if (gfxPrefs::LayersTilesEnabled()) {
+    omtp.ForceDisable(FeatureStatus::Blocked, "OMTP does not yet support tiling",
+                      NS_LITERAL_CSTRING("FEATURE_FAILURE_OMTP_TILING"));
   }
 
-  if (gfxConfig::IsEnabled(Feature::OMTP)) {
+  if (omtp.IsEnabled()) {
     gfxVars::SetUseOMTP(true);
     reporter.SetSuccessful();
   }
 }
 
 bool
 gfxPlatform::CanUseHardwareVideoDecoding()
 {
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -913,18 +913,16 @@ description =
 [PGMPVideoDecoder::NeedShmem]
 description =
 [PGMPVideoEncoder::NeedShmem]
 description =
 [PVideoDecoderManager::PVideoDecoder]
 description =
 [PVideoDecoderManager::Readback]
 description =
-[PBrowserStream::NPN_RequestRead]
-description =
 [PBackgroundStorage::Preload]
 description =
 [PRemoteSpellcheckEngine::Check]
 description =
 [PRemoteSpellcheckEngine::CheckAndSuggest]
 description =
 [PRemoteSpellcheckEngine::SetDictionary]
 description =
--- a/ipc/mscom/ActivationContext.cpp
+++ b/ipc/mscom/ActivationContext.cpp
@@ -163,45 +163,96 @@ ActivationContext::GetCurrentManifestPat
   aOutManifestPath = nsDependentString(assemblyInfo->lpAssemblyManifestPath,
                                        (assemblyInfo->ulManifestPathLength + 1) / sizeof(wchar_t));
 
   return S_OK;
 }
 
 #endif // defined(MOZILLA_INTERNAL_API)
 
+ActivationContextRegion::ActivationContextRegion()
+  : mActCookie(0)
+{
+}
+
 ActivationContextRegion::ActivationContextRegion(const ActivationContext& aActCtx)
   : mActCtx(aActCtx)
   , mActCookie(0)
 {
   Activate();
 }
 
+ActivationContextRegion&
+ActivationContextRegion::operator=(const ActivationContext& aActCtx)
+{
+  Deactivate();
+  mActCtx = aActCtx;
+  Activate();
+  return *this;
+}
+
 ActivationContextRegion::ActivationContextRegion(ActivationContext&& aActCtx)
   : mActCtx(Move(aActCtx))
   , mActCookie(0)
 {
   Activate();
 }
 
+ActivationContextRegion&
+ActivationContextRegion::operator=(ActivationContext&& aActCtx)
+{
+  Deactivate();
+  mActCtx = Move(aActCtx);
+  Activate();
+  return *this;
+}
+
+ActivationContextRegion::ActivationContextRegion(ActivationContextRegion&& aRgn)
+  : mActCtx(Move(aRgn.mActCtx))
+  , mActCookie(aRgn.mActCookie)
+{
+  aRgn.mActCookie = 0;
+}
+
+ActivationContextRegion&
+ActivationContextRegion::operator=(ActivationContextRegion&& aRgn)
+{
+  Deactivate();
+  mActCtx = Move(aRgn.mActCtx);
+  mActCookie = aRgn.mActCookie;
+  aRgn.mActCookie = 0;
+  return *this;
+}
+
 void
 ActivationContextRegion::Activate()
 {
   if (mActCtx.mActCtx == INVALID_HANDLE_VALUE) {
     return;
   }
 
-  DebugOnly<BOOL> activated = ::ActivateActCtx(mActCtx.mActCtx, &mActCookie);
-  MOZ_ASSERT(activated);
+  BOOL activated = ::ActivateActCtx(mActCtx.mActCtx, &mActCookie);
+  MOZ_DIAGNOSTIC_ASSERT(activated);
+}
+
+bool
+ActivationContextRegion::Deactivate()
+{
+  if (!mActCookie) {
+    return true;
+  }
+
+  BOOL deactivated = ::DeactivateActCtx(0, mActCookie);
+  MOZ_DIAGNOSTIC_ASSERT(deactivated);
+  if (deactivated) {
+    mActCookie = 0;
+  }
+
+  return !!deactivated;
 }
 
 ActivationContextRegion::~ActivationContextRegion()
 {
-  if (!mActCookie) {
-    return;
-  }
-
-  DebugOnly<BOOL> deactivated = ::DeactivateActCtx(0, mActCookie);
-  MOZ_ASSERT(deactivated);
+  Deactivate();
 }
 
 } // namespace mscom
 } // namespace mozilla
--- a/ipc/mscom/ActivationContext.h
+++ b/ipc/mscom/ActivationContext.h
@@ -18,16 +18,21 @@
 #include <windows.h>
 
 namespace mozilla {
 namespace mscom {
 
 class ActivationContext final
 {
 public:
+  ActivationContext()
+    : mActCtx(INVALID_HANDLE_VALUE)
+  {
+  }
+
   explicit ActivationContext(WORD aResourceId);
   explicit ActivationContext(HMODULE aLoadFromModule, WORD aResourceId = 2);
 
   ActivationContext(ActivationContext&& aOther);
   ActivationContext& operator=(ActivationContext&& aOther);
 
   ActivationContext(const ActivationContext& aOther);
   ActivationContext& operator=(const ActivationContext& aOther);
@@ -61,24 +66,38 @@ public:
   template <typename... Args>
   explicit ActivationContextRegion(Args... aArgs)
     : mActCtx(Forward<Args>(aArgs)...)
     , mActCookie(0)
   {
     Activate();
   }
 
+  ActivationContextRegion();
+
   explicit ActivationContextRegion(const ActivationContext& aActCtx);
+  ActivationContextRegion& operator=(const ActivationContext& aActCtx);
+
   explicit ActivationContextRegion(ActivationContext&& aActCtx);
+  ActivationContextRegion& operator=(ActivationContext&& aActCtx);
+
+  ActivationContextRegion(ActivationContextRegion&& aRgn);
+  ActivationContextRegion& operator=(ActivationContextRegion&& aRgn);
+
   ~ActivationContextRegion();
 
+  explicit operator bool() const
+  {
+    return !!mActCookie;
+  }
+
   ActivationContextRegion(const ActivationContextRegion&) = delete;
-  ActivationContextRegion(ActivationContextRegion&&) = delete;
   ActivationContextRegion& operator=(const ActivationContextRegion&) = delete;
-  ActivationContextRegion& operator=(ActivationContextRegion&&) = delete;
+
+  bool Deactivate();
 
 private:
   void Activate();
 
   ActivationContext mActCtx;
   ULONG_PTR         mActCookie;
 };
 
--- a/ipc/mscom/COMPtrHolder.h
+++ b/ipc/mscom/COMPtrHolder.h
@@ -24,43 +24,55 @@ namespace mozilla {
 namespace mscom {
 
 template<typename Interface, const IID& _IID>
 class COMPtrHolder
 {
 public:
   typedef ProxyUniquePtr<Interface> COMPtrType;
   typedef COMPtrHolder<Interface, _IID> ThisType;
+  typedef typename detail::EnvironmentSelector<Interface>::Type EnvType;
 
   COMPtrHolder() {}
 
   MOZ_IMPLICIT COMPtrHolder(decltype(nullptr))
   {
   }
 
   explicit COMPtrHolder(COMPtrType&& aPtr)
     : mPtr(Forward<COMPtrType>(aPtr))
   {
   }
 
+  COMPtrHolder(COMPtrType&& aPtr, const ActivationContext& aActCtx)
+    : mPtr(Forward<COMPtrType>(aPtr))
+    , mActCtx(aActCtx)
+  {
+  }
+
   Interface* Get() const
   {
     return mPtr.get();
   }
 
   MOZ_MUST_USE Interface* Release()
   {
     return mPtr.release();
   }
 
   void Set(COMPtrType&& aPtr)
   {
     mPtr = Forward<COMPtrType>(aPtr);
   }
 
+  void SetActCtx(const ActivationContext& aActCtx)
+  {
+    mActCtx = aActCtx;
+  }
+
 #if defined(MOZ_CONTENT_SANDBOX)
   // This method is const because we need to call it during IPC write, where
   // we are passed as a const argument. At higher sandboxing levels we need to
   // save this artifact from the serialization process for later deletion.
   void PreserveStream(PreservedStreamPtr aPtr) const
   {
     MOZ_ASSERT(!mMarshaledStream);
     mMarshaledStream = Move(aPtr);
@@ -118,17 +130,18 @@ public:
 
   bool IsNull() const
   {
     return !mPtr;
   }
 
 private:
   // This is mutable to facilitate the above operator= hack
-  mutable COMPtrType mPtr;
+  mutable COMPtrType  mPtr;
+  ActivationContext   mActCtx;
 
 #if defined(MOZ_CONTENT_SANDBOX)
   // This is mutable so that we may optionally store a reference to a marshaled
   // stream to be cleaned up later via PreserveStream().
   mutable PreservedStreamPtr mMarshaledStream;
 #endif // defined(MOZ_CONTENT_SANDBOX)
 };
 
@@ -146,21 +159,23 @@ struct ParamTraits<mozilla::mscom::COMPt
   {
 #if defined(MOZ_CONTENT_SANDBOX)
     static const bool sIsStreamPreservationNeeded =
       XRE_IsParentProcess() && mozilla::GetEffectiveContentSandboxLevel() >= 3;
 #else
     const bool sIsStreamPreservationNeeded = false;
 #endif // defined(MOZ_CONTENT_SANDBOX)
 
+    paramType::EnvType env;
+
     mozilla::mscom::ProxyStreamFlags flags = sIsStreamPreservationNeeded ?
          mozilla::mscom::ProxyStreamFlags::ePreservable :
          mozilla::mscom::ProxyStreamFlags::eDefault;
 
-    mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get(), flags);
+    mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get(), &env, flags);
     int bufLen;
     const BYTE* buf = proxyStream.GetBuffer(bufLen);
     MOZ_ASSERT(buf || !bufLen);
     aMsg->WriteInt(bufLen);
     if (bufLen) {
       aMsg->WriteBytes(reinterpret_cast<const char*>(buf), bufLen);
     }
 
@@ -188,17 +203,19 @@ struct ParamTraits<mozilla::mscom::COMPt
     mozilla::UniquePtr<BYTE[]> buf;
     if (length) {
       buf = mozilla::MakeUnique<BYTE[]>(length);
       if (!aMsg->ReadBytesInto(aIter, buf.get(), length)) {
         return false;
       }
     }
 
-    mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length);
+    paramType::EnvType env;
+
+    mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length, &env);
     if (!proxyStream.IsValid()) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamValid"),
                                          NS_LITERAL_CSTRING("false"));
 #endif // defined(MOZ_CRASHREPORTER)
       return false;
     }
 
--- a/ipc/mscom/PassthruProxy.cpp
+++ b/ipc/mscom/PassthruProxy.cpp
@@ -19,25 +19,25 @@ PassthruProxy::PassthruProxy()
   : mRefCnt(0)
   , mWrappedIid()
   , mVTableSize(0)
   , mVTable(nullptr)
   , mForgetPreservedStream(false)
 {
 }
 
-PassthruProxy::PassthruProxy(REFIID aIidToWrap, uint32_t aVTableSize,
-                             NotNull<IUnknown*> aObjToWrap)
+PassthruProxy::PassthruProxy(ProxyStream::Environment* aEnv, REFIID aIidToWrap,
+                             uint32_t aVTableSize, NotNull<IUnknown*> aObjToWrap)
   : mRefCnt(0)
   , mWrappedIid(aIidToWrap)
   , mVTableSize(aVTableSize)
   , mVTable(nullptr)
   , mForgetPreservedStream(false)
 {
-  ProxyStream proxyStream(aIidToWrap, aObjToWrap,
+  ProxyStream proxyStream(aIidToWrap, aObjToWrap, aEnv,
                           ProxyStreamFlags::ePreservable);
   mPreservedStream = Move(proxyStream.GetPreservedStream());
   MOZ_ASSERT(mPreservedStream);
 }
 
 PassthruProxy::~PassthruProxy()
 {
   if (mForgetPreservedStream) {
--- a/ipc/mscom/PassthruProxy.h
+++ b/ipc/mscom/PassthruProxy.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_mscom_PassthruProxy_h
 #define mozilla_mscom_PassthruProxy_h
 
 #include "mozilla/Atomics.h"
+#include "mozilla/mscom/ProxyStream.h"
 #include "mozilla/mscom/Ptr.h"
 #include "mozilla/NotNull.h"
 
 #include <objbase.h>
 
 namespace mozilla {
 namespace mscom {
 namespace detail {
@@ -34,17 +35,19 @@ class PassthruProxy final : public IMars
                           , public IClientSecurity
 {
 public:
   template <typename Iface>
   static RefPtr<Iface> Wrap(NotNull<Iface*> aIn)
   {
     static_assert(detail::VTableSizer<Iface>::Size >= 3, "VTable too small");
 
-    RefPtr<PassthruProxy> passthru(new PassthruProxy(__uuidof(Iface),
+    detail::EnvironmentSelector<Iface>::Type env;
+
+    RefPtr<PassthruProxy> passthru(new PassthruProxy(&env, __uuidof(Iface),
                                                      detail::VTableSizer<Iface>::Size,
                                                      aIn));
 
     RefPtr<Iface> result;
     if (FAILED(passthru->QueryProxyInterface(getter_AddRefs(result)))) {
       return nullptr;
     }
 
@@ -87,18 +90,18 @@ public:
                           OLECHAR* aSrvPrincName, DWORD aAuthnLevel,
                           DWORD aImpLevel, void* aAuthInfo, DWORD aCapabilities) override
   { return E_NOTIMPL; }
 
   STDMETHODIMP CopyProxy(IUnknown* aProxy, IUnknown** aOutCopy) override
   { return E_NOTIMPL; }
 
 private:
-  PassthruProxy(REFIID aIidToWrap, uint32_t aVTableSize,
-                NotNull<IUnknown*> aObjToWrap);
+  PassthruProxy(ProxyStream::Environment* aEnv, REFIID aIidToWrap,
+                uint32_t aVTableSize, NotNull<IUnknown*> aObjToWrap);
   ~PassthruProxy();
 
   bool IsInitialMarshal() const { return !mStream; }
   HRESULT QueryProxyInterface(void** aOutInterface);
 
   Atomic<ULONG>     mRefCnt;
   IID               mWrappedIid;
   PreservedStreamPtr  mPreservedStream;
--- a/ipc/mscom/ProxyStream.cpp
+++ b/ipc/mscom/ProxyStream.cpp
@@ -8,16 +8,17 @@
 #if defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
 #include "HandlerData.h"
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/mscom/ActivationContext.h"
 #endif // defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
 #include "mozilla/mscom/EnsureMTA.h"
 #include "mozilla/mscom/ProxyStream.h"
 #include "mozilla/mscom/Utils.h"
+#include "mozilla/ScopeExit.h"
 
 #if defined(MOZ_CRASHREPORTER)
 #include "mozilla/mscom/Objref.h"
 #include "nsExceptionHandler.h"
 #include "nsPrintfCString.h"
 #include "RegistrationAnnotator.h"
 #endif
 
@@ -34,17 +35,17 @@ ProxyStream::ProxyStream()
   , mBufSize(0)
   , mPreserveStream(false)
 {
 }
 
 // GetBuffer() fails with this variant, but that's okay because we're just
 // reconstructing the stream from a buffer anyway.
 ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf,
-                         const int aInitBufSize)
+                         const int aInitBufSize, Environment* aEnv)
   : mGlobalLockedBuf(nullptr)
   , mHGlobal(nullptr)
   , mBufSize(aInitBufSize)
   , mPreserveStream(false)
 {
 #if defined(MOZ_CRASHREPORTER)
   NS_NAMED_LITERAL_CSTRING(kCrashReportKey, "ProxyStreamUnmarshalStatus");
 #endif
@@ -88,21 +89,38 @@ ProxyStream::ProxyStream(REFIID aIID, co
 
   HRESULT unmarshalResult = S_OK;
 
   // We need to convert to an interface here otherwise we mess up const
   // correctness with IPDL. We'll request an IUnknown and then QI the
   // actual interface later.
 
 #if defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
-  auto marshalFn = [this, &strActCtx, &manifestPath, &unmarshalResult, &aIID]() -> void
+  auto marshalFn = [this, &strActCtx, &manifestPath, &unmarshalResult, &aIID, aEnv]() -> void
 #else
-  auto marshalFn = [this, &unmarshalResult, &aIID]() -> void
+  auto marshalFn = [this, &unmarshalResult, &aIID, aEnv]() -> void
 #endif // defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
   {
+    if (aEnv) {
+      bool pushOk = aEnv->Push();
+      MOZ_DIAGNOSTIC_ASSERT(pushOk);
+      if (!pushOk) {
+        return;
+      }
+    }
+
+    auto popEnv = MakeScopeExit([aEnv]() -> void {
+      if (!aEnv) {
+        return;
+      }
+
+      bool popOk = aEnv->Pop();
+      MOZ_DIAGNOSTIC_ASSERT(popOk);
+    });
+
 #if defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
     auto curActCtx = ActivationContext::GetCurrent();
     if (curActCtx.isOk()) {
       strActCtx.AppendPrintf("0x%p", curActCtx.unwrap());
     } else {
       strActCtx.AppendPrintf("HRESULT 0x%08X", curActCtx.unwrapErr());
     }
 
@@ -264,17 +282,17 @@ ProxyStream::GetInterface(void** aOutInt
   if (!aOutInterface) {
     return false;
   }
 
   *aOutInterface = mUnmarshaledProxy.release();
   return true;
 }
 
-ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject,
+ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
                          ProxyStreamFlags aFlags)
   : mGlobalLockedBuf(nullptr)
   , mHGlobal(nullptr)
   , mBufSize(0)
   , mPreserveStream(aFlags & ProxyStreamFlags::ePreservable)
 {
   if (!aObject) {
     return;
@@ -290,23 +308,40 @@ ProxyStream::ProxyStream(REFIID aIID, IU
   HRESULT statResult = S_OK;
   HRESULT getHGlobalResult = S_OK;
 
 #if defined(MOZ_CRASHREPORTER)
   nsAutoString manifestPath;
 
   auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
                     &hglobal, &createStreamResult, &marshalResult, &statResult,
-                    &getHGlobalResult, &manifestPath]() -> void
+                    &getHGlobalResult, aEnv, &manifestPath]() -> void
 #else
   auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
                     &hglobal, &createStreamResult, &marshalResult, &statResult,
-                    &getHGlobalResult]() -> void
+                    &getHGlobalResult, aEnv]() -> void
 #endif // defined(MOZ_CRASHREPORTER)
   {
+    if (aEnv) {
+      bool pushOk = aEnv->Push();
+      MOZ_DIAGNOSTIC_ASSERT(pushOk);
+      if (!pushOk) {
+        return;
+      }
+    }
+
+    auto popEnv = MakeScopeExit([aEnv]() -> void {
+      if (!aEnv) {
+        return;
+      }
+
+      bool popOk = aEnv->Pop();
+      MOZ_DIAGNOSTIC_ASSERT(popOk);
+    });
+
     createStreamResult = ::CreateStreamOnHGlobal(nullptr, TRUE,
                                                  getter_AddRefs(stream));
     if (FAILED(createStreamResult)) {
       return;
     }
 
 #if defined(MOZ_CRASHREPORTER)
     ActivationContext::GetCurrentManifestPath(manifestPath);
--- a/ipc/mscom/ProxyStream.h
+++ b/ipc/mscom/ProxyStream.h
@@ -25,20 +25,36 @@ enum class ProxyStreamFlags : uint32_t
   ePreservable = 1
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ProxyStreamFlags);
 
 class ProxyStream final
 {
 public:
+  class MOZ_RAII Environment
+  {
+  public:
+    virtual ~Environment() = default;
+    virtual bool Push() = 0;
+    virtual bool Pop() = 0;
+  };
+
+  class MOZ_RAII DefaultEnvironment : public Environment
+  {
+  public:
+    bool Push() override { return true; }
+    bool Pop() override { return true; }
+  };
+
   ProxyStream();
-  ProxyStream(REFIID aIID, IUnknown* aObject,
+  ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
               ProxyStreamFlags aFlags = ProxyStreamFlags::eDefault);
-  ProxyStream(REFIID aIID, const BYTE* aInitBuf, const int aInitBufSize);
+  ProxyStream(REFIID aIID, const BYTE* aInitBuf, const int aInitBufSize,
+              Environment* aEnv);
 
   ~ProxyStream();
 
   // Not copyable because this would mess up the COM marshaling.
   ProxyStream(const ProxyStream& aOther) = delete;
   ProxyStream& operator=(const ProxyStream& aOther) = delete;
 
   ProxyStream(ProxyStream&& aOther);
@@ -63,12 +79,21 @@ private:
   RefPtr<IStream> mStream;
   BYTE*           mGlobalLockedBuf;
   HGLOBAL         mHGlobal;
   int             mBufSize;
   ProxyUniquePtr<IUnknown> mUnmarshaledProxy;
   bool            mPreserveStream;
 };
 
+namespace detail {
+
+template <typename Interface>
+struct EnvironmentSelector
+{
+  typedef ProxyStream::DefaultEnvironment Type;
+};
+
+} // namespace detail
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_ProxyStream_h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -79,16 +79,22 @@ ExpectedOwnerForChild(const nsIFrame& aF
   }
 
   if (aFrame.IsLetterFrame()) {
     // Ditto for ::first-letter. A first-letter always arrives here via its
     // direct parent, except when it's parented to a ::first-line.
     return parent->IsLineFrame() ? parent->GetParent() : parent;
   }
 
+  if (parent->IsLetterFrame()) {
+    // Things never have ::first-letter as their expected parent.  Go
+    // on up to the ::first-letter's parent.
+    parent = parent->GetParent();
+  }
+
   parent = FirstContinuationOrPartOfIBSplit(parent);
 
   // We've handled already anon boxes and bullet frames, so now we're looking at
   // a frame of a DOM element or pseudo. Hop through anon and line-boxes
   // generated by our DOM parent, and go find the owner frame for it.
   while (parent && (IsAnonBox(*parent) || parent->IsLineFrame())) {
     auto* pseudo = parent->StyleContext()->GetPseudo();
     if (pseudo == nsCSSAnonBoxes::tableWrapper) {
@@ -106,19 +112,36 @@ ExpectedOwnerForChild(const nsIFrame& aF
 }
 
 void
 ServoRestyleState::AssertOwner(const ServoRestyleState& aParent) const
 {
   MOZ_ASSERT(mOwner);
   MOZ_ASSERT(!mOwner->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
   // We allow aParent.mOwner to be null, for cases when we're not starting at
-  // the root of the tree.
-  MOZ_ASSERT_IF(aParent.mOwner,
-                ExpectedOwnerForChild(*mOwner) == aParent.mOwner);
+  // the root of the tree.  We also allow aParent.mOwner to be somewhere up our
+  // expected owner chain not our immediate owner, which allows us creating long
+  // chains of ServoRestyleStates in some cases where it's just not worth it.
+#ifdef DEBUG
+  if (aParent.mOwner) {
+    const nsIFrame* owner = ExpectedOwnerForChild(*mOwner);
+    if (owner != aParent.mOwner) {
+      MOZ_ASSERT(IsAnonBox(*owner),
+                 "Should only have expected owner weirdness when anon boxes are involved");
+      bool found = false;
+      for (; owner; owner = ExpectedOwnerForChild(*owner)) {
+        if (owner == aParent.mOwner) {
+          found = true;
+          break;
+        }
+      }
+      MOZ_ASSERT(found, "Must have aParent.mOwner on our expected owner chain");
+    }
+  }
+#endif
 }
 
 nsChangeHint
 ServoRestyleState::ChangesHandledFor(const nsIFrame& aFrame) const
 {
   if (!mOwner) {
     MOZ_ASSERT(!mChangesHandled);
     return mChangesHandled;
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1391736.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="UTF-8">
+<script>
+window.onload = () => {
+  a = document.createElement("div")
+  b = document.createElement("div")
+  a.appendChild(b)
+  document.documentElement.appendChild(a)
+  a.style.overflow = "scroll"
+  a.style.columnWidth = "calc(-15px)"
+  b.style.display = "table-caption"
+  requestIdleCallback(() => {
+    a.style.stopColor = "#000"
+    b.style.gridColumn = "crispEdges"
+    window.saved = b.offsetWidth;
+    document.documentElement.className = "";
+  })
+}
+</script>
+</head>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1402476.html
@@ -0,0 +1,13 @@
+<html class="reftest-wait">
+  <script>
+    a = document.createElement("style")
+    a.appendChild(document.createTextNode("*:first-letter { }"))
+    document.documentElement.appendChild(a)
+    a.style.display = "contents"
+    requestIdleCallback(() => {
+      a.appendChild(document.createElement("x"));
+      a.lastChild.offsetWidth;
+      document.documentElement.className = "";
+    })
+  </script>
+</html>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -500,8 +500,10 @@ load 1395715-1.html
 load 1397398-1.html
 load 1397398-2.html
 load 1397398-3.html
 load 1398500.html
 load 1400438-1.html
 load 1400599-1.html
 load 1401739.html
 load 1401840.html
+load 1402476.html
+load 1391736.html
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -34,16 +34,17 @@
 #include "nsCaret.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSColorUtils.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsPlaceholderFrame.h"
 #include "nsIScrollableFrame.h"
+#include "nsSubDocumentFrame.h"
 #include "nsIDOMEvent.h"
 #include "nsDisplayList.h"
 #include "nsRegion.h"
 #include "nsFrameManager.h"
 #include "nsBlockFrame.h"
 #include "nsBidiPresUtils.h"
 #include "imgIContainer.h"
 #include "ImageOps.h"
@@ -120,16 +121,17 @@
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "RegionBuilder.h"
 #include "SVGSVGElement.h"
 #include "DisplayItemClip.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "prenv.h"
 #include "TextDrawTarget.h"
+#include "nsDeckFrame.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 #include "GeckoProfiler.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
@@ -3420,48 +3422,52 @@ nsLayoutUtils::CalculateAndSetDisplayPor
   FrameMetrics metrics = CalculateBasicFrameMetrics(aScrollFrame);
   ScreenMargin displayportMargins = APZCTreeManager::CalculatePendingDisplayPort(
       metrics, ParentLayerPoint(0.0f, 0.0f));
   nsIPresShell* presShell = frame->PresContext()->GetPresShell();
   return nsLayoutUtils::SetDisplayPortMargins(
       content, presShell, displayportMargins, 0, aRepaintMode);
 }
 
-void
+bool
 nsLayoutUtils::MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
-                                      nsIFrame* aScrollFrame) {
+                                      nsIFrame* aScrollFrame,
+                                      RepaintMode aRepaintMode)
+{
   nsIContent* content = aScrollFrame->GetContent();
   nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
   if (!content || !scrollableFrame) {
-    return;
+    return false;
   }
 
   bool haveDisplayPort = HasDisplayPort(content);
 
   // We perform an optimization where we ensure that at least one
   // async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport.
   // If that's not the case yet, and we are async-scrollable, we will get a
   // displayport.
   if (aBuilder.IsPaintingToWindow() &&
       nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) &&
       !aBuilder.HaveScrollableDisplayPort() &&
       scrollableFrame->WantAsyncScroll()) {
 
     // If we don't already have a displayport, calculate and set one.
     if (!haveDisplayPort) {
-      CalculateAndSetDisplayPortMargins(scrollableFrame, nsLayoutUtils::RepaintMode::DoNotRepaint);
+      CalculateAndSetDisplayPortMargins(scrollableFrame, aRepaintMode);
 #ifdef DEBUG
       haveDisplayPort = HasDisplayPort(content);
       MOZ_ASSERT(haveDisplayPort, "should have a displayport after having just set it");
 #endif
     }
 
     // Record that the we now have a scrollable display port.
     aBuilder.SetHaveScrollableDisplayPort();
-  }
+    return true;
+  }
+  return false;
 }
 
 nsIScrollableFrame*
 nsLayoutUtils::GetAsyncScrollableAncestorFrame(nsIFrame* aTarget)
 {
   uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT
                  | nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE
                  | nsLayoutUtils::SCROLLABLE_FIXEDPOS_FINDS_ROOT;
@@ -3490,16 +3496,60 @@ nsLayoutUtils::SetZeroMarginDisplayPortO
         !nsLayoutUtils::HasDisplayPort(frame->GetContent())) {
       nsLayoutUtils::SetDisplayPortMargins(
         frame->GetContent(), frame->PresContext()->PresShell(), ScreenMargin(), 0,
         aRepaintMode);
     }
   }
 }
 
+bool
+nsLayoutUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered(
+  nsIFrame* aFrame, nsDisplayListBuilder& aBuilder)
+{
+  nsIScrollableFrame* sf = do_QueryFrame(aFrame);
+  if (sf) {
+    if (MaybeCreateDisplayPort(aBuilder, aFrame, RepaintMode::Repaint)) {
+      return true;
+    }
+  }
+  if (aFrame->IsPlaceholderFrame()) {
+    nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
+    if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(
+          placeholder->GetOutOfFlowFrame(), aBuilder)) {
+      return true;
+    }
+  }
+  if (aFrame->IsSubDocumentFrame()) {
+    nsIPresShell* presShell =
+      static_cast<nsSubDocumentFrame*>(aFrame)->GetSubdocumentPresShellForPainting(0);
+    nsIFrame* root = presShell ? presShell->GetRootFrame() : nullptr;
+    if (root) {
+      if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(root, aBuilder)) {
+        return true;
+      }
+    }
+  }
+  if (aFrame->IsDeckFrame()) {
+    // only descend the visible card of a decks
+    nsIFrame* child = static_cast<nsDeckFrame*>(aFrame)->GetSelectedBox();
+    if (child) {
+      return MaybeCreateDisplayPortInFirstScrollFrameEncountered(child, aBuilder);
+    }
+  }
+
+  for (nsIFrame* child : aFrame->PrincipalChildList()) {
+    if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(child, aBuilder)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 void
 nsLayoutUtils::ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame)
 {
   nsIFrame* frame = aFrame;
   while (frame) {
     frame = nsLayoutUtils::GetCrossDocParentFrame(frame);
     if (!frame) {
       break;
@@ -3623,17 +3673,17 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
   }
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   if (rootScrollFrame && !aFrame->GetParent()) {
     nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
     MOZ_ASSERT(rootScrollableFrame);
     nsRect displayPortBase = aFrame->GetVisualOverflowRectRelativeToSelf();
     Unused << rootScrollableFrame->DecideScrollableLayer(&builder, &displayPortBase,
-                /* aAllowCreateDisplayPort = */ true);
+                /* aSetBase = */ true);
   }
 
   nsRegion visibleRegion;
   if (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) {
     // This layer tree will be reused, so we'll need to calculate it
     // for the whole "visible" area of the window
     //
     // |ignoreViewportScrolling| and |usingDisplayPort| are persistent
@@ -3680,16 +3730,21 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
     if (canvasFrame) {
       // Use UnionRect here to ensure that areas where the scrollbars
       // were are still filled with the background color.
       canvasArea.UnionRect(canvasArea,
         canvasFrame->CanvasArea() + builder.ToReferenceFrame(canvasFrame));
     }
   }
 
+  builder.ClearHaveScrollableDisplayPort();
+  if (builder.IsPaintingToWindow()) {
+    MaybeCreateDisplayPortInFirstScrollFrameEncountered(aFrame, builder);
+  }
+
   nsRect dirtyRect = visibleRegion.GetBounds();
 
   {
     AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame:BuildDisplayList",
                         GRAPHICS);
     AutoProfilerTracing tracing("Paint", "DisplayList");
 
     PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList);
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1061,16 +1061,20 @@ public:
    * Return whether any part of aTestRect is inside of the rounded
    * rectangle formed by aBounds and aRadii (which are indexed by the
    * enum HalfCorner constants in gfx/2d/Types.h). This is precise.
    */
   static bool RoundedRectIntersectsRect(const nsRect& aRoundedRect,
                                         const nscoord aRadii[8],
                                         const nsRect& aTestRect);
 
+  static bool MaybeCreateDisplayPortInFirstScrollFrameEncountered(
+    nsIFrame* aFrame, nsDisplayListBuilder& aBuilder);
+
+
   enum class PaintFrameFlags : uint32_t {
     PAINT_IN_TRANSFORM = 0x01,
     PAINT_SYNC_DECODE_IMAGES = 0x02,
     PAINT_WIDGET_LAYERS = 0x04,
     PAINT_IGNORE_SUPPRESSION = 0x08,
     PAINT_DOCUMENT_RELATIVE = 0x10,
     PAINT_HIDE_CARET = 0x20,
     PAINT_TO_WINDOW = 0x40,
@@ -2809,20 +2813,25 @@ public:
   static bool CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFrame,
                                                 RepaintMode aRepaintMode);
 
   /**
    * If |aScrollFrame| WantsAsyncScroll() and we don't have a scrollable
    * displayport yet (as tracked by |aBuilder|), calculate and set a
    * displayport.
    *
-   * This is intended to be called during display list building.
+   * If this is called during display list building pass DoNotRepaint in
+   * aRepaintMode.
+   *
+   * Returns true if there is a displayport on an async scrollable scrollframe
+   * after this call, either because one was just added or it already existed.
    */
-  static void MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
-                                     nsIFrame* aScrollFrame);
+  static bool MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
+                                     nsIFrame* aScrollFrame,
+                                     RepaintMode aRepaintMode);
 
   static nsIScrollableFrame* GetAsyncScrollableAncestorFrame(nsIFrame* aTarget);
 
   /**
    * Sets a zero margin display port on all proper ancestors of aFrame that
    * are async scrollable.
    */
   static void SetZeroMarginDisplayPortOnAsyncScrollableAncestors(nsIFrame* aFrame,
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3295,19 +3295,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
       if (mScrollPosForLayerPixelAlignment == nsPoint(-1,-1)) {
         mScrollPosForLayerPixelAlignment = mScrollPosAtLastPaint;
       }
     } else {
       mScrollPosForLayerPixelAlignment = nsPoint(-1,-1);
     }
   }
 
-  // It's safe to get this value before the DecideScrollableLayer call below
-  // because that call cannot create a displayport for root scroll frames,
-  // and hence it cannot create an ignore scroll frame.
   bool ignoringThisScrollFrame =
     aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping();
 
   // Overflow clipping can never clip frames outside our subtree, so there
   // is no need to worry about whether we are a moving frame that might clip
   // non-moving frames.
   // Not all our descendants will be clipped by overflow clipping, but all
   // the ones that aren't clipped will be out of flow frames that have already
@@ -3315,17 +3312,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
   // dirty rect here.
   nsRect dirtyRect = aBuilder->GetDirtyRect();
   if (!ignoringThisScrollFrame) {
     dirtyRect = dirtyRect.Intersect(mScrollPort);
   }
 
   Unused << DecideScrollableLayer(aBuilder, &dirtyRect,
-              /* aAllowCreateDisplayPort = */ !mIsRoot);
+              /* aSetBase = */ !mIsRoot);
 
   bool usingDisplayPort = aBuilder->IsPaintingToWindow() &&
     nsLayoutUtils::HasDisplayPort(mOuter->GetContent());
 
   if (aBuilder->IsForFrameVisibility()) {
     // We expand the dirty rect to catch frames just outside of the scroll port.
     // We use the dirty rect instead of the whole scroll port to prevent
     // too much expansion in the presence of very large (bigger than the
@@ -3584,17 +3581,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi
                                              ScreenMargin(),
                                              0,
                                              nsLayoutUtils::RepaintMode::DoNotRepaint);
         // Call DecideScrollableLayer to recompute mWillBuildScrollableLayer and
         // recompute the current animated geometry root if needed.
         // It's too late to change the dirty rect so pass a copy.
         nsRect copyOfDirtyRect = dirtyRect;
         Unused << DecideScrollableLayer(aBuilder, &copyOfDirtyRect,
-                    /* aAllowCreateDisplayPort = */ false);
+                    /* aSetBase = */ false);
         if (mWillBuildScrollableLayer) {
           asrSetter.InsertScrollFrame(sf);
         }
       }
     }
   }
 
   if (mWillBuildScrollableLayer) {
@@ -3629,46 +3626,39 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   AppendScrollPartsTo(aBuilder, scrolledContent, createLayersForScrollbars, true);
 
   scrolledContent.MoveTo(aLists);
 }
 
 bool
 ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                                          nsRect* aDirtyRect,
-                                         bool aAllowCreateDisplayPort)
+                                         bool aSetBase)
 {
   // Save and check if this changes so we can recompute the current agr.
   bool oldWillBuildScrollableLayer = mWillBuildScrollableLayer;
 
-  bool wasUsingDisplayPort = false;
-  bool usingDisplayPort = false;
   nsIContent* content = mOuter->GetContent();
+  bool usingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
   if (aBuilder->IsPaintingToWindow()) {
-    wasUsingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
-
-    if (aAllowCreateDisplayPort) {
-      nsLayoutUtils::MaybeCreateDisplayPort(*aBuilder, mOuter);
-
+    if (aSetBase) {
       nsRect displayportBase = *aDirtyRect;
       nsPresContext* pc = mOuter->PresContext();
       if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
         displayportBase =
           nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
       } else {
         // Make the displayport base equal to the dirty rect restricted to
         // the scrollport and the root composition bounds, relative to the
         // scrollport.
         displayportBase = aDirtyRect->Intersect(mScrollPort);
 
         // Only restrict to the root composition bounds if necessary,
         // as the required coordinate transformation is expensive.
-        // Note that we call HasDisplayPort again instead of using
-        // wasUsingDisplayPort because we might have just created a display port.
-        if (nsLayoutUtils::HasDisplayPort(content)) {
+        if (usingDisplayPort) {
           const nsPresContext* rootPresContext =
             pc->GetToplevelContentDocumentPresContext();
           if (!rootPresContext) {
             rootPresContext = pc->GetRootPresContext();
           }
           if (rootPresContext) {
             const nsIPresShell* const rootPresShell = rootPresContext->PresShell();
             nsIFrame* rootFrame = rootPresShell->GetRootScrollFrame();
@@ -3731,18 +3721,18 @@ ScrollFrameHelper::DecideScrollableLayer
         }
 
         displayportBase -= mScrollPort.TopLeft();
       }
 
       nsLayoutUtils::SetDisplayPortBase(mOuter->GetContent(), displayportBase);
     }
 
-    // If we don't have aAllowCreateDisplayPort == true then should have already
-    // been called with aAllowCreateDisplayPort == true which should have set a
+    // If we don't have aSetBase == true then should have already
+    // been called with aSetBase == true which should have set a
     // displayport base.
     MOZ_ASSERT(content->GetProperty(nsGkAtoms::DisplayPortBase));
     nsRect displayPort;
     usingDisplayPort =
       nsLayoutUtils::GetDisplayPort(content, &displayPort, RelativeTo::ScrollFrame);
 
     if (usingDisplayPort) {
       // Override the dirty rectangle if the displayport has been set.
@@ -3762,17 +3752,17 @@ ScrollFrameHelper::DecideScrollableLayer
   // When a displayport is being used, force building of a layer so that
   // the compositor can find the scrollable layer for async scrolling.
   // If the element is marked 'scrollgrab', also force building of a layer
   // so that APZ can implement scroll grabbing.
   mWillBuildScrollableLayer = usingDisplayPort || nsContentUtils::HasScrollgrab(content);
 
   // The cached animated geometry root for the display builder is out of
   // date if we just introduced a new animated geometry root.
-  if ((oldWillBuildScrollableLayer != mWillBuildScrollableLayer) || (wasUsingDisplayPort != usingDisplayPort)) {
+  if (oldWillBuildScrollableLayer != mWillBuildScrollableLayer) {
     aBuilder->RecomputeCurrentAnimatedGeometryRoot();
   }
 
   if (gfxPrefs::LayoutUseContainersForRootFrames() && mWillBuildScrollableLayer && mIsRoot) {
     mIsScrollableLayerInRootContainer = true;
   }
 
   return mWillBuildScrollableLayer;
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -405,17 +405,17 @@ public:
   void SetZoomableByAPZ(bool aZoomable);
 
   bool UsesContainerScrolling() const;
 
   ScrollSnapInfo GetScrollSnapInfo() const;
 
   bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                              nsRect* aDirtyRect,
-                             bool aAllowCreateDisplayPort);
+                             bool aSetBase);
   void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort);
   bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort);
 
   bool AllowDisplayPortExpiration();
   void TriggerDisplayPortExpiration();
   void ResetDisplayPortExpiryTimer();
 
   void ScheduleSyntheticMouseMove();
@@ -943,18 +943,18 @@ public:
   virtual void MarkScrollbarsDirtyForReflow() const override {
     mHelper.MarkScrollbarsDirtyForReflow();
   }
   virtual bool UsesContainerScrolling() const override {
     return mHelper.UsesContainerScrolling();
   }
   virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                                      nsRect* aDirtyRect,
-                                     bool aAllowCreateDisplayPort) override {
-    return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
+                                     bool aSetBase) override {
+    return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aSetBase);
   }
   virtual void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort) override {
     mHelper.NotifyApproximateFrameVisibilityUpdate(aIgnoreDisplayPort);
   }
   virtual bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort) override {
     return mHelper.GetDisplayPortAtLastApproximateFrameVisibilityUpdate(aDisplayPort);
   }
   void TriggerDisplayPortExpiration() override {
@@ -1452,18 +1452,18 @@ public:
   void SetScrollableByAPZ(bool aScrollable) override {
     mHelper.SetScrollableByAPZ(aScrollable);
   }
   void SetZoomableByAPZ(bool aZoomable) override {
     mHelper.SetZoomableByAPZ(aZoomable);
   }
   virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                                      nsRect* aDirtyRect,
-                                     bool aAllowCreateDisplayPort) override {
-    return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
+                                     bool aSetBase) override {
+    return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aSetBase);
   }
   virtual void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort) override {
     mHelper.NotifyApproximateFrameVisibilityUpdate(aIgnoreDisplayPort);
   }
   virtual bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort) override {
     return mHelper.GetDisplayPortAtLastApproximateFrameVisibilityUpdate(aDisplayPort);
   }
   void TriggerDisplayPortExpiration() override {
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -437,23 +437,23 @@ public:
    */
   virtual bool UsesContainerScrolling() const = 0;
 
   /**
    * Determine if we should build a scrollable layer for this scroll frame and
    * return the result. It will also record this result on the scroll frame.
    * Pass the dirty rect in aDirtyRect. On return it will be set to the
    * displayport if there is one (ie the dirty rect that should be used).
-   * This function may create a display port where one did not exist before if
-   * aAllowCreateDisplayPort is true. It is only allowed to be false if there
-   * has been a call with it set to true before on the same paint.
+   * This function will set the display port base rect if aSetBase is true.
+   * aSetBase is only allowed to be false if there has been a call with it
+   * set to true before on the same paint.
    */
   virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                                      nsRect* aDirtyRect,
-                                     bool aAllowCreateDisplayPort) = 0;
+                                     bool aSetBase) = 0;
 
   /**
    * Notification that this scroll frame is getting its frame visibility updated.
    * aIgnoreDisplayPort indicates that the display port was ignored (because
    * there was no suitable base rect)
    */
   virtual void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort) = 0;
 
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -399,17 +399,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
 
     if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
       nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
       MOZ_ASSERT(rootScrollableFrame);
       // Use a copy, so the rects don't get modified.
       nsRect copyOfDirty = dirty;
       haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
                           &copyOfDirty,
-                          /* aAllowCreateDisplayPort = */ true);
+                          /* aSetBase = */ true);
 
       if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
         haveDisplayPort = false;
       }
 
       ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
       if (ignoreViewportScrolling) {
         savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -581,16 +581,17 @@ public:
   bool GetAncestorHasApzAwareEventHandler() { return mAncestorHasApzAwareEventHandler; }
   void SetAncestorHasApzAwareEventHandler(bool aValue)
   {
     mAncestorHasApzAwareEventHandler = aValue;
   }
 
   bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; }
   void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; }
+  void ClearHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = false; }
 
   bool SetIsCompositingCheap(bool aCompositingCheap) {
     bool temp = mIsCompositingCheap;
     mIsCompositingCheap = aCompositingCheap;
     return temp;
   }
   bool IsCompositingCheap() const { return mIsCompositingCheap; }
   /**
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -1556,24 +1556,16 @@ Options::ModeString() const
     return "(unknown DMD mode)";
   }
 }
 
 //---------------------------------------------------------------------------
 // DMD start-up
 //---------------------------------------------------------------------------
 
-#ifdef XP_MACOSX
-static void
-NopStackWalkCallback(uint32_t aFrameNumber, void* aPc, void* aSp,
-                     void* aClosure)
-{
-}
-#endif
-
 static void
 prefork()
 {
   if (gStateLock) {
     gStateLock->Lock();
   }
 }
 
@@ -1612,27 +1604,16 @@ Init(const malloc_table_t* aMallocTable)
     StatusMsg("$DMD = '%s'\n", e);
   } else {
     StatusMsg("$DMD is undefined\n");
   }
 
   // Parse $DMD env var.
   gOptions = InfallibleAllocPolicy::new_<Options>(e);
 
-#ifdef XP_MACOSX
-  // On Mac OS X we need to call StackWalkInitCriticalAddress() very early
-  // (prior to the creation of any mutexes, apparently) otherwise we can get
-  // hangs when getting stack traces (bug 821577).  But
-  // StackWalkInitCriticalAddress() isn't exported from xpcom/, so instead we
-  // just call MozStackWalk, because that calls StackWalkInitCriticalAddress().
-  // See the comment above StackWalkInitCriticalAddress() for more details.
-  (void)MozStackWalk(NopStackWalkCallback, /* skipFrames */ 0,
-                     /* maxFrames */ 1, nullptr);
-#endif
-
   gStateLock = InfallibleAllocPolicy::new_<Mutex>();
 
   gBernoulli = (FastBernoulliTrial*)
     InfallibleAllocPolicy::malloc_(sizeof(FastBernoulliTrial));
   ResetBernoulli();
 
   DMD_CREATE_TLS_INDEX(gTlsIndex);
 
--- a/mozglue/misc/StackWalk.cpp
+++ b/mozglue/misc/StackWalk.cpp
@@ -10,25 +10,16 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/StackWalk.h"
 
 #include <string.h>
 
 using namespace mozilla;
 
-// The presence of this address is the stack must stop the stack walk. If
-// there is no such address, the structure will be {nullptr, true}.
-struct CriticalAddress
-{
-  void* mAddr;
-  bool mInit;
-};
-static CriticalAddress gCriticalAddress;
-
 // for _Unwind_Backtrace from libcxxrt or libunwind
 // cxxabi.h from libcxxrt implicitly includes unwind.h first
 #if defined(HAVE__UNWIND_BACKTRACE) && !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
 #endif
 
 #if defined(HAVE_DLOPEN) || defined(XP_DARWIN)
 #include <dlfcn.h>
@@ -60,137 +51,16 @@ extern MOZ_EXPORT void* __libc_stack_end
 #endif
 
 #ifdef ANDROID
 #include <algorithm>
 #include <unistd.h>
 #include <pthread.h>
 #endif
 
-#if MOZ_STACKWALK_SUPPORTS_MACOSX
-#include <pthread.h>
-#include <sys/errno.h>
-#ifdef MOZ_WIDGET_COCOA
-#include <CoreServices/CoreServices.h>
-#endif
-
-typedef void
-malloc_logger_t(uint32_t aType,
-                uintptr_t aArg1, uintptr_t aArg2, uintptr_t aArg3,
-                uintptr_t aResult, uint32_t aNumHotFramesToSkip);
-extern malloc_logger_t* malloc_logger;
-
-static void
-stack_callback(uint32_t aFrameNumber, void* aPc, void* aSp, void* aClosure)
-{
-  const char* name = static_cast<char*>(aClosure);
-  Dl_info info;
-
-  // On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
-  // stack shows up as having two pthread_cond_wait$UNIX2003 frames. The
-  // correct one is the first that we find on our way up, so the
-  // following check for gCriticalAddress.mAddr is critical.
-  if (gCriticalAddress.mAddr || dladdr(aPc, &info) == 0  ||
-      !info.dli_sname || strcmp(info.dli_sname, name) != 0) {
-    return;
-  }
-  gCriticalAddress.mAddr = aPc;
-}
-
-static void
-my_malloc_logger(uint32_t aType,
-                 uintptr_t aArg1, uintptr_t aArg2, uintptr_t aArg3,
-                 uintptr_t aResult, uint32_t aNumHotFramesToSkip)
-{
-  static bool once = false;
-  if (once) {
-    return;
-  }
-  once = true;
-
-  // On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
-  // stack shows up as having two pthread_cond_wait$UNIX2003 frames.
-  const char* name = "new_sem_from_pool";
-  MozStackWalk(stack_callback, /* skipFrames */ 0, /* maxFrames */ 0,
-               const_cast<char*>(name));
-}
-
-// This is called from NS_LogInit() and from the stack walking functions, but
-// only the first call has any effect.  We need to call this function from both
-// places because it must run before any mutexes are created, and also before
-// any objects whose refcounts we're logging are created.  Running this
-// function during NS_LogInit() ensures that we meet the first criterion, and
-// running this function during the stack walking functions ensures we meet the
-// second criterion.
-MFBT_API void
-StackWalkInitCriticalAddress()
-{
-  if (gCriticalAddress.mInit) {
-    return;
-  }
-  gCriticalAddress.mInit = true;
-  // We must not do work when 'new_sem_from_pool' calls realloc, since
-  // it holds a non-reentrant spin-lock and we will quickly deadlock.
-  // new_sem_from_pool is not directly accessible using dlsym, so
-  // we force a situation where new_sem_from_pool is on the stack and
-  // use dladdr to check the addresses.
-
-  // malloc_logger can be set by external tools like 'Instruments' or 'leaks'
-  malloc_logger_t* old_malloc_logger = malloc_logger;
-  malloc_logger = my_malloc_logger;
-
-  pthread_cond_t cond;
-  int r = pthread_cond_init(&cond, 0);
-  MOZ_ASSERT(r == 0);
-  pthread_mutex_t mutex;
-  r = pthread_mutex_init(&mutex, 0);
-  MOZ_ASSERT(r == 0);
-  r = pthread_mutex_lock(&mutex);
-  MOZ_ASSERT(r == 0);
-  struct timespec abstime = { 0, 1 };
-  r = pthread_cond_timedwait_relative_np(&cond, &mutex, &abstime);
-
-  // restore the previous malloc logger
-  malloc_logger = old_malloc_logger;
-
-  // XXX: the critical address machinery appears to have been unnecessary since
-  // Mac OS 10.7 (the minimum version we currently support is 10.9). See bug
-  // 1384814 for details.
-  MOZ_DIAGNOSTIC_ASSERT(!gCriticalAddress.mAddr);
-
-  MOZ_ASSERT(r == ETIMEDOUT);
-  r = pthread_mutex_unlock(&mutex);
-  MOZ_ASSERT(r == 0);
-  r = pthread_mutex_destroy(&mutex);
-  MOZ_ASSERT(r == 0);
-  r = pthread_cond_destroy(&cond);
-  MOZ_ASSERT(r == 0);
-}
-
-static bool
-IsCriticalAddress(void* aPC)
-{
-  return gCriticalAddress.mAddr == aPC;
-}
-#else
-static bool
-IsCriticalAddress(void* aPC)
-{
-  return false;
-}
-// We still initialize gCriticalAddress.mInit so that this code behaves
-// the same on all platforms. Otherwise a failure to init would be visible
-// only on OS X.
-MFBT_API void
-StackWalkInitCriticalAddress()
-{
-  gCriticalAddress.mInit = true;
-}
-#endif
-
 #if MOZ_STACKWALK_SUPPORTS_WINDOWS
 
 #include <windows.h>
 #include <process.h>
 #include <stdio.h>
 #include <malloc.h>
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
@@ -619,17 +489,16 @@ WalkStackThread(void* aData)
  * whose in memory address doesn't match its in-file address.
  */
 
 MFBT_API void
 MozStackWalkThread(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
                    uint32_t aMaxFrames, void* aClosure,
                    HANDLE aThread, CONTEXT* aContext)
 {
-  StackWalkInitCriticalAddress();
   static HANDLE myProcess = nullptr;
   HANDLE myThread;
   DWORD walkerReturn;
   struct WalkStackData data;
 
   InitializeDbgHelpCriticalSection();
 
   // EnsureWalkThreadReady's _beginthreadex takes a heap lock and must be
@@ -992,18 +861,16 @@ void DemangleSymbol(const char* aSymbol,
 // {x86, ppc} x {Linux, Mac} stackwalking code.
 #if ((defined(__i386) || defined(PPC) || defined(__ppc__)) && \
      (MOZ_STACKWALK_SUPPORTS_MACOSX || MOZ_STACKWALK_SUPPORTS_LINUX))
 
 MFBT_API void
 MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
              uint32_t aMaxFrames, void* aClosure)
 {
-  StackWalkInitCriticalAddress();
-
   // Get the frame pointer
   void** bp = (void**)__builtin_frame_address(0);
 
   void* stackEnd;
 #if HAVE___LIBC_STACK_END
   stackEnd = __libc_stack_end;
 #elif defined(XP_DARWIN)
   stackEnd = pthread_get_stackaddr_np(pthread_self());
@@ -1054,38 +921,31 @@ struct unwind_info
 };
 
 static _Unwind_Reason_Code
 unwind_callback(struct _Unwind_Context* context, void* closure)
 {
   unwind_info* info = static_cast<unwind_info*>(closure);
   void* pc = reinterpret_cast<void*>(_Unwind_GetIP(context));
   // TODO Use something like '_Unwind_GetGR()' to get the stack pointer.
-  if (IsCriticalAddress(pc)) {
-    // We just want to stop the walk, so any error code will do.  Using
-    // _URC_NORMAL_STOP would probably be the most accurate, but it is not
-    // defined on Android for ARM.
-    return _URC_FOREIGN_EXCEPTION_CAUGHT;
-  }
   if (--info->skip < 0) {
     info->numFrames++;
     (*info->callback)(info->numFrames, pc, nullptr, info->closure);
     if (info->maxFrames != 0 && info->numFrames == info->maxFrames) {
       // Again, any error code that stops the walk will do.
       return _URC_FOREIGN_EXCEPTION_CAUGHT;
     }
   }
   return _URC_NO_REASON;
 }
 
 MFBT_API void
 MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
              uint32_t aMaxFrames, void* aClosure)
 {
-  StackWalkInitCriticalAddress();
   unwind_info info;
   info.callback = aCallback;
   info.skip = aSkipFrames + 1;
   info.maxFrames = aMaxFrames;
   info.numFrames = 0;
   info.closure = aClosure;
 
   // We ignore the return value from _Unwind_Backtrace. There are three main
@@ -1188,19 +1048,16 @@ FramePointerStackWalk(MozWalkStackCallba
 #if (defined(__ppc__) && defined(XP_MACOSX)) || defined(__powerpc64__)
     // ppc mac or powerpc64 linux
     void* pc = *(aBp + 2);
     aBp += 3;
 #else // i386 or powerpc32 linux
     void* pc = *(aBp + 1);
     aBp += 2;
 #endif
-    if (IsCriticalAddress(pc)) {
-      return;
-    }
     if (--skip < 0) {
       // Assume that the SP points to the BP of the function
       // it called. We can't know the exact location of the SP
       // but this should be sufficient for our use the SP
       // to order elements on the stack.
       numFrames++;
       (*aCallback)(numFrames, pc, aBp, aClosure);
       if (aMaxFrames != 0 && numFrames == aMaxFrames) {
--- a/mozglue/misc/StackWalk.h
+++ b/mozglue/misc/StackWalk.h
@@ -169,16 +169,9 @@ namespace mozilla {
 
 MFBT_API void
 FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
                       uint32_t aMaxFrames, void* aClosure, void** aBp,
                       void* aStackEnd);
 
 } // namespace mozilla
 
-/**
- * Initialize the critical sections for this platform so that we can
- * abort stack walks when needed.
- */
-MFBT_API void
-StackWalkInitCriticalAddress(void);
-
 #endif
--- a/toolkit/components/crashes/CrashService.js
+++ b/toolkit/components/crashes/CrashService.js
@@ -45,16 +45,18 @@ function runMinidumpAnalyzer(minidumpPat
 
       exe.append(exeName);
 
       let args = [ minidumpPath ];
       let process = Cc["@mozilla.org/process/util;1"]
                       .createInstance(Ci.nsIProcess);
       process.init(exe);
       process.startHidden = true;
+      process.noShell = true;
+
       process.runAsync(args, args.length, (subject, topic, data) => {
         switch (topic) {
           case "process-finished":
             gRunningProcesses.delete(process);
             resolve();
             break;
           default:
             reject(new Error("Unexpected topic received " + topic));
--- a/toolkit/components/telemetry/TelemetrySend.jsm
+++ b/toolkit/components/telemetry/TelemetrySend.jsm
@@ -1337,11 +1337,12 @@ var TelemetrySendImpl = {
 
     let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile);
     exe.append(exeName);
 
     let process = Cc["@mozilla.org/process/util;1"]
                   .createInstance(Ci.nsIProcess);
     process.init(exe);
     process.startHidden = true;
+    process.noShell = true;
     process.run(/* blocking */ false, [url, pingPath], 2);
   },
 };
--- a/xpcom/base/nsTraceRefcnt.cpp
+++ b/xpcom/base/nsTraceRefcnt.cpp
@@ -916,17 +916,16 @@ WalkTheStackSavingLocations(std::vector<
 //----------------------------------------------------------------------
 
 EXPORT_XPCOM_API(void)
 NS_LogInit()
 {
   NS_SetMainThread();
 
   // FIXME: This is called multiple times, we should probably not allow that.
-  StackWalkInitCriticalAddress();
   if (++gInitCount) {
     nsTraceRefcnt::SetActivityIsLegal(true);
   }
 }
 
 EXPORT_XPCOM_API(void)
 NS_LogTerm()
 {
--- a/xpcom/threads/nsIProcess.idl
+++ b/xpcom/threads/nsIProcess.idl
@@ -77,16 +77,22 @@ interface nsIProcess : nsISupports
   /**
    * When set to true the process will not open a new window when started and
    * will run hidden from the user. This currently affects only the Windows
    * platform.
    */
   attribute boolean startHidden;
 
   /**
+   * When set to true the process will be launched directly without using the
+   * shell. This currently affects only the Windows platform.
+   */
+  attribute boolean noShell;
+
+  /**
    * The process identifier of the currently running process. This will only
    * be available after the process has started and may not be available on
    * some platforms.
    */
   readonly attribute unsigned long pid;
 
   /**
    * The exit value of the process. This is only valid after the process has
--- a/xpcom/threads/nsProcess.h
+++ b/xpcom/threads/nsProcess.h
@@ -58,16 +58,17 @@ private:
   nsresult RunProcess(bool aBlocking, char** aArgs, nsIObserver* aObserver,
                       bool aHoldWeak, bool aArgsUTF8);
 
   PRThread* mThread;
   mozilla::Mutex mLock;
   bool mShutdown;
   bool mBlocking;
   bool mStartHidden;
+  bool mNoShell;
 
   nsCOMPtr<nsIFile> mExecutable;
   nsString mTargetPath;
   int32_t mPid;
   nsCOMPtr<nsIObserver> mObserver;
   nsWeakPtr mWeakObserver;
 
   // These members are modified by multiple threads, any accesses should be
--- a/xpcom/threads/nsProcessCommon.cpp
+++ b/xpcom/threads/nsProcessCommon.cpp
@@ -28,16 +28,17 @@
 #include "GeckoProfiler.h"
 
 #include <stdlib.h>
 
 #if defined(PROCESSMODEL_WINAPI)
 #include "nsString.h"
 #include "nsLiteralString.h"
 #include "nsReadableUtils.h"
+#include "mozilla/UniquePtrExtensions.h"
 #else
 #ifdef XP_MACOSX
 #include <crt_externs.h>
 #include <spawn.h>
 #include <sys/wait.h>
 #include <sys/errno.h>
 #endif
 #include <sys/types.h>
@@ -67,16 +68,17 @@ NS_IMPL_ISUPPORTS(nsProcess, nsIProcess,
 
 //Constructor
 nsProcess::nsProcess()
   : mThread(nullptr)
   , mLock("nsProcess.mLock")
   , mShutdown(false)
   , mBlocking(false)
   , mStartHidden(false)
+  , mNoShell(false)
   , mPid(-1)
   , mObserver(nullptr)
   , mWeakObserver(nullptr)
   , mExitValue(-1)
 #if !defined(XP_MACOSX)
   , mProcess(nullptr)
 #endif
 {
@@ -461,56 +463,88 @@ nsProcess::RunProcess(bool aBlocking, ch
     }
   }
 
   mExitValue = -1;
   mPid = -1;
 
 #if defined(PROCESSMODEL_WINAPI)
   BOOL retVal;
-  wchar_t* cmdLine = nullptr;
+  UniqueFreePtr<wchar_t> cmdLine;
 
   // |aMyArgv| is null-terminated and always starts with the program path. If
   // the second slot is non-null then arguments are being passed.
-  if (aMyArgv[1] && assembleCmdLine(aMyArgv + 1, &cmdLine,
-                                    aArgsUTF8 ? CP_UTF8 : CP_ACP) == -1) {
-    return NS_ERROR_FILE_EXECUTION_FAILED;
-  }
+  if (aMyArgv[1] || mNoShell) {
+    // Pass the executable path as argv[0] to the launched program when calling
+    // CreateProcess().
+    char** argv = mNoShell ? aMyArgv : aMyArgv + 1;
 
-  /* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
-   * from appearing. This makes behavior the same on all platforms. The flag
-   * will not have any effect on non-console applications.
-   */
+    wchar_t* assembledCmdLine = nullptr;
+    if (assembleCmdLine(argv, &assembledCmdLine,
+                        aArgsUTF8 ? CP_UTF8 : CP_ACP) == -1) {
+      return NS_ERROR_FILE_EXECUTION_FAILED;
+    }
+    cmdLine.reset(assembledCmdLine);
+  }
 
   // The program name in aMyArgv[0] is always UTF-8
   NS_ConvertUTF8toUTF16 wideFile(aMyArgv[0]);
 
-  SHELLEXECUTEINFOW sinfo;
-  memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
-  sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
-  sinfo.hwnd   = nullptr;
-  sinfo.lpFile = wideFile.get();
-  sinfo.nShow  = mStartHidden ? SW_HIDE : SW_SHOWNORMAL;
-  sinfo.fMask  = SEE_MASK_FLAG_DDEWAIT |
-                 SEE_MASK_NO_CONSOLE |
-                 SEE_MASK_NOCLOSEPROCESS;
+  if (mNoShell) {
+    STARTUPINFO startupInfo;
+    ZeroMemory(&startupInfo, sizeof(startupInfo));
+    startupInfo.cb = sizeof(startupInfo);
+    startupInfo.dwFlags = STARTF_USESHOWWINDOW;
+    startupInfo.wShowWindow = mStartHidden ? SW_HIDE : SW_SHOWNORMAL;
+
+    PROCESS_INFORMATION processInfo;
+    retVal = CreateProcess(/* lpApplicationName = */ wideFile.get(),
+                           /* lpCommandLine */ cmdLine.get(),
+                           /* lpProcessAttributes = */ NULL,
+                           /* lpThreadAttributes = */ NULL,
+                           /* bInheritHandles = */ FALSE,
+                           /* dwCreationFlags = */ 0,
+                           /* lpEnvironment = */ NULL,
+                           /* lpCurrentDirectory = */ NULL,
+                           /* lpStartupInfo = */ &startupInfo,
+                           /* lpProcessInformation */ &processInfo);
+
+    if (!retVal) {
+      return NS_ERROR_FILE_EXECUTION_FAILED;
+    }
+
+    CloseHandle(processInfo.hThread);
 
-  if (cmdLine) {
-    sinfo.lpParameters = cmdLine;
-  }
+    mProcess = processInfo.hProcess;
+  } else {
+    SHELLEXECUTEINFOW sinfo;
+    memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
+    sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+    sinfo.hwnd   = nullptr;
+    sinfo.lpFile = wideFile.get();
+    sinfo.nShow  = mStartHidden ? SW_HIDE : SW_SHOWNORMAL;
 
-  retVal = ShellExecuteExW(&sinfo);
-  if (!retVal) {
-    return NS_ERROR_FILE_EXECUTION_FAILED;
-  }
+    /* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
+     * from appearing. This makes behavior the same on all platforms. The flag
+     * will not have any effect on non-console applications.
+     */
+    sinfo.fMask  = SEE_MASK_FLAG_DDEWAIT |
+                   SEE_MASK_NO_CONSOLE |
+                   SEE_MASK_NOCLOSEPROCESS;
 
-  mProcess = sinfo.hProcess;
+    if (cmdLine) {
+      sinfo.lpParameters = cmdLine.get();
+    }
 
-  if (cmdLine) {
-    free(cmdLine);
+    retVal = ShellExecuteExW(&sinfo);
+    if (!retVal) {
+      return NS_ERROR_FILE_EXECUTION_FAILED;
+    }
+
+    mProcess = sinfo.hProcess;
   }
 
   mPid = GetProcessId(mProcess);
 #elif defined(XP_MACOSX)
   // Initialize spawn attributes.
   posix_spawnattr_t spawnattr;
   if (posix_spawnattr_init(&spawnattr) != 0) {
     return NS_ERROR_FAILURE;
@@ -599,16 +633,30 @@ nsProcess::GetStartHidden(bool* aStartHi
 NS_IMETHODIMP
 nsProcess::SetStartHidden(bool aStartHidden)
 {
   mStartHidden = aStartHidden;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsProcess::GetNoShell(bool* aNoShell)
+{
+  *aNoShell = mNoShell;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsProcess::SetNoShell(bool aNoShell)
+{
+  mNoShell = aNoShell;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsProcess::GetPid(uint32_t* aPid)
 {
   if (!mThread) {
     return NS_ERROR_FAILURE;
   }
   if (mPid < 0) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }