Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 16 May 2016 14:19:52 -0700
changeset 367573 a884b96685aa13b65601feddb24e5f85ba861561
parent 367425 e9533997fcef31fa5d2db464c6ceec0ca6ea560f (current diff)
parent 367404 349f5ef87e5be1c7be0a24c60895c0efe3fa2495 (diff)
child 367574 ae689711c21875e2f732c97264e35527c7f6b963
child 367583 1ebb86ba28c701cd4dfde93f92473424459a7fce
child 367585 c1bce0caa654ef9e958ea908d898c682b644f316
child 367602 75423e6be2f647e5f6bf5c5a3c9c8111c7af4a3e
child 367616 05689bc2d1928d9dc17fe6a8a32318d716f08f7a
child 367619 ce5a89d30332a00246864cfdde837206af303994
child 367631 80a46d318b4ecd9a5f9ce994d9de032da2319738
child 367636 b8381f52305a38970d50a7b7e2967abca95f4391
child 367637 44f718bb2282512003fa09eb9a796ff4b580c957
child 367652 8063ba7c7a649a718e5cc1687f40b2766a6bd593
child 367654 dfb8749dc89c7c1b0b2cc1548abf22e2a1897f69
child 367659 002ec2e3104d618e4dc00791dcb3cfa61e7bed2c
child 367662 8f4f55c8f8a44df70d4329d5c50e625d5010491b
child 367669 0f9cf8926c0add19fd65685fe3101935b64b039e
child 367676 72deb6f3200e8e961a70c13f482551bc5f86e61b
child 367684 ed546c6587b5401c6285cecdfd209acd792a6bf5
child 367693 e3c8046eceb59be707a7601b203ac39a3ea3ebe2
child 367696 6ef4f6b99c03b2172f1de087f3fda7199def3674
child 367705 178d2c9ea5e34fc0cb84ba94bbdee26f9efbb825
child 367706 826847b24b4af6e7e1a34f0469e3ea6870cc932b
child 367708 bd613cb895912cc3a5047001311485bb6856d84c
child 367734 a28a3191647d241049c15443a6a1ac837ff49782
child 367800 8ca8b109f7d5804ce4df013666db042d5d157b7c
child 367801 5849c9dd3d21dcb89a9b3386102c457e42bee149
child 367816 b2358b1f43ea59890f9ffbeaa06a9c69ad971231
child 367817 48bfe349caa06d067fd0059961f234ee29f04c70
child 367824 3f6c99837c5d2ad1a1c47e6a29d1861174d9aef3
child 367831 c7da63ffc26de1622e6bdf08723985f07dba5da1
child 367838 3780a3a6b83aeda143f9562829c830410a0c961e
child 367849 6a90d6c0e5a62ba233e54e34ef8493a8b10a1b02
child 368113 d507ef58c8556ee45be49668422c3843c92ed5bc
child 368187 669c7665e81dbf308b771c138edb33a5fbc10be8
child 368211 522e08891f8d5c9ff90bd86280aaf713a70aeaf2
child 369136 b0571b0a39704c54d44994a533f96fa3b1543a3d
child 369157 506fc8910046a13a7b86208dd02bfbe7942f206e
child 369661 56e789088df3ebbd8088d05019c42aaae7eeb595
child 369663 a57a0f37502a6949f9d63c9d9b868ffdd47fae47
child 369702 78a970c85dd90eb7278290c66040d0ae298fb3eb
push id18276
push usergkruglov@mozilla.com
push dateMon, 16 May 2016 21:43:53 +0000
reviewersmerge
milestone49.0a1
Merge inbound to central, a=merge
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -126,20 +126,22 @@ var FullScreen = {
         // to get its corresponding browser here.
         let browser;
         if (event.target == gBrowser) {
           browser = event.originalTarget;
         } else {
           let topWin = event.target.ownerDocument.defaultView.top;
           browser = gBrowser.getBrowserForContentWindow(topWin);
         }
+        TelemetryStopwatch.start("FULLSCREEN_CHANGE_MS");
         this.enterDomFullscreen(browser);
         break;
       }
       case "MozDOMFullscreen:Exited":
+        TelemetryStopwatch.start("FULLSCREEN_CHANGE_MS");
         this.cleanupDomFullscreen();
         break;
     }
   },
 
   receiveMessage: function(aMessage) {
     let browser = aMessage.target;
     switch (aMessage.name) {
@@ -152,16 +154,17 @@ var FullScreen = {
         break;
       }
       case "DOMFullscreen:Exit": {
         this._windowUtils.remoteFrameFullscreenReverted();
         break;
       }
       case "DOMFullscreen:Painted": {
         Services.obs.notifyObservers(window, "fullscreen-painted", "");
+        TelemetryStopwatch.finish("FULLSCREEN_CHANGE_MS");
         break;
       }
     }
   },
 
   enterDomFullscreen : function(aBrowser) {
     if (!document.fullscreenElement) {
       return;
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -263,17 +263,17 @@ tags = mcb
 [browser_bug832435.js]
 [browser_bug839103.js]
 [browser_bug880101.js]
 [browser_bug882977.js]
 [browser_bug902156.js]
 tags = mcb
 [browser_bug906190.js]
 tags = mcb
-skip-if = buildapp == "mulet" || e10s # Bug 1093642 - test manipulates content and relies on content focus
+skip-if = buildapp == "mulet" # Bug 1093642 - test manipulates content and relies on content focus
 [browser_mixedContentFromOnunload.js]
 tags = mcb
 [browser_mixedContentFramesOnHttp.js]
 tags = mcb
 [browser_bug970746.js]
 [browser_bug1015721.js]
 skip-if = os == 'win'
 [browser_bug1064280_changeUrlInPinnedTab.js]
--- a/browser/base/content/test/general/browser_bug906190.js
+++ b/browser/base/content/test/general/browser_bug906190.js
@@ -187,45 +187,54 @@ add_task(function* test_same_origin_meta
   }, true);
 });
 
 /**
  * 5. - Load a html page which has mixed content
  *    - Doorhanger to disable protection appears - we disable it
  *    - Load a new page from the same origin in a new tab simulating a click
  *    - Redirect to another page from the same origin using 302 redirect
- *    - Doorhanger >> APPEARS << , but should >> NOT << appear again!
- *    - FOLLOW UP BUG 914860!
  */
 add_task(function* test_same_origin_302redirect_same_origin() {
   // the sjs files returns a 302 redirect- note, same origins
   yield doTest(gHttpTestRoot1 + "file_bug906190_1.html",
                gHttpTestRoot1 + "file_bug906190.sjs", function* () {
     // The doorhanger should appear but activeBlocked should be >> NOT << true.
     // Currently it is >> TRUE << - see follow up bug 914860
-    todo(!gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
-         "OK: Mixed Content is NOT being blocked");
+    ok(!gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
+       "OK: Mixed Content is NOT being blocked");
 
-    todo_is(content.document.getElementById('mctestdiv').innerHTML,
-            "Mixed Content Blocker disabled", "OK: Executed mixed script");
+    is(content.document.getElementById('mctestdiv').innerHTML,
+       "Mixed Content Blocker disabled", "OK: Executed mixed script");
   });
 });
 
 /**
  * 6. - Load a html page which has mixed content
  *    - Doorhanger to disable protection appears - we disable it
  *    - Load a new page from the same origin in a new tab simulating a click
  *    - Redirect to another page from a different origin using 302 redirect
- *    - Doorhanger >> SHOULD << appear again!
  */
 add_task(function* test_same_origin_302redirect_different_origin() {
   // the sjs files returns a 302 redirect - note, different origins
   yield doTest(gHttpTestRoot2 + "file_bug906190_1.html",
                gHttpTestRoot2 + "file_bug906190.sjs", function* () {
     // The doorhanger should appear and activeBlocked should be >> TRUE <<.
     yield assertMixedContentBlockingState(gBrowser, {
       activeLoaded: false, activeBlocked: true, passiveLoaded: false,
     });
 
     is(content.document.getElementById('mctestdiv').innerHTML,
        "Mixed Content Blocker enabled", "OK: Blocked mixed script");
   });
 });
+
+/**
+ * 7. - Test memory leak issue on redirection error. See Bug 1269426.
+ */
+add_task(function* test_bad_redirection() {
+  // the sjs files returns a 302 redirect - note, different origins
+  yield doTest(gHttpTestRoot2 + "file_bug906190_1.html",
+               gHttpTestRoot2 + "file_bug906190.sjs?bad-redirection=1", function* () {
+    // Nothing to do. Just see if memory leak is reported in the end.
+    ok(true, "Nothing to do");
+  });
+});
--- a/browser/base/content/test/general/file_bug906190.sjs
+++ b/browser/base/content/test/general/file_bug906190.sjs
@@ -1,11 +1,17 @@
 function handleRequest(request, response) {
   var page = "<!DOCTYPE html><html><body>bug 906190</body></html>";
   var path = "https://test1.example.com/browser/browser/base/content/test/general/";
-  var url = path + "file_bug906190_redirected.html";
+  var url;
+
+  if (request.queryString.includes('bad-redirection=1')) {
+    url = path + "this_page_does_not_exist.html";
+  } else {
+    url = path + "file_bug906190_redirected.html";
+  }
 
   response.setHeader("Cache-Control", "no-cache", false);
   response.setHeader("Content-Type", "text/html", false);
   response.setStatusLine(request.httpVersion, "302", "Found");
   response.setHeader("Location", url, false);
   response.write(page);
 }
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7348,16 +7348,29 @@ nsDocShell::OnLocationChange(nsIWebProgr
 void
 nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
                                   nsIChannel* aNewChannel,
                                   uint32_t aRedirectFlags,
                                   uint32_t aStateFlags)
 {
   NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
                "Calling OnRedirectStateChange when there is no redirect");
+
+  // If mixed content is allowed for the old channel, we forward
+  // the permission to the new channel if it has the same origin
+  // as the old one.
+  if (mMixedContentChannel && mMixedContentChannel == aOldChannel) {
+    nsresult rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, aNewChannel);
+    if (NS_SUCCEEDED(rv)) {
+      SetMixedContentChannel(aNewChannel); // Same origin: forward permission.
+    } else {
+      SetMixedContentChannel(nullptr); // Different origin: clear mMixedContentChannel.
+    }
+  }
+
   if (!(aStateFlags & STATE_IS_DOCUMENT)) {
     return;  // not a toplevel document
   }
 
   nsCOMPtr<nsIURI> oldURI, newURI;
   aOldChannel->GetURI(getter_AddRefs(oldURI));
   aNewChannel->GetURI(getter_AddRefs(newURI));
   if (!oldURI || !newURI) {
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -685,16 +685,24 @@ KeyframeEffectReadOnly::SetIsRunningOnCo
       if (aIsRunning) {
         property.mPerformanceWarning.reset();
       }
       return;
     }
   }
 }
 
+void
+KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
+{
+  for (AnimationProperty& property : mProperties) {
+    property.mIsRunningOnCompositor = false;
+  }
+}
+
 KeyframeEffectReadOnly::~KeyframeEffectReadOnly()
 {
 }
 
 static Maybe<OwningAnimationTarget>
 ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
 {
   // Return value optimization.
@@ -746,24 +754,16 @@ KeyframeEffectReadOnly::ConstructKeyfram
   if (aRv.Failed()) {
     return nullptr;
   }
 
   return effect.forget();
 }
 
 void
-KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
-{
-  for (AnimationProperty& property : mProperties) {
-    property.mIsRunningOnCompositor = false;
-  }
-}
-
-void
 KeyframeEffectReadOnly::ResetWinsInCascade()
 {
   for (AnimationProperty& property : mProperties) {
     property.mWinsInCascade = false;
   }
 }
 
 void
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -307,16 +307,17 @@ public:
   // AnimationEffect for the current time except any properties already
   // contained in |aSetProperties|.
   // Any updated properties are added to |aSetProperties|.
   void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
                     nsCSSPropertySet& aSetProperties);
   // Returns true if at least one property is being animated on compositor.
   bool IsRunningOnCompositor() const;
   void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
+  void ResetIsRunningOnCompositor();
 
   // Returns true if this effect, applied to |aFrame|, contains properties
   // that mean we shouldn't run transform compositor animations on this element.
   //
   // For example, if we have an animation of geometric properties like 'left'
   // and 'top' on an element, we force all 'transform' animations running at
   // the same time on the same element to run on the main thread.
   //
@@ -347,17 +348,16 @@ protected:
   template<class KeyframeEffectType, class OptionsType>
   static already_AddRefed<KeyframeEffectType>
   ConstructKeyframeEffect(const GlobalObject& aGlobal,
                           const Nullable<ElementOrCSSPseudoElement>& aTarget,
                           JS::Handle<JSObject*> aKeyframes,
                           const OptionsType& aOptions,
                           ErrorResult& aRv);
 
-  void ResetIsRunningOnCompositor();
   void ResetWinsInCascade();
 
   // This effect is registered with its target element so long as:
   //
   // (a) It has a target element, and
   // (b) It is "relevant" (i.e. yet to finish but not idle, or finished but
   //     filling forwards)
   //
--- a/dom/animation/test/chrome/test_restyles.html
+++ b/dom/animation/test/chrome/test_restyles.html
@@ -416,19 +416,19 @@ waitForAllPaints(function() {
 
     // We need to wait a frame to apply display:none style.
     yield waitForFrame();
 
     is(animation.playState, 'running',
        'Opacity script animations keep running even when the target element ' +
        'has "display: none" style');
 
-    todo(!animation.isRunningOnCompositor,
-         'Opacity script animations on "display:none" element should not ' +
-         'run on the compositor');
+    ok(!animation.isRunningOnCompositor,
+       'Opacity script animations on "display:none" element should not ' +
+       'run on the compositor');
 
     var markers = yield observeStyling(5);
     is(markers.length, 0,
        'Opacity script animations on "display: none" element should not ' +
        'update styles');
 
     div.style.display = '';
 
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -98,16 +98,21 @@
 #include "mozilla/WebBrowserPersistLocalDocument.h"
 
 #include "nsPrincipal.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
+#ifdef NS_PRINTING
+#include "mozilla/embedding/printingui/PrintingParent.h"
+#include "nsIWebBrowserPrint.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::hal;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 typedef FrameMetrics::ViewID ViewID;
 
@@ -3097,16 +3102,56 @@ nsFrameLoader::RequestNotifyLayerTreeCle
     new AsyncEventDispatcher(mOwnerContent,
                              NS_LITERAL_STRING("MozLayerTreeCleared"),
                              true, false);
   event->PostDOMEvent();
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::Print(nsIPrintSettings* aPrintSettings,
+                     nsIWebProgressListener* aProgressListener)
+{
+#if defined(NS_PRINTING)
+  if (mRemoteBrowser) {
+    RefPtr<embedding::PrintingParent> printingParent =
+      mRemoteBrowser->Manager()->AsContentParent()->GetPrintingParent();
+
+    embedding::PrintData printData;
+    nsresult rv = printingParent->SerializeAndEnsureRemotePrintJob(
+      aPrintSettings, aProgressListener, nullptr, &printData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    bool success = mRemoteBrowser->SendPrint(printData);
+    return success ? NS_OK : NS_ERROR_FAILURE;
+  }
+
+  if (mDocShell) {
+    nsCOMPtr<nsIContentViewer> viewer;
+    mDocShell->GetContentViewer(getter_AddRefs(viewer));
+    if (!viewer) {
+      return NS_ERROR_FAILURE;
+    }
+
+    nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_QueryInterface(viewer);
+    if (!webBrowserPrint) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return webBrowserPrint->Print(aPrintSettings, aProgressListener);
+  }
+
+  return NS_ERROR_FAILURE;
+#endif
+  return NS_OK;
+}
+
 /* [infallible] */ NS_IMETHODIMP
 nsFrameLoader::SetVisible(bool aVisible)
 {
   if (mVisible == aVisible) {
     return NS_OK;
   }
 
   mVisible = aVisible;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6243,16 +6243,17 @@ private:
   static const char* const kPaintedTopic;
 
   RefPtr<nsGlobalWindow> mWindow;
   nsCOMPtr<nsIWidget> mWidget;
   nsCOMPtr<nsIScreen> mScreen;
   nsCOMPtr<nsITimer> mTimer;
   nsCOMPtr<nsISupports> mTransitionData;
 
+  TimeStamp mFullscreenChangeStartTime;
   FullscreenTransitionDuration mDuration;
   Stage mStage;
   bool mFullscreen;
 };
 
 const char* const
 FullscreenTransitionTask::kPaintedTopic = "fullscreen-painted";
 
@@ -6269,16 +6270,17 @@ FullscreenTransitionTask::Run()
   }
   if (stage == eBeforeToggle) {
     PROFILER_MARKER("Fullscreen transition start");
     mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
                                          mDuration.mFadeIn, mTransitionData,
                                          this);
   } else if (stage == eToggleFullscreen) {
     PROFILER_MARKER("Fullscreen toggle start");
+    mFullscreenChangeStartTime = TimeStamp::Now();
     if (MOZ_UNLIKELY(mWindow->mFullScreen != mFullscreen)) {
       // This could happen in theory if several fullscreen requests in
       // different direction happen continuously in a short time. We
       // need to ensure the fullscreen state matches our target here,
       // otherwise the widget would change the window state as if we
       // toggle for Fullscreen Mode instead of Fullscreen API.
       NS_WARNING("The fullscreen state of the window does not match");
       mWindow->mFullScreen = mFullscreen;
@@ -6305,16 +6307,18 @@ FullscreenTransitionTask::Run()
     // powerful, layout could take a long time, in which case, staying
     // in black screen for that long could hurt user experience even
     // more than exposing an intermediate state.
     mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     uint32_t timeout =
       Preferences::GetUint("full-screen-api.transition.timeout", 500);
     mTimer->Init(observer, timeout, nsITimer::TYPE_ONE_SHOT);
   } else if (stage == eAfterToggle) {
+    Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
+                                   mFullscreenChangeStartTime);
     mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
                                          mDuration.mFadeOut, mTransitionData,
                                          this);
   } else if (stage == eEnd) {
     PROFILER_MARKER("Fullscreen transition end");
   }
   return NS_OK;
 }
--- a/dom/base/nsIFrameLoader.idl
+++ b/dom/base/nsIFrameLoader.idl
@@ -11,16 +11,18 @@ interface nsIDocShell;
 interface nsIURI;
 interface nsIFrame;
 interface nsSubDocumentFrame;
 interface nsIMessageSender;
 interface nsIVariant;
 interface nsIDOMElement;
 interface nsITabParent;
 interface nsILoadContext;
+interface nsIPrintSettings;
+interface nsIWebProgressListener;
 
 [scriptable, builtinclass, uuid(1645af04-1bc7-4363-8f2c-eb9679220ab1)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
@@ -135,16 +137,26 @@ interface nsIFrameLoader : nsISupports
    * Request an event when the layer tree from the remote tab becomes
    * available or unavailable. When this happens, a mozLayerTreeReady
    * or mozLayerTreeCleared event is fired.
    */
   void requestNotifyLayerTreeReady();
   void requestNotifyLayerTreeCleared();
 
   /**
+   * Print the current document.
+   *
+   * @param aPrintSettings optional print settings to use; printSilent can be
+   *                       set to prevent prompting.
+   * @param aProgressListener optional print progress listener.
+   */
+  void print(in nsIPrintSettings aPrintSettings,
+             in nsIWebProgressListener aProgressListener);
+
+  /**
    * The default event mode automatically forwards the events
    * handled in EventStateManager::HandleCrossProcessEvent to
    * the child content process when these events are targeted to
    * the remote browser element.
    *
    * Used primarly for input events (mouse, keyboard)
    */
   const unsigned long EVENT_MODE_NORMAL_DISPATCH = 0x00000000;
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1181,19 +1181,18 @@ nsDOMCameraControl::NotifyRecordingStatu
     mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
     if (!mAudioChannelAgent) {
       return NS_ERROR_UNEXPECTED;
     }
 
     // Camera app will stop recording when it falls to the background, so no callback is necessary.
     mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
     // Video recording doesn't output any sound, so it's not necessary to check canPlay.
-    float volume = 0.0;
-    bool muted = true;
-    rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
+    AudioPlaybackConfig config;
+    rv = mAudioChannelAgent->NotifyStartedPlaying(&config, AudioChannelService::AudibleState::eAudible);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 #endif
   return rv;
 }
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -102,16 +102,17 @@
 #include "nsAnonymousTemporaryFile.h"
 #include "nsISpellChecker.h"
 #include "nsClipboardProxy.h"
 #include "nsISystemMessageCache.h"
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsContentPermissionHelper.h"
+#include "nsPrintingProxy.h"
 
 #include "IHistory.h"
 #include "nsNetUtil.h"
 
 #include "base/message_loop.h"
 #include "base/process_util.h"
 #include "base/task.h"
 
@@ -706,16 +707,21 @@ ContentChild::Init(MessageLoop* aIOLoop,
   }
 #endif
 
 #ifdef MOZ_NUWA_PROCESS
   if (IsNuwaProcess()) {
     NuwaAddConstructor(ResetTransports, nullptr);
   }
 #endif
+#ifdef NS_PRINTING
+  // Force the creation of the nsPrintingProxy so that it's IPC counterpart,
+  // PrintingParent, is always available for printing initiated from the parent.
+  RefPtr<nsPrintingProxy> printingProxy = nsPrintingProxy::GetInstance();
+#endif
 
   return true;
 }
 
 void
 ContentChild::InitProcessAttributes()
 {
 #ifdef MOZ_WIDGET_GONK
@@ -925,23 +931,23 @@ ContentChild::ProvideWindowCommon(TabChi
     return NS_ERROR_ABORT;
   }
 
   if (layersId == 0) { // if renderFrame is invalid.
     PRenderFrameChild::Send__delete__(renderFrame);
     renderFrame = nullptr;
   }
 
-  ShowInfo showInfo(EmptyString(), false, false, true, 0, 0);
+  ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0);
   auto* opener = nsPIDOMWindowOuter::From(aParent);
   nsIDocShell* openerShell;
   if (opener && (openerShell = opener->GetDocShell())) {
     nsCOMPtr<nsILoadContext> context = do_QueryInterface(openerShell);
     showInfo = ShowInfo(EmptyString(), false,
-                        context->UsePrivateBrowsing(), true,
+                        context->UsePrivateBrowsing(), true, false,
                         aTabOpener->mDPI, aTabOpener->mDefaultScale);
   }
 
   // Unfortunately we don't get a window unless we've shown the frame.  That's
   // pretty bogus; see bug 763602.
   newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame,
                        showInfo);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -81,16 +81,17 @@
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/PSendStreamParent.h"
 #include "mozilla/ipc/SendStreamAlloc.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/PAPZParent.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
@@ -2553,17 +2554,17 @@ ContentParent::InitInternal(ProcessPrior
     // NB: internally, this will send an IPC message to the child
     // process to get it to create the CompositorBridgeChild.  This
     // message goes through the regular IPC queue for this
     // channel, so delivery will happen-before any other messages
     // we send.  The CompositorBridgeChild must be created before any
     // PBrowsers are created, because they rely on the Compositor
     // already being around.  (Creation is async, so can't happen
     // on demand.)
-    bool useOffMainThreadCompositing = !!CompositorBridgeParent::CompositorLoop();
+    bool useOffMainThreadCompositing = !!CompositorThreadHolder::Loop();
     if (useOffMainThreadCompositing) {
       DebugOnly<bool> opened = PCompositorBridge::Open(this);
       MOZ_ASSERT(opened);
 
       opened = PImageBridge::Open(this);
       MOZ_ASSERT(opened);
 
       opened = gfx::PVRManager::Open(this);
@@ -3814,34 +3815,52 @@ ContentParent::DeallocPNeckoParent(PNeck
   delete necko;
   return true;
 }
 
 PPrintingParent*
 ContentParent::AllocPPrintingParent()
 {
 #ifdef NS_PRINTING
-  return new PrintingParent();
+  MOZ_ASSERT(!mPrintingParent,
+             "Only one PrintingParent should be created per process.");
+
+  // Create the printing singleton for this process.
+  mPrintingParent = new PrintingParent();
+  return mPrintingParent.get();
 #else
+  MOZ_ASSERT_UNREACHABLE("Should never be created if no printing.");
   return nullptr;
 #endif
 }
 
 bool
-ContentParent::RecvPPrintingConstructor(PPrintingParent* aActor)
-{
+ContentParent::DeallocPPrintingParent(PPrintingParent* printing)
+{
+#ifdef NS_PRINTING
+  MOZ_ASSERT(mPrintingParent == printing,
+             "Only one PrintingParent should have been created per process.");
+
+  mPrintingParent = nullptr;
+#else
+  MOZ_ASSERT_UNREACHABLE("Should never have been created if no printing.");
+#endif
   return true;
 }
 
-bool
-ContentParent::DeallocPPrintingParent(PPrintingParent* printing)
-{
-  delete printing;
-  return true;
-}
+#ifdef NS_PRINTING
+already_AddRefed<embedding::PrintingParent>
+ContentParent::GetPrintingParent()
+{
+  MOZ_ASSERT(mPrintingParent);
+
+  RefPtr<embedding::PrintingParent> printingParent = mPrintingParent;
+  return printingParent.forget();
+}
+#endif
 
 PSendStreamParent*
 ContentParent::AllocPSendStreamParent()
 {
   return mozilla::ipc::AllocPSendStreamParent();
 }
 
 bool
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -44,16 +44,20 @@ class PRemoteSpellcheckEngineParent;
 class ProfileGatherer;
 #endif
 
 #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
 class SandboxBroker;
 class SandboxBrokerPolicyFactory;
 #endif
 
+namespace embedding {
+class PrintingParent;
+}
+
 namespace ipc {
 class OptionalURIParams;
 class PFileDescriptorSetParent;
 class URIParams;
 class TestShellParent;
 } // namespace ipc
 
 namespace jsipc {
@@ -375,19 +379,24 @@ public:
 
   virtual bool RecvPNeckoConstructor(PNeckoParent* aActor) override
   {
     return PContentParent::RecvPNeckoConstructor(aActor);
   }
 
   virtual PPrintingParent* AllocPPrintingParent() override;
 
-  virtual bool RecvPPrintingConstructor(PPrintingParent* aActor) override;
+  virtual bool DeallocPPrintingParent(PPrintingParent* aActor) override;
 
-  virtual bool DeallocPPrintingParent(PPrintingParent* aActor) override;
+#if defined(NS_PRINTING)
+  /**
+   * @return the PrintingParent for this ContentParent.
+   */
+  already_AddRefed<embedding::PrintingParent> GetPrintingParent();
+#endif
 
   virtual PSendStreamParent* AllocPSendStreamParent() override;
   virtual bool DeallocPSendStreamParent(PSendStreamParent* aActor) override;
 
   virtual PScreenManagerParent*
   AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
                             float* aSystemDefaultScale,
                             bool* aSuccess) override;
@@ -1195,16 +1204,20 @@ private:
 
   UniquePtr<gfx::DriverCrashGuard> mDriverCrashGuard;
 
 #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
   mozilla::UniquePtr<SandboxBroker> mSandboxBroker;
   static mozilla::UniquePtr<SandboxBrokerPolicyFactory>
       sSandboxBrokerPolicyFactory;
 #endif
+
+#ifdef NS_PRINTING
+  RefPtr<embedding::PrintingParent> mPrintingParent;
+#endif
 };
 
 } // namespace dom
 } // namespace mozilla
 
 class ParentIdleListener : public nsIObserver
 {
   friend class mozilla::dom::ContentParent;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -10,20 +10,22 @@ include protocol PColorPicker;
 include protocol PContent;
 include protocol PContentBridge;
 include protocol PDocAccessible;
 include protocol PDocumentRenderer;
 include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PRenderFrame;
 include protocol PPluginWidget;
+include protocol PRemotePrintJob;
 include DOMTypes;
 include JavaScriptTypes;
 include URIParams;
 include BrowserConfiguration;
+include PPrintingTypes;
 include PTabContext;
 
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using class mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h";
 using struct gfxSize from "gfxPoint.h";
 using CSSRect from "Units.h";
 using CSSSize from "Units.h";
@@ -87,16 +89,17 @@ union MaybeNativeKeyBinding
 };
 
 struct ShowInfo
 {
   nsString name;
   bool fullscreenAllowed;
   bool isPrivate;
   bool fakeShowInfo;
+  bool isTransparent;
   float dpi;
   double defaultScale;
 };
 
 prio(normal upto urgent) sync protocol PBrowser
 {
     manager PContent or PContentBridge;
 
@@ -776,16 +779,23 @@ child:
      * @param aKeyEventData      The key event which was posted to the parent
      *                           process.
      * @param aIsConsumed        true if aKeyEventData is consumed in the
      *                           parent process.  Otherwise, false.
      */
     async HandledWindowedPluginKeyEvent(NativeEventData aKeyEventData,
                                         bool aIsConsumed);
 
+    /**
+     * Tell the child to print the current page with the given settings.
+     *
+     * @param aPrintData the serialized settings to print with
+     */
+    async Print(PrintData aPrintData);
+
 /*
  * FIXME: write protocol!
 
 state LIVE:
     send LoadURL goto LIVE;
 //etc.
     send Destroy goto DYING;
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -107,16 +107,23 @@
 #include "nsNetUtil.h"
 #include "nsIPermissionManager.h"
 #include "nsIURILoader.h"
 #include "nsIScriptError.h"
 #include "mozilla/EventForwards.h"
 #include "nsDeviceContext.h"
 #include "FrameLayerBuilder.h"
 
+#ifdef NS_PRINTING
+#include "nsIPrintSession.h"
+#include "nsIPrintSettings.h"
+#include "nsIPrintSettingsService.h"
+#include "nsIWebBrowserPrint.h"
+#endif
+
 #define BROWSER_ELEMENT_CHILD_SCRIPT \
     NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
 
 #define TABC_LOG(...)
 // #define TABC_LOG(...) printf_stderr("TABC: " __VA_ARGS__)
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -586,16 +593,17 @@ TabChild::TabChild(nsIContentChild* aMan
   , mOrientation(eScreenOrientation_PortraitPrimary)
   , mUpdateHitRegion(false)
   , mIgnoreKeyPressEvent(false)
   , mHasValidInnerSize(false)
   , mDestroyed(false)
   , mUniqueId(aTabId)
   , mDPI(0)
   , mDefaultScale(0)
+  , mIsTransparent(false)
   , mIPCOpen(true)
   , mParentIsActive(false)
   , mDidSetRealShowInfo(false)
   , mDidLoadURLInit(false)
   , mAPZChild(nullptr)
 {
   // In the general case having the TabParent tell us if APZ is enabled or not
   // doesn't really work because the TabParent itself may not have a reference
@@ -1298,40 +1306,16 @@ TabChild::SetProcessNameToAppName()
     NS_WARNING("Failed to retrieve app name");
     return;
   }
 
   ContentChild::GetSingleton()->SetProcessName(appName, true);
 }
 
 bool
-TabChild::IsRootContentDocument() const
-{
-    // A TabChild is a "root content document" if it's
-    //
-    //  - <iframe mozapp> not inside another <iframe mozapp>,
-    //  - <iframe mozbrowser> (not mozapp), or
-    //  - a vanilla remote frame (<html:iframe remote=true> or <xul:browser
-    //    remote=true>).
-    //
-    // Put another way, an iframe is /not/ a "root content document" iff it's a
-    // mozapp inside a mozapp.  (This corresponds exactly to !HasAppOwnerApp.)
-    //
-    // Note that we're lying through our teeth here (thus the scare quotes).
-    // <html:iframe remote=true> or <xul:browser remote=true> inside another
-    // content iframe is not actually a root content document, but we say it is.
-    //
-    // We do this because we make a remote frame opaque iff
-    // IsRootContentDocument(), and making vanilla remote frames transparent
-    // breaks our remote reftests.
-
-    return !HasAppOwnerApp();
-}
-
-bool
 TabChild::RecvLoadURL(const nsCString& aURI,
                       const BrowserConfiguration& aConfiguration,
                       const ShowInfo& aInfo)
 {
   if (!mDidLoadURLInit) {
     mDidLoadURLInit = true;
     if (!InitTabChildGlobal()) {
       return false;
@@ -1559,16 +1543,17 @@ TabChild::ApplyShowInfo(const ShowInfo& 
         } else {
           context->SetUsePrivateBrowsing(true);
         }
       }
     }
   }
   mDPI = aInfo.dpi();
   mDefaultScale = aInfo.defaultScale();
+  mIsTransparent = aInfo.isTransparent();
 }
 
 #ifdef MOZ_WIDGET_GONK
 void
 TabChild::MaybeRequestPreinitCamera()
 {
     // Check if this tab is an app (not a browser frame) and will use the
     // `camera` permission,
@@ -2453,16 +2438,55 @@ TabChild::RecvSetUseGlobalHistory(const 
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to set UseGlobalHistory on TabChild docShell");
   }
 
   return true;
 }
 
 bool
+TabChild::RecvPrint(const PrintData& aPrintData)
+{
+#ifdef NS_PRINTING
+  nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_GetInterface(mWebNav);
+  if (NS_WARN_IF(!webBrowserPrint)) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
+    do_GetService("@mozilla.org/gfx/printsettings-service;1");
+  if (NS_WARN_IF(!printSettingsSvc)) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrintSettings> printSettings;
+  nsresult rv =
+    printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrintSession>  printSession =
+    do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return true;
+  }
+
+  printSettings->SetPrintSession(printSession);
+  printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
+  rv = webBrowserPrint->Print(printSettings, nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return true;
+  }
+
+#endif
+  return true;
+}
+
+bool
 TabChild::RecvDestroy()
 {
   MOZ_ASSERT(mDestroyed == false);
   mDestroyed = true;
 
   nsTArray<PContentPermissionRequestChild*> childArray =
       nsContentPermissionUtils::GetContentPermissionRequestChildById(GetTabId());
 
@@ -2989,17 +3013,17 @@ TabChild::InvalidateLayers()
 
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
   FrameLayerBuilder::InvalidateAllLayers(lm);
 }
 
 void
 TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier)
 {
-  gfxPlatform::GetPlatform()->UpdateRenderModeIfDeviceReset();
+  gfxPlatform::GetPlatform()->CompositorUpdated();
 
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
   ClientLayerManager* clm = lm->AsClientLayerManager();
 
   mTextureFactoryIdentifier = aNewIdentifier;
   clm->UpdateTextureFactoryIdentifier(aNewIdentifier);
   FrameLayerBuilder::InvalidateAllLayers(clm);
 }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -189,22 +189,22 @@ public:
                                        const mozilla::layers::FrameMetrics::ViewID& aViewId,
                                        const Maybe<mozilla::layers::ZoomConstraints>& aConstraints) = 0;
 
   virtual ScreenIntSize GetInnerSize() = 0;
 
   // Get the Document for the top-level window in this tab.
   already_AddRefed<nsIDocument> GetDocument() const;
 
+  // Get the pres-shell of the document for the top-level window in this tab.
+  already_AddRefed<nsIPresShell> GetPresShell() const;
+
 protected:
   virtual ~TabChildBase();
 
-  // Get the pres-shell of the document for the top-level window in this tab.
-  already_AddRefed<nsIPresShell> GetPresShell() const;
-
   // Wraps up a JSON object as a structured clone and sends it to the browser
   // chrome script.
   //
   // XXX/bug 780335: Do the work the browser chrome script does in C++ instead
   // so we don't need things like this.
   void DispatchMessageManagerMessage(const nsAString& aMessageName,
                                      const nsAString& aJSONData);
 
@@ -260,18 +260,16 @@ public:
    */
   static void PreloadSlowThings();
 
   /** Return a TabChild with the given attributes. */
   static already_AddRefed<TabChild>
   Create(nsIContentChild* aManager, const TabId& aTabId,
          const TabContext& aContext, uint32_t aChromeFlags);
 
-  bool IsRootContentDocument() const;
-
   // Let managees query if it is safe to send messages.
   bool IsDestroyed() const{ return mDestroyed; }
 
   const TabId GetTabId() const
   {
     MOZ_ASSERT(mUniqueId != 0);
     return mUniqueId;
   }
@@ -471,16 +469,18 @@ public:
 
   virtual PuppetWidget* WebWidget() override { return mPuppetWidget; }
 
   /** Return the DPI of the widget this TabChild draws to. */
   void GetDPI(float* aDPI);
 
   void GetDefaultScale(double *aScale);
 
+  bool IsTransparent() const { return mIsTransparent; }
+
   void GetMaxTouchPoints(uint32_t* aTouchPoints);
 
   ScreenOrientationInternal GetOrientation() const { return mOrientation; }
 
   void SetBackgroundColor(const nscolor& aColor);
 
   void NotifyPainted();
 
@@ -575,16 +575,18 @@ public:
                                                   const bool& aMuted) override;
 
   virtual bool RecvSetUseGlobalHistory(const bool& aUse) override;
 
   virtual bool RecvHandledWindowedPluginKeyEvent(
                  const mozilla::NativeEventData& aKeyEventData,
                  const bool& aIsConsumed) override;
 
+  virtual bool RecvPrint(const PrintData& aPrintData) override;
+
   /**
    * Native widget remoting protocol for use with windowed plugins with e10s.
    */
   PPluginWidgetChild* AllocPPluginWidgetChild() override;
 
   bool DeallocPPluginWidgetChild(PPluginWidgetChild* aActor) override;
 
   nsresult CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut);
@@ -746,16 +748,18 @@ private:
   // Position of tab, relative to parent widget (typically the window)
   LayoutDeviceIntPoint mChromeDisp;
   TabId mUniqueId;
 
   friend class ContentChild;
   float mDPI;
   double mDefaultScale;
 
+  bool mIsTransparent;
+
   bool mIPCOpen;
   bool mParentIsActive;
   bool mAsyncPanZoomEnabled;
   CSSSize mUnscaledInnerSize;
   bool mDidSetRealShowInfo;
   bool mDidLoadURLInit;
 
   AutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -3320,22 +3320,25 @@ TabParent::GetShowInfo()
   TryCacheDPIAndScale();
   if (mFrameElement) {
     nsAutoString name;
     mFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
     bool allowFullscreen =
       mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
       mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen);
     bool isPrivate = mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
+    bool isTransparent =
+      nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
+      mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent);
     return ShowInfo(name, allowFullscreen, isPrivate, false,
-                    mDPI, mDefaultScale.scale);
+                    isTransparent, mDPI, mDefaultScale.scale);
   }
 
   return ShowInfo(EmptyString(), false, false, false,
-                  mDPI, mDefaultScale.scale);
+                  false, mDPI, mDefaultScale.scale);
 }
 
 void
 TabParent::AudioChannelChangeNotification(nsPIDOMWindowOuter* aWindow,
                                           AudioChannel aAudioChannel,
                                           float aVolume,
                                           bool aMuted)
 {
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -182,16 +182,17 @@ WidevineDecryptor::Decrypt(GMPBuffer* aB
   mCallback->Decrypted(aBuffer, ToGMPErr(rv));
 }
 
 void
 WidevineDecryptor::DecryptingComplete()
 {
   Log("WidevineDecryptor::DecryptingComplete() this=%p", this);
   mCDM = nullptr;
+  mCallback = nullptr;
   Release();
 }
 
 class WidevineBuffer : public cdm::Buffer {
 public:
   WidevineBuffer(size_t aSize) {
     Log("WidevineBuffer(size=" PRIuSIZE ") created", aSize);
     mBuffer.SetLength(aSize);
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1964,44 +1964,70 @@ TrackBuffersManager::SkipToNextRandomAcc
       break;
     }
     parsed++;
   }
 
   return parsed;
 }
 
+const MediaRawData*
+TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
+                               size_t aIndex,
+                               const TimeUnit& aExpectedDts,
+                               const TimeUnit& aExpectedPts,
+                               const TimeUnit& aFuzz)
+{
+  const TrackBuffer& track = GetTrackBuffer(aTrack);
+
+  if (aIndex >= track.Length()) {
+    // reached the end.
+    return nullptr;
+  }
+
+  const RefPtr<MediaRawData>& sample = track[aIndex];
+  if (!aIndex || sample->mTimecode <= (aExpectedDts + aFuzz).ToMicroseconds() ||
+      sample->mTime <= (aExpectedPts + aFuzz).ToMicroseconds()) {
+    return sample;
+  }
+
+  // Gap is too big. End of Stream or Waiting for Data.
+  // TODO, check that we have continuous data based on the sanitized buffered
+  // range instead.
+  return nullptr;
+}
+
 already_AddRefed<MediaRawData>
 TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
                                const TimeUnit& aFuzz,
                                bool& aError)
 {
   MOZ_ASSERT(OnTaskQueue());
   auto& trackData = GetTracksData(aTrack);
   const TrackBuffer& track = GetTrackBuffer(aTrack);
 
   aError = false;
 
-  if (!track.Length() ||
-      (trackData.mNextGetSampleIndex.isSome() &&
-       trackData.mNextGetSampleIndex.ref() >= track.Length())) {
+  if (!track.Length()) {
     return nullptr;
   }
   if (trackData.mNextGetSampleIndex.isNothing() &&
       trackData.mNextSampleTimecode == TimeUnit()) {
     // First demux, get first sample.
     trackData.mNextGetSampleIndex = Some(0u);
   }
 
   if (trackData.mNextGetSampleIndex.isSome()) {
-    const RefPtr<MediaRawData>& sample =
-      track[trackData.mNextGetSampleIndex.ref()];
-    if (trackData.mNextGetSampleIndex.ref() &&
-        sample->mTimecode > (trackData.mNextSampleTimecode + aFuzz).ToMicroseconds()) {
-      // Gap is too big. End of Stream or Waiting for Data.
+    const MediaRawData* sample =
+      GetSample(aTrack,
+                trackData.mNextGetSampleIndex.ref(),
+                trackData.mNextSampleTimecode,
+                trackData.mNextSampleTime,
+                aFuzz);
+    if (!sample) {
       return nullptr;
     }
 
     RefPtr<MediaRawData> p = sample->Clone();
     if (!p) {
       aError = true;
       return nullptr;
     }
@@ -2073,28 +2099,30 @@ TrackBuffersManager::GetNextRandomAccess
                                               const TimeUnit& aFuzz)
 {
   auto& trackData = GetTracksData(aTrack);
   MOZ_ASSERT(trackData.mNextGetSampleIndex.isSome());
   const TrackBuffersManager::TrackBuffer& track = GetTrackBuffer(aTrack);
 
   uint32_t i = trackData.mNextGetSampleIndex.ref();
   TimeUnit nextSampleTimecode = trackData.mNextSampleTimecode;
+  TimeUnit nextSampleTime = trackData.mNextSampleTime;
 
   for (; i < track.Length(); i++) {
-    const RefPtr<MediaRawData>& sample = track[i];
-    if (sample->mTimecode > (nextSampleTimecode + aFuzz).ToMicroseconds()) {
-      // Gap is too big. End of Stream or Waiting for Data.
+    const MediaRawData* sample =
+      GetSample(aTrack, i, nextSampleTimecode, nextSampleTime, aFuzz);
+    if (!sample) {
       break;
     }
     if (sample->mKeyframe) {
       return TimeUnit::FromMicroseconds(sample->mTime);
     }
     nextSampleTimecode =
       TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
+    nextSampleTime = TimeUnit::FromMicroseconds(sample->GetEndTime());
   }
   return TimeUnit::FromInfinity();
 }
 
 void
 TrackBuffersManager::TrackData::AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes)
 {
   for (TrackBuffer& buffer : mBuffers) {
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -335,16 +335,21 @@ private:
                     const media::TimeIntervals& aIntervals,
                     TrackData& aTrackData);
   void RemoveFrames(const media::TimeIntervals& aIntervals,
                     TrackData& aTrackData,
                     uint32_t aStartIndex);
   // Find index of sample. Return a negative value if not found.
   uint32_t FindSampleIndex(const TrackBuffer& aTrackBuffer,
                            const media::TimeInterval& aInterval);
+  const MediaRawData* GetSample(TrackInfo::TrackType aTrack,
+                                size_t aIndex,
+                                const media::TimeUnit& aExpectedDts,
+                                const media::TimeUnit& aExpectedPts,
+                                const media::TimeUnit& aFuzz);
   void UpdateBufferedRanges();
   void RejectProcessing(nsresult aRejectValue, const char* aName);
   void ResolveProcessing(bool aResolveValue, const char* aName);
   MozPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
   MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
 
   // Trackbuffers definition.
   nsTArray<TrackData*> GetTracksList();
--- a/dom/media/systemservices/MediaSystemResourceService.cpp
+++ b/dom/media/systemservices/MediaSystemResourceService.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaSystemResourceManagerParent.h"
-#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/unused.h"
 
 #include "MediaSystemResourceService.h"
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 
@@ -41,17 +41,17 @@ MediaSystemResourceService::Shutdown()
     sSingleton->Destroy();
     sSingleton = nullptr;
   }
 }
 
 MediaSystemResourceService::MediaSystemResourceService()
   : mDestroyed(false)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
 #ifdef MOZ_WIDGET_GONK
   // The maximum number of hardware resoureces available.
   // XXX need to hange to a dynamic way.
   enum
   {
     VIDEO_DECODER_COUNT = 1,
     VIDEO_ENCODER_COUNT = 1
   };
@@ -77,17 +77,17 @@ MediaSystemResourceService::Destroy()
 }
 
 void
 MediaSystemResourceService::Acquire(media::MediaSystemResourceManagerParent* aParent,
                                     uint32_t aId,
                                     MediaSystemResourceType aResourceType,
                                     bool aWillWait)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   MOZ_ASSERT(aParent);
 
   if (mDestroyed) {
     return;
   }
 
   MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
 
@@ -118,17 +118,17 @@ MediaSystemResourceService::Acquire(medi
     MediaSystemResourceRequest(aParent, aId));
 }
 
 void
 MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
                                             uint32_t aId,
                                             MediaSystemResourceType aResourceType)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   MOZ_ASSERT(aParent);
 
   if (mDestroyed) {
     return;
   }
 
   MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
 
--- a/embedding/components/printingui/ipc/PPrinting.ipdl
+++ b/embedding/components/printingui/ipc/PPrinting.ipdl
@@ -18,16 +18,17 @@ sync protocol PPrinting
   manager PContent;
   manages PPrintProgressDialog;
   manages PPrintSettingsDialog;
   manages PRemotePrintJob;
 
 parent:
   sync ShowProgress(PBrowser browser,
                     PPrintProgressDialog printProgressDialog,
+                    PRemotePrintJob remotePrintJob,
                     bool isForPrinting)
     returns(bool notifyOnOpen,
             nsresult rv);
 
   async ShowPrintDialog(PPrintSettingsDialog dialog,
                         PBrowser browser,
                         PrintData settings);
 
--- a/embedding/components/printingui/ipc/PrintingParent.cpp
+++ b/embedding/components/printingui/ipc/PrintingParent.cpp
@@ -1,40 +1,42 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/unused.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIPrintingPromptService.h"
-#include "nsIPrintOptions.h"
 #include "nsIPrintProgressParams.h"
 #include "nsIPrintSettingsService.h"
 #include "nsIServiceManager.h"
+#include "nsServiceManagerUtils.h"
 #include "nsIWebProgressListener.h"
 #include "PrintingParent.h"
 #include "PrintDataUtils.h"
 #include "PrintProgressDialogParent.h"
 #include "PrintSettingsDialogParent.h"
 #include "mozilla/layout/RemotePrintJobParent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layout;
 
 namespace mozilla {
 namespace embedding {
 bool
 PrintingParent::RecvShowProgress(PBrowserParent* parent,
                                  PPrintProgressDialogParent* printProgressDialog,
+                                 PRemotePrintJobParent* remotePrintJob,
                                  const bool& isForPrinting,
                                  bool* notifyOnOpen,
                                  nsresult* result)
 {
   *result = NS_ERROR_FAILURE;
   *notifyOnOpen = false;
 
   nsCOMPtr<nsPIDOMWindowOuter> parentWin = DOMWindowFromBrowserParent(parent);
@@ -57,17 +59,25 @@ PrintingParent::RecvShowProgress(PBrowse
 
   *result = pps->ShowProgress(parentWin, nullptr, nullptr, observer,
                               isForPrinting,
                               getter_AddRefs(printProgressListener),
                               getter_AddRefs(printProgressParams),
                               notifyOnOpen);
   NS_ENSURE_SUCCESS(*result, true);
 
-  dialogParent->SetWebProgressListener(printProgressListener);
+  if (remotePrintJob) {
+    // If we have a RemotePrintJob use that as a more general forwarder for
+    // print progress listeners.
+    static_cast<RemotePrintJobParent*>(remotePrintJob)
+      ->RegisterListener(printProgressListener);
+  } else {
+    dialogParent->SetWebProgressListener(printProgressListener);
+  }
+
   dialogParent->SetPrintProgressParams(printProgressParams);
 
   return true;
 }
 
 nsresult
 PrintingParent::ShowPrintDialog(PBrowserParent* aParent,
                                 const PrintData& aData,
@@ -83,35 +93,32 @@ PrintingParent::ShowPrintDialog(PBrowser
     return NS_ERROR_FAILURE;
   }
 
   // The initSettings we got can be wrapped using
   // PrintDataUtils' MockWebBrowserPrint, which implements enough of
   // nsIWebBrowserPrint to keep the dialogs happy.
   nsCOMPtr<nsIWebBrowserPrint> wbp = new MockWebBrowserPrint(aData);
 
-  nsresult rv;
-  nsCOMPtr<nsIPrintOptions> po = do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
+  nsCOMPtr<nsIPrintSettings> settings;
+  nsresult rv = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(settings));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIPrintSettings> settings;
-  rv = po->CreatePrintSettings(getter_AddRefs(settings));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = po->DeserializeToPrintSettings(aData, settings);
+  rv = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = pps->ShowPrintDialog(parentWin, wbp, settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // And send it back.
-  rv = po->SerializeToPrintData(settings, nullptr, aResult);
-
-  PRemotePrintJobParent* remotePrintJob = new RemotePrintJobParent(settings);
-  aResult->remotePrintJobParent() = SendPRemotePrintJobConstructor(remotePrintJob);
+  // Serialize back to aResult. Use the existing RemotePrintJob if we have one
+  // otherwise SerializeAndEnsureRemotePrintJob() will create a new one.
+  RemotePrintJobParent* remotePrintJob =
+    static_cast<RemotePrintJobParent*>(aData.remotePrintJobParent());
+  rv = SerializeAndEnsureRemotePrintJob(settings, nullptr, remotePrintJob,
+                                        aResult);
 
   return rv;
 }
 
 bool
 PrintingParent::RecvShowPrintDialog(PPrintSettingsDialogParent* aDialog,
                                     PBrowserParent* aParent,
                                     const PrintData& aData)
@@ -132,31 +139,26 @@ PrintingParent::RecvShowPrintDialog(PPri
 }
 
 bool
 PrintingParent::RecvSavePrintSettings(const PrintData& aData,
                                       const bool& aUsePrinterNamePrefix,
                                       const uint32_t& aFlags,
                                       nsresult* aResult)
 {
-  nsCOMPtr<nsIPrintSettingsService> pss =
-    do_GetService("@mozilla.org/gfx/printsettings-service;1", aResult);
-  NS_ENSURE_SUCCESS(*aResult, true);
-
-  nsCOMPtr<nsIPrintOptions> po = do_QueryInterface(pss, aResult);
+  nsCOMPtr<nsIPrintSettings> settings;
+  *aResult = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(settings));
   NS_ENSURE_SUCCESS(*aResult, true);
 
-  nsCOMPtr<nsIPrintSettings> settings;
-  *aResult = po->CreatePrintSettings(getter_AddRefs(settings));
+  *aResult = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
   NS_ENSURE_SUCCESS(*aResult, true);
 
-  *aResult = po->DeserializeToPrintSettings(aData, settings);
-  NS_ENSURE_SUCCESS(*aResult, true);
-
-  *aResult = pss->SavePrintSettingsToPrefs(settings, aUsePrinterNamePrefix, aFlags);
+  *aResult = mPrintSettingsSvc->SavePrintSettingsToPrefs(settings,
+                                                        aUsePrinterNamePrefix,
+                                                        aFlags);
 
   return true;
 }
 
 PPrintProgressDialogParent*
 PrintingParent::AllocPPrintProgressDialogParent()
 {
   PrintProgressDialogParent* actor = new PrintProgressDialogParent();
@@ -233,21 +235,65 @@ PrintingParent::DOMWindowFromBrowserPare
   nsCOMPtr<nsPIDOMWindowOuter> parentWin = frame->OwnerDoc()->GetWindow();
   if (!parentWin) {
     return nullptr;
   }
 
   return parentWin;
 }
 
+nsresult
+PrintingParent::SerializeAndEnsureRemotePrintJob(
+  nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aListener,
+  layout::RemotePrintJobParent* aRemotePrintJob, PrintData* aPrintData)
+{
+  MOZ_ASSERT(aPrintData);
+
+  nsresult rv;
+  nsCOMPtr<nsIPrintSettings> printSettings;
+  if (aPrintSettings) {
+    printSettings = aPrintSettings;
+  } else {
+    rv = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  rv = mPrintSettingsSvc->SerializeToPrintData(aPrintSettings, nullptr,
+                                               aPrintData);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  RemotePrintJobParent* remotePrintJob;
+  if (aRemotePrintJob) {
+    remotePrintJob = aRemotePrintJob;
+    aPrintData->remotePrintJobParent() = remotePrintJob;
+  } else {
+    remotePrintJob = new RemotePrintJobParent(aPrintSettings);
+    aPrintData->remotePrintJobParent() =
+      SendPRemotePrintJobConstructor(remotePrintJob);
+  }
+  if (aListener) {
+    remotePrintJob->RegisterListener(aListener);
+  }
+
+  return NS_OK;
+}
+
 PrintingParent::PrintingParent()
 {
-    MOZ_COUNT_CTOR(PrintingParent);
+  MOZ_COUNT_CTOR(PrintingParent);
+
+  mPrintSettingsSvc =
+    do_GetService("@mozilla.org/gfx/printsettings-service;1");
+  MOZ_ASSERT(mPrintSettingsSvc);
 }
 
 PrintingParent::~PrintingParent()
 {
-    MOZ_COUNT_DTOR(PrintingParent);
+  MOZ_COUNT_DTOR(PrintingParent);
 }
 
 } // namespace embedding
 } // namespace mozilla
 
--- a/embedding/components/printingui/ipc/PrintingParent.h
+++ b/embedding/components/printingui/ipc/PrintingParent.h
@@ -5,33 +5,39 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_embedding_PrintingParent_h
 #define mozilla_embedding_PrintingParent_h
 
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/embedding/PPrintingParent.h"
 
+class nsIPrintSettingsService;
+class nsIWebProgressListener;
 class nsPIDOMWindowOuter;
 class PPrintProgressDialogParent;
 class PPrintSettingsDialogParent;
 
 namespace mozilla {
 namespace layout {
 class PRemotePrintJobParent;
+class RemotePrintJobParent;
 }
 
 namespace embedding {
 
 class PrintingParent final : public PPrintingParent
 {
 public:
+    NS_INLINE_DECL_REFCOUNTING(PrintingParent)
+
     virtual bool
     RecvShowProgress(PBrowserParent* parent,
                      PPrintProgressDialogParent* printProgressDialog,
+                     PRemotePrintJobParent* remotePrintJob,
                      const bool& isForPrinting,
                      bool* notifyOnOpen,
                      nsresult* result);
     virtual bool
     RecvShowPrintDialog(PPrintSettingsDialogParent* aDialog,
                         PBrowserParent* aParent,
                         const PrintData& aData);
 
@@ -58,24 +64,46 @@ public:
 
     virtual bool
     DeallocPRemotePrintJobParent(PRemotePrintJobParent* aActor);
 
     virtual void
     ActorDestroy(ActorDestroyReason aWhy);
 
     MOZ_IMPLICIT PrintingParent();
+
+    /**
+     * Serialize nsIPrintSettings to PrintData ready for sending to a child
+     * process. A RemotePrintJob will be created and added to the PrintData.
+     * An optional progress listener can be given, which will be registered
+     * with the RemotePrintJob, so that progress can be tracked in the parent.
+     *
+     * @param aPrintSettings optional print settings to serialize, otherwise a
+     *                       default print settings will be used.
+     * @param aProgressListener optional print progress listener.
+     * @param aRemotePrintJob optional remote print job, so that an existing
+     *                        one can be used.
+     * @param aPrintData PrintData to populate.
+     */
+    nsresult
+    SerializeAndEnsureRemotePrintJob(nsIPrintSettings* aPrintSettings,
+                                     nsIWebProgressListener* aListener,
+                                     layout::RemotePrintJobParent* aRemotePrintJob,
+                                     PrintData* aPrintData);
+
+private:
     virtual ~PrintingParent();
 
-private:
     nsPIDOMWindowOuter*
     DOMWindowFromBrowserParent(PBrowserParent* parent);
 
     nsresult
     ShowPrintDialog(PBrowserParent* parent,
                     const PrintData& data,
                     PrintData* result);
+
+    nsCOMPtr<nsIPrintSettingsService> mPrintSettingsSvc;
 };
 
 } // namespace embedding
 } // namespace mozilla
 
 #endif
--- a/embedding/components/printingui/ipc/nsPrintingProxy.cpp
+++ b/embedding/components/printingui/ipc/nsPrintingProxy.cpp
@@ -9,20 +9,23 @@
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/layout/RemotePrintJobChild.h"
 #include "mozilla/unused.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIPrintingPromptService.h"
+#include "nsIPrintSession.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintOptionsImpl.h"
+#include "nsServiceManagerUtils.h"
 #include "PrintDataUtils.h"
 #include "PrintProgressDialogChild.h"
+#include "PrintSettingsDialogChild.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::embedding;
 using namespace mozilla::layout;
 
 static StaticRefPtr<nsPrintingProxy> sPrintingProxyInstance;
 
@@ -82,22 +85,23 @@ nsPrintingProxy::ShowPrintDialog(mozIDOM
 
   nsCOMPtr<nsITabChild> tabchild = docShell->GetTabChild();
   NS_ENSURE_STATE(tabchild);
 
   TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
 
   // Next, serialize the nsIWebBrowserPrint and nsIPrintSettings we were given.
   nsresult rv = NS_OK;
-  nsCOMPtr<nsIPrintOptions> po =
+  nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
     do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrintData inSettings;
-  rv = po->SerializeToPrintData(printSettings, webBrowserPrint, &inSettings);
+  rv = printSettingsSvc->SerializeToPrintData(printSettings, webBrowserPrint,
+                                              &inSettings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now, the waiting game. The parent process should be showing
   // the printing dialog soon. In the meantime, we need to spin a
   // nested event loop while we wait for the results of the dialog
   // to be returned to us.
 
   RefPtr<PrintSettingsDialogChild> dialog = new PrintSettingsDialogChild();
@@ -107,17 +111,18 @@ nsPrintingProxy::ShowPrintDialog(mozIDOM
 
   while(!dialog->returned()) {
     NS_ProcessNextEvent(nullptr, true);
   }
 
   rv = dialog->result();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = po->DeserializeToPrintSettings(dialog->data(), printSettings);
+  rv = printSettingsSvc->DeserializeToPrintSettings(dialog->data(),
+                                                    printSettings);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrintingProxy::ShowProgress(mozIDOMWindowProxy*      parent,
                               nsIWebBrowserPrint*      webBrowserPrint,    // ok to be null
                               nsIPrintSettings*        printSettings,      // ok to be null
                               nsIObserver*             openDialogObserver, // ok to be null
@@ -140,24 +145,39 @@ nsPrintingProxy::ShowProgress(mozIDOMWin
   nsCOMPtr<nsITabChild> tabchild = docShell->GetTabChild();
   TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
 
   RefPtr<PrintProgressDialogChild> dialogChild =
     new PrintProgressDialogChild(openDialogObserver);
 
   SendPPrintProgressDialogConstructor(dialogChild);
 
+  // Get the RemotePrintJob if we have one available.
+  RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
+  if (printSettings) {
+    nsCOMPtr<nsIPrintSession> printSession;
+    nsresult rv = printSettings->GetPrintSession(getter_AddRefs(printSession));
+    if (NS_SUCCEEDED(rv) && printSession) {
+      printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
+    }
+  }
+
   nsresult rv = NS_OK;
-  mozilla::Unused << SendShowProgress(pBrowser, dialogChild,
+  mozilla::Unused << SendShowProgress(pBrowser, dialogChild, remotePrintJob,
                                       isForPrinting, notifyOnOpen, &rv);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  NS_ADDREF(*webProgressListener = dialogChild);
+  // If we have a RemotePrintJob that will be being used as a more general
+  // forwarder for print progress listeners. Once we always have one we can
+  // remove the interface from PrintProgressDialogChild.
+  if (!remotePrintJob) {
+    NS_ADDREF(*webProgressListener = dialogChild);
+  }
   NS_ADDREF(*printProgressParams = dialogChild);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrintingProxy::ShowPageSetup(mozIDOMWindowProxy *parent,
                                nsIPrintSettings *printSettings,
@@ -175,22 +195,22 @@ nsPrintingProxy::ShowPrinterProperties(m
 }
 
 nsresult
 nsPrintingProxy::SavePrintSettings(nsIPrintSettings* aPS,
                                    bool aUsePrinterNamePrefix,
                                    uint32_t aFlags)
 {
   nsresult rv;
-  nsCOMPtr<nsIPrintOptions> po =
+  nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
     do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrintData settings;
-  rv = po->SerializeToPrintData(aPS, nullptr, &settings);
+  rv = printSettingsSvc->SerializeToPrintData(aPS, nullptr, &settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   Unused << SendSavePrintSettings(settings, aUsePrinterNamePrefix, aFlags,
                                   &rv);
   return rv;
 }
 
 PPrintProgressDialogChild*
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/Compositor.h"
 #include "base/message_loop.h"          // for MessageLoop
 #include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "gfx2DGlue.h"
 #include "nsAppRunner.h"
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 #include "libdisplay/GonkDisplay.h"     // for GonkDisplay
 #include <ui/Fence.h>
 #include "nsWindow.h"
@@ -20,18 +21,18 @@
 
 namespace mozilla {
 
 namespace layers {
 
 /* static */ void
 Compositor::AssertOnCompositorThread()
 {
-  MOZ_ASSERT(!CompositorBridgeParent::CompositorLoop() ||
-             CompositorBridgeParent::CompositorLoop() == MessageLoop::current(),
+  MOZ_ASSERT(!CompositorThreadHolder::Loop() ||
+             CompositorThreadHolder::Loop() == MessageLoop::current(),
              "Can only call this from the compositor thread!");
 }
 
 bool
 Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags)
 {
   if ((aFlags & DiagnosticFlags::TILE) && !(mDiagnosticTypes & DiagnosticTypes::TILE_BORDERS)) {
     return false;
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -190,16 +190,18 @@ protected:
 public:
   NS_INLINE_DECL_REFCOUNTING(Compositor)
 
   explicit Compositor(widget::CompositorWidgetProxy* aWidget,
                       CompositorBridgeParent* aParent = nullptr)
     : mCompositorID(0)
     , mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
     , mParent(aParent)
+    , mPixelsPerFrame(0)
+    , mPixelsFilled(0)
     , mScreenRotation(ROTATION_0)
     , mWidget(aWidget)
   {
   }
 
   virtual already_AddRefed<DataTextureSource> CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) = 0;
 
   virtual already_AddRefed<DataTextureSource>
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -12,17 +12,17 @@
 #include "Effects.h"
 #include "mozilla/Endian.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 
 #include "TexturePoolOGL.h"
 #include "mozilla/layers/CompositorOGL.h"
-#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/TextureHostOGL.h"
 
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "gfxPrefs.h"
 #include "nsIWidget.h"
 
@@ -1894,17 +1894,17 @@ LayerScope::SendLayerDump(UniquePtr<Pack
         new DebugGLLayersData(Move(aPacket)));
 }
 
 /*static*/
 bool
 LayerScope::CheckSendable()
 {
     // Only compositor threads check LayerScope status
-    MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread() || gIsGtest);
+    MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || gIsGtest);
 
     if (!gfxPrefs::LayerScopeEnabled()) {
         return false;
     }
     if (!gLayerScopeManager.GetSocketManager()) {
         Init();
         return false;
     }
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -499,16 +499,24 @@ CanvasClientSharedSurface::Updated()
   //            implementation of the WebVR 1.0 API, which will enable
   //            the inputFrameID to be passed through Javascript with
   //            the new VRDisplay API.
   t->mInputFrameID = VRManagerChild::Get()->GetInputFrameID();
   forwarder->UseTextures(this, textures);
 }
 
 void
+CanvasClientSharedSurface::OnDetach() {
+  if (mShSurfClient) {
+    mShSurfClient->CancelWaitForCompositorRecycle();
+  }
+  ClearSurfaces();
+}
+
+void
 CanvasClientSharedSurface::ClearSurfaces()
 {
   mFront = nullptr;
   mNewFront = nullptr;
   mShSurfClient = nullptr;
   mReadbackClient = nullptr;
 }
 
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -155,19 +155,17 @@ public:
   virtual void Update(gfx::IntSize aSize,
                       ClientCanvasLayer* aLayer) override;
   void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer);
 
   virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
 
   virtual void Updated() override;
 
-  virtual void OnDetach() override {
-    ClearSurfaces();
-  }
+  virtual void OnDetach() override;
 };
 
 /**
  * Used for OMT<canvas> uploads using the image bridge protocol.
  * Actual CanvasClient is on the ImageBridgeChild thread, so we
  * only forward its AsyncID here
  */
 class CanvasClientBridge final : public CanvasClient
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -200,16 +200,17 @@ ClientLayerManager::BeginTransactionWith
   Log();
 #endif
 
   NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
   mPhase = PHASE_CONSTRUCTION;
 
   if (DependsOnStaleDevice()) {
     FrameLayerBuilder::InvalidateAllLayers(this);
+    mDeviceCounter = gfxPlatform::GetPlatform()->GetDeviceCounter();
   }
 
   MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");
 
   // If the last transaction was incomplete (a failed DoEmptyTransaction),
   // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
   // to the previous transaction.
   dom::ScreenOrientationInternal orientation;
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Point.h"          // for RoundedToInt, PointTyped
 #include "mozilla/gfx/Rect.h"           // for RoundedToInt, RectTyped
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/layers/APZUtils.h"    // for CompleteAsyncTransform
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerAnimationUtils.h" // for TimingFunctionToComputedTimingFunction
 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
 #include "nsCoord.h"                    // for NSAppUnitsToFloatPixels, etc
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
 #include "nsDeviceContext.h"            // for nsDeviceContext
 #include "nsDisplayList.h"              // for nsDisplayTransform, etc
 #include "nsMathUtils.h"                // for NS_round
 #include "nsPoint.h"                    // for nsPoint
@@ -701,17 +702,17 @@ SampleAPZAnimations(const LayerMetricsWr
 
   return activeAnimations;
 }
 
 void
 AsyncCompositionManager::RecordShadowTransforms(Layer* aLayer)
 {
   MOZ_ASSERT(gfxPrefs::CollectScrollTransforms());
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
 
   ForEachNodePostOrder<ForwardIterator>(
       aLayer,
       [this] (Layer* layer)
       {
         for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
           AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i);
           if (!apzc) {
@@ -1434,17 +1435,17 @@ AsyncCompositionManager::TransformScroll
                             fixedLayerMargins, nullptr);
 
   ExpandRootClipRect(aLayer, fixedLayerMargins);
 }
 
 void
 AsyncCompositionManager::GetFrameUniformity(FrameUniformityData* aOutData)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mLayerTransformRecorder.EndTest(aOutData);
 }
 
 bool
 AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
                                              TransformsToSkip aSkip)
 {
   PROFILER_LABEL("AsyncCompositionManager", "TransformShadowTree",
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=2 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
 #include <stddef.h>                     // for size_t
 #include "ClientLayerManager.h"         // for ClientLayerManager
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
@@ -175,17 +176,17 @@ CompositorBridgeChild::Create(Transport*
 
 bool
 CompositorBridgeChild::OpenSameProcess(CompositorBridgeParent* aParent)
 {
   MOZ_ASSERT(aParent);
 
   mCompositorBridgeParent = aParent;
   mCanSend = Open(mCompositorBridgeParent->GetIPCChannel(),
-                  CompositorBridgeParent::CompositorLoop(),
+                  CompositorThreadHolder::Loop(),
                   ipc::ChildSide);
   return mCanSend;
 }
 
 /*static*/ CompositorBridgeChild*
 CompositorBridgeChild::Get()
 {
   // This is only expected to be used in child processes.
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -33,16 +33,17 @@
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
 #include "mozilla/layers/APZThreadUtils.h"  // for APZCTreeManager
 #include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/BasicCompositor.h"  // for BasicCompositor
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorLRU.h"  // for CompositorLRU
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/FrameUniformityData.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/layers/RemoteContentController.h"
 #include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
@@ -85,21 +86,16 @@
 #ifdef MOZ_ANDROID_APZ
 #include "AndroidBridge.h"
 #endif
 
 #include "LayerScope.h"
 
 namespace mozilla {
 
-namespace gfx {
-// See VRManagerChild.cpp
-void ReleaseVRManagerParentSingleton();
-} // namespace gfx
-
 namespace layers {
 
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace std;
 
 using base::ProcessId;
 using base::Thread;
@@ -150,109 +146,40 @@ CompositorBridgeParent::ForEachIndirectL
 /**
   * A global map referencing each compositor by ID.
   *
   * This map is used by the ImageBridge protocol to trigger
   * compositions without having to keep references to the
   * compositor
   */
 typedef map<uint64_t,CompositorBridgeParent*> CompositorMap;
-static CompositorMap* sCompositorMap;
-
-static void CreateCompositorMap()
+static StaticAutoPtr<CompositorMap> sCompositorMap;
+
+void
+CompositorBridgeParent::Initialize()
 {
+  EnsureLayerTreeMapReady();
+
   MOZ_ASSERT(!sCompositorMap);
   sCompositorMap = new CompositorMap;
 }
 
-static void DestroyCompositorMap()
+void
+CompositorBridgeParent::Shutdown()
 {
   MOZ_ASSERT(sCompositorMap);
   MOZ_ASSERT(sCompositorMap->empty());
-  delete sCompositorMap;
   sCompositorMap = nullptr;
 }
 
-// See ImageBridgeChild.cpp
-void ReleaseImageBridgeParentSingleton();
-
-CompositorThreadHolder::CompositorThreadHolder()
-  : mCompositorThread(CreateCompositorThread())
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_COUNT_CTOR(CompositorThreadHolder);
-}
-
-CompositorThreadHolder::~CompositorThreadHolder()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_COUNT_DTOR(CompositorThreadHolder);
-
-  DestroyCompositorThread(mCompositorThread);
-}
-
-static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
-static bool sFinishedCompositorShutDown = false;
-
-CompositorThreadHolder* GetCompositorThreadHolder()
-{
-  return sCompositorThreadHolder;
-}
-
-/* static */ Thread*
-CompositorThreadHolder::CreateCompositorThread()
+void
+CompositorBridgeParent::FinishShutdown()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
-
-  Thread* compositorThread = new Thread("Compositor");
-
-  Thread::Options options;
-  /* Timeout values are powers-of-two to enable us get better data.
-     128ms is chosen for transient hangs because 8Hz should be the minimally
-     acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
-  options.transient_hang_timeout = 128; // milliseconds
-  /* 2048ms is chosen for permanent hangs because it's longer than most
-   * Compositor hangs seen in the wild, but is short enough to not miss getting
-   * native hang stacks. */
-  options.permanent_hang_timeout = 2048; // milliseconds
-#if defined(_WIN32)
-  /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As
-   * such the thread is a gui thread, and must process a windows message queue or
-   * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */
-  options.message_loop_type = MessageLoop::TYPE_UI;
-#endif
-
-  if (!compositorThread->StartWithOptions(options)) {
-    delete compositorThread;
-    return nullptr;
-  }
-
-  EnsureLayerTreeMapReady();
-  CreateCompositorMap();
-
-  return compositorThread;
-}
-
-/* static */ void
-CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
-
-  DestroyCompositorMap();
-  delete aCompositorThread;
-  sFinishedCompositorShutDown = true;
-}
-
-static Thread* CompositorThread() {
-  return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr;
+  // TODO: this should be empty by now...
+  sIndirectLayerTrees.clear();
 }
 
 static void SetThreadPriority()
 {
   hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
 }
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
@@ -353,17 +280,17 @@ CompositorVsyncScheduler::~CompositorVsy
 
 #ifdef MOZ_WIDGET_GONK
 #if ANDROID_VERSION >= 19
 void
 CompositorVsyncScheduler::SetDisplay(bool aDisplayEnable)
 {
   // SetDisplay() is usually called from nsScreenManager at main thread. Post
   // to compositor thread if needs.
-  if (!CompositorBridgeParent::IsInCompositorThread()) {
+  if (!CompositorThreadHolder::IsInCompositorThread()) {
     MOZ_ASSERT(NS_IsMainThread());
     MonitorAutoLock lock(mSetDisplayMonitor);
     RefPtr<CancelableRunnable> task =
       NewCancelableRunnableMethod<bool>(this, &CompositorVsyncScheduler::SetDisplay, aDisplayEnable);
     mSetDisplayTask = task;
     ScheduleTask(task.forget(), 0);
     return;
   } else {
@@ -380,17 +307,17 @@ CompositorVsyncScheduler::SetDisplay(boo
     CancelCurrentSetNeedsCompositeTask();
     CancelCurrentCompositeTask();
   }
 }
 
 void
 CompositorVsyncScheduler::CancelSetDisplayTask()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   MonitorAutoLock lock(mSetDisplayMonitor);
   if (mSetDisplayTask) {
     mSetDisplayTask->Cancel();
     mSetDisplayTask = nullptr;
   }
 
   // CancelSetDisplayTask is only be called in clean-up process, so
   // mDisplayEnabled could be false there.
@@ -401,17 +328,17 @@ CompositorVsyncScheduler::CancelSetDispl
 
 void
 CompositorVsyncScheduler::Destroy()
 {
   if (!mVsyncObserver) {
     // Destroy was already called on this object.
     return;
   }
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   UnobserveVsync();
   mVsyncObserver->Destroy();
   mVsyncObserver = nullptr;
 
 #ifdef MOZ_WIDGET_GONK
 #if ANDROID_VERSION >= 19
   CancelSetDisplayTask();
 #endif
@@ -432,17 +359,17 @@ CompositorVsyncScheduler::PostCompositeT
     mCurrentCompositeTask = task;
     ScheduleTask(task.forget(), 0);
   }
 }
 
 void
 CompositorVsyncScheduler::ScheduleComposition()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   if (mAsapScheduling) {
     // Used only for performance testing purposes
     PostCompositeTask(TimeStamp::Now());
 #ifdef MOZ_WIDGET_ANDROID
   } else if (mNeedsComposite >= 2 && mIsObservingVsync) {
     // uh-oh, we already requested a composite at least twice so far, and a
     // composite hasn't happened yet. It is possible that the vsync observation
     // is blocked on the main thread, so let's just composite ASAP and not
@@ -454,17 +381,17 @@ CompositorVsyncScheduler::ScheduleCompos
   } else {
     SetNeedsComposite();
   }
 }
 
 void
 CompositorVsyncScheduler::CancelCurrentSetNeedsCompositeTask()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   MonitorAutoLock lock(mSetNeedsCompositeMonitor);
   if (mSetNeedsCompositeTask) {
     mSetNeedsCompositeTask->Cancel();
     mSetNeedsCompositeTask = nullptr;
   }
   mNeedsComposite = 0;
 }
 
@@ -473,17 +400,17 @@ CompositorVsyncScheduler::CancelCurrentS
  * If a composite takes 17 ms, do we composite ASAP or wait until next vsync?
  * If a layer transaction comes after vsync, do we composite ASAP or wait until
  * next vsync?
  * How many skipped vsync events until we stop listening to vsync events?
  */
 void
 CompositorVsyncScheduler::SetNeedsComposite()
 {
-  if (!CompositorBridgeParent::IsInCompositorThread()) {
+  if (!CompositorThreadHolder::IsInCompositorThread()) {
     MonitorAutoLock lock(mSetNeedsCompositeMonitor);
     RefPtr<CancelableRunnable> task =
       NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite);
     mSetNeedsCompositeTask = task;
     ScheduleTask(task.forget(), 0);
     return;
   } else {
     MonitorAutoLock lock(mSetNeedsCompositeMonitor);
@@ -504,37 +431,37 @@ CompositorVsyncScheduler::SetNeedsCompos
     ObserveVsync();
   }
 }
 
 bool
 CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
   // Called from the vsync dispatch thread
-  MOZ_ASSERT(!CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(!CompositorThreadHolder::IsInCompositorThread());
   MOZ_ASSERT(!NS_IsMainThread());
   PostCompositeTask(aVsyncTimestamp);
   return true;
 }
 
 void
 CompositorVsyncScheduler::CancelCurrentCompositeTask()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread() || NS_IsMainThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || NS_IsMainThread());
   MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
   if (mCurrentCompositeTask) {
     mCurrentCompositeTask->Cancel();
     mCurrentCompositeTask = nullptr;
   }
 }
 
 void
 CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   {
     MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
     mCurrentCompositeTask = nullptr;
   }
 
   if ((aVsyncTimestamp < mLastCompose) && !mAsapScheduling) {
     // We can sometimes get vsync timestamps that are in the past
     // compared to the last compose with force composites.
@@ -567,128 +494,100 @@ CompositorVsyncScheduler::OnForceCompose
    * where we receive many sync RecvFlushComposites. We also get vsync notifications which
    * will increment mVsyncNotificationsSkipped because a composite just occurred. After
    * enough vsyncs and RecvFlushComposites occurred, we will disable vsync. Then at the next
    * ScheduleComposite, we will enable vsync, then get a RecvFlushComposite, which will
    * force us to unobserve vsync again. On some platforms, enabling/disabling vsync is not
    * free and this oscillating behavior causes a performance hit. In order to avoid this problem,
    * we reset the mVsyncNotificationsSkipped counter to keep vsync enabled.
    */
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mVsyncNotificationsSkipped = 0;
 }
 
 void
 CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   OnForceComposeToTarget();
   mLastCompose = TimeStamp::Now();
   ComposeToTarget(aTarget, aRect);
 }
 
 bool
 CompositorVsyncScheduler::NeedsComposite()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   return mNeedsComposite;
 }
 
 void
 CompositorVsyncScheduler::ObserveVsync()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mCompositorVsyncDispatcher->SetCompositorVsyncObserver(mVsyncObserver);
   mIsObservingVsync = true;
 }
 
 void
 CompositorVsyncScheduler::UnobserveVsync()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mCompositorVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
   mIsObservingVsync = false;
 }
 
 void
 CompositorVsyncScheduler::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
 {
 #ifdef MOZ_WIDGET_GONK
   GeckoTouchDispatcher::GetInstance()->NotifyVsync(aVsyncTimestamp);
 #endif
 }
 
 void
 CompositorVsyncScheduler::DispatchVREvents(TimeStamp aVsyncTimestamp)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
 
   VRManager* vm = VRManager::Get();
   vm->NotifyVsync(aVsyncTimestamp);
 }
 
-void CompositorBridgeParent::StartUp()
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
-  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
-
-  sCompositorThreadHolder = new CompositorThreadHolder();
-}
-
-void CompositorBridgeParent::ShutDown()
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
-  MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
-
-  ReleaseImageBridgeParentSingleton();
-  ReleaseVRManagerParentSingleton();
-  MediaSystemResourceService::Shutdown();
-
-  sCompositorThreadHolder = nullptr;
-
-  // No locking is needed around sFinishedCompositorShutDown because it is only
-  // ever accessed on the main thread.
-  while (!sFinishedCompositorShutDown) {
-    NS_ProcessNextEvent(nullptr, true);
-  }
-
-  // TODO: this should be empty by now...
-  sIndirectLayerTrees.clear();
-}
-
-MessageLoop* CompositorBridgeParent::CompositorLoop()
-{
-  return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
-}
-
 void
 CompositorVsyncScheduler::ScheduleTask(already_AddRefed<CancelableRunnable> aTask,
                                        int aTime)
 {
-  MOZ_ASSERT(CompositorBridgeParent::CompositorLoop());
+  MOZ_ASSERT(CompositorThreadHolder::Loop());
   MOZ_ASSERT(aTime >= 0);
-  CompositorBridgeParent::CompositorLoop()->PostDelayedTask(Move(aTask), aTime);
+  CompositorThreadHolder::Loop()->PostDelayedTask(Move(aTask), aTime);
 }
 
 void
 CompositorVsyncScheduler::ResumeComposition()
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mLastCompose = TimeStamp::Now();
   ComposeToTarget(nullptr);
 }
 
 void
 CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
 {
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   MOZ_ASSERT(mCompositorBridgeParent);
   mCompositorBridgeParent->CompositeToTarget(aTarget, aRect);
 }
 
+static inline MessageLoop*
+CompositorLoop()
+{
+  return CompositorThreadHolder::Loop();
+}
+
 CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget,
                                                CSSToLayoutDeviceScale aScale,
                                                bool aUseAPZ,
                                                bool aUseExternalSurfaceSize,
                                                int aSurfaceWidth, int aSurfaceHeight)
   : mWidgetProxy(aWidget)
   , mIsTesting(false)
   , mPendingTransaction(0)
@@ -696,17 +595,17 @@ CompositorBridgeParent::CompositorBridge
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mPauseCompositionMonitor("PauseCompositionMonitor")
   , mResumeCompositionMonitor("ResumeCompositionMonitor")
   , mResetCompositorMonitor("ResetCompositorMonitor")
   , mRootLayerTreeID(AllocateLayerTreeId())
   , mOverrideComposeReadiness(false)
   , mForceCompositionTask(nullptr)
-  , mCompositorThreadHolder(sCompositorThreadHolder)
+  , mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
   , mCompositorScheduler(nullptr)
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
   , mLastPluginUpdateLayerTreeId(0)
   , mDeferPluginWindows(false)
   , mPluginWindowsHidden(false)
 #endif
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -739,22 +638,16 @@ CompositorBridgeParent::CompositorBridge
 
   mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
   LayerScope::SetPixelScale(aScale.scale);
 
   // mSelfRef is cleared in DeferredDestroy.
   mSelfRef = this;
 }
 
-bool
-CompositorBridgeParent::IsInCompositorThread()
-{
-  return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId();
-}
-
 uint64_t
 CompositorBridgeParent::RootLayerTreeId()
 {
   return mRootLayerTreeID;
 }
 
 CompositorBridgeParent::~CompositorBridgeParent()
 {
@@ -1010,17 +903,17 @@ CompositorBridgeParent::InvalidateOnComp
 {
   MOZ_ASSERT(CompositorLoop());
   CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::Invalidate));
 }
 
 void
 CompositorBridgeParent::PauseComposition()
 {
-  MOZ_ASSERT(IsInCompositorThread(),
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
              "PauseComposition() can only be called on the compositor thread");
 
   MonitorAutoLock lock(mPauseCompositionMonitor);
 
   if (!mPaused) {
     mPaused = true;
 
     mCompositor->Pause();
@@ -1031,17 +924,17 @@ CompositorBridgeParent::PauseComposition
 
   // if anyone's waiting to make sure that composition really got paused, tell them
   lock.NotifyAll();
 }
 
 void
 CompositorBridgeParent::ResumeComposition()
 {
-  MOZ_ASSERT(IsInCompositorThread(),
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
              "ResumeComposition() can only be called on the compositor thread");
 
   MonitorAutoLock lock(mResumeCompositionMonitor);
 
   if (!mCompositor->Resume()) {
 #ifdef MOZ_WIDGET_ANDROID
     // We can't get a surface. This could be because the activity changed between
     // the time resume was scheduled and now.
@@ -1165,17 +1058,17 @@ CompositorBridgeParent::NotifyShadowTree
   if (aScheduleComposite) {
     ScheduleComposition();
   }
 }
 
 void
 CompositorBridgeParent::ScheduleComposition()
 {
-  MOZ_ASSERT(IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   if (mPaused) {
     return;
   }
 
   mCompositorScheduler->ScheduleComposition();
 }
 
 // Go down the composite layer tree, setting properties to match their
@@ -1208,17 +1101,17 @@ CompositorBridgeParent::SetShadowPropert
 
 void
 CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect)
 {
   profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
   PROFILER_LABEL("CompositorBridgeParent", "Composite",
     js::ProfileEntry::Category::GRAPHICS);
 
-  MOZ_ASSERT(IsInCompositorThread(),
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
              "Composite can only be called on the compositor thread");
   TimeStamp start = TimeStamp::Now();
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeDuration scheduleDelta = TimeStamp::Now() - mCompositorScheduler->GetExpectedComposeStartTime();
   if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
       scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
     printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
@@ -1368,17 +1261,17 @@ CompositorBridgeParent::CanComposite()
          mLayerManager->GetRoot() &&
          !mPaused;
 }
 
 void
 CompositorBridgeParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig,
                                                      bool aIsFirstPaint)
 {
-  MOZ_ASSERT(IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
 
   if (!aIsFirstPaint &&
       !mCompositionManager->IsFirstPaint() &&
       mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) {
     if (mForceCompositionTask != nullptr) {
       mForceCompositionTask->Cancel();
     }
     RefPtr<CancelableRunnable> task =
@@ -1867,27 +1760,27 @@ CompositorBridgeParent::ComputeRenderInt
 
   return 1.0f;
 }
 
 static void
 InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
 {
 #ifdef MOZ_ENABLE_PROFILER_SPS
-  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   VsyncPayload* payload = new VsyncPayload(aVsyncTimestamp);
   PROFILER_MARKER_PAYLOAD("VsyncTimestamp", payload);
 #endif
 }
 
 /*static */ void
 CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
 {
   // Called in the vsync thread
-  if (profiler_is_active() && sCompositorThreadHolder) {
+  if (profiler_is_active() && CompositorThreadHolder::IsActive()) {
     CompositorLoop()->PostTask(
       NewRunnableFunction(InsertVsyncProfilerMarker, aVsyncTimestamp));
   }
 }
 
 /* static */ void
 CompositorBridgeParent::RequestNotifyLayerTreeReady(uint64_t aLayersId, CompositorUpdateObserver* aObserver)
 {
@@ -2067,17 +1960,19 @@ public:
 
   virtual bool AllocUnsafeShmem(size_t aSize,
                                 mozilla::ipc::SharedMemory::SharedMemoryType aType,
                                 mozilla::ipc::Shmem* aShmem) override;
 
   virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
 
 protected:
-  void OnChannelConnected(int32_t pid) override { mCompositorThreadHolder = sCompositorThreadHolder; }
+  void OnChannelConnected(int32_t pid) override {
+    mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();
+  }
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CrossProcessCompositorBridgeParent();
 
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -12,19 +12,16 @@
 // its responsiveness objectives:
 //    1) Compose a frame within 15ms of receiving a ScheduleCompositeCall
 //    2) Unless a frame was composited within the throttle threshold in
 //       which the deadline will be 15ms + throttle threshold
 //#define COMPOSITOR_PERFORMANCE_WARNING
 
 #include <stdint.h>                     // for uint64_t
 #include "Layers.h"                     // for Layer
-#include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
-#include "base/platform_thread.h"       // for PlatformThreadId
-#include "base/thread.h"                // for Thread
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/Maybe.h"
 #include "mozilla/Monitor.h"            // for Monitor
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
@@ -63,51 +60,30 @@ namespace layers {
 class APZCTreeManager;
 class AsyncCompositionManager;
 class Compositor;
 class CompositorBridgeParent;
 class LayerManagerComposite;
 class LayerTransactionParent;
 class PAPZParent;
 class CrossProcessCompositorBridgeParent;
+class CompositorThreadHolder;
 
 struct ScopedLayerTreeRegistration
 {
   ScopedLayerTreeRegistration(APZCTreeManager* aApzctm,
                               uint64_t aLayersId,
                               Layer* aRoot,
                               GeckoContentController* aController);
   ~ScopedLayerTreeRegistration();
 
 private:
   uint64_t mLayersId;
 };
 
-class CompositorThreadHolder final
-{
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
-
-public:
-  CompositorThreadHolder();
-
-  base::Thread* GetCompositorThread() const {
-    return mCompositorThread;
-  }
-
-private:
-  ~CompositorThreadHolder();
-
-  base::Thread* const mCompositorThread;
-
-  static base::Thread* CreateCompositorThread();
-  static void DestroyCompositorThread(base::Thread* aCompositorThread);
-
-  friend class CompositorBridgeParent;
-};
-
 /**
  * Manages the vsync (de)registration and tracking on behalf of the
  * compositor when it need to paint.
  * Turns vsync notifications into scheduled composites.
  **/
 class CompositorVsyncScheduler
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler)
@@ -226,16 +202,17 @@ protected:
 };
 
 class CompositorBridgeParent final : public PCompositorBridgeParent,
                                      public ShadowLayersManager,
                                      public ISurfaceAllocator,
                                      public ShmemAllocator
 {
   friend class CompositorVsyncScheduler;
+  friend class CompositorThreadHolder;
 
 public:
   explicit CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget,
                                   CSSToLayoutDeviceScale aScale,
                                   bool aUseAPZ,
                                   bool aUseExternalSurfaceSize = false,
                                   int aSurfaceWidth = -1, int aSurfaceHeight = -1);
 
@@ -391,37 +368,16 @@ public:
   void InvalidateRemoteLayers();
 
   /**
    * Returns a pointer to the compositor corresponding to the given ID.
    */
   static CompositorBridgeParent* GetCompositor(uint64_t id);
 
   /**
-   * Returns the compositor thread's message loop.
-   *
-   * This message loop is used by CompositorBridgeParent, ImageBridgeParent,
-   * and VRManagerParent
-   */
-  static MessageLoop* CompositorLoop();
-
-  /**
-   * Creates the compositor thread and the global compositor map.
-   */
-  static void StartUp();
-
-  /**
-   * Waits for all [CrossProcess]CompositorBridgeParent's to be gone,
-   * and destroys the compositor thread and global compositor map.
-   *
-   * Does not return until all of that has completed.
-   */
-  static void ShutDown();
-
-  /**
    * Allocate an ID that can be used to refer to a layer tree and
    * associated resources that live only on the compositor thread.
    *
    * Must run on the content main thread.
    */
   static uint64_t AllocateLayerTreeId();
   /**
    * Release compositor-thread resources referred to by |aID|.
@@ -514,21 +470,16 @@ public:
   static void PostInsertVsyncProfilerMarker(mozilla::TimeStamp aVsyncTimestamp);
 
   static void RequestNotifyLayerTreeReady(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
   static void RequestNotifyLayerTreeCleared(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
   static void SwapLayerTreeObservers(uint64_t aLayer, uint64_t aOtherLayer);
 
   float ComputeRenderIntegrity();
 
-  /**
-   * Returns true if the calling thread is the compositor thread.
-   */
-  static bool IsInCompositorThread();
-
   widget::CompositorWidgetProxy* GetWidgetProxy() { return mWidgetProxy; }
 
   void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
 
   /**
    * Creates a new RemoteContentController for aTabId. Should only be called on
    * the main thread.
    *
@@ -579,17 +530,32 @@ protected:
    * Add a compositor to the global compositor map.
    */
   static void AddCompositor(CompositorBridgeParent* compositor, uint64_t* id);
   /**
    * Remove a compositor from the global compositor map.
    */
   static CompositorBridgeParent* RemoveCompositor(uint64_t id);
 
-   /**
+  /**
+   * Creates the global compositor map.
+   */
+  static void Initialize();
+
+  /**
+   * Destroys the compositor thread and global compositor map.
+   */
+  static void Shutdown();
+
+  /**
+   * Finish the shutdown operation on the compositor thread.
+   */
+  static void FinishShutdown();
+
+  /**
    * Return true if current state allows compositing, that is
    * finishing a layers transaction.
    */
   bool CanComposite();
 
   void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
   // The indirect layer tree lock must be held before calling this function.
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorThread.cpp
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=99 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "CompositorThread.h"
+#include "MainThreadUtils.h"
+#include "nsThreadUtils.h"
+#include "CompositorBridgeParent.h"
+#include "mozilla/media/MediaSystemResourceService.h"
+
+namespace mozilla {
+
+namespace gfx {
+// See VRManagerChild.cpp
+void ReleaseVRManagerParentSingleton();
+} // namespace gfx
+
+namespace layers {
+
+static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
+static bool sFinishedCompositorShutDown = false;
+
+// See ImageBridgeChild.cpp
+void ReleaseImageBridgeParentSingleton();
+
+CompositorThreadHolder* GetCompositorThreadHolder()
+{
+  return sCompositorThreadHolder;
+}
+
+base::Thread*
+CompositorThread()
+{
+  return sCompositorThreadHolder
+         ? sCompositorThreadHolder->GetCompositorThread()
+         : nullptr;
+}
+
+/* static */ MessageLoop*
+CompositorThreadHolder::Loop()
+{
+  return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
+}
+
+CompositorThreadHolder*
+CompositorThreadHolder::GetSingleton()
+{
+  return sCompositorThreadHolder;
+}
+
+CompositorThreadHolder::CompositorThreadHolder()
+  : mCompositorThread(CreateCompositorThread())
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_COUNT_CTOR(CompositorThreadHolder);
+}
+
+CompositorThreadHolder::~CompositorThreadHolder()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  MOZ_COUNT_DTOR(CompositorThreadHolder);
+
+  DestroyCompositorThread(mCompositorThread);
+}
+
+/* static */ void
+CompositorThreadHolder::DestroyCompositorThread(base::Thread* aCompositorThread)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
+
+  CompositorBridgeParent::Shutdown();
+  delete aCompositorThread;
+  sFinishedCompositorShutDown = true;
+}
+
+/* static */ base::Thread*
+CompositorThreadHolder::CreateCompositorThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
+
+  base::Thread* compositorThread = new base::Thread("Compositor");
+
+  base::Thread::Options options;
+  /* Timeout values are powers-of-two to enable us get better data.
+     128ms is chosen for transient hangs because 8Hz should be the minimally
+     acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
+  options.transient_hang_timeout = 128; // milliseconds
+  /* 2048ms is chosen for permanent hangs because it's longer than most
+   * Compositor hangs seen in the wild, but is short enough to not miss getting
+   * native hang stacks. */
+  options.permanent_hang_timeout = 2048; // milliseconds
+#if defined(_WIN32)
+  /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As
+   * such the thread is a gui thread, and must process a windows message queue or
+   * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */
+  options.message_loop_type = MessageLoop::TYPE_UI;
+#endif
+
+  if (!compositorThread->StartWithOptions(options)) {
+    delete compositorThread;
+    return nullptr;
+  }
+
+  CompositorBridgeParent::Initialize();
+
+  return compositorThread;
+}
+
+void
+CompositorThreadHolder::Start()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
+  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
+
+  sCompositorThreadHolder = new CompositorThreadHolder();
+}
+
+void
+CompositorThreadHolder::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
+  MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
+
+  ReleaseImageBridgeParentSingleton();
+  gfx::ReleaseVRManagerParentSingleton();
+  MediaSystemResourceService::Shutdown();
+
+  sCompositorThreadHolder = nullptr;
+
+  // No locking is needed around sFinishedCompositorShutDown because it is only
+  // ever accessed on the main thread.
+  while (!sFinishedCompositorShutDown) {
+    NS_ProcessNextEvent(nullptr, true);
+  }
+
+  CompositorBridgeParent::FinishShutdown();
+}
+
+/* static */ bool
+CompositorThreadHolder::IsInCompositorThread()
+{
+  return CompositorThread() &&
+         CompositorThread()->thread_id() == PlatformThread::CurrentId();
+}
+
+} // namespace mozilla
+} // namespace layers
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorThread.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=99 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef mozilla_layers_CompositorThread_h
+#define mozilla_layers_CompositorThread_h
+
+#include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
+#include "base/platform_thread.h"       // for PlatformThreadId
+#include "base/thread.h"                // for Thread
+#include "base/message_loop.h"
+#include "nsISupportsImpl.h"
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+
+namespace mozilla {
+namespace layers {
+
+class CompositorThreadHolder final
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
+
+public:
+  CompositorThreadHolder();
+
+  base::Thread* GetCompositorThread() const {
+    return mCompositorThread;
+  }
+
+  static CompositorThreadHolder* GetSingleton();
+
+  static bool IsActive() {
+    return !!GetSingleton();
+  }
+
+  /**
+   * Creates the compositor thread and the global compositor map.
+   */
+  static void Start();
+
+  /*
+   * Waits for all [CrossProcess]CompositorBridgeParents to shutdown and
+   * releases compositor-thread owned resources.
+   */
+  static void Shutdown();
+
+  static MessageLoop* Loop();
+
+  // Returns true if the calling thread is the compositor thread.
+  static bool IsInCompositorThread();
+
+private:
+  ~CompositorThreadHolder();
+
+  base::Thread* const mCompositorThread;
+
+  static base::Thread* CreateCompositorThread();
+  static void DestroyCompositorThread(base::Thread* aCompositorThread);
+
+  friend class CompositorBridgeParent;
+};
+
+base::Thread* CompositorThread();
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_CompositorThread_h
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -19,17 +19,17 @@
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/AsyncCanvasRenderer.h"
 #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
 #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
-#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "mozilla/layers/LayersMessages.h"  // for CompositableOperation
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "mozilla/layers/PImageContainerChild.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
@@ -839,17 +839,17 @@ bool ImageBridgeChild::StartUpOnThread(T
   MOZ_ASSERT(aThread, "ImageBridge needs a thread.");
   if (sImageBridgeChildSingleton == nullptr) {
     sImageBridgeChildThread = aThread;
     if (!aThread->IsRunning()) {
       aThread->Start();
     }
     sImageBridgeChildSingleton = new ImageBridgeChild();
     sImageBridgeParentSingleton = new ImageBridgeParent(
-      CompositorBridgeParent::CompositorLoop(), nullptr, base::GetCurrentProcId());
+      CompositorThreadHolder::Loop(), nullptr, base::GetCurrentProcId());
     sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton);
     sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
       NewRunnableFunction(CallSendImageBridgeThreadId,
                           sImageBridgeChildSingleton.get()));
     return true;
   } else {
     return false;
   }
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/HalTypes.h"           // for hal::THREAD_PRIORITY_COMPOSITOR
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
 #include "mozilla/layers/CompositableTransactionParent.h"
 #include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply
 #include "mozilla/layers/LayersSurfaces.h"  // for PGrallocBufferParent
 #include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/PImageBridgeParent.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
@@ -195,17 +196,17 @@ ConnectImageBridgeInParentProcess(ImageB
                                   base::ProcessId aOtherPid)
 {
   aBridge->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ParentSide);
 }
 
 /*static*/ PImageBridgeParent*
 ImageBridgeParent::Create(Transport* aTransport, ProcessId aChildProcessId, GeckoChildProcessHost* aProcessHost)
 {
-  MessageLoop* loop = CompositorBridgeParent::CompositorLoop();
+  MessageLoop* loop = CompositorThreadHolder::Loop();
   RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aTransport, aChildProcessId);
 
   if (aProcessHost) {
     bridge->mSubprocess = aProcessHost;
     aProcessHost->AssociateActor();
   }
 
   loop->PostTask(NewRunnableFunction(ConnectImageBridgeInParentProcess,
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -153,16 +153,17 @@ EXPORTS.mozilla.layers += [
     'ImageDataSerializer.h',
     'ipc/APZChild.h',
     'ipc/AsyncTransactionTracker.h',
     'ipc/CompositableForwarder.h',
     'ipc/CompositableTransactionParent.h',
     'ipc/CompositorBridgeChild.h',
     'ipc/CompositorBridgeParent.h',
     'ipc/CompositorLRU.h',
+    'ipc/CompositorThread.h',
     'ipc/FenceUtils.h',
     'ipc/GonkNativeHandle.h',
     'ipc/GonkNativeHandleUtils.h',
     'ipc/ImageBridgeChild.h',
     'ipc/ImageBridgeParent.h',
     'ipc/ImageContainerParent.h',
     'ipc/ISurfaceAllocator.h',
     'ipc/LayerAnimationUtils.h',
@@ -338,16 +339,17 @@ UNIFIED_SOURCES += [
     'ImageLayers.cpp',
     'ipc/APZChild.cpp',
     'ipc/AsyncTransactionTracker.cpp',
     'ipc/CompositableTransactionParent.cpp',
     'ipc/CompositorBench.cpp',
     'ipc/CompositorBridgeChild.cpp',
     'ipc/CompositorBridgeParent.cpp',
     'ipc/CompositorLRU.cpp',
+    'ipc/CompositorThread.cpp',
     'ipc/FenceUtils.cpp',
     'ipc/ImageBridgeChild.cpp',
     'ipc/ImageBridgeParent.cpp',
     'ipc/ImageContainerParent.cpp',
     'ipc/ISurfaceAllocator.cpp',
     'ipc/LayerAnimationUtils.cpp',
     'ipc/LayerTransactionChild.cpp',
     'ipc/LayerTransactionParent.cpp',
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -1242,33 +1242,22 @@ CompositorOGL::DrawQuad(const Rect& aRec
   case EffectTypes::RGB: {
       TexturedEffect* texturedEffect =
           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
       TextureSource *source = texturedEffect->mTexture;
 
       didSetBlendMode = SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied);
 
       gfx::Filter filter = texturedEffect->mFilter;
-      Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform();
 
-#ifdef MOZ_WIDGET_ANDROID
-      gfx::Matrix textureTransform2D;
-      if (filter != gfx::Filter::POINT &&
-          aTransform.Is2DIntegerTranslation() &&
-          textureTransform.Is2D(&textureTransform2D) &&
-          textureTransform2D.HasOnlyIntegerTranslation()) {
-        // On Android we encounter small resampling errors in what should be
-        // pixel-aligned compositing operations. This works around them. This
-        // code should not be needed!
-        filter = gfx::Filter::POINT;
-      }
-#endif
       source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
 
       program->SetTextureUnit(0);
+
+      Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform();
       program->SetTextureTransform(textureTransform);
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
       }
       if (mixBlendBackdrop) {
         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
       }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
 #include "mozilla/layers/CompositorBridgeChild.h"
-#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 
 #include "mozilla/Logging.h"
@@ -863,17 +863,17 @@ gfxPlatform::InitLayersIPC()
       return;
     }
     sLayersIPCIsUp = true;
 
     AsyncTransactionTrackersHolder::Initialize();
 
     if (XRE_IsParentProcess())
     {
-        mozilla::layers::CompositorBridgeParent::StartUp();
+        layers::CompositorThreadHolder::Start();
 #ifdef MOZ_WIDGET_GONK
         SharedBufferManagerChild::StartUp();
 #endif
         mozilla::layers::ImageBridgeChild::StartUp();
         gfx::VRManagerChild::StartUpSameProcess();
     }
 }
 
@@ -900,17 +900,17 @@ gfxPlatform::ShutdownLayersIPC()
         layers::CompositorBridgeChild::ShutDown();
         layers::ImageBridgeChild::ShutDown();
 
 #ifdef MOZ_WIDGET_GONK
         layers::SharedBufferManagerChild::ShutDown();
 #endif
 
         // This has to happen after shutting down the child protocols.
-        layers::CompositorBridgeParent::ShutDown();
+        layers::CompositorThreadHolder::Shutdown();
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
 }
 
 gfxPlatform::~gfxPlatform()
 {
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -131,17 +131,18 @@ enum class DeviceResetReason
   INVALID_CALL,
   OUT_OF_MEMORY,
   FORCED_RESET,
   UNKNOWN
 };
 
 enum class ForcedDeviceResetReason
 {
-  OPENSHAREDHANDLE = 0
+  OPENSHAREDHANDLE = 0,
+  COMPOSITOR_UPDATED,
 };
 
 class gfxPlatform {
     friend class SRGBOverrideObserver;
 
 public:
     typedef mozilla::gfx::Color Color;
     typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
@@ -628,16 +629,18 @@ public:
      */
     static bool PerfWarnings();
 
     void NotifyCompositorCreated(mozilla::layers::LayersBackend aBackend);
     mozilla::layers::LayersBackend GetCompositorBackend() const {
       return mCompositorBackend;
     }
 
+    virtual void CompositorUpdated() {}
+
     // Return information on how child processes should initialize graphics
     // devices. Currently this is only used on Windows.
     virtual void GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut);
 
     // Plugin async drawing support.
     virtual bool SupportsPluginDirectBitmapDrawing() {
       return false;
     }
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -1326,25 +1326,27 @@ gfxUserFontSet::UserFontCache::Entry::Re
                 spec.Truncate(252);
                 spec.Append("...");
             }
             path.AppendPrintf(", url=%s", spec.get());
         }
         if (mPrincipal) {
             nsCOMPtr<nsIURI> uri;
             mPrincipal->GetURI(getter_AddRefs(uri));
-            nsCString spec;
-            uri->GetSpec(spec);
-            if (!spec.IsEmpty()) {
-                // Include a clue as to who loaded this resource. (Note that
-                // because of font entry sharing, other pages may now be using
-                // this resource, and the original page may not even be loaded
-                // any longer.)
-                spec.ReplaceChar('/', '\\');
-                path.AppendPrintf(", principal=%s", spec.get());
+            if (uri) {
+                nsCString spec;
+                uri->GetSpec(spec);
+                if (!spec.IsEmpty()) {
+                    // Include a clue as to who loaded this resource. (Note
+                    // that because of font entry sharing, other pages may now
+                    // be using this resource, and the original page may not
+                    // even be loaded any longer.)
+                    spec.ReplaceChar('/', '\\');
+                    path.AppendPrintf(", principal=%s", spec.get());
+                }
             }
         }
     }
     path.Append(')');
 
     return aCb->
         Callback(EmptyCString(), path,
                  nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -32,17 +32,17 @@
 #include "nsIGfxInfo.h"
 #include "GfxDriverInfo.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "gfxGDIFontList.h"
 #include "gfxGDIFont.h"
 
-#include "mozilla/layers/CompositorBridgeParent.h"   // for CompositorBridgeParent::IsInCompositorThread
+#include "mozilla/layers/CompositorThread.h"
 #include "DeviceManagerD3D9.h"
 #include "mozilla/layers/ReadbackManagerD3D11.h"
 
 #include "WinUtils.h"
 
 #include "gfxDWriteFontList.h"
 #include "gfxDWriteFonts.h"
 #include "gfxDWriteCommon.h"
@@ -62,20 +62,20 @@
 #include "nsMemory.h"
 
 #include <d3d11.h>
 
 #include "nsIMemoryReporter.h"
 #include <winternl.h>
 #include "d3dkmtQueryStatistics.h"
 
+#include "base/thread.h"
 #include "SurfaceCache.h"
 #include "gfxPrefs.h"
 #include "gfxConfig.h"
-
 #include "VsyncSource.h"
 #include "DriverCrashGuard.h"
 #include "mozilla/dom/ContentParent.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
@@ -942,16 +942,23 @@ static DeviceResetReason HResultToResetR
   case E_OUTOFMEMORY:
     return DeviceResetReason::OUT_OF_MEMORY;
   default:
     MOZ_ASSERT(false);
   }
   return DeviceResetReason::UNKNOWN;
 }
 
+void
+gfxWindowsPlatform::CompositorUpdated()
+{
+  ForceDeviceReset(ForcedDeviceResetReason::COMPOSITOR_UPDATED);
+  UpdateRenderMode();
+}
+
 bool
 gfxWindowsPlatform::IsDeviceReset(HRESULT hr, DeviceResetReason* aResetReason)
 {
   if (hr != S_OK) {
     mDeviceResetReason = HResultToResetReason(hr);
     mHasDeviceReset = true;
     if (aResetReason) {
       *aResetReason = mDeviceResetReason;
@@ -1405,17 +1412,17 @@ gfxWindowsPlatform::D3D9DeviceReset() {
 already_AddRefed<DeviceManagerD3D9>
 gfxWindowsPlatform::GetD3D9DeviceManager()
 {
   // We should only create the d3d9 device on the compositor thread
   // or we don't have a compositor thread.
   RefPtr<DeviceManagerD3D9> result;
   if (!mDeviceManager &&
       (!gfxPlatform::UsesOffMainThreadCompositing() ||
-       CompositorBridgeParent::IsInCompositorThread())) {
+       CompositorThreadHolder::IsInCompositorThread())) {
     mDeviceManager = new DeviceManagerD3D9();
     if (!mDeviceManager->Init()) {
       gfxCriticalError() << "[D3D9] Could not Initialize the DeviceManagerD3D9";
       mDeviceManager = nullptr;
     }
   }
 
   MutexAutoLock lock(mDeviceLock);
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -173,16 +173,18 @@ public:
 
     virtual bool CanUseHardwareVideoDecoding() override;
 
     /**
      * Check whether format is supported on a platform or not (if unclear, returns true)
      */
     virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) override;
 
+    virtual void CompositorUpdated() override;
+
     bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) override;
     void SchedulePaintIfDeviceReset() override;
     void UpdateRenderModeIfDeviceReset() override;
 
     mozilla::gfx::BackendType GetContentBackendFor(mozilla::layers::LayersBackend aLayers) override;
 
     // ClearType is not always enabled even when available (e.g. Windows XP)
     // if either of these prefs are enabled and apply, use ClearType rendering
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -5,17 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "VRManagerChild.h"
 #include "VRManagerParent.h"
 #include "VRDeviceProxy.h"
 #include "VRDeviceProxyOrientationFallBack.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
+#include "mozilla/layers/CompositorThread.h" // for CompositorThread
 #include "mozilla/dom/Navigator.h"
 
 namespace mozilla {
 namespace gfx {
 
 static StaticRefPtr<VRManagerChild> sVRManagerChildSingleton;
 static StaticRefPtr<VRManagerParent> sVRManagerParentSingleton;
 
@@ -72,17 +72,17 @@ VRManagerChild::StartUpInChildProcess(Tr
 /*static*/ void
 VRManagerChild::StartUpSameProcess()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
   if (sVRManagerChildSingleton == nullptr) {
     sVRManagerChildSingleton = new VRManagerChild();
     sVRManagerParentSingleton = VRManagerParent::CreateSameProcess();
     sVRManagerChildSingleton->Open(sVRManagerParentSingleton->GetIPCChannel(),
-                                   mozilla::layers::CompositorBridgeParent::CompositorLoop(),
+                                   mozilla::layers::CompositorThreadHolder::Loop(),
                                    mozilla::ipc::ChildSide);
   }
 }
 
 /*static*/ void
 VRManagerChild::ShutDown()
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -5,28 +5,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "VRManagerParent.h"
 #include "mozilla/gfx/PVRManagerParent.h"
 #include "mozilla/ipc/ProtocolTypes.h"
 #include "mozilla/ipc/ProtocolUtils.h"       // for IToplevelProtocol
 #include "mozilla/TimeStamp.h"               // for TimeStamp
-#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/unused.h"
 #include "VRManager.h"
 
 namespace mozilla {
-namespace layers {
-
-// defined in CompositorBridgeParent.cpp
-CompositorThreadHolder* GetCompositorThreadHolder();
-
-} // namespace layers
-
 namespace gfx {
 
 VRManagerParent::VRManagerParent(MessageLoop* aLoop,
                                  Transport* aTransport,
                                  ProcessId aChildProcessId)
 {
   MOZ_COUNT_CTOR(VRManagerParent);
   MOZ_ASSERT(NS_IsMainThread());
@@ -71,36 +64,36 @@ VRManagerParent::ConnectVRManagerInParen
 {
   aVRManager->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ParentSide);
   aVRManager->RegisterWithManager();
 }
 
 /*static*/ VRManagerParent*
 VRManagerParent::CreateCrossProcess(Transport* aTransport, ProcessId aChildProcessId)
 {
-  MessageLoop* loop = mozilla::layers::CompositorBridgeParent::CompositorLoop();
+  MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
   RefPtr<VRManagerParent> vmp = new VRManagerParent(loop, aTransport, aChildProcessId);
   vmp->mSelfRef = vmp;
   loop->PostTask(NewRunnableFunction(ConnectVRManagerInParentProcess,
                                      vmp.get(), aTransport, aChildProcessId));
   return vmp.get();
 }
 
 /*static*/ void
 VRManagerParent::RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager)
 {
   aVRManager->RegisterWithManager();
 }
 
 /*static*/ VRManagerParent*
 VRManagerParent::CreateSameProcess()
 {
-  MessageLoop* loop = mozilla::layers::CompositorBridgeParent::CompositorLoop();
+  MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
   RefPtr<VRManagerParent> vmp = new VRManagerParent(loop, nullptr, base::GetCurrentProcId());
-  vmp->mCompositorThreadHolder = layers::GetCompositorThreadHolder();
+  vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
   vmp->mSelfRef = vmp;
   loop->PostTask(NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get()));
   return vmp.get();
 }
 
 void
 VRManagerParent::DeferredDestroy()
 {
@@ -134,17 +127,17 @@ VRManagerParent::CloneToplevel(const Inf
     }
   }
   return nullptr;
 }
 
 void
 VRManagerParent::OnChannelConnected(int32_t aPid)
 {
-  mCompositorThreadHolder = layers::GetCompositorThreadHolder();
+  mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
 }
 
 bool
 VRManagerParent::RecvRefreshDevices()
 {
   VRManager* vm = VRManager::Get();
   vm->RefreshVRDevices();
 
--- a/gfx/vr/ipc/VRManagerParent.h
+++ b/gfx/vr/ipc/VRManagerParent.h
@@ -3,17 +3,17 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_VR_VRMANAGERPARENT_H
 #define MOZILLA_GFX_VR_VRMANAGERPARENT_H
 
-#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorThreadHolder
+#include "mozilla/layers/CompositorThread.h" // for CompositorThreadHolder
 #include "mozilla/gfx/PVRManagerParent.h" // for PVRManagerParent
 #include "mozilla/ipc/ProtocolUtils.h"    // for IToplevelProtocol
 #include "mozilla/TimeStamp.h"            // for TimeStamp
 #include "gfxVR.h"                        // for VRFieldOfView
 
 namespace mozilla {
 namespace gfx {
 
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -581,17 +581,18 @@ class JS_PUBLIC_API(AutoCheckCannotGC) :
 {
   public:
     AutoCheckCannotGC() : AutoAssertOnGC() {}
     explicit AutoCheckCannotGC(JSRuntime* rt) : AutoAssertOnGC(rt) {}
 } JS_HAZ_GC_INVALIDATED;
 
 /**
  * Unsets the gray bit for anything reachable from |thing|. |kind| should not be
- * JS::TraceKind::Shape. |thing| should be non-null.
+ * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates
+ * if anything was unmarked.
  */
 extern JS_FRIEND_API(bool)
 UnmarkGrayGCThingRecursively(GCCellPtr thing);
 
 } /* namespace JS */
 
 namespace js {
 namespace gc {
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -66,29 +66,47 @@ class JS_PUBLIC_API(JSTracer)
         Tenuring,
         Callback
     };
     bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; }
     bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; }
     bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; }
     bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; }
     inline JS::CallbackTracer* asCallbackTracer();
+#ifdef DEBUG
+    bool checkEdges() { return checkEdges_; }
+#endif
 
   protected:
     JSTracer(JSRuntime* rt, TracerKindTag tag,
              WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
-      : runtime_(rt), weakMapAction_(weakTraceKind), tag_(tag)
+      : runtime_(rt)
+      , weakMapAction_(weakTraceKind)
+#ifdef DEBUG
+      , checkEdges_(true)
+#endif
+      , tag_(tag)
     {}
 
+#ifdef DEBUG
+    // Set whether to check edges are valid in debug builds.
+    void setCheckEdges(bool check) {
+        checkEdges_ = check;
+    }
+#endif
+
   private:
-    JSRuntime*          runtime_;
-    WeakMapTraceKind    weakMapAction_;
+    JSRuntime* runtime_;
+    WeakMapTraceKind weakMapAction_;
+#ifdef DEBUG
+    bool checkEdges_;
+#endif
 
   protected:
-    TracerKindTag       tag_;
+    TracerKindTag tag_;
 };
 
 namespace JS {
 
 class AutoTracingName;
 class AutoTracingIndex;
 class AutoTracingCallback;
 
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -80,17 +80,22 @@ class MOZ_RAII AutoStopVerifyingBarriers
 {
     GCRuntime* gc;
     bool restartPreVerifier;
 
   public:
     AutoStopVerifyingBarriers(JSRuntime* rt, bool isShutdown)
       : gc(&rt->gc)
     {
-        restartPreVerifier = gc->endVerifyPreBarriers() && !isShutdown;
+        if (gc->isVerifyPreBarriersEnabled()) {
+            gc->endVerifyPreBarriers();
+            restartPreVerifier = !isShutdown;
+        } else {
+            restartPreVerifier = false;
+        }
     }
 
     ~AutoStopVerifyingBarriers() {
         // Nasty special case: verification runs a minor GC, which *may* nest
         // inside of an outer minor GC. This is not allowed by the
         // gc::Statistics phase tree. So we pause the "real" GC, if in fact one
         // is in progress.
         gcstats::Phase outer = gc->stats.currentPhase();
@@ -110,18 +115,18 @@ class MOZ_RAII AutoStopVerifyingBarriers
 #else
 struct MOZ_RAII AutoStopVerifyingBarriers
 {
     AutoStopVerifyingBarriers(JSRuntime*, bool) {}
 };
 #endif /* JS_GC_ZEAL */
 
 #ifdef JSGC_HASH_TABLE_CHECKS
-void
-CheckHashTablesAfterMovingGC(JSRuntime* rt);
+void CheckHashTablesAfterMovingGC(JSRuntime* rt);
+void CheckHeapAfterMovingGC(JSRuntime* rt);
 #endif
 
 struct MovingTracer : JS::CallbackTracer
 {
     explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
 
     void onObjectEdge(JSObject** objp) override;
     void onShapeEdge(Shape** shapep) override;
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -189,17 +189,17 @@ class GCSchedulingTunables
     double highFrequencyHeapGrowthMax() const { return highFrequencyHeapGrowthMax_; }
     double highFrequencyHeapGrowthMin() const { return highFrequencyHeapGrowthMin_; }
     double lowFrequencyHeapGrowth() const { return lowFrequencyHeapGrowth_; }
     bool isDynamicMarkSliceEnabled() const { return dynamicMarkSliceEnabled_; }
     bool areRefreshFrameSlicesEnabled() const { return refreshFrameSlicesEnabled_; }
     unsigned minEmptyChunkCount(const AutoLockGC&) const { return minEmptyChunkCount_; }
     unsigned maxEmptyChunkCount() const { return maxEmptyChunkCount_; }
 
-    bool setParameter(JSGCParamKey key, uint32_t value, const AutoLockGC& lock);
+    MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value, const AutoLockGC& lock);
 };
 
 /*
  * GC Scheduling Overview
  * ======================
  *
  * Scheduling GC's in SpiderMonkey/Firefox is tremendously complicated because
  * of the large number of subtle, cross-cutting, and widely dispersed factors
@@ -579,59 +579,61 @@ class ChainedIter
 typedef HashMap<Value*, const char*, DefaultHasher<Value*>, SystemAllocPolicy> RootedValueMap;
 
 using AllocKinds = mozilla::EnumSet<AllocKind>;
 
 class GCRuntime
 {
   public:
     explicit GCRuntime(JSRuntime* rt);
-    bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
+    MOZ_MUST_USE bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
     void finishRoots();
     void finish();
 
     inline bool hasZealMode(ZealMode mode);
     inline void clearZealMode(ZealMode mode);
     inline bool upcomingZealousGC();
     inline bool needZealousGC();
 
-    bool addRoot(Value* vp, const char* name);
+    MOZ_MUST_USE bool addRoot(Value* vp, const char* name);
     void removeRoot(Value* vp);
     void setMarkStackLimit(size_t limit, AutoLockGC& lock);
 
-    bool setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock);
+    MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock);
     uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
 
-    bool triggerGC(JS::gcreason::Reason reason);
+    MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
     void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
+    // The return value indicates if we were able to do the GC.
     bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason);
-    bool maybeGC(Zone* zone);
+    MOZ_MUST_USE bool maybeGC(Zone* zone);
     void maybePeriodicFullGC();
     void minorGC(JS::gcreason::Reason reason) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC);
         minorGCImpl(reason, nullptr);
     }
     void minorGC(JSContext* cx, JS::gcreason::Reason reason);
     void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_EVICT_NURSERY);
         minorGCImpl(reason, nullptr);
     }
+    // The return value indicates whether a major GC was performed.
     bool gcIfRequested(JSContext* cx = nullptr);
     void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
     void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
     void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0);
     void finishGC(JS::gcreason::Reason reason);
     void abortGC();
     void startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget);
     void debugGCSlice(SliceBudget& budget);
 
     void triggerFullGCForAtoms() {
         MOZ_ASSERT(fullGCForAtomsRequested_);
         fullGCForAtomsRequested_ = false;
-        triggerGC(JS::gcreason::ALLOC_TRIGGER);
+        MOZ_RELEASE_ASSERT(triggerGC(JS::gcreason::ALLOC_TRIGGER));
     }
 
     void runDebugGC();
     inline void poke();
 
     enum TraceOrMarkRuntime {
         TraceRuntime,
         MarkRuntime
@@ -750,36 +752,38 @@ class GCRuntime
     void disableGenerationalGC();
     void enableGenerationalGC();
 
     void disableCompactingGC();
     void enableCompactingGC();
     bool isCompactingGCEnabled() const;
 
     void setGrayRootsTracer(JSTraceDataOp traceOp, void* data);
-    bool addBlackRootsTracer(JSTraceDataOp traceOp, void* data);
+    MOZ_MUST_USE bool addBlackRootsTracer(JSTraceDataOp traceOp, void* data);
     void removeBlackRootsTracer(JSTraceDataOp traceOp, void* data);
 
     void setMaxMallocBytes(size_t value);
     int32_t getMallocBytes() const { return mallocBytesUntilGC; }
     void resetMallocBytes();
     bool isTooMuchMalloc() const { return mallocBytesUntilGC <= 0; }
     void updateMallocCounter(JS::Zone* zone, size_t nbytes);
     void onTooMuchMalloc();
 
     void setGCCallback(JSGCCallback callback, void* data);
     void callGCCallback(JSGCStatus status) const;
     void setObjectsTenuredCallback(JSObjectsTenuredCallback callback,
                                    void* data);
     void callObjectsTenuredCallback();
-    bool addFinalizeCallback(JSFinalizeCallback callback, void* data);
+    MOZ_MUST_USE bool addFinalizeCallback(JSFinalizeCallback callback, void* data);
     void removeFinalizeCallback(JSFinalizeCallback func);
-    bool addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, void* data);
+    MOZ_MUST_USE bool addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback,
+                                                      void* data);
     void removeWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback);
-    bool addWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback, void* data);
+    MOZ_MUST_USE bool addWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback,
+                                                        void* data);
     void removeWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback);
     JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
     JS::GCNurseryCollectionCallback setNurseryCollectionCallback(
         JS::GCNurseryCollectionCallback callback);
 
     void setFullCompartmentChecks(bool enable);
 
     bool isManipulatingDeadZones() { return manipulatingDeadZones; }
@@ -836,17 +840,17 @@ class GCRuntime
     const ChunkPool& emptyChunks(const AutoLockGC& lock) const { return emptyChunks_; }
     typedef ChainedIter<Chunk*, ChunkPool::Iter, ChunkPool::Iter> NonEmptyChunksIter;
     NonEmptyChunksIter allNonEmptyChunks() {
         return NonEmptyChunksIter(ChunkPool::Iter(availableChunks_), ChunkPool::Iter(fullChunks_));
     }
 
 #ifdef JS_GC_ZEAL
     void startVerifyPreBarriers();
-    bool endVerifyPreBarriers();
+    void endVerifyPreBarriers();
     void finishVerifier();
     bool isVerifyPreBarriersEnabled() const { return !!verifyPreData; }
 #else
     bool isVerifyPreBarriersEnabled() const { return false; }
 #endif
 
     // Free certain LifoAlloc blocks from the background sweep thread.
     void freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo);
@@ -855,17 +859,17 @@ class GCRuntime
     // Public here for ReleaseArenaLists and FinalizeTypedArenas.
     void releaseArena(Arena* arena, const AutoLockGC& lock);
 
     void releaseHeldRelocatedArenas();
     void releaseHeldRelocatedArenasWithoutUnlocking(const AutoLockGC& lock);
 
     // Allocator
     template <AllowGC allowGC>
-    bool checkAllocatorState(JSContext* cx, AllocKind kind);
+    MOZ_MUST_USE bool checkAllocatorState(JSContext* cx, AllocKind kind);
     template <AllowGC allowGC>
     JSObject* tryNewNurseryObject(JSContext* cx, size_t thingSize, size_t nDynamicSlots,
                                   const Class* clasp);
     template <AllowGC allowGC>
     static JSObject* tryNewTenuredObject(ExclusiveContext* cx, AllocKind kind, size_t thingSize,
                                          size_t nDynamicSlots);
     template <typename T, AllowGC allowGC>
     static T* tryNewTenuredThing(ExclusiveContext* cx, AllocKind kind, size_t thingSize);
@@ -883,17 +887,17 @@ class GCRuntime
     // For ArenaLists::allocateFromArena()
     friend class ArenaLists;
     Chunk* pickChunk(const AutoLockGC& lock,
                      AutoMaybeStartBackgroundAllocation& maybeStartBGAlloc);
     Arena* allocateArena(Chunk* chunk, Zone* zone, AllocKind kind, const AutoLockGC& lock);
     void arenaAllocatedDuringGC(JS::Zone* zone, Arena* arena);
 
     // Allocator internals
-    bool gcIfNeededPerAllocation(JSContext* cx);
+    MOZ_MUST_USE bool gcIfNeededPerAllocation(JSContext* cx);
     template <typename T>
     static void checkIncrementalZoneState(ExclusiveContext* cx, T* t);
     static void* refillFreeListFromAnyThread(ExclusiveContext* cx, AllocKind thingKind,
                                              size_t thingSize);
     static void* refillFreeListFromMainThread(JSContext* cx, AllocKind thingKind,
                                               size_t thingSize);
     static void* refillFreeListOffMainThread(ExclusiveContext* cx, AllocKind thingKind);
 
@@ -916,42 +920,43 @@ class GCRuntime
     void resetIncrementalGC(const char* reason);
 
     // Assert if the system state is such that we should never
     // receive a request to do GC work.
     void checkCanCallAPI();
 
     // Check if the system state is such that GC has been supressed
     // or otherwise delayed.
-    bool checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason);
+    MOZ_MUST_USE bool checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason);
 
     gcstats::ZoneGCStats scanZonesBeforeGC();
     void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
-    bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason);
+    MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget,
+                              JS::gcreason::Reason reason);
     void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason);
 
     void pushZealSelectedObjects();
     void purgeRuntime();
-    bool beginMarkPhase(JS::gcreason::Reason reason);
+    MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason);
     bool shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime,
                                JS::gcreason::Reason reason);
     void bufferGrayRoots();
     void markCompartments();
     IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase);
     template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);
     void markWeakReferencesInCurrentGroup(gcstats::Phase phase);
     template <class ZoneIterT, class CompartmentIterT> void markGrayReferences(gcstats::Phase phase);
     void markBufferedGrayRoots(JS::Zone* zone);
     void markGrayReferencesInCurrentGroup(gcstats::Phase phase);
     void markAllWeakReferences(gcstats::Phase phase);
     void markAllGrayReferences(gcstats::Phase phase);
 
     void beginSweepPhase(bool lastGC);
     void findZoneGroups();
-    bool findZoneEdgesForWeakMaps();
+    MOZ_MUST_USE bool findZoneEdgesForWeakMaps();
     void getNextZoneGroup();
     void endMarkingZoneGroup();
     void beginSweepingZoneGroup();
     bool shouldReleaseObservedTypes();
     void endSweepingZoneGroup();
     IncrementalProgress sweepPhase(SliceBudget& sliceBudget);
     void endSweepPhase(bool lastGC);
     void sweepZones(FreeOp* fop, bool lastGC);
@@ -962,18 +967,18 @@ class GCRuntime
     void sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadType threadType);
     void assertBackgroundSweepingFinished();
     bool shouldCompact();
     void beginCompactPhase();
     IncrementalProgress compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget);
     void endCompactPhase(JS::gcreason::Reason reason);
     void sweepTypesAfterCompacting(Zone* zone);
     void sweepZoneAfterCompacting(Zone* zone);
-    bool relocateArenas(Zone* zone, JS::gcreason::Reason reason, Arena*& relocatedListOut,
-                        SliceBudget& sliceBudget);
+    MOZ_MUST_USE bool relocateArenas(Zone* zone, JS::gcreason::Reason reason,
+                                     Arena*& relocatedListOut, SliceBudget& sliceBudget);
     void updateTypeDescrObjects(MovingTracer* trc, Zone* zone);
     void updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, size_t bgTaskCount);
     void updateAllCellPointers(MovingTracer* trc, Zone* zone);
     void updatePointersToRelocatedCells(Zone* zone);
     void protectAndHoldArenas(Arena* arenaList);
     void unprotectHeldRelocatedArenas();
     void releaseRelocatedArenas(Arena* arenaList);
     void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, const AutoLockGC& lock);
@@ -1042,16 +1047,18 @@ class GCRuntime
     // An incrementing id used to assign unique ids to cells that require one.
     mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> nextCellUniqueId_;
 
     /*
      * Number of the committed arenas in all GC chunks including empty chunks.
      */
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
     VerifyPreTracer* verifyPreData;
+
+  private:
     bool chunkAllocationSinceLastGC;
     int64_t nextFullGCTime;
     int64_t lastGCTime;
 
     JSGCMode mode;
 
     mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
 
--- a/js/src/gc/GCTrace.h
+++ b/js/src/gc/GCTrace.h
@@ -12,33 +12,33 @@
 namespace js {
 
 class ObjectGroup;
 
 namespace gc {
 
 #ifdef JS_GC_TRACE
 
-extern bool InitTrace(GCRuntime& gc);
+extern MOZ_MUST_USE bool InitTrace(GCRuntime& gc);
 extern void FinishTrace();
 extern bool TraceEnabled();
 extern void TraceNurseryAlloc(Cell* thing, size_t size);
 extern void TraceTenuredAlloc(Cell* thing, AllocKind kind);
 extern void TraceCreateObject(JSObject* object);
 extern void TraceMinorGCStart();
 extern void TracePromoteToTenured(Cell* src, Cell* dst);
 extern void TraceMinorGCEnd();
 extern void TraceMajorGCStart();
 extern void TraceTenuredFinalize(Cell* thing);
 extern void TraceMajorGCEnd();
 extern void TraceTypeNewScript(js::ObjectGroup* group);
 
 #else
 
-inline bool InitTrace(GCRuntime& gc) { return true; }
+inline MOZ_MUST_USE bool InitTrace(GCRuntime& gc) { return true; }
 inline void FinishTrace() {}
 inline bool TraceEnabled() { return false; }
 inline void TraceNurseryAlloc(Cell* thing, size_t size) {}
 inline void TraceTenuredAlloc(Cell* thing, AllocKind kind) {}
 inline void TraceCreateObject(JSObject* object) {}
 inline void TraceMinorGCStart() {}
 inline void TracePromoteToTenured(Cell* src, Cell* dst) {}
 inline void TraceMinorGCEnd() {}
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -48,16 +48,17 @@ extern bool
 RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone);
 
 // Barriers can't be triggered during backend Ion compilation, which may run on
 // a helper thread.
 extern bool
 CurrentThreadIsIonCompiling();
 #endif
 
+// The return value indicates if anything was unmarked.
 extern bool
 UnmarkGrayCellRecursively(gc::Cell* cell, JS::TraceKind kind);
 
 extern void
 TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, const char* name);
 
 namespace gc {
 
@@ -290,16 +291,17 @@ class TenuredCell : public Cell
 {
   public:
     // Construct a TenuredCell from a void*, making various sanity assertions.
     static MOZ_ALWAYS_INLINE TenuredCell* fromPointer(void* ptr);
     static MOZ_ALWAYS_INLINE const TenuredCell* fromPointer(const void* ptr);
 
     // Mark bit management.
     MOZ_ALWAYS_INLINE bool isMarked(uint32_t color = BLACK) const;
+    // The return value indicates if the cell went from unmarked to marked.
     MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
     MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
     MOZ_ALWAYS_INLINE void copyMarkBitsFrom(const TenuredCell* src);
 
     // Note: this is in TenuredCell because JSObject subclasses are sometimes
     // used tagged.
     static MOZ_ALWAYS_INLINE bool isNullLike(const Cell* thing) { return !thing; }
 
@@ -872,16 +874,17 @@ struct ChunkBitmap
     }
 
     MOZ_ALWAYS_INLINE MOZ_TSAN_BLACKLIST bool isMarked(const Cell* cell, uint32_t color) {
         uintptr_t* word, mask;
         getMarkWordAndMask(cell, color, &word, &mask);
         return *word & mask;
     }
 
+    // The return value indicates if the cell went from unmarked to marked.
     MOZ_ALWAYS_INLINE bool markIfUnmarked(const Cell* cell, uint32_t color) {
         uintptr_t* word, mask;
         getMarkWordAndMask(cell, BLACK, &word, &mask);
         if (*word & mask)
             return false;
         *word |= mask;
         if (color != BLACK) {
             /*
@@ -990,17 +993,17 @@ struct Chunk
         return info.trailer.storeBuffer;
     }
 
     Arena* allocateArena(JSRuntime* rt, JS::Zone* zone, AllocKind kind, const AutoLockGC& lock);
 
     void releaseArena(JSRuntime* rt, Arena* arena, const AutoLockGC& lock);
     void recycleArena(Arena* arena, SortedArenaList& dest, size_t thingsPerArena);
 
-    bool decommitOneFreeArena(JSRuntime* rt, AutoLockGC& lock);
+    MOZ_MUST_USE bool decommitOneFreeArena(JSRuntime* rt, AutoLockGC& lock);
     void decommitAllArenasWithoutUnlocking(const AutoLockGC& lock);
 
     static Chunk* allocate(JSRuntime* rt);
 
   private:
     inline void init(JSRuntime* rt);
 
     void decommitAllArenas(JSRuntime* rt);
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -176,16 +176,19 @@ template <> bool ThingIsPermanentAtomOrW
 template<typename T>
 void
 js::CheckTracedThing(JSTracer* trc, T* thing)
 {
 #ifdef DEBUG
     MOZ_ASSERT(trc);
     MOZ_ASSERT(thing);
 
+    if (!trc->checkEdges())
+        return;
+
     thing = MaybeForwarded(thing);
 
     /* This function uses data that's not available in the nursery. */
     if (IsInsideNursery(thing))
         return;
 
     MOZ_ASSERT_IF(!IsMovingTracer(trc) && !trc->isTenuringTracer(), !IsForwarded(thing));
 
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -82,33 +82,33 @@ class MarkStack
     ptrdiff_t position() const { return tos_ - stack_; }
 
     void setStack(uintptr_t* stack, size_t tosIndex, size_t capacity) {
         stack_ = stack;
         tos_ = stack + tosIndex;
         end_ = stack + capacity;
     }
 
-    bool init(JSGCMode gcMode);
+    MOZ_MUST_USE bool init(JSGCMode gcMode);
 
     void setBaseCapacity(JSGCMode mode);
     size_t maxCapacity() const { return maxCapacity_; }
     void setMaxCapacity(size_t maxCapacity);
 
-    bool push(uintptr_t item) {
+    MOZ_MUST_USE bool push(uintptr_t item) {
         if (tos_ == end_) {
             if (!enlarge(1))
                 return false;
         }
         MOZ_ASSERT(tos_ < end_);
         *tos_++ = item;
         return true;
     }
 
-    bool push(uintptr_t item1, uintptr_t item2, uintptr_t item3) {
+    MOZ_MUST_USE bool push(uintptr_t item1, uintptr_t item2, uintptr_t item3) {
         uintptr_t* nextTos = tos_ + 3;
         if (nextTos > end_) {
             if (!enlarge(3))
                 return false;
             nextTos = tos_ + 3;
         }
         MOZ_ASSERT(nextTos <= end_);
         tos_[0] = item1;
@@ -125,17 +125,17 @@ class MarkStack
     uintptr_t pop() {
         MOZ_ASSERT(!isEmpty());
         return *--tos_;
     }
 
     void reset();
 
     /* Grow the stack, ensuring there is space for at least count elements. */
-    bool enlarge(unsigned count);
+    MOZ_MUST_USE bool enlarge(unsigned count);
 
     void setGCMode(JSGCMode gcMode);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
 namespace gc {
 
@@ -163,17 +163,17 @@ using WeakKeyTable = OrderedHashMap<JS::
                                     js::SystemAllocPolicy>;
 
 } /* namespace gc */
 
 class GCMarker : public JSTracer
 {
   public:
     explicit GCMarker(JSRuntime* rt);
-    bool init(JSGCMode gcMode);
+    MOZ_MUST_USE bool init(JSGCMode gcMode);
 
     void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
     size_t maxCapacity() const { return stack.maxCapacity(); }
 
     void start();
     void stop();
     void reset();
 
@@ -211,26 +211,26 @@ class GCMarker : public JSTracer
     void abortLinearWeakMarking() {
         leaveWeakMarkingMode();
         linearWeakMarkingDisabled_ = true;
     }
 
     void delayMarkingArena(gc::Arena* arena);
     void delayMarkingChildren(const void* thing);
     void markDelayedChildren(gc::Arena* arena);
-    bool markDelayedChildren(SliceBudget& budget);
+    MOZ_MUST_USE bool markDelayedChildren(SliceBudget& budget);
     bool hasDelayedChildren() const {
         return !!unmarkedArenaStackTop;
     }
 
     bool isDrained() {
         return isMarkStackEmpty() && !unmarkedArenaStackTop;
     }
 
-    bool drainMarkStack(SliceBudget& budget);
+    MOZ_MUST_USE bool drainMarkStack(SliceBudget& budget);
 
     void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
 #ifdef DEBUG
     bool shouldCheckCompartments() { return strictCompartmentChecking; }
 #endif
@@ -284,17 +284,17 @@ class GCMarker : public JSTracer
 
     // We may not have concrete types yet, so this has to be outside the header.
     template <typename T>
     void dispatchToTraceChildren(T* thing);
 
     // Mark the given GC thing, but do not trace its children. Return true
     // if the thing became marked.
     template <typename T>
-    bool mark(T* thing);
+    MOZ_MUST_USE bool mark(T* thing);
 
     void pushTaggedPtr(StackTag tag, void* ptr) {
         checkZone(ptr);
         uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
         MOZ_ASSERT(!(addr & StackTagMask));
         if (!stack.push(addr | uintptr_t(tag)))
             delayMarkingChildren(ptr);
     }
@@ -314,17 +314,17 @@ class GCMarker : public JSTracer
         if (!stack.push(endAddr, startAddr, tagged))
             delayMarkingChildren(obj);
     }
 
     bool isMarkStackEmpty() {
         return stack.isEmpty();
     }
 
-    bool restoreValueArray(JSObject* obj, void** vpp, void** endp);
+    MOZ_MUST_USE bool restoreValueArray(JSObject* obj, void** vpp, void** endp);
     void saveValueRanges();
     inline void processMarkStackTop(SliceBudget& budget);
 
     /* The mark stack. Pointers in this stack are "gray" in the GC sense. */
     MarkStack stack;
 
     /* The color is only applied to objects and functions. */
     uint32_t color;
@@ -446,16 +446,17 @@ struct RewrapTaggedPointer<Value, T>
 {
     static Value wrap(typename IsPrivateGCThingInValue<T>::Type* thing) {
         return JS::PrivateGCThingValue(thing);
     }
 };
 
 } /* namespace gc */
 
+// The return value indicates if anything was unmarked.
 bool
 UnmarkGrayShapeRecursively(Shape* shape);
 
 template<typename T>
 void
 CheckTracedThing(JSTracer* trc, T* thing);
 
 template<typename T>
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -257,24 +257,23 @@ MarkPagesUnused(void* p, size_t size)
     if (!DecommitEnabled())
         return true;
 
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     LPVOID p2 = MapMemoryAt(p, size, MEM_RESET);
     return p2 == p;
 }
 
-bool
+void
 MarkPagesInUse(void* p, size_t size)
 {
     if (!DecommitEnabled())
-        return true;
+        return;
 
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
-    return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     PROCESS_MEMORY_COUNTERS pmc;
     if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
         return 0;
@@ -315,17 +314,16 @@ MarkPagesUnused(void* p, size_t size)
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     return true;
 }
 
 bool
 MarkPagesInUse(void* p, size_t size)
 {
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
-    return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     // GetProcessMemoryInfo is unavailable.
     return 0;
 }
@@ -394,20 +392,19 @@ MarkPagesUnused(void* p, size_t size)
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     return true;
 }
 
 bool
 MarkPagesInUse(void* p, size_t size)
 {
     if (!DecommitEnabled())
-        return true;
+        return;
 
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
-    return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     return 0;
 }
 
@@ -662,24 +659,23 @@ MarkPagesUnused(void* p, size_t size)
     if (!DecommitEnabled())
         return false;
 
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
     int result = madvise(p, size, MADV_DONTNEED);
     return result != -1;
 }
 
-bool
+void
 MarkPagesInUse(void* p, size_t size)
 {
     if (!DecommitEnabled())
-        return true;
+        return;
 
     MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
-    return true;
 }
 
 size_t
 GetPageFaultCount()
 {
     struct rusage usage;
     int err = getrusage(RUSAGE_SELF, &usage);
     if (err)
--- a/js/src/gc/Memory.h
+++ b/js/src/gc/Memory.h
@@ -24,17 +24,17 @@ void UnmapPages(void* p, size_t size);
 
 // Tell the OS that the given pages are not in use, so they should not be
 // written to a paging file. This may be a no-op on some platforms.
 bool MarkPagesUnused(void* p, size_t size);
 
 // Undo |MarkPagesUnused|: tell the OS that the given pages are of interest
 // and should be paged in and out normally. This may be a no-op on some
 // platforms.
-bool MarkPagesInUse(void* p, size_t size);
+void MarkPagesInUse(void* p, size_t size);
 
 // Returns #(hard faults) + #(soft faults)
 size_t GetPageFaultCount();
 
 // Allocate memory mapped content.
 // The offset must be aligned according to alignment requirement.
 void* AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment);
 
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -497,16 +497,23 @@ js::Nursery::collect(JSRuntime* rt, JS::
     // Make sure hashtables have been updated after the collection.
     TIME_START(checkHashTables);
 #ifdef JS_GC_ZEAL
     if (rt->hasZealMode(ZealMode::CheckHashTablesOnMinorGC))
         CheckHashTablesAfterMovingGC(rt);
 #endif
     TIME_END(checkHashTables);
 
+    TIME_START(checkHeap);
+#ifdef JS_GC_ZEAL
+    if (rt->hasZealMode(ZealMode::CheckHeapOnMovingGC))
+        CheckHeapAfterMovingGC(rt);
+#endif
+    TIME_END(checkHeap);
+
     // Resize the nursery.
     TIME_START(resize);
     double promotionRate = mover.tenuredSize / double(allocationEnd() - start());
     if (promotionRate > 0.05)
         growAllocableSpace();
     else if (promotionRate < 0.01)
         shrinkAllocableSpace();
     TIME_END(resize);
@@ -547,16 +554,17 @@ js::Nursery::collect(JSRuntime* rt, JS::
         } PrintList[] = {
             {"canIon", TIME_TOTAL(cancelIonCompilations)},
             {"mkVals", TIME_TOTAL(traceValues)},
             {"mkClls", TIME_TOTAL(traceCells)},
             {"mkSlts", TIME_TOTAL(traceSlots)},
             {"mcWCll", TIME_TOTAL(traceWholeCells)},
             {"mkGnrc", TIME_TOTAL(traceGenericEntries)},
             {"ckTbls", TIME_TOTAL(checkHashTables)},
+            {"ckHeap", TIME_TOTAL(checkHeap)},
             {"mkRntm", TIME_TOTAL(markRuntime)},
             {"mkDbgr", TIME_TOTAL(markDebugger)},
             {"clrNOC", TIME_TOTAL(clearNewObjectCache)},
             {"collct", TIME_TOTAL(collectToFP)},
             {" tenCB", TIME_TOTAL(objectsTenuredCallback)},
             {"swpABO", TIME_TOTAL(sweepArrayBufferViewList)},
             {"updtIn", TIME_TOTAL(updateJitActivations)},
             {"frSlts", TIME_TOTAL(freeMallocedBuffers)},
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -105,17 +105,17 @@ class Nursery
         numActiveChunks_(0),
         numNurseryChunks_(0),
         profileThreshold_(0),
         enableProfiling_(false),
         freeMallocedBuffersTask(nullptr)
     {}
     ~Nursery();
 
-    bool init(uint32_t maxNurseryBytes);
+    MOZ_MUST_USE bool init(uint32_t maxNurseryBytes);
 
     bool exists() const { return numNurseryChunks_ != 0; }
     size_t numChunks() const { return numNurseryChunks_; }
     size_t nurserySize() const { return numNurseryChunks_ << ChunkShift; }
 
     void enable();
     void disable();
     bool isEnabled() const { return numActiveChunks_ != 0; }
@@ -166,34 +166,34 @@ class Nursery
      */
     void collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList* pretenureGroups);
 
     /*
      * Check if the thing at |*ref| in the Nursery has been forwarded. If so,
      * sets |*ref| to the new location of the object and returns true. Otherwise
      * returns false and leaves |*ref| unset.
      */
-    MOZ_ALWAYS_INLINE bool getForwardedPointer(JSObject** ref) const;
+    MOZ_ALWAYS_INLINE MOZ_MUST_USE bool getForwardedPointer(JSObject** ref) const;
 
     /* Forward a slots/elements pointer stored in an Ion frame. */
     void forwardBufferPointer(HeapSlot** pSlotsElems);
 
     void maybeSetForwardingPointer(JSTracer* trc, void* oldData, void* newData, bool direct) {
         if (trc->isTenuringTracer() && isInside(oldData))
             setForwardingPointer(oldData, newData, direct);
     }
 
     /* Mark a malloced buffer as no longer needing to be freed. */
     void removeMallocedBuffer(void* buffer) {
         mallocedBuffers.remove(buffer);
     }
 
     void waitBackgroundFreeEnd();
 
-    bool addedUniqueIdToCell(gc::Cell* cell) {
+    MOZ_MUST_USE bool addedUniqueIdToCell(gc::Cell* cell) {
         if (!IsInsideNursery(cell) || !isEnabled())
             return true;
         MOZ_ASSERT(cellsWithUid_.initialized());
         MOZ_ASSERT(!cellsWithUid_.has(cell));
         return cellsWithUid_.put(cell);
     }
 
     size_t sizeOfHeapCommitted() const {
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -155,32 +155,32 @@ struct Statistics
      * DAGs, this decision should be reconsidered.
      */
     static const size_t MaxMultiparentPhases = 6;
     static const size_t NumTimingArrays = MaxMultiparentPhases + 1;
 
     /* Create a convenient type for referring to tables of phase times. */
     using PhaseTimeTable = int64_t[NumTimingArrays][PHASE_LIMIT];
 
-    static bool initialize();
+    static MOZ_MUST_USE bool initialize();
 
     explicit Statistics(JSRuntime* rt);
     ~Statistics();
 
     void beginPhase(Phase phase);
     void endPhase(Phase phase);
     void endParallelPhase(Phase phase, const GCParallelTask* task);
 
     void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
                     SliceBudget budget, JS::gcreason::Reason reason);
     void endSlice();
     void setSliceCycleCount(unsigned cycleCount);
 
-    bool startTimingMutator();
-    bool stopTimingMutator(double& mutator_ms, double& gc_ms);
+    MOZ_MUST_USE bool startTimingMutator();
+    MOZ_MUST_USE bool stopTimingMutator(double& mutator_ms, double& gc_ms);
 
     void reset(const char* reason) {
         if (!aborted)
             slices.back().resetReason = reason;
     }
 
     void nonincremental(const char* reason) { nonincrementalReason_ = reason; }
 
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -61,32 +61,30 @@ StoreBuffer::disable()
     if (!enabled_)
         return;
 
     aboutToOverflow_ = false;
 
     enabled_ = false;
 }
 
-bool
+void
 StoreBuffer::clear()
 {
     if (!enabled_)
-        return true;
+        return;
 
     aboutToOverflow_ = false;
     cancelIonCompilations_ = false;
 
     bufferVal.clear();
     bufferCell.clear();
     bufferSlot.clear();
     bufferWholeCell.clear();
     bufferGeneric.clear();
-
-    return true;
 }
 
 void
 StoreBuffer::setAboutToOverflow()
 {
     if (!aboutToOverflow_) {
         aboutToOverflow_ = true;
         runtime_->gc.stats.count(gcstats::STAT_STOREBUFFER_OVERFLOW);
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -69,17 +69,17 @@ class StoreBuffer
         T last_;
 
         /* Maximum number of entries before we request a minor GC. */
         const static size_t MaxEntries = 48 * 1024 / sizeof(T);
 
         explicit MonoTypeBuffer() : last_(T()) {}
         ~MonoTypeBuffer() { stores_.finish(); }
 
-        bool init() {
+        MOZ_MUST_USE bool init() {
             if (!stores_.initialized() && !stores_.init())
                 return false;
             clear();
             return true;
         }
 
         void clear() {
             last_ = T();
@@ -136,17 +136,17 @@ class StoreBuffer
 
     struct GenericBuffer
     {
         LifoAlloc* storage_;
 
         explicit GenericBuffer() : storage_(nullptr) {}
         ~GenericBuffer() { js_delete(storage_); }
 
-        bool init() {
+        MOZ_MUST_USE bool init() {
             if (!storage_)
                 storage_ = js_new<LifoAlloc>(LifoAllocBlockSize);
             clear();
             return bool(storage_);
         }
 
         void clear() {
             if (!storage_)
@@ -405,17 +405,17 @@ class StoreBuffer
 #endif
     {
     }
 
     bool enable();
     void disable();
     bool isEnabled() const { return enabled_; }
 
-    bool clear();
+    void clear();
 
     /* Get the overflowed status. */
     bool isAboutToOverflow() const { return aboutToOverflow_; }
 
     bool cancelIonCompilations() const { return cancelIonCompilations_; }
 
     /* Insert a single edge into the buffer/remembered set. */
     void putValue(JS::Value* vp) { put(bufferVal, ValueEdge(vp)); }
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -3,16 +3,18 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_VALGRIND
 # include <valgrind/memcheck.h>
 #endif
 
+#include "mozilla/IntegerPrintfMacros.h"
+
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsprf.h"
 
 #include "gc/GCInternals.h"
 #include "gc/Zone.h"
 #include "js/GCAPI.h"
 #include "js/HashTable.h"
@@ -297,23 +299,23 @@ AssertMarkedOrAllocated(const EdgeValue&
         return;
 
     char msgbuf[1024];
     JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", edge.label);
     MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
     MOZ_CRASH();
 }
 
-bool
+void
 gc::GCRuntime::endVerifyPreBarriers()
 {
     VerifyPreTracer* trc = verifyPreData;
 
     if (!trc)
-        return false;
+        return;
 
     MOZ_ASSERT(!JS::IsGenerationalGCEnabled(rt));
 
     AutoPrepareForTracing prep(rt, SkipAtoms);
 
     bool compartmentCreated = false;
 
     /* We need to disable barriers before tracing, which may invoke barriers. */
@@ -352,17 +354,16 @@ gc::GCRuntime::endVerifyPreBarriers()
             node = NextNode(node);
         }
     }
 
     marker.reset();
     marker.stop();
 
     js_delete(trc);
-    return true;
 }
 
 /*** Barrier Verifier Scheduling ***/
 
 void
 gc::GCRuntime::verifyPreBarriers()
 {
     if (verifyPreData)
@@ -409,8 +410,128 @@ js::gc::GCRuntime::finishVerifier()
 {
     if (verifyPreData) {
         js_delete(verifyPreData);
         verifyPreData = nullptr;
     }
 }
 
 #endif /* JS_GC_ZEAL */
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+
+class CheckHeapTracer : public JS::CallbackTracer
+{
+  public:
+    explicit CheckHeapTracer(JSRuntime* rt);
+    bool init();
+    bool check();
+
+  private:
+    void onChild(const JS::GCCellPtr& thing) override;
+
+    struct WorkItem {
+        WorkItem(JS::GCCellPtr thing, const char* name, int parentIndex)
+          : thing(thing), name(name), parentIndex(parentIndex), processed(false)
+        {}
+
+        JS::GCCellPtr thing;
+        const char* name;
+        int parentIndex;
+        bool processed;
+    };
+
+    JSRuntime* rt;
+    bool oom;
+    size_t failures;
+    HashSet<Cell*, DefaultHasher<Cell*>, SystemAllocPolicy> visited;
+    Vector<WorkItem, 0, SystemAllocPolicy> stack;
+    int parentIndex;
+};
+
+CheckHeapTracer::CheckHeapTracer(JSRuntime* rt)
+  : CallbackTracer(rt, TraceWeakMapKeysValues),
+    rt(rt),
+    oom(false),
+    failures(0),
+    parentIndex(-1)
+{
+    setCheckEdges(false);
+}
+
+bool
+CheckHeapTracer::init()
+{
+    return visited.init();
+}
+
+void
+CheckHeapTracer::onChild(const JS::GCCellPtr& thing)
+{
+    Cell* cell = thing.asCell();
+    if (visited.lookup(cell))
+        return;
+
+    if (!visited.put(cell)) {
+        oom = true;
+        return;
+    }
+
+    if (!IsGCThingValidAfterMovingGC(cell)) {
+        failures++;
+        fprintf(stderr, "Stale pointer %p\n", cell);
+        const char* name = contextName();
+        for (int index = parentIndex; index != -1; index = stack[index].parentIndex) {
+            const WorkItem& parent = stack[index];
+            cell = parent.thing.asCell();
+            fprintf(stderr, "  from %s %p %s edge\n",
+                    GCTraceKindToAscii(cell->getTraceKind()), cell, name);
+            name = parent.name;
+        }
+        fprintf(stderr, "  from root %s\n", name);
+        return;
+    }
+
+    WorkItem item(thing, contextName(), parentIndex);
+    if (!stack.append(item))
+        oom = true;
+}
+
+bool
+CheckHeapTracer::check()
+{
+    // The analysis thinks that markRuntime might GC by calling a GC callback.
+    JS::AutoSuppressGCAnalysis nogc(rt);
+    rt->gc.markRuntime(this, GCRuntime::TraceRuntime);
+
+    while (!stack.empty()) {
+        WorkItem item = stack.back();
+        if (item.processed) {
+            stack.popBack();
+        } else {
+            parentIndex = stack.length() - 1;
+            TraceChildren(this, item.thing);
+            stack.back().processed = true;
+        }
+    }
+
+    if (oom)
+        return false;
+
+    if (failures) {
+        fprintf(stderr, "Heap check: %zu failure(s) out of %" PRIu32 " pointers checked\n",
+                failures, visited.count());
+    }
+    MOZ_RELEASE_ASSERT(failures == 0);
+
+    return true;
+}
+
+void
+js::gc::CheckHeapAfterMovingGC(JSRuntime* rt)
+{
+    MOZ_ASSERT(rt->isHeapCollecting());
+    CheckHeapTracer tracer(rt);
+    if (!tracer.init() || !tracer.check())
+        fprintf(stderr, "OOM checking heap\n");
+}
+
+#endif /* JSGC_HASH_TABLE_CHECKS */
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -667,16 +667,16 @@ class ZoneAllocPolicy
     template <typename T>
     T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
         return zone->pod_realloc<T>(p, oldSize, newSize);
     }
 
     void free_(void* p) { js_free(p); }
     void reportAllocOverflow() const {}
 
-    bool checkSimulatedOOM() const {
+    MOZ_MUST_USE bool checkSimulatedOOM() const {
         return !js::oom::ShouldFailWithOOM();
     }
 };
 
 } // namespace js
 
 #endif // gc_Zone_h
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1209,17 +1209,18 @@ const char* gc::ZealModeHelpText =
     "    6: (StackRooting) Verify stack rooting\n"
     "    7: (GenerationalGC) Collect the nursery every N nursery allocations\n"
     "    8: (IncrementalRootsThenFinish) Incremental GC in two slices: 1) mark roots 2) finish collection\n"
     "    9: (IncrementalMarkAllThenFinish) Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
     "   10: (IncrementalMultipleSlices) Incremental GC in multiple slices\n"
     "   11: (IncrementalMarkingValidator) Verify incremental marking\n"
     "   12: (ElementsBarrier) Always use the individual element post-write barrier, regardless of elements size\n"
     "   13: (CheckHashTablesOnMinorGC) Check internal hashtables on minor GC\n"
-    "   14: (Compact) Perform a shrinking collection every N allocations\n";
+    "   14: (Compact) Perform a shrinking collection every N allocations\n"
+    "   15: (CheckHeapOnMovingGC) Walk the heap to check all pointers have been updated\n";
 
 void
 GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
 {
     MOZ_ASSERT(zeal <= unsigned(ZealMode::Limit));
 
     if (verifyPreData)
         VerifyBarriers(rt, PreBarrierVerifier);
@@ -3377,30 +3378,30 @@ GCRuntime::triggerZoneGC(Zone* zone, JS:
     }
 
     /* GC is already running. */
     if (rt->isHeapCollecting())
         return false;
 
 #ifdef JS_GC_ZEAL
     if (hasZealMode(ZealMode::Alloc)) {
-        triggerGC(reason);
+        MOZ_RELEASE_ASSERT(triggerGC(reason));
         return true;
     }
 #endif
 
     if (zone->isAtomsZone()) {
         /* We can't do a zone GC of the atoms compartment. */
         if (rt->keepAtoms()) {
             /* Skip GC and retrigger later, since atoms zone won't be collected
              * if keepAtoms is true. */
             fullGCForAtomsRequested_ = true;
             return false;
         }
-        triggerGC(reason);
+        MOZ_RELEASE_ASSERT(triggerGC(reason));
         return true;
     }
 
     PrepareZoneForGC(zone);
     requestMajorGC(reason);
     return true;
 }
 
@@ -4355,18 +4356,18 @@ GCRuntime::markWeakReferences(gcstats::P
 {
     MOZ_ASSERT(marker.isDrained());
 
     gcstats::AutoPhase ap1(stats, phase);
 
     marker.enterWeakMarkingMode();
 
     // TODO bug 1167452: Make weak marking incremental
-    SliceBudget budget = SliceBudget::unlimited();
-    marker.drainMarkStack(budget);
+    auto unlimited = SliceBudget::unlimited();
+    MOZ_RELEASE_ASSERT(marker.drainMarkStack(unlimited));
 
     for (;;) {
         bool markedAny = false;
         if (!marker.isWeakMarkingTracer()) {
             for (ZoneIterT zone(rt); !zone.done(); zone.next())
                 markedAny |= WeakMapBase::markZoneIteratively(zone, &marker);
         }
         for (CompartmentsIterT<ZoneIterT> c(rt); !c.done(); c.next()) {
@@ -4375,17 +4376,17 @@ GCRuntime::markWeakReferences(gcstats::P
         }
         markedAny |= Debugger::markAllIteratively(&marker);
         markedAny |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker);
 
         if (!markedAny)
             break;
 
         auto unlimited = SliceBudget::unlimited();
-        marker.drainMarkStack(unlimited);
+        MOZ_RELEASE_ASSERT(marker.drainMarkStack(unlimited));
     }
     MOZ_ASSERT(marker.isDrained());
 
     marker.leaveWeakMarkingMode();
 }
 
 void
 GCRuntime::markWeakReferencesInCurrentGroup(gcstats::Phase phase)
@@ -4402,17 +4403,17 @@ GCRuntime::markGrayReferences(gcstats::P
         for (ZoneIterT zone(rt); !zone.done(); zone.next())
             markBufferedGrayRoots(zone);
     } else {
         MOZ_ASSERT(!isIncremental);
         if (JSTraceDataOp op = grayRootTracer.op)
             (*op)(&marker, grayRootTracer.data);
     }
     auto unlimited = SliceBudget::unlimited();
-    marker.drainMarkStack(unlimited);
+    MOZ_RELEASE_ASSERT(marker.drainMarkStack(unlimited));
 }
 
 void
 GCRuntime::markGrayReferencesInCurrentGroup(gcstats::Phase phase)
 {
     markGrayReferences<GCZoneGroupIter, GCCompartmentGroupIter>(phase);
 }
 
@@ -4563,19 +4564,19 @@ js::gc::MarkingValidator::nonIncremental
             gcmarker->reset();
 
             for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next())
                 chunk->bitmap.clear();
         }
 
         gc->markRuntime(gcmarker, GCRuntime::MarkRuntime);
 
+        gc->incrementalState = MARK;
         auto unlimited = SliceBudget::unlimited();
-        gc->incrementalState = MARK;
-        gc->marker.drainMarkStack(unlimited);
+        MOZ_RELEASE_ASSERT(gc->marker.drainMarkStack(unlimited));
     }
 
     gc->incrementalState = SWEEP;
     {
         gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP);
         gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK);
 
         gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_WEAK);
@@ -5026,17 +5027,17 @@ MarkIncomingCrossCompartmentPointers(JSR
             }
         }
 
         if (unlinkList)
             c->gcIncomingGrayPointers = nullptr;
     }
 
     auto unlimited = SliceBudget::unlimited();
-    rt->gc.marker.drainMarkStack(unlimited);
+    MOZ_RELEASE_ASSERT(rt->gc.marker.drainMarkStack(unlimited));
 }
 
 static bool
 RemoveFromGrayList(JSObject* wrapper)
 {
     if (!IsGrayListObject(wrapper))
         return false;
 
@@ -5888,16 +5889,20 @@ GCRuntime::compactPhase(JS::gcreason::Re
 
     // Clear runtime caches that can contain cell pointers.
     rt->newObjectCache.purge();
     rt->nativeIterCache.purge();
 
 #ifdef DEBUG
     CheckHashTablesAfterMovingGC(rt);
 #endif
+#ifdef JS_GC_ZEAL
+    if (rt->hasZealMode(ZealMode::CheckHeapOnMovingGC))
+        CheckHeapAfterMovingGC(rt);
+#endif
 
     return zonesToMaybeCompact.isEmpty() ? Finished : NotFinished;
 }
 
 void
 GCRuntime::endCompactPhase(JS::gcreason::Reason reason)
 {
     startedCompacting = false;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1181,23 +1181,28 @@ MaybeForwarded(T t)
         t = Forwarded(t);
     MakeAccessibleAfterMovingGC(t);
     return t;
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 template <typename T>
+inline bool
+IsGCThingValidAfterMovingGC(T* t)
+{
+    return !IsInsideNursery(t) && !RelocationOverlay::isCellForwarded(t);
+}
+
+template <typename T>
 inline void
 CheckGCThingAfterMovingGC(T* t)
 {
-    if (t) {
-        MOZ_RELEASE_ASSERT(!IsInsideNursery(t));
-        MOZ_RELEASE_ASSERT(!RelocationOverlay::isCellForwarded(t));
-    }
+    if (t)
+        MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t));
 }
 
 template <typename T>
 inline void
 CheckGCThingAfterMovingGC(const ReadBarriered<T*>& t)
 {
     CheckGCThingAfterMovingGC(t.unbarrieredGet());
 }
@@ -1223,23 +1228,24 @@ CheckValueAfterMovingGC(const JS::Value&
             D(StackRooting, 6)                 \
             D(GenerationalGC, 7)               \
             D(IncrementalRootsThenFinish, 8)   \
             D(IncrementalMarkAllThenFinish, 9) \
             D(IncrementalMultipleSlices, 10)   \
             D(IncrementalMarkingValidator, 11) \
             D(ElementsBarrier, 12)             \
             D(CheckHashTablesOnMinorGC, 13)    \
-            D(Compact, 14)
+            D(Compact, 14)                     \
+            D(CheckHeapOnMovingGC, 15)
 
 enum class ZealMode {
 #define ZEAL_MODE(name, value) name = value,
     JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
 #undef ZEAL_MODE
-    Limit = 14
+    Limit = 15
 };
 
 enum VerifierType {
     PreBarrierVerifier
 };
 
 #ifdef JS_GC_ZEAL
 
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1150,16 +1150,25 @@ RestyleManager::AnimationsWithDestroyedF
   for (nsIContent* content : aArray) {
     if (content->GetPrimaryFrame()) {
       continue;
     }
     dom::Element* element = content->AsElement();
 
     animationManager->StopAnimationsForElement(element, aPseudoType);
     transitionManager->StopTransitionsForElement(element, aPseudoType);
+
+    // All other animations should keep running but not running on the
+    // *compositor* at this point.
+    EffectSet* effectSet = EffectSet::GetEffectSet(element, aPseudoType);
+    if (effectSet) {
+      for (KeyframeEffectReadOnly* effect : *effectSet) {
+        effect->ResetIsRunningOnCompositor();
+      }
+    }
   }
 }
 
 static inline dom::Element*
 ElementForStyleContext(nsIContent* aParentContent,
                        nsIFrame* aFrame,
                        CSSPseudoElementType aPseudoType);
 
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -96,25 +96,19 @@
 #ifdef NS_PRINTING
 
 #include "nsIWebBrowserPrint.h"
 
 #include "nsPrintEngine.h"
 
 // Print Options
 #include "nsIPrintSettings.h"
-#include "nsIPrintOptions.h"
+#include "nsIPrintSettingsService.h"
 #include "nsISimpleEnumerator.h"
 
-#ifdef DEBUG
-// PrintOptions is now implemented by PrintSettingsService
-static const char sPrintOptionsContractID[] =
-  "@mozilla.org/gfx/printsettings-service;1";
-#endif // DEBUG
-
 #include "nsIPluginDocument.h"
 
 #endif // NS_PRINTING
 
 //focus
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMEventListener.h"
 #include "nsISelectionController.h"
@@ -2720,21 +2714,22 @@ nsDocumentViewer::Print(bool            
 
 #ifdef DEBUG
   nsresult rv = NS_ERROR_FAILURE;
 
   mDebugFile = aDebugFile;
   // if they don't pass in a PrintSettings, then make one
   // it will have all the default values
   printSettings = aPrintSettings;
-  nsCOMPtr<nsIPrintOptions> printOptions = do_GetService(sPrintOptionsContractID, &rv);
+  nsCOMPtr<nsIPrintSettingsService> printSettingsSvc
+    = do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
   if (NS_SUCCEEDED(rv)) {
     // if they don't pass in a PrintSettings, then make one
     if (printSettings == nullptr) {
-      printOptions->CreatePrintSettings(getter_AddRefs(printSettings));
+      printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
     }
     NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
   }
   if (printSettings) printSettings->SetPrintSilent(aSilent);
   if (printSettings) printSettings->SetShowPrintProgress(false);
 #endif
 
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2729,31 +2729,16 @@ nsPresContext::IsRootContentDocument() c
   if (!view) {
     return true;
   }
 
   nsIFrame* f = view->GetFrame();
   return (f && f->PresContext()->IsChrome());
 }
 
-bool
-nsPresContext::IsCrossProcessRootContentDocument()
-{
-  if (!IsRootContentDocument()) {
-    return false;
-  }
-
-  if (XRE_IsParentProcess()) {
-    return true;
-  }
-
-  TabChild* tabChild = TabChild::GetFrom(mShell);
-  return (tabChild && tabChild->IsRootContentDocument());
-}
-
 bool nsPresContext::GetPaintFlashing() const
 {
   if (!mPaintFlashingInitialized) {
     bool pref = Preferences::GetBool("nglayout.debug.paint_flashing");
     if (!pref && IsChrome()) {
       pref = Preferences::GetBool("nglayout.debug.paint_flashing_chrome");
     }
     mPaintFlashing = pref;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1034,17 +1034,16 @@ public:
   }
 
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
   bool IsRootContentDocument() const;
-  bool IsCrossProcessRootContentDocument();
 
   bool IsGlyph() const {
     return mIsGlyph;
   }
 
   void SetIsGlyph(bool aValue) {
     mIsGlyph = aValue;
   }
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5368,18 +5368,31 @@ static bool IsTransparentContainerElemen
   if (!docShell) {
     return false;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> pwin = docShell->GetWindow();
   if (!pwin)
     return false;
   nsCOMPtr<Element> containerElement = pwin->GetFrameElementInternal();
-  return containerElement &&
-         containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent);
+
+  TabChild* tab = TabChild::GetFrom(docShell);
+  if (tab) {
+    // Check if presShell is the top PresShell. Only the top can
+    // influence the canvas background color.
+    nsCOMPtr<nsIPresShell> presShell = aPresContext->GetPresShell();
+    nsCOMPtr<nsIPresShell> topPresShell = tab->GetPresShell();
+    if (presShell != topPresShell) {
+      tab = nullptr;
+    }
+  }
+
+  return (containerElement &&
+          containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent))
+    || (tab && tab->IsTransparent());
 }
 
 nscolor PresShell::GetDefaultBackgroundColorToDraw()
 {
   if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) {
     return NS_RGB(255,255,255);
   }
   return mPresContext->DefaultBackgroundColor();
@@ -5401,17 +5414,17 @@ void PresShell::UpdateCanvasBackground()
     bool drawBackgroundImage;
     bool drawBackgroundColor;
     mCanvasBackgroundColor =
       nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
                                                rootStyleFrame,
                                                drawBackgroundImage,
                                                drawBackgroundColor);
     mHasCSSBackgroundColor = drawBackgroundColor;
-    if (GetPresContext()->IsCrossProcessRootContentDocument() &&
+    if (mPresContext->IsRootContentDocument() &&
         !IsTransparentContainerElement(mPresContext)) {
       mCanvasBackgroundColor =
         NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor);
     }
   }
 
   // If the root element of the document (ie html) has style 'display: none'
   // then the document's background color does not get drawn; cache the
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -87,16 +87,17 @@
 #include "StickyScrollContainer.h"
 #include "nsFontInflationData.h"
 #include "gfxASurface.h"
 #include "nsRegion.h"
 #include "nsIFrameInlines.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EffectCompositor.h"
+#include "mozilla/EffectSet.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/css/ImageLoader.h"
 #include "mozilla/gfx/Tools.h"
@@ -695,17 +696,17 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
       RestyleManager::ReframingStyleContexts* rsc =
         presContext->RestyleManager()->AsGecko()->GetReframingStyleContexts();
       if (rsc) {
         rsc->Put(mContent, mStyleContext);
       }
     }
   }
 
-  if (HasCSSAnimations() || HasCSSTransitions()) {
+  if (EffectSet::GetEffectSet(this)) {
     // If no new frame for this element is created by the end of the
     // restyling process, stop animations and transitions for this frame
     if (presContext->RestyleManager()->IsGecko()) {
       RestyleManager::AnimationsWithDestroyedFrame* adf =
         presContext->RestyleManager()->AsGecko()->GetAnimationsWithDestroyedFrame();
       // AnimationsWithDestroyedFrame only lives during the restyling process.
       if (adf) {
         adf->Put(mContent, mStyleContext);
--- a/layout/printing/ipc/PRemotePrintJob.ipdl
+++ b/layout/printing/ipc/PRemotePrintJob.ipdl
@@ -26,16 +26,28 @@ parent:
   // print device.
   // This will always deallocate the shared memory.
   async ProcessPage(Shmem aStoredPage);
 
   // This informs the real print device that we've finished, so it can trigger
   // the actual print.
   async FinalizePrint();
 
+  // Report a state change to listeners in the parent process.
+  async StateChange(long aStateFlags,
+                    nsresult aStatus);
+
+  // Report a progress change to listeners in the parent process.
+  async ProgressChange(long aCurSelfProgress,
+                       long aMaxSelfProgress,
+                       long aCurTotalProgress,
+                       long aMaxTotalProgress);
+
+  // Report a status change to listeners in the parent process.
+  async StatusChange(nsresult aStatus);
 
 child:
   // Inform the child that the print has been initialized in the parent or has
   // failed with result aRv.
   async PrintInitializationResult(nsresult aRv);
 
   // Inform the child that the latest page has been processed remotely.
   async PageProcessed();
--- a/layout/printing/ipc/RemotePrintJobChild.cpp
+++ b/layout/printing/ipc/RemotePrintJobChild.cpp
@@ -8,16 +8,19 @@
 
 #include "mozilla/unused.h"
 #include "nsPagePrintTimer.h"
 #include "nsPrintEngine.h"
 
 namespace mozilla {
 namespace layout {
 
+NS_IMPL_ISUPPORTS(RemotePrintJobChild,
+                  nsIWebProgressListener)
+
 RemotePrintJobChild::RemotePrintJobChild()
 {
   MOZ_COUNT_CTOR(RemotePrintJobChild);
 }
 
 nsresult
 RemotePrintJobChild::InitializePrint(const nsString& aDocumentTitle,
                                      const nsString& aPrintToFile,
@@ -81,16 +84,66 @@ RemotePrintJobChild::SetPagePrintTimer(n
 void
 RemotePrintJobChild::SetPrintEngine(nsPrintEngine* aPrintEngine)
 {
   MOZ_ASSERT(aPrintEngine);
 
   mPrintEngine = aPrintEngine;
 }
 
+// nsIWebProgressListener
+
+NS_IMETHODIMP
+RemotePrintJobChild::OnStateChange(nsIWebProgress* aProgress,
+                                   nsIRequest* aRequest, uint32_t aStateFlags,
+                                   nsresult aStatus)
+{
+  Unused << SendStateChange(aStateFlags, aStatus);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RemotePrintJobChild::OnProgressChange(nsIWebProgress * aProgress,
+                                      nsIRequest * aRequest,
+                                      int32_t aCurSelfProgress,
+                                      int32_t aMaxSelfProgress,
+                                      int32_t aCurTotalProgress,
+                                      int32_t aMaxTotalProgress)
+{
+  Unused << SendProgressChange(aCurSelfProgress, aMaxSelfProgress,
+                               aCurTotalProgress, aMaxTotalProgress);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RemotePrintJobChild::OnLocationChange(nsIWebProgress* aProgress,
+                                      nsIRequest* aRequest, nsIURI* aURI,
+                                      uint32_t aFlags)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RemotePrintJobChild::OnStatusChange(nsIWebProgress* aProgress,
+                                    nsIRequest* aRequest, nsresult aStatus,
+                                    const char16_t* aMessage)
+{
+  Unused << SendStatusChange(aStatus);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RemotePrintJobChild::OnSecurityChange(nsIWebProgress* aProgress,
+                                      nsIRequest* aRequest, uint32_t aState)
+{
+  return NS_OK;
+}
+
+// End of nsIWebProgressListener
+
 RemotePrintJobChild::~RemotePrintJobChild()
 {
   MOZ_COUNT_DTOR(RemotePrintJobChild);
 }
 
 void
 RemotePrintJobChild::ActorDestroy(ActorDestroyReason aWhy)
 {
--- a/layout/printing/ipc/RemotePrintJobChild.h
+++ b/layout/printing/ipc/RemotePrintJobChild.h
@@ -5,27 +5,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layout_RemotePrintJobChild_h
 #define mozilla_layout_RemotePrintJobChild_h
 
 #include "mozilla/layout/PRemotePrintJobChild.h"
 
 #include "mozilla/RefPtr.h"
+#include "nsIWebProgressListener.h"
 
 class nsPagePrintTimer;
 class nsPrintEngine;
 
 namespace mozilla {
 namespace layout {
 
 class RemotePrintJobChild final : public PRemotePrintJobChild
+                                , public nsIWebProgressListener
 {
 public:
-  NS_INLINE_DECL_REFCOUNTING(RemotePrintJobChild)
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWEBPROGRESSLISTENER
 
   RemotePrintJobChild();
 
   void ActorDestroy(ActorDestroyReason aWhy) final;
 
   nsresult InitializePrint(const nsString& aDocumentTitle,
                            const nsString& aPrintToFile,
                            const int32_t& aStartPage,
--- a/layout/printing/ipc/RemotePrintJobParent.cpp
+++ b/layout/printing/ipc/RemotePrintJobParent.cpp
@@ -10,16 +10,17 @@
 
 #include "gfxContext.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/unused.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDeviceContext.h"
 #include "nsIDeviceContextSpec.h"
 #include "nsIPrintSettings.h"
+#include "nsIWebProgressListener.h"
 #include "PrintTranslator.h"
 
 namespace mozilla {
 namespace layout {
 
 RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings)
   : mPrintSettings(aPrintSettings)
 {
@@ -144,16 +145,66 @@ RemotePrintJobParent::RecvAbortPrint(con
   if (mPrintDeviceContext) {
     Unused << mPrintDeviceContext->AbortDocument();
   }
 
   Unused << Send__delete__(this);
   return true;
 }
 
+bool
+RemotePrintJobParent::RecvStateChange(const long& aStateFlags,
+                                      const nsresult& aStatus)
+{
+  uint32_t numberOfListeners = mPrintProgressListeners.Length();
+  for (uint32_t i = 0; i < numberOfListeners; ++i) {
+    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
+    listener->OnStateChange(nullptr, nullptr, aStateFlags, aStatus);
+  }
+
+  return true;
+}
+
+bool
+RemotePrintJobParent::RecvProgressChange(const long& aCurSelfProgress,
+                                         const long& aMaxSelfProgress,
+                                         const long& aCurTotalProgress,
+                                         const long& aMaxTotalProgress)
+{
+  uint32_t numberOfListeners = mPrintProgressListeners.Length();
+  for (uint32_t i = 0; i < numberOfListeners; ++i) {
+    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
+    listener->OnProgressChange(nullptr, nullptr,
+                               aCurSelfProgress, aMaxSelfProgress,
+                               aCurTotalProgress, aMaxTotalProgress);
+  }
+
+  return true;
+}
+
+bool
+RemotePrintJobParent::RecvStatusChange(const nsresult& aStatus)
+{
+  uint32_t numberOfListeners = mPrintProgressListeners.Length();
+  for (uint32_t i = 0; i < numberOfListeners; ++i) {
+    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
+    listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr);
+  }
+
+  return true;
+}
+
+void
+RemotePrintJobParent::RegisterListener(nsIWebProgressListener* aListener)
+{
+  MOZ_ASSERT(aListener);
+
+  mPrintProgressListeners.AppendElement(aListener);
+}
+
 RemotePrintJobParent::~RemotePrintJobParent()
 {
   MOZ_COUNT_DTOR(RemotePrintJobParent);
 }
 
 void
 RemotePrintJobParent::ActorDestroy(ActorDestroyReason aWhy)
 {
--- a/layout/printing/ipc/RemotePrintJobParent.h
+++ b/layout/printing/ipc/RemotePrintJobParent.h
@@ -4,22 +4,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layout_RemotePrintJobParent_h
 #define mozilla_layout_RemotePrintJobParent_h
 
 #include "mozilla/layout/PRemotePrintJobParent.h"
 
+#include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 
 class nsDeviceContext;
 class nsIPrintSettings;
+class nsIWebProgressListener;
 class PrintTranslator;
 
 namespace mozilla {
 namespace layout {
 
 class RemotePrintJobParent final : public PRemotePrintJobParent
 {
 public:
@@ -33,27 +35,45 @@ public:
                            const int32_t& aEndPage) final;
 
   bool RecvProcessPage(Shmem&& aStoredPage) final;
 
   bool RecvFinalizePrint() final;
 
   bool RecvAbortPrint(const nsresult& aRv) final;
 
+  bool RecvStateChange(const long& aStateFlags,
+                       const nsresult& aStatus) final;
+
+  bool RecvProgressChange(const long& aCurSelfProgress,
+                          const long& aMaxSelfProgress,
+                          const long& aCurTotalProgress,
+                          const long& aMaxTotalProgress) final;
+
+  bool RecvStatusChange(const nsresult& aStatus) final;
+
+  /**
+    * Register a progress listener to receive print progress updates.
+    *
+    * @param aListener the progress listener to register. Must not be null.
+    */
+  void RegisterListener(nsIWebProgressListener* aListener);
+
 private:
   ~RemotePrintJobParent() final;
 
   nsresult InitializePrintDevice(const nsString& aDocumentTitle,
                                  const nsString& aPrintToFile,
                                  const int32_t& aStartPage,
                                  const int32_t& aEndPage);
 
   nsresult PrintPage(const Shmem& aStoredPage);
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   RefPtr<nsDeviceContext> mPrintDeviceContext;
   UniquePtr<PrintTranslator> mPrintTranslator;
+  nsCOMArray<nsIWebProgressListener> mPrintProgressListeners;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif // mozilla_layout_RemotePrintJobParent_h
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -115,8 +115,20 @@ nsPrintData::DoOnProgressChange(int32_t 
     nsIWebProgressListener* wpl = mPrintProgressListeners.ObjectAt(i);
     wpl->OnProgressChange(nullptr, nullptr, aProgress, aMaxProgress, aProgress, aMaxProgress);
     if (aDoStartStop) {
       wpl->OnStateChange(nullptr, nullptr, aFlag, NS_OK);
     }
   }
 }
 
+void
+nsPrintData::DoOnStatusChange(nsresult aStatus)
+{
+  uint32_t numberOfListeners = mPrintProgressListeners.Length();
+  for (uint32_t i = 0; i < numberOfListeners; ++i) {
+    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
+    if (listener) {
+      listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr);
+    }
+  }
+}
+
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -46,16 +46,18 @@ public:
   // Listener Helper Methods
   void OnEndPrinting();
   void OnStartPrinting();
   void DoOnProgressChange(int32_t      aProgress,
                           int32_t      aMaxProgress,
                           bool         aDoStartStop,
                           int32_t      aFlag);
 
+  void DoOnStatusChange(nsresult aStatus);
+
 
   ePrintDataType               mType;            // the type of data this is (Printing or Print Preview)
   RefPtr<nsDeviceContext>   mPrintDC;
   FILE                        *mDebugFilePtr;    // a file where information can go to when printing
 
   nsPrintObject *                mPrintObject;
   nsPrintObject *                mSelectedPO;
 
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -470,24 +470,39 @@ nsPrintEngine::DoCommonPrint(bool       
     if (viewer) {
       viewer->SetTextZoom(1.0f);
       viewer->SetFullZoom(1.0f);
       viewer->SetMinFontSize(0);
     }
   }
 
   // Create a print session and let the print settings know about it.
+  // Don't overwrite an existing print session.
   // The print settings hold an nsWeakPtr to the session so it does not
   // need to be cleared from the settings at the end of the job.
   // XXX What lifetime does the printSession need to have?
   nsCOMPtr<nsIPrintSession> printSession;
+  bool remotePrintJobListening = false;
   if (!aIsPrintPreview) {
-    printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    mPrt->mPrintSettings->SetPrintSession(printSession);
+    rv = mPrt->mPrintSettings->GetPrintSession(getter_AddRefs(printSession));
+    if (NS_FAILED(rv) || !printSession) {
+      printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
+      NS_ENSURE_SUCCESS(rv, rv);
+      mPrt->mPrintSettings->SetPrintSession(printSession);
+    } else {
+      RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
+      printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
+      if (NS_SUCCEEDED(rv) && remotePrintJob) {
+        // If we have a RemotePrintJob add it to the print progress listeners,
+        // so it can forward to the parent.
+        mPrt->mPrintProgressListeners.AppendElement(remotePrintJob);
+        remotePrintJobListening = true;
+      }
+    }
+
   }
 
   if (aWebProgressListener != nullptr) {
     mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener);
   }
 
   // Get the currently focused window and cache it
   // because the Print Dialog will "steal" focus and later when you try
@@ -607,16 +622,27 @@ nsPrintEngine::DoCommonPrint(bool       
         if (NS_SUCCEEDED(rv)) {
           // since we got the dialog and it worked then make sure we 
           // are telling GFX we want to print silent
           printSilently = true;
 
           if (mPrt->mPrintSettings) {
             // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
             mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
+
+            // If we haven't already added the RemotePrintJob as a listener,
+            // add it now if there is one.
+            if (!remotePrintJobListening) {
+              RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
+              printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
+              if (NS_SUCCEEDED(rv) && remotePrintJob) {
+                mPrt->mPrintProgressListeners.AppendElement(remotePrintJob);
+                remotePrintJobListening = true;
+              }
+            }
           }
         } else if (rv == NS_ERROR_NOT_IMPLEMENTED) {
           // This means the Dialog service was there,
           // but they choose not to implement this dialog and
           // are looking for default behavior from the toolkit
           rv = NS_OK;
         }
       } else {
@@ -1526,16 +1552,19 @@ nsPrintEngine::FirePrintingErrorEvent(ns
   event->InitCustomEvent(NS_LITERAL_STRING("PrintingError"), false, false,
                          resultVariant);
   event->SetTrusted(true);
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(doc, event);
   asyncDispatcher->mOnlyChromeDispatch = true;
   asyncDispatcher->RunDOMEventWhenSafe();
+
+  // Inform any progress listeners of the Error.
+  mPrt->DoOnStatusChange(aPrintError);
 }
 
 //-----------------------------------------------------------------
 //-- Section: Reflow Methods
 //-----------------------------------------------------------------
 
 nsresult
 nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale)
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -356,17 +356,17 @@ pref("media.apple.mp4.enabled", true);
 // media.gmp.storage.version.observed, and if the versions don't match,
 // we clear storage and set media.gmp.storage.version.observed=expected.
 // This provides a mechanism to clear GMP storage when non-compatible
 // changes are made.
 pref("media.gmp.storage.version.expected", 1);
 
 // Filter what triggers user notifications.
 // See DecoderDoctorDocumentWatcher::ReportAnalysis for details.
-pref("media.decoder-doctor.notifications-allowed", "MediaWidevineNoWMFNoSilverlight");
+pref("media.decoder-doctor.notifications-allowed", "MediaWMFNeeded,MediaWidevineNoWMFNoSilverlight");
 // Whether we report partial failures.
 pref("media.decoder-doctor.verbose", false);
 
 // Whether to suspend decoding of videos in background tabs.
 pref("media.suspend-bkgnd-video.enabled", true);
 
 #ifdef MOZ_WEBRTC
 pref("media.navigator.enabled", true);
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -819,21 +819,20 @@ class Artifacts(object):
                           'pushid': pushid,
                           'num': NUM_PUSHHEADS_TO_QUERY_PER_PARENT},
                          'Retrieving the last {num} pushheads starting with id {pushid} on {tree}')
                 candidate_pushheads.extend(pushhead_cache.pushid_range(tree, start, end))
 
         return candidate_pushheads
 
     def _get_hg_revisions_from_git(self):
-
-        # First commit is HEAD, next is HEAD~1, etc.
         rev_list = subprocess.check_output([
             self._git, 'rev-list', '--topo-order',
-            'HEAD~{num}..HEAD'.format(num=NUM_REVISIONS_TO_QUERY),
+            '--max-count={num}'.format(num=NUM_REVISIONS_TO_QUERY),
+            'HEAD',
         ])
 
         hg_hash_list = subprocess.check_output([
             self._git, 'cinnabar', 'git2hg'
         ] + rev_list.splitlines())
 
         zeroes = "0" * 40
 
--- a/testing/mozharness/configs/builds/branch_specifics.py
+++ b/testing/mozharness/configs/builds/branch_specifics.py
@@ -179,16 +179,91 @@ config = {
             'win32-mulet': {
                 'update_channel': 'default',
             },
             'win64-debug': {
                 'update_channel': 'default',
             },
         },
     },
+    'mozilla-esr45': {
+        'enable_release_promotion': True,
+        'repo_path': 'releases/mozilla-esr45',
+        'update_channel': 'esr',
+        'branch_uses_per_checkin_strategy': True,
+        'use_branch_in_symbols_extra_buildid': False,
+        'stage_server': 'upload.ffxbld.productdelivery.prod.mozaws.net',
+        'platform_overrides': {
+            'linux': {
+                'src_mozconfig': 'browser/config/mozconfigs/linux32/release',
+                'force_clobber': True,
+            },
+            'linux64': {
+                'src_mozconfig': 'browser/config/mozconfigs/linux64/release',
+                'force_clobber': True,
+            },
+            'macosx64': {
+                'src_mozconfig': 'browser/config/mozconfigs/macosx-universal/release',
+                'force_clobber': True,
+            },
+            'win32': {
+                'src_mozconfig': 'browser/config/mozconfigs/win32/release',
+                'force_clobber': True,
+            },
+            'win64': {
+                'src_mozconfig': 'browser/config/mozconfigs/win64/release',
+                'force_clobber': True,
+            },
+            'linux-debug': {
+                'update_channel': 'default',
+            },
+            'linux64-debug': {
+                'update_channel': 'default',
+            },
+            'linux64-asan-debug': {
+                'update_channel': 'default',
+            },
+            'linux64-asan': {
+                'update_channel': 'default',
+            },
+            'linux64-cc': {
+                'update_channel': 'default',
+            },
+            'linux64-st-an-debug': {
+                'update_channel': 'default',
+            },
+            'linux64-st-an': {
+                'update_channel': 'default',
+            },
+            'linux64-tsan': {
+                'update_channel': 'default',
+            },
+            'macosx64-debug': {
+                'update_channel': 'default',
+            },
+            'macosx64-st-an': {
+                'update_channel': 'default',
+            },
+            'macosx64-mulet': {
+                'update_channel': 'default',
+            },
+            'macosx64-st-an-debug': {
+                'update_channel': 'default',
+            },
+            'win32-debug': {
+                'update_channel': 'default',
+            },
+            'win32-mulet': {
+                'update_channel': 'default',
+            },
+            'win64-debug': {
+                'update_channel': 'default',
+            },
+        },
+    },
     'mozilla-aurora': {
         'repo_path': 'releases/mozilla-aurora',
         'update_channel': 'aurora',
         'branch_uses_per_checkin_strategy': True,
         'stage_server': 'upload.ffxbld.productdelivery.prod.mozaws.net',
     },
     'try': {
         'repo_path': 'try',
new file mode 100644
--- /dev/null
+++ b/testing/mozharness/configs/releases/postrelease_firefox_esr45.py
@@ -0,0 +1,18 @@
+config = {
+    "log_name": "bump_esr45",
+    "version_files": [
+        {"file": "browser/config/version.txt"},
+        {"file": "browser/config/version_display.txt"},
+        {"file": "config/milestone.txt"},
+    ],
+    "repo": {
+        "repo": "https://hg.mozilla.org/releases/mozilla-esr45",
+        "revision": "default",
+        "dest": "mozilla-esr45",
+        "vcs": "hg",
+    },
+    "push_dest": "ssh://hg.mozilla.org/releases/mozilla-esr45",
+    "ignore_no_changes": True,
+    "ssh_user": "ffxbld",
+    "ssh_key": "~/.ssh/ffxbld_rsa",
+}
new file mode 100644
--- /dev/null
+++ b/testing/mozharness/configs/releases/updates_firefox_esr45.py
@@ -0,0 +1,34 @@
+
+config = {
+    "log_name": "updates_esr45",
+    "repo": {
+        "repo": "https://hg.mozilla.org/build/tools",
+        "revision": "default",
+        "dest": "tools",
+        "vcs": "hg",
+    },
+    "push_dest": "ssh://hg.mozilla.org/build/tools",
+    "shipped-locales-url": "https://hg.mozilla.org/releases/mozilla-esr45/raw-file/{revision}/browser/locales/shipped-locales",
+    "ignore_no_changes": True,
+    "ssh_user": "ffxbld",
+    "ssh_key": "~/.ssh/ffxbld_rsa",
+    "archive_domain": "archive.mozilla.org",
+    "archive_prefix": "https://archive.mozilla.org/pub",
+    "previous_archive_prefix": "https://archive.mozilla.org/pub",
+    "download_domain": "download.mozilla.org",
+    "balrog_url": "https://aus5.mozilla.org",
+    "balrog_username": "ffxbld",
+    "update_channels": {
+        "esr": {
+            "version_regex": r".*",
+            "requires_mirrors": True,
+            "patcher_config": "mozEsr45-branch-patcher2.cfg",
+            "update_verify_channel": "esr-localtest",
+            "mar_channel_ids": [],
+            "channel_names": ["esr", "esr-localtest", "esr-cdntest"],
+            "rules_to_update": ["esr45-cdntest", "esr45-localtest"],
+            "publish_rules": ["esr"],
+        },
+    },
+    "balrog_use_dummy_suffix": False,
+}
new file mode 100644
--- /dev/null
+++ b/testing/mozharness/configs/single_locale/mozilla-esr45.py
@@ -0,0 +1,40 @@
+config = {
+    "nightly_build": True,
+    "branch": "mozilla-esr45",
+    "en_us_binary_url": "http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-mozilla-esr45/",
+    "update_channel": "esr",
+    "latest_mar_dir": '/pub/mozilla.org/firefox/nightly/latest-mozilla-esr45-l10n',
+
+    # l10n
+    "hg_l10n_base": "https://hg.mozilla.org/releases/l10n/mozilla-release",
+
+    # repositories
+    "mozilla_dir": "mozilla-esr45",
+    "repos": [{
+        "vcs": "hg",
+        "repo": "https://hg.mozilla.org/build/tools",
+        "revision": "default",
+        "dest": "tools",
+    }, {
+        "vcs": "hgtool",
+        "repo": "https://hg.mozilla.org/releases/mozilla-esr45",
+        "revision": "default",
+        "dest": "mozilla-esr45",
+    }, {
+        "vcs": "hgtool",
+        "repo": "https://hg.mozilla.org/build/compare-locales",
+        "revision": "RELEASE_AUTOMATION"
+    }],
+    # purge options
+    'purge_minsize': 12,
+    'is_automation': True,
+    'default_actions': [
+        "clobber",
+        "pull",
+        "list-locales",
+        "setup",
+        "repack",
+        "taskcluster-upload",
+        "summary",
+    ],
+}
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -331,16 +331,36 @@
   "FORGET_SKIPPABLE_MAX": {
     "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 10000,
     "n_buckets": 50,
     "description": "Max time spent on one forget skippable (ms)"
   },
+  "FULLSCREEN_TRANSITION_BLACK_MS": {
+    "alert_emails": ["xquan@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "low": 100,
+    "high": 5000,
+    "n_buckets": 50,
+    "bug_numbers": [1271160],
+    "description": "The time spent in the fully-black screen in fullscreen transition"
+  },
+  "FULLSCREEN_CHANGE_MS": {
+    "alert_emails": ["xquan@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "low": 100,
+    "high": 5000,
+    "n_buckets": 50,
+    "bug_numbers": [1271160],
+    "description": "The time content uses to enter/exit fullscreen regardless of fullscreen transition timeout"
+  },
   "GC_REASON_2": {
     "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 100,
     "description": "Reason (enum value) for initiating a GC"
   },
   "GC_IS_COMPARTMENTAL": {
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/unit/test_listmanager.js
@@ -0,0 +1,245 @@
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                  "resource://gre/modules/NetUtil.jsm");
+
+// These tables share the same updateURL.
+const TEST_TABLE_DATA_LIST = [
+  // 0:
+  {
+    tableName: "test-listmanager0-digest256",
+    providerName: "google",
+    updateUrl: "http://localhost:4444/safebrowsing/update",
+    gethashUrl: "http://localhost:4444/safebrowsing/gethash0",
+  },
+
+  // 1:
+  {
+    tableName: "test-listmanager1-digest256",
+    providerName: "google",
+    updateUrl: "http://localhost:4444/safebrowsing/update",
+    gethashUrl: "http://localhost:4444/safebrowsing/gethash1",
+  },
+
+  // 2.
+  {
+    tableName: "test-listmanager2-digest256",
+    providerName: "google",
+    updateUrl: "http://localhost:4444/safebrowsing/update",
+    gethashUrl: "http://localhost:4444/safebrowsing/gethash2",
+  }
+];
+
+// This table has a different update URL.
+const TEST_TABLE_DATA_ANOTHER = {
+  tableName: "test-listmanageranother-digest256",
+  providerName: "google",
+  updateUrl: "http://localhost:5555/safebrowsing/update",
+  gethashUrl: "http://localhost:5555/safebrowsing/gethash-another",
+};
+
+const PREF_NEXTUPDATETIME = "browser.safebrowsing.provider.google.nextupdatetime";
+
+let gListManager = Cc["@mozilla.org/url-classifier/listmanager;1"]
+                     .getService(Ci.nsIUrlListManager);
+
+// Global test server for serving safebrowsing updates.
+let gHttpServ = null;
+let gUpdateResponse = "";
+let gExpectedUpdateRequest = "";
+
+// Handles request for TEST_TABLE_DATA_ANOTHER.
+let gHttpServAnother = null;
+
+// These two variables are used to synchronize the last two racing updates
+// (in terms of "update URL") in test_update_all_tables().
+let gUpdatedCntForTableData = 0; // For TEST_TABLE_DATA_LIST.
+let gIsAnotherUpdated = false;   // For TEST_TABLE_DATA_ANOTHER.
+
+prefBranch.setBoolPref("browser.safebrowsing.debug", true);
+
+// Register tables.
+TEST_TABLE_DATA_LIST.forEach(function(t) {
+  gListManager.registerTable(t.tableName,
+                             t.providerName,
+                             t.updateUrl,
+                             t.gethashUrl);
+});
+gListManager.registerTable(TEST_TABLE_DATA_ANOTHER.tableName,
+                           TEST_TABLE_DATA_ANOTHER.providerName,
+                           TEST_TABLE_DATA_ANOTHER.updateUrl,
+                           TEST_TABLE_DATA_ANOTHER.gethashUrl);
+
+const SERVER_INVOLVED_TEST_CASE_LIST = [
+  // - Do table0 update.
+  // - Server would respond "a:5:32:32\n[DATA]".
+  function test_update_table0() {
+    disableAllUpdates();
+
+    gListManager.enableUpdate(TEST_TABLE_DATA_LIST[0].tableName);
+    gExpectedUpdateRequest = TEST_TABLE_DATA_LIST[0].tableName + ";\n";
+
+    gUpdateResponse = "n:1000\ni:" + TEST_TABLE_DATA_LIST[0].tableName + "\n";
+    gUpdateResponse += readFileToString("data/digest2.chunk");
+
+    forceTableUpdate();
+  },
+
+  // - Do table0 update again. Since chunk 5 was added to table0 in the last
+  //   update, the expected request contains "a:5".
+  // - Server would respond "s;2-12\n[DATA]".
+  function test_update_table0_with_existing_chunks() {
+    disableAllUpdates();
+
+    gListManager.enableUpdate(TEST_TABLE_DATA_LIST[0].tableName);
+    gExpectedUpdateRequest = TEST_TABLE_DATA_LIST[0].tableName + ";a:5\n";
+
+    gUpdateResponse = "n:1000\ni:" + TEST_TABLE_DATA_LIST[0].tableName + "\n";
+    gUpdateResponse += readFileToString("data/digest1.chunk");
+
+    forceTableUpdate();
+  },
+
+  // - Do all-table update.
+  // - Server would respond no chunk control.
+  //
+  // Note that this test MUST be the last one in the array since we rely on
+  // the number of sever-involved test case to synchronize the racing last
+  // two udpates for different URL.
+  function test_update_all_tables() {
+    disableAllUpdates();
+
+    // Enable all tables including TEST_TABLE_DATA_ANOTHER!
+    TEST_TABLE_DATA_LIST.forEach(function(t) {
+      gListManager.enableUpdate(t.tableName);
+    });
+    gListManager.enableUpdate(TEST_TABLE_DATA_ANOTHER.tableName);
+
+    gExpectedUpdateRequest = TEST_TABLE_DATA_LIST[0].tableName + ";a:5:s:2-12\n" +
+                             TEST_TABLE_DATA_LIST[1].tableName + ";\n" +
+                             TEST_TABLE_DATA_LIST[2].tableName + ";\n";
+    gUpdateResponse = "n:1000\n";
+
+    forceTableUpdate();
+  },
+
+];
+
+SERVER_INVOLVED_TEST_CASE_LIST.forEach(t => add_test(t));
+
+// Tests nsIUrlListManager.getGethashUrl.
+add_test(function test_getGethashUrl() {
+  TEST_TABLE_DATA_LIST.forEach(function (t) {
+    equal(gListManager.getGethashUrl(t.tableName), t.gethashUrl);
+  });
+  equal(gListManager.getGethashUrl(TEST_TABLE_DATA_ANOTHER.tableName),
+        TEST_TABLE_DATA_ANOTHER.gethashUrl);
+  run_next_test();
+});
+
+function run_test() {
+  // Setup primary testing server.
+  gHttpServ = new HttpServer();
+  gHttpServ.registerDirectory("/", do_get_cwd());
+
+  gHttpServ.registerPathHandler("/safebrowsing/update", function(request, response) {
+    let body = NetUtil.readInputStreamToString(request.bodyInputStream,
+                                               request.bodyInputStream.available());
+
+    // Verify if the request is as expected.
+    equal(body, gExpectedUpdateRequest);
+
+    // Respond the update which is controlled by the test case.
+    response.setHeader("Content-Type",
+                       "application/vnd.google.safebrowsing-update", false);
+    response.setStatusLine(request.httpVersion, 200, "OK");
+    response.bodyOutputStream.write(gUpdateResponse, gUpdateResponse.length);
+
+    gUpdatedCntForTableData++;
+
+    if (gUpdatedCntForTableData !== SERVER_INVOLVED_TEST_CASE_LIST.length) {
+      // This is not the last test case so run the next once upon the
+      // the update success.
+      waitForUpdateSuccess(run_next_test);
+      return;
+    }
+
+    if (gIsAnotherUpdated) {
+      run_next_test();  // All tests are done. Just finish.
+      return;
+    }
+
+    do_print("Waiting for TEST_TABLE_DATA_ANOTHER to be tested ...");
+  });
+
+  gHttpServ.start(4444);
+
+  // Setup another testing server for the different update URL.
+  gHttpServAnother = new HttpServer();
+  gHttpServAnother.registerDirectory("/", do_get_cwd());
+
+  gHttpServAnother.registerPathHandler("/safebrowsing/update", function(request, response) {
+    let body = NetUtil.readInputStreamToString(request.bodyInputStream,
+                                               request.bodyInputStream.available());
+
+    // Verify if the request is as expected.
+    equal(body, TEST_TABLE_DATA_ANOTHER.tableName + ";\n");
+
+    // Respond with no chunk control.
+    response.setHeader("Content-Type",
+                       "application/vnd.google.safebrowsing-update", false);
+    response.setStatusLine(request.httpVersion, 200, "OK");
+
+    let content = "n:1000\n";
+    response.bodyOutputStream.write(content, content.length);
+
+    gIsAnotherUpdated = true;
+
+    if (gUpdatedCntForTableData === SERVER_INVOLVED_TEST_CASE_LIST.length) {
+      // All tests are done!
+      run_next_test();
+      return;
+    }
+
+    do_print("Wait for all sever-involved tests to be done ...");
+  });
+
+  gHttpServAnother.start(5555);
+
+  run_next_test();
+}
+
+// A trick to force updating tables. However, before calling this, we have to
+// call disableAllUpdates() first to clean up the updateCheckers in listmanager.
+function forceTableUpdate() {
+  prefBranch.setCharPref(PREF_NEXTUPDATETIME, "1");
+  gListManager.maybeToggleUpdateChecking();
+}
+
+function disableAllUpdates() {
+  TEST_TABLE_DATA_LIST.forEach(t => gListManager.disableUpdate(t.tableName));
+  gListManager.disableUpdate(TEST_TABLE_DATA_ANOTHER.tableName);
+}
+
+// Since there's no public interface on listmanager to know the update success,
+// we could only rely on the refresh of "nextupdatetime".
+function waitForUpdateSuccess(callback) {
+  let nextupdatetime = parseInt(prefBranch.getCharPref(PREF_NEXTUPDATETIME));
+  do_print("nextupdatetime: " + nextupdatetime);
+  if (nextupdatetime !== 1) {
+    callback();
+    return;
+  }
+  do_timeout(1000, waitForUpdateSuccess.bind(null, callback));
+}
+
+// Construct an update from a file.
+function readFileToString(aFilename) {
+  let f = do_get_file(aFilename);
+  let stream = Cc["@mozilla.org/network/file-input-stream;1"]
+    .createInstance(Ci.nsIFileInputStream);
+  stream.init(f, -1, 0, 0);
+  let buf = NetUtil.readInputStreamToString(stream, stream.available());
+  return buf;
+}
--- a/toolkit/components/url-classifier/tests/unit/xpcshell.ini
+++ b/toolkit/components/url-classifier/tests/unit/xpcshell.ini
@@ -12,8 +12,9 @@ support-files =
 [test_hashcompleter.js]
 # Bug 752243: Profile cleanup frequently fails
 #skip-if = os == "mac" || os == "linux"
 [test_partial.js]
 [test_prefixset.js]
 [test_provider_url.js]
 [test_streamupdater.js]
 [test_digest256.js]
+[test_listmanager.js]
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1321,16 +1321,32 @@
           if (!this.docShell || !this.docShell.contentViewer) {
             return true;
           }
           return {permitUnload: this.docShell.contentViewer.permitUnload(), timedOut: false};
         ]]>
         </body>
       </method>
 
+      <method name="print">
+        <parameter name="aPrintSettings"/>
+        <parameter name="aPrintProgressListener"/>
+        <body>
+          <![CDATA[
+            var owner = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
+            if (!owner.frameLoader) {
+              throw Components.Exception("No frame loader.",
+                                         Components.results.NS_ERROR_FAILURE);
+            }
+
+            owner.frameLoader.print(aPrintSettings, aPrintProgressListener);
+          ]]>
+        </body>
+      </method>
+
       <!-- This will go away if the binding has been removed for some reason. -->
       <field name="_alive">true</field>
     </implementation>
 
     <handlers>
       <handler event="keypress" keycode="VK_F7" group="system">
         <![CDATA[
           if (event.defaultPrevented || !event.isTrusted)
--- a/widget/android/nsPrintOptionsAndroid.cpp
+++ b/widget/android/nsPrintOptionsAndroid.cpp
@@ -20,17 +20,18 @@ public:
 nsPrintOptionsAndroid::nsPrintOptionsAndroid()
 {
 }
 
 nsPrintOptionsAndroid::~nsPrintOptionsAndroid()
 {
 }
 
-NS_IMETHODIMP nsPrintOptionsAndroid::CreatePrintSettings(nsIPrintSettings **_retval)
+nsresult
+nsPrintOptionsAndroid::_CreatePrintSettings(nsIPrintSettings** _retval)
 {
   nsPrintSettings * printSettings = new nsPrintSettingsAndroid();
   NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
   NS_ADDREF(*_retval = printSettings);
   (void)InitPrintSettingsFromPrefs(*_retval, false,
                                    nsIPrintSettings::kInitSaveAll);
   return NS_OK;
 }
--- a/widget/android/nsPrintOptionsAndroid.h
+++ b/widget/android/nsPrintOptionsAndroid.h
@@ -12,12 +12,12 @@
 //***    nsPrintOptions
 //*****************************************************************************
 class nsPrintOptionsAndroid : public nsPrintOptions
 {
 public:
   nsPrintOptionsAndroid();
   virtual ~nsPrintOptionsAndroid();
 
-  NS_IMETHOD CreatePrintSettings(nsIPrintSettings **_retval);
+  nsresult _CreatePrintSettings(nsIPrintSettings** _retval) override;
 };
 
 #endif /* nsPrintOptionsAndroid_h__ */
--- a/widget/gtk/nsDeviceContextSpecG.cpp
+++ b/widget/gtk/nsDeviceContextSpecG.cpp
@@ -426,21 +426,16 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::In
   DO_PR_DEBUG_LOG(("Setting default filename to '%s'\n", filename.get()));
   aPrintSettings->SetToFileName(NS_ConvertUTF8toUTF16(filename).get());
 
   aPrintSettings->SetIsInitializedFromPrinter(true);
 
   return NS_OK;    
 }
 
-NS_IMETHODIMP nsPrinterEnumeratorGTK::DisplayPropertiesDlg(const char16_t *aPrinter, nsIPrintSettings *aPrintSettings)
-{
-  return NS_OK;
-}
-
 //----------------------------------------------------------------------
 nsresult GlobalPrinters::InitializeGlobalPrinters ()
 {
   if (PrintersAreAllocated()) {
     return NS_OK;
   }
 
   mGlobalPrinterList = new nsTArray<nsString>();
--- a/widget/nsIPrintOptions.idl
+++ b/widget/nsIPrintOptions.idl
@@ -1,109 +1,33 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIPrintSettings.idl"
 
-%{ C++
-struct nsFont;
-
-namespace mozilla {
-namespace embedding {
-  class PrintData;
-}
-}
-%}
-
 interface nsIStringEnumerator;
-interface nsIWebBrowserPrint;
-
-/**
- * Native types
- */
-[ref] native nsNativeFontRef(nsFont);
-[ref] native PrintDataRef(const mozilla::embedding::PrintData);
-[ptr] native PrintDataPtr(mozilla::embedding::PrintData);
 
 /**
  * Print options interface
  *
  * Do not attempt to freeze this API - it still needs lots of work. Consult
  * John Keiser <jkeiser@netscape.com> and Roland Mainz
  * <roland.mainz@informatik.med.uni-giessen.de> for futher details.
  */
 [scriptable, uuid(2ac74034-700e-40fd-8059-81d33223af58)]
 
 interface nsIPrintOptions : nsISupports
 {
   /**
    * Show Native Print Options dialog, this may not be supported on all platforms
    */
   void ShowPrintSetupDialog(in nsIPrintSettings aThePrintSettings);
-
-  /**
-   * Creates a new PrintSettnigs Object
-   * and initializes it from prefs
-   */
-  nsIPrintSettings CreatePrintSettings();
-
-  /**
-   * Get a prefixed integer pref 
-   */
-  int32_t getPrinterPrefInt(in nsIPrintSettings aPrintSettings, in wstring
-                            aPrefName);
-
-  /**
-   * display Printer Job Properties dialog
-   */
-  void displayJobProperties (in wstring aPrinter, in nsIPrintSettings
-                             aPrintSettings, out boolean aDisplayed);
-
-  /**
-   * Native data constants
-   */
-  const short kNativeDataPrintRecord        = 0;
-
-  [noscript] voidPtr GetNativeData(in short aDataType);
-
-  /**
-   * Given some nsIPrintSettings and (optionally) an nsIWebBrowserPrint, populates
-   * a PrintData representing them which can be sent over IPC. Values are only
-   * ever read from aSettings and aWBP.
-   *
-   * @param aSettings
-   *        An nsIPrintSettings for a print job.
-   * @param aWBP (optional)
-   *        The nsIWebBrowserPrint for the print job.
-   * @param data
-   *        Pointer to a pre-existing PrintData to populate.
-   *
-   * @return nsresult
-   */
-  [noscript] void SerializeToPrintData(in nsIPrintSettings aPrintSettings,
-                                       in nsIWebBrowserPrint aWebBrowserPrint,
-                                       in PrintDataPtr data);
-
-  /**
-   * This function is the opposite of SerializeToPrintData, in that it takes
-   * a PrintData, and populates a pre-existing nsIPrintSettings with the data
-   * from PrintData.
-   *
-   * @param PrintData
-   *        Printing information sent through IPC.
-   * @param settings
-   *        A pre-existing nsIPrintSettings to populate with the PrintData.
-   *
-   * @return nsresult
-   */
-  [noscript] void DeserializeToPrintSettings(in PrintDataRef data,
-                                             in nsIPrintSettings aPrintSettings);
 };
 
 [scriptable, uuid(5e738fff-404c-4c94-9189-e8f2cce93e94)]
 
 interface nsIPrinterEnumerator : nsISupports
 {
   /**
    * The name of the system default printer. This name should also be
@@ -121,16 +45,10 @@ interface nsIPrinterEnumerator : nsISupp
    *   Number of Copies
    */
   void initPrintSettingsFromPrinter(in wstring aPrinterName, in nsIPrintSettings aPrintSettings);
 
   /**
    * The list of printer names
    */
   readonly attribute nsIStringEnumerator printerNameList;
-
-  /*  takes printer selected and will display job properties dlg for that printer
-   *  returns true if dialog displays
-   */
-  void displayPropertiesDlg(in wstring aPrinter, in nsIPrintSettings aPrintSettings);
-
 };
 
--- a/widget/nsIPrintSettingsService.idl
+++ b/widget/nsIPrintSettingsService.idl
@@ -5,16 +5,31 @@
 
 /* Interface to the Service for gwetting the Global PrintSettings object
    or a unique PrintSettings object
 */
 
 #include "nsISupports.idl"
 
 interface nsIPrintSettings;
+interface nsIWebBrowserPrint;
+
+%{ C++
+namespace mozilla {
+namespace embedding {
+  class PrintData;
+}
+}
+%}
+
+/**
+ * Native types
+ */
+[ref] native PrintDataRef(const mozilla::embedding::PrintData);
+[ptr] native PrintDataPtr(mozilla::embedding::PrintData);
 
 [scriptable, uuid(841387C8-72E6-484b-9296-BF6EEA80D58A)]
 interface nsIPrintSettingsService : nsISupports
 {
   /**
    * Returns a "global" PrintSettings object 
    * Creates a new the first time, if one doesn't exist.
    *
@@ -29,17 +44,18 @@ interface nsIPrintSettingsService : nsIS
    *
    * For example, if each browser was to have its own unique
    * PrintSettings, then each browser window would call this to
    * create its own unique PrintSettings object.
    *
    * If each browse window was to use the same PrintSettings object
    * then it should use "globalPrintSettings"
    *
-   * Initializes the newPrintSettings from the default printer
+   * Initializes the newPrintSettings from the unprefixed printer
+   * (Note: this may not happen if there is an OS specific implementation.)
    *
    */
   readonly attribute nsIPrintSettings newPrintSettings;
 
   /**
    * The name of the last printer used, or else the system default printer.
    */
   readonly attribute wstring defaultPrinterName;
@@ -92,15 +108,50 @@ interface nsIPrintSettingsService : nsIS
    * Items not written:
    *   startPageRange, endPageRange, scaling, printRange, title
    *   docURL, howToEnableFrameUI, isCancelled, printFrameTypeUsage
    *   printFrameType, printSilent, shrinkToFit, numCopies
    *
    */
   void savePrintSettingsToPrefs(in nsIPrintSettings aPrintSettings, in boolean aUsePrinterNamePrefix, in unsigned long aFlags);
 
+  /**
+   * Given some nsIPrintSettings and (optionally) an nsIWebBrowserPrint,
+   * populates a PrintData representing them which can be sent over IPC. Values
+   * are only ever read from aSettings and aWBP.
+   *
+   * @param aSettings
+   *        An nsIPrintSettings for a print job.
+   * @param aWBP (optional)
+   *        The nsIWebBrowserPrint for the print job.
+   * @param data
+   *        Pointer to a pre-existing PrintData to populate.
+   *
+   * @return nsresult
+   */
+  [noscript]
+  void SerializeToPrintData(in nsIPrintSettings aPrintSettings,
+                            in nsIWebBrowserPrint aWebBrowserPrint,
+                            in PrintDataPtr data);
+
+  /**
+   * This function is the opposite of SerializeToPrintData, in that it takes
+   * a PrintData, and populates a pre-existing nsIPrintSettings with the data
+   * from PrintData.
+   *
+   * @param PrintData
+   *        Printing information sent through IPC.
+   * @param settings
+   *        A pre-existing nsIPrintSettings to populate with the PrintData.
+   *
+   * @return nsresult
+   */
+  [noscript]
+  void DeserializeToPrintSettings(in PrintDataRef data,
+                                  in nsIPrintSettings aPrintSettings);
+
 };
 
 %{C++
 // {841387C8-72E6-484b-9296-BF6EEA80D58A}
 #define NS_PRINTSETTINGSSERVICE_IID \
  {0x841387c8, 0x72e6, 0x484b, { 0x92, 0x96, 0xbf, 0x6e, 0xea, 0x80, 0xd5, 0x8a}}
 %}
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -7,19 +7,19 @@
 
 #include "mozilla/embedding/PPrinting.h"
 #include "mozilla/layout/RemotePrintJobChild.h"
 #include "mozilla/RefPtr.h"
 #include "nsPrintingProxy.h"
 #include "nsReadableUtils.h"
 #include "nsPrintSettingsImpl.h"
 #include "nsIPrintSession.h"
+#include "nsServiceManagerUtils.h"
 
 #include "nsIDOMWindow.h"
-#include "nsIServiceManager.h"
 #include "nsIDialogParamBlock.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIWindowWatcher.h"
 #include "nsISupportsArray.h"
 #include "prprf.h"
 
 #include "nsIStringEnumerator.h"
@@ -100,16 +100,26 @@ nsPrintOptions::Init()
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrintOptions::SerializeToPrintData(nsIPrintSettings* aSettings,
                                      nsIWebBrowserPrint* aWBP,
                                      PrintData* data)
 {
+  nsCOMPtr<nsIPrintSession> session;
+  nsresult rv = aSettings->GetPrintSession(getter_AddRefs(session));
+  if (NS_SUCCEEDED(rv) && session) {
+    RefPtr<RemotePrintJobChild> remotePrintJob;
+    rv = session->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
+    if (NS_SUCCEEDED(rv)) {
+      data->remotePrintJobChild() = remotePrintJob;
+    }
+  }
+
   aSettings->GetStartPageRange(&data->startPageRange());
   aSettings->GetEndPageRange(&data->endPageRange());
 
   aSettings->GetEdgeTop(&data->edgeTop());
   aSettings->GetEdgeLeft(&data->edgeLeft());
   aSettings->GetEdgeBottom(&data->edgeBottom());
   aSettings->GetEdgeRight(&data->edgeRight());
 
@@ -960,43 +970,16 @@ nsPrintOptions::WritePrefs(nsIPrintSetti
   }
 
   // Not Writing Out:
   //   Number of Copies
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsPrintOptions::DisplayJobProperties(const char16_t *aPrinter,
-                                     nsIPrintSettings* aPrintSettings,
-                                     bool *aDisplayed)
-{
-  NS_ENSURE_ARG_POINTER(aPrinter);
-  *aDisplayed = false;
-
-  nsresult rv;
-  nsCOMPtr<nsIPrinterEnumerator> propDlg =
-           do_CreateInstance(NS_PRINTER_ENUMERATOR_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_ENSURE_ARG_POINTER(aPrintSettings);
-  rv = propDlg->DisplayPropertiesDlg(aPrinter, aPrintSettings);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aDisplayed = true;
-
-  return rv;
-}
-
-NS_IMETHODIMP nsPrintOptions::GetNativeData(int16_t aDataType, void * *_retval)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
 nsresult nsPrintOptions::_CreatePrintSettings(nsIPrintSettings **_retval)
 {
   // does not initially ref count
   nsPrintSettings * printSettings = new nsPrintSettings();
   NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*_retval = printSettings); // ref count
 
@@ -1006,38 +989,33 @@ nsresult nsPrintOptions::_CreatePrintSet
   (*_retval)->SetPrinterName(printerName.get());
 
   (void)InitPrintSettingsFromPrefs(*_retval, false,
                                    nsIPrintSettings::kInitSaveAll);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintOptions::CreatePrintSettings(nsIPrintSettings **_retval)
-{
-  return _CreatePrintSettings(_retval);
-}
-
 NS_IMETHODIMP
 nsPrintOptions::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings)
 {
   nsresult rv;
 
-  rv = CreatePrintSettings(getter_AddRefs(mGlobalPrintSettings));
+  rv = _CreatePrintSettings(getter_AddRefs(mGlobalPrintSettings));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*aGlobalPrintSettings = mGlobalPrintSettings.get());
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsPrintOptions::GetNewPrintSettings(nsIPrintSettings * *aNewPrintSettings)
 {
-  return CreatePrintSettings(aNewPrintSettings);
+  return _CreatePrintSettings(aNewPrintSettings);
 }
 
 NS_IMETHODIMP
 nsPrintOptions::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
 {
   nsresult rv;
   nsCOMPtr<nsIPrinterEnumerator> prtEnum =
            do_GetService(NS_PRINTER_ENUMERATOR_CONTRACTID, &rv);
@@ -1099,16 +1077,17 @@ nsPrintOptions::InitPrintSettingsFromPri
 
   rv = prtEnum->InitPrintSettingsFromPrinter(aPrinterName, aPrintSettings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aPrintSettings->SetIsInitializedFromPrinter(true);
   return rv;
 }
 
+#ifndef MOZ_X11
 /** ---------------------------------------------------
  *  Helper function - Returns either the name or sets the length to zero
  */
 static nsresult 
 GetAdjustedPrinterName(nsIPrintSettings* aPS, bool aUsePNP,
                        nsAString& aPrinterName)
 {
   NS_ENSURE_ARG_POINTER(aPS);
@@ -1138,41 +1117,17 @@ GetAdjustedPrinterName(nsIPrintSettings*
     int32_t i = 0;
     while ((i = aPrinterName.FindChar(uChar, i)) != kNotFound) {
       aPrinterName.Replace(i, 1, replSubstr);
       i++;
     }
   }
   return NS_OK;
 }
-
-NS_IMETHODIMP
-nsPrintOptions::GetPrinterPrefInt(nsIPrintSettings *aPrintSettings,
-                                  const char16_t *aPrefName, int32_t *_retval)
-{
-  NS_ENSURE_ARG_POINTER(aPrintSettings);
-  NS_ENSURE_ARG_POINTER(aPrefName);
-
-  nsAutoString prtName;
-  // Get the Printer Name from the PrintSettings
-  // to use as a prefix for Pref Names
-  GetAdjustedPrinterName(aPrintSettings, true, prtName);
-
-  const char* prefName =
-    GetPrefName(NS_LossyConvertUTF16toASCII(aPrefName).get(), prtName);
-
-  NS_ENSURE_TRUE(prefName, NS_ERROR_FAILURE);
-
-  int32_t iVal;
-  nsresult rv = Preferences::GetInt(prefName, &iVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *_retval = iVal;
-  return rv;
-}
+#endif
 
 NS_IMETHODIMP 
 nsPrintOptions::InitPrintSettingsFromPrefs(nsIPrintSettings* aPS,
                                            bool aUsePNP, uint32_t aFlags)
 {
   NS_ENSURE_ARG_POINTER(aPS);
 
   bool isInitialized;
--- a/widget/qt/nsDeviceContextSpecQt.cpp
+++ b/widget/qt/nsDeviceContextSpecQt.cpp
@@ -251,16 +251,8 @@ NS_IMETHODIMP nsPrinterEnumeratorQt::Ini
         const char16_t* aPrinterName,
         nsIPrintSettings* aPrintSettings)
 {
     DO_PR_DEBUG_LOG(("nsPrinterEnumeratorQt::InitPrintSettingsFromPrinter()"));
     // XXX Leave NS_OK for now
     // Probably should use NS_ERROR_NOT_IMPLEMENTED
     return NS_OK;
 }
-
-NS_IMETHODIMP nsPrinterEnumeratorQt::DisplayPropertiesDlg(
-        const char16_t* aPrinter,
-        nsIPrintSettings* aPrintSettings)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
--- a/widget/windows/nsDeviceContextSpecWin.cpp
+++ b/widget/windows/nsDeviceContextSpecWin.cpp
@@ -509,24 +509,16 @@ nsPrinterEnumeratorWin::GetPrinterNameLi
     LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx);
     names[printerInx].Assign(name);
   }
 
   return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
 }
 
 //----------------------------------------------------------------------------------
-// Display the AdvancedDocumentProperties for the selected Printer
-NS_IMETHODIMP nsPrinterEnumeratorWin::DisplayPropertiesDlg(const char16_t *aPrinterName, nsIPrintSettings* aPrintSettings)
-{
-  // Implementation removed because it is unused
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------------------
 //-- Global Printers
 //----------------------------------------------------------------------------------
 
 //----------------------------------------------------------------------------------
 // THe array hold the name and port for each printer
 void 
 GlobalPrinters::ReallocatePrinters()
 {