Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 07 Aug 2015 16:02:43 -0400
changeset 288498 461fc0a6a130b5cee4c18481db4aa51b818c65f5
parent 288462 e1925e00d2b85fe904d852059d02a3a3b349211a (current diff)
parent 288497 ebbd4386dbd3bfb23dc118fe1a6a63c3f51cf4c3 (diff)
child 288513 8d0287d9c8e4e05e0245d9fcc7f5e03cbd58fe0b
child 288533 2c5a611f298646326c73bdca44336fce92a59af0
child 288540 34d22581dab4cb0ec9fad15b8a4430b3ec8b4e21
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
--- a/browser/components/loop/test/shared/frontend_tester.py
+++ b/browser/components/loop/test/shared/frontend_tester.py
@@ -67,17 +67,19 @@ class BaseTestFrontendUnits(MarionetteTe
         # Note: when e10s is enabled by default, this pref can go away. The automatic
         # restart will also go away if this is still the only pref set here.
         self.marionette.enforce_gecko_prefs({
             "browser.tabs.remote.autostart": True
         })
 
         # This extends the timeout for find_element. We need this as the tests
         # take an amount of time to run after loading, which we have to wait for.
-        self.marionette.set_search_timeout(60000)
+        self.marionette.set_search_timeout(120000)
+
+        self.marionette.timeouts("page load", 120000)
 
     # srcdir_path should be the directory relative to this file.
     def set_server_prefix(self, srcdir_path):
         # We may be run from a different path than topsrcdir, e.g. in the case
         # of packaged tests. If so, then we have to work out the right directory
         # for the local server.
 
         # First find the top of the working directory.
--- a/browser/components/loop/test/standalone/test_standalone_all.py
+++ b/browser/components/loop/test/standalone/test_standalone_all.py
@@ -1,16 +1,16 @@
 # need to get this dir in the path so that we make the import work
 import os
 import sys
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'shared'))
 
 from frontend_tester import BaseTestFrontendUnits
 
 
-class TestDesktopUnits(BaseTestFrontendUnits):
+class TestStandaloneUnits(BaseTestFrontendUnits):
 
     def setUp(self):
-        super(TestDesktopUnits, self).setUp()
+        super(TestStandaloneUnits, self).setUp()
         self.set_server_prefix("../standalone/")
 
     def test_units(self):
         self.check_page("index.html")
--- a/browser/components/loop/test/ui-showcase/test_ui-showcase.py
+++ b/browser/components/loop/test/ui-showcase/test_ui-showcase.py
@@ -1,16 +1,16 @@
 # need to get this dir in the path so that we make the import work
 import os
 import sys
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'shared'))
 
 from frontend_tester import BaseTestFrontendUnits
 
 
-class TestDesktopUnits(BaseTestFrontendUnits):
+class TestUiShowcaseUnits(BaseTestFrontendUnits):
 
     def setUp(self):
-        super(TestDesktopUnits, self).setUp()
+        super(TestUiShowcaseUnits, self).setUp()
         self.set_server_prefix("../../ui/")
 
     def test_units(self):
         self.check_page("index.html")
--- a/dom/alarm/test/mochitest.ini
+++ b/dom/alarm/test/mochitest.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 support-files =
   file_empty.html
+  system_message_chrome_script.js
 
 [test_alarm_add_data.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_add_date.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_add_respectTimezone.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_non_permitted_app.html]
new file mode 100644
--- /dev/null
+++ b/dom/alarm/test/system_message_chrome_script.js
@@ -0,0 +1,18 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+'use strict';
+
+const { classes: Cc, interfaces: Ci } = Components;
+
+const systemMessenger = Cc["@mozilla.org/system-message-internal;1"]
+                          .getService(Ci.nsISystemMessagesInternal);
+const ioService = Cc["@mozilla.org/network/io-service;1"]
+                    .getService(Ci.nsIIOService);
+
+addMessageListener("trigger-register-page", function(aData) {
+  systemMessenger.registerPage(aData.type,
+                               ioService.newURI(aData.pageURL, null, null),
+                               ioService.newURI(aData.manifestURL, null, null));
+  sendAsyncMessage("page-registered");
+});
--- a/dom/alarm/test/test_bug1037079.html
+++ b/dom/alarm/test/test_bug1037079.html
@@ -9,30 +9,44 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test">
   <script type="application/javascript">
 
   "use strict";
 
+  function registerPage() {
+    var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('system_message_chrome_script.js'));
+    gScript.addMessageListener("page-registered", function pageRegisteredHandler() {
+      gScript.removeMessageListener("page-registered", pageRegisteredHandler);
+      gScript.destroy();
+      testFireTimeAlert();
+    });
+
+    gScript.sendAsyncMessage("trigger-register-page",
+                             { type: "alarm",
+                               manifestURL: window.location.origin + "/manifest.webapp",
+                               pageURL: window.location.href });
+  }
+
   function testFireTimeAlert() {
     var secondsLater = new Date();
     secondsLater.setSeconds(secondsLater.getSeconds() + 10);
 
     var domRequest;
     try {
       // Set system message handler.
       navigator.mozSetMessageHandler('alarm', function(message){
         ok(true, "Time alert has been fired.");
         SimpleTest.finish();
       });
 
       domRequest = navigator.mozAlarms.add(secondsLater, "honorTimezone",
-    		                               {type: "timer"});
+                                           {type: "timer"});
     } catch (e) {
       ok(false, "Unexpected exception trying to set time alert.");
 
       return SimpleTest.finish();
     }
     domRequest.onsuccess = function(e) {
       ok(true, "Set time alert. Waiting to be fired.");
     };
@@ -57,17 +71,17 @@
                  SpecialPowers.Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
         ok(true, "mozAlarms is not allowed for non-installed apps. " +
                  "TODO Bug 876981.");
         isAllowedToTest = false;
       }
 
       if (isAllowedToTest) {
         ok(true, "Start to test...");
-        testFireTimeAlert();
+        registerPage();
       } else {
         // A sanity check to make sure we must run tests on Firefox OS (B2G).
         if (navigator.userAgent.indexOf("Mobile") != -1 &&
             navigator.appVersion.indexOf("Android") == -1) {
           ok(false, "Should run the test on Firefox OS (B2G)!");
         }
 
         SimpleTest.finish();
--- a/dom/alarm/test/test_bug1090896.html
+++ b/dom/alarm/test/test_bug1090896.html
@@ -9,16 +9,30 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test">
   <script type="application/javascript">
 
   "use strict";
 
+  function registerPage() {
+    var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('system_message_chrome_script.js'));
+    gScript.addMessageListener("page-registered", function pageRegisteredHandler() {
+      gScript.removeMessageListener("page-registered", pageRegisteredHandler);
+      gScript.destroy();
+      testFireTimeAlertWithNoData();
+    });
+
+    gScript.sendAsyncMessage("trigger-register-page",
+                             { type: "alarm",
+                               manifestURL: window.location.origin + "/manifest.webapp",
+                               pageURL: window.location.href });
+  }
+
   function testFireTimeAlertWithNoData() {
     var secondsLater = new Date();
     secondsLater.setSeconds(secondsLater.getSeconds() + 1);
 
     var domRequest;
     try {
       // Set system message handler.
       navigator.mozSetMessageHandler('alarm', function(message){
@@ -56,17 +70,17 @@
                  SpecialPowers.Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
         ok(true, "mozAlarms is not allowed for non-installed apps. " +
                  "TODO Bug 876981.");
         isAllowedToTest = false;
       }
 
       if (isAllowedToTest) {
         ok(true, "Start to test...");
-        testFireTimeAlertWithNoData();
+        registerPage();
       } else {
         // A sanity check to make sure we must run tests on Firefox OS (B2G).
         if (navigator.userAgent.indexOf("Mobile") != -1 &&
             navigator.appVersion.indexOf("Android") == -1) {
           ok(false, "Should run the test on Firefox OS (B2G)!");
         }
 
         SimpleTest.finish();
--- a/dom/media/DecodedStream.cpp
+++ b/dom/media/DecodedStream.cpp
@@ -229,16 +229,17 @@ OutputStreamData::Init(DecodedStream* aD
   mListener = new OutputStreamListener(aDecodedStream, aStream);
   aStream->AddListener(mListener);
 }
 
 DecodedStream::DecodedStream(MediaQueue<MediaData>& aAudioQueue,
                              MediaQueue<MediaData>& aVideoQueue)
   : mMonitor("DecodedStream::mMonitor")
   , mPlaying(false)
+  , mVolume(1.0)
   , mAudioQueue(aAudioQueue)
   , mVideoQueue(aVideoQueue)
 {
 }
 
 DecodedStream::~DecodedStream()
 {
 }
@@ -414,16 +415,23 @@ DecodedStream::SetPlaying(bool aPlaying)
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mPlaying = aPlaying;
   if (mData) {
     mData->SetPlaying(aPlaying);
   }
 }
 
 void
+DecodedStream::SetVolume(double aVolume)
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  mVolume = aVolume;
+}
+
+void
 DecodedStream::InitTracks()
 {
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (mData->mStreamInitialized) {
     return;
   }
 
@@ -661,23 +669,23 @@ DecodedStream::AdvanceTracks()
   }
 
   if (!mData->mHaveSentFinish) {
     mData->mStream->AdvanceKnownTracksTime(endPosition);
   }
 }
 
 bool
-DecodedStream::SendData(double aVolume, bool aIsSameOrigin)
+DecodedStream::SendData(bool aIsSameOrigin)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()");
 
   InitTracks();
-  SendAudio(aVolume, aIsSameOrigin);
+  SendAudio(mVolume, aIsSameOrigin);
   SendVideo(aIsSameOrigin);
   AdvanceTracks();
 
   bool finished = (!mInfo.HasAudio() || mAudioQueue.IsFinished()) &&
                   (!mInfo.HasVideo() || mVideoQueue.IsFinished());
 
   if (finished && !mData->mHaveSentFinish) {
     mData->mHaveSentFinish = true;
--- a/dom/media/DecodedStream.h
+++ b/dom/media/DecodedStream.h
@@ -56,24 +56,27 @@ public:
   void StartPlayback(int64_t aStartTime, const MediaInfo& aInfo);
   // Mimic MDSM::StopAudioThread.
   void StopPlayback();
 
   void DestroyData();
   void RecreateData();
   void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
   void Remove(MediaStream* aStream);
+
   void SetPlaying(bool aPlaying);
+  void SetVolume(double aVolume);
+
   int64_t AudioEndTime() const;
   int64_t GetPosition() const;
   bool IsFinished() const;
   bool HasConsumers() const;
 
   // Return true if stream is finished.
-  bool SendData(double aVolume, bool aIsSameOrigin);
+  bool SendData(bool aIsSameOrigin);
 
 protected:
   virtual ~DecodedStream();
 
 private:
   ReentrantMonitor& GetReentrantMonitor() const;
   void RecreateData(MediaStreamGraph* aGraph);
   void Connect(OutputStreamData* aStream);
@@ -92,16 +95,18 @@ private:
   // required by bug 1146482. DecodedStream needs to release monitor before
   // calling back into MDSM functions in order to prevent deadlocks.
   //
   // Please move all capture-stream related code from MDSM into DecodedStream
   // and apply "dispatch + mirroring" to get rid of this monitor in the future.
   mutable ReentrantMonitor mMonitor;
 
   bool mPlaying;
+  double mVolume;
+
   Maybe<int64_t> mStartTime;
   MediaInfo mInfo;
 
   MediaQueue<MediaData>& mAudioQueue;
   MediaQueue<MediaData>& mVideoQueue;
 };
 
 } // namespace mozilla
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -371,17 +371,17 @@ int64_t MediaDecoderStateMachine::GetDec
 }
 
 void MediaDecoderStateMachine::SendStreamData()
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
 
-  bool finished = mDecodedStream->SendData(mVolume, mSameOriginMedia);
+  bool finished = mDecodedStream->SendData(mSameOriginMedia);
 
   const auto clockTime = GetClock();
   while (true) {
     const MediaData* a = AudioQueue().PeekFront();
 
     // If we discard audio samples fed to the stream immediately, we will
     // keep decoding audio samples till the end and consume a lot of memory.
     // Therefore we only discard those behind the stream clock to throttle
@@ -1164,16 +1164,17 @@ void MediaDecoderStateMachine::SetState(
 
 void MediaDecoderStateMachine::VolumeChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mAudioSink) {
     mAudioSink->SetVolume(mVolume);
   }
+  mDecodedStream->SetVolume(mVolume);
 }
 
 void MediaDecoderStateMachine::RecomputeDuration()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   TimeUnit duration;
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -169,17 +169,17 @@ public:
   {
   }
 
   VideoInfo(int32_t aWidth, int32_t aHeight)
     : TrackInfo(kVideoTrack, NS_LITERAL_STRING("2"), NS_LITERAL_STRING("main"),
                 EmptyString(), EmptyString(), true, 2)
     , mDisplay(nsIntSize(aWidth, aHeight))
     , mStereoMode(StereoMode::MONO)
-    , mImage(nsIntSize(aWidth, aHeight))
+    , mImage(nsIntRect(0, 0, aWidth, aHeight))
     , mCodecSpecificConfig(new MediaByteBuffer)
     , mExtraData(new MediaByteBuffer)
   {
   }
 
   VideoInfo(const VideoInfo& aOther)
     : TrackInfo(aOther)
     , mDisplay(aOther.mDisplay)
@@ -212,18 +212,18 @@ public:
 
   // Size in pixels at which the video is rendered. This is after it has
   // been scaled by its aspect ratio.
   nsIntSize mDisplay;
 
   // Indicates the frame layout for single track stereo videos.
   StereoMode mStereoMode;
 
-  // Size in pixels of decoded video's image.
-  nsIntSize mImage;
+  // Visible area of the decoded video's image.
+  nsIntRect mImage;
   nsRefPtr<MediaByteBuffer> mCodecSpecificConfig;
   nsRefPtr<MediaByteBuffer> mExtraData;
 };
 
 class AudioInfo : public TrackInfo {
 public:
   AudioInfo()
     : TrackInfo(kAudioTrack, NS_LITERAL_STRING("1"), NS_LITERAL_STRING("main"),
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -318,16 +318,22 @@ RTCPeerConnection.prototype = {
   contractID: PC_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
   init: function(win) { this._win = win; },
 
   __init: function(rtcConfig) {
     this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
     .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+    // TODO: Update this code once we support pc.setConfiguration, to track
+    // setting from content independently from pref (Bug 1181768).
+    if (rtcConfig.iceTransportPolicy == "all" &&
+        Services.prefs.getBoolPref("media.peerconnection.ice.relay_only")) {
+      rtcConfig.iceTransportPolicy = "relay";
+    }
     if (!rtcConfig.iceServers ||
         !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
       try {
          rtcConfig.iceServers =
            JSON.parse(Services.prefs.getCharPref("media.peerconnection.default_iceservers") || "[]");
       } catch (e) {
         this.logWarning(
             "Ignoring invalid media.peerconnection.default_iceservers in about:config",
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -255,17 +255,18 @@ static const uint8_t sTestH264ExtraData[
 static already_AddRefed<MediaDataDecoder>
 CreateTestH264Decoder(layers::LayersBackend aBackend,
                       VideoInfo& aConfig)
 {
   aConfig.mMimeType = "video/avc";
   aConfig.mId = 1;
   aConfig.mDuration = 40000;
   aConfig.mMediaTime = 0;
-  aConfig.mDisplay = aConfig.mImage = nsIntSize(64, 64);
+  aConfig.mDisplay = nsIntSize(64, 64);
+  aConfig.mImage = nsIntRect(0, 0, 64, 64);
   aConfig.mExtraData = new MediaByteBuffer();
   aConfig.mExtraData->AppendElements(sTestH264ExtraData,
                                      MOZ_ARRAY_LENGTH(sTestH264ExtraData));
 
   PlatformDecoderModule::Init();
 
   nsRefPtr<PlatformDecoderModule> platform = PlatformDecoderModule::Create();
   if (!platform) {
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -310,22 +310,27 @@ TrackBuffersManager::Ended()
 }
 
 void
 TrackBuffersManager::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
 
+  // Abort pending operations if any.
+  AbortAppendData();
+
   nsRefPtr<TrackBuffersManager> self = this;
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableFunction([self] () {
       // Clear our sourcebuffer
       self->CodedFrameRemoval(TimeInterval(TimeUnit::FromSeconds(0),
                                            TimeUnit::FromInfinity()));
+      self->mProcessingPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
+      self->mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
       self->mMediaSourceDuration.DisconnectIfConnected();
     });
   GetTaskQueue()->Dispatch(task.forget());
 }
 
 #if defined(DEBUG)
 void
 TrackBuffersManager::Dump(const char* aPath)
@@ -656,20 +661,19 @@ TrackBuffersManager::SegmentParserLoop()
           RecreateParser(false);
         }
         continue;
       }
       if (mParser->IsMediaSegmentPresent(mInputBuffer)) {
         SetAppendState(AppendState::PARSING_MEDIA_SEGMENT);
         continue;
       }
-      // We have neither an init segment nor a media segment, this is invalid
-      // data. We can ignore it.
-      MSE_DEBUG("Found invalid data, ignoring.");
-      mInputBuffer = nullptr;
+      // We have neither an init segment nor a media segment, this is either
+      // invalid data or not enough data to detect a segment type.
+      MSE_DEBUG("Found invalid or incomplete data.");
       NeedMoreData();
       return;
     }
 
     int64_t start, end;
     mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end);
     mProcessedInput += mInputBuffer->Length();
 
@@ -1029,35 +1033,42 @@ TrackBuffersManager::OnDemuxerInitFailed
   RejectAppend(NS_ERROR_FAILURE, __func__);
 }
 
 nsRefPtr<TrackBuffersManager::CodedFrameProcessingPromise>
 TrackBuffersManager::CodedFrameProcessing()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mProcessingPromise.IsEmpty());
-  nsRefPtr<CodedFrameProcessingPromise> p = mProcessingPromise.Ensure(__func__);
 
   MediaByteRange mediaRange = mParser->MediaSegmentRange();
   if (mediaRange.IsNull()) {
     AppendDataToCurrentInputBuffer(mInputBuffer);
     mInputBuffer = nullptr;
   } else {
+    MOZ_ASSERT(mProcessedInput >= mInputBuffer->Length());
+    if (int64_t(mProcessedInput - mInputBuffer->Length()) > mediaRange.mEnd) {
+      // Something is not quite right with the data appended. Refuse it.
+      // This would typically happen if the previous media segment was partial
+      // yet a new complete media segment was added.
+      return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    }
     // The mediaRange is offset by the init segment position previously added.
     uint32_t length =
       mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length());
     nsRefPtr<MediaByteBuffer> segment = new MediaByteBuffer;
-    MOZ_ASSERT(mInputBuffer->Length() >= length);
     if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) {
       return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
     }
     AppendDataToCurrentInputBuffer(segment);
     mInputBuffer->RemoveElementsAt(0, length);
   }
 
+  nsRefPtr<CodedFrameProcessingPromise> p = mProcessingPromise.Ensure(__func__);
+
   DoDemuxVideo();
 
   return p;
 }
 
 void
 TrackBuffersManager::OnDemuxFailed(TrackType aTrack,
                                    DemuxerFailureReason aFailure)
@@ -1627,23 +1638,25 @@ TrackBuffersManager::RemoveFrames(const 
         lastRemovedIndex - firstRemovedIndex.ref() + 1;
     }
   }
 
   if (aTrackData.mNextInsertionIndex.isSome()) {
     if (aTrackData.mNextInsertionIndex.ref() > firstRemovedIndex.ref() &&
         aTrackData.mNextInsertionIndex.ref() <= lastRemovedIndex + 1) {
       aTrackData.ResetAppendState();
+      MSE_DEBUG("NextInsertionIndex got reset.");
     } else if (aTrackData.mNextInsertionIndex.ref() > lastRemovedIndex + 1) {
       aTrackData.mNextInsertionIndex.ref() -=
         lastRemovedIndex - firstRemovedIndex.ref() + 1;
     }
   }
 
   // Update our buffered range to exclude the range just removed.
+  removedIntervals.SetFuzz(TimeUnit::FromMicroseconds(maxSampleDuration/2));
   aTrackData.mBufferedRanges -= removedIntervals;
 
   data.RemoveElementsAt(firstRemovedIndex.ref(),
                         lastRemovedIndex - firstRemovedIndex.ref() + 1);
 }
 
 void
 TrackBuffersManager::RecreateParser(bool aReuseInitData)
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -25,18 +25,17 @@ extern PRLogModuleInfo* gMediaDecoderLog
 VPXDecoder::VPXDecoder(const VideoInfo& aConfig,
                        ImageContainer* aImageContainer,
                        FlushableTaskQueue* aTaskQueue,
                        MediaDataDecoderCallback* aCallback)
   : mImageContainer(aImageContainer)
   , mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
   , mIter(nullptr)
-  , mDisplayWidth(aConfig.mDisplay.width)
-  , mDisplayHeight(aConfig.mDisplay.height)
+  , mInfo(aConfig)
 {
   MOZ_COUNT_CTOR(VPXDecoder);
   if (aConfig.mMimeType.EqualsLiteral("video/webm; codecs=vp8")) {
     mCodec = Codec::VP8;
   } else if (aConfig.mMimeType.EqualsLiteral("video/webm; codecs=vp9")) {
     mCodec = Codec::VP9;
   } else {
     mCodec = -1;
@@ -120,33 +119,32 @@ VPXDecoder::DoDecodeFrame(MediaRawData* 
     b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
 
     b.mPlanes[2].mData = img->planes[2];
     b.mPlanes[2].mStride = img->stride[2];
     b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
     b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
     b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
 
-    IntRect picture = IntRect(0, 0, img->d_w, img->d_h);
     VideoInfo info;
-    info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);
+    info.mDisplay = mInfo.mDisplay;
     nsRefPtr<VideoData> v = VideoData::Create(info,
                                               mImageContainer,
                                               aSample->mOffset,
                                               aSample->mTime,
                                               aSample->mDuration,
                                               b,
                                               aSample->mKeyframe,
                                               aSample->mTimecode,
-                                              picture);
+                                              mInfo.mImage);
 
     if (!v) {
       LOG("Image allocation error source %ldx%ld display %ldx%ld picture %ldx%ld",
-          img->d_w, img->d_h, mDisplayWidth, mDisplayHeight,
-          picture.width, picture.height);
+          img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height,
+          mInfo.mImage.width, mInfo.mImage.height);
       return -1;
     }
     mCallback->Output(v);
     return 1;
   }
   mIter = nullptr;
   return 0;
 }
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -51,17 +51,16 @@ private:
   nsRefPtr<ImageContainer> mImageContainer;
   RefPtr<FlushableTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
   // VPx decoder state
   vpx_codec_ctx_t mVPX;
   vpx_codec_iter_t mIter;
 
-  uint32_t mDisplayWidth;
-  uint32_t mDisplayHeight;
+  const VideoInfo& mInfo;
 
   int mCodec;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -250,16 +250,19 @@ public:
     ENVOKE_CALLBACK(Output, data);
     return NS_OK;
   }
 };
 
 
 bool AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType)
 {
+  if (!AndroidBridge::Bridge() || (AndroidBridge::Bridge()->GetAPIVersion() < 16)) {
+    return false;
+  }
   if (aMimeType.EqualsLiteral("video/mp4") ||
       aMimeType.EqualsLiteral("video/avc")) {
     return true;
   }
   return static_cast<bool>(mozilla::CreateDecoder(aMimeType));
 }
 
 already_AddRefed<MediaDataDecoder>
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -202,16 +202,22 @@ WMFVideoMFTManager::InitInternal(bool aF
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   RefPtr<IMFAttributes> attr(decoder->GetAttributes());
   UINT32 aware = 0;
   if (attr) {
       attr->GetUINT32(MF_SA_D3D_AWARE, &aware);
       attr->SetUINT32(CODECAPI_AVDecNumWorkerThreads,
                       WMFDecoderModule::GetNumDecoderThreads());
+      hr = attr->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE);
+      if (SUCCEEDED(hr)) {
+        LOG("Enabling Low Latency Mode");
+      } else {
+        LOG("Couldn't enable Low Latency Mode");
+      }
   }
 
   if (useDxva) {
     if (aware) {
       // TODO: Test if I need this anywhere... Maybe on Vista?
       //hr = attr->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
       //NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
       MOZ_ASSERT(mDXVA2Manager);
--- a/dom/media/test/test_mediarecorder_record_timeslice.html
+++ b/dom/media/test/test_mediarecorder_record_timeslice.html
@@ -20,16 +20,17 @@ function startTest(test, token) {
   var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
 
   element.token = token;
   manager.started(token);
 
   element.src = test.name;
   element.test = test;
   element.stream = element.mozCaptureStream();
+  element.loop = true;
 
   var mediaRecorder = new MediaRecorder(element.stream);
 
   mediaRecorder.onerror = function () {
     ok(false, 'Unexpected onerror callback fired');
   };
 
   mediaRecorder.onwarning = function () {
@@ -63,35 +64,35 @@ function startTest(test, token) {
     // We'll stop recording upon the 1st blob being received
     if (dataAvailableCount === 1) {
       mediaRecorder.onstop = function (evt) {
         info('onstop fired');
 
         if (!onDataAvailableFirst) {
           ok(false, 'onstop unexpectedly fired before ondataavailable');
         }
-
+        element.pause();
         manager.finished(token);
       };
 
       mediaRecorder.stop();
       is(mediaRecorder.state, 'inactive',
          'Media recorder is inactive after being stopped');
       is(mediaRecorder.stream, element.stream,
          'Media recorder stream = element stream post recording');
 
     } else if (dataAvailableCount === 2) {
       // Ensure we've received at least two ondataavailable events before onstop
       onDataAvailableFirst = true;
     }
   };
 
-  // Start recording once canplaythrough fires
-  element.oncanplaythrough = function() {
-    element.oncanplaythrough = null;
+  // Start recording once metadataloaded fires
+  element.onloadedmetadata = function() {
+    element.onloadedmetadata = null;
     mediaRecorder.start(250);
     is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
     is(mediaRecorder.stream, element.stream,
        'Media recorder stream = element stream at the start of recording');
   };
 
   element.play();
 }
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -113,16 +113,18 @@ skip-if = toolkit == 'gonk' # B2G emulat
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_offerRequiresReceiveAudio.html]
 [test_peerConnection_offerRequiresReceiveVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideoAudio.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_promiseSendOnly.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
+[test_peerConnection_relayOnly.html]
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_callbacks.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_replaceTrack.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_syncSetDescription.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
 [test_peerConnection_setLocalAnswerInStable.html]
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1184,28 +1184,25 @@ PeerConnectionWrapper.prototype = {
    * Registers a callback for the ICE connection state change and
    * reports success (=connected) or failure via the callbacks.
    * States "new" and "checking" are ignored.
    *
    * @returns {Promise}
    *          resolves when connected, rejects on failure
    */
   waitForIceConnected : function() {
-    return new Promise((resolve, reject) => {
-      var iceConnectedChanged = () => {
-        if (this.isIceConnected()) {
-          delete this.ice_connection_callbacks.waitForIceConnected;
-          resolve();
-        } else if (! this.isIceConnectionPending()) {
-          delete this.ice_connection_callbacks.waitForIceConnected;
-          resolve();
-        }
+    return new Promise((resolve, reject) =>
+        this.ice_connection_callbacks.waitForIceConnected = () => {
+      if (this.isIceConnected()) {
+        delete this.ice_connection_callbacks.waitForIceConnected;
+        resolve();
+      } else if (!this.isIceConnectionPending()) {
+        delete this.ice_connection_callbacks.waitForIceConnected;
+        reject(new Error('ICE failed'));
       }
-
-      this.ice_connection_callbacks.waitForIceConnected = iceConnectedChanged;
     });
   },
 
   /**
    * Setup a onicecandidate handler
    *
    * @param {object} test
    *        A PeerConnectionTest object to which the ice candidates gets
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_relayOnly.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+createHTML({
+  bug: "1187775",
+  title: "peer connection ICE fails on relay-only without TURN"
+});
+
+function PC_LOCAL_NO_CANDIDATES(test) {
+  var isnt = can => is(can, null, "No candidates: " + JSON.stringify(can));
+  test.pcLocal._pc.addEventListener("icecandidate", e => isnt(e.candidate));
+}
+
+function PC_BOTH_WAIT_FOR_ICE_FAILED(test) {
+  var isFail = (f, reason, msg) =>
+    f().then(() => { throw new Error(msg + " must fail"); },
+             e => is(e.message, reason, msg + " must fail with: " + e.message));
+
+  return Promise.all([
+    isFail(() => waitForIceConnected(test, test.pcLocal), "ICE failed", "Local ICE"),
+    isFail(() => waitForIceConnected(test, test.pcRemote), "ICE failed", "Remote ICE")
+  ])
+  .then(() => ok(true, "ICE on both sides must fail."));
+}
+
+var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
+var test;
+
+runNetworkTest(options =>
+    pushPrefs(['media.peerconnection.ice.stun_client_maximum_transmits', 3],
+              ['media.peerconnection.ice.trickle_grace_period', 5000]).then(() => {
+  options = options || {};
+  options.config_local = options.config_local || {};
+  var servers = options.config_local.iceServers || [];
+  // remove any turn servers
+  options.config_local.iceServers = servers.filter(server =>
+      server.urls.every(u => !u.toLowerCase().startsWith('turn')));
+
+  // Here's the setting we're testing. Comment out and this test should fail:
+  options.config_local.iceTransportPolicy = "relay";
+
+  test = new PeerConnectionTest(options);
+  test.setMediaConstraints([{audio: true}, {video: true}],
+                           [{audio: true}, {video: true}]);
+  test.chain.remove("PC_LOCAL_SETUP_ICE_LOGGER");  // Needed to suppress failing
+  test.chain.remove("PC_REMOTE_SETUP_ICE_LOGGER"); // on ICE-failure.
+  test.chain.insertAfter("PC_LOCAL_SETUP_ICE_HANDLER", PC_LOCAL_NO_CANDIDATES);
+  test.chain.replace("PC_LOCAL_WAIT_FOR_ICE_CONNECTED", PC_BOTH_WAIT_FOR_ICE_FAILED);
+  test.chain.removeAfter("PC_BOTH_WAIT_FOR_ICE_FAILED");
+  test.run();
+}));
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -311,18 +311,17 @@ WebMDemuxer::ReadMetadata()
         // Video track's frame sizes will overflow. Ignore the video track.
         continue;
       }
 
       mVideoTrack = track;
       mHasVideo = true;
 
       mInfo.mVideo.mDisplay = displaySize;
-
-      mPicture = pictureRect;
+      mInfo.mVideo.mImage = pictureRect;
 
       switch (params.stereo_mode) {
         case NESTEGG_VIDEO_MONO:
           mInfo.mVideo.mStereoMode = StereoMode::MONO;
           break;
         case NESTEGG_VIDEO_STEREO_LEFT_RIGHT:
           mInfo.mVideo.mStereoMode = StereoMode::LEFT_RIGHT;
           break;
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -143,19 +143,16 @@ private:
   uint64_t mSeekPreroll;
 
   int64_t mLastAudioFrameTime;
 
   // Calculate the frame duration from the last decodeable frame using the
   // previous frame's timestamp.  In NS.
   int64_t mLastVideoFrameTime;
 
-  // Picture region, as relative to the initial frame size.
-  nsIntRect mPicture;
-
   // Codec ID of audio track
   int mAudioCodec;
   // Codec ID of video track
   int mVideoCodec;
 
   // Booleans to indicate if we have audio and/or video data
   bool mHasVideo;
   bool mHasAudio;
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -737,21 +737,19 @@ SystemMessageInternal.prototype = {
       return MSG_SENT_FAILURE_PERM_DENIED;
     }
 
     // Queue this message in the corresponding pages.
     let page = this._findPage(aType, aPageURL, aManifestURL);
     if (!page) {
       debug("Message " + aType + " is not registered for " +
             aPageURL + " @ " + aManifestURL);
-      // FIXME bug 1140275 should only send message to page registered in manifest
-      // return MSG_SENT_FAILURE_PERM_DENIED;
+      return MSG_SENT_FAILURE_PERM_DENIED;
     }
-    if (page)
-      this._queueMessage(page, aMessage, aMessageID);
+    this._queueMessage(page, aMessage, aMessageID);
 
     let appPageIsRunning = false;
     let pageKey = this._createKeyForPage({ type: aType,
                                            manifestURL: aManifestURL,
                                            pageURL: aPageURL });
 
     let cache = this._findCacheForApp(aManifestURL);
     let targets = this._listeners[aManifestURL];
@@ -796,18 +794,17 @@ SystemMessageInternal.prototype = {
       // wake it up. We still need to acquire a CPU wake lock for that page and
       // expect that we will receive a "SystemMessageManager:HandleMessagesDone"
       // or a "SystemMessageManager:HandleMessageDone" message when the page
       // finishes handling the system message with other pending messages. At
       // that point, we'll release the lock we acquired.
       result = MSG_SENT_FAILURE_APP_NOT_RUNNING;
       this._acquireCpuWakeLock(pageKey);
     }
-    if (page)
-      this._openAppPage(page, aMessage, aExtra, result);
+    this._openAppPage(page, aMessage, aExtra, result);
     return result;
   },
 
   _resolvePendingPromises: function(aMessageID) {
     if (!this._pendingPromises.has(aMessageID)) {
       debug("Unknown pendingPromise messageID. This seems a bug!!");
       return;
     }
--- a/dom/messages/test/mochitest.ini
+++ b/dom/messages/test/mochitest.ini
@@ -1,2 +1,6 @@
+[DEFAULT]
+support-files =
+  system_message_chrome_script.js
+
 [test_bug_993732.html]
 skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
new file mode 100644
--- /dev/null
+++ b/dom/messages/test/system_message_chrome_script.js
@@ -0,0 +1,18 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+'use strict';
+
+const { classes: Cc, interfaces: Ci } = Components;
+
+const systemMessenger = Cc["@mozilla.org/system-message-internal;1"]
+                          .getService(Ci.nsISystemMessagesInternal);
+const ioService = Cc["@mozilla.org/network/io-service;1"]
+                    .getService(Ci.nsIIOService);
+
+addMessageListener("trigger-register-page", function(aData) {
+  systemMessenger.registerPage(aData.type,
+                               ioService.newURI(aData.pageURL, null, null),
+                               ioService.newURI(aData.manifestURL, null, null));
+  sendAsyncMessage("page-registered");
+});
--- a/dom/messages/test/test_bug_993732.html
+++ b/dom/messages/test/test_bug_993732.html
@@ -14,16 +14,30 @@
 
   "use strict";
 
   // The syndrome of Bug 993732 is that the running app (either foreground or background)
   // is not able to receive system messages. Even worse, the app will be killed when the
   // listening system message is broadcast. So this test case uses the alarm message
   // to test if a running app can receive the system message.
 
+  function registerPage() {
+    var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('system_message_chrome_script.js'));
+    gScript.addMessageListener("page-registered", function pageRegisteredHandler() {
+      gScript.removeMessageListener("page-registered", pageRegisteredHandler);
+      gScript.destroy();
+      testAlarm(10000);
+    });
+
+    gScript.sendAsyncMessage("trigger-register-page",
+                             { type: "alarm",
+                               manifestURL: window.location.origin + "/manifest.webapp",
+                               pageURL: window.location.href });
+  }
+
   function testAlarm(aMillisecondsFromNow) {
     var at = new Date();
     at.setTime(at.getTime() + aMillisecondsFromNow);
 
     navigator.mozSetMessageHandler('alarm', function(message) {
       ok(true, "We got alarm message!");
       SimpleTest.finish();
     });
@@ -35,29 +49,29 @@
       ok(false,
          "Unexpected exception while adding alarm " + aMillisecondsFromNow + " ms from now.");
       SimpleTest.finish();
     }
     domRequest.onsuccess = function(e) {
       // Waiting for alarm message.
     };
     domRequest.onerror = function(e) {
-      ok(false, "Unable to add alarm for tomorrow`.");
+      ok(false, "Unable to add alarm.");
       SimpleTest.finish();
     };
   }
 
   function startTests() {
 
     SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function() {
       // Currently applicable only on FxOS
       if (navigator.userAgent.indexOf("Mobile") != -1 &&
           navigator.appVersion.indexOf("Android") == -1)
       {
-        testAlarm(10000);
+        registerPage();
       } else {
         ok(true, "mozAlarms on Firefox OS only.");
         SimpleTest.finish();
       }
     });
   }
 
   SimpleTest.expectAssertions(0, 9);
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -63,20 +63,22 @@ intr protocol PPluginInstance
   manages PBrowserStream;
   manages PPluginStream;
   manages PStreamNotify;
   manages PPluginSurface;
 
 child:
   intr __delete__();
 
-  // Return value is only used on Windows and only when the window needs its
-  // parent set to the chrome widget native window.
-  intr NPP_SetWindow(NPRemoteWindow window)
-    returns (NPRemoteWindow childWindowToBeAdopted);
+  // This is only used on Windows and, for windowed plugins, must be called
+  // before the first call to NPP_SetWindow.
+  intr CreateChildPluginWindow(NPRemoteWindow window)
+    returns (NPRemoteWindow createdChild);
+
+  intr NPP_SetWindow(NPRemoteWindow window);
 
   intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
     returns (bool value, NPError result);
 
   // this message is not used on non-X platforms
   intr NPP_GetValue_NPPVpluginNeedsXEmbed()
     returns (bool value, NPError result);
 
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -1141,18 +1141,44 @@ void PluginInstanceChild::DeleteWindow()
 #endif
 
   // We don't have to keep the plug-in window ID any longer.
   mWindow.window = nullptr;
 }
 #endif
 
 bool
-PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
-                                         NPRemoteWindow* aChildWindowToBeAdopted)
+PluginInstanceChild::AnswerCreateChildPluginWindow(const NPRemoteWindow& aWindow,
+                                                   NPRemoteWindow* aCreatedChild)
+{
+#if defined(XP_WIN)
+    MOZ_ASSERT(aWindow.type == NPWindowTypeWindow);
+    MOZ_ASSERT(!mPluginWindowHWND);
+
+    if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
+        aWindow.width == 0 && aWindow.height == 0) {
+
+        // Skip CreateChildPluginWindow call for hidden QuickTime plugins.
+        return true;
+    }
+
+    if (!CreatePluginWindow()) {
+        return false;
+    }
+
+    aCreatedChild->window = reinterpret_cast<uint64_t>(mPluginWindowHWND);
+    return true;
+#else
+    NS_NOTREACHED("PluginInstanceChild::CreateChildPluginWindow not implemented!");
+    return false;
+#endif
+}
+
+bool
+PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
 {
     PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
                       FULLFUNCTION,
                       aWindow.window,
                       aWindow.x, aWindow.y,
                       aWindow.width, aWindow.height));
     NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
                  "Shouldn't be receiving NPP_SetWindow with layer rendering");
@@ -1230,45 +1256,27 @@ PluginInstanceChild::AnswerNPP_SetWindow
       {
           if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
               aWindow.width == 0 &&
               aWindow.height == 0) {
             // Skip SetWindow call for hidden QuickTime plugins
             return true;
           }
 
-          if (!CreatePluginWindow())
-              return false;
+          MOZ_ASSERT(mPluginWindowHWND,
+                     "Child plugin window must exist before call to SetWindow");
+
+          HWND parentHWND =  reinterpret_cast<HWND>(aWindow.window);
+          if (mPluginWindowHWND != parentHWND) {
+              mPluginParentHWND = parentHWND;
+              ShowWindow(mPluginWindowHWND, SW_SHOWNA);
+          }
 
           SizePluginWindow(aWindow.width, aWindow.height);
 
-          // If the window is not our parent set the return child window so that
-          // it can be re-parented in the chrome process. Re-parenting now
-          // happens there as we might not have sufficient permission.
-          // Also, this needs to be after SizePluginWindow because SetWindowPos
-          // relies on things that it sets.
-          HWND parentWindow = reinterpret_cast<HWND>(aWindow.window);
-          if (mPluginParentHWND != parentWindow  && IsWindow(parentWindow)) {
-              mPluginParentHWND = parentWindow;
-              aChildWindowToBeAdopted->window =
-                  reinterpret_cast<uint64_t>(mPluginWindowHWND);
-          } else {
-              // Now we know that the window has the correct parent we can show
-              // it. The actual visibility is controlled by its parent.
-              // First time round, these calls are made by our caller after the
-              // parent is set.
-              ShowWindow(mPluginWindowHWND, SW_SHOWNA);
-
-              // This used to be called in SizePluginWindow, but we need to make
-              // sure that mPluginWindowHWND has had it's parent set correctly,
-              // otherwise it can cause a focus issue.
-              SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, aWindow.width,
-                           aWindow.height, SWP_NOZORDER | SWP_NOREPOSITION);
-          }
-
           mWindow.window = (void*)mPluginWindowHWND;
           mWindow.x = aWindow.x;
           mWindow.y = aWindow.y;
           mWindow.width = aWindow.width;
           mWindow.height = aWindow.height;
           mWindow.type = aWindow.type;
 
           if (mPluginIface->setwindow) {
@@ -1453,16 +1461,18 @@ PluginInstanceChild::DestroyPluginWindow
 
 void
 PluginInstanceChild::SizePluginWindow(int width,
                                       int height)
 {
     if (mPluginWindowHWND) {
         mPluginSize.x = width;
         mPluginSize.y = height;
+        SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height,
+                     SWP_NOZORDER | SWP_NOREPOSITION);
     }
 }
 
 // See chromium's webplugin_delegate_impl.cc for explanation of this function.
 // static
 LRESULT CALLBACK
 PluginInstanceChild::DummyWindowProc(HWND hWnd,
                                      UINT message,
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -60,18 +60,20 @@ class PluginInstanceChild : public PPlug
                                              LPARAM lParam);
     static LRESULT CALLBACK PluginWindowProcInternal(HWND hWnd,
                                                      UINT message,
                                                      WPARAM wParam,
                                                      LPARAM lParam);
 #endif
 
 protected:
-    bool AnswerNPP_SetWindow(const NPRemoteWindow& window,
-                             NPRemoteWindow* aChildWindowToBeAdopted) override;
+    bool AnswerCreateChildPluginWindow(const NPRemoteWindow& window,
+                                       NPRemoteWindow* aCreatedChild) override;
+
+    bool AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
 
     virtual bool
     AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override;
     virtual bool
     AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(bool* needs, NPError* rv) override;
     virtual bool
     AnswerNPP_GetValue_NPPVpluginScriptableNPObject(PPluginScriptableObjectChild** value,
                                                     NPError* result) override;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -112,16 +112,18 @@ PluginInstanceParent::PluginInstancePare
     , mUseSurrogate(true)
     , mNPP(npp)
     , mNPNIface(npniface)
     , mIsWhitelistedForShumway(false)
     , mWindowType(NPWindowTypeWindow)
     , mDrawingModel(kDefaultDrawingModel)
 #if defined(OS_WIN)
     , mPluginHWND(nullptr)
+    , mChildPluginHWND(nullptr)
+    , mChildPluginsParentHWND(nullptr)
     , mPluginWndProc(nullptr)
     , mNestedEventState(false)
 #endif // defined(XP_WIN)
 #if defined(XP_MACOSX)
     , mShWidth(0)
     , mShHeight(0)
     , mShColorSpace(nullptr)
 #endif
@@ -1020,41 +1022,47 @@ PluginInstanceParent::NPP_SetWindow(cons
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     const NPSetWindowCallbackStruct* ws_info =
       static_cast<NPSetWindowCallbackStruct*>(aWindow->ws_info);
     window.visualID = ws_info->visual ? ws_info->visual->visualid : None;
     window.colormap = ws_info->colormap;
 #endif
 
-    NPRemoteWindow childWindow;
-    if (!CallNPP_SetWindow(window, &childWindow)) {
-        return NPERR_GENERIC_ERROR;
+#if defined(XP_WIN)
+    // On Windows we need to create and set the parent before we set the window
+    // on the plugin, or certain things like keyboard interaction will not work.
+    if (!mChildPluginHWND && mWindowType == NPWindowTypeWindow) {
+        NPRemoteWindow childWindow;
+        if (!CallCreateChildPluginWindow(window, &childWindow)) {
+            return NPERR_GENERIC_ERROR;
+        }
+
+        mChildPluginHWND = reinterpret_cast<HWND>(childWindow.window);
     }
 
-#if defined(XP_WIN)
-    // If a child window is returned it means that we need to re-parent it.
-    if (childWindow.window) {
+    // It's not clear if the parent window would ever change, but when this was
+    // done in the NPAPI child it used to allow for this.
+    if (mChildPluginHWND && mPluginHWND != mChildPluginsParentHWND) {
         nsCOMPtr<nsIWidget> widget;
         static_cast<const nsPluginNativeWindow*>(aWindow)->
             GetPluginWidget(getter_AddRefs(widget));
         if (widget) {
             widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
-                                  static_cast<uintptr_t>(childWindow.window));
+                                  reinterpret_cast<uintptr_t>(mChildPluginHWND));
         }
 
-        // Now it has got the correct parent, make sure it is visible.
-        // In subsequent calls to SetWindow these calls happen in the Child.
-        HWND childHWND = reinterpret_cast<HWND>(childWindow.window);
-        ShowWindow(childHWND, SW_SHOWNA);
-        SetWindowPos(childHWND, nullptr, 0, 0, window.width, window.height,
-                     SWP_NOZORDER | SWP_NOREPOSITION);
+        mChildPluginsParentHWND = mPluginHWND;
     }
 #endif
 
+    if (!CallNPP_SetWindow(window)) {
+        return NPERR_GENERIC_ERROR;
+    }
+
     return NPERR_NO_ERROR;
 }
 
 NPError
 PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
                                    void* _retval)
 {
     switch (aVariable) {
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -361,16 +361,18 @@ private:
     void SubclassPluginWindow(HWND aWnd);
     void UnsubclassPluginWindow();
 
 private:
     gfx::SharedDIBWin  mSharedSurfaceDib;
     nsIntRect          mPluginPort;
     nsIntRect          mSharedSize;
     HWND               mPluginHWND;
+    HWND               mChildPluginHWND;
+    HWND               mChildPluginsParentHWND;
     WNDPROC            mPluginWndProc;
     bool               mNestedEventState;
 
     // This will automatically release the textures when this object goes away.
     nsRefPtrHashtable<nsPtrHashKey<void>, ID3D10Texture2D> mTextureMap;
 #endif // defined(XP_WIN)
 #if defined(MOZ_WIDGET_COCOA)
 private:
--- a/dom/requestsync/tests/mochitest.ini
+++ b/dom/requestsync/tests/mochitest.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 skip-if = e10s
 support-files =
   file_app.template.webapp
   file_app.sjs
   file_basic_app.html
   common_app.js
   common_basic.js
+  system_message_chrome_script.js
 
 [test_webidl.html]
 [test_minInterval.html]
 [test_basic.html]
 [test_basic_app.html]
 skip-if = buildapp == 'b2g'
 [test_wakeUp.html]
 skip-if = !(buildapp == 'b2g' && toolkit == 'gonk')
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/tests/system_message_chrome_script.js
@@ -0,0 +1,18 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+'use strict';
+
+const { classes: Cc, interfaces: Ci } = Components;
+
+const systemMessenger = Cc["@mozilla.org/system-message-internal;1"]
+                          .getService(Ci.nsISystemMessagesInternal);
+const ioService = Cc["@mozilla.org/network/io-service;1"]
+                    .getService(Ci.nsIIOService);
+
+addMessageListener("trigger-register-page", function(aData) {
+  systemMessenger.registerPage(aData.type,
+                               ioService.newURI(aData.pageURL, null, null),
+                               ioService.newURI(aData.manifestURL, null, null));
+  sendAsyncMessage("page-registered");
+});
--- a/dom/requestsync/tests/test_runNow.html
+++ b/dom/requestsync/tests/test_runNow.html
@@ -8,16 +8,30 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <div id="container"></div>
   <script type="application/javascript;version=1.7">
 
   var taskExecuted = false;
 
+  function registerPage() {
+    var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('system_message_chrome_script.js'));
+    gScript.addMessageListener("page-registered", function pageRegisteredHandler() {
+      gScript.removeMessageListener("page-registered", pageRegisteredHandler);
+      gScript.destroy();
+      runTests();
+    });
+
+    gScript.sendAsyncMessage("trigger-register-page",
+                             { type: "request-sync",
+                               manifestURL: window.location.origin + "/manifest.webapp",
+                               pageURL: window.location.href });
+  }
+
   function setMessageHandler() {
     navigator.mozSetMessageHandler('request-sync', function(e) {
       ok(true, "One event has been received!");
 
       if (e.task == "oneShot") {
         is(e.data, 42, "e.data is correct");
         is(e.lastSync, 0, "e.lastSync is correct");
         is(e.oneShot, true, "e.oneShot is correct");
@@ -80,16 +94,18 @@
 
     function() {
       if (SpecialPowers.isMainProcess()) {
         SpecialPowers.Cu.import("resource://gre/modules/RequestSyncService.jsm");
       }
       runTests();
     },
 
+    registerPage,
+
     setMessageHandler,
 
     test_register_oneShot,
 
     test_runNow,
 
     test_unregister_oneShot,
   ];
--- a/dom/requestsync/tests/test_wakeUp.html
+++ b/dom/requestsync/tests/test_wakeUp.html
@@ -15,16 +15,30 @@
   var multiShotCounter = 0;
 
   function maybeDone() {
     if (oneShotCounter == 1 && multiShotCounter == 5) {
       runTests();
     }
   }
 
+  function registerPage() {
+    var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('system_message_chrome_script.js'));
+    gScript.addMessageListener("page-registered", function pageRegisteredHandler() {
+      gScript.removeMessageListener("page-registered", pageRegisteredHandler);
+      gScript.destroy();
+      runTests();
+    });
+
+    gScript.sendAsyncMessage("trigger-register-page",
+                             { type: "request-sync",
+                               manifestURL: window.location.origin + "/manifest.webapp",
+                               pageURL: window.location.href });
+  }
+
   function setMessageHandler() {
     navigator.mozSetMessageHandler('request-sync', function(e) {
       ok(true, "One event has been received!");
 
       if (e.task == "oneShot") {
         is(e.data, 42, "e.data is correct");
         is(e.lastSync, 0, "e.lastSync is correct");
         is(e.oneShot, true, "e.oneShot is correct");
@@ -141,16 +155,17 @@
 
     function() {
       if (SpecialPowers.isMainProcess()) {
         SpecialPowers.Cu.import("resource://gre/modules/RequestSyncService.jsm");
       }
       runTests();
     },
 
+    registerPage,
     setMessageHandler,
 
     test_register_oneShot,
     test_register_multiShots,
 
     test_wait,
 
     test_unregister_oneShot,
--- a/dom/storage/DOMStorageDBThread.cpp
+++ b/dom/storage/DOMStorageDBThread.cpp
@@ -182,28 +182,28 @@ DOMStorageDBThread::GetScopesHavingData(
 nsresult
 DOMStorageDBThread::InsertDBOp(DOMStorageDBThread::DBOperation* aOperation)
 {
   MonitorAutoLock monitor(mThreadObserver->GetMonitor());
 
   // Sentinel to don't forget to delete the operation when we exit early.
   nsAutoPtr<DOMStorageDBThread::DBOperation> opScope(aOperation);
 
+  if (NS_FAILED(mStatus)) {
+    MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
+    aOperation->Finalize(mStatus);
+    return mStatus;
+  }
+
   if (mStopIOThread) {
     // Thread use after shutdown demanded.
     MOZ_ASSERT(false);
     return NS_ERROR_NOT_INITIALIZED;
   }
 
-  if (NS_FAILED(mStatus)) {
-    MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
-    aOperation->Finalize(mStatus);
-    return mStatus;
-  }
-
   switch (aOperation->Type()) {
   case DBOperation::opPreload:
   case DBOperation::opPreloadUrgent:
     if (mPendingTasks.IsScopeUpdatePending(aOperation->Scope())) {
       // If there is a pending update operation for the scope first do the flush
       // before we preload the cache.  This may happen in an extremely rare case
       // when a child process throws away its cache before flush on the parent
       // has finished.  If we would preloaded the cache as a priority operation 
--- a/dom/webidl/RTCConfiguration.webidl
+++ b/dom/webidl/RTCConfiguration.webidl
@@ -9,20 +9,27 @@
 
 dictionary RTCIceServer {
     (DOMString or sequence<DOMString>) urls;
     DOMString  url; //deprecated
     DOMString? credential = null;
     DOMString? username = null;
 };
 
+enum RTCIceTransportPolicy {
+    "none",
+    "relay",
+    "all"
+};
+
 enum RTCBundlePolicy {
     "balanced",
     "max-compat",
     "max-bundle"
 };
 
 dictionary RTCConfiguration {
     sequence<RTCIceServer> iceServers;
+    RTCIceTransportPolicy  iceTransportPolicy = "all";
     RTCBundlePolicy bundlePolicy = "balanced";
     DOMString? peerIdentity = null;
     sequence<RTCCertificate> certificates;
 };
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -6,16 +6,17 @@ support-files =
   cookieprompt.js
   cookieprompt.manifest
 
 [test_bug526789.js]
 [test_bug650522.js]
 [test_bug667087.js]
 [test_cookies_async_failure.js]
 [test_cookies_persistence.js]
+skip-if = true # Bug 863738
 [test_cookies_privatebrowsing.js]
 [test_cookies_profile_close.js]
 [test_cookies_read.js]
 [test_cookies_sync_failure.js]
 [test_cookies_thirdparty.js]
 [test_cookies_thirdparty_session.js]
 [test_domain_eviction.js]
 [test_eviction.js]
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -1055,51 +1055,52 @@ gfxPlatformFontList::SizeOfFontFamilyTab
         // We don't count the size of the family here, because this is an
         // *extra* reference to a family that will have already been counted in
         // the main list.
         n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     }
     return n;
 }
 
+/*static*/ size_t
+gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
+    const FontEntryTable& aTable,
+    MallocSizeOf aMallocSizeOf)
+{
+    size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
+    for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
+        // The font itself is counted by its owning family; here we only care
+        // about the names stored in the hashtable keys.
+        n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    }
+    return n;
+}
+
 void
 gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                             FontListSizes* aSizes) const
 {
     aSizes->mFontListSize +=
         mFontFamilies.ShallowSizeOfExcludingThis(aMallocSizeOf);
     for (auto iter = mFontFamilies.ConstIter(); !iter.Done(); iter.Next()) {
         aSizes->mFontListSize +=
             iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
         iter.Data()->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
     }
 
     aSizes->mFontListSize +=
         SizeOfFontFamilyTableExcludingThis(mOtherFamilyNames, aMallocSizeOf);
 
     if (mExtraNames) {
-        // For these two tables, the font itself is counted by its owning
-        // family; here we only care about the names stored in the hashtable
-        // keys.
         aSizes->mFontListSize +=
-            mExtraNames->mFullnames.ShallowSizeOfExcludingThis(aMallocSizeOf);
-        for (auto iter = mExtraNames->mFullnames.ConstIter();
-             !iter.Done();
-             iter.Next()) {
-            aSizes->mFontListSize +=
-                iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-        }
+            SizeOfFontEntryTableExcludingThis(mExtraNames->mFullnames,
+                                              aMallocSizeOf);
         aSizes->mFontListSize +=
-            mExtraNames->mPostscriptNames.ShallowSizeOfExcludingThis(aMallocSizeOf);
-        for (auto iter = mExtraNames->mPostscriptNames.ConstIter();
-             !iter.Done();
-             iter.Next()) {
-            aSizes->mFontListSize +=
-                iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-        }
+            SizeOfFontEntryTableExcludingThis(mExtraNames->mPostscriptNames,
+                                              aMallocSizeOf);
     }
 
     aSizes->mFontListSize +=
         mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
     aSizes->mFontListSize +=
         mFontFamiliesToLoad.ShallowSizeOfExcludingThis(aMallocSizeOf);
 
     aSizes->mFontListSize +=
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -297,21 +297,25 @@ protected:
     void GetPrefsAndStartLoader();
 
     // for font list changes that affect all documents
     void ForceGlobalReflow();
 
     void RebuildLocalFonts();
 
     typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontFamilyTable;
+    typedef nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> FontEntryTable;
 
     // used by memory reporter to accumulate sizes of family names in the table
     static size_t
     SizeOfFontFamilyTableExcludingThis(const FontFamilyTable& aTable,
                                        mozilla::MallocSizeOf aMallocSizeOf);
+    static size_t
+    SizeOfFontEntryTableExcludingThis(const FontEntryTable& aTable,
+                                      mozilla::MallocSizeOf aMallocSizeOf);
 
     // canonical family name ==> family entry (unique, one name per family entry)
     FontFamilyTable mFontFamilies;
 
 #if defined(XP_MACOSX)
     // hidden system fonts used within UI elements
     FontFamilyTable mSystemFontFamilies;
 #endif
@@ -323,20 +327,21 @@ protected:
     // flag set after InitOtherFamilyNames is called upon first name lookup miss
     bool mOtherFamilyNamesInitialized;
 
     // flag set after fullname and Postcript name lists are populated
     bool mFaceNameListsInitialized;
 
     struct ExtraNames {
       ExtraNames() : mFullnames(64), mPostscriptNames(64) {}
+
       // fullname ==> font entry (unique, one name per font entry)
-      nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> mFullnames;
+      FontEntryTable mFullnames;
       // Postscript name ==> font entry (unique, one name per font entry)
-      nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> mPostscriptNames;
+      FontEntryTable mPostscriptNames;
     };
     nsAutoPtr<ExtraNames> mExtraNames;
 
     // face names missed when face name loading takes a long time
     nsAutoPtr<nsTHashtable<nsStringHashKey> > mFaceNamesMissed;
 
     // localized family names missed when face name loading takes a long time
     nsAutoPtr<nsTHashtable<nsStringHashKey> > mOtherNamesMissed;
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1413,16 +1413,17 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
         if (skipSides.Bottom()) {
           nscoord ymost = fragmentClip.YMost();
           nscoord overflow = ymost - aFrameArea.YMost();
           if (overflow > 0) {
             fragmentClip.height -= overflow;
           }
         }
       }
+      fragmentClip = fragmentClip.Intersect(aDirtyRect);
       renderContext->
         Clip(NSRectToSnappedRect(fragmentClip,
                                  aForFrame->PresContext()->AppUnitsPerDevPixel(),
                                  aDrawTarget));
 
       RectCornerRadii clipRectRadii;
       if (hasBorderRadius) {
         Float spreadDistance = shadowItem->mSpread / twipsPerPixel;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-shadow/1178575-2-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcase #2 for bug 1178575</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:16px; padding:0; margin:20px;
+        }
+
+        div {
+            position: absolute;
+            left: 0;
+            right: 0;
+            box-shadow: 0 0 0 10px rgba(0, 255, 0, 0.5);
+            margin-top: 10px;
+            height: 40px;
+        }
+
+        span {
+          position: relative;
+          display: block;
+          overflow: hidden;
+          height: 100px;
+        }
+
+    </style>
+</head>
+<body><span><div></div><span></body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-shadow/1178575-2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+    <meta charset="utf-8">
+    <title>Testcase #2 for bug 1178575</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:16px; padding:0; margin:20px;
+        }
+
+        div {
+            position: absolute;
+            left: 0;
+            right: 0;
+            box-shadow: 0 0 0 10px rgba(0, 255, 0, 0.5);
+            margin-top: 10px;
+        }
+
+        span {
+          position: relative;
+          display: block;
+          overflow: hidden;
+          height: 200px;
+        }
+
+    </style>
+<script>
+function tweak() {
+  document.querySelector('div').style.height = "40px";
+  document.documentElement.removeAttribute("class");
+}
+window.addEventListener("MozReftestInvalidate", tweak, false);
+</script>
+</head>
+<body><span><div></div><span></body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-shadow/1178575-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 1178575</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:16px; padding:0; margin:0;
+        }
+
+        div {
+            position: absolute;
+            left: 0;
+            right: 0;
+            box-shadow: 0 0 0 10px rgba(0, 255, 0, 0.5);
+            margin-top: 10px;
+            height: 3em;
+        }
+
+    </style>
+</head>
+<body><div></div></body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-shadow/1178575.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 1178575</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:16px; padding:0; margin:0;
+        }
+
+        div {
+            position: absolute;
+            left: 0;
+            right: 0;
+            box-shadow: 0 0 0 10px rgba(0, 255, 0, 0.5);
+            margin-top: 10px;
+        }
+
+    </style>
+<script>
+function tweak() {
+  document.querySelector('div').style.height = "3em";
+  document.documentElement.removeAttribute("class");
+}
+window.addEventListener("MozReftestInvalidate", tweak, false);
+</script>
+</head>
+<body><div></div></body></html>
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -24,8 +24,10 @@ random-if(d2d) == boxshadow-threecorners
 
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
 == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
 fails-if(B2G||Mulet) == 611574-1.html 611574-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fails-if(B2G||Mulet) == 611574-2.html 611574-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(winWidget,5,30) == fieldset.html fieldset-ref.html # minor anti-aliasing problem on Windows
 fuzzy-if(winWidget,5,30) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows
+== 1178575.html 1178575-ref.html
+== 1178575-2.html 1178575-2-ref.html
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -376,19 +376,20 @@ void NrIceCtx::trickle_cb(void *arg, nr_
   s->SignalCandidate(s, candidate_str);
 }
 
 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
                                   bool offerer,
                                   bool set_interface_priorities,
                                   bool allow_loopback,
                                   bool tcp_enabled,
-                                  bool allow_link_local) {
+                                  bool allow_link_local,
+                                  Policy policy) {
 
-  RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
+  RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer, policy);
 
   // Initialize the crypto callbacks and logging stuff
   if (!initialized) {
     NR_reg_init(NR_REG_MODE_LOCAL);
     RLogRingBuffer::CreateInstance();
     nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
     initialized = true;
 
@@ -480,16 +481,19 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
   }
 
   // Create the ICE context
   int r;
 
   UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
       NR_ICE_CTX_FLAGS_ANSWERER;
   flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
+  if (policy == ICE_POLICY_RELAY) {
+    flags |= NR_ICE_CTX_FLAGS_RELAY_ONLY;
+  }
 
   r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags,
                         &ctx->ctx_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name << "'");
     return nullptr;
   }
 
@@ -604,16 +608,21 @@ nsresult NrIceCtx::SetControlling(Contro
             controlling);
   return NS_OK;
 }
 
 NrIceCtx::Controlling NrIceCtx::GetControlling() {
   return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
 }
 
+nsresult NrIceCtx::SetPolicy(Policy policy) {
+  policy_ = policy;
+  return NS_OK;
+}
+
 nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>&
                                   stun_servers) {
   if (stun_servers.empty())
     return NS_OK;
 
   auto servers = MakeUnique<nr_ice_stun_server[]>(stun_servers.size());
 
   for (size_t i=0; i < stun_servers.size(); ++i) {
@@ -709,16 +718,19 @@ abort:
     nr_socket_wrapper_factory_destroy(&wrapper);
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult NrIceCtx::StartGathering() {
   ASSERT_ON_THREAD(sts_target_);
+  if (policy_ == ICE_POLICY_NONE) {
+    return NS_OK;
+  }
   SetGatheringState(ICE_CTX_GATHER_STARTED);
   // This might start gathering for the first time, or again after
   // renegotiation, or might do nothing at all if gathering has already
   // finished.
   int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this);
 
   if (!r) {
     SetGatheringState(ICE_CTX_GATHER_COMPLETE);
@@ -783,16 +795,21 @@ nsresult NrIceCtx::ParseGlobalAttributes
   }
 
   return NS_OK;
 }
 
 nsresult NrIceCtx::StartChecks() {
   int r;
 
+  if (policy_ == ICE_POLICY_NONE) {
+    MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks because policy == none");
+    SetConnectionState(ICE_CTX_FAILED);
+    return NS_ERROR_FAILURE;
+  }
   r=nr_ice_peer_ctx_pair_candidates(peer_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on "
               << name_ << "'");
     SetConnectionState(ICE_CTX_FAILED);
     return NS_ERROR_FAILURE;
   }
 
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -203,22 +203,28 @@ class NrIceCtx {
                         ICE_CTX_GATHER_STARTED,
                         ICE_CTX_GATHER_COMPLETE
   };
 
   enum Controlling { ICE_CONTROLLING,
                      ICE_CONTROLLED
   };
 
+  enum Policy { ICE_POLICY_NONE,
+                ICE_POLICY_RELAY,
+                ICE_POLICY_ALL
+  };
+
   static RefPtr<NrIceCtx> Create(const std::string& name,
                                  bool offerer,
                                  bool set_interface_priorities = true,
                                  bool allow_loopback = false,
                                  bool tcp_enabled = true,
-                                 bool allow_link_local = false);
+                                 bool allow_link_local = false,
+                                 Policy policy = ICE_POLICY_ALL);
 
   // Deinitialize all ICE global state. Used only for testing.
   static void internal_DeinitializeGlobal();
 
 
   nr_ice_ctx *ctx() { return ctx_; }
   nr_ice_peer_ctx *peer() { return peer_; }
 
@@ -267,16 +273,24 @@ class NrIceCtx {
   // Set the other side's global attributes
   nsresult ParseGlobalAttributes(std::vector<std::string> attrs);
 
   // Set whether we are controlling or not.
   nsresult SetControlling(Controlling controlling);
 
   Controlling GetControlling();
 
+  // Set whether we're allowed to produce none, relay or all candidates.
+  // TODO(jib@mozilla.com): Work out what change means mid-connection (1181768)
+  nsresult SetPolicy(Policy policy);
+
+  Policy policy() const {
+    return policy_;
+  }
+
   // Set the STUN servers. Must be called before StartGathering
   // (if at all).
   nsresult SetStunServers(const std::vector<NrIceStunServer>& stun_servers);
 
   // Set the TURN servers. Must be called before StartGathering
   // (if at all).
   nsresult SetTurnServers(const std::vector<NrIceTurnServer>& turn_servers);
 
@@ -310,27 +324,29 @@ class NrIceCtx {
 
   // The thread to direct method calls to
   nsCOMPtr<nsIEventTarget> thread() { return sts_target_; }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx)
 
  private:
   NrIceCtx(const std::string& name,
-           bool offerer)
+           bool offerer,
+           Policy policy)
   : connection_state_(ICE_CTX_INIT),
     gathering_state_(ICE_CTX_GATHER_INIT),
     name_(name),
     offerer_(offerer),
     streams_(),
     ctx_(nullptr),
     peer_(nullptr),
     ice_handler_vtbl_(nullptr),
     ice_handler_(nullptr),
-    trickle_(true) {
+    trickle_(true),
+    policy_(policy) {
     // XXX: offerer_ will be used eventually;  placate clang in the meantime.
     (void)offerer_;
   }
 
   virtual ~NrIceCtx();
 
   DISALLOW_COPY_ASSIGN(NrIceCtx);
 
@@ -366,13 +382,14 @@ class NrIceCtx {
   bool offerer_;
   std::vector<RefPtr<NrIceMediaStream> > streams_;
   nr_ice_ctx *ctx_;
   nr_ice_peer_ctx *peer_;
   nr_ice_handler_vtbl* ice_handler_vtbl_;  // Must be pointer
   nr_ice_handler* ice_handler_;  // Must be pointer
   bool trickle_;
   nsCOMPtr<nsIEventTarget> sts_target_; // The thread to run on
+  Policy policy_;
 };
 
 
 }  // close namespace
 #endif
--- a/media/mtransport/test/turn_unittest.cpp
+++ b/media/mtransport/test/turn_unittest.cpp
@@ -499,17 +499,18 @@ int main(int argc, char **argv)
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   // Set up the ICE registry, etc.
   // TODO(ekr@rtfm.com): Clean up
   std::string dummy("dummy");
   RUN_ON_THREAD(test_utils->sts_target(),
                 WrapRunnableNM(&NrIceCtx::Create,
-                               dummy, false, false, false, false, false),
+                               dummy, false, false, false, false, false,
+                               NrIceCtx::ICE_POLICY_ALL),
                 NS_DISPATCH_SYNC);
 
   // Start the tests
   ::testing::InitGoogleTest(&argc, argv);
 
   int rv = RUN_ALL_TESTS();
   delete test_utils;
   return rv;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -129,16 +129,17 @@ static int nr_ice_candidate_format_stun_
 
     _status=0;
    abort:
     return(_status);
   }
 
 int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
   {
+    assert(!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) || ctype == RELAYED);
     nr_ice_candidate *cand=0;
     nr_ice_candidate *tmp=0;
     int r,_status;
     char label[512];
 
     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
       ABORT(R_NO_MEMORY);
     cand->state=NR_ICE_CAND_STATE_CREATED;
@@ -916,16 +917,17 @@ static void nr_ice_turn_allocated_cb(NR_
 
 /* Format the candidate attribute as per ICE S 15.1 */
 int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen)
   {
     int r,_status;
     char addr[64];
     int port;
     int len;
+    nr_transport_addr *raddr;
 
     assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
     assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
 
     if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
       ABORT(r);
     if(r=nr_transport_addr_get_port(&cand->addr,&port))
       ABORT(r);
@@ -934,33 +936,36 @@ int nr_ice_format_candidate_attribute(nr
       port=9;
     snprintf(attr,maxlen,"candidate:%s %d %s %u %s %d typ %s",
       cand->foundation, cand->component_id, cand->addr.protocol==IPPROTO_UDP?"UDP":"TCP",cand->priority, addr, port,
       nr_ctype_name(cand->type));
 
     len=strlen(attr); attr+=len; maxlen-=len;
 
     /* raddr, rport */
+    raddr = (cand->stream->ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) ?
+      &cand->addr : &cand->base;
+
     switch(cand->type){
       case HOST:
         break;
       case SERVER_REFLEXIVE:
       case PEER_REFLEXIVE:
-        if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
+        if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
           ABORT(r);
-        if(r=nr_transport_addr_get_port(&cand->base,&port))
+        if(r=nr_transport_addr_get_port(raddr,&port))
           ABORT(r);
 
         snprintf(attr,maxlen," raddr %s rport %d",addr,port);
         break;
       case RELAYED:
         // comes from XorMappedAddress via AllocateResponse
-        if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
+        if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
           ABORT(r);
-        if(r=nr_transport_addr_get_port(&cand->base,&port))
+        if(r=nr_transport_addr_get_port(raddr,&port))
           ABORT(r);
 
         snprintf(attr,maxlen," raddr %s rport %d",addr,port);
         break;
       default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
@@ -255,17 +255,22 @@ static void nr_ice_candidate_pair_stun_c
           while(cand){
             if(!nr_transport_addr_cmp(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
               break;
 
             cand=TAILQ_NEXT(cand,entry_comp);
           }
 
           /* OK, nothing found, must be peer reflexive */
-          if(!cand){
+          if(!cand) {
+            if (pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) {
+              /* Any STUN response with a reflexive address in it is unwanted
+                 when we'll send on relay only. Bail since cand is used below. */
+              goto done;
+            }
             if(r=nr_ice_candidate_create(pair->pctx->ctx,
               pair->local->component,pair->local->isock,pair->local->osock,
               PEER_REFLEXIVE,pair->local->tcp_type,0,pair->local->component->component_id,&cand))
               ABORT(r);
             if(r=nr_transport_addr_copy(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr))
               ABORT(r);
             cand->state=NR_ICE_CAND_STATE_INITIALIZED;
             TAILQ_INSERT_TAIL(&pair->local->component->candidates,cand,entry_comp);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -221,63 +221,69 @@ static int nr_ice_component_initialize_u
       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].addr.as_string);
       if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addrs[i].addr,&sock))){
         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].addr.as_string);
         continue;
       }
 
       if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM,&isock))
         ABORT(r);
-      /* Create one host candidate */
-      if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
-        component->component_id,&cand))
-        ABORT(r);
-
-      TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
-      component->candidate_ct++;
-      cand=0;
 
-      /* And a srvrflx candidate for each STUN server */
-      for(j=0;j<ctx->stun_server_ct;j++){
-        /* Skip non-UDP */
-        if(ctx->stun_servers[j].transport!=IPPROTO_UDP)
-          continue;
+      if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
+        /* Create one host candidate */
+        if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
+          component->component_id,&cand))
+          ABORT(r);
 
-        if(r=nr_ice_candidate_create(ctx,component,
-          isock,sock,SERVER_REFLEXIVE,0,
-          &ctx->stun_servers[j],component->component_id,&cand))
-          ABORT(r);
         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
         component->candidate_ct++;
         cand=0;
+
+        /* And a srvrflx candidate for each STUN server */
+        for(j=0;j<ctx->stun_server_ct;j++){
+          /* Skip non-UDP */
+          if(ctx->stun_servers[j].transport!=IPPROTO_UDP)
+            continue;
+
+          if(r=nr_ice_candidate_create(ctx,component,
+            isock,sock,SERVER_REFLEXIVE,0,
+            &ctx->stun_servers[j],component->component_id,&cand))
+            ABORT(r);
+          TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
+          component->candidate_ct++;
+          cand=0;
+        }
       }
 
 #ifdef USE_TURN
-      /* And both a srvrflx and relayed candidate for each TURN server */
+      /* And both a srvrflx and relayed candidate for each TURN server (unless
+         we're in relay-only mode, in which case just the relayed one) */
       for(j=0;j<ctx->turn_server_ct;j++){
         nr_socket *turn_sock;
-        nr_ice_candidate *srvflx_cand;
+        nr_ice_candidate *srvflx_cand=0;
 
         /* Skip non-UDP */
         if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP)
           continue;
 
-        /* srvrflx */
-        if(r=nr_ice_candidate_create(ctx,component,
-          isock,sock,SERVER_REFLEXIVE,0,
-          &ctx->turn_servers[j].turn_server,component->component_id,&cand))
-          ABORT(r);
-        cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
-        cand->done_cb=nr_ice_gather_finished_cb;
-        cand->cb_arg=cand;
+        if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
+          /* srvrflx */
+          if(r=nr_ice_candidate_create(ctx,component,
+            isock,sock,SERVER_REFLEXIVE,0,
+            &ctx->turn_servers[j].turn_server,component->component_id,&cand))
+            ABORT(r);
+          cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
+          cand->done_cb=nr_ice_gather_finished_cb;
+          cand->cb_arg=cand;
 
-        TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
-        component->candidate_ct++;
-        srvflx_cand=cand;
-
+          TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
+          component->candidate_ct++;
+          srvflx_cand=cand;
+          cand=0;
+        }
         /* relayed*/
         if(r=nr_socket_turn_create(sock, &turn_sock))
           ABORT(r);
         if(r=nr_ice_candidate_create(ctx,component,
           isock,turn_sock,RELAYED,0,
           &ctx->turn_servers[j].turn_server,component->component_id,&cand))
            ABORT(r);
         cand->u.relayed.srvflx_candidate=srvflx_cand;
@@ -403,16 +409,19 @@ static int nr_ice_component_initialize_t
       if(r!=R_NOT_FOUND)
         ABORT(r);
     }
 
     if ((r=NR_reg_get_char(NR_ICE_REG_ICE_TCP_DISABLE, &ice_tcp_disabled))) {
       if (r != R_NOT_FOUND)
         ABORT(r);
     }
+    if (ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) {
+      ice_tcp_disabled = 1;
+    }
 
     for(i=0;i<addr_ct;i++){
       char suppress;
       nr_ice_socket *isock_psv=0;
       nr_ice_socket *isock_so=0;
 
       if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
         if(r!=R_NOT_FOUND)
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
@@ -152,16 +152,17 @@ struct nr_ice_ctx_ {
   void *trickle_cb_arg;
 };
 
 int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp);
 #define NR_ICE_CTX_FLAGS_OFFERER                           1
 #define NR_ICE_CTX_FLAGS_ANSWERER                          (1<<1)
 #define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION             (1<<2)
 #define NR_ICE_CTX_FLAGS_LITE                              (1<<3)
+#define NR_ICE_CTX_FLAGS_RELAY_ONLY                        (1<<4)
 
 int nr_ice_ctx_destroy(nr_ice_ctx **ctxp);
 int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);
 int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand);
 void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg);
 int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp);
 int nr_ice_remove_media_stream(nr_ice_ctx *ctx,nr_ice_media_stream **streamp);
 int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -517,16 +517,30 @@ PeerConnectionConfiguration::Init(const 
       setBundlePolicy(kBundleMaxCompat);
       break;
     case dom::RTCBundlePolicy::Max_bundle:
       setBundlePolicy(kBundleMaxBundle);
       break;
     default:
       MOZ_CRASH();
   }
+
+  switch (aSrc.mIceTransportPolicy) {
+    case dom::RTCIceTransportPolicy::None:
+      setIceTransportPolicy(NrIceCtx::ICE_POLICY_NONE);
+      break;
+    case dom::RTCIceTransportPolicy::Relay:
+      setIceTransportPolicy(NrIceCtx::ICE_POLICY_RELAY);
+      break;
+    case dom::RTCIceTransportPolicy::All:
+      setIceTransportPolicy(NrIceCtx::ICE_POLICY_ALL);
+      break;
+    default:
+      MOZ_CRASH();
+  }
   return NS_OK;
 }
 
 nsresult
 PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
 {
   NS_ENSURE_STATE(aServer.mUrls.WasPassed());
   NS_ENSURE_STATE(aServer.mUrls.Value().IsStringSequence());
@@ -733,17 +747,18 @@ PeerConnectionImpl::Initialize(PeerConne
   mMedia->SignalIceConnectionStateChange.connect(
       this,
       &PeerConnectionImpl::IceConnectionStateChange);
 
   mMedia->SignalCandidate.connect(this, &PeerConnectionImpl::CandidateReady);
 
   // Initialize the media object.
   res = mMedia->Init(aConfiguration.getStunServers(),
-                     aConfiguration.getTurnServers());
+                     aConfiguration.getTurnServers(),
+                     aConfiguration.getIceTransportPolicy());
   if (NS_FAILED(res)) {
     CSFLogError(logTag, "%s: Couldn't initialize media object", __FUNCTION__);
     return res;
   }
 
   PeerConnectionCtx::GetInstance()->mPeerConnections[mHandle] = this;
 
   mJsepSession = MakeUnique<JsepSessionImpl>(mName,
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -144,17 +144,19 @@ class PCUuidGenerator : public mozilla::
 
  private:
   nsCOMPtr<nsIUUIDGenerator> mGenerator;
 };
 
 class PeerConnectionConfiguration
 {
 public:
-  PeerConnectionConfiguration() : mBundlePolicy(kBundleBalanced) {}
+  PeerConnectionConfiguration()
+  : mBundlePolicy(kBundleBalanced),
+    mIceTransportPolicy(NrIceCtx::ICE_POLICY_ALL) {}
 
   bool addStunServer(const std::string& addr, uint16_t port,
                      const char* transport)
   {
     NrIceStunServer* server(NrIceStunServer::Create(addr, port, transport));
     if (!server) {
       return false;
     }
@@ -181,26 +183,29 @@ public:
     return true;
   }
   void addStunServer(const NrIceStunServer& server) { mStunServers.push_back (server); }
   void addTurnServer(const NrIceTurnServer& server) { mTurnServers.push_back (server); }
   const std::vector<NrIceStunServer>& getStunServers() const { return mStunServers; }
   const std::vector<NrIceTurnServer>& getTurnServers() const { return mTurnServers; }
   void setBundlePolicy(JsepBundlePolicy policy) { mBundlePolicy = policy;}
   JsepBundlePolicy getBundlePolicy() const { return mBundlePolicy; }
+  void setIceTransportPolicy(NrIceCtx::Policy policy) { mIceTransportPolicy = policy;}
+  NrIceCtx::Policy getIceTransportPolicy() const { return mIceTransportPolicy; }
 
 #ifndef MOZILLA_EXTERNAL_LINKAGE
   nsresult Init(const RTCConfiguration& aSrc);
   nsresult AddIceServer(const RTCIceServer& aServer);
 #endif
 
 private:
   std::vector<NrIceStunServer> mStunServers;
   std::vector<NrIceTurnServer> mTurnServers;
   JsepBundlePolicy mBundlePolicy;
+  NrIceCtx::Policy mIceTransportPolicy;
 };
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
 // Not an inner class so we can forward declare.
 class RTCStatsQuery {
   public:
     explicit RTCStatsQuery(bool internalStats);
     ~RTCStatsQuery();
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -225,17 +225,18 @@ PeerConnectionMedia::PeerConnectionMedia
       mDNSResolver(new NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
       mProxyResolveCompleted(false) {
 }
 
 nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
-                                   const std::vector<NrIceTurnServer>& turn_servers)
+                                   const std::vector<NrIceTurnServer>& turn_servers,
+                                   NrIceCtx::Policy policy)
 {
   nsresult rv;
 #if defined(MOZILLA_XPCOMRT_API)
   // TODO(Bug 1126039) Standalone XPCOMRT does not currently support nsIProtocolProxyService or nsIIOService
   mProxyResolveCompleted = true;
 #else
 
   nsCOMPtr<nsIProtocolProxyService> pps =
@@ -309,17 +310,18 @@ nsresult PeerConnectionMedia::Init(const
 
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
   mIceCtx = NrIceCtx::Create("PC:" + mParentName,
                              true, // Offerer
                              true, // Explicitly set priorities
                              mParent->GetAllowIceLoopback(),
                              ice_tcp,
-                             mParent->GetAllowIceLinkLocal());
+                             mParent->GetAllowIceLinkLocal(),
+                             policy);
   if(!mIceCtx) {
     CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
     CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
     return rv;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -223,17 +223,18 @@ class RemoteSourceStreamInfo : public So
 class PeerConnectionMedia : public sigslot::has_slots<> {
   ~PeerConnectionMedia() {}
 
  public:
   explicit PeerConnectionMedia(PeerConnectionImpl *parent);
 
   PeerConnectionImpl* GetPC() { return mParent; }
   nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
-                const std::vector<NrIceTurnServer>& turn_servers);
+                const std::vector<NrIceTurnServer>& turn_servers,
+                NrIceCtx::Policy policy);
   // WARNING: This destroys the object!
   void SelfDestruct();
 
   RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
 
   RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const {
     return mIceCtx->GetStream(i);
   }
--- a/memory/mozjemalloc/jemalloc.c
+++ b/memory/mozjemalloc/jemalloc.c
@@ -6777,17 +6777,17 @@ void*
 	/*
 	 * In order for all trailing bytes to be zeroed, the caller needs to
 	 * use calloc(), followed by recalloc().  However, the current calloc()
 	 * implementation only zeros the bytes requested, so if recalloc() is
 	 * to work 100% correctly, calloc() will need to change to zero
 	 * trailing bytes.
 	 */
 
-	ptr = realloc(ptr, newsize);
+	ptr = realloc_impl(ptr, newsize);
 	if (ptr != NULL && oldsize < newsize) {
 		memset((void *)((uintptr_t)ptr + oldsize), 0, newsize -
 		    oldsize);
 	}
 
 	return ptr;
 }
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -393,16 +393,17 @@ pref("media.peerconnection.video.min_bit
 pref("media.peerconnection.video.start_bitrate", 300);
 pref("media.peerconnection.video.max_bitrate", 2000);
 #endif
 pref("media.navigator.permission.disabled", false);
 pref("media.peerconnection.default_iceservers", "[]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.ice.tcp", false);
 pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses
+pref("media.peerconnection.ice.relay_only", false); // Limit candidates to TURN
 pref("media.peerconnection.use_document_iceservers", true);
 pref("media.peerconnection.identity.enabled", true);
 pref("media.peerconnection.identity.timeout", 10000);
 pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
 pref("media.peerconnection.ice.trickle_grace_period", 5000);
 // These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
 // kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
 // setting (for Xxx = Ec, Agc, or Ns).  Defaults are all set to kXxxDefault here.
@@ -471,27 +472,23 @@ pref("media.track.enabled", false);
 pref("media.mediasource.enabled", true);
 #else
 pref("media.mediasource.enabled", false);
 #endif
 
 pref("media.mediasource.mp4.enabled", true);
 pref("media.mediasource.webm.enabled", false);
 
-#if defined(MOZ_WIDGET_GONK)
-pref("media.mediasource.format-reader", false);
-#else
 // Enable new MediaSource architecture.
 pref("media.mediasource.format-reader", true);
-#endif
 
 // Enable new MediaFormatReader architecture for webm in MSE
 pref("media.mediasource.format-reader.webm", false);
 // Enable new MediaFormatReader architecture for plain webm.
-pref("media.format-reader.webm", false);
+pref("media.format-reader.webm", true);
 
 #ifdef MOZ_WEBSPEECH
 pref("media.webspeech.recognition.enable", false);
 pref("media.webspeech.synth.enabled", false);
 #endif
 #ifdef MOZ_WEBM_ENCODER
 pref("media.encoder.webm.enabled", true);
 #endif
--- a/security/certverifier/ExtendedValidation.cpp
+++ b/security/certverifier/ExtendedValidation.cpp
@@ -536,29 +536,16 @@ static struct nsMyTrustedEVInfo myTruste
       0x86, 0x5B, 0xDF, 0x1C, 0xD4, 0x10, 0x2E, 0x7D, 0x07, 0x59, 0xAF,
       0x63, 0x5A, 0x7C, 0xF4, 0x72, 0x0D, 0xC9, 0x63, 0xC5, 0x3B },
     "MEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFIzMRMwEQYDVQQKEwpH"
     "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu",
     "BAAAAAABIVhTCKI=",
     nullptr
   },
   {
-    // CN=Buypass Class 3 CA 1,O=Buypass AS-983163327,C=NO
-    "2.16.578.1.26.1.3.3",
-    "Buypass EV OID",
-    SEC_OID_UNKNOWN,
-    { 0xB7, 0xB1, 0x2B, 0x17, 0x1F, 0x82, 0x1D, 0xAA, 0x99, 0x0C, 0xD0,
-      0xFE, 0x50, 0x87, 0xB1, 0x28, 0x44, 0x8B, 0xA8, 0xE5, 0x18, 0x4F,
-      0x84, 0xC5, 0x1E, 0x02, 0xB5, 0xC8, 0xFB, 0x96, 0x2B, 0x24 },
-    "MEsxCzAJBgNVBAYTAk5PMR0wGwYDVQQKDBRCdXlwYXNzIEFTLTk4MzE2MzMyNzEd"
-    "MBsGA1UEAwwUQnV5cGFzcyBDbGFzcyAzIENBIDE=",
-    "Ag==",
-    nullptr
-  },
-  {
     // CN=Buypass Class 3 Root CA,O=Buypass AS-983163327,C=NO
     "2.16.578.1.26.1.3.3",
     "Buypass EV OID",
     SEC_OID_UNKNOWN,
     { 0xED, 0xF7, 0xEB, 0xBC, 0xA2, 0x7A, 0x2A, 0x38, 0x4D, 0x38, 0x7B,
       0x7D, 0x40, 0x10, 0xC6, 0x66, 0xE2, 0xED, 0xB4, 0x84, 0x3E, 0x4C,
       0x29, 0xB4, 0xAE, 0x1D, 0x5B, 0x93, 0x32, 0xE6, 0xB2, 0x4D },
     "ME4xCzAJBgNVBAYTAk5PMR0wGwYDVQQKDBRCdXlwYXNzIEFTLTk4MzE2MzMyNzEg"
@@ -1246,27 +1233,28 @@ IdentityInfoInit()
 
     entry.cert = CERT_FindCertByIssuerAndSN(nullptr, &ias);
 
     SECITEM_FreeItem(&ias.derIssuer, false);
     SECITEM_FreeItem(&ias.serialNumber, false);
 
     // If an entry is missing in the NSS root database, it may be because the
     // root database is out of sync with what we expect (e.g. a different
-    // version of system NSS is installed). We will just silently avoid
-    // treating that root cert as EV.
+    // version of system NSS is installed). We assert on debug builds, but
+    // silently continue on release builds. In both cases, the root cert does
+    // not get EV treatment.
     if (!entry.cert) {
 #ifdef DEBUG
       // The debug CA structs are at positions 0 to NUM_TEST_EV_ROOTS - 1, and
       // are NOT in the NSS root DB.
       if (iEV < NUM_TEST_EV_ROOTS) {
         continue;
       }
 #endif
-      //PR_NOT_REACHED("Could not find EV root in NSS storage");
+      PR_NOT_REACHED("Could not find EV root in NSS storage");
       continue;
     }
 
     unsigned char certFingerprint[SHA256_LENGTH];
     rv = PK11_HashBuf(SEC_OID_SHA256, certFingerprint,
                       entry.cert->derCert.data,
                       static_cast<int32_t>(entry.cert->derCert.len));
     PR_ASSERT(rv == SECSuccess);
--- a/testing/mozharness/mozharness/mozilla/buildbot.py
+++ b/testing/mozharness/mozharness/mozilla/buildbot.py
@@ -176,8 +176,42 @@ class BuildbotMixin(object):
             ]
 
         for d in downloadables:
             sendchange += [d]
 
         retcode = self.run_command(buildbot + sendchange)
         if retcode != 0:
             self.info("The sendchange failed but we don't want to turn the build orange: %s" % retcode)
+
+    def query_build_name(self):
+        build_name = self.config.get('platform')
+        if not build_name:
+            self.fatal('Must specify "platform" in the mozharness config for indexing')
+
+        return build_name
+
+    def query_build_type(self):
+        if self.config.get('build_type'):
+            build_type = self.config['build_type']
+        elif self.config.get('pgo_build'):
+            build_type = 'pgo'
+        elif self.config.get('debug_build', False):
+            build_type = 'debug'
+        else:
+            build_type = 'opt'
+        return build_type
+
+    def buildid_to_dict(self, buildid):
+        """Returns an dict with the year, month, day, hour, minute, and second
+           as keys, as parsed from the buildid"""
+        buildidDict = {}
+        try:
+            # strptime is no good here because it strips leading zeros
+            buildidDict['year'] = buildid[0:4]
+            buildidDict['month'] = buildid[4:6]
+            buildidDict['day'] = buildid[6:8]
+            buildidDict['hour'] = buildid[8:10]
+            buildidDict['minute'] = buildid[10:12]
+            buildidDict['second'] = buildid[12:14]
+        except:
+            self.fatal('Could not parse buildid into YYYYMMDDHHMMSS: %s' % buildid)
+        return buildidDict
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1365,16 +1365,17 @@ or run without that action (ie: --no-{ac
                 self.return_code = self.worst_level(
                     EXIT_STATUS_DICT[TBPL_WARNING], self.return_code,
                     AUTOMATION_EXIT_CODES[::-1]
                 )
 
         self.generated_build_props = True
 
     def upload_files(self):
+        dirs = self.query_abs_dirs()
         auth = os.path.join(os.getcwd(), self.config['taskcluster_credentials_file'])
         credentials = {}
         execfile(auth, credentials)
         client_id = credentials.get('taskcluster_clientId')
         access_token = credentials.get('taskcluster_accessToken')
         if not client_id or not access_token:
             self.warning('Skipping S3 file upload: No taskcluster credentials.')
             return
@@ -1386,29 +1387,57 @@ or run without that action (ie: --no-{ac
         # which is necessary before the virtualenv can be created.
         self.create_virtualenv()
         self.activate_virtualenv()
 
         # Enable Taskcluster debug logging, so at least we get some debug
         # messages while we are testing uploads.
         logging.getLogger('taskcluster').setLevel(logging.DEBUG)
 
+        routes_json = os.path.join(dirs['abs_src_dir'],
+                                   'testing/taskcluster/routes.json')
+        with open(routes_json) as f:
+            contents = json.load(f)
+            if self.query_is_nightly():
+                templates = contents['nightly']
+
+                # Nightly builds with l10n counterparts also publish to the
+                # 'en-US' locale.
+                if self.config.get('publish_nightly_en_US_routes'):
+                    templates.extend(contents['l10n'])
+            else:
+                templates = contents['routes']
+        routes = []
+        for template in templates:
+            fmt = {
+                'index': 'index.garbage.staging.mshal-testing', # TODO
+                'project': self.buildbot_config['properties']['branch'],
+                'head_rev': self.query_revision(),
+                'build_product': self.config['stage_product'],
+                'build_name': self.query_build_name(),
+                'build_type': self.query_build_type(),
+                'locale': 'en-US',
+            }
+            fmt.update(self.buildid_to_dict(self.query_buildid()))
+            routes.append(template.format(**fmt))
+        self.info("Using routes: %s" % routes)
+
         tc = Taskcluster(self.branch,
                          self.query_pushdate(), # Use pushdate as the rank
                          client_id,
                          access_token,
                          self.log_obj,
                          )
 
         index = self.config.get('taskcluster_index', 'index.garbage.staging')
         # TODO: Bug 1165980 - these should be in tree
-        routes = [
+        routes.extend([
             "%s.buildbot.branches.%s.%s" % (index, self.branch, self.stage_platform),
             "%s.buildbot.revisions.%s.%s.%s" % (index, self.query_revision(), self.branch, self.stage_platform),
-        ]
+        ])
         task = tc.create_task(routes)
         tc.claim_task(task)
 
         # Some trees may not be setting uploadFiles, so default to []. Normally
         # we'd only expect to get here if the build completes successfully,
         # which means we should have uploadFiles.
         files = self.query_buildbot_property('uploadFiles') or []
         if not files:
@@ -1468,17 +1497,16 @@ or run without that action (ie: --no-{ac
             '.zip',
             '.json',
         )
 
         # Also upload our mozharness log files
         files.extend([os.path.join(self.log_obj.abs_log_dir, x) for x in self.log_obj.log_files.values()])
 
         # Also upload our buildprops.json file.
-        dirs = self.query_abs_dirs()
         files.extend([os.path.join(dirs['base_work_dir'], 'buildprops.json')])
 
         for upload_file in files:
             # Create an S3 artifact for each file that gets uploaded. We also
             # check the uploaded file against the property conditions so that we
             # can set the buildbot config with the correct URLs for package
             # locations.
             tc.create_artifact(task, upload_file)
--- a/testing/mozharness/scripts/desktop_l10n.py
+++ b/testing/mozharness/scripts/desktop_l10n.py
@@ -201,20 +201,18 @@ class DesktopSingleLocale(LocalesMixin, 
         self.upload_env = None
         self.revision = None
         self.version = None
         self.upload_urls = {}
         self.locales_property = {}
         self.l10n_dir = None
         self.package_urls = {}
         self.pushdate = None
-        # Each locale adds its list of files to upload_files - some will be
-        # duplicates (like the mar binaries), so we use a set to prune those
-        # when uploading to taskcluster.
-        self.upload_files = set()
+        # upload_files is a dictionary of files to upload, keyed by locale.
+        self.upload_files = {}
 
         if 'mock_target' in self.config:
             self.enable_mock()
 
     def _pre_config_lock(self, rw_config):
         """replaces 'configuration_tokens' with their values, before the
            configuration gets locked. If some of the configuration_tokens
            are not present, stops the execution of the script"""
@@ -744,19 +742,19 @@ class DesktopSingleLocale(LocalesMixin, 
         cwd = dirs['abs_locales_dir']
         output = self._get_output_from_make(target=target, cwd=cwd, env=env)
         self.info('UPLOAD_FILES is "%s"' % (output))
         files = shlex.split(output)
         if not files:
             self.error('failed to get upload file list for locale %s' % (locale))
             return FAILURE
 
-        for f in files:
-            abs_file = os.path.abspath(os.path.join(cwd, f))
-            self.upload_files.update([abs_file])
+        self.upload_files[locale] = [
+            os.path.abspath(os.path.join(cwd, f)) for f in files
+        ]
         return SUCCESS
 
     def make_installers(self, locale):
         """wrapper for make installers-(locale)"""
         env = self.query_l10n_env()
         self._copy_mozconfig()
         env['L10NBASEDIR'] = self.l10n_dir
         dirs = self.query_abs_dirs()
@@ -1013,41 +1011,58 @@ class DesktopSingleLocale(LocalesMixin, 
 
         # Enable Taskcluster debug logging, so at least we get some debug
         # messages while we are testing uploads.
         logging.getLogger('taskcluster').setLevel(logging.DEBUG)
 
         branch = self.config['branch']
         platform = self.config['platform']
         revision = self._query_revision()
-        tc = Taskcluster(self.config['branch'],
-                         self.query_pushdate(),
-                         client_id,
-                         access_token,
-                         self.log_obj,
-                         )
+
+        routes_json = os.path.join(self.query_abs_dirs()['abs_mozilla_dir'],
+                                   'testing/taskcluster/routes.json')
+        with open(routes_json) as f:
+            contents = json.load(f)
+            templates = contents['l10n']
 
-        index = self.config.get('taskcluster_index', 'index.garbage.staging')
-        # TODO: Bug 1165980 - these should be in tree. Note the '.l10n' suffix.
-        routes = [
-            "%s.buildbot.branches.%s.%s.l10n" % (index, branch, platform),
-            "%s.buildbot.revisions.%s.%s.%s.l10n" % (index, revision, branch, platform),
-        ]
+        for locale, files in self.upload_files.iteritems():
+            self.info("Uploading files to S3 for locale '%s': %s" % (locale, files))
+            routes = []
+            for template in templates:
+                fmt = {
+                    # TODO: Bug 1133074
+                    #index = self.config.get('taskcluster_index', 'index.garbage.staging')
+                    'index': 'index.garbage.staging.mshal-testing',
+                    'project': branch,
+                    'head_rev': revision,
+                    'build_product': self.config['stage_product'],
+                    'build_name': self.query_build_name(),
+                    'build_type': self.query_build_type(),
+                    'locale': locale,
+                }
+                fmt.update(self.buildid_to_dict(self._query_buildid()))
+                routes.append(template.format(**fmt))
+                self.info('Using routes: %s' % routes)
 
-        task = tc.create_task(routes)
-        tc.claim_task(task)
+            tc = Taskcluster(branch,
+                             self.query_pushdate(),
+                             client_id,
+                             access_token,
+                             self.log_obj,
+                             )
+            task = tc.create_task(routes)
+            tc.claim_task(task)
 
-        self.info("Uploading files to S3: %s" % self.upload_files)
-        for upload_file in self.upload_files:
-            # Create an S3 artifact for each file that gets uploaded. We also
-            # check the uploaded file against the property conditions so that we
-            # can set the buildbot config with the correct URLs for package
-            # locations.
-            tc.create_artifact(task, upload_file)
-        tc.report_completed(task)
+            for upload_file in files:
+                # Create an S3 artifact for each file that gets uploaded. We also
+                # check the uploaded file against the property conditions so that we
+                # can set the buildbot config with the correct URLs for package
+                # locations.
+                tc.create_artifact(task, upload_file)
+            tc.report_completed(task)
 
     def query_pushdate(self):
         if self.pushdate:
             return self.pushdate
 
         mozilla_dir = self.config['mozilla_dir']
         repo = None
         for repository in self.config['repos']:
--- a/toolkit/content/tests/chrome/test_mousecapture.xul
+++ b/toolkit/content/tests/chrome/test_mousecapture.xul
@@ -6,17 +6,17 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
 <script>
 <![CDATA[
 
-SimpleTest.expectAssertions(12);
+SimpleTest.expectAssertions(6, 12);
 
 SimpleTest.waitForExplicitFinish();
 
 var captureRetargetMode = false;
 var cachedMouseDown = null;
 var previousWidth = 0, originalWidth = 0;
 var loadInWindow = false;
 
--- a/toolkit/webapps/tests/chrome.ini
+++ b/toolkit/webapps/tests/chrome.ini
@@ -26,14 +26,14 @@ skip-if = (os == "win" && os_version == 
 [test_packaged_uninstall.xul]
 skip-if = (os == "win" && os_version == "5.1") || (os == 'mac' && os_version == '10.10') # WinXP: bug 981251; OS X 10.10: bug 1123085
 [test_hosted_update_from_webapp_runtime.xul]
 skip-if = asan
 [test_packaged_update_from_webapp_runtime.xul]
 skip-if = asan
 [test_hosted_icons.xul]
 [test_hosted_checkforupdates_from_webapp_runtime.xul]
-skip-if = asan || ((os == "win" && os_version == "6.2") && debug) # Win8: bug 1162987
+skip-if = asan || (os == "win" && os_version == "6.2") # Win8: bug 1162987
 [test_packaged_icons.xul]
 [test_packaged_checkforupdates_from_webapp_runtime.xul]
-skip-if = asan || ((os == "win" && os_version == "6.2") && debug) # Win8: bug 1154545
+skip-if = asan || (os == "win" && os_version == "6.2") # Win8: bug 1154545
 [test_webapp_runtime_executable_update.xul]
 [test_non_ascii_app_name.xul]
--- a/widget/gtk/gtk3drawing.c
+++ b/widget/gtk/gtk3drawing.c
@@ -2633,26 +2633,35 @@ moz_gtk_get_widget_border(GtkThemeWidget
                           gboolean inhtml)
 {
     GtkWidget* w;
     GtkStyleContext* style;
     *left = *top = *right = *bottom = 0;
 
     switch (widget) {
     case MOZ_GTK_BUTTON:
+    case MOZ_GTK_TOOLBAR_BUTTON:
         {
             ensure_button_widget();
             style = gtk_widget_get_style_context(gButtonWidget);
 
             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
 
             /* Don't add this padding in HTML, otherwise the buttons will
                become too big and stuff the layout. */
             if (!inhtml) {
+                if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
+                    gtk_style_context_save(style);
+                    gtk_style_context_add_class(style, "image-button");
+                }
+              
                 moz_gtk_add_style_padding(style, left, top, right, bottom);
+                
+                if (widget == MOZ_GTK_TOOLBAR_BUTTON)
+                    gtk_style_context_restore(style);
             }
 
             moz_gtk_add_style_border(style, left, top, right, bottom);
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_ENTRY:
         {
             ensure_entry_widget();
@@ -3104,16 +3113,17 @@ moz_gtk_widget_paint(GtkThemeWidgetType 
                      GtkTextDirection direction)
 {
     /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=694086
      */
     cairo_new_path(cr);
 
     switch (widget) {
     case MOZ_GTK_BUTTON:
+    case MOZ_GTK_TOOLBAR_BUTTON:
         if (state->depressed) {
             ensure_toggle_button_widget();
             return moz_gtk_button_paint(cr, rect, state,
                                         (GtkReliefStyle) flags,
                                         gToggleButtonWidget, direction);
         }
         ensure_button_widget();
         return moz_gtk_button_paint(cr, rect, state,
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -84,16 +84,18 @@ typedef gint (*style_prop_t)(GtkStyle*, 
 /*** checkbox/radio flags ***/
 #define MOZ_GTK_WIDGET_CHECKED 1
 #define MOZ_GTK_WIDGET_INCONSISTENT (1 << 1)
 
 /*** widget type constants ***/
 typedef enum {
   /* Paints a GtkButton. flags is a GtkReliefStyle. */
   MOZ_GTK_BUTTON,
+  /* Paints a button with image and no text */
+  MOZ_GTK_TOOLBAR_BUTTON,
   /* Paints a GtkCheckButton. flags is a boolean, 1=checked, 0=not checked. */
   MOZ_GTK_CHECKBUTTON,
   /* Paints a GtkRadioButton. flags is a boolean, 1=checked, 0=not checked. */
   MOZ_GTK_RADIOBUTTON,
   /**
    * Paints the button of a GtkScrollbar. flags is a GtkArrowType giving
    * the arrow direction.
    */
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -386,21 +386,25 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
           *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused);
         }
       }
     }
   }
 
   switch (aWidgetType) {
   case NS_THEME_BUTTON:
+    if (aWidgetFlags)
+      *aWidgetFlags = GTK_RELIEF_NORMAL;
+    aGtkWidgetType = MOZ_GTK_BUTTON;
+    break;
   case NS_THEME_TOOLBAR_BUTTON:
   case NS_THEME_TOOLBAR_DUAL_BUTTON:
     if (aWidgetFlags)
-      *aWidgetFlags = (aWidgetType == NS_THEME_BUTTON) ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE;
-    aGtkWidgetType = MOZ_GTK_BUTTON;
+      *aWidgetFlags = GTK_RELIEF_NONE;
+    aGtkWidgetType = MOZ_GTK_TOOLBAR_BUTTON;
     break;
   case NS_THEME_FOCUS_OUTLINE:
     aGtkWidgetType = MOZ_GTK_ENTRY;
     break;
   case NS_THEME_CHECKBOX:
   case NS_THEME_RADIO:
     aGtkWidgetType = (aWidgetType == NS_THEME_RADIO) ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON;
     break;