Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 14 Jul 2017 17:14:43 -0700
changeset 420117 bd1b6a4e5d8e1184a89ae60a74fd86d3d4a9e95c
parent 420071 9ce83907a2bc83f47e393761b3990432005d8223 (current diff)
parent 420116 b292385f25f7621f56409342a964ce6c6973c7a4 (diff)
child 420118 6bb5782dfefa5ecb67ba04842c8d399c238a6513
child 420142 c3337a381ff45d5a586d870b15416c4f287efae4
child 420181 4272f49e842120d850d1b310eaee7a254e6f5c28
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone56.0a1
first release with
nightly linux32
bd1b6a4e5d8e / 56.0a1 / 20170715100214 / files
nightly linux64
bd1b6a4e5d8e / 56.0a1 / 20170715100214 / files
nightly mac
bd1b6a4e5d8e / 56.0a1 / 20170715100207 / files
nightly win32
bd1b6a4e5d8e / 56.0a1 / 20170715030206 / files
nightly win64
bd1b6a4e5d8e / 56.0a1 / 20170715030206 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to central, a=merge MozReview-Commit-ID: 8nlqm5dHCUQ
mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
toolkit/components/extensions/ExtensionParent.jsm
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # browser_506482.js is disabled because of frequent failures (bug 538672)
 # browser_526613.js is disabled because of frequent failures (bug 534489)
 # browser_589246.js is disabled for leaking browser windows (bug 752467)
 # browser_580512.js is disabled for leaking browser windows (bug 752467)
 
 [DEFAULT]
+skip-if = os == 'linux' && !e10s
 support-files =
   head.js
   content.js
   content-forms.js
   browser_formdata_sample.html
   browser_formdata_xpath_sample.html
   browser_frametree_sample.html
   browser_frametree_sample_frameset.html
--- a/browser/config/mozconfigs/macosx64/beta
+++ b/browser/config/mozconfigs/macosx64/beta
@@ -1,10 +1,10 @@
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
--- a/browser/config/mozconfigs/macosx64/devedition
+++ b/browser/config/mozconfigs/macosx64/devedition
@@ -1,10 +1,10 @@
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
--- a/browser/config/mozconfigs/macosx64/release
+++ b/browser/config/mozconfigs/macosx64/release
@@ -1,13 +1,13 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -70,33 +70,31 @@ whitelist['nightly']['win64'] += [
 
 for platform in all_platforms:
     whitelist['release'][platform] = [
         'ac_add_options --enable-update-channel=release',
         'ac_add_options --enable-official-branding',
         'mk_add_options MOZ_MAKE_FLAGS="-j4"',
         'export BUILDING_RELEASE=1',
         'if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then',
-        'MOZ_AUTOMATION_UPLOAD_SYMBOLS=1',
+        'MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}',
         'MOZ_AUTOMATION_UPDATE_PACKAGING=1',
         'fi',
     ]
 whitelist['release']['win32'] += ['mk_add_options MOZ_PGO=1']
 whitelist['release']['win64'] += ['mk_add_options MOZ_PGO=1']
 
 whitelist['release']['linux32'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     'mk_add_options MOZ_PGO=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
-    'MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}',
 ]
 whitelist['release']['linux64'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     'mk_add_options MOZ_PGO=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
-    'MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}',
 ]
 
 if __name__ == '__main__':
     import pprint
     pprint.pprint(whitelist)
--- a/browser/config/mozconfigs/win32/beta
+++ b/browser/config/mozconfigs/win32/beta
@@ -1,10 +1,10 @@
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 mk_add_options MOZ_PGO=1
 
--- a/browser/config/mozconfigs/win32/devedition
+++ b/browser/config/mozconfigs/win32/devedition
@@ -1,10 +1,10 @@
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -1,13 +1,13 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 mk_add_options MOZ_PGO=1
 
--- a/browser/config/mozconfigs/win64/beta
+++ b/browser/config/mozconfigs/win64/beta
@@ -1,10 +1,10 @@
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 mk_add_options MOZ_PGO=1
--- a/browser/config/mozconfigs/win64/devedition
+++ b/browser/config/mozconfigs/win64/devedition
@@ -1,10 +1,10 @@
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 # Add-on signing is not required for DevEdition
--- a/browser/config/mozconfigs/win64/release
+++ b/browser/config/mozconfigs/win64/release
@@ -1,13 +1,13 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
+  MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 mk_add_options MOZ_PGO=1
--- a/devtools/client/jsonview/components/json-panel.js
+++ b/devtools/client/jsonview/components/json-panel.js
@@ -111,28 +111,26 @@ define(function (require, exports, modul
         expandedNodes: expandedNodes,
       });
     },
 
     render: function () {
       let content;
       let data = this.props.data;
 
-      try {
-        if (isObject(data)) {
-          content = this.renderTree();
-        } else {
-          content = div({className: "jsonParseError"},
-            data + ""
-          );
-        }
-      } catch (err) {
+      if (!isObject(data)) {
+        content = div({className: "jsonPrimitiveValue"}, Rep({
+          object: data
+        }));
+      } else if (data instanceof Error) {
         content = div({className: "jsonParseError"},
-          err + ""
+          data + ""
         );
+      } else {
+        content = this.renderTree();
       }
 
       return (
         div({className: "jsonPanelBox tab-panel-inner"},
           JsonToolbar({actions: this.props.actions}),
           div({className: "panelContent"},
             content
           )
--- a/devtools/client/jsonview/css/json-panel.css
+++ b/devtools/client/jsonview/css/json-panel.css
@@ -1,15 +1,19 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /******************************************************************************/
 /* JSON Panel */
 
+.jsonPrimitiveValue,
 .jsonParseError {
   font-size: 12px;
   font-family: Lucida Grande, Tahoma, sans-serif;
   line-height: 15px;
   padding: 10px;
+}
+
+.jsonParseError {
   color: red;
 }
--- a/devtools/client/jsonview/json-viewer.js
+++ b/devtools/client/jsonview/json-viewer.js
@@ -14,17 +14,17 @@ define(function (require, exports, modul
   const json = document.getElementById("json");
 
   let jsonData;
   let prettyURL;
 
   try {
     jsonData = JSON.parse(json.textContent);
   } catch (err) {
-    jsonData = err + "";
+    jsonData = err;
   }
 
   // Application state object.
   let input = {
     jsonText: json.textContent,
     jsonPretty: null,
     json: jsonData,
     headers: JSONView.headers,
@@ -54,16 +54,20 @@ define(function (require, exports, modul
       dispatchEvent("copy-headers", input.headers);
     },
 
     onSearch: function (value) {
       theApp.setState({searchFilter: value});
     },
 
     onPrettify: function (data) {
+      if (jsonData instanceof Error) {
+        // Cannot prettify invalid JSON
+        return;
+      }
       if (input.prettified) {
         theApp.setState({jsonText: input.jsonText});
       } else {
         if (!input.jsonPretty) {
           input.jsonPretty = JSON.stringify(jsonData, null, "  ");
         }
         theApp.setState({jsonText: input.jsonPretty});
       }
--- a/dom/file/FileReader.cpp
+++ b/dom/file/FileReader.cpp
@@ -368,32 +368,40 @@ FileReader::ReadFileContent(Blob& aBlob,
   mTotal = 0;
   mReadyState = EMPTY;
   FreeFileData();
 
   mBlob = &aBlob;
   mDataFormat = aDataFormat;
   CopyUTF16toUTF8(aCharset, mCharset);
 
-  nsresult rv;
-  nsCOMPtr<nsIStreamTransportService> sts =
-    do_GetService(kStreamTransportServiceCID, &rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(rv);
-    return;
-  }
-
   nsCOMPtr<nsIInputStream> stream;
   mBlob->GetInternalStream(getter_AddRefs(stream), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
+  bool nonBlocking = false;
+  aRv = stream->IsNonBlocking(&nonBlocking);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
   mAsyncStream = do_QueryInterface(stream);
-  if (!mAsyncStream) {
+
+  // We want to have a non-blocking nsIAsyncInputStream.
+  if (!mAsyncStream || !nonBlocking) {
+    nsresult rv;
+    nsCOMPtr<nsIStreamTransportService> sts =
+      do_GetService(kStreamTransportServiceCID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aRv.Throw(rv);
+      return;
+    }
+
     nsCOMPtr<nsITransport> transport;
     aRv = sts->CreateInputTransport(stream,
                                     /* aStartOffset */ 0,
                                     /* aReadLimit */ -1,
                                     /* aCloseWhenDone */ true,
                                     getter_AddRefs(transport));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -577,18 +577,20 @@ public:
   uint32_t mBufferEnd;
   uint32_t mLoopStart;
   uint32_t mLoopEnd;
   uint32_t mBufferPosition;
   int32_t mBufferSampleRate;
   int32_t mResamplerOutRate;
   uint32_t mChannels;
   float mDopplerShift;
-  AudioNodeStream* mDestination;
-  AudioNodeStream* mSource;
+  RefPtr<AudioNodeStream> mDestination;
+
+  // mSource deletes the engine in its destructor.
+  AudioNodeStream* MOZ_NON_OWNING_REF mSource;
   AudioParamTimeline mPlaybackRateTimeline;
   AudioParamTimeline mDetuneTimeline;
   bool mLoop;
 };
 
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
   : AudioScheduledSourceNode(aContext,
                              2,
--- a/dom/media/webaudio/AudioNode.h
+++ b/dom/media/webaudio/AudioNode.h
@@ -172,18 +172,18 @@ public:
       size_t amount = 0;
       if (mStreamPort) {
         amount += mStreamPort->SizeOfIncludingThis(aMallocSizeOf);
       }
 
       return amount;
     }
 
-    // Weak reference.
-    AudioNode* mInputNode;
+    // The InputNode is destroyed when mInputNode is disconnected.
+    AudioNode* MOZ_NON_OWNING_REF mInputNode;
     RefPtr<MediaInputPort> mStreamPort;
     // The index of the input port this node feeds into.
     // This is not used for connections to AudioParams.
     uint32_t mInputPort;
     // The index of the output port this node comes out of.
     uint32_t mOutputPort;
   };
 
--- a/dom/media/webaudio/AudioNodeEngine.h
+++ b/dom/media/webaudio/AudioNodeEngine.h
@@ -388,17 +388,18 @@ public:
   void SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                            AudioNodeSizes& aUsage) const
   {
     aUsage.mEngine = SizeOfIncludingThis(aMallocSizeOf);
     aUsage.mNodeType = mNodeType;
   }
 
 private:
-  dom::AudioNode* mNode; // main thread only
+  // This is cleared from AudioNode::DestroyMediaStream()
+  dom::AudioNode* MOZ_NON_OWNING_REF mNode; // main thread only
   const char* const mNodeType;
   const uint16_t mInputCount;
   const uint16_t mOutputCount;
 
 protected:
   const RefPtr<AbstractThread> mAbstractMainThread;
 };
 
--- a/dom/media/webaudio/AudioNodeStream.cpp
+++ b/dom/media/webaudio/AudioNodeStream.cpp
@@ -139,17 +139,19 @@ AudioNodeStream::SetStreamTimeParameter(
         mRelativeToStream(aRelativeToStream), mIndex(aIndex)
     {}
     void Run() override
     {
       static_cast<AudioNodeStream*>(mStream)->
           SetStreamTimeParameterImpl(mIndex, mRelativeToStream, mStreamTime);
     }
     double mStreamTime;
-    MediaStream* mRelativeToStream;
+    MediaStream* MOZ_UNSAFE_REF("ControlMessages are processed in order.  This \
+destination stream is not yet destroyed.  Its (future) destroy message will be \
+processed after this message.") mRelativeToStream;
     uint32_t mIndex;
   };
 
   GraphImpl()->AppendMessage(MakeUnique<Message>(this, aIndex,
                                                  aContext->DestinationStream(),
                                                  aStreamTime));
 }
 
--- a/dom/media/webaudio/BiquadFilterNode.cpp
+++ b/dom/media/webaudio/BiquadFilterNode.cpp
@@ -229,17 +229,17 @@ public:
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
 private:
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   BiquadFilterType mType;
   AudioParamTimeline mFrequency;
   AudioParamTimeline mDetune;
   AudioParamTimeline mQ;
   AudioParamTimeline mGain;
   nsTArray<WebCore::Biquad> mBiquads;
   uint64_t mWindowID;
 };
--- a/dom/media/webaudio/ConstantSourceNode.cpp
+++ b/dom/media/webaudio/ConstantSourceNode.cpp
@@ -129,18 +129,19 @@ public:
     return amount;
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
-  AudioNodeStream* mSource;
-  AudioNodeStream* mDestination;
+  // mSource deletes the engine in its destructor.
+  AudioNodeStream* MOZ_NON_OWNING_REF mSource;
+  RefPtr<AudioNodeStream> mDestination;
   StreamTime mStart;
   StreamTime mStop;
   AudioParamTimeline mOffset;
 };
 
 ConstantSourceNode::ConstantSourceNode(AudioContext* aContext)
   : AudioScheduledSourceNode(aContext,
                              1,
--- a/dom/media/webaudio/DelayNode.cpp
+++ b/dom/media/webaudio/DelayNode.cpp
@@ -176,17 +176,17 @@ public:
     return amount;
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   AudioParamTimeline mDelay;
   DelayBuffer mBuffer;
   double mMaxDelay;
   bool mHaveProducedBeforeInput;
   // How much data we have in our buffer which needs to be flushed out when our inputs
   // finish.
   int32_t mLeftOverData;
 };
--- a/dom/media/webaudio/DynamicsCompressorNode.cpp
+++ b/dom/media/webaudio/DynamicsCompressorNode.cpp
@@ -169,17 +169,17 @@ private:
       RefPtr<AudioNodeStream> mStream;
       float mReduction;
     };
 
     mAbstractMainThread->Dispatch(do_AddRef(new Command(aStream, aReduction)));
   }
 
 private:
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   AudioParamTimeline mThreshold;
   AudioParamTimeline mKnee;
   AudioParamTimeline mRatio;
   AudioParamTimeline mAttack;
   AudioParamTimeline mRelease;
   nsAutoPtr<DynamicsCompressor> mCompressor;
 };
 
--- a/dom/media/webaudio/GainNode.cpp
+++ b/dom/media/webaudio/GainNode.cpp
@@ -96,27 +96,27 @@ public:
         AudioBlockCopyChannelWithScale(inputBuffer, alignedComputedGain, buffer);
       }
     }
   }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     // Not owned:
-    // - mDestination (probably)
+    // - mDestination - MediaStreamGraphImpl::CollectSizesForMemoryReport() accounts for mDestination.
     // - mGain - Internal ref owned by AudioNode
     return AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   AudioParamTimeline mGain;
 };
 
 GainNode::GainNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
--- a/dom/media/webaudio/IIRFilterNode.cpp
+++ b/dom/media/webaudio/IIRFilterNode.cpp
@@ -120,17 +120,17 @@ public:
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
 private:
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   nsTArray<nsAutoPtr<blink::IIRFilter>> mIIRFilters;
   AudioDoubleArray mFeedforward;
   AudioDoubleArray mFeedback;
   uint64_t mWindowID;
 };
 
 IIRFilterNode::IIRFilterNode(AudioContext* aContext,
                              const Sequence<double>& aFeedforward,
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -384,18 +384,19 @@ public:
     return amount;
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
-  AudioNodeStream* mSource;
-  AudioNodeStream* mDestination;
+  // mSource deletes this engine in its destructor
+  AudioNodeStream* MOZ_NON_OWNING_REF mSource;
+  RefPtr<AudioNodeStream> mDestination;
   StreamTime mStart;
   StreamTime mStop;
   AudioParamTimeline mFrequency;
   AudioParamTimeline mDetune;
   OscillatorType mType;
   float mPhase;
   float mFinalFrequency;
   float mPhaseIncrement;
--- a/dom/media/webaudio/PannerNode.cpp
+++ b/dom/media/webaudio/PannerNode.cpp
@@ -257,17 +257,17 @@ public:
     return amount;
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   // This member is set on the main thread, but is not accessed on the rendering
   // thread untile mPanningModelFunction has changed, and this happens strictly
   // later, via a MediaStreamGraph ControlMessage.
   nsAutoPtr<HRTFPanner> mHRTFPanner;
   typedef void (PannerNodeEngine::*PanningModelFunction)(const AudioBlock& aInput, AudioBlock* aOutput, StreamTime tick);
   PanningModelFunction mPanningModelFunction;
   typedef float (PannerNodeEngine::*DistanceModelFunction)(double aDistance);
   DistanceModelFunction mDistanceModelFunction;
--- a/dom/media/webaudio/ScriptProcessorNode.cpp
+++ b/dom/media/webaudio/ScriptProcessorNode.cpp
@@ -471,17 +471,17 @@ private:
 
     RefPtr<Command> command = new Command(aStream, mInputBuffer.forget(),
                                           playbackTime);
     mAbstractMainThread->Dispatch(command.forget());
   }
 
   friend class ScriptProcessorNode;
 
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   nsAutoPtr<SharedBuffers> mSharedBuffers;
   RefPtr<ThreadSharedFloatArrayBufferList> mInputBuffer;
   const uint32_t mBufferSize;
   const uint32_t mInputChannelCount;
   // The write index into the current input buffer
   uint32_t mInputWriteIndex;
   bool mIsConnected = false;
 };
--- a/dom/media/webaudio/StereoPannerNode.cpp
+++ b/dom/media/webaudio/StereoPannerNode.cpp
@@ -161,17 +161,17 @@ public:
     }
   }
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
-  AudioNodeStream* mDestination;
+  RefPtr<AudioNodeStream> mDestination;
   AudioParamTimeline mPan;
 };
 
 StereoPannerNode::StereoPannerNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Clamped_max,
               ChannelInterpretation::Speakers)
--- a/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
+++ b/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
@@ -117,17 +117,18 @@ public:
   {
   }
   NS_IMETHOD Run() override
   {
     mLoader->MainThreadRelease();
     return NS_OK;
     }
 private:
-    HRTFDatabaseLoader* mLoader;
+    // Ownership transferred by ProxyRelease
+    HRTFDatabaseLoader* MOZ_OWNING_REF mLoader;
 };
 
 void HRTFDatabaseLoader::ProxyRelease()
 {
     nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
     if (MOZ_LIKELY(mainTarget)) {
         RefPtr<ProxyReleaseEvent> event = new ProxyReleaseEvent(this);
         DebugOnly<nsresult> rv =
--- a/dom/media/webaudio/blink/HRTFDatabaseLoader.h
+++ b/dom/media/webaudio/blink/HRTFDatabaseLoader.h
@@ -121,17 +121,18 @@ private:
         {
         }
 
         size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
         {
             return mLoader ? mLoader->sizeOfIncludingThis(aMallocSizeOf) : 0;
         }
 
-        HRTFDatabaseLoader* mLoader;
+        // The HRTFDatabaseLoader removes itself from s_loaderMap on destruction.
+        HRTFDatabaseLoader* MOZ_NON_OWNING_REF mLoader;
     };
 
     // Keeps track of loaders on a per-sample-rate basis.
     static nsTHashtable<LoaderByRateEntry> *s_loaderMap; // singleton
 
     mozilla::Atomic<int> m_refCnt;
 
     nsAutoRef<HRTFDatabase> m_hrtfDatabase;
--- a/dom/webauthn/U2FHIDTokenManager.cpp
+++ b/dom/webauthn/U2FHIDTokenManager.cpp
@@ -34,17 +34,18 @@ U2FHIDTokenManager::~U2FHIDTokenManager(
 // 1      key handle length
 // *      key handle
 // ASN.1  attestation certificate
 // *      attestation signature
 //
 RefPtr<U2FRegisterPromise>
 U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                              const nsTArray<uint8_t>& aApplication,
-                             const nsTArray<uint8_t>& aChallenge)
+                             const nsTArray<uint8_t>& aChallenge,
+                             uint32_t aTimeoutMS)
 {
   return U2FRegisterPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
 }
 
 // A U2F Sign operation creates a signature over the "param" arguments (plus
 // some other stuff) using the private key indicated in the key handle argument.
 //
 // The format of the signed data is as follows:
@@ -58,17 +59,18 @@ U2FHIDTokenManager::Register(const nsTAr
 //
 //  1     User presence
 //  4     Counter
 //  *     Signature
 //
 RefPtr<U2FSignPromise>
 U2FHIDTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                          const nsTArray<uint8_t>& aApplication,
-                         const nsTArray<uint8_t>& aChallenge)
+                         const nsTArray<uint8_t>& aChallenge,
+                         uint32_t aTimeoutMS)
 {
   return U2FSignPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
 }
 
 void
 U2FHIDTokenManager::Cancel()
 {
 }
--- a/dom/webauthn/U2FHIDTokenManager.h
+++ b/dom/webauthn/U2FHIDTokenManager.h
@@ -20,22 +20,24 @@ namespace dom {
 class U2FHIDTokenManager final : public U2FTokenTransport
 {
 public:
   explicit U2FHIDTokenManager();
 
   virtual RefPtr<U2FRegisterPromise>
   Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
            const nsTArray<uint8_t>& aApplication,
-           const nsTArray<uint8_t>& aChallenge) override;
+           const nsTArray<uint8_t>& aChallenge,
+           uint32_t aTimeoutMS) override;
 
   virtual RefPtr<U2FSignPromise>
   Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
        const nsTArray<uint8_t>& aApplication,
-       const nsTArray<uint8_t>& aChallenge) override;
+       const nsTArray<uint8_t>& aChallenge,
+       uint32_t aTimeoutMS) override;
 
   void Cancel() override;
 
 private:
   ~U2FHIDTokenManager();
 };
 
 } // namespace dom
--- a/dom/webauthn/U2FSoftTokenManager.cpp
+++ b/dom/webauthn/U2FSoftTokenManager.cpp
@@ -631,17 +631,18 @@ U2FSoftTokenManager::IsRegistered(const 
 // 1      key handle length
 // *      key handle
 // ASN.1  attestation certificate
 // *      attestation signature
 //
 RefPtr<U2FRegisterPromise>
 U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                               const nsTArray<uint8_t>& aApplication,
-                              const nsTArray<uint8_t>& aChallenge)
+                              const nsTArray<uint8_t>& aChallenge,
+                              uint32_t aTimeoutMS)
 {
   nsNSSShutDownPreventionLock locker;
   if (NS_WARN_IF(isAlreadyShutDown())) {
     return U2FRegisterPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
   }
 
   if (!mInitialized) {
     nsresult rv = Init();
@@ -754,17 +755,18 @@ U2FSoftTokenManager::Register(const nsTA
 //
 //  1     User presence
 //  4     Counter
 //  *     Signature
 //
 RefPtr<U2FSignPromise>
 U2FSoftTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                           const nsTArray<uint8_t>& aApplication,
-                          const nsTArray<uint8_t>& aChallenge)
+                          const nsTArray<uint8_t>& aChallenge,
+                          uint32_t aTimeoutMS)
 {
   nsNSSShutDownPreventionLock locker;
   if (NS_WARN_IF(isAlreadyShutDown())) {
     return U2FSignPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
   }
 
   nsTArray<uint8_t> keyHandle;
   for (auto desc: aDescriptors) {
--- a/dom/webauthn/U2FSoftTokenManager.h
+++ b/dom/webauthn/U2FSoftTokenManager.h
@@ -23,22 +23,24 @@ class U2FSoftTokenManager final : public
                                   public nsNSSShutDownObject
 {
 public:
   explicit U2FSoftTokenManager(uint32_t aCounter);
 
   virtual RefPtr<U2FRegisterPromise>
   Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
            const nsTArray<uint8_t>& aApplication,
-           const nsTArray<uint8_t>& aChallenge) override;
+           const nsTArray<uint8_t>& aChallenge,
+           uint32_t aTimeoutMS) override;
 
   virtual RefPtr<U2FSignPromise>
   Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
        const nsTArray<uint8_t>& aApplication,
-       const nsTArray<uint8_t>& aChallenge) override;
+       const nsTArray<uint8_t>& aChallenge,
+       uint32_t aTimeoutMS) override;
 
   virtual void Cancel() override;
 
   // For nsNSSShutDownObject
   virtual void virtualDestroyNSSReference() override;
   void destructorSafeDestroyNSSReference();
 
 private:
--- a/dom/webauthn/U2FTokenManager.cpp
+++ b/dom/webauthn/U2FTokenManager.cpp
@@ -249,17 +249,18 @@ U2FTokenManager::Register(WebAuthnTransa
   if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
       (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
     AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
     return;
   }
 
   mRegisterPromise = mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
                                                  aTransactionInfo.RpIdHash(),
-                                                 aTransactionInfo.ClientDataHash());
+                                                 aTransactionInfo.ClientDataHash(),
+                                                 aTransactionInfo.TimeoutMS());
 
   mRegisterPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
                          [tid](U2FRegisterResult&& aResult) {
                            U2FTokenManager* mgr = U2FTokenManager::Get();
                            mgr->MaybeConfirmRegister(tid, aResult);
                          },
                          [tid](nsresult rv) {
                            MOZ_ASSERT(NS_FAILED(rv));
@@ -302,17 +303,18 @@ U2FTokenManager::Sign(WebAuthnTransactio
   if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
       (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
     AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
     return;
   }
 
   mSignPromise = mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
                                          aTransactionInfo.RpIdHash(),
-                                         aTransactionInfo.ClientDataHash());
+                                         aTransactionInfo.ClientDataHash(),
+                                         aTransactionInfo.TimeoutMS());
 
   mSignPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
                      [tid](U2FSignResult&& aResult) {
                        U2FTokenManager* mgr = U2FTokenManager::Get();
                        mgr->MaybeConfirmSign(tid, aResult);
                      },
                      [tid](nsresult rv) {
                        MOZ_ASSERT(NS_FAILED(rv));
--- a/dom/webauthn/U2FTokenTransport.h
+++ b/dom/webauthn/U2FTokenTransport.h
@@ -60,22 +60,24 @@ class U2FTokenTransport
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(U2FTokenTransport);
   U2FTokenTransport() {}
 
   virtual RefPtr<U2FRegisterPromise>
   Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
            const nsTArray<uint8_t>& aApplication,
-           const nsTArray<uint8_t>& aChallenge) = 0;
+           const nsTArray<uint8_t>& aChallenge,
+           uint32_t aTimeoutMS) = 0;
 
   virtual RefPtr<U2FSignPromise>
   Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
        const nsTArray<uint8_t>& aApplication,
-       const nsTArray<uint8_t>& aChallenge) = 0;
+       const nsTArray<uint8_t>& aChallenge,
+       uint32_t aTimeoutMS) = 0;
 
   virtual void Cancel() = 0;
 
 protected:
   virtual ~U2FTokenTransport() = default;
 };
 
 } // namespace dom
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/file_bug611182.html
@@ -0,0 +1,1 @@
+<html><body>foo bar</body></html>
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/file_bug611182.sjs
@@ -0,0 +1,240 @@
+// SJS file for test_bug611182.html
+"use strict";
+
+const TESTS = [
+  {
+    ct: "text/html",
+    val: "<html contenteditable>fooz bar</html>",
+  },
+  {
+    ct: "text/html",
+    val: "<html contenteditable><body>fooz bar</body></html>",
+  },
+  {
+    ct: "text/html",
+    val: "<body contenteditable>fooz bar</body>",
+  },
+  {
+    ct: "text/html",
+    val: "<body contenteditable><p>fooz bar</p></body>",
+  },
+  {
+    ct: "text/html",
+    val: "<body contenteditable><div>fooz bar</div></body>",
+  },
+  {
+    ct: "text/html",
+    val: "<body contenteditable><span>fooz bar</span></body>",
+  },
+  {
+    ct: "text/html",
+    val: "<p contenteditable style='outline:none'>fooz bar</p>",
+  },
+  {
+    ct: "text/html",
+    val: "<!DOCTYPE html><html><body contenteditable>fooz bar</body></html>",
+  },
+  {
+    ct: "text/html",
+    val: "<!DOCTYPE html><html contenteditable><body>fooz bar</body></html>",
+  },
+  {
+    ct: "application/xhtml+xml",
+    val: '<html xmlns="http://www.w3.org/1999/xhtml"><body contenteditable="true">fooz bar</body></html>',
+  },
+  {
+    ct: "application/xhtml+xml",
+    val: '<html xmlns="http://www.w3.org/1999/xhtml" contenteditable="true"><body>fooz bar</body></html>',
+  },
+  {
+    ct: "text/html",
+    val: "<body onload=\"document.designMode='on'\">fooz bar</body>",
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'var old = document.body;' +
+            'old.parentNode.removeChild(old);' +
+            'var r = document.documentElement;' +
+            'var b = document.createElement("body");' +
+            'r.appendChild(b);' +
+            'b.appendChild(document.createTextNode("fooz bar"));' +
+            'b.contentEditable = "true";' +
+         '};' +
+        '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+           'onload = function() {' +
+             'var old = document.body;' +
+             'old.parentNode.removeChild(old);' +
+             'var r = document.documentElement;' +
+             'var b = document.createElement("body");' +
+             'b.appendChild(document.createTextNode("fooz bar"));' +
+             'b.contentEditable = "true";' +
+             'r.appendChild(b);' +
+           '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'var old = document.body;' +
+            'old.parentNode.removeChild(old);' +
+            'var r = document.documentElement;' +
+            'var b = document.createElement("body");' +
+            'r.appendChild(b);' +
+            'b.appendChild(document.createTextNode("fooz bar"));' +
+            'b.setAttribute("contenteditable", "true");' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'var old = document.body;' +
+            'old.parentNode.removeChild(old);' +
+            'var r = document.documentElement;' +
+            'var b = document.createElement("body");' +
+            'b.appendChild(document.createTextNode("fooz bar"));' +
+            'b.setAttribute("contenteditable", "true");' +
+            'r.appendChild(b);' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+           'onload = function() {' +
+             'var old = document.body;' +
+             'old.parentNode.removeChild(old);' +
+             'var r = document.documentElement;' +
+             'var b = document.createElement("body");' +
+             'r.appendChild(b);' +
+             'b.contentEditable = "true";' +
+             'b.appendChild(document.createTextNode("fooz bar"));' +
+           '};' +
+          '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'var old = document.body;' +
+            'old.parentNode.removeChild(old);' +
+            'var r = document.documentElement;' +
+            'var b = document.createElement("body");' +
+            'b.contentEditable = "true";' +
+            'r.appendChild(b);' +
+            'b.appendChild(document.createTextNode("fooz bar"));' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'var old = document.body;' +
+            'old.parentNode.removeChild(old);' +
+            'var r = document.documentElement;' +
+            'var b = document.createElement("body");' +
+            'r.appendChild(b);' +
+            'b.setAttribute("contenteditable", "true");' +
+            'b.appendChild(document.createTextNode("fooz bar"));' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'var old = document.body;' +
+            'old.parentNode.removeChild(old);' +
+            'var r = document.documentElement;' +
+            'var b = document.createElement("body");' +
+            'b.setAttribute("contenteditable", "true");' +
+            'r.appendChild(b);' +
+            'b.appendChild(document.createTextNode("fooz bar"));' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'document.open();' +
+            'document.write("<body contenteditable>fooz bar</body>");' +
+            'document.close();' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: 'data:text/html,<html><script>' +
+          'onload = function() {' +
+            'document.open();' +
+            'document.write("<body contenteditable><div>fooz bar</div></body>");' +
+            'document.close();' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'document.open();' +
+            'document.write("<body contenteditable><span>fooz bar</span></body>");' +
+            'document.close();' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'document.open();' +
+            'document.write("<p contenteditable style=\\"outline: none\\">fooz bar</p>");' +
+            'document.close();' +
+           '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'document.open();' +
+            'document.write("<html contenteditable>fooz bar</html>");' +
+            'document.close();' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+  {
+    ct: "text/html",
+    val: '<html><script>' +
+          'onload = function() {' +
+            'document.open();' +
+            'document.write("<html contenteditable><body>fooz bar</body></html>");' +
+            'document.close();' +
+          '};' +
+         '<\/script><body></body></html>',
+  },
+];
+
+function handleRequest(request, response) {
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  let query = request.queryString;
+  if (query === "queryTotalTests") {
+    response.setHeader("Content-Type", "text/html", false);
+    response.write(TESTS.length);
+    return;
+  }
+
+  var curTest = TESTS[query];
+  response.setHeader("Content-Type", curTest.ct, false);
+  response.write(curTest.val);
+}
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/file_bug795418-2.sjs
@@ -0,0 +1,8 @@
+// SJS file for test_bug795418-2.html
+"use strict";
+
+function handleRequest(request, response) {
+  response.setHeader("Cache-Control", "no-cache", false);
+  response.setHeader("Content-Type", "application/xhtml+xml", false);
+  response.write("<html contenteditable='' xmlns='http://www.w3.org/1999/xhtml'><span>AB</span></html>");
+}
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -2,17 +2,20 @@
 support-files =
   data/cfhtml-chromium.txt
   data/cfhtml-firefox.txt
   data/cfhtml-ie.txt
   data/cfhtml-ooo.txt
   data/cfhtml-nocontext.txt
   file_bug549262.html
   file_bug586662.html
+  file_bug611182.html
+  file_bug611182.sjs
   file_bug674770-1.html
+  file_bug795418-2.sjs
   file_bug915962.html
   file_select_all_without_body.html
   green.png
   spellcheck.js
 
 [test_bug46555.html]
 [test_bug200416.html]
 [test_bug289384.html]
--- a/editor/libeditor/tests/test_bug611182.html
+++ b/editor/libeditor/tests/test_bug611182.html
@@ -10,17 +10,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=611182">Mozilla Bug 611182</a>
 <p id="display"></p>
 <div id="content">
   <iframe></iframe>
-  <iframe id="ref" src="data:text/html,foo bar"></iframe>
+  <iframe id="ref" src="./file_bug611182.html"></iframe>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 611182 **/
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function() {
   var iframe = document.querySelector("iframe");
@@ -70,168 +70,35 @@ SimpleTest.waitForFocus(function() {
 
       var snapshot = snapshotWindow(win, false);
       ok(compareSnapshots(snapshot, ref, true)[0], "No bogus node should exist in the document");
 
       callback();
     }, {once: true});
     iframe.src = src;
   }
-
-  const TEST_URIS = [
-    "data:text/html,<html contenteditable>fooz bar</html>",
-    "data:text/html,<html contenteditable><body>fooz bar</body></html>",
-    "data:text/html,<body contenteditable>fooz bar</body>",
-    "data:text/html,<body contenteditable><p>fooz bar</p></body>",
-    "data:text/html,<body contenteditable><div>fooz bar</div></body>",
-    "data:text/html,<body contenteditable><span>fooz bar</span></body>",
-    "data:text/html,<p contenteditable style='outline:none'>fooz bar</p>",
-    "data:text/html,<!DOCTYPE html><html><body contenteditable>fooz bar</body></html>",
-    "data:text/html,<!DOCTYPE html><html contenteditable><body>fooz bar</body></html>",
-    'data:application/xhtml+xml,<html xmlns="http://www.w3.org/1999/xhtml"><body contenteditable="true">fooz bar</body></html>',
-    'data:application/xhtml+xml,<html xmlns="http://www.w3.org/1999/xhtml" contenteditable="true"><body>fooz bar</body></html>',
-    "data:text/html,<body onload=\"document.designMode='on'\">fooz bar</body>",
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'r.appendChild(b);' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                       'b.contentEditable = "true";' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                       'b.contentEditable = "true";' +
-                       'r.appendChild(b);' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'r.appendChild(b);' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                       'b.setAttribute("contenteditable", "true");' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                       'b.setAttribute("contenteditable", "true");' +
-                       'r.appendChild(b);' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'r.appendChild(b);' +
-                       'b.contentEditable = "true";' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'b.contentEditable = "true";' +
-                       'r.appendChild(b);' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'r.appendChild(b);' +
-                       'b.setAttribute("contenteditable", "true");' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'var old = document.body;' +
-                       'old.parentNode.removeChild(old);' +
-                       'var r = document.documentElement;' +
-                       'var b = document.createElement("body");' +
-                       'b.setAttribute("contenteditable", "true");' +
-                       'r.appendChild(b);' +
-                       'b.appendChild(document.createTextNode("fooz bar"));' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'document.open();' +
-                       'document.write("<body contenteditable>fooz bar</body>");' +
-                       'document.close();' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'document.open();' +
-                       'document.write("<body contenteditable><div>fooz bar</div></body>");' +
-                       'document.close();' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'document.open();' +
-                       'document.write("<body contenteditable><span>fooz bar</span></body>");' +
-                       'document.close();' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'document.open();' +
-                       'document.write("<p contenteditable style=\\"outline: none\\">fooz bar</p>");' +
-                       'document.close();' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'document.open();' +
-                       'document.write("<html contenteditable>fooz bar</html>");' +
-                       'document.close();' +
-                     '};' +
-                   '<\/script><body></body></html>',
-    'data:text/html,<html><script>' +
-                     'onload = function() {' +
-                       'document.open();' +
-                       'document.write("<html contenteditable><body>fooz bar</body></html>");' +
-                       'document.close();' +
-                     '};' +
-                   '<\/script><body></body></html>',
-  ];
+  
+  var totalTests = 0;
   var currentTest = 0;
   function runAllTests() {
-    if (currentTest == TEST_URIS.length) {
+    if (currentTest == totalTests) {
       SimpleTest.finish();
       return;
     }
-    testBackspace(TEST_URIS[currentTest++], runAllTests);
+    testBackspace("file_bug611182.sjs?" + currentTest, runAllTests)
+    currentTest++;
   }
-  runAllTests();
+
+  // query total number of tests to be run from the server and
+  // start running all tests.
+  var myXHR = new XMLHttpRequest();
+  myXHR.open("GET", "file_bug611182.sjs?queryTotalTests");
+  myXHR.onload = function(e) {
+    totalTests = myXHR.responseText;
+    runAllTests();
+  }
+  myXHR.send();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/editor/libeditor/tests/test_bug795418-2.html
+++ b/editor/libeditor/tests/test_bug795418-2.html
@@ -12,17 +12,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772796">Mozilla Bug 795418</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 
 <div id="copySource">Copy this</div>
-<iframe src="data:application/xhtml+xml,<html contenteditable='' xmlns='http://www.w3.org/1999/xhtml'><span>AB</span></html>"></iframe>
+<!-- load content of type application/xhtml+xml using an *.sjs file -->
+<iframe src="./file_bug795418-2.sjs"></iframe>
 
 <pre id="test">
 
 <script type="application/javascript">
 
 /** Test for Bug 795418 **/
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function() {
--- a/editor/libeditor/tests/test_bug795418-3.html
+++ b/editor/libeditor/tests/test_bug795418-3.html
@@ -12,17 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772796">Mozilla Bug 795418</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 
 <div id="copySource">Copy this</div>
-<iframe src="data:text/html,<html><body><span>AB</span>"></iframe>
+<iframe srcdoc="<html><body><span>AB</span>"></iframe>
 
 <pre id="test">
 
 <script type="application/javascript">
 
 /** Test for Bug 795418 **/
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function() {
--- a/editor/libeditor/tests/test_dom_input_event_on_htmleditor.html
+++ b/editor/libeditor/tests/test_dom_input_event_on_htmleditor.html
@@ -5,21 +5,21 @@
           src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript"
           src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css"
           href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <div id="display">
-  <iframe id="editor1" src="data:text/html,<html><body contenteditable id='eventTarget'></body></html>"></iframe>
-  <iframe id="editor2" src="data:text/html,<html contenteditable id='eventTarget'><body></body></html>"></iframe>
-  <iframe id="editor3" src="data:text/html,<html><body><div contenteditable id='eventTarget'></div></body></html>"></iframe>
-  <iframe id="editor4" src="data:text/html,<html contenteditable id='eventTarget'><body><div contenteditable id='editTarget'></div></body></html>"></iframe>
-  <iframe id="editor5" src="data:text/html,<html><body id='eventTarget'></body><script>document.designMode='on';</script></html>"></iframe>
+  <iframe id="editor1" srcdoc="<html><body contenteditable id='eventTarget'></body></html>"></iframe>
+  <iframe id="editor2" srcdoc="<html contenteditable id='eventTarget'><body></body></html>"></iframe>
+  <iframe id="editor3" srcdoc="<html><body><div contenteditable id='eventTarget'></div></body></html>"></iframe>
+  <iframe id="editor4" srcdoc="<html contenteditable id='eventTarget'><body><div contenteditable id='editTarget'></div></body></html>"></iframe>
+  <iframe id="editor5" srcdoc="<html><body id='eventTarget'></body><script>document.designMode='on';</script></html>"></iframe>
 </div>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 </pre>
 
 <script class="testbody" type="application/javascript">
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -27,16 +27,17 @@ DrawTargetCaptureImpl::Init(const IntSiz
 {
   if (!aRefDT) {
     return false;
   }
 
   mRefDT = aRefDT;
 
   mSize = aSize;
+  mFormat = aRefDT->GetFormat();
   return true;
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetCaptureImpl::Snapshot()
 {
   RefPtr<DrawTarget> dt = mRefDT->CreateSimilarDrawTarget(mSize, mRefDT->GetFormat());
 
--- a/gfx/layers/apz/test/mochitest/helper_iframe_pan.html
+++ b/gfx/layers/apz/test/mochitest/helper_iframe_pan.html
@@ -28,14 +28,14 @@ function checkScroll() {
   subtestDone();
 }
 
 waitUntilApzStable().then(scrollOuter);
 
   </script>
 </head>
 <body>
- <iframe id="outer" style="height: 250px; border: solid 1px black" src="data:text/html,<body style='height:5000px'>"></iframe>
+ <iframe id="outer" style="height: 250px; border: solid 1px black" srcdoc="<body style='height:5000px'>"></iframe>
  <div style="height: 5000px; background-color: lightgreen;">
   This div makes the top-level page scrollable.
  </div>
 </body>
 </html>
--- a/gfx/layers/apz/test/mochitest/helper_scroll_on_position_fixed.html
+++ b/gfx/layers/apz/test/mochitest/helper_scroll_on_position_fixed.html
@@ -48,15 +48,15 @@ waitUntilApzStable()
 .then(runContinuation(test))
 .then(subtestDone);
 
   </script>
 </head>
 <body style="height:5000px; margin:0">
   <div style="position:sticky; width: 100px; height: 300px; top: 0; background-color:red">sticky</div>
   <div style="position:fixed; width: 100px; height: 300px; top: 0; left: 200px; background-color: green">fixed</div>
-  <iframe id='iframe' width="300" height="400" src="data:text/html,<body style='height:5000px; margin:0'><div style='position:sticky; width:100px; height:300px; top: 0; background-color:red'>sticky</div><div style='position:fixed; right:0; top: 0; width:100px; height:300px; background-color:green'>fixed</div>"></iframe>
+  <iframe id='iframe' width="300" height="400" srcdoc="<body style='height:5000px; margin:0'><div style='position:sticky; width:100px; height:300px; top: 0; background-color:red'>sticky</div><div style='position:fixed; right:0; top: 0; width:100px; height:300px; background-color:green'>fixed</div>"></iframe>
 
   <div id="fpos_scrollable" style="position:fixed; width: 100px; height: 300px; top: 0; left: 400px; background-color: red; overflow:scroll">
    <div style="background-color: blue; height: 1000px; margin: 3px">scrollable content inside a fixed-pos item</div>
   </div>
 </body>
 </head>
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -108,60 +108,16 @@ ClientPaintedLayer::UpdatePaintRegion(Pa
    // (this could be the whole visible area if our buffer switched
    // from RGB to RGBA, because we might need to repaint with
    // subpixel AA)
   aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
                                  GetLocalVisibleRegion().ToUnknownRegion());
   return true;
 }
 
-void
-ClientPaintedLayer::PaintOffMainThread(DrawTargetCapture* aCapture)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  LayerIntRegion visibleRegion = GetVisibleRegion();
-  mContentClient->BeginPaint();
-
-  uint32_t flags = GetPaintFlags();
-
-  PaintState state =
-    mContentClient->BeginPaintBuffer(this, flags);
-  if (!UpdatePaintRegion(state)) {
-    return;
-  }
-
-  bool didUpdate = false;
-  RotatedContentBuffer::DrawIterator iter;
-  while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
-    if (!target || !target->IsValid()) {
-      if (target) {
-        mContentClient->ReturnDrawTargetToBuffer(target);
-      }
-      continue;
-    }
-
-    SetAntialiasingFlags(this, target);
-
-    // Basic version, wait for the paint thread to finish painting.
-    PaintThread::Get()->PaintContents(aCapture, target);
-
-    mContentClient->ReturnDrawTargetToBuffer(target);
-    didUpdate = true;
-  }
-
-  // ending paint w/o any readback updates
-  // TODO: Fix me
-  mContentClient->EndPaint(nullptr);
-
-  if (didUpdate) {
-    UpdateContentClient(state);
-   }
- }
-
-
 uint32_t
 ClientPaintedLayer::GetPaintFlags()
 {
   uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
   #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
    if (ClientManager()->CompositorMightResample()) {
      flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
    }
@@ -221,93 +177,93 @@ ClientPaintedLayer::PaintThebes(nsTArray
 
   mContentClient->EndPaint(aReadbackUpdates);
 
   if (didUpdate) {
     UpdateContentClient(state);
   }
 }
 
-already_AddRefed<DrawTargetCapture>
-ClientPaintedLayer::CapturePaintedContent()
+bool
+ClientPaintedLayer::PaintOffMainThread()
 {
-  LayerIntRegion visibleRegion = GetVisibleRegion();
-  LayerIntRect bounds = visibleRegion.GetBounds();
-  LayerIntSize size = bounds.Size();
+  mContentClient->BeginPaint();
 
-  if (visibleRegion.IsEmpty()) {
-    if (gfxPrefs::LayersDump()) {
-      printf_stderr("PaintedLayer %p skipping\n", this);
-    }
-    return nullptr;
-  }
+  uint32_t flags = GetPaintFlags();
 
-  nsIntRegion regionToPaint;
-  regionToPaint.Sub(mVisibleRegion.ToUnknownRegion(), GetValidRegion());
-
-  if (regionToPaint.IsEmpty()) {
-    // Do we ever have to do anything if the region to paint is empty
-    // but we have a painted layer callback?
-    return nullptr;
+  PaintState state = mContentClient->BeginPaintBuffer(this, flags);
+  if (!UpdatePaintRegion(state)) {
+    return false;
   }
 
-  if (!ClientManager()->GetPaintedLayerCallback()) {
-    ClientManager()->SetTransactionIncomplete();
-    return nullptr;
+  bool didUpdate = false;
+  RotatedContentBuffer::DrawIterator iter;
+  while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
+    if (!target || !target->IsValid()) {
+      if (target) {
+        mContentClient->ReturnDrawTargetToBuffer(target);
+      }
+      continue;
+    }
+
+    RefPtr<DrawTarget> refDT =
+      Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetDefaultContentBackend(),
+                                target->GetSize(), target->GetFormat());
+
+    // We don't clear the rect here like WRPaintedBlobLayers do
+    // because ContentClient already clears the surface for us during BeginPaint.
+    RefPtr<DrawTargetCapture> captureDT = refDT->CreateCaptureDT(target->GetSize());
+    captureDT->SetTransform(target->GetTransform());
+
+    SetAntialiasingFlags(this, refDT);
+    SetAntialiasingFlags(this, captureDT);
+    SetAntialiasingFlags(this, target);
+
+    RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
+    MOZ_ASSERT(ctx); // already checked the target above
+
+    ClientManager()->GetPaintedLayerCallback()(this,
+                                              ctx,
+                                              iter.mDrawRegion,
+                                              iter.mDrawRegion,
+                                              state.mClip,
+                                              state.mRegionToInvalidate,
+                                              ClientManager()->GetPaintedLayerCallbackData());
+
+    ctx = nullptr;
+
+    PaintThread::Get()->PaintContents(captureDT, target);
+
+    mContentClient->ReturnDrawTargetToBuffer(target);
+    didUpdate = true;
   }
 
-  IntSize imageSize(size.ToUnknownSize());
-
-  // DrawTargetCapture requires a reference DT
-  // That is used when some API requires a snapshot.
-  // TODO: Fixup so DrawTargetCapture lazily creates a reference DT
-  RefPtr<DrawTarget> refDT =
-    Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetDefaultContentBackend(),
-                              imageSize, gfx::SurfaceFormat::B8G8R8A8);
+  mContentClient->EndPaint(nullptr);
 
-  // We don't clear the rect here like WRPaintedBlobLayers do
-  // because ContentClient already clears the surface for us during BeginPaint.
-  RefPtr<DrawTargetCapture> captureDT = refDT->CreateCaptureDT(imageSize);
-  captureDT->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
-
-  RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
-  MOZ_ASSERT(ctx); // already checked the target above
-
-  ClientManager()->GetPaintedLayerCallback()(this,
-                                             ctx,
-                                             visibleRegion.ToUnknownRegion(),
-                                             visibleRegion.ToUnknownRegion(),
-                                             DrawRegionClip::DRAW,
-                                             nsIntRegion(),
-                                             ClientManager()->GetPaintedLayerCallbackData());
-
-  return captureDT.forget();
+  if (didUpdate) {
+    UpdateContentClient(state);
+  }
+  return true;
 }
 
 void
 ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
 {
   RenderMaskLayers(this);
 
+  if (!EnsureContentClient()) {
+    return;
+  }
+
   if (CanRecordLayer(aReadback)) {
-    RefPtr<DrawTargetCapture> capture = CapturePaintedContent();
-    if (capture) {
-      if (!EnsureContentClient()) {
-        return;
-      }
-
-      PaintOffMainThread(capture);
+    if (PaintOffMainThread()) {
       return;
     }
   }
 
-  if (!EnsureContentClient()) {
-    return;
-  }
-
   nsTArray<ReadbackProcessor::Update> readbackUpdates;
   nsIntRegion readbackRegion;
   if (aReadback && UsedForReadback()) {
     aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
   }
 
   PaintThebes(&readbackUpdates);
 }
--- a/gfx/layers/client/ClientPaintedLayer.h
+++ b/gfx/layers/client/ClientPaintedLayer.h
@@ -115,18 +115,17 @@ protected:
   void PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates);
   void RecordThebes();
   bool CanRecordLayer(ReadbackProcessor* aReadback);
   bool HasMaskLayers();
   bool EnsureContentClient();
   uint32_t GetPaintFlags();
   void UpdateContentClient(PaintState& aState);
   bool UpdatePaintRegion(PaintState& aState);
-  void PaintOffMainThread(gfx::DrawTargetCapture* aCapture);
-  already_AddRefed<gfx::DrawTargetCapture> CapturePaintedContent();
+  bool PaintOffMainThread();
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
   void DestroyBackBuffer()
   {
     mContentClient = nullptr;
   }
 
--- a/gfx/layers/d3d11/mlgshaders/common-vs.hlsl
+++ b/gfx/layers/d3d11/mlgshaders/common-vs.hlsl
@@ -80,22 +80,22 @@ float ComputeDepth(float4 aPosition, flo
 
 // Compute the world-space, screen-space, layer-space clip, and mask
 // uv-coordinates given a layer-space vertex, id, and z-index.
 VertexInfo ComputePosition(float2 aVertex, uint aLayerId, float aSortIndex)
 {
   Layer layer = sLayers[aLayerId];
 
   // Translate from unit vertex to layer quad vertex.
-  float4 position = float4(aVertex, 0, 1);
   float4 clipRect = layer.clipRect;
 
   // Transform to screen coordinates.
   float4x4 transform = layer.transform;
-  position = mul(transform, position);
+  float4 layerPos = mul(transform, float4(aVertex, 0, 1));
+  float4 position = layerPos;
   position.xyz /= position.w;
   position.xy -= RenderTargetOffset.xy;
   position.xyz *= position.w;
 
   float4 worldPos = mul(WorldTransform, position);
 
   // Depth must be computed after the world transform, since we don't want
   // 3d transforms clobbering the z-value. We assume a viewport culling
@@ -104,17 +104,17 @@ VertexInfo ComputePosition(float2 aVerte
   //
   // Note that we have to normalize this value to w=1, since the GPU will
   // divide all values by w internally.
   worldPos.z = ComputeDepth(worldPos, aSortIndex);
 
   VertexInfo info;
   info.screenPos = position.xy;
   info.worldPos = worldPos;
-  info.maskCoords = ComputeMaskCoords(position, layer);
+  info.maskCoords = ComputeMaskCoords(layerPos, layer);
   info.clipRect = clipRect;
   return info;
 }
 
 // This function takes a unit quad position and a layer rectangle, and computes
 // a clipped draw rect. It is only valid to use this function for layers with
 // rectilinear transforms that do not have masks.
 float4 ComputeClippedPosition(const float2 aVertex,
--- a/image/test/mochitest/test_drawDiscardedImage.html
+++ b/image/test/mochitest/test_drawDiscardedImage.html
@@ -56,17 +56,17 @@ function step2()
   is(drawImage(), data1, "Same image before and after iframe display:none");
   SimpleTest.finish();
 }
 
 </script>
 
 <canvas id='canvas'></canvas>
 
-<iframe id='iframe' onload='iframeLoad()' src='data:text/html,<img id="image"
+<iframe id='iframe' onload='iframeLoad()' srcdoc='<img id="image"
 src="data:image/png;base64,
 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADRElEQVQ4EQXBTWgcZQCA4ff7ZmZ3
 NpvNZLObTWpCuoZGIxWJplAKbVUKavUiHrQHaRG1XrV4SNuD4MFcRDwUoR4qEq2gFUlBEWmtppYi
 acSmMakxtfkx/5tNdmd35/8bn0cAzJ7IXwKGH/q8NDF48vy+7vk/3tzVXDs8nj9cAAiDcD70gwVi
 vvvr4tsjAAAAAmD2RD4GOL34wge21XHsnHWh9/aUjX1pC4C1UpXrP08zN7vMvvujPx3P/PD+0VH3
 BoAcTspXAbK9iuGe78+csy70ZnsVvh+xWQ8p1QI8dNK7CiT9CmeO28/4ZsuVX9/IvQwgmzLaU9LS
 AGh/3KJ5jw6A6ynyL7Xx7UCORiwQGRN0g7C4m4FX9poNV35681ShU6ZbxKDRLJVuZQl9RdSQRB4c
 OtDGoQNtPGHBuh0SaAa+ZvLjHYt8fwfZrpTl2cFp2ZwVDyQzSgLgVIndGN/tIP/c61y/WWb14gaV
--- a/intl/uconv/tests/test_big5_encoder.html
+++ b/intl/uconv/tests/test_big5_encoder.html
@@ -19,24 +19,24 @@ https://bugzilla.mozilla.org/show_bug.cg
  * (testing/web-platform/tests/encoding/big5-encoder.html) and this test can
  * simply be removed.
  */
 SimpleTest.waitForExplicitFinish();
 
 function test() {
   var f = document.getElementsByTagName("iframe")[0];
   f.onload = function() {
-    var href = f.contentWindow.location.href;
+    var href = SpecialPowers.wrap(f).contentWindow.location.href;
     var index = href.indexOf("?foo=");
     var actual = href.substring(index + 5);
     var expected = "h%26%2340614%3Bi%26%23156267%3Bj%A1%40k%A3%E1l%A4%40m%C8%A4n%C8%CDo%FE%FEp%26%238365%3Bq%FDjr%F9%F9s%26%23128169%3Bt";
     is(actual, expected, "Should have gotten the expected encode.");
     SimpleTest.finish();
   }
-  f.contentDocument.forms[0].submit();
+  SpecialPowers.wrap(f).contentDocument.forms[0].submit();
 }
 </script>
 </pre>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=912470">Mozilla Bug 912470</a>
 <p id="display"></p>
 <div id="content" style="display: none"><iframe src="data:text/html;charset=big5,<form><input name=foo value=h&amp;%23x9EA6;i&amp;%23x2626B;j&amp;%23x3000;k&amp;%23x20AC;l&amp;%23x4E00;m&amp;%23x27607;n&amp;%23xFFE2;o&amp;%23x79D4;p&amp;%23x20AD;q&amp;%23x203B5;r&amp;%23x2550;s&amp;%23x1F4A9;t></form>">
 </div>
 </body>
--- a/intl/uconv/tests/test_long_doc.html
+++ b/intl/uconv/tests/test_long_doc.html
@@ -84,16 +84,16 @@ for (var i = 0; i < decoders.length; i++
 function lastTest(frame)
 {
     testDecoding(frame);
     SimpleTest.finish();
 }
 
 function testDecoding(frame)
 {
-    var iframeDoc = $(frame).contentDocument;
+    var iframeDoc = SpecialPowers.wrap($(frame)).contentDocument;
     var outString = iframeDoc.getElementById("testPara").innerHTML;
     is(outString, inString, "content decoded as " + frame);
 }
 </script>
 </pre>
 </body>
 </html>
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -20,43 +20,51 @@ function MapConstructorInit(iterable) {
         if (!IsObject(nextItem))
             ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Map");
 
         // Steps 8.e-j.
         callContentFunction(adder, map, nextItem[0], nextItem[1]);
     }
 }
 
-/* ES6 20121122 draft 15.14.4.4. */
+// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
+// 23.1.3.5 Map.prototype.forEach ( callbackfn [ , thisArg ] )
 function MapForEach(callbackfn, thisArg = undefined) {
-    /* Step 1-2. */
+    // Step 1.
     var M = this;
-    if (!IsObject(M))
-        ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Map", "forEach", typeof M);
 
-    /* Step 3-4. */
-    try {
-        callFunction(std_Map_has, M);
-    } catch (e) {
-        // has will throw on non-Map objects, throw our own error in that case.
-        ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Map", "forEach", typeof M);
-    }
+    // Steps 2-3.
+    if (!IsObject(M) || !IsMapObject(M))
+        return callFunction(CallMapMethodIfWrapped, M, callbackfn, thisArg, "MapForEach");
 
-    /* Step 5. */
+    // Step 4.
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
-    /* Step 6-8. */
+    // Steps 5-8.
     var entries = callFunction(std_Map_iterator, M);
+
+    // Inlined: MapIteratorNext
+    var mapIterationResultPair = iteratorTemp.mapIterationResultPair;
+    if (!mapIterationResultPair) {
+        mapIterationResultPair = iteratorTemp.mapIterationResultPair =
+            _CreateMapIterationResultPair();
+    }
+
     while (true) {
-        var result = callFunction(MapIteratorNext, entries);
-        if (result.done)
+        var done = _GetNextMapEntryForIterator(entries, mapIterationResultPair);
+        if (done)
             break;
-        var entry = result.value;
-        callContentFunction(callbackfn, thisArg, entry[1], entry[0], M);
+
+        var key = mapIterationResultPair[0];
+        var value = mapIterationResultPair[1];
+        mapIterationResultPair[0] = null;
+        mapIterationResultPair[1] = null;
+
+        callContentFunction(callbackfn, thisArg, value, key, M);
     }
 }
 
 function MapEntries() {
     return callFunction(std_Map_iterator, this);
 }
 _SetCanonicalName(MapEntries, "entries");
 
--- a/js/src/builtin/Number.js
+++ b/js/src/builtin/Number.js
@@ -48,35 +48,63 @@ function Number_isFinite(num) {
 
 // ES6 draft ES6 20.1.2.2
 function Number_isNaN(num) {
     if (typeof num !== "number")
         return false;
     return num !== num;
 }
 
-// ES6 draft ES6 20.1.2.5
+// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
+// 20.1.2.3 Number.isInteger ( number )
+function Number_isInteger(number) {
+    // Step 1.
+    if (typeof number !== "number")
+        return false;
+
+    // -(2**31) is an int32, but abs(-(2**31)) isn't. Avoid bailouts below by
+    // special casing it here.
+    if (number === -(2 ** 31))
+        return true;
+
+    // Step 3.
+    // Note: We're using abs + floor instead ceil to workaround bug 1379626.
+    var absNumber = std_Math_abs(number);
+    var integer = std_Math_floor(absNumber);
+
+    // Steps 2, 4.
+    if (absNumber - integer !== 0)
+        return false;
+
+    // Step 5.
+    return true;
+}
+
+// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
+// 20.1.2.5 Number.isSafeInteger ( number )
 function Number_isSafeInteger(number) {
     // Step 1.
     if (typeof number !== "number")
         return false;
 
-    // Step 2.
-    if (!Number_isFinite(number))
-        return false;
+    // -(2**31) is an int32, but abs(-(2**31)) isn't. Avoid bailouts below by
+    // special casing it here.
+    if (number === -(2 ** 31))
+        return true;
 
     // Step 3.
-    var integer = ToInteger(number);
+    var absNumber = std_Math_abs(number);
+    var integer = std_Math_floor(absNumber);
 
-    // Step 4.
-    if (integer !== number)
+    // Steps 2, 4.
+    if (absNumber - integer !== 0)
         return false;
 
-    // Step 5. If abs(integer) <= 2**53 - 1, return true.
-    if (std_Math_abs(integer) <= 9007199254740991)
+    // Step 5.
+    if (integer <= (2 ** 53) - 1)
         return true;
 
     // Step 6.
     return false;
 }
 
 function Global_isNaN(number) {
     return Number_isNaN(ToNumber(number));
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -14,42 +14,46 @@ function SetConstructorInit(iterable) {
     if (!IsCallable(adder))
         ThrowTypeError(JSMSG_NOT_FUNCTION, typeof adder);
 
     // Steps 6.c-8.
     for (var nextValue of allowContentIter(iterable))
         callContentFunction(adder, set, nextValue);
 }
 
-/* ES6 20121122 draft 15.16.4.6. */
+// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
+// 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] )
 function SetForEach(callbackfn, thisArg = undefined) {
-    /* Step 1-2. */
+    // Step 1.
     var S = this;
-    if (!IsObject(S))
-        ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Set", "forEach", typeof S);
 
-    /* Step 3-4. */
-    try {
-        callFunction(std_Set_has, S);
-    } catch (e) {
-        // has will throw on non-Set objects, throw our own error in that case.
-        ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Set", "forEach", typeof S);
-    }
+    // Steps 2-3.
+    if (!IsObject(S) || !IsSetObject(S))
+        return callFunction(CallSetMethodIfWrapped, S, callbackfn, thisArg, "SetForEach");
 
-    /* Step 5-6. */
+    // Step 4.
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
-    /* Step 7-8. */
+    // Steps 5-8.
     var values = callFunction(std_Set_iterator, S);
+
+    // Inlined: SetIteratorNext
+    var setIterationResult = setIteratorTemp.setIterationResult;
+    if (!setIterationResult)
+        setIterationResult = setIteratorTemp.setIterationResult = _CreateSetIterationResult();
+
     while (true) {
-        var result = callFunction(SetIteratorNext, values);
-        if (result.done)
+        var done = _GetNextSetEntryForIterator(values, setIterationResult);
+        if (done)
             break;
-        var value = result.value;
+
+        var value = setIterationResult[0];
+        setIterationResult[0] = null;
+
         callContentFunction(callbackfn, thisArg, value, value, S);
     }
 }
 
 function SetValues() {
     return callFunction(std_Set_iterator, this);
 }
 _SetCanonicalName(SetValues, "values");
@@ -71,19 +75,18 @@ function SetIteratorNext() {
     // Steps 2-3.
     if (!IsObject(O) || !IsSetIterator(O))
         return callFunction(CallSetIteratorMethodIfWrapped, O, "SetIteratorNext");
 
     // Steps 4-5 (implemented in _GetNextSetEntryForIterator).
     // Steps 8-9 (omitted).
 
     var setIterationResult = setIteratorTemp.setIterationResult;
-    if (!setIterationResult) {
+    if (!setIterationResult)
         setIterationResult = setIteratorTemp.setIterationResult = _CreateSetIterationResult();
-    }
 
     var retVal = {value: undefined, done: true};
 
     // Steps 10.a, 11.
     var done = _GetNextSetEntryForIterator(O, setIterationResult);
     if (!done) {
         // Steps 10.b-c (omitted).
 
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -123,18 +123,20 @@
     _(IntrinsicObjectHasPrototype)  \
     _(IntrinsicFinishBoundFunctionInit) \
                                     \
     _(IntrinsicIsArrayIterator)     \
     _(IntrinsicIsMapIterator)       \
     _(IntrinsicIsSetIterator)       \
     _(IntrinsicIsStringIterator)    \
                                     \
+    _(IntrinsicIsMapObject)         \
     _(IntrinsicGetNextMapEntryForIterator) \
                                     \
+    _(IntrinsicIsSetObject)         \
     _(IntrinsicGetNextSetEntryForIterator) \
                                     \
     _(IntrinsicNewArrayIterator)    \
     _(IntrinsicNewStringIterator)   \
                                     \
     _(IntrinsicArrayBufferByteLength) \
     _(IntrinsicPossiblyWrappedArrayBufferByteLength) \
                                     \
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/Casting.h"
 
 #include "jsmath.h"
 #include "jsobj.h"
 #include "jsstr.h"
 
 #include "builtin/AtomicsObject.h"
 #include "builtin/Intl.h"
+#include "builtin/MapObject.h"
 #include "builtin/SIMD.h"
 #include "builtin/TestingFunctions.h"
 #include "builtin/TypedObject.h"
 #include "jit/BaselineInspector.h"
 #include "jit/InlinableNatives.h"
 #include "jit/IonBuilder.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
@@ -308,20 +309,24 @@ IonBuilder::inlineNativeCall(CallInfo& c
       case InlinableNative::IntrinsicIsStringIterator:
         return inlineHasClass(callInfo, &StringIteratorObject::class_);
       case InlinableNative::IntrinsicObjectHasPrototype:
         return inlineObjectHasPrototype(callInfo);
       case InlinableNative::IntrinsicFinishBoundFunctionInit:
         return inlineFinishBoundFunctionInit(callInfo);
 
       // Map intrinsics.
+      case InlinableNative::IntrinsicIsMapObject:
+        return inlineHasClass(callInfo, &MapObject::class_);
       case InlinableNative::IntrinsicGetNextMapEntryForIterator:
         return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map);
 
       // Set intrinsics.
+      case InlinableNative::IntrinsicIsSetObject:
+        return inlineHasClass(callInfo, &SetObject::class_);
       case InlinableNative::IntrinsicGetNextSetEntryForIterator:
         return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set);
 
       // ArrayBuffer intrinsics.
       case InlinableNative::IntrinsicArrayBufferByteLength:
         return inlineArrayBufferByteLength(callInfo);
       case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
         return inlinePossiblyWrappedArrayBufferByteLength(callInfo);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1113,36 +1113,20 @@ static const JSFunctionSpec number_metho
 #endif
     JS_FN(js_valueOf_str,        num_valueOf,           0, 0),
     JS_FN("toFixed",             num_toFixed,           1, 0),
     JS_FN("toExponential",       num_toExponential,     1, 0),
     JS_FN("toPrecision",         num_toPrecision,       1, 0),
     JS_FS_END
 };
 
-// ES6 draft ES6 15.7.3.12
-static bool
-Number_isInteger(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() < 1 || !args[0].isNumber()) {
-        args.rval().setBoolean(false);
-        return true;
-    }
-    Value val = args[0];
-    args.rval().setBoolean(val.isInt32() ||
-                           (mozilla::IsFinite(val.toDouble()) &&
-                            JS::ToInteger(val.toDouble()) == val.toDouble()));
-    return true;
-}
-
 
 static const JSFunctionSpec number_static_methods[] = {
     JS_SELF_HOSTED_FN("isFinite", "Number_isFinite", 1,0),
-    JS_FN("isInteger", Number_isInteger, 1, 0),
+    JS_SELF_HOSTED_FN("isInteger", "Number_isInteger", 1,0),
     JS_SELF_HOSTED_FN("isNaN", "Number_isNaN", 1,0),
     JS_SELF_HOSTED_FN("isSafeInteger", "Number_isSafeInteger", 1,0),
     JS_FS_END
 };
 
 
 bool
 js::InitRuntimeNumberState(JSRuntime* rt)
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsstr.h"
 
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Range.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Unused.h"
@@ -82,16 +83,157 @@ ArgToRootedString(JSContext* cx, const C
     JSString* str = ToString<CanGC>(cx, args[argno]);
     if (!str)
         return nullptr;
 
     args[argno].setString(str);
     return str->ensureLinear(cx);
 }
 
+template <typename CharT> struct MaximumInlineLength;
+
+template<> struct MaximumInlineLength<Latin1Char> {
+    static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
+};
+
+template<> struct MaximumInlineLength<char16_t> {
+    static constexpr size_t value = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
+};
+
+// Character buffer class used for ToLowerCase and ToUpperCase operations, as
+// well as other string operations where the final string length is known in
+// advance.
+//
+// Case conversion operations normally return a string with the same length as
+// the input string. To avoid over-allocation, we optimistically allocate an
+// array with same size as the input string and only when we detect special
+// casing characters, which can change the output string length, we reallocate
+// the output buffer to the final string length.
+//
+// As a further mean to improve runtime performance, the character buffer
+// contains an inline storage, so we don't need to heap-allocate an array when
+// a JSInlineString will be used for the output string.
+//
+// Why not use mozilla::Vector instead? mozilla::Vector doesn't provide enough
+// fine-grained control to avoid over-allocation when (re)allocating for exact
+// buffer sizes. This led to visible performance regressions in µ-benchmarks.
+template <typename CharT>
+class MOZ_NON_PARAM InlineCharBuffer
+{
+    static constexpr size_t InlineCapacity = MaximumInlineLength<CharT>::value;
+
+    CharT inlineStorage[InlineCapacity];
+    UniquePtr<CharT[], JS::FreePolicy> heapStorage;
+
+#ifdef DEBUG
+    // In debug mode, we keep track of the requested string lengths to ensure
+    // all character buffer methods are called in the correct order and with
+    // the expected argument values.
+    size_t lastRequestedLength = 0;
+
+    void assertValidRequest(size_t expectedLastLength, size_t length) {
+        MOZ_ASSERT(length >= expectedLastLength, "cannot shrink requested length");
+        MOZ_ASSERT(lastRequestedLength == expectedLastLength);
+        lastRequestedLength = length;
+    }
+#else
+    void assertValidRequest(size_t expectedLastLength, size_t length) {}
+#endif
+
+  public:
+    CharT* get()
+    {
+        return heapStorage ? heapStorage.get() : inlineStorage;
+    }
+
+    bool maybeAlloc(JSContext* cx, size_t length)
+    {
+        assertValidRequest(0, length);
+
+        if (length <= InlineCapacity)
+            return true;
+
+        MOZ_ASSERT(!heapStorage, "heap storage already allocated");
+        heapStorage = cx->make_pod_array<CharT>(length + 1);
+        return !!heapStorage;
+    }
+
+    bool maybeRealloc(JSContext* cx, size_t oldLength, size_t newLength)
+    {
+        assertValidRequest(oldLength, newLength);
+
+        if (newLength <= InlineCapacity)
+            return true;
+
+        if (!heapStorage) {
+            heapStorage = cx->make_pod_array<CharT>(newLength + 1);
+            if (!heapStorage)
+                return false;
+
+            MOZ_ASSERT(oldLength <= InlineCapacity);
+            PodCopy(heapStorage.get(), inlineStorage, oldLength);
+            return true;
+        }
+
+        CharT* oldChars = heapStorage.release();
+        CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
+        if (!newChars) {
+            js_free(oldChars);
+            return false;
+        }
+
+        heapStorage.reset(newChars);
+        return true;
+    }
+
+    JSString* toStringDontDeflate(JSContext* cx, size_t length)
+    {
+        MOZ_ASSERT(length == lastRequestedLength);
+
+        if (JSInlineString::lengthFits<CharT>(length)) {
+            MOZ_ASSERT(!heapStorage,
+                       "expected only inline storage when length fits in inline string");
+
+            return NewStringCopyNDontDeflate<CanGC>(cx, inlineStorage, length);
+        }
+
+        MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
+
+        heapStorage.get()[length] = '\0'; // Null-terminate
+        JSString* res = NewStringDontDeflate<CanGC>(cx, heapStorage.get(), length);
+        if (!res)
+            return nullptr;
+
+        mozilla::Unused << heapStorage.release();
+        return res;
+    }
+
+    JSString* toString(JSContext* cx, size_t length)
+    {
+        MOZ_ASSERT(length == lastRequestedLength);
+
+        if (JSInlineString::lengthFits<CharT>(length)) {
+            MOZ_ASSERT(!heapStorage,
+                       "expected only inline storage when length fits in inline string");
+
+            return NewStringCopyN<CanGC>(cx, inlineStorage, length);
+        }
+
+        MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
+
+        heapStorage.get()[length] = '\0'; // Null-terminate
+        JSString* res = NewString<CanGC>(cx, heapStorage.get(), length);
+        if (!res)
+            return nullptr;
+
+        mozilla::Unused << heapStorage.release();
+        return res;
+    }
+};
+
 /*
  * Forward declarations for URI encode/decode and helper routines
  */
 static bool
 str_decodeURI(JSContext* cx, unsigned argc, Value* vp);
 
 static bool
 str_decodeURI_Component(JSContext* cx, unsigned argc, Value* vp);
@@ -104,18 +246,19 @@ str_encodeURI_Component(JSContext* cx, u
 
 /*
  * Global string methods
  */
 
 
 /* ES5 B.2.1 */
 template <typename CharT>
-static Latin1Char*
-Escape(JSContext* cx, const CharT* chars, uint32_t length, uint32_t* newLengthOut)
+static bool
+Escape(JSContext* cx, const CharT* chars, uint32_t length, InlineCharBuffer<Latin1Char>& newChars,
+       uint32_t* newLengthOut)
 {
     static const uint8_t shouldPassThrough[128] = {
          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,       /*    !"#$%&'()*+,-./  */
          1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,       /*   0123456789:;<=>?  */
          1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /*   @ABCDEFGHIJKLMNO  */
          1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,       /*   PQRSTUVWXYZ[\]^_  */
@@ -136,74 +279,82 @@ Escape(JSContext* cx, const CharT* chars
         /*
          * newlength is incremented by at most 5 on each iteration, so worst
          * case newlength == length * 6. This can't overflow.
          */
         static_assert(JSString::MAX_LENGTH < UINT32_MAX / 6,
                       "newlength must not overflow");
     }
 
-    Latin1Char* newChars = cx->pod_malloc<Latin1Char>(newLength + 1);
-    if (!newChars)
-        return nullptr;
+    if (newLength == length) {
+        *newLengthOut = newLength;
+        return true;
+    }
+
+    if (!newChars.maybeAlloc(cx, newLength))
+        return false;
 
     static const char digits[] = "0123456789ABCDEF";
 
+    Latin1Char* rawNewChars = newChars.get();
     size_t i, ni;
     for (i = 0, ni = 0; i < length; i++) {
         char16_t ch = chars[i];
         if (ch < 128 && shouldPassThrough[ch]) {
-            newChars[ni++] = ch;
+            rawNewChars[ni++] = ch;
         } else if (ch < 256) {
-            newChars[ni++] = '%';
-            newChars[ni++] = digits[ch >> 4];
-            newChars[ni++] = digits[ch & 0xF];
+            rawNewChars[ni++] = '%';
+            rawNewChars[ni++] = digits[ch >> 4];
+            rawNewChars[ni++] = digits[ch & 0xF];
         } else {
-            newChars[ni++] = '%';
-            newChars[ni++] = 'u';
-            newChars[ni++] = digits[ch >> 12];
-            newChars[ni++] = digits[(ch & 0xF00) >> 8];
-            newChars[ni++] = digits[(ch & 0xF0) >> 4];
-            newChars[ni++] = digits[ch & 0xF];
+            rawNewChars[ni++] = '%';
+            rawNewChars[ni++] = 'u';
+            rawNewChars[ni++] = digits[ch >> 12];
+            rawNewChars[ni++] = digits[(ch & 0xF00) >> 8];
+            rawNewChars[ni++] = digits[(ch & 0xF0) >> 4];
+            rawNewChars[ni++] = digits[ch & 0xF];
         }
     }
     MOZ_ASSERT(ni == newLength);
-    newChars[newLength] = 0;
 
     *newLengthOut = newLength;
-    return newChars;
+    return true;
 }
 
 static bool
 str_escape(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JSLinearString* str = ArgToRootedString(cx, args, 0);
     if (!str)
         return false;
 
-    ScopedJSFreePtr<Latin1Char> newChars;
+    InlineCharBuffer<Latin1Char> newChars;
     uint32_t newLength = 0;  // initialize to silence GCC warning
     if (str->hasLatin1Chars()) {
         AutoCheckCannotGC nogc;
-        newChars = Escape(cx, str->latin1Chars(nogc), str->length(), &newLength);
+        if (!Escape(cx, str->latin1Chars(nogc), str->length(), newChars, &newLength))
+            return false;
     } else {
         AutoCheckCannotGC nogc;
-        newChars = Escape(cx, str->twoByteChars(nogc), str->length(), &newLength);
+        if (!Escape(cx, str->twoByteChars(nogc), str->length(), newChars, &newLength))
+            return false;
     }
 
-    if (!newChars)
-        return false;
-
-    JSString* res = NewString<CanGC>(cx, newChars.get(), newLength);
+    // Return input if no characters need to be escaped.
+    if (newLength == str->length()) {
+        args.rval().setString(str);
+        return true;
+    }
+
+    JSString* res = newChars.toString(cx, newLength);
     if (!res)
         return false;
 
-    newChars.forget();
     args.rval().setString(res);
     return true;
 }
 
 template <typename CharT>
 static inline bool
 Unhex4(const RangedPtr<const CharT> chars, char16_t* result)
 {
@@ -232,115 +383,103 @@ Unhex2(const RangedPtr<const CharT> char
     *result = (JS7_UNHEX(a) << 4) + JS7_UNHEX(b);
     return true;
 }
 
 template <typename CharT>
 static bool
 Unescape(StringBuffer& sb, const mozilla::Range<const CharT> chars)
 {
-    /*
-     * NB: use signed integers for length/index to allow simple length
-     * comparisons without unsigned-underflow hazards.
-     */
-    static_assert(JSString::MAX_LENGTH <= INT_MAX, "String length must fit in a signed integer");
-    int length = AssertedCast<int>(chars.length());
+    // Step 2.
+    uint32_t length = chars.length();
 
     /*
      * Note that the spec algorithm has been optimized to avoid building
      * a string in the case where no escapes are present.
      */
-
-    /* Step 4. */
-    int k = 0;
     bool building = false;
 
-    /* Step 5. */
-    while (k < length) {
-        /* Step 6. */
-        char16_t c = chars[k];
-
-        /* Step 7. */
-        if (c != '%')
-            goto step_18;
-
-        /* Step 8. */
-        if (k > length - 6)
-            goto step_14;
-
-        /* Step 9. */
-        if (chars[k + 1] != 'u')
-            goto step_14;
-
 #define ENSURE_BUILDING                                      \
         do {                                                 \
             if (!building) {                                 \
                 building = true;                             \
                 if (!sb.reserve(length))                     \
                     return false;                            \
                 sb.infallibleAppend(chars.begin().get(), k); \
             }                                                \
         } while(false);
 
-        /* Step 10-13. */
-        if (Unhex4(chars.begin() + k + 2, &c)) {
-            ENSURE_BUILDING;
-            k += 5;
-            goto step_18;
+    // Step 4.
+    uint32_t k = 0;
+
+    // Step 5.
+    while (k < length) {
+        // Step 5.a.
+        char16_t c = chars[k];
+
+        // Step 5.b.
+        if (c == '%') {
+            static_assert(JSString::MAX_LENGTH < UINT32_MAX - 6,
+                          "String length is not near UINT32_MAX");
+
+            // Steps 5.b.i-ii.
+            if (k + 6 <= length && chars[k + 1] == 'u') {
+                if (Unhex4(chars.begin() + k + 2, &c)) {
+                    ENSURE_BUILDING
+                    k += 5;
+                }
+            } else if (k + 3 <= length) {
+                if (Unhex2(chars.begin() + k + 1, &c)) {
+                    ENSURE_BUILDING
+                    k += 2;
+                }
+            }
         }
 
-      step_14:
-        /* Step 14. */
-        if (k > length - 3)
-            goto step_18;
-
-        /* Step 15-17. */
-        if (Unhex2(chars.begin() + k + 1, &c)) {
-            ENSURE_BUILDING;
-            k += 2;
-        }
-
-      step_18:
+        // Step 5.c.
         if (building && !sb.append(c))
             return false;
 
-        /* Step 19. */
+        // Step 5.d.
         k += 1;
     }
 
     return true;
 #undef ENSURE_BUILDING
 }
 
-/* ES5 B.2.2 */
+// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
+// B.2.1.2 unescape ( string )
 static bool
 str_unescape(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    /* Step 1. */
+    // Step 1.
     RootedLinearString str(cx, ArgToRootedString(cx, args, 0));
     if (!str)
         return false;
 
-    /* Step 3. */
+    // Step 3.
     StringBuffer sb(cx);
     if (str->hasTwoByteChars() && !sb.ensureTwoByteChars())
         return false;
 
+    // Steps 2, 4-5.
     if (str->hasLatin1Chars()) {
         AutoCheckCannotGC nogc;
         if (!Unescape(sb, str->latin1Range(nogc)))
             return false;
     } else {
         AutoCheckCannotGC nogc;
         if (!Unescape(sb, str->twoByteRange(nogc)))
             return false;
     }
 
+    // Step 6.
     JSLinearString* result;
     if (!sb.empty()) {
         result = sb.finishString();
         if (!result)
             return false;
     } else {
         result = str;
     }
@@ -598,135 +737,16 @@ js::SubstringKernel(JSContext* cx, Handl
             return nullptr;
 
         return JSRope::new_<CanGC>(cx, lhs, rhs, len);
     }
 
     return NewDependentString(cx, str, begin, len);
 }
 
-template <typename CharT> struct MaximumInlineLength;
-
-template<> struct MaximumInlineLength<Latin1Char> {
-    static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
-};
-
-template<> struct MaximumInlineLength<char16_t> {
-    static constexpr size_t value = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
-};
-
-// Character buffer class used for ToLowerCase and ToUpperCase operations.
-//
-// Case conversion operations normally return a string with the same length as
-// the input string. To avoid over-allocation, we optimistically allocate an
-// array with same size as the input string and only when we detect special
-// casing characters, which can change the output string length, we reallocate
-// the output buffer to the final string length.
-//
-// As a further mean to improve runtime performance, the character buffer
-// contains an inline storage, so we don't need to heap-allocate an array when
-// a JSInlineString will be used for the output string.
-//
-// Why not use mozilla::Vector instead? mozilla::Vector doesn't provide enough
-// fine-grained control to avoid over-allocation when (re)allocating for exact
-// buffer sizes. This led to visible performance regressions in µ-benchmarks.
-template <typename CharT>
-class MOZ_NON_PARAM InlineCharBuffer
-{
-    using CharPtr = UniquePtr<CharT[], JS::FreePolicy>;
-    static constexpr size_t InlineCapacity = MaximumInlineLength<CharT>::value;
-
-    CharT inlineStorage[InlineCapacity];
-    CharPtr heapStorage;
-
-#ifdef DEBUG
-    // In debug mode, we keep track of the requested string lengths to ensure
-    // all character buffer methods are called in the correct order and with
-    // the expected argument values.
-    size_t lastRequestedLength = 0;
-
-    void assertValidRequest(size_t expectedLastLength, size_t length) {
-        MOZ_ASSERT(length > expectedLastLength, "cannot shrink requested length");
-        MOZ_ASSERT(lastRequestedLength == expectedLastLength);
-        lastRequestedLength = length;
-    }
-#else
-    void assertValidRequest(size_t expectedLastLength, size_t length) {}
-#endif
-
-  public:
-    CharT* get()
-    {
-        return heapStorage ? heapStorage.get() : inlineStorage;
-    }
-
-    bool maybeAlloc(JSContext* cx, size_t length)
-    {
-        assertValidRequest(0, length);
-
-        if (length <= InlineCapacity)
-            return true;
-
-        MOZ_ASSERT(!heapStorage, "heap storage already allocated");
-        heapStorage = cx->make_pod_array<CharT>(length + 1);
-        return !!heapStorage;
-    }
-
-    bool maybeRealloc(JSContext* cx, size_t oldLength, size_t newLength)
-    {
-        assertValidRequest(oldLength, newLength);
-
-        if (newLength <= InlineCapacity)
-            return true;
-
-        if (!heapStorage) {
-            heapStorage = cx->make_pod_array<CharT>(newLength + 1);
-            if (!heapStorage)
-                return false;
-
-            MOZ_ASSERT(oldLength <= InlineCapacity);
-            PodCopy(heapStorage.get(), inlineStorage, oldLength);
-            return true;
-        }
-
-        CharT* oldChars = heapStorage.release();
-        CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
-        if (!newChars) {
-            js_free(oldChars);
-            return false;
-        }
-
-        heapStorage.reset(newChars);
-        return true;
-    }
-
-    JSString* toString(JSContext* cx, size_t length)
-    {
-        MOZ_ASSERT(length == lastRequestedLength);
-
-        if (JSInlineString::lengthFits<CharT>(length)) {
-            MOZ_ASSERT(!heapStorage,
-                       "expected only inline storage when length fits in inline string");
-
-            mozilla::Range<const CharT> range(inlineStorage, length);
-            return NewInlineString<CanGC>(cx, range);
-        }
-
-        MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
-
-        heapStorage.get()[length] = '\0'; // Null-terminate
-        JSString* res = NewStringDontDeflate<CanGC>(cx, heapStorage.get(), length);
-        if (!res)
-            return nullptr;
-
-        mozilla::Unused << heapStorage.release();
-        return res;
-    }
-};
-
 /**
  * U+03A3 GREEK CAPITAL LETTER SIGMA has two different lower case mappings
  * depending on its context:
  * When it's preceded by a cased character and not followed by another cased
  * character, its lower case form is U+03C2 GREEK SMALL LETTER FINAL SIGMA.
  * Otherwise its lower case mapping is U+03C3 GREEK SMALL LETTER SIGMA.
  *
  * Unicode 9.0, §3.13 Default Case Algorithms
@@ -958,17 +978,17 @@ ToLowerCase(JSContext* cx, JSLinearStrin
             if (!newChars.maybeRealloc(cx, length, resultLength))
                 return nullptr;
 
             MOZ_ALWAYS_TRUE(length ==
                 ToLowerCaseImpl(newChars.get(), chars, readChars, length, resultLength));
         }
     }
 
-    return newChars.toString(cx, resultLength);
+    return newChars.toStringDontDeflate(cx, resultLength);
 }
 
 JSString*
 js::StringToLowerCase(JSContext* cx, HandleLinearString string)
 {
     if (string->hasLatin1Chars())
         return ToLowerCase<Latin1Char>(cx, string);
     return ToLowerCase<char16_t>(cx, string);
@@ -1294,18 +1314,18 @@ ToUpperCase(JSContext* cx, JSLinearStrin
             newChars.construct<TwoByteBuffer>();
 
             if (!ToUpperCase(cx, newChars.ref<TwoByteBuffer>(), chars, i, length, &resultLength))
                 return nullptr;
         }
     }
 
     return newChars.constructed<Latin1Buffer>()
-           ? newChars.ref<Latin1Buffer>().toString(cx, resultLength)
-           : newChars.ref<TwoByteBuffer>().toString(cx, resultLength);
+           ? newChars.ref<Latin1Buffer>().toStringDontDeflate(cx, resultLength)
+           : newChars.ref<TwoByteBuffer>().toStringDontDeflate(cx, resultLength);
 }
 
 JSString*
 js::StringToUpperCase(JSContext* cx, HandleLinearString string)
 {
     if (string->hasLatin1Chars())
         return ToUpperCase<Latin1Char>(cx, string);
     return ToUpperCase<char16_t>(cx, string);
@@ -3218,86 +3238,63 @@ js::StringConstructor(JSContext* cx, uns
         args.rval().setObject(*strobj);
         return true;
     }
 
     args.rval().setString(str);
     return true;
 }
 
-static bool
-str_fromCharCode_few_args(JSContext* cx, const CallArgs& args)
-{
-    MOZ_ASSERT(args.length() <= JSFatInlineString::MAX_LENGTH_TWO_BYTE);
-
-    char16_t chars[JSFatInlineString::MAX_LENGTH_TWO_BYTE];
-    for (unsigned i = 0; i < args.length(); i++) {
-        uint16_t code;
-        if (!ToUint16(cx, args[i], &code))
-            return false;
-        chars[i] = char16_t(code);
-    }
-    JSString* str = NewStringCopyN<CanGC>(cx, chars, args.length());
-    if (!str)
-        return false;
-    args.rval().setString(str);
-    return true;
-}
-
 bool
 js::str_fromCharCode(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
 
     // Optimize the single-char case.
     if (args.length() == 1)
         return str_fromCharCode_one_arg(cx, args[0], args.rval());
 
     // Optimize the case where the result will definitely fit in an inline
     // string (thin or fat) and so we don't need to malloc the chars. (We could
     // cover some cases where args.length() goes up to
     // JSFatInlineString::MAX_LENGTH_LATIN1 if we also checked if the chars are
     // all Latin-1, but it doesn't seem worth the effort.)
-    if (args.length() <= JSFatInlineString::MAX_LENGTH_TWO_BYTE)
-        return str_fromCharCode_few_args(cx, args);
-
-    char16_t* chars = cx->pod_malloc<char16_t>(args.length() + 1);
-    if (!chars)
+    InlineCharBuffer<char16_t> chars;
+    if (!chars.maybeAlloc(cx, args.length()))
         return false;
+
+    char16_t* rawChars = chars.get();
     for (unsigned i = 0; i < args.length(); i++) {
         uint16_t code;
-        if (!ToUint16(cx, args[i], &code)) {
-            js_free(chars);
+        if (!ToUint16(cx, args[i], &code))
             return false;
-        }
-        chars[i] = char16_t(code);
+
+        rawChars[i] = char16_t(code);
     }
-    chars[args.length()] = 0;
-    JSString* str = NewString<CanGC>(cx, chars, args.length());
-    if (!str) {
-        js_free(chars);
+
+    JSString* str = chars.toString(cx, args.length());
+    if (!str)
         return false;
-    }
 
     args.rval().setString(str);
     return true;
 }
 
 static inline bool
 CodeUnitToString(JSContext* cx, uint16_t ucode, MutableHandleValue rval)
 {
     if (StaticStrings::hasUnit(ucode)) {
         rval.setString(cx->staticStrings().getUnit(ucode));
         return true;
     }
 
     char16_t c = char16_t(ucode);
-    JSString* str = NewStringCopyN<CanGC>(cx, &c, 1);
+    JSString* str = NewStringCopyNDontDeflate<CanGC>(cx, &c, 1);
     if (!str)
         return false;
 
     rval.setString(str);
     return true;
 }
 
 bool
@@ -3317,17 +3314,17 @@ ToCodePoint(JSContext* cx, HandleValue c
     // String.fromCodePoint, Steps 5.a-b.
     double nextCP;
     if (!ToNumber(cx, code, &nextCP))
         return false;
 
     // String.fromCodePoint, Steps 5.c-d.
     if (JS::ToInteger(nextCP) != nextCP || nextCP < 0 || nextCP > unicode::NonBMPMax) {
         ToCStringBuf cbuf;
-        if (char* numStr = NumberToCString(cx, &cbuf, nextCP))
+        if (const char* numStr = NumberToCString(cx, &cbuf, nextCP))
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_A_CODEPOINT, numStr);
         return false;
     }
 
     *codePoint = uint32_t(nextCP);
     return true;
 }
 
@@ -3402,17 +3399,17 @@ js::str_fromCodePoint(JSContext* cx, uns
     // JSFatInlineString::MAX_LENGTH_LATIN1 / 2 if we also checked if the chars
     // are all Latin-1, but it doesn't seem worth the effort.)
     if (args.length() <= JSFatInlineString::MAX_LENGTH_TWO_BYTE / 2)
         return str_fromCodePoint_few_args(cx, args);
 
     // Steps 1-2 (omitted).
 
     // Step 3.
-    static_assert(ARGS_LENGTH_MAX < std::numeric_limits<size_t>::max() / 2,
+    static_assert(ARGS_LENGTH_MAX < std::numeric_limits<decltype(args.length())>::max() / 2,
                   "|args.length() * 2 + 1| does not overflow");
     char16_t* elements = cx->pod_malloc<char16_t>(args.length() * 2 + 1);
     if (!elements)
         return false;
 
     // Steps 4-5.
     unsigned length = 0;
     for (unsigned nextIndex = 0; nextIndex < args.length(); nextIndex++) {
@@ -3636,20 +3633,19 @@ js::ValueToSource(JSContext* cx, HandleV
         return cx->names().void0;
     if (v.isString())
         return StringToSource(cx, v.toString());
     if (v.isSymbol())
         return SymbolToSource(cx, v.toSymbol());
     if (v.isPrimitive()) {
         /* Special case to preserve negative zero, _contra_ toString. */
         if (v.isDouble() && IsNegativeZero(v.toDouble())) {
-            /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
-            static const char16_t js_negzero_ucNstr[] = {'-', '0'};
-
-            return NewStringCopyN<CanGC>(cx, js_negzero_ucNstr, 2);
+            static const Latin1Char negativeZero[] = {'-', '0'};
+
+            return NewStringCopyN<CanGC>(cx, negativeZero, mozilla::ArrayLength(negativeZero));
         }
         return ToString<CanGC>(cx, v);
     }
 
     RootedValue fval(cx);
     RootedObject obj(cx, &v.toObject());
     if (!GetProperty(cx, obj, obj, cx->names().toSource, &fval))
         return nullptr;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2423,16 +2423,24 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("CallTypedArrayMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0),
 
     JS_FN("CallLegacyGeneratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<LegacyGeneratorObject>>, 2, 0),
     JS_FN("CallStarGeneratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
 
+    JS_INLINABLE_FN("IsMapObject", intrinsic_IsInstanceOfBuiltin<MapObject>, 1, 0,
+                    IntrinsicIsMapObject),
+    JS_FN("CallMapMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<MapObject>>, 2, 0),
+
+    JS_INLINABLE_FN("IsSetObject", intrinsic_IsInstanceOfBuiltin<SetObject>, 1, 0,
+                    IntrinsicIsSetObject),
+    JS_FN("CallSetMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0),
+
     JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin<WeakSetObject>, 1,0),
     JS_FN("CallWeakSetMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
 
     // See builtin/TypedObject.h for descriptors of the typedobj functions.
     JS_FN("NewOpaqueTypedObject",           js::NewOpaqueTypedObject, 1, 0),
     JS_FN("NewDerivedTypedObject",          js::NewDerivedTypedObject, 3, 0),
     JS_FN("TypedObjectBuffer",              TypedObject::GetBuffer, 1, 0),
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -143,17 +143,17 @@ ErrorReporter::ErrorReporter(const nsCSS
                              const Loader* aLoader,
                              nsIURI* aURI)
   : mScanner(&aScanner), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
     mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
     mErrorColNumber(0)
 {
 }
 
-ErrorReporter::ErrorReporter(const StyleSheet* aSheet,
+ErrorReporter::ErrorReporter(const ServoStyleSheet* aSheet,
                              const Loader* aLoader,
                              nsIURI* aURI)
   : mScanner(nullptr), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
     mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
     mErrorColNumber(0)
 {
 }
 
@@ -250,50 +250,64 @@ ErrorReporter::OutputError(uint32_t aLin
 // - the column number of the error
 // - the complete source line containing the invalid CSS
 
 void
 ErrorReporter::OutputError(uint32_t aLineNumber,
                            uint32_t aColNumber,
                            const nsACString& aSourceLine)
 {
-  mErrorLine.Truncate();
-  // This could be a really long string for minified CSS; just leave it empty if we OOM.
-  if (!AppendUTF8toUTF16(aSourceLine, mErrorLine, fallible)) {
+  mErrorLineNumber = aLineNumber;
+  mErrorColNumber = aColNumber;
+
+  // Retrieve the error line once per line, and reuse the same nsString
+  // for all errors on that line.  That causes the text of the line to
+  // be shared among all the nsIScriptError objects.
+  if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
     mErrorLine.Truncate();
+    // This could be a really long string for minified CSS; just leave it empty if we OOM.
+    if (!AppendUTF8toUTF16(aSourceLine, mErrorLine, fallible)) {
+      mErrorLine.Truncate();
+    }
+
+    mPrevErrorLineNumber = aLineNumber;
   }
-  mPrevErrorLineNumber = aLineNumber;
-  OutputError(aLineNumber, aColNumber);
+
+  OutputError();
 }
 
 void
 ErrorReporter::ClearError()
 {
   mError.Truncate();
 }
 
 void
 ErrorReporter::AddToError(const nsString &aErrorText)
 {
   if (!ShouldReportErrors()) return;
 
   if (mError.IsEmpty()) {
     mError = aErrorText;
-    mErrorLineNumber = mScanner ? mScanner->GetLineNumber() : 0;
-    mErrorColNumber = mScanner ? mScanner->GetColumnNumber() : 0;
-    // Retrieve the error line once per line, and reuse the same nsString
-    // for all errors on that line.  That causes the text of the line to
-    // be shared among all the nsIScriptError objects.
-    if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
-      // Be careful here: the error line might be really long and OOM
-      // when we try to make a copy here.  If so, just leave it empty.
-      if (!mScanner || !mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
-        mErrorLine.Truncate();
+    // If this error reporter is being used from Stylo, the equivalent operation occurs
+    // in the OutputError variant that provides source information.
+    if (!IsServo()) {
+      mErrorLineNumber = mScanner->GetLineNumber();
+      mErrorColNumber = mScanner->GetColumnNumber();
+      // Retrieve the error line once per line, and reuse the same nsString
+      // for all errors on that line.  That causes the text of the line to
+      // be shared among all the nsIScriptError objects.
+      if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
+        // Be careful here: the error line might be really long and OOM
+        // when we try to make a copy here.  If so, just leave it empty.
+        if (!mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
+          mErrorLine.Truncate();
+        }
+        mPrevErrorLineNumber = mErrorLineNumber;
       }
-      mPrevErrorLineNumber = mErrorLineNumber;
     }
   } else {
     mError.AppendLiteral("  ");
     mError.Append(aErrorText);
   }
 }
 
 void
@@ -414,12 +428,18 @@ ErrorReporter::ReportUnexpectedEOF(char1
 
   nsAutoString str;
   sStringBundle->FormatStringFromName("PEUnexpEOF2",
                                       params, ArrayLength(params),
                                       getter_Copies(str));
   AddToError(str);
 }
 
+bool
+ErrorReporter::IsServo() const
+{
+  return !mScanner;
+}
+
 } // namespace css
 } // namespace mozilla
 
 #endif
--- a/layout/style/ErrorReporter.h
+++ b/layout/style/ErrorReporter.h
@@ -27,17 +27,17 @@ class Loader;
 // If CSS_REPORT_PARSE_ERRORS is not defined, all of this class's
 // methods become inline stubs.
 class ErrorReporter {
 public:
   ErrorReporter(const nsCSSScanner &aScanner,
                 const StyleSheet *aSheet,
                 const Loader *aLoader,
                 nsIURI *aURI);
-  ErrorReporter(const StyleSheet *aSheet,
+  ErrorReporter(const ServoStyleSheet *aSheet,
                 const Loader *aLoader,
                 nsIURI *aURI);
   ~ErrorReporter();
 
   static void ReleaseGlobals();
 
   void OutputError();
   void OutputError(uint32_t aLineNumber, uint32_t aLineOffset);
@@ -68,16 +68,18 @@ public:
   // name or a single character.  In the former case there may not be
   // any format parameters.
   void ReportUnexpectedEOF(const char *aExpected);
   void ReportUnexpectedEOF(char16_t aExpected);
 
 private:
   void AddToError(const nsString &aErrorText);
 
+  bool IsServo() const;
+
 #ifdef CSS_REPORT_PARSE_ERRORS
   nsAutoString mError;
   nsString mErrorLine;
   nsString mFileName;
   const nsCSSScanner *mScanner;
   const StyleSheet *mSheet;
   const Loader *mLoader;
   nsIURI *mURI;
--- a/media/libjpeg/LICENSE.md
+++ b/media/libjpeg/LICENSE.md
@@ -4,22 +4,21 @@ libjpeg-turbo Licenses
 libjpeg-turbo is covered by three compatible BSD-style open source licenses:
 
 - The IJG (Independent JPEG Group) License, which is listed in
   [README.ijg](README.ijg)
 
   This license applies to the libjpeg API library and associated programs
   (any code inherited from libjpeg, and any modifications to that code.)
 
-- The Modified (3-clause) BSD License, which is listed in
-  [turbojpeg.c](turbojpeg.c)
+- The Modified (3-clause) BSD License, which is listed below
 
   This license covers the TurboJPEG API library and associated programs.
 
-- The zlib License, which is listed in [simd/jsimdext.inc](simd/jsimdext.inc)
+- The zlib License, which is listed below
 
   This license is a subset of the other two, and it covers the libjpeg-turbo
   SIMD extensions.
 
 
 Complying with the libjpeg-turbo Licenses
 =========================================
 
@@ -81,8 +80,60 @@ 3.  You cannot use the name of the IJG o
 4.  The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be
     free of defects, nor do we accept any liability for undesirable
     consequences resulting from your use of the software.
 
     **Origin**
     - IJG License
     - Modified BSD License
     - zlib License
+
+
+The Modified (3-clause) BSD License
+===================================
+
+Copyright (C)\<YEAR\> \<AUTHOR\>.  All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+- Neither the name of the libjpeg-turbo Project nor the names of its
+  contributors may be used to endorse or promote products derived from this
+  software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+The zlib License
+================
+
+Copyright (C) \<YEAR\>, \<AUTHOR\>.
+
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
--- a/media/libjpeg/README.md
+++ b/media/libjpeg/README.md
@@ -37,25 +37,25 @@ Refer to [BUILDING.md](BUILDING.md) for 
 
 
 Using libjpeg-turbo
 ===================
 
 libjpeg-turbo includes two APIs that can be used to compress and decompress
 JPEG images:
 
-- **TurboJPEG API**  
+- **TurboJPEG API**<br>
   This API provides an easy-to-use interface for compressing and decompressing
   JPEG images in memory.  It also provides some functionality that would not be
   straightforward to achieve using the underlying libjpeg API, such as
   generating planar YUV images and performing multiple simultaneous lossless
   transforms on an image.  The Java interface for libjpeg-turbo is written on
   top of the TurboJPEG API.
 
-- **libjpeg API**  
+- **libjpeg API**<br>
   This is the de facto industry-standard API for compressing and decompressing
   JPEG images.  It is more difficult to use than the TurboJPEG API but also
   more powerful.  The libjpeg API implementation in libjpeg-turbo is both
   API/ABI-compatible and mathematically compatible with libjpeg v6b.  It can
   also optionally be configured to be API/ABI-compatible with libjpeg v7 and v8
   (see below.)
 
 There is no significant performance advantage to either API when both are used
@@ -136,27 +136,27 @@ version of libjpeg-turbo that emulates t
 programs that are built against libjpeg v7 or v8 can be run with libjpeg-turbo.
 The following section describes which libjpeg v7+ features are supported and
 which aren't.
 
 ### Support for libjpeg v7 and v8 Features
 
 #### Fully supported
 
-- **libjpeg: IDCT scaling extensions in decompressor**  
+- **libjpeg: IDCT scaling extensions in decompressor**<br>
   libjpeg-turbo supports IDCT scaling with scaling factors of 1/8, 1/4, 3/8,
   1/2, 5/8, 3/4, 7/8, 9/8, 5/4, 11/8, 3/2, 13/8, 7/4, 15/8, and 2/1 (only 1/4
   and 1/2 are SIMD-accelerated.)
 
 - **libjpeg: Arithmetic coding**
 
-- **libjpeg: In-memory source and destination managers**  
+- **libjpeg: In-memory source and destination managers**<br>
   See notes below.
 
-- **cjpeg: Separate quality settings for luminance and chrominance**  
+- **cjpeg: Separate quality settings for luminance and chrominance**<br>
   Note that the libpjeg v7+ API was extended to accommodate this feature only
   for convenience purposes.  It has always been possible to implement this
   feature with libjpeg v6b (see rdswitch.c for an example.)
 
 - **cjpeg: 32-bit BMP support**
 
 - **cjpeg: `-rgb` option**
 
@@ -175,45 +175,45 @@ which aren't.
 
 NOTE:  As of this writing, extensive research has been conducted into the
 usefulness of DCT scaling as a means of data reduction and SmartScale as a
 means of quality improvement.  The reader is invited to peruse the research at
 <http://www.libjpeg-turbo.org/About/SmartScale> and draw his/her own conclusions,
 but it is the general belief of our project that these features have not
 demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.
 
-- **libjpeg: DCT scaling in compressor**  
+- **libjpeg: DCT scaling in compressor**<br>
   `cinfo.scale_num` and `cinfo.scale_denom` are silently ignored.
   There is no technical reason why DCT scaling could not be supported when
   emulating the libjpeg v7+ API/ABI, but without the SmartScale extension (see
   below), only scaling factors of 1/2, 8/15, 4/7, 8/13, 2/3, 8/11, 4/5, and
   8/9 would be available, which is of limited usefulness.
 
-- **libjpeg: SmartScale**  
+- **libjpeg: SmartScale**<br>
   `cinfo.block_size` is silently ignored.
   SmartScale is an extension to the JPEG format that allows for DCT block
   sizes other than 8x8.  Providing support for this new format would be
   feasible (particularly without full acceleration.)  However, until/unless
   the format becomes either an official industry standard or, at minimum, an
   accepted solution in the community, we are hesitant to implement it, as
   there is no sense of whether or how it might change in the future.  It is
   our belief that SmartScale has not demonstrated sufficient usefulness as a
   lossless format nor as a means of quality enhancement, and thus our primary
   interest in providing this feature would be as a means of supporting
   additional DCT scaling factors.
 
-- **libjpeg: Fancy downsampling in compressor**  
+- **libjpeg: Fancy downsampling in compressor**<br>
   `cinfo.do_fancy_downsampling` is silently ignored.
   This requires the DCT scaling feature, which is not supported.
 
-- **jpegtran: Scaling**  
+- **jpegtran: Scaling**<br>
   This requires both the DCT scaling and SmartScale features, which are not
   supported.
 
-- **Lossless RGB JPEG files**  
+- **Lossless RGB JPEG files**<br>
   This requires the SmartScale feature, which is not supported.
 
 ### What About libjpeg v9?
 
 libjpeg v9 introduced yet another field to the JPEG compression structure
 (`color_transform`), thus making the ABI backward incompatible with that of
 libjpeg v8.  This new field was introduced solely for the purpose of supporting
 lossless SmartScale encoding.  Furthermore, there was actually no reason to
@@ -221,17 +221,17 @@ extend the API in this manner, as the co
 been activated by way of a new JPEG colorspace constant, thus preserving
 backward ABI compatibility.
 
 Our research (see link above) has shown that lossless SmartScale does not
 generally accomplish anything that can't already be accomplished better with
 existing, standard lossless formats.  Therefore, at this time it is our belief
 that there is not sufficient technical justification for software projects to
 upgrade from libjpeg v8 to libjpeg v9, and thus there is not sufficient
-echnical justification for us to emulate the libjpeg v9 ABI.
+technical justification for us to emulate the libjpeg v9 ABI.
 
 In-Memory Source/Destination Managers
 -------------------------------------
 
 By default, libjpeg-turbo 1.3 and later includes the `jpeg_mem_src()` and
 `jpeg_mem_dest()` functions, even when not emulating the libjpeg v8 API/ABI.
 Previously, it was necessary to build libjpeg-turbo from source with libjpeg v8
 API/ABI emulation in order to use the in-memory source/destination managers,
@@ -244,18 +244,18 @@ libjpeg-turbo binaries.
 Those who are concerned about maintaining strict conformance with the libjpeg
 v6b or v7 API can pass an argument of `--without-mem-srcdst` to `configure` or
 an argument of `-DWITH_MEM_SRCDST=0` to `cmake` prior to building
 libjpeg-turbo.  This will restore the pre-1.3 behavior, in which
 `jpeg_mem_src()` and `jpeg_mem_dest()` are only included when emulating the
 libjpeg v8 API/ABI.
 
 On Un*x systems, including the in-memory source/destination managers changes
-the dynamic library version from 62.0.0 to 62.1.0 if using libjpeg v6b API/ABI
-emulation and from 7.0.0 to 7.1.0 if using libjpeg v7 API/ABI emulation.
+the dynamic library version from 62.1.0 to 62.2.0 if using libjpeg v6b API/ABI
+emulation and from 7.1.0 to 7.2.0 if using libjpeg v7 API/ABI emulation.
 
 Note that, on most Un*x systems, the dynamic linker will not look for a
 function in a library until that function is actually used.  Thus, if a program
 is built against libjpeg-turbo 1.3+ and uses `jpeg_mem_src()` or
 `jpeg_mem_dest()`, that program will not fail if run against an older version
 of libjpeg-turbo or against libjpeg v7- until the program actually tries to
 call `jpeg_mem_src()` or `jpeg_mem_dest()`.  Such is not the case on Windows.
 If a program is built against the libjpeg-turbo 1.3+ DLL and uses
--- a/media/libjpeg/jconfig.h
+++ b/media/libjpeg/jconfig.h
@@ -1,16 +1,16 @@
 /* jconfig.h.  Generated from jconfig.h.in by configure, then manually edited
    for Mozilla. */
 
 /* Export libjpeg v6.2's ABI. */
 #define JPEG_LIB_VERSION 62
 
 /* libjpeg-turbo version */
-#define LIBJPEG_TURBO_VERSION 1.5.1
+#define LIBJPEG_TURBO_VERSION 1.5.2
 
 /* Support arithmetic encoding */
 /*#undef C_ARITH_CODING_SUPPORTED */
 
 /* Support arithmetic decoding */
 /*#undef D_ARITH_CODING_SUPPORTED */
 
 /*
--- a/media/libjpeg/jconfigint.h
+++ b/media/libjpeg/jconfigint.h
@@ -1,7 +1,7 @@
-#define VERSION "1.5.1"
-#define BUILD "2016-09-20"
+#define VERSION "1.5.2"
+#define BUILD "2017-07-07"
 #define PACKAGE_NAME "libjpeg-turbo"
 
 /* Need to use Mozilla-specific function inlining. */
 #include "mozilla/Attributes.h"
 #define INLINE MOZ_ALWAYS_INLINE
--- a/media/libjpeg/jdarith.c
+++ b/media/libjpeg/jdarith.c
@@ -16,16 +16,19 @@
  * Suspension is not currently supported in this module.
  */
 
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
 
 
+#define NEG_1 ((unsigned int)-1)
+
+
 /* Expanded entropy decoder object for arithmetic decoding. */
 
 typedef struct {
   struct jpeg_entropy_decoder pub; /* public fields */
 
   JLONG c;       /* C register, base of coding interval + input bit buffer */
   JLONG a;               /* A register, normalized size of coding interval */
   int ct;     /* bit shift counter, # of bits left in bit buffer part of C */
@@ -445,17 +448,17 @@ decode_mcu_AC_refine (j_decompress_ptr c
 
   if (entropy->ct == -1) return TRUE;   /* if error do nothing */
 
   /* There is always only one block per MCU */
   block = MCU_data[0];
   tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
 
   p1 = 1 << cinfo->Al;          /* 1 in the bit position being coded */
-  m1 = (-1) << cinfo->Al;       /* -1 in the bit position being coded */
+  m1 = (NEG_1) << cinfo->Al;    /* -1 in the bit position being coded */
 
   /* Establish EOBx (previous stage end-of-block) index */
   for (kex = cinfo->Se; kex > 0; kex--)
     if ((*block)[jpeg_natural_order[kex]]) break;
 
   for (k = cinfo->Ss; k <= cinfo->Se; k++) {
     st = entropy->ac_stats[tbl] + 3 * (k - 1);
     if (k > kex)
--- a/media/libjpeg/jmemmgr.c
+++ b/media/libjpeg/jmemmgr.c
@@ -27,18 +27,20 @@
  * memory then you shouldn't care about a little bit of unused code...)
  */
 
 #define JPEG_INTERNALS
 #define AM_MEMORY_MANAGER       /* we define jvirt_Xarray_control structs */
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jmemsys.h"            /* import the system-dependent declarations */
+#ifndef _WIN32
 #include <stdint.h>
-#include <limits.h>             /* some NDKs define SIZE_MAX in limits.h */
+#endif
+#include <limits.h>
 
 #ifndef NO_GETENV
 #ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare getenv() */
 extern char *getenv (const char *name);
 #endif
 #endif
 
 
--- a/media/libjpeg/jmemnobs.c
+++ b/media/libjpeg/jmemnobs.c
@@ -1,26 +1,25 @@
 /*
  * jmemnobs.c
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1992-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code and
- * information relevant to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2017, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
  * This file provides a really simple implementation of the system-
  * dependent portion of the JPEG memory manager.  This implementation
  * assumes that no backing-store files are needed: all required space
  * can be obtained from malloc().
  * This is very portable in the sense that it'll compile on almost anything,
  * but you'd better have lots of main memory (or virtual memory) if you want
  * to process big images.
- * Note that the max_memory_to_use option is ignored by this implementation.
  */
 
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jmemsys.h"            /* import the system-dependent declarations */
 
 #ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc(),free() */
@@ -61,24 +60,31 @@ GLOBAL(void)
 jpeg_free_large (j_common_ptr cinfo, void *object, size_t sizeofobject)
 {
   free(object);
 }
 
 
 /*
  * This routine computes the total memory space available for allocation.
- * Here we always say, "we got all you want bud!"
  */
 
 GLOBAL(size_t)
 jpeg_mem_available (j_common_ptr cinfo, size_t min_bytes_needed,
                     size_t max_bytes_needed, size_t already_allocated)
 {
-  return max_bytes_needed;
+  if (cinfo->mem->max_memory_to_use) {
+    if (cinfo->mem->max_memory_to_use > already_allocated)
+      return cinfo->mem->max_memory_to_use - already_allocated;
+    else
+      return 0;
+  } else {
+    /* Here we always say, "we got all you want bud!" */
+    return max_bytes_needed;
+  }
 }
 
 
 /*
  * Backing store (temporary file) management.
  * Since jpeg_mem_available always promised the moon,
  * this should never be called and we can just error out.
  */
--- a/media/libjpeg/jversion.h
+++ b/media/libjpeg/jversion.h
@@ -1,15 +1,15 @@
 /*
  * jversion.h
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2016, D. R. Commander.
+ * Copyright (C) 2010, 2012-2017, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
  * This file contains software version identification.
  */
 
 
 #if JPEG_LIB_VERSION >= 80
@@ -30,20 +30,20 @@
  * NOTE: It is our convention to place the authors in the following order:
  * - libjpeg-turbo authors (2009-) in descending order of the date of their
  *   most recent contribution to the project, then in ascending order of the
  *   date of their first contribution to the project
  * - Upstream authors in descending order of the date of the first inclusion of
  *   their code
  */
 
-#define JCOPYRIGHT      "Copyright (C) 2009-2016 D. R. Commander\n" \
+#define JCOPYRIGHT      "Copyright (C) 2009-2017 D. R. Commander\n" \
                         "Copyright (C) 2011-2016 Siarhei Siamashka\n" \
                         "Copyright (C) 2015-2016 Matthieu Darbois\n" \
                         "Copyright (C) 2015 Google, Inc.\n" \
                         "Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \
                         "Copyright (C) 2013 Linaro Limited\n" \
                         "Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
                         "Copyright (C) 2009 Pierre Ossman for Cendio AB\n" \
                         "Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
                         "Copyright (C) 1991-2016 Thomas G. Lane, Guido Vollbeding" \
 
-#define JCOPYRIGHT_SHORT "Copyright (C) 1991-2016 The libjpeg-turbo Project and many others"
+#define JCOPYRIGHT_SHORT "Copyright (C) 1991-2017 The libjpeg-turbo Project and many others"
--- a/media/libjpeg/mozilla.diff
+++ b/media/libjpeg/mozilla.diff
@@ -1,29 +1,8 @@
-diff --git jmemmgr.c jmemmgr.c
---- jmemmgr.c
-+++ jmemmgr.c
-@@ -28,16 +28,17 @@
-  */
- 
- #define JPEG_INTERNALS
- #define AM_MEMORY_MANAGER       /* we define jvirt_Xarray_control structs */
- #include "jinclude.h"
- #include "jpeglib.h"
- #include "jmemsys.h"            /* import the system-dependent declarations */
- #include <stdint.h>
-+#include <limits.h>             /* some NDKs define SIZE_MAX in limits.h */
- 
- #ifndef NO_GETENV
- #ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare getenv() */
- extern char *getenv (const char *name);
- #endif
- #endif
-
-
 diff --git jmorecfg.h jmorecfg.h
 --- jmorecfg.h
 +++ jmorecfg.h
 @@ -9,16 +9,17 @@
   * For conditions of distribution and use, see the accompanying README.ijg
   * file.
   *
   * This file contains additional configuration options that customize the
--- a/media/libjpeg/simd/jchuff-sse2.asm
+++ b/media/libjpeg/simd/jchuff-sse2.asm
@@ -1,12 +1,12 @@
 ;
 ; jchuff-sse2.asm - Huffman entropy encoding (SSE2)
 ;
-; Copyright (C) 2009-2011, 2014-2016, D. R. Commander.
+; Copyright (C) 2009-2011, 2014-2017, D. R. Commander.
 ; Copyright (C) 2015, Matthieu Darbois.
 ;
 ; Based on the x86 SIMD extension for IJG JPEG library
 ; Copyright (C) 1999-2006, MIYASAKA Masaru.
 ; For conditions of distribution and use, see copyright notice in jsimdext.inc
 ;
 ; This file should be assembled with NASM (Netwide Assembler),
 ; can *not* be assembled with Microsoft's MASM or any compatible
@@ -283,23 +283,23 @@ EXTN(jsimd_huff_encode_one_block_sse2):
         or  edx, ecx
         not edx  ; index = ~index;
 
         lea esi, [esp+t1]
         mov ebp, POINTER [esp+actbl]  ; ebp = actbl
 
 .BLOOP:
         bsf ecx, edx  ; r = __builtin_ctzl(index);
-        jz .ELOOP
+        jz near .ELOOP
         lea esi, [esi+ecx*2]  ; k += r;
         shr edx, cl  ; index >>= r;
         mov DWORD [esp+temp3], edx
 .BRLOOP:
         cmp ecx, 16  ; while (r > 15) {
-        jl .ERLOOP
+        jl near .ERLOOP
         sub ecx, 16 ; r -= 16;
         mov DWORD [esp+temp], ecx
         mov   eax, INT [ebp + 240 * 4]  ; code_0xf0 = actbl->ehufco[0xf0];
         movzx ecx, byte [ebp + 1024 + 240]  ; size_0xf0 = actbl->ehufsi[0xf0];
         EMIT_BITS eax  ; EMIT_BITS(code_0xf0, size_0xf0)
         mov ecx, DWORD [esp+temp]
         jmp .BRLOOP
 .ERLOOP:
@@ -343,31 +343,31 @@ EXTN(jsimd_huff_encode_one_block_sse2):
         shl ecx, 16
         or  edx, ecx
         not edx  ; index = ~index;
 
         lea eax, [esp + t1 + (DCTSIZE2/2) * 2]
         sub eax, esi
         shr eax, 1
         bsf ecx, edx  ; r = __builtin_ctzl(index);
-        jz .ELOOP2
+        jz near .ELOOP2
         shr edx, cl  ; index >>= r;
         add ecx, eax
         lea esi, [esi+ecx*2]  ; k += r;
         mov DWORD [esp+temp3], edx
         jmp .BRLOOP2
 .BLOOP2:
         bsf ecx, edx  ; r = __builtin_ctzl(index);
-        jz .ELOOP2
+        jz near .ELOOP2
         lea esi, [esi+ecx*2]  ; k += r;
         shr edx, cl  ; index >>= r;
         mov DWORD [esp+temp3], edx
 .BRLOOP2:
         cmp ecx, 16  ; while (r > 15) {
-        jl .ERLOOP2
+        jl near .ERLOOP2
         sub ecx, 16  ; r -= 16;
         mov DWORD [esp+temp], ecx
         mov   eax, INT [ebp + 240 * 4]  ; code_0xf0 = actbl->ehufco[0xf0];
         movzx ecx, byte [ebp + 1024 + 240]  ; size_0xf0 = actbl->ehufsi[0xf0];
         EMIT_BITS eax  ; EMIT_BITS(code_0xf0, size_0xf0)
         mov ecx, DWORD [esp+temp]
         jmp .BRLOOP2
 .ERLOOP2:
--- a/media/libjpeg/simd/jsimd_arm.c
+++ b/media/libjpeg/simd/jsimd_arm.c
@@ -1,12 +1,13 @@
 /*
  * jsimd_arm.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
  * Copyright (C) 2009-2011, 2013-2014, 2016, D. R. Commander.
  * Copyright (C) 2015-2016, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
  * For conditions of distribution and use, see copyright notice in jsimdext.inc
  *
  * This file contains the interface between the "normal" portions
--- a/media/libjpeg/simd/jsimd_arm64.c
+++ b/media/libjpeg/simd/jsimd_arm64.c
@@ -1,12 +1,13 @@
 /*
  * jsimd_arm64.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
  * Copyright (C) 2009-2011, 2013-2014, 2016, D. R. Commander.
  * Copyright (C) 2015-2016, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
  * For conditions of distribution and use, see copyright notice in jsimdext.inc
  *
  * This file contains the interface between the "normal" portions
--- a/media/libjpeg/simd/jsimd_mips.c
+++ b/media/libjpeg/simd/jsimd_mips.c
@@ -58,16 +58,18 @@ parse_proc_cpuinfo(const char* search_st
 /*
  * Check what SIMD accelerations are supported.
  *
  * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd (void)
 {
+  char *env = NULL;
+
   if (simd_support != ~0U)
     return;
 
   simd_support = 0;
 
 #if defined(__MIPSEL__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2)
   simd_support |= JSIMD_MIPS_DSPR2;
 #elif defined(__linux__)
--- a/media/libjpeg/simd/jsimd_powerpc.c
+++ b/media/libjpeg/simd/jsimd_powerpc.c
@@ -9,28 +9,39 @@
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
  * For conditions of distribution and use, see copyright notice in jsimdext.inc
  *
  * This file contains the interface between the "normal" portions
  * of the library and the SIMD implementations when running on a
  * PowerPC architecture.
  */
 
+#ifdef __amigaos4__
+/* This must be defined first as it re-defines GLOBAL otherwise */
+#include <proto/exec.h>
+#endif
+
 #define JPEG_INTERNALS
 #include "../jinclude.h"
 #include "../jpeglib.h"
 #include "../jsimd.h"
 #include "../jdct.h"
 #include "../jsimddct.h"
 #include "jsimd.h"
 
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 
+#if defined(__OpenBSD__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <machine/cpu.h>
+#endif
+
 static unsigned int simd_support = ~0;
 
 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
 
 #define SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT (1024 * 1024)
 
 LOCAL(int)
 check_feature (char *buffer, char *feature)
@@ -96,31 +107,44 @@ parse_proc_cpuinfo (int bufsize)
  * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd (void)
 {
   char *env = NULL;
 #if !defined(__ALTIVEC__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__))
   int bufsize = 1024; /* an initial guess for the line buffer size limit */
+#elif defined(__amigaos4__)
+  uint32 altivec = 0;
+#elif defined(__OpenBSD__)
+  int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC };
+  int altivec;
+  size_t len = sizeof(altivec);
 #endif
 
   if (simd_support != ~0U)
     return;
 
   simd_support = 0;
 
 #if defined(__ALTIVEC__) || defined(__APPLE__)
   simd_support |= JSIMD_ALTIVEC;
 #elif defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
   while (!parse_proc_cpuinfo(bufsize)) {
     bufsize *= 2;
     if (bufsize > SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT)
       break;
   }
+#elif defined(__amigaos4__)
+  IExec->GetCPUInfoTags(GCIT_VectorUnit, &altivec, TAG_DONE);
+  if(altivec == VECTORTYPE_ALTIVEC)
+    simd_support |= JSIMD_ALTIVEC;
+#elif defined(__OpenBSD__)
+  if (sysctl(mib, 2, &altivec, &len, NULL, 0) == 0 && altivec != 0)
+    simd_support |= JSIMD_ALTIVEC;
 #endif
 
   /* Force different settings through environment variables */
   env = getenv("JSIMD_FORCEALTIVEC");
   if ((env != NULL) && (strcmp(env, "1") == 0))
     simd_support = JSIMD_ALTIVEC;
   env = getenv("JSIMD_FORCENONE");
   if ((env != NULL) && (strcmp(env, "1") == 0))
--- a/media/webrtc/signaling/gtest/mediaconduit_unittests.cpp
+++ b/media/webrtc/signaling/gtest/mediaconduit_unittests.cpp
@@ -1,121 +1,43 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <iostream>
 #include <string>
 #include <fstream>
-#include <unistd.h>
 #include <vector>
 #include <math.h>
 
 using namespace std;
 
-#include "mozilla/SyncRunnable.h"
+#include <MediaConduitInterface.h>
+#include <VideoConduit.h>
 #include "mozilla/UniquePtr.h"
-#include <MediaConduitInterface.h>
-#include "nsIEventTarget.h"
-#include "nsThreadUtils.h"
+#include "nss.h"
 #include "runnable_utils.h"
 #include "signaling/src/common/EncodingConstraints.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
-//Video Frame Color
-const int COLOR = 0x80; //Gray
+const uint32_t SSRC = 1;
 
 //MWC RNG of George Marsaglia
 //taken from xiph.org
 static int32_t Rz, Rw;
 static inline int32_t fast_rand(void)
 {
   Rz=36969*(Rz&65535)+(Rz>>16);
   Rw=18000*(Rw&65535)+(Rw>>16);
   return (Rz<<16)+Rw;
 }
 
 /**
-  * Global structure to store video test results.
-  */
-struct VideoTestStats
-{
- int numRawFramesInserted;
- int numFramesRenderedSuccessfully;
- int numFramesRenderedWrongly;
-};
-
-VideoTestStats vidStatsGlobal={0,0,0};
-
-/**
- * A Dummy Video Conduit Tester.
- * The test-case inserts a 640*480 grey imagerevery 33 milliseconds
- * to the video-conduit for encoding and transporting.
- */
-
-class VideoSendAndReceive
-{
-public:
-  VideoSendAndReceive():width(640),
-                        height(480),
-			rate(30)
-  {
-  }
-
-  ~VideoSendAndReceive()
-  {
-  }
-
-  void SetDimensions(int w, int h)
-  {
-    width = w;
-    height = h;
-  }
-  void SetRate(int r) {
-    rate = r;
-  }
-  void Init(RefPtr<mozilla::VideoSessionConduit> aSession)
-  {
-        mSession = aSession;
-        mLen = ((width * height) * 3 / 2);
-        mFrame = mozilla::MakeUnique<uint8_t[]>(mLen);
-        memset(mFrame.get(), COLOR, mLen);
-        numFrames = 121;
-  }
-
-  void GenerateAndReadSamples()
-  {
-    do
-    {
-      mSession->SendVideoFrame(reinterpret_cast<unsigned char*>(mFrame.get()),
-                                mLen,
-                                width,
-                                height,
-                                mozilla::kVideoI420,
-                                0);
-      PR_Sleep(PR_MillisecondsToInterval(1000/rate));
-      vidStatsGlobal.numRawFramesInserted++;
-      numFrames--;
-    } while(numFrames >= 0);
-  }
-
-private:
-RefPtr<mozilla::VideoSessionConduit> mSession;
-mozilla::UniquePtr<uint8_t[]> mFrame;
-int mLen;
-int width, height;
-int rate;
-int numFrames;
-};
-
-
-
-/**
  * A Dummy AudioConduit Tester
  * The test reads PCM samples of a standard test file and
  * passws to audio-conduit for encoding, RTPfication and
  * decoding every 10 milliseconds.
  * This decoded samples are read-off the conduit for writing
  * into output audio file in PCM format.
  */
 class AudioSendAndReceive
@@ -339,86 +261,16 @@ void AudioSendAndReceive::GenerateAndRea
     }
    }while(numSamplesReadFromInput < SAMPLES);
 
    FinishWaveHeader(outFile);
    free(inbuf);
    fclose(outFile);
 }
 
-/**
- * Dummy Video Target for the conduit
- * This class acts as renderer attached to the video conduit
- * As of today we just verify if the frames rendered are exactly
- * the same as frame inserted at the first place
- */
-class DummyVideoTarget: public mozilla::VideoRenderer
-{
-public:
-  DummyVideoTarget()
-  {
-  }
-
-  virtual ~DummyVideoTarget()
-  {
-  }
-
-
-  void RenderVideoFrame(const unsigned char* buffer,
-                        size_t buffer_size,
-                        uint32_t y_stride,
-                        uint32_t cbcr_stride,
-                        uint32_t time_stamp,
-                        int64_t render_time,
-                        const mozilla::ImageHandle& handle) override
-  {
-    RenderVideoFrame(buffer, buffer_size, time_stamp, render_time, handle);
-  }
-
-  void RenderVideoFrame(const unsigned char* buffer,
-                        size_t buffer_size,
-                        uint32_t time_stamp,
-                        int64_t render_time,
-                        const mozilla::ImageHandle& handle) override
- {
-  //write the frame to the file
-  if(VerifyFrame(buffer, buffer_size) == 0)
-  {
-      vidStatsGlobal.numFramesRenderedSuccessfully++;
-  } else
-  {
-      vidStatsGlobal.numFramesRenderedWrongly++;
-  }
- }
-
- void FrameSizeChange(unsigned int, unsigned int, unsigned int) override
- {
-    //do nothing
- }
-
- //This is hardcoded to check if the contents of frame is COLOR
- // as we set while sending.
- int VerifyFrame(const unsigned char* buffer, unsigned int buffer_size)
- {
-    int good = 0;
-    for(int i=0; i < (int) buffer_size; i++)
-    {
-      if(buffer[i] == COLOR)
-      {
-        ++good;
-      }
-      else
-      {
-        --good;
-      }
-    }
-   return 0;
- }
-
-};
 
 /**
  *  Webrtc Audio and Video External Transport Class
  *  The functions in this class will be invoked by the conduit
  *  when it has RTP/RTCP frame to transmit.
  *  For everty RTP/RTCP frame we receive, we pass it back
  *  to the conduit for eventual decoding and rendering.
  */
@@ -433,22 +285,23 @@ public:
 
   ~WebrtcMediaTransport()
   {
   }
 
   virtual nsresult SendRtpPacket(const uint8_t* data, size_t len)
   {
     ++numPkts;
+
     if(mAudio)
     {
-      mOtherAudioSession->ReceivedRTPPacket(data,len);
+      mOtherAudioSession->ReceivedRTPPacket(data,len,SSRC);
     } else
     {
-      mOtherVideoSession->ReceivedRTPPacket(data,len);
+      mOtherVideoSession->ReceivedRTPPacket(data,len,SSRC);
     }
     return NS_OK;
   }
 
   virtual nsresult SendRtcpPacket(const uint8_t* data, size_t len)
   {
     if(mAudio)
     {
@@ -497,16 +350,18 @@ class TransportConduitTest : public ::te
 {
  public:
 
   TransportConduitTest()
   {
     //input and output file names
     iAudiofilename = "input.wav";
     oAudiofilename = "recorded.wav";
+
+    NSS_NoDB_Init(nullptr);
   }
 
   ~TransportConduitTest()
   {
     mAudioSession = nullptr;
     mAudioSession2 = nullptr;
     mAudioTransport = nullptr;
 
@@ -570,165 +425,97 @@ class TransportConduitTest : public ::te
     cerr << "   ******************************************************** " << endl;
     audioTester.GenerateAndReadSamples();
     cerr << "   ******************************************************** " << endl;
     cerr << "    Input Audio  File                " << iAudiofilename << endl;
     cerr << "    Output Audio File                " << oAudiofilename << endl;
     cerr << "   ******************************************************** " << endl;
   }
 
-  //2. Dump audio samples to dummy external transport
-  void TestDummyVideoAndTransport(const char *source_file = nullptr)
-  {
-    int err = 0;
-    //get pointer to VideoSessionConduit
-    mVideoSession = VideoSessionConduit::Create();
-    if( !mVideoSession )
-      ASSERT_NE(mVideoSession, (void*)nullptr);
-
-    // This session is for other one
-    mVideoSession2 = VideoSessionConduit::Create();
-    if( !mVideoSession2 )
-      ASSERT_NE(mVideoSession2,(void*)nullptr);
-
-    mVideoRenderer = new DummyVideoTarget();
-    ASSERT_NE(mVideoRenderer, (void*)nullptr);
-
-    WebrtcMediaTransport* xport = new WebrtcMediaTransport();
-    ASSERT_NE(xport, (void*)nullptr);
-    xport->SetVideoSession(mVideoSession,mVideoSession2);
-    mVideoTransport = xport;
-
-    // attach the transport and renderer to video-conduit
-    err = mVideoSession2->AttachRenderer(mVideoRenderer);
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-    err = mVideoSession->SetTransmitterTransport(mVideoTransport);
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-    err = mVideoSession2->SetReceiverTransport(mVideoTransport);
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-
-    mozilla::EncodingConstraints constraints;
-    //configure send and recv codecs on theconduit
-    mozilla::VideoCodecConfig cinst1(120, "VP8", constraints);
-    mozilla::VideoCodecConfig cinst2(124, "I420", constraints);
-
-
-    std::vector<mozilla::VideoCodecConfig* > rcvCodecList;
-    rcvCodecList.push_back(&cinst1);
-    rcvCodecList.push_back(&cinst2);
-
-    err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
-
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-    err = mVideoSession->StartTransmitting();
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-
-    err = mVideoSession2->ConfigureSendMediaCodec(&cinst1);
-    err = mVideoSession2->StartTransmitting();
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-    err = mVideoSession2->ConfigureRecvMediaCodecs(rcvCodecList);
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-
-    //start generating samples
-    cerr << "   *************************************************" << endl;
-    cerr << "    Starting the Video Sample Generation " << endl;
-    cerr << "   *************************************************" << endl;
-    videoTester.Init(mVideoSession);
-    videoTester.GenerateAndReadSamples();
-
-    cerr << "   **************************************************" << endl;
-    cerr << "    Done With The Testing  " << endl;
-    cerr << "    VIDEO TEST STATS  "  << endl;
-    cerr << "    Num Raw Frames Inserted: "<<
-                                        vidStatsGlobal.numRawFramesInserted << endl;
-    cerr << "    Num Frames Successfully Rendered: "<<
-                                        vidStatsGlobal.numFramesRenderedSuccessfully << endl;
-    cerr << "    Num Frames Wrongly Rendered: "<<
-                                        vidStatsGlobal.numFramesRenderedWrongly << endl;
-
-    cerr << "    Done With The Testing  " << endl;
-
-    cerr << "   **************************************************" << endl;
-
-    ASSERT_EQ(0, vidStatsGlobal.numFramesRenderedWrongly);
-    ASSERT_EQ(vidStatsGlobal.numRawFramesInserted,
-		          vidStatsGlobal.numFramesRenderedSuccessfully);
-  }
-
- void TestVideoConduitCodecAPI()
+  void TestVideoConduitCodecAPI()
   {
     int err = 0;
     RefPtr<mozilla::VideoSessionConduit> videoSession;
     //get pointer to VideoSessionConduit
-    videoSession = VideoSessionConduit::Create();
+    videoSession = VideoSessionConduit::Create(WebRtcCallWrapper::Create());
     if( !videoSession )
       ASSERT_NE(videoSession, (void*)nullptr);
 
+    std::vector<unsigned int> ssrcs = {SSRC};
+    videoSession->SetLocalSSRCs(ssrcs);
+
     //Test Configure Recv Codec APIS
     cerr << "   *************************************************" << endl;
     cerr << "    Test Receive Codec Configuration API Now " << endl;
     cerr << "   *************************************************" << endl;
 
     std::vector<mozilla::VideoCodecConfig* > rcvCodecList;
 
     //Same APIs
+    mozilla::EncodingConstraints constraints;
+    mozilla::VideoCodecConfig cinst1(120, "VP8", constraints);
+    VideoCodecConfig::SimulcastEncoding encoding;
+    cinst1.mSimulcastEncodings.push_back(encoding);
+
+    // This test is disabled because with the current code this will trigger an
+    // assertion in video_receive_stream.cc because we this results in a
+    // duplicate payload type for different encoders.
+    /*
     cerr << "   *************************************************" << endl;
     cerr << "    1. Same Codec (VP8) Repeated Twice " << endl;
     cerr << "   *************************************************" << endl;
 
-    mozilla::EncodingConstraints constraints;
-    mozilla::VideoCodecConfig cinst1(120, "VP8", constraints);
     mozilla::VideoCodecConfig cinst2(120, "VP8", constraints);
+    cinst2.mSimulcastEncodings.push_back(encoding);
     rcvCodecList.push_back(&cinst1);
     rcvCodecList.push_back(&cinst2);
     err = videoSession->ConfigureRecvMediaCodecs(rcvCodecList);
     EXPECT_EQ(err, mozilla::kMediaConduitNoError);
     rcvCodecList.pop_back();
     rcvCodecList.pop_back();
-
+    */
 
     cerr << "   *************************************************" << endl;
     cerr << "    2. Codec With Invalid Payload Names " << endl;
     cerr << "   *************************************************" << endl;
     cerr << "   Setting payload 1 with name: I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676" << endl;
     cerr << "   Setting payload 2 with name of zero length" << endl;
 
     mozilla::VideoCodecConfig cinst3(124, "I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676", constraints);
+    cinst3.mSimulcastEncodings.push_back(encoding);
     mozilla::VideoCodecConfig cinst4(124, "", constraints);
+    cinst4.mSimulcastEncodings.push_back(encoding);
 
     rcvCodecList.push_back(&cinst3);
     rcvCodecList.push_back(&cinst4);
 
     err = videoSession->ConfigureRecvMediaCodecs(rcvCodecList);
     EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
     rcvCodecList.pop_back();
     rcvCodecList.pop_back();
 
 
     cerr << "   *************************************************" << endl;
     cerr << "    3. Null Codec Parameter  " << endl;
     cerr << "   *************************************************" << endl;
 
-    rcvCodecList.push_back(0);
+    rcvCodecList.push_back(nullptr);
 
     err = videoSession->ConfigureRecvMediaCodecs(rcvCodecList);
     EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
     rcvCodecList.pop_back();
 
     cerr << "   *************************************************" << endl;
     cerr << "    Test Send Codec Configuration API Now " << endl;
     cerr << "   *************************************************" << endl;
 
     cerr << "   *************************************************" << endl;
     cerr << "    1. Same Codec (VP8) Repeated Twice " << endl;
     cerr << "   *************************************************" << endl;
 
-
     err = videoSession->ConfigureSendMediaCodec(&cinst1);
     EXPECT_EQ(mozilla::kMediaConduitNoError, err);
     err = videoSession->StartTransmitting();
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
     err = videoSession->ConfigureSendMediaCodec(&cinst1);
     EXPECT_EQ(mozilla::kMediaConduitNoError, err);
     err = videoSession->StartTransmitting();
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
@@ -755,150 +542,148 @@ class TransportConduitTest : public ::te
   {
     cerr << "Applying max_fs=" << max_fs << " to input resolution " <<
                  orig_width << "x" << orig_height << endl;
     cerr << "New resolution: " << new_width << "x" << new_height << endl;
     cerr << endl;
   }
 
   // Calculate new resolution for sending video by applying max-fs constraint.
-  void GetVideoResolutionWithMaxFs(int orig_width, int orig_height, int max_fs,
-                                   int *new_width, int *new_height)
+  void GetVideoResolutionWithMaxFs(unsigned short orig_width,
+                                   unsigned short orig_height,
+                                   int max_fs,
+                                   unsigned short &new_width,
+                                   unsigned short &new_height)
   {
     int err = 0;
 
     // Get pointer to VideoSessionConduit.
-    mVideoSession = VideoSessionConduit::Create();
+    mVideoSession = VideoSessionConduit::Create(WebRtcCallWrapper::Create());
     if( !mVideoSession )
       ASSERT_NE(mVideoSession, (void*)nullptr);
 
+    std::vector<unsigned int> ssrcs = {SSRC};
+    mVideoSession->SetLocalSSRCs(ssrcs);
+
     mozilla::EncodingConstraints constraints;
     constraints.maxFs = max_fs;
     // Configure send codecs on the conduit.
     mozilla::VideoCodecConfig cinst1(120, "VP8", constraints);
+    VideoCodecConfig::SimulcastEncoding encoding;
+    cinst1.mSimulcastEncodings.push_back(encoding);
 
     err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
     err = mVideoSession->StartTransmitting();
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
 
     // Send one frame.
     MOZ_ASSERT(!(orig_width & 1));
     MOZ_ASSERT(!(orig_height & 1));
-    int len = ((orig_width * orig_height) * 3 / 2);
-    uint8_t* frame = (uint8_t*) malloc(len);
-
-    memset(frame, COLOR, len);
-    mVideoSession->SendVideoFrame((unsigned char*)frame,
-                                  len,
-                                  orig_width,
-                                  orig_height,
-                                  mozilla::kVideoI420,
-                                  0);
-    free(frame);
 
     // Get the new resolution as adjusted by the max-fs constraint.
-    *new_width = mVideoSession->SendingWidth();
-    *new_height = mVideoSession->SendingHeight();
+    mVideoSession->SetSendingWidthAndHeight(orig_width, orig_height,
+                                            new_width, new_height);
   }
 
   void TestVideoConduitMaxFs()
   {
-    int orig_width, orig_height, width, height, max_fs;
+    unsigned short orig_width, orig_height, width, height;
+    int max_fs;
 
     // No limitation.
     cerr << "Test no max-fs limition" << endl;
     orig_width = 640;
     orig_height = 480;
     max_fs = 0;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 640);
     ASSERT_EQ(height, 480);
 
     // VGA to QVGA.
     cerr << "Test resizing from VGA to QVGA" << endl;
     orig_width = 640;
     orig_height = 480;
     max_fs = 300;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 320);
     ASSERT_EQ(height, 240);
 
     // Extreme input resolution.
     cerr << "Test extreme input resolution" << endl;
     orig_width = 3072;
     orig_height = 100;
     max_fs = 300;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 768);
     ASSERT_EQ(height, 25);
 
     // Small max-fs.
     cerr << "Test small max-fs (case 1)" << endl;
     orig_width = 8;
     orig_height = 32;
     max_fs = 1;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 4);
     ASSERT_EQ(height, 16);
 
     // Small max-fs.
     cerr << "Test small max-fs (case 2)" << endl;
     orig_width = 4;
     orig_height = 50;
     max_fs = 1;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 1);
     ASSERT_EQ(height, 16);
 
     // Small max-fs.
     cerr << "Test small max-fs (case 3)" << endl;
     orig_width = 872;
     orig_height = 136;
     max_fs = 3;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 48);
     ASSERT_EQ(height, 7);
 
     // Small max-fs.
     cerr << "Test small max-fs (case 4)" << endl;
     orig_width = 160;
     orig_height = 8;
     max_fs = 5;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 80);
     ASSERT_EQ(height, 4);
 
      // Extremely small width and height(see bug 919979).
     cerr << "Test with extremely small width and height" << endl;
     orig_width = 2;
     orig_height = 2;
     max_fs = 5;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
+    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
     DumpMaxFs(orig_width, orig_height, max_fs, width, height);
     ASSERT_EQ(width, 2);
     ASSERT_EQ(height, 2);
 
     // Random values.
     cerr << "Test with random values" << endl;
     for (int i = 0; i < 30; i++) {
       cerr << ".";
       max_fs = rand() % 1000;
       orig_width = ((rand() % 2000) & ~1) + 2;
       orig_height = ((rand() % 2000) & ~1) + 2;
 
       GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs,
-                                  &width, &height);
+                                  width, height);
       if (max_fs > 0 &&
           ceil(width / 16.) * ceil(height / 16.) > max_fs) {
         DumpMaxFs(orig_width, orig_height, max_fs, width, height);
         ADD_FAILURE();
       }
     }
     cerr << endl;
  }
@@ -910,37 +695,29 @@ class TransportConduitTest : public ::te
   RefPtr<mozilla::TransportInterface> mAudioTransport;
   AudioSendAndReceive audioTester;
 
   //Video Conduit Test Objects
   RefPtr<mozilla::VideoSessionConduit> mVideoSession;
   RefPtr<mozilla::VideoSessionConduit> mVideoSession2;
   RefPtr<mozilla::VideoRenderer> mVideoRenderer;
   RefPtr<mozilla::TransportInterface> mVideoTransport;
-  VideoSendAndReceive videoTester;
 
   std::string fileToPlay;
   std::string fileToRecord;
   std::string iAudiofilename;
   std::string oAudiofilename;
 };
 
 
-// Test 1: Test Dummy External Xport
-// See Bug 1319121
+// Disabled, see Bug 1319121
 TEST_F(TransportConduitTest, DISABLED_TestDummyAudioWithTransport) {
   TestDummyAudioAndTransport();
 }
 
-// Test 2: Test Dummy External Xport
-// See Bug 1319121
-TEST_F(TransportConduitTest, DISABLED_TestDummyVideoWithTransport) {
-  TestDummyVideoAndTransport();
- }
-
 TEST_F(TransportConduitTest, TestVideoConduitCodecAPI) {
   TestVideoConduitCodecAPI();
  }
 
 TEST_F(TransportConduitTest, TestVideoConduitMaxFs) {
   TestVideoConduitMaxFs();
  }
 
--- a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
@@ -29,17 +29,17 @@
 #include "SharedBuffer.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
 using namespace mozilla;
 MOZ_MTLOG_MODULE("mediapipeline")
 
-MtransportTestUtils *test_utils;
+static MtransportTestUtils *test_utils;
 
 namespace {
 
 class FakeSourceMediaStream : public mozilla::SourceMediaStream {
 
 public:
 
   FakeSourceMediaStream()
--- a/media/webrtc/signaling/gtest/moz.build
+++ b/media/webrtc/signaling/gtest/moz.build
@@ -1,16 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # TODO: bug 1172551 - get these tests working on iOS
-if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uikit':
+if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uikit' and CONFIG['OS_TARGET'] != 'Android':
     if CONFIG['OS_TARGET'] == 'Linux':
         DEFINES['WEBRTC_LINUX'] = True
         DEFINES['WEBRTC_POSIX'] = True
     elif CONFIG['OS_TARGET'] in ('DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD'):
         DEFINES['WEBRTC_BSD'] = True
         DEFINES['WEBRTC_POSIX'] = True
     elif CONFIG['OS_TARGET'] == 'Darwin':
         DEFINES['WEBRTC_MAC'] = True
@@ -20,31 +20,33 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uiki
 
     LOCAL_INCLUDES += [
       '/dom/media',
       '/ipc/chromium/src',
       '/media/mtransport',
       '/media/mtransport/test',
       '/media/mtransport/third_party/nrappkit/src/registry',
       '/media/webrtc/',
+      '/media/webrtc/signaling/src/common',
       '/media/webrtc/signaling/src/common/time_profiling',
       '/media/webrtc/signaling/src/media-conduit',
       '/media/webrtc/signaling/src/mediapipeline',
       '/media/webrtc/signaling/src/peerconnection',
       '/media/webrtc/trunk',
     ]
 
     SOURCES += [
         'jsep_session_unittest.cpp',
         'jsep_track_unittest.cpp',
+        'mediaconduit_unittests.cpp',
         'sdp_unittests.cpp',
     ]
 
     # See Bug 1372950, mediapipeline tests seem to cause crashes on Windows
-    if CONFIG['OS_TARGET'] not in ('Android', 'WINNT'):
+    if CONFIG['OS_TARGET'] != 'WINNT':
         SOURCES += [
             'mediapipeline_unittest.cpp',
         ]
 
     FINAL_LIBRARY = 'xul-gtest'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
--- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
+++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
@@ -419,22 +419,23 @@ public:
    * NOTE: This API can be invoked multiple time. Invoking this API may involve restarting
    *        reception sub-system on the engine
    *
    */
   virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
       const std::vector<VideoCodecConfig* >& recvCodecConfigList) = 0;
 
   /**
-   * These methods allow unit tests to double-check that the
+   * This method allows unit tests to double-check that the
    * max-fs and max-fr related settings are as expected.
    */
-  virtual unsigned short SendingWidth() = 0;
-
-  virtual unsigned short SendingHeight() = 0;
+  virtual void SetSendingWidthAndHeight(unsigned short frame_width,
+                                        unsigned short frame_height,
+                                        unsigned short &result_width,
+                                        unsigned short &result_height) = 0;
 
   virtual unsigned int SendingMaxFs() = 0;
 
   virtual unsigned int SendingMaxFr() = 0;
 
   /**
     * These methods allow unit tests to double-check that the
     * rtcp-fb settings are as expected.
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -675,17 +675,17 @@ MediaConduitErrorCode
 WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
 {
   CSFLogDebug(logTag, "%s for %s", __FUNCTION__,
     codecConfig ? codecConfig->mName.c_str() : "<null>");
 
   MediaConduitErrorCode condError = kMediaConduitNoError;
 
   // validate basic params
-  if ((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError) {
+  if ((condError = ValidateCodecConfig(codecConfig)) != kMediaConduitNoError) {
     return condError;
   }
 
   size_t streamCount = std::min(codecConfig->mSimulcastEncodings.size(),
                                 (size_t)webrtc::kMaxSimulcastStreams);
   CSFLogDebug(logTag, "%s for VideoConduit:%p stream count:%d", __FUNCTION__,
               this, static_cast<int>(streamCount));
 
@@ -1275,25 +1275,25 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
   int ulpfec_payload_type = kNullPayloadType;
   int red_payload_type = kNullPayloadType;
   bool configuredH264 = false;
   nsTArray<UniquePtr<VideoCodecConfig>> recv_codecs;
 
   // Try Applying the codecs in the list
   // we treat as success if at least one codec was applied and reception was
   // started successfully.
+  std::set<unsigned int> codec_types_seen;
   for (const auto& codec_config : codecConfigList) {
-    // if the codec param is invalid or duplicate, return error
-    if ((condError = ValidateCodecConfig(codec_config, false))
+    if ((condError = ValidateCodecConfig(codec_config))
         != kMediaConduitNoError) {
       CSFLogError(logTag, "%s Invalid config for %s decoder: %i", __FUNCTION__,
-                  codec_config->mName.c_str(), condError);
+                  codec_config ? codec_config->mName.c_str() : "<null>",
+                  condError);
       continue;
     }
-
     if (codec_config->mName == "H264") {
       // TODO(bug 1200768): We can only handle configuring one recv H264 codec
       if (configuredH264) {
         continue;
       }
       configuredH264 = true;
     }
 
@@ -1325,16 +1325,21 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
     use_nack_basic |= codec_config->RtcpFbNackIsSet("");
     use_tmmbr |= codec_config->RtcpFbCcmIsSet("tmmbr");
     use_remb |= codec_config->RtcpFbRembIsSet();
     use_fec |= codec_config->RtcpFbFECIsSet();
 
     recv_codecs.AppendElement(new VideoCodecConfig(*codec_config));
   }
 
+  if (!recv_codecs.Length()) {
+    CSFLogError(logTag, "%s Found no valid receive codecs", __FUNCTION__);
+    return kMediaConduitMalformedArgument;
+  }
+
   // Now decide if we need to recreate the receive stream, or can keep it
   if (!mRecvStream ||
       CodecsDifferent(recv_codecs, mRecvCodecList) ||
       mRecvStreamConfig.rtp.nack.rtp_history_ms != (use_nack_basic ? 1000 : 0) ||
       mRecvStreamConfig.rtp.remb != use_remb ||
       mRecvStreamConfig.rtp.tmmbr != use_tmmbr ||
       mRecvStreamConfig.rtp.keyframe_method != kf_request_method ||
       (use_fec &&
@@ -1828,17 +1833,16 @@ WebrtcVideoConduit::SelectSendFrameRate(
 MediaConduitErrorCode
 WebrtcVideoConduit::SendVideoFrame(unsigned char* video_buffer,
                                    unsigned int video_length,
                                    unsigned short width,
                                    unsigned short height,
                                    VideoType video_type,
                                    uint64_t capture_time)
 {
-
   // check for parameter sanity
   if (!video_buffer || video_length == 0 || width == 0 || height == 0) {
     CSFLogError(logTag, "%s Invalid Parameters ", __FUNCTION__);
     MOZ_ASSERT(false);
     return kMediaConduitMalformedArgument;
   }
   MOZ_ASSERT(video_type == VideoType::kVideoI420);
 
@@ -2336,18 +2340,17 @@ WebrtcVideoConduit::CodecsDifferent(cons
   return false;
 }
 
 /**
  * Perform validation on the codecConfig to be applied
  * Verifies if the codec is already applied.
  */
 MediaConduitErrorCode
-WebrtcVideoConduit::ValidateCodecConfig(const VideoCodecConfig* codecInfo,
-                                        bool send)
+WebrtcVideoConduit::ValidateCodecConfig(const VideoCodecConfig* codecInfo)
 {
   if(!codecInfo) {
     CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
 
   if((codecInfo->mName.empty()) ||
      (codecInfo->mName.length() >= CODEC_PLNAME_SIZE)) {
@@ -2389,16 +2392,30 @@ WebrtcVideoConduit::CodecPluginID()
   }
   if (mRecvCodecPlugin) {
     return mRecvCodecPlugin->PluginID();
   }
 
   return 0;
 }
 
+void
+WebrtcVideoConduit::SetSendingWidthAndHeight(unsigned short frame_width,
+                                             unsigned short frame_height,
+                                             unsigned short &result_width,
+                                             unsigned short &result_height)
+{
+  MutexAutoLock lock(mCodecMutex);
+  result_width = 0;
+  result_height = 0;
+  (void)SelectSendResolution(frame_width, frame_height, nullptr);
+  result_width = mSendingWidth;
+  result_height = mSendingHeight;
+}
+
 bool
 WebrtcVideoConduit::RequiresNewSendStream(const VideoCodecConfig& newConfig) const
 {
   return !mCurSendCodecConfig
     || mCurSendCodecConfig->mName != newConfig.mName
     || mCurSendCodecConfig->mType != newConfig.mType
     || mCurSendCodecConfig->RtcpFbNackIsSet("") != newConfig.RtcpFbNackIsSet("")
     || mCurSendCodecConfig->RtcpFbFECIsSet() != newConfig.RtcpFbFECIsSet()
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -250,23 +250,24 @@ public:
   void OnSinkWantsChanged(const rtc::VideoSinkWants& wants);
 
   virtual uint64_t CodecPluginID() override;
 
   virtual void SetPCHandle(const std::string& aPCHandle) override {
     mPCHandle = aPCHandle;
   }
 
-  unsigned short SendingWidth() override {
-    return mSendingWidth;
-  }
-
-  unsigned short SendingHeight() override {
-    return mSendingHeight;
-  }
+  /**
+   * This method allows unit tests to double-check that the
+   * max-fs and max-fr related settings are as expected.
+   */
+  virtual void SetSendingWidthAndHeight(unsigned short frame_width,
+                                        unsigned short frame_height,
+                                        unsigned short &result_width,
+                                        unsigned short &result_height) override;
 
   unsigned int SendingMaxFs() override {
     if(mCurSendCodecConfig) {
       return mCurSendCodecConfig->mEncodingConstraints.maxFs;
     }
     return 0;
   }
 
@@ -445,17 +446,17 @@ private:
     std::vector<SimulcastStreamConfig> mSimulcastStreams;
   };
 
   //Function to convert between WebRTC and Conduit codec structures
   void CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
                                 webrtc::VideoCodec& cinst);
 
   //Checks the codec to be applied
-  MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo, bool send);
+  MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo);
 
   //Utility function to dump recv codec database
   void DumpCodecDB() const;
 
   bool CodecsDifferent(const nsTArray<UniquePtr<VideoCodecConfig>>& a,
                        const nsTArray<UniquePtr<VideoCodecConfig>>& b);
 
   // Factory class for VideoStreams... vie_encoder.cc will call this to reconfigure.
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
@@ -593,22 +593,24 @@ int32_t DesktopCaptureImpl::IncomingFram
     if (dst_width > dest_max_width || dst_height > dest_max_height) {
       scale_width = (float)dest_max_width / (float)dst_width;
       scale_height = (float)dest_max_height / (float)dst_height;
       scale = std::min(scale_width, scale_height);
       dst_width = (int)(scale * dst_width);
       dst_height = (int)(scale * dst_height);
     }
 
+    int dst_stride_y = dst_width;
+    int dst_stride_uv = (dst_width + 1) / 2;
     if (dst_width == target_width && dst_height == target_height) {
       DeliverCapturedFrame(captureFrame, captureTime);
     } else {
       rtc::scoped_refptr<webrtc::I420Buffer> buffer;
-      buffer = I420Buffer::Create(dst_width, dst_height, stride_y,
-                                  stride_uv, stride_uv);
+      buffer = I420Buffer::Create(dst_width, dst_height, dst_stride_y,
+                                  dst_stride_uv, dst_stride_uv);
 
       buffer->ScaleFrom(*captureFrame.video_frame_buffer().get());
       webrtc::VideoFrame scaledFrame(buffer, 0, 0, kVideoRotation_0);
       DeliverCapturedFrame(scaledFrame, captureTime);
     }
   } else {
     assert(false);
     return -1;
--- a/mobile/android/app/src/main/res/layout/customtabs_activity.xml
+++ b/mobile/android/app/src/main/res/layout/customtabs_activity.xml
@@ -22,16 +22,26 @@
 
     <org.mozilla.gecko.GeckoView
         android:id="@+id/gecko_view"
         android:layout_width="fill_parent"
         android:layout_below="@id/actionbar"
         android:layout_height="match_parent"
         android:scrollbars="none"/>
 
+    <ProgressBar
+        android:id="@id/page_progress"
+        style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="4dp"
+        android:layout_alignTop="@id/gecko_view"
+        android:background="@drawable/url_bar_bg"
+        android:progressDrawable="@drawable/progressbar"
+        tools:progress="70"/>
+
     <View android:id="@+id/custom_tabs_doorhanger_overlay"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:background="@color/dark_transparent_overlay"
         android:alpha="0"
         android:layerType="hardware"/>
 
 </RelativeLayout>
\ No newline at end of file
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -23,16 +23,17 @@ import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.widget.ProgressBar;
 
 import org.mozilla.gecko.ActivityHandlerHelper;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.GeckoViewSettings;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.SnackbarBuilder;
 import org.mozilla.gecko.Telemetry;
@@ -56,16 +57,17 @@ public class CustomTabsActivity extends 
                                            GeckoView.ProgressListener {
 
     private static final String LOGTAG = "CustomTabsActivity";
 
     private final SparseArrayCompat<PendingIntent> menuItemsIntent = new SparseArrayCompat<>();
     private GeckoPopupMenu popupMenu;
     private View doorhangerOverlay;
     private ActionBarPresenter actionBarPresenter;
+    private ProgressBar mProgressView;
     // A state to indicate whether this activity is finishing with customize animation
     private boolean usingCustomAnimation = false;
 
     private MenuItem menuItemControl;
 
     private GeckoView mGeckoView;
     private PromptService mPromptService;
 
@@ -81,16 +83,18 @@ public class CustomTabsActivity extends 
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.customtabs_activity);
 
         final SafeIntent intent = new SafeIntent(getIntent());
 
         doorhangerOverlay = findViewById(R.id.custom_tabs_doorhanger_overlay);
 
+        mProgressView = (ProgressBar) findViewById(R.id.page_progress);
+        updateProgress(10);
         final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);
         setSupportActionBar(toolbar);
         final ActionBar actionBar = getSupportActionBar();
         bindNavigationCallback(toolbar);
 
         actionBarPresenter = new ActionBarPresenter(actionBar, getActionBarTextColor());
         actionBarPresenter.displayUrlOnly(intent.getDataString());
         actionBarPresenter.setBackgroundColor(IntentUtil.getToolbarColor(intent), getWindow());
@@ -384,16 +388,29 @@ public class CustomTabsActivity extends 
             return;
         }
 
         final MenuItem forwardMenuItem = popupMenu.getMenu().findItem(R.id.custom_tabs_menu_forward);
         forwardMenuItem.setEnabled(mCanGoForward);
     }
 
     /**
+     * Update the state of the progress bar.
+     * @param progress The current loading progress; must be between 0 and 100
+     */
+    private void updateProgress(final int progress) {
+        if (mCanStop) {
+            mProgressView.setVisibility(View.VISIBLE);
+            mProgressView.setProgress(progress);
+        } else {
+            mProgressView.setVisibility(View.GONE);
+        }
+    }
+
+    /**
      * Update loading status of current page
      */
     private void updateCanStop() {
         if (menuItemControl != null) {
             Drawable icon = menuItemControl.getIcon();
             if (mCanStop) {
                 icon.setLevel(0);
             } else {
@@ -493,16 +510,17 @@ public class CustomTabsActivity extends 
         return null;
     }
 
     /* GeckoView.NavigationListener */
     @Override
     public void onLocationChange(GeckoView view, String url) {
         mCurrentUrl = url;
         updateActionBar();
+        updateProgress(60);
     }
 
     @Override
     public void onCanGoBack(GeckoView view, boolean canGoBack) {
         mCanGoBack = canGoBack;
     }
 
     @Override
@@ -513,26 +531,28 @@ public class CustomTabsActivity extends 
 
     /* GeckoView.ProgressListener */
     @Override
     public void onPageStart(GeckoView view, String url) {
         mCurrentUrl = url;
         mCanStop = true;
         updateActionBar();
         updateCanStop();
+        updateProgress(20);
     }
 
     @Override
     public void onPageStop(GeckoView view, boolean success) {
         mCanStop = false;
         updateCanStop();
+        updateProgress(100);
     }
 
     @Override
-    public void onSecurityChange(GeckoView view, int status) {
+    public void onSecurityChange(GeckoView view, int status, GeckoBundle identity) {
         if ((status & STATE_IS_INSECURE) != 0) {
             mSecurityStatus = STATE_IS_INSECURE;
         } else if ((status & STATE_IS_BROKEN) != 0) {
             mSecurityStatus = STATE_IS_BROKEN;
         } else if ((status & STATE_IS_SECURE) != 0) {
             mSecurityStatus = STATE_IS_SECURE;
         }
         updateActionBar();
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -157,19 +157,19 @@ public class GeckoView extends LayerView
                                       final EventCallback callback) {
                 if ("GeckoView:PageStart".equals(event)) {
                     listener.onPageStart(GeckoView.this,
                                          message.getString("uri"));
                 } else if ("GeckoView:PageStop".equals(event)) {
                     listener.onPageStop(GeckoView.this,
                                         message.getBoolean("success"));
                 } else if ("GeckoView:SecurityChanged".equals(event)) {
-                    int state = message.getInt("status") &
-                                GeckoView.ProgressListener.STATE_ALL;
-                    listener.onSecurityChange(GeckoView.this, state);
+                    final int state = message.getInt("status") & ProgressListener.STATE_ALL;
+                    final GeckoBundle identity = message.getBundle("identity");
+                    listener.onSecurityChange(GeckoView.this, state, identity);
                 }
             }
         };
 
     private final GeckoViewHandler<ScrollListener> mScrollHandler =
         new GeckoViewHandler<ScrollListener>(
             "GeckoViewScroll", this,
             new String[]{ "GeckoView:ScrollChanged" }
@@ -1140,18 +1140,36 @@ public class GeckoView extends LayerView
         * @param success Whether the page loaded successfully or an error occurred.
         */
         void onPageStop(GeckoView view, boolean success);
 
         /**
         * The security status has been updated.
         * @param view The GeckoView that initiated the callback.
         * @param status The new security status.
+        * @param identity A bundle containing the most up-to-date security information, with keys:
+        *          "origin": A string containing the origin of the cert, should always be present
+        *          "secure": A boolean indicating whether or not the site is secure
+        *          "host": A string containing the host associated with the certificate
+        *          "security_exception": A boolean indicating if the site is a security exception
+        *          "organization": A string containing the human readable name of the subject
+        *          "subjectName": A string containing the full subject name (including location data)
+        *          "issuerCommonName": A string containing the common name of the issuing authority
+        *          "issuerOrganization": A string containing the proper name of the issuing authority
+        *          "mode": A GeckoBundle containing information about the security mode, with keys:
+        *            "identity": A string indicating the security level of the site, should always be
+        *                        present. Possible values are "unknown", "identified", and "verified"
+        *            "mixed_display": A string indicating if passive mixed content is present, possible
+        *                             values are: "unknown", "blocked", "loaded"
+        *            "mixed_active": A string indicating if active mixed content is present, possible
+        *                            values are: "unknown", "blocked", "loaded"
+        *            "tracking": A string indicating the status of tracking protection, possible values
+        *                        are: "unknown", "blocked", "loaded"
         */
-        void onSecurityChange(GeckoView view, int status);
+        void onSecurityChange(GeckoView view, int status, GeckoBundle identity);
     }
 
     public interface ContentListener {
         /**
         * A page title was discovered in the content or updated after the content
         * loaded.
         * @param view The GeckoView that initiated the callback.
         * @param title The title sent from the content.
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -11,16 +11,17 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.WindowManager;
 
 import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.GeckoViewSettings;
+import org.mozilla.gecko.util.GeckoBundle;
 
 public class GeckoViewActivity extends Activity {
     private static final String LOGTAG = "GeckoViewActivity";
     private static final String DEFAULT_URL = "https://mozilla.org";
     private static final String USE_MULTIPROCESS_EXTRA = "use_multiprocess";
 
     /* package */ static final int REQUEST_FILE_PICKER = 1;
 
@@ -123,17 +124,17 @@ public class GeckoViewActivity extends A
         @Override
         public void onPageStop(GeckoView view, boolean success) {
             Log.i(LOGTAG, "Stopping page load " + (success ? "successfully" : "unsuccessfully"));
             Log.i(LOGTAG, "zerdatime " + SystemClock.elapsedRealtime() +
                   " - page load stop");
         }
 
         @Override
-        public void onSecurityChange(GeckoView view, int status) {
+        public void onSecurityChange(GeckoView view, int status, GeckoBundle identity) {
             String statusString;
             if ((status & STATE_IS_BROKEN) != 0) {
                 statusString = "broken";
             } else if ((status & STATE_IS_SECURE) != 0) {
                 statusString = "secure";
             } else if ((status & STATE_IS_INSECURE) != 0) {
                 statusString = "insecure";
             } else {
--- a/mobile/android/modules/geckoview/GeckoViewProgress.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewProgress.jsm
@@ -4,50 +4,265 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["GeckoViewProgress"];
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/GeckoViewModule.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
   "resource://gre/modules/Messaging.jsm");
 
 var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
            .AndroidLog.d.bind(null, "ViewProgress");
 
 function debug(aMsg) {
   // dump(aMsg);
 }
 
+var IdentityHandler = {
+  // No trusted identity information. No site identity icon is shown.
+  IDENTITY_MODE_UNKNOWN: "unknown",
+
+  // Domain-Validation SSL CA-signed domain verification (DV).
+  IDENTITY_MODE_IDENTIFIED: "identified",
+
+  // Extended-Validation SSL CA-signed identity information (EV). A more rigorous validation process.
+  IDENTITY_MODE_VERIFIED: "verified",
+
+  // The following mixed content modes are only used if "security.mixed_content.block_active_content"
+  // is enabled. Our Java frontend coalesces them into one indicator.
+
+  // No mixed content information. No mixed content icon is shown.
+  MIXED_MODE_UNKNOWN: "unknown",
+
+  // Blocked active mixed content.
+  MIXED_MODE_CONTENT_BLOCKED: "blocked",
+
+  // Loaded active mixed content.
+  MIXED_MODE_CONTENT_LOADED: "loaded",
+
+  // The following tracking content modes are only used if tracking protection
+  // is enabled. Our Java frontend coalesces them into one indicator.
+
+  // No tracking content information. No tracking content icon is shown.
+  TRACKING_MODE_UNKNOWN: "unknown",
+
+  // Blocked active tracking content. Shield icon is shown, with a popup option to load content.
+  TRACKING_MODE_CONTENT_BLOCKED: "blocked",
+
+  // Loaded active tracking content. Yellow triangle icon is shown.
+  TRACKING_MODE_CONTENT_LOADED: "loaded",
+
+  _useTrackingProtection : false,
+  _usePrivateMode : false,
+
+  setUseTrackingProtection : function(aUse) {
+    this._useTrackingProtection = aUse;
+  },
+
+  setUsePrivateMode : function(aUse) {
+    this._usePrivateMode = aUse;
+  },
+
+  /**
+   * Determines the identity mode corresponding to the icon we show in the urlbar.
+   */
+  getIdentityMode: function getIdentityMode(aState) {
+    if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) {
+      return this.IDENTITY_MODE_VERIFIED;
+    }
+
+    if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE) {
+      return this.IDENTITY_MODE_IDENTIFIED;
+    }
+
+    return this.IDENTITY_MODE_UNKNOWN;
+  },
+
+  getMixedDisplayMode: function getMixedDisplayMode(aState) {
+    if (aState & Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT) {
+        return this.MIXED_MODE_CONTENT_LOADED;
+    }
+
+    if (aState & Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_DISPLAY_CONTENT) {
+        return this.MIXED_MODE_CONTENT_BLOCKED;
+    }
+
+    return this.MIXED_MODE_UNKNOWN;
+  },
+
+  getMixedActiveMode: function getActiveDisplayMode(aState) {
+    // Only show an indicator for loaded mixed content if the pref to block it is enabled
+    if ((aState & Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT) &&
+        !Services.prefs.getBoolPref("security.mixed_content.block_active_content")) {
+      return this.MIXED_MODE_CONTENT_LOADED;
+    }
+
+    if (aState & Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) {
+      return this.MIXED_MODE_CONTENT_BLOCKED;
+    }
+
+    return this.MIXED_MODE_UNKNOWN;
+  },
+
+  getTrackingMode: function getTrackingMode(aState) {
+    if (aState & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
+      return this.TRACKING_MODE_CONTENT_BLOCKED;
+    }
+
+    // Only show an indicator for loaded tracking content if the pref to block it is enabled
+    if ((aState & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) && this._useTrackingProtection) {
+      return this.TRACKING_MODE_CONTENT_LOADED;
+    }
+
+    return this.TRACKING_MODE_UNKNOWN;
+  },
+
+  /**
+   * Determine the identity of the page being displayed by examining its SSL cert
+   * (if available). Return the data needed to update the UI.
+   */
+  checkIdentity: function checkIdentity(aState, aBrowser) {
+    let lastStatus = aBrowser.securityUI.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
+
+    // Don't pass in the actual location object, since it can cause us to
+    // hold on to the window object too long.  Just pass in the fields we
+    // care about. (bug 424829)
+    let lastLocation = {};
+    try {
+      let location = aBrowser.contentWindow.location;
+      lastLocation.host = location.host;
+      lastLocation.hostname = location.hostname;
+      lastLocation.port = location.port;
+      lastLocation.origin = location.origin;
+    } catch (ex) {
+      // Can sometimes throw if the URL being visited has no host/hostname,
+      // e.g. about:blank. The _state for these pages means we won't need these
+      // properties anyways, though.
+    }
+
+    let uri = aBrowser.currentURI;
+    try {
+      uri = Services.uriFixup.createExposableURI(uri);
+    } catch (e) {}
+
+    let identityMode = this.getIdentityMode(aState);
+    let mixedDisplay = this.getMixedDisplayMode(aState);
+    let mixedActive = this.getMixedActiveMode(aState);
+    let trackingMode = this.getTrackingMode(aState);
+    let result = {
+      origin: lastLocation.origin,
+      mode: {
+        identity: identityMode,
+        mixed_display: mixedDisplay,
+        mixed_active: mixedActive,
+        tracking: trackingMode
+      }
+    };
+
+    // Don't show identity data for pages with an unknown identity or if any
+    // mixed content is loaded (mixed display content is loaded by default).
+    if (identityMode === this.IDENTITY_MODE_UNKNOWN ||
+        aState & Ci.nsIWebProgressListener.STATE_IS_BROKEN) {
+      result.secure = false;
+      return result;
+    }
+
+    result.secure = true;
+
+    result.host = this.getEffectiveHost(lastLocation, uri);
+
+    let status = lastStatus.QueryInterface(Ci.nsISSLStatus);
+    let cert = status.serverCert;
+
+    result.organization = cert.organization;
+    result.subjectName = cert.subjectName;
+    result.issuerOrganization = cert.issuerOrganization;
+    result.issuerCommonName = cert.issuerCommonName;
+
+    // Cache the override service the first time we need to check it
+    if (!this._overrideService) {
+      this._overrideService = Cc["@mozilla.org/security/certoverride;1"].getService(Ci.nsICertOverrideService);
+    }
+
+    // Check whether this site is a security exception. XPConnect does the right
+    // thing here in terms of converting lastLocation.port from string to int, but
+    // the overrideService doesn't like undefined ports, so make sure we have
+    // something in the default case (bug 432241).
+    // .hostname can return an empty string in some exceptional cases -
+    // hasMatchingOverride does not handle that, so avoid calling it.
+    // Updating the tooltip value in those cases isn't critical.
+    // FIXME: Fixing bug 646690 would probably makes this check unnecessary
+    if (lastLocation.hostname &&
+        this._overrideService.hasMatchingOverride(lastLocation.hostname,
+                                                  (lastLocation.port || 443),
+                                                  cert, {}, {})) {
+      result.security_exception = true;
+    }
+    return result;
+  },
+
+  /**
+   * Attempt to provide proper IDN treatment for host names
+   */
+  getEffectiveHost: function getEffectiveHost(aLastLocation, aUri) {
+    if (!this._IDNService) {
+      this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
+                         .getService(Ci.nsIIDNService);
+    }
+    try {
+      return this._IDNService.convertToDisplayIDN(aUri.host, {});
+    } catch (e) {
+      // If something goes wrong (e.g. hostname is an IP address) just fail back
+      // to the full domain.
+      return aLastLocation.hostname;
+    }
+  }
+};
+
 class GeckoViewProgress extends GeckoViewModule {
+  init() {
+    this._hostChanged = false;
+  }
+
   register() {
     debug("register");
 
     let flags = Ci.nsIWebProgress.NOTIFY_STATE_NETWORK |
-                Ci.nsIWebProgress.NOTIFY_SECURITY;
+                Ci.nsIWebProgress.NOTIFY_SECURITY |
+                Ci.nsIWebProgress.NOTIFY_LOCATION;
     this.progressFilter =
       Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
       .createInstance(Ci.nsIWebProgress);
     this.progressFilter.addProgressListener(this, flags);
     this.browser.addProgressListener(this.progressFilter, flags);
   }
 
   unregister() {
     debug("unregister");
 
     if (this.progressFilter) {
       this.progressFilter.removeProgressListener(this);
       this.browser.removeProgressListener(this.progressFilter);
     }
   }
 
+  onSettingsUpdate() {
+    let settings = this.settings;
+    debug("onSettingsUpdate: " + JSON.stringify(settings));
+
+    IdentityHandler.setUseTrackingProtection(!!settings.useTrackingProtection);
+    IdentityHandler.setUsePrivateMode(!!settings.usePrivateMode);
+  }
+
   onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
     debug("onStateChange()");
 
     if (!aWebProgress.isTopLevel) {
       return;
     }
 
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
@@ -65,18 +280,31 @@ class GeckoViewProgress extends GeckoVie
         success: !aStatus
       };
 
       this.eventDispatcher.sendRequest(message);
     }
   }
 
   onSecurityChange(aWebProgress, aRequest, aState) {
-    debug("onSecurityChange()");
+    // Don't need to do anything if the data we use to update the UI hasn't changed
+    if (this._state === aState && !this._hostChanged) {
+      return;
+    }
+
+    this._state = aState;
+    this._hostChanged = false;
+
+    let identity = IdentityHandler.checkIdentity(aState, this.browser);
 
     let message = {
       type: "GeckoView:SecurityChanged",
-      status: aState
+      status: aState,
+      identity: identity
     };
 
     this.eventDispatcher.sendRequest(message);
   }
+
+  onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
+    this._hostChanged = true;
+  }
 }
--- a/netwerk/cache2/CacheIndex.cpp
+++ b/netwerk/cache2/CacheIndex.cpp
@@ -2734,29 +2734,28 @@ CacheIndex::InitEntryFromDiskData(CacheI
   const char *altData = aMetaData->GetElement(CacheFileUtils::kAltDataKey);
   bool hasAltData = altData ? true : false;
   if (hasAltData &&
       NS_FAILED(CacheFileUtils::ParseAlternativeDataInfo(altData, nullptr, nullptr))) {
     return NS_ERROR_FAILURE;
   }
   aEntry->SetHasAltData(hasAltData);
 
-  static auto getUint16MetaData = [&aMetaData](const char *key) -> uint16_t {
-    const char* s64 = aMetaData->GetElement(key);
-    if (s64) {
-      nsresult rv;
-      uint64_t n64 = nsCString(s64).ToInteger64(&rv);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-      return n64 <= kIndexTimeOutOfBound ? n64 : kIndexTimeOutOfBound;
+  static auto toUint16 = [](const char *aUint16String) -> uint16_t {
+    if (!aUint16String) {
+      return kIndexTimeNotAvailable;
     }
-    return kIndexTimeNotAvailable;
+    nsresult rv;
+    uint64_t n64 = nsCString(aUint16String).ToInteger64(&rv);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    return n64 <= kIndexTimeOutOfBound ? n64 : kIndexTimeOutOfBound;
   };
 
-  aEntry->SetOnStartTime(getUint16MetaData("net-response-time-onstart"));
-  aEntry->SetOnStopTime(getUint16MetaData("net-response-time-onstop"));
+  aEntry->SetOnStartTime(toUint16(aMetaData->GetElement("net-response-time-onstart")));
+  aEntry->SetOnStopTime(toUint16(aMetaData->GetElement("net-response-time-onstop")));
 
   aEntry->SetFileSize(static_cast<uint32_t>(
                         std::min(static_cast<int64_t>(PR_UINT32_MAX),
                                  (aFileSize + 0x3FF) >> 10)));
   return NS_OK;
 }
 
 bool
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_16_BETA1
+NSPR_4_16_BETA2
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/nsprpub/pr/src/io/prsocket.c
+++ b/nsprpub/pr/src/io/prsocket.c
@@ -317,17 +317,17 @@ static PRStatus PR_CALLBACK SocketConnec
     }
     /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
      * input/output.
      * To get result we need to use GetOverlappedResult. */
     if (fd->secret->overlappedActive) {
         PR_ASSERT(fd->secret->nonblocking);
         PRInt32 rvSent;
         if (GetOverlappedResult(osfd, &fd->secret->ol, &rvSent, FALSE) == TRUE) {
-            fd->secret->overlappedActive = FALSE;
+            fd->secret->overlappedActive = PR_FALSE;
             PR_LOG(_pr_io_lm, PR_LOG_MIN,
                ("SocketConnectContinue GetOverlappedResult succeeded\n"));
             /* When ConnectEx is used, all previously set socket options and
              * property are not enabled and to enable them
              * SO_UPDATE_CONNECT_CONTEXT option need to be set. */
             if (setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) {
                 err = WSAGetLastError();
                 PR_LOG(_pr_io_lm, PR_LOG_MIN,
@@ -337,17 +337,17 @@ static PRStatus PR_CALLBACK SocketConnec
             }
             return PR_SUCCESS;
         } else {
             err = WSAGetLastError();
             PR_LOG(_pr_io_lm, PR_LOG_MIN,
                ("SocketConnectContinue GetOverlappedResult failed %d\n", err));
             if (err != ERROR_IO_INCOMPLETE) {
                 _PR_MD_MAP_CONNECT_ERROR(err);
-                fd->secret->overlappedActive = FALSE;
+                fd->secret->overlappedActive = PR_FALSE;
                 return PR_FAILURE;
             } else {
                 PR_SetError(PR_IN_PROGRESS_ERROR, 0);
                 return PR_FAILURE;
             }
         }
     }
 #endif
--- a/nsprpub/pr/src/md/windows/w95sock.c
+++ b/nsprpub/pr/src/md/windows/w95sock.c
@@ -328,33 +328,36 @@ PRInt32
         }
     } while(bytesSent < amount);
     return bytesSent;
 }
 
 #if defined(_WIN64)
 
 static PRCallOnceType _pr_has_connectex_once;
-typedef BOOL (WINAPI *_pr_win_connectex_ptr)(SOCKET, const struct sockaddr *, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED);
+typedef BOOL (PASCAL FAR * _pr_win_connectex_ptr)(_In_ SOCKET s, _In_reads_bytes_(namelen) const struct sockaddr FAR *name, _In_ int namelen, _In_reads_bytes_opt_(dwSendDataLength) PVOID lpSendBuffer, _In_ DWORD dwSendDataLength, _Out_ LPDWORD lpdwBytesSent, _Inout_ LPOVERLAPPED lpOverlapped);
+
+
+
 #ifndef WSAID_CONNECTEX
 #define WSAID_CONNECTEX \
   {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
 #endif
 #ifndef SIO_GET_EXTENSION_FUNCTION_POINTER
 #define SIO_GET_EXTENSION_FUNCTION_POINTER 0xC8000006
 #endif
 #ifndef TCP_FASTOPEN
 #define TCP_FASTOPEN 15
 #endif
 
 #ifndef SO_UPDATE_CONNECT_CONTEXT
 #define SO_UPDATE_CONNECT_CONTEXT 0x7010
 #endif
 
-static _pr_win_connectex_ptr _pr_win_connectex;
+static _pr_win_connectex_ptr _pr_win_connectex = NULL;
 
 static PRStatus PR_CALLBACK _pr_set_connectex(void)
 {
     _pr_win_connectex = NULL;
     SOCKET sock;
     PRInt32 dwBytes;
     int rc;
 
@@ -453,24 +456,29 @@ PRInt32
     } else {
         err = WSAGetLastError();
         PR_LOG(_pr_io_lm, PR_LOG_MIN,
                ("_PR_MD_TCPSENDTO error _pr_win_connectex failed %d\n", err));
         if (err != ERROR_IO_PENDING) {
             _PR_MD_MAP_CONNECT_ERROR(err);
             return -1;
         } else if (fd->secret->nonblocking) {
-            /* Remember that overlapped structure is set. We will neede to get
+            /* Remember that overlapped structure is set. We will need to get
              * the final result of ConnectEx call. */
             fd->secret->overlappedActive = PR_TRUE;
-            _PR_MD_MAP_CONNECT_ERROR(WSAEWOULDBLOCK);
+
             /* ConnectEx will copy supplied data to a internal buffer and send
              * them during Fast Open or after connect. Therefore we can assumed
              * this data already send. */
-            return amount;
+            if (amount > 0) {
+              return amount;
+            }
+
+            _PR_MD_MAP_CONNECT_ERROR(WSAEWOULDBLOCK);
+            return -1;
         }
         // err is ERROR_IO_PENDING and socket is blocking, so query
         // GetOverlappedResult.
         err = ERROR_IO_INCOMPLETE;
         while (err == ERROR_IO_INCOMPLETE) {
             rv = socket_io_wait(osfd, WRITE_FD, timeout);
             if ( rv < 0 ) {
                 return -1;
--- a/nsprpub/pr/src/pthreads/ptsynch.c
+++ b/nsprpub/pr/src/pthreads/ptsynch.c
@@ -50,22 +50,21 @@ pt_pthread_mutex_is_locked(pthread_mutex
 /**************************************************************/
 
 void _PR_InitLocks(void)
 {
     int rv;
     rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); 
     PR_ASSERT(0 == rv);
 
-#ifdef LINUX
-#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
+#if (defined(LINUX) && (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) || \
+    (defined(FREEBSD) && __FreeBSD_version > 700055)
     rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
     PR_ASSERT(0 == rv);
 #endif
-#endif
 
     rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr);
     PR_ASSERT(0 == rv);
 }
 
 static void pt_PostNotifies(PRLock *lock, PRBool unlock)
 {
     PRIntn index, rv;
--- a/nsprpub/pr/tests/accept.c
+++ b/nsprpub/pr/tests/accept.c
@@ -138,22 +138,23 @@ ClientThread(void *_action)
                         "client: unable to connect to server (%ld, %ld, %ld, %ld)\n",
                         iterations, rv, PR_GetError(), PR_GetOSError());
                 goto ErrorExit;
             }
 
             if (action != CLIENT_TIMEOUT_SEND) {
                 if ((rv = PR_Send(sock, buf, CLIENT_DATA,
                     0, timeoutTime))< 0) {
-                    if (!debug_mode)
+                    if (!debug_mode) {
                         failed_already=1;
-                    else    
-                        PR_fprintf(output, 
+                    } else {
+                        PR_fprintf(output,
                             "client: unable to send to server (%d, %ld, %ld)\n",
                             CLIENT_DATA, rv, PR_GetError());
+                    }
                 	goto ErrorExit;
                 }
             } else {
                 PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1));
             }
         } else {
             PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1));
         }
@@ -195,18 +196,19 @@ int i;
     i = 0;
     while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) {
         if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
             listenAddr.inet.port += 2;
             if (i++ < SERVER_MAX_BIND_COUNT)
                 continue;
         }
         failed_already=1;
-        if (debug_mode)
+        if (debug_mode) {
         	PR_fprintf(output,"accept: ERROR - PR_Bind failed\n");
+        }
 		return;
     }
 
 
     rv = PR_Listen(listenSock, 100);
     if (rv == PR_FAILURE) {
         failed_already=1;
         if (debug_mode)
--- a/nsprpub/pr/tests/alarm.c
+++ b/nsprpub/pr/tests/alarm.c
@@ -406,25 +406,25 @@ static PRIntervalTime Alarms3(PRUint32 l
 }  /* Alarms3 */
 
 static PRUint32 TimeThis(
     const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
 {
     PRUint32 overhead, usecs;
     PRIntervalTime predicted, timein, timeout, ticks;
 
- if (debug_mode)
-    printf("Testing %s ...", msg);
+    if (debug_mode)
+      printf("Testing %s ...", msg);
 
     timein = PR_IntervalNow();
     predicted = func(loops);
     timeout = PR_IntervalNow();
 
-  if (debug_mode)
-    printf(" done\n");
+    if (debug_mode)
+      printf(" done\n");
 
     ticks = timeout - timein;
     usecs = PR_IntervalToMicroseconds(ticks);
     overhead = PR_IntervalToMicroseconds(predicted);
 
     if(ticks < predicted)
     {
 		if (debug_mode) {
@@ -486,27 +486,27 @@ int prmain(int argc, char** argv)
 	if (debug_mode)
 		printf("Alarm: Using %d loops\n", loops);
 
 	if (debug_mode)		
         printf("Alarm: Using %d cpu(s)\n", cpus);
 
     for (cpu = 1; cpu <= cpus; ++cpu)
     {
-    if (debug_mode)
+      if (debug_mode)
         printf("\nAlarm: Using %d CPU(s)\n", cpu);
 
-	PR_SetConcurrency(cpu);
-        
-        /* some basic time test */
-        (void)TimeThis("ConditionNotify", ConditionNotify, loops);
-        (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
-        (void)TimeThis("Alarms1", Alarms1, loops);
-        (void)TimeThis("Alarms2", Alarms2, loops);
-        (void)TimeThis("Alarms3", Alarms3, loops);
+      PR_SetConcurrency(cpu);
+
+      /* some basic time test */
+      (void)TimeThis("ConditionNotify", ConditionNotify, loops);
+      (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
+      (void)TimeThis("Alarms1", Alarms1, loops);
+      (void)TimeThis("Alarms2", Alarms2, loops);
+      (void)TimeThis("Alarms3", Alarms3, loops);
     }
     return 0;
 }
 
 int main(int argc, char** argv)
 {
      PR_Initialize(prmain, argc, argv, 0);
      PR_STDIO_INIT();
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -8,16 +8,17 @@
 
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
 #include "PKCS11.h"
 #include "ScopedNSSTypes.h"
 #include "SharedSSLState.h"
 #include "cert.h"
 #include "certdb.h"
+#include "mozStorageCID.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/PublicSSL.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
@@ -2027,16 +2028,24 @@ nsNSSComponent::Init()
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
   MOZ_ASSERT(XRE_IsParentProcess());
   if (!XRE_IsParentProcess()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
+  // To avoid a sqlite3_config race in NSS init, as a workaround for
+  // bug 730495, we require the storage service to get initialized first.
+  nsCOMPtr<nsISupports> storageService =
+    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
+  if (!storageService) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));
 
   nsresult rv = InitializePIPNSSBundle();
   if (NS_FAILED(rv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to create pipnss bundle.\n"));
     return rv;
   }
 
--- a/taskcluster/ci/test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -560,20 +560,19 @@ mochitest-browser-chrome:
 
 mochitest-browser-screenshots:
     description: "Mochitest Browser Screenshots"
     suite: mochitest/browser-chrome-screenshots
     treeherder-symbol: tc-M(ss)
     loopback-video: true
     run-on-projects:
         by-test-platform:
-            windows10/opt: ['mozilla-central', 'try']
-            windows7/opt: ['mozilla-central', 'try']
+            windows.*/opt: ['mozilla-central', 'try']
             linux64/opt: ['mozilla-central', 'try']
-            macosx/opt: ['mozilla-central', 'try']
+            macosx.*/opt: ['mozilla-central', 'try']
             default: []
     e10s: both
     max-run-time: 3600
     mozharness:
         mochitest-flavor: browser
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
@@ -973,16 +972,17 @@ mochitest-webgl:
             windows10.*: []
             default: built-projects
     chunks:
         by-test-platform:
             android.*: 10
             default: 3
     e10s:
       by-test-platform:
+        windows7.*: true
         macosx.*: true
         default: both
     loopback-video: true
     max-run-time:
         by-test-platform:
             windows.*: 5400
             android.*: 7200
             default: 3600
--- a/testing/web-platform/meta/2dcontext/fill-and-stroke-styles/2d.gradient.radial.outside3.html.ini
+++ b/testing/web-platform/meta/2dcontext/fill-and-stroke-styles/2d.gradient.radial.outside3.html.ini
@@ -1,11 +1,8 @@
 [2d.gradient.radial.outside3.html]
   type: testharness
   [Canvas test: 2d.gradient.radial.outside3]
     expected:
-      if not debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
-      if debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
-      if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
-      if debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
+      if (os == "win") and (version != "6.2.9200"): FAIL
       if os == "mac": FAIL
       if os == "linux": FAIL
 
--- a/testing/web-platform/meta/2dcontext/path-objects/2d.path.stroke.prune.arc.html.ini
+++ b/testing/web-platform/meta/2dcontext/path-objects/2d.path.stroke.prune.arc.html.ini
@@ -1,16 +1,11 @@
 [2d.path.stroke.prune.arc.html]
   type: testharness
   [Zero-length line segments from arcTo and arc are removed before stroking]
     expected:
       if not debug and (os == "linux") and (processor == "x86") and (bits == 32): FAIL
-      if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and (os == "linux") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and (os == "linux") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and (os == "linux") and (processor == "x86") and (bits == 32): FAIL
-      if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
-      if debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): FAIL
-      if not debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): FAIL
-      if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
-      if (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
+      if os == "win": FAIL
       if os == "mac": FAIL
 
--- a/testing/web-platform/meta/2dcontext/path-objects/2d.path.stroke.prune.curve.html.ini
+++ b/testing/web-platform/meta/2dcontext/path-objects/2d.path.stroke.prune.curve.html.ini
@@ -1,16 +1,11 @@
 [2d.path.stroke.prune.curve.html]
   type: testharness
   [Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed before stroking]
     expected:
       if not debug and (os == "linux") and (processor == "x86") and (bits == 32): FAIL
-      if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and (os == "linux") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and (os == "linux") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and (os == "linux") and (processor == "x86") and (bits == 32): FAIL
-      if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
-      if debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): FAIL
-      if not debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): FAIL
-      if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
-      if (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
+      if os == "win": FAIL
       if os == "mac": FAIL
 
--- a/testing/web-platform/meta/2dcontext/path-objects/2d.path.stroke.prune.line.html.ini
+++ b/testing/web-platform/meta/2dcontext/path-objects/2d.path.stroke.prune.line.html.ini
@@ -1,16 +1,11 @@
 [2d.path.stroke.prune.line.html]
   type: testharness
   [Zero-length line segments from lineTo are removed before stroking]
     expected:
       if not debug and (os == "linux") and (processor == "x86") and (bits == 32): FAIL
-      if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and (os == "linux") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and (os == "linux") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and (os == "linux") and (processor == "x86") and (bits == 32): FAIL
-      if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
-      if debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): FAIL
-      if not debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): FAIL
-      if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
-      if (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
+      if os == "win": FAIL
       if os == "mac": FAIL
 
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/mathml/relations/html5-tree/unique-identifier-1.html.ini
@@ -0,0 +1,4 @@
+[unique-identifier-1.html]
+  type: reftest
+  disabled:
+    if os == "win": https://bugzilla.mozilla.org/show_bug.cgi?id=1377406
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -85,16 +85,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyGetter(
   this, "processScript",
   () => Cc["@mozilla.org/webextensions/extension-process-script;1"]
           .getService().wrappedJSObject);
 
 Cu.import("resource://gre/modules/ExtensionParent.jsm");
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
+                                   "@mozilla.org/addons/addon-manager-startup;1",
+                                   "amIAddonManagerStartup");
 XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
                                       "extensions.webextensions.remote", false);
 
 var {
@@ -385,56 +388,45 @@ this.ExtensionData = class {
         // not a directory) for symmetry with the ZipReader behavior.
         Cu.reportError(e);
       }
       iter.close();
 
       return results;
     }
 
-    // FIXME: We need a way to do this without main thread IO.
-
     let uri = this.rootURI.QueryInterface(Ci.nsIJARURI);
-
     let file = uri.JARFile.QueryInterface(Ci.nsIFileURL).file;
-    let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(Ci.nsIZipReader);
-    zipReader.open(file);
-    try {
-      let results = [];
 
-      // Normalize the directory path.
-      path = `${uri.JAREntry}/${path}`;
-      path = path.replace(/\/\/+/g, "/").replace(/^\/|\/$/g, "") + "/";
-
-      // Escape pattern metacharacters.
-      let pattern = path.replace(/[[\]()?*~|$\\]/g, "\\$&");
+    // Normalize the directory path.
+    path = `${uri.JAREntry}/${path}`;
+    path = path.replace(/\/\/+/g, "/").replace(/^\/|\/$/g, "") + "/";
 
-      let enumerator = zipReader.findEntries(pattern + "*");
-      while (enumerator.hasMore()) {
-        let name = enumerator.getNext();
-        if (!name.startsWith(path)) {
-          throw new Error("Unexpected ZipReader entry");
-        }
+    // Escape pattern metacharacters.
+    let pattern = path.replace(/[[\]()?*~|$\\]/g, "\\$&") + "*";
 
-        // The enumerator returns the full path of all entries.
-        // Trim off the leading path, and filter out entries from
-        // subdirectories.
-        name = name.slice(path.length);
-        if (name && !/\/./.test(name)) {
-          results.push({
-            name: name.replace("/", ""),
-            isDir: name.endsWith("/"),
-          });
-        }
+    let results = [];
+    for (let name of aomStartup.enumerateZipFile(file, pattern)) {
+      if (!name.startsWith(path)) {
+        throw new Error("Unexpected ZipReader entry");
       }
 
-      return results;
-    } finally {
-      zipReader.close();
+      // The enumerator returns the full path of all entries.
+      // Trim off the leading path, and filter out entries from
+      // subdirectories.
+      name = name.slice(path.length);
+      if (name && !/\/./.test(name)) {
+        results.push({
+          name: name.replace("/", ""),
+          isDir: name.endsWith("/"),
+        });
+      }
     }
+
+    return results;
   }
 
   readJSON(path) {
     return new Promise((resolve, reject) => {
       let uri = this.rootURI.resolve(`./${path}`);
 
       NetUtil.asyncFetch({uri, loadUsingSystemPrincipal: true}, (inputStream, status) => {
         if (!Components.isSuccessCode(status)) {
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -240,20 +240,23 @@ ProxyMessenger = {
     let failures = 0;
     let tryPromise = async promise => {
       try {
         let res = await promise;
         if (result === undefined) {
           result = res;
         }
       } catch (e) {
-        if (e.result != MessageChannel.RESULT_NO_HANDLER) {
+        if (e.result === MessageChannel.RESULT_NO_RESPONSE) {
+          // Ignore.
+        } else if (e.result === MessageChannel.RESULT_NO_HANDLER) {
+          failures++;
+        } else {
           throw e;
         }
-        failures++;
       }
     };
 
     await Promise.all([tryPromise(promise1), tryPromise(promise2)]);
     if (failures == 2) {
       return Promise.reject(noHandlerError);
     }
     return result;
--- a/toolkit/mozapps/extensions/AddonManagerStartup.cpp
+++ b/toolkit/mozapps/extensions/AddonManagerStartup.cpp
@@ -20,16 +20,21 @@
 #include "mozilla/Unused.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsAppRunner.h"
 #include "nsContentUtils.h"
 #include "nsIAddonInterposition.h"
+#include "nsIIOService.h"
+#include "nsIJARProtocolHandler.h"
+#include "nsIStringEnumerator.h"
+#include "nsIZipReader.h"
+#include "nsReadableUtils.h"
 #include "nsXULAppAPI.h"
 
 #include <stdlib.h>
 
 namespace mozilla {
 
 template <>
 class MOZ_MUST_USE_TYPE GenericErrorResult<nsresult>
@@ -242,16 +247,34 @@ static bool
 ParseJSON(JSContext* cx, nsACString& jsonData, JS::MutableHandleValue result)
 {
   NS_ConvertUTF8toUTF16 str(jsonData);
   jsonData.Truncate();
 
   return JS_ParseJSON(cx, str.Data(), str.Length(), result);
 }
 
+static Result<nsCOMPtr<nsIZipReaderCache>, nsresult>
+GetJarCache()
+{
+  nsCOMPtr<nsIIOService> ios = services::GetIOService();
+  NS_ENSURE_TRUE(ios, Err(NS_ERROR_FAILURE));
+
+  nsCOMPtr<nsIProtocolHandler> jarProto;
+  NS_TRY(ios->GetProtocolHandler("jar", getter_AddRefs(jarProto)));
+
+  nsCOMPtr<nsIJARProtocolHandler> jar = do_QueryInterface(jarProto);
+  MOZ_ASSERT(jar);
+
+  nsCOMPtr<nsIZipReaderCache> zipCache;
+  NS_TRY(jar->GetJARCache(getter_AddRefs(zipCache)));
+
+  return Move(zipCache);
+}
+
 
 /*****************************************************************************
  * JSON data handling
  *****************************************************************************/
 
 class MOZ_STACK_CLASS WrapperBase {
 protected:
   WrapperBase(JSContext* cx, JSObject* object)
@@ -694,16 +717,53 @@ AddonManagerStartup::DecodeBlob(JS::Hand
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 
   ErrorResult rv;
   holder.Read(cx, result, rv);
   return rv.StealNSResult();;
 }
 
 nsresult
+AddonManagerStartup::EnumerateZipFile(nsIFile* file, const nsACString& pattern,
+                                      uint32_t* countOut, char16_t*** entriesOut)
+{
+  NS_ENSURE_ARG_POINTER(file);
+  NS_ENSURE_ARG_POINTER(countOut);
+  NS_ENSURE_ARG_POINTER(entriesOut);
+
+  nsCOMPtr<nsIZipReaderCache> zipCache;
+  MOZ_TRY_VAR(zipCache, GetJarCache());
+
+  nsCOMPtr<nsIZipReader> zip;
+  NS_TRY(zipCache->GetZip(file, getter_AddRefs(zip)));
+
+  nsCOMPtr<nsIUTF8StringEnumerator> entries;
+  NS_TRY(zip->FindEntries(pattern, getter_AddRefs(entries)));
+
+  nsTArray<nsString> results;
+  bool hasMore;
+  while (NS_SUCCEEDED(entries->HasMore(&hasMore)) && hasMore) {
+    nsAutoCString name;
+    NS_TRY(entries->GetNext(name));
+
+    results.AppendElement(NS_ConvertUTF8toUTF16(name));
+  }
+
+  auto strResults = MakeUnique<char16_t*[]>(results.Length());
+  for (uint32_t i = 0; i < results.Length(); i++) {
+    strResults[i] = ToNewUnicode(results[i]);
+  }
+
+  *countOut = results.Length();
+  *entriesOut = strResults.release();
+
+  return NS_OK;
+}
+
+nsresult
 AddonManagerStartup::Reset()
 {
   MOZ_RELEASE_ASSERT(xpc::IsInAutomation());
 
   mInitialized = false;
 
   mExtensionPaths.Clear();
   mThemePaths.Clear();
--- a/toolkit/mozapps/extensions/amIAddonManagerStartup.idl
+++ b/toolkit/mozapps/extensions/amIAddonManagerStartup.idl
@@ -1,14 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
+interface nsIFile;
+
 [scriptable, builtinclass, uuid(01dfa47b-87e4-4135-877b-586d033e1b5d)]
 interface amIAddonManagerStartup : nsISupports
 {
   /**
    * Reads and parses startup data from the addonState.json.lz4 file, checks
    * for modifications, and returns the result.
    *
    * Returns null for an empty or nonexistent state file, but throws for an
@@ -26,16 +28,32 @@ interface amIAddonManagerStartup : nsISu
 
   [implicit_jscontext]
   jsval encodeBlob(in jsval value);
 
   [implicit_jscontext]
   jsval decodeBlob(in jsval value);
 
   /**
+   * Enumerates over all entries in the given zip file matching the given
+   * pattern, and returns an array of their paths.
+   *
+   * This should be used in preference to manually opening or retrieving a
+   * ZipReader from the zip cache, since the former causes main thread IO and
+   * the latter can lead to file locking issues due to unpredictable GC behavior
+   * keeping the cached ZipReader alive after the cache is flushed.
+   *
+   * @param file The zip file to enumerate.
+   * @param pattern The pattern to match, as passed to nsIZipReader.findEntries.
+   */
+  void enumerateZipFile(in nsIFile file, in AUTF8String pattern,
+                        [optional] out unsigned long count,
+                        [retval, array, size_is(count)] out wstring entries);
+
+  /**
    * Resets the internal state of the startup service, and allows
    * initializeExtensions() to be called again. Does *not* fully unregister
    * chrome registry locations for previously registered add-ons.
    *
    * NOT FOR USE OUTSIDE OF UNIT TESTS.
    */
   void reset();
 };
--- a/widget/tests/chrome.ini
+++ b/widget/tests/chrome.ini
@@ -27,16 +27,17 @@ skip-if = os == 'linux' && debug #Bug 11
 [test_wheeltransaction.xul]
 support-files = window_wheeltransaction.xul
 [test_imestate.html]
 support-files = window_imestate_iframes.html
 [test_plugin_scroll_consistency.html]
 [test_composition_text_querycontent.xul]
 support-files = window_composition_text_querycontent.xul
 [test_input_events_on_deactive_window.xul]
+support-files = file_input_events_on_deactive_window.html
 [test_position_on_resize.xul]
 [test_sizemode_events.xul]
 [test_taskbar_progress.xul]
 skip-if = toolkit != "cocoa" && toolkit != "windows"
 [test_bug760802.xul]
 [test_clipboard.xul]
 subsuite = clipboard
 [test_panel_mouse_coords.xul]
new file mode 100644
--- /dev/null
+++ b/widget/tests/file_input_events_on_deactive_window.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+  this is an active window.
+</body>
+</html>
--- a/widget/tests/test_input_events_on_deactive_window.xul
+++ b/widget/tests/test_input_events_on_deactive_window.xul
@@ -37,17 +37,17 @@ function runTests()
   textarea.focus();
   is(fm.focusedElement, textarea, "we're deactive");
   if (fm.focusedElement != textarea) {
     SimpleTest.finish();
     return;
   }
 
   otherWindow =
-    window.open("data:text/plain,this is an active window.", "_blank",
+    window.open("./file_input_events_on_deactive_window.html", "_blank",
                 "chrome,width=100,height=100");
   ok(otherWindow, "failed to open other window");
   if (!otherWindow) {
     SimpleTest.finish();
     return;
   }
 
   SimpleTest.waitForFocus(startTests, otherWindow);
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -7183,16 +7183,26 @@ bool nsWindow::AutoErase(HDC dc)
 }
 
 bool
 nsWindow::IsPopup()
 {
   return mWindowType == eWindowType_popup;
 }
 
+bool
+nsWindow::ShouldUseOffMainThreadCompositing()
+{
+  if (IsSmallPopup()) {
+    return false;
+  }
+
+  return nsBaseWidget::ShouldUseOffMainThreadCompositing();
+}
+
 void
 nsWindow::WindowUsesOMTC()
 {
   ULONG_PTR style = ::GetClassLongPtr(mWnd, GCL_STYLE);
   if (!style) {
     NS_WARNING("Could not get window class style");
     return;
   }
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -297,16 +297,17 @@ public:
 
   // Open file picker tracking
   void                    PickerOpen();
   void                    PickerClosed();
 
   bool                    const DestroyCalled() { return mDestroyCalled; }
 
   bool IsPopup();
+  virtual bool ShouldUseOffMainThreadCompositing() override;
 
   const IMEContext& DefaultIMC() const { return mDefaultIMC; }
 
   virtual void SetCandidateWindowForPlugin(
                  const mozilla::widget::CandidateWindowPosition&
                    aPosition) override;
   virtual void DefaultProcOfPluginEvent(
                  const mozilla::WidgetPluginEvent& aEvent) override;