Merge mozilla-central to autoland. a=merge CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Thu, 03 May 2018 00:07:30 +0300
changeset 472829 4cd21995f6d93788eeb72e5f62f59dd2861a0a2f
parent 472828 aa5c4afe0acb45067fe6985bd94f407138f323e0 (current diff)
parent 472826 2d83e1843241d869a2fc5cf06f96d3af44c70e70 (diff)
child 472830 5da4a0c6ba28e6ba399624085195cf6c09df170b
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
taskcluster/ci/release-source/source.yml
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6935,17 +6935,17 @@ var WebAuthnPromptHelper = {
       this.sign(mgr, data);
     } else if (data.action == "cancel") {
       this.cancel(data);
     }
   },
 
   register(mgr, {origin, tid}) {
     let mainAction = this.buildCancelAction(mgr, tid);
-    this.show(tid, "register", "webauthn.registerPrompt", origin, mainAction);
+    this.show(tid, "register", "webauthn.registerPrompt2", origin, mainAction);
   },
 
   registerDirect(mgr, {origin, tid}) {
     let mainAction = this.buildProceedAction(mgr, tid);
     let secondaryActions = [this.buildCancelAction(mgr, tid)];
 
     let learnMoreURL =
       Services.urlFormatter.formatURLPref("app.support.baseURL") +
@@ -6953,23 +6953,23 @@ var WebAuthnPromptHelper = {
 
     let options = {
       learnMoreURL,
       checkbox: {
         label: gNavigatorBundle.getString("webauthn.anonymize")
       }
     };
 
-    this.show(tid, "register-direct", "webauthn.registerDirectPrompt",
+    this.show(tid, "register-direct", "webauthn.registerDirectPrompt2",
               origin, mainAction, secondaryActions, options);
   },
 
   sign(mgr, {origin, tid}) {
     let mainAction = this.buildCancelAction(mgr, tid);
-    this.show(tid, "sign", "webauthn.signPrompt", origin, mainAction);
+    this.show(tid, "sign", "webauthn.signPrompt2", origin, mainAction);
   },
 
   show(tid, id, stringId, origin, mainAction, secondaryActions = [], options = {}) {
     this.reset();
 
     try {
       origin = Services.io.newURI(origin).asciiHost;
     } catch (e) {
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -2493,18 +2493,19 @@ var gMainPane = {
       // compute index to display download folder label and icon to avoid
       // displaying blank downloadFolder label and icon on load of preferences UI
       // Set folderIndex to 1 if currentDirPref is unspecified
       folderIndex = currentDirPref.value ? await this._folderToIndex(currentDirPref.value) : 1;
     }
 
     // Display a 'pretty' label or the path in the UI.
     if (folderIndex == 2) {
-      // Custom path selected and is configured
-      downloadFolder.value = currentDirPref.value ? currentDirPref.value.path : "";
+      // Force the left-to-right direction when displaying a custom path.
+      downloadFolder.value = currentDirPref.value ?
+        `\u2066${currentDirPref.value.path}\u2069` : "";
       iconUrlSpec = fph.getURLSpecFromFile(currentDirPref.value);
     } else if (folderIndex == 1) {
       // 'Downloads'
       downloadFolder.value = bundlePreferences.getString("downloadsFolderName");
       iconUrlSpec = fph.getURLSpecFromFile(await this._indexToFolder(1));
     } else {
       // 'Desktop'
       downloadFolder.value = bundlePreferences.getString("desktopFolderName");
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -482,31 +482,31 @@ offlineApps.manageUsageAccessKey=S
 canvas.siteprompt=Will you allow %S to use your HTML5 canvas image data? This may be used to uniquely identify your computer.
 canvas.notAllow=Don’t Allow
 canvas.notAllow.accesskey=n
 canvas.allow=Allow Data Access
 canvas.allow.accesskey=A
 canvas.remember=Always remember my decision
 
 # WebAuthn prompts
-# LOCALIZATION NOTE (webauthn.registerPrompt): %S is hostname
-webauthn.registerPrompt=%S wants to register an account with one of your security tokens. You can connect and authorize one now, or cancel.
-# LOCALIZATION NOTE (webauthn.registerDirectPrompt):
+# LOCALIZATION NOTE (webauthn.registerPrompt2): %S is hostname
+webauthn.registerPrompt2=%S wants to register an account with one of your security keys. You can connect and authorize one now, or cancel.
+# LOCALIZATION NOTE (webauthn.registerDirectPrompt2):
 # %1$S is hostname. %2$S is brandShortName.
 # The website is asking for extended information about your
 # hardware authenticator that shouldn't be generally necessary. Permitting
 # this is safe if you only use one account at this website. If you have
 # multiple accounts at this website, and you use the same hardware
 # authenticator, then the website could link those accounts together.
 # And this is true even if you use a different profile / browser (or even Tor
 # Browser). To avoid this, you should use different hardware authenticators
 # for different accounts on this website.
-webauthn.registerDirectPrompt=%1$S is requesting extended information about your authenticator, which may affect your privacy.\n\n%2$S can anonymize this for you, but the website might decline this authenticator. If declined, you can try again.
-# LOCALIZATION NOTE (webauthn.signPrompt): %S is hostname
-webauthn.signPrompt=%S wants to authenticate you using a registered security token. You can connect and authorize one now, or cancel.
+webauthn.registerDirectPrompt2=%1$S is requesting extended information about your security key, which may affect your privacy.\n\n%2$S can anonymize this for you, but the website might decline this key. If declined, you can try again.
+# LOCALIZATION NOTE (webauthn.signPrompt2): %S is hostname
+webauthn.signPrompt2=%S wants to authenticate you using a registered security key. You can connect and authorize one now, or cancel.
 webauthn.cancel=Cancel
 webauthn.cancel.accesskey=c
 webauthn.proceed=Proceed
 webauthn.proceed.accesskey=p
 webauthn.anonymize=Anonymize anyway
 
 # Spoof Accept-Language prompt
 privacy.spoof_english=Changing your language setting to English will make you more difficult to identify and enhance your privacy. Do you want to request English language versions of web pages?
--- a/dom/base/DOMMozPromiseRequestHolder.h
+++ b/dom/base/DOMMozPromiseRequestHolder.h
@@ -37,16 +37,26 @@ namespace dom {
  *
  *      RefPtr<DOMMozPromiseRequestHolder> holder =
  *        new DOMMozPromiseRequestHolder(global);
  *
  *      DoAsyncStuff()->Then(
  *        global->EventTargetFor(TaskCategory::Other), __func__,
  *        [holder, outer] (const Result& aResult) {
  *          holder->Complete();
+ *
+ *          // Note, you can access the holder's bound global in
+ *          // your reaction handler.  Its mostly likely set if
+ *          // the handler fires, but you still must check for
+ *          // its existence since something could disconnect
+ *          // the global between when the MozPromise reaction
+ *          // runnable is queued and when it actually runs.
+ *          nsIGlobalObject* global = holder->GetParentObject();
+ *          NS_ENSURE_TRUE_VOID(global);
+ *
  *          outer->MaybeResolve(aResult);
  *        }, [holder, outer] (nsresult aRv) {
  *          holder->Complete();
  *          outer->MaybeReject(aRv);
  *        })->Track(*holder);
  *
  *      return outer.forget();
  *    }
@@ -96,17 +106,16 @@ public:
   {
     return mHolder;
   }
 
   void
   Complete()
   {
     mHolder.Complete();
-    DisconnectFromOwner();
   }
 
   void
   DisconnectIfExists()
   {
     mHolder.DisconnectIfExists();
   }
 
--- a/dom/clients/api/Client.cpp
+++ b/dom/clients/api/Client.cpp
@@ -6,16 +6,17 @@
 
 #include "Client.h"
 
 #include "ClientDOMUtil.h"
 #include "mozilla/dom/ClientHandle.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientState.h"
+#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "nsIGlobalObject.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -167,40 +168,33 @@ Client::Focus(ErrorResult& aRv)
     return outerPromise.forget();
   }
 
   if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
     outerPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return outerPromise.forget();
   }
 
-  // Hold the worker thread alive while we perform the async operation
-  // and also avoid invoking callbacks if the worker starts shutting
-  // down.
-  RefPtr<WorkerHolderToken> token =
-    WorkerHolderToken::Create(GetCurrentThreadWorkerPrivate(), Closing);
+  EnsureHandle();
 
-  EnsureHandle();
-  RefPtr<ClientStatePromise> innerPromise = mHandle->Focus();
-  RefPtr<Client> self = this;
+  IPCClientInfo ipcClientInfo(mData->info());
+  auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<ClientStatePromise>>(mGlobal);
 
-  innerPromise->Then(mGlobal->EventTargetFor(TaskCategory::Other), __func__,
-    [self, token, outerPromise] (const ClientState& aResult) {
-      if (token->IsShuttingDown()) {
-        return;
-      }
-      RefPtr<Client> newClient =
-        new Client(self->mGlobal, ClientInfoAndState(self->mData->info(), aResult.ToIPC()));
+  mHandle->Focus()->Then(mGlobal->EventTargetFor(TaskCategory::Other), __func__,
+    [ipcClientInfo, holder, outerPromise] (const ClientState& aResult) {
+      holder->Complete();
+      NS_ENSURE_TRUE_VOID(holder->GetParentObject());
+      RefPtr<Client> newClient = new Client(holder->GetParentObject(),
+                                            ClientInfoAndState(ipcClientInfo,
+                                                               aResult.ToIPC()));
       outerPromise->MaybeResolve(newClient);
-    }, [self, token, outerPromise] (nsresult aResult) {
-      if (token->IsShuttingDown()) {
-        return;
-      }
+    }, [holder, outerPromise] (nsresult aResult) {
+      holder->Complete();
       outerPromise->MaybeReject(aResult);
-    });
+    })->Track(*holder);
 
   return outerPromise.forget();
 }
 
 already_AddRefed<Promise>
 Client::Navigate(const nsAString& aURL, ErrorResult& aRv)
 {
   MOZ_ASSERT(!NS_IsMainThread());
@@ -213,18 +207,17 @@ Client::Navigate(const nsAString& aURL, 
   if (aRv.Failed()) {
     return outerPromise.forget();
   }
 
   ClientNavigateArgs args(mData->info(), NS_ConvertUTF16toUTF8(aURL),
                           workerPrivate->GetLocationInfo().mHref);
   RefPtr<Client> self = this;
 
-  StartClientManagerOp(&ClientManager::Navigate, args,
-    mGlobal->EventTargetFor(TaskCategory::Other),
+  StartClientManagerOp(&ClientManager::Navigate, args, mGlobal,
     [self, outerPromise] (const ClientOpResult& aResult) {
       if (aResult.type() != ClientOpResult::TClientInfoAndState) {
         outerPromise->MaybeResolve(JS::NullHandleValue);
         return;
       }
       RefPtr<Client> newClient =
         new Client(self->mGlobal, aResult.get_ClientInfoAndState());
       outerPromise->MaybeResolve(newClient);
--- a/dom/clients/api/ClientDOMUtil.h
+++ b/dom/clients/api/ClientDOMUtil.h
@@ -3,49 +3,47 @@
 /* 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_dom_ClientDOMUtil_h
 #define _mozilla_dom_ClientDOMUtil_h
 
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/ClientOpPromise.h"
+#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
 #include "mozilla/dom/WorkerHolderToken.h"
 #include "mozilla/dom/WorkerPrivate.h"
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 // Utility method to properly execute a ClientManager operation.  It
 // will properly hold a worker thread alive and avoid executing callbacks
 // if the thread is shutting down.
 template<typename Func, typename Arg, typename Resolve, typename Reject>
 void
-StartClientManagerOp(Func aFunc, const Arg& aArg, nsISerialEventTarget* aTarget,
+StartClientManagerOp(Func aFunc, const Arg& aArg, nsIGlobalObject* aGlobal,
                      Resolve aResolve, Reject aReject)
 {
-  RefPtr<WorkerHolderToken> token;
-  if (!NS_IsMainThread()) {
-    token = WorkerHolderToken::Create(GetCurrentThreadWorkerPrivate(),
-                                      WorkerStatus::Closing);
-  }
+  MOZ_DIAGNOSTIC_ASSERT(aGlobal);
+
+  nsCOMPtr<nsISerialEventTarget> target =
+    aGlobal->EventTargetFor(TaskCategory::Other);
+
+  auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<ClientOpPromise>>(aGlobal);
 
-  RefPtr<ClientOpPromise> promise = aFunc(aArg, aTarget);
-  promise->Then(aTarget, __func__,
-    [aResolve, token](const ClientOpResult& aResult) {
-      if (token && token->IsShuttingDown()) {
-        return;
-      }
+  aFunc(aArg, target)->Then(
+    target, __func__,
+    [aResolve, holder](const ClientOpResult& aResult) {
+      holder->Complete();
       aResolve(aResult);
-    }, [aReject, token](nsresult aResult) {
-      if (token && token->IsShuttingDown()) {
-        return;
-      }
+    }, [aReject, holder](nsresult aResult) {
+      holder->Complete();
       aReject(aResult);
-    });
+    })->Track(*holder);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientDOMUtil_h
--- a/dom/clients/api/Clients.cpp
+++ b/dom/clients/api/Clients.cpp
@@ -79,37 +79,41 @@ Clients::Get(const nsAString& aClientID,
   const PrincipalInfo& principalInfo = workerPrivate->GetPrincipalInfo();
   nsCOMPtr<nsISerialEventTarget> target =
     mGlobal->EventTargetFor(TaskCategory::Other);
 
   RefPtr<ClientOpPromise> innerPromise =
     ClientManager::GetInfoAndState(ClientGetInfoAndStateArgs(id, principalInfo),
                                    target);
 
-  nsCOMPtr<nsIGlobalObject> global = mGlobal;
   nsCString scope = workerPrivate->ServiceWorkerScope();
+  auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<ClientOpPromise>>(mGlobal);
 
   innerPromise->Then(target, __func__,
-    [outerPromise, global, scope] (const ClientOpResult& aResult) {
-      RefPtr<Client> client = new Client(global, aResult.get_ClientInfoAndState());
+    [outerPromise, holder, scope] (const ClientOpResult& aResult) {
+      holder->Complete();
+      NS_ENSURE_TRUE_VOID(holder->GetParentObject());
+      RefPtr<Client> client = new Client(holder->GetParentObject(),
+                                         aResult.get_ClientInfoAndState());
       if (client->GetStorageAccess() == nsContentUtils::StorageAccess::eAllow) {
         outerPromise->MaybeResolve(Move(client));
         return;
       }
       nsCOMPtr<nsIRunnable> r =
-        NS_NewRunnableFunction("Clients::MatchAll() storage denied",
+        NS_NewRunnableFunction("Clients::Get() storage denied",
         [scope] {
           ServiceWorkerManager::LocalizeAndReportToAllClients(
             scope, "ServiceWorkerGetClientStorageError", nsTArray<nsString>());
         });
       SystemGroup::Dispatch(TaskCategory::Other, r.forget());
       outerPromise->MaybeResolveWithUndefined();
-    }, [outerPromise] (nsresult aResult) {
+    }, [outerPromise, holder] (nsresult aResult) {
+      holder->Complete();
       outerPromise->MaybeResolveWithUndefined();
-    });
+    })->Track(*holder);
 
   return outerPromise.forget();
 }
 
 namespace {
 
 class MatchAllComparator final
 {
@@ -161,18 +165,17 @@ Clients::MatchAll(const ClientQueryOptio
   }
 
   nsCOMPtr<nsIGlobalObject> global = mGlobal;
   nsCString scope = workerPrivate->ServiceWorkerScope();
 
   ClientMatchAllArgs args(workerPrivate->GetServiceWorkerDescriptor().ToIPC(),
                           aOptions.mType,
                           aOptions.mIncludeUncontrolled);
-  StartClientManagerOp(&ClientManager::MatchAll, args,
-    mGlobal->EventTargetFor(TaskCategory::Other),
+  StartClientManagerOp(&ClientManager::MatchAll, args, mGlobal,
     [outerPromise, global, scope] (const ClientOpResult& aResult) {
       nsTArray<RefPtr<Client>> clientList;
       bool storageDenied = false;
       for (const ClientInfoAndState& value : aResult.get_ClientList().values()) {
         RefPtr<Client> client = new Client(global, value);
         if (client->GetStorageAccess() != nsContentUtils::StorageAccess::eAllow) {
           storageDenied = true;
           continue;
@@ -224,18 +227,17 @@ Clients::OpenWindow(const nsAString& aUR
 
   const PrincipalInfo& principalInfo = workerPrivate->GetPrincipalInfo();
   nsCString baseURL = workerPrivate->GetLocationInfo().mHref;
   ClientOpenWindowArgs args(principalInfo, NS_ConvertUTF16toUTF8(aURL),
                             baseURL);
 
   nsCOMPtr<nsIGlobalObject> global = mGlobal;
 
-  StartClientManagerOp(&ClientManager::OpenWindow, args,
-    mGlobal->EventTargetFor(TaskCategory::Other),
+  StartClientManagerOp(&ClientManager::OpenWindow, args, mGlobal,
     [outerPromise, global] (const ClientOpResult& aResult) {
       if (aResult.type() != ClientOpResult::TClientInfoAndState) {
         outerPromise->MaybeResolve(JS::NullHandleValue);
         return;
       }
       RefPtr<Client> client =
         new Client(global, aResult.get_ClientInfoAndState());
       outerPromise->MaybeResolve(client);
@@ -266,18 +268,18 @@ Clients::Claim(ErrorResult& aRv)
     workerPrivate->GetServiceWorkerDescriptor();
 
   if (serviceWorker.State() != ServiceWorkerState::Activating &&
       serviceWorker.State() != ServiceWorkerState::Activated) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return outerPromise.forget();
   }
 
-  StartClientManagerOp(&ClientManager::Claim, ClientClaimArgs(serviceWorker.ToIPC()),
-    mGlobal->EventTargetFor(TaskCategory::Other),
+  StartClientManagerOp(
+    &ClientManager::Claim, ClientClaimArgs(serviceWorker.ToIPC()), mGlobal,
     [outerPromise] (const ClientOpResult& aResult) {
       outerPromise->MaybeResolveWithUndefined();
     }, [outerPromise] (nsresult aResult) {
       outerPromise->MaybeReject(aResult);
     });
 
   return outerPromise.forget();
 }
--- a/dom/clients/manager/ClientHandle.cpp
+++ b/dom/clients/manager/ClientHandle.cpp
@@ -32,42 +32,37 @@ ClientHandle::Shutdown()
     return;
   }
 
   ShutdownThing();
 
   mManager = nullptr;
 }
 
-already_AddRefed<ClientOpPromise>
-ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs)
+void
+ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs,
+                      const ClientOpCallback&& aResolveCallback,
+                      const ClientOpCallback&& aRejectCallback)
 {
-  RefPtr<ClientOpPromise::Private> promise =
-    new ClientOpPromise::Private(__func__);
-
   // Hold a ref to the client until the remote operation completes.  Otherwise
   // the ClientHandle might get de-refed and teardown the actor before we
   // get an answer.
   RefPtr<ClientHandle> kungFuGrip = this;
-  promise->Then(mSerialEventTarget, __func__,
-                [kungFuGrip] (const ClientOpResult &) { },
-                [kungFuGrip] (nsresult) { });
 
-  MaybeExecute([aArgs, promise] (ClientHandleChild* aActor) {
-    ClientHandleOpChild* actor = new ClientHandleOpChild(aArgs, promise);
+  MaybeExecute([aArgs, kungFuGrip, aRejectCallback,
+                resolve = Move(aResolveCallback)] (ClientHandleChild* aActor) {
+    ClientHandleOpChild* actor =
+      new ClientHandleOpChild(aArgs, Move(resolve), Move(aRejectCallback));
     if (!aActor->SendPClientHandleOpConstructor(actor, aArgs)) {
-      // Constructor failure will reject promise via ActorDestroy()
+      // Constructor failure will call reject callback via ActorDestroy()
       return;
     }
-  }, [promise] {
-    promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
+  }, [aRejectCallback, kungFuGrip] {
+    aRejectCallback(NS_ERROR_DOM_INVALID_STATE_ERR);
   });
-
-  RefPtr<ClientOpPromise> ref = promise.get();
-  return ref.forget();
 }
 
 void
 ClientHandle::OnShutdownThing()
 {
   NS_ASSERT_OWNINGTHREAD(ClientHandle);
   if (!mDetachPromise) {
     return;
@@ -119,39 +114,34 @@ ClientHandle::Info() const
 }
 
 RefPtr<GenericPromise>
 ClientHandle::Control(const ServiceWorkerDescriptor& aServiceWorker)
 {
   RefPtr<GenericPromise::Private> outerPromise =
     new GenericPromise::Private(__func__);
 
-  RefPtr<ClientOpPromise> innerPromise =
-    StartOp(ClientControlledArgs(aServiceWorker.ToIPC()));
-
-  innerPromise->Then(mSerialEventTarget, __func__,
+  StartOp(ClientControlledArgs(aServiceWorker.ToIPC()),
     [outerPromise](const ClientOpResult& aResult) {
       outerPromise->Resolve(true, __func__);
     },
     [outerPromise](const ClientOpResult& aResult) {
       outerPromise->Reject(aResult.get_nsresult(), __func__);
     });
 
   return outerPromise.forget();
 }
 
 RefPtr<ClientStatePromise>
 ClientHandle::Focus()
 {
   RefPtr<ClientStatePromise::Private> outerPromise =
     new ClientStatePromise::Private(__func__);
 
-  RefPtr<ClientOpPromise> innerPromise = StartOp(ClientFocusArgs());
-
-  innerPromise->Then(mSerialEventTarget, __func__,
+  StartOp(ClientFocusArgs(),
     [outerPromise](const ClientOpResult& aResult) {
       outerPromise->Resolve(ClientState::FromIPC(aResult.get_IPCClientState()), __func__);
     }, [outerPromise](const ClientOpResult& aResult) {
       outerPromise->Reject(aResult.get_nsresult(), __func__);
     });
 
   RefPtr<ClientStatePromise> ref = outerPromise.get();
   return ref.forget();
@@ -175,18 +165,17 @@ ClientHandle::PostMessage(StructuredClon
                                                       args.clonedData())) {
     ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
     return ref.forget();
   }
 
   RefPtr<GenericPromise::Private> outerPromise =
     new GenericPromise::Private(__func__);
 
-  RefPtr<ClientOpPromise> innerPromise = StartOp(args);
-  innerPromise->Then(mSerialEventTarget, __func__,
+  StartOp(args,
     [outerPromise](const ClientOpResult& aResult) {
       outerPromise->Resolve(true, __func__);
     }, [outerPromise](const ClientOpResult& aResult) {
       outerPromise->Reject(aResult.get_nsresult(), __func__);
     });
 
   ref = outerPromise.get();
   return ref.forget();
--- a/dom/clients/manager/ClientHandle.h
+++ b/dom/clients/manager/ClientHandle.h
@@ -45,18 +45,20 @@ class ClientHandle final : public Client
   RefPtr<GenericPromise::Private> mDetachPromise;
   ClientInfo mClientInfo;
 
   ~ClientHandle();
 
   void
   Shutdown();
 
-  already_AddRefed<ClientOpPromise>
-  StartOp(const ClientOpConstructorArgs& aArgs);
+  void
+  StartOp(const ClientOpConstructorArgs& aArgs,
+          const ClientOpCallback&& aResolveCallback,
+          const ClientOpCallback&& aRejectCallback);
 
   // ClientThing interface
   void
   OnShutdownThing() override;
 
   // Private methods called by ClientHandleChild
   void
   ExecutionReady(const ClientInfo& aClientInfo);
--- a/dom/clients/manager/ClientHandleOpChild.cpp
+++ b/dom/clients/manager/ClientHandleOpChild.cpp
@@ -7,42 +7,35 @@
 #include "ClientHandleOpChild.h"
 
 namespace mozilla {
 namespace dom {
 
 void
 ClientHandleOpChild::ActorDestroy(ActorDestroyReason aReason)
 {
-  if (mPromise) {
-    mPromise->Reject(NS_ERROR_ABORT, __func__);
-    mPromise = nullptr;
-  }
+  mRejectCallback(NS_ERROR_DOM_ABORT_ERR);
 }
 
 mozilla::ipc::IPCResult
 ClientHandleOpChild::Recv__delete__(const ClientOpResult& aResult)
 {
   if (aResult.type() == ClientOpResult::Tnsresult &&
       NS_FAILED(aResult.get_nsresult())) {
-    mPromise->Reject(aResult.get_nsresult(), __func__);
-    mPromise = nullptr;
+    mRejectCallback(aResult.get_nsresult());
     return IPC_OK();
   }
-  mPromise->Resolve(aResult, __func__);
-  mPromise = nullptr;
+  mResolveCallback(aResult);
   return IPC_OK();
 }
 
 ClientHandleOpChild::ClientHandleOpChild(const ClientOpConstructorArgs& aArgs,
-                                         ClientOpPromise::Private* aPromise)
-  : mPromise(aPromise)
+                                         const ClientOpCallback&& aResolveCallback,
+                                         const ClientOpCallback&& aRejectCallback)
+  : mResolveCallback(Move(aResolveCallback))
+  , mRejectCallback(Move(aRejectCallback))
 {
-  MOZ_DIAGNOSTIC_ASSERT(mPromise);
-}
-
-ClientHandleOpChild::~ClientHandleOpChild()
-{
-  MOZ_DIAGNOSTIC_ASSERT(!mPromise);
+  MOZ_DIAGNOSTIC_ASSERT(mResolveCallback);
+  MOZ_DIAGNOSTIC_ASSERT(mRejectCallback);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientHandleOpChild.h
+++ b/dom/clients/manager/ClientHandleOpChild.h
@@ -3,35 +3,36 @@
 /* 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_dom_ClientHandleOpChild_h
 #define _mozilla_dom_ClientHandleOpChild_h
 
 #include "mozilla/dom/ClientOpPromise.h"
 #include "mozilla/dom/PClientHandleOpChild.h"
-#include "mozilla/MozPromise.h"
 
 namespace mozilla {
 namespace dom {
 
 class ClientHandleOpChild final : public PClientHandleOpChild
 {
-  RefPtr<ClientOpPromise::Private> mPromise;
+  const ClientOpCallback mResolveCallback;
+  const ClientOpCallback mRejectCallback;
 
   // PClientHandleOpChild interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   mozilla::ipc::IPCResult
   Recv__delete__(const ClientOpResult& aResult) override;
 
 public:
   ClientHandleOpChild(const ClientOpConstructorArgs& aArgs,
-                      ClientOpPromise::Private* aPromise);
+                      const ClientOpCallback&& aResolveCallback,
+                      const ClientOpCallback&& aRejectCallback);
 
-  ~ClientHandleOpChild();
+  ~ClientHandleOpChild() = default;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientHandleOpChild_h
--- a/dom/clients/manager/ClientManager.cpp
+++ b/dom/clients/manager/ClientManager.cpp
@@ -40,18 +40,25 @@ ClientManager::ClientManager()
     return;
   }
 
   RefPtr<WorkerHolderToken> workerHolderToken;
   if (!NS_IsMainThread()) {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
 
+    // Note, it would be nice to replace this with a WorkerRef, but
+    // currently there is no WorkerRef option that matches what we
+    // need here.  We need something like a StrongWorkerRef that will
+    // let us keep the worker alive until our actor is destroyed, but
+    // we also need to use AllowIdleShutdownStart like WeakWorkerRef.
+    // We need AllowIdleShutdownStart since every worker thread will
+    // have a ClientManager to support creating its ClientSource.
     workerHolderToken =
-      WorkerHolderToken::Create(workerPrivate, Closing,
+      WorkerHolderToken::Create(workerPrivate, Terminating,
                                 WorkerHolderToken::AllowIdleShutdownStart);
     if (NS_WARN_IF(!workerHolderToken)) {
       Shutdown();
       return;
     }
   }
 
   ClientManagerChild* actor = new ClientManagerChild(workerHolderToken);
--- a/dom/clients/manager/ClientOpPromise.h
+++ b/dom/clients/manager/ClientOpPromise.h
@@ -13,12 +13,14 @@ namespace dom {
 
 class ClientOpResult;
 class ClientState;
 
 typedef MozPromise<ClientOpResult, nsresult, false> ClientOpPromise;
 
 typedef MozPromise<ClientState, nsresult, false> ClientStatePromise;
 
+typedef std::function<void(const ClientOpResult&)> ClientOpCallback;
+
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientOpPromise_h
--- a/dom/clients/manager/ClientSource.cpp
+++ b/dom/clients/manager/ClientSource.cpp
@@ -8,16 +8,17 @@
 
 #include "ClientManager.h"
 #include "ClientManagerChild.h"
 #include "ClientPrincipalUtils.h"
 #include "ClientSourceChild.h"
 #include "ClientState.h"
 #include "ClientValidation.h"
 #include "mozilla/dom/ClientIPCTypes.h"
+#include "mozilla/dom/DOMMozPromiseRequestHolder.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/ServiceWorker.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
@@ -631,23 +632,28 @@ ClientSource::Claim(const ClientClaimArg
     SetController(swd);
     ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
     return ref.forget();
   }
 
   RefPtr<ClientOpPromise::Private> outerPromise =
     new ClientOpPromise::Private(__func__);
 
+  auto holder =
+    MakeRefPtr<DOMMozPromiseRequestHolder<GenericPromise>>(innerWindow->AsGlobal());
+
   RefPtr<GenericPromise> p = swm->MaybeClaimClient(doc, swd);
   p->Then(mEventTarget, __func__,
-    [outerPromise] (bool aResult) {
+    [outerPromise, holder] (bool aResult) {
+      holder->Complete();
       outerPromise->Resolve(NS_OK, __func__);
-    }, [outerPromise] (nsresult aResult) {
+    }, [outerPromise, holder] (nsresult aResult) {
+      holder->Complete();
       outerPromise->Reject(aResult, __func__);
-    });
+    })->Track(*holder);
 
   ref = outerPromise;
   return ref.forget();
 }
 
 RefPtr<ClientOpPromise>
 ClientSource::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
 {
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -530,18 +530,24 @@ FetchRequest(nsIGlobalObject* aGlobal, c
     RefPtr<WorkerFetchResolver> resolver =
       WorkerFetchResolver::Create(worker, p, signal, observer);
     if (!resolver) {
       NS_WARNING("Could not keep the worker alive.");
       aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
       return nullptr;
     }
 
+    Maybe<ClientInfo> clientInfo(worker->GetClientInfo());
+    if (clientInfo.isNothing()) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+      return nullptr;
+    }
+
     RefPtr<MainThreadFetchRunnable> run =
-      new MainThreadFetchRunnable(resolver, worker->GetClientInfo(),
+      new MainThreadFetchRunnable(resolver, clientInfo.ref(),
                                   worker->GetController(), r);
     worker->DispatchToMainThread(run.forget());
   }
 
   return p.forget();
 }
 
 void
--- a/dom/smil/moz.build
+++ b/dom/smil/moz.build
@@ -11,16 +11,17 @@ MOCHITEST_MANIFESTS += ['test/mochitest.
 
 EXPORTS += [
     'nsISMILAttr.h',
     'nsISMILType.h',
     'nsSMILAnimationController.h',
     'nsSMILAnimationFunction.h',
     'nsSMILCompositorTable.h',
     'nsSMILCSSProperty.h',
+    'nsSMILCSSValueType.h',
     'nsSMILInstanceTime.h',
     'nsSMILInterval.h',
     'nsSMILKeySpline.h',
     'nsSMILMilestone.h',
     'nsSMILNullType.h',
     'nsSMILRepeatCount.h',
     'nsSMILSetAnimationFunction.h',
     'nsSMILTargetIdentifier.h',
--- a/dom/smil/nsSMILCSSProperty.cpp
+++ b/dom/smil/nsSMILCSSProperty.cpp
@@ -102,32 +102,17 @@ nsSMILCSSProperty::ValueFromString(const
   }
   return NS_OK;
 }
 
 nsresult
 nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
 {
   NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
-
-  // Convert nsSMILValue to string
-  nsAutoString valStr;
-  nsSMILCSSValueType::ValueToString(aValue, valStr);
-
-  // Use string value to style the target element
-  nsDOMCSSAttributeDeclaration* overrideDecl = mElement->GetSMILOverrideStyle();
-  if (overrideDecl) {
-    nsAutoString oldValStr;
-    overrideDecl->GetPropertyValue(mPropID, oldValStr);
-    if (valStr.Equals(oldValStr)) {
-      return NS_OK;
-    }
-    overrideDecl->SetPropertyValue(mPropID, valStr, nullptr);
-  }
-  return NS_OK;
+  return mElement->GetSMILOverrideStyle()->SetSMILValue(mPropID, aValue);
 }
 
 void
 nsSMILCSSProperty::ClearAnimValue()
 {
   // Put empty string in override style for our property
   nsDOMCSSAttributeDeclaration* overrideDecl = mElement->GetSMILOverrideStyle();
   if (overrideDecl) {
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1905,17 +1905,19 @@ class ChannelGetterRunnable final : publ
 
 public:
   ChannelGetterRunnable(WorkerPrivate* aParentWorker,
                         const nsAString& aScriptURL,
                         WorkerLoadInfo& aLoadInfo)
     : WorkerMainThreadRunnable(aParentWorker,
                                NS_LITERAL_CSTRING("ScriptLoader :: ChannelGetter"))
     , mScriptURL(aScriptURL)
-    , mClientInfo(aParentWorker->GetClientInfo())
+    // ClientInfo should always be present since this should not be called
+    // if parent's status is greater than Running.
+    , mClientInfo(aParentWorker->GetClientInfo().ref())
     , mLoadInfo(aLoadInfo)
     , mResult(NS_ERROR_FAILURE)
   {
     MOZ_ASSERT(aParentWorker);
     aParentWorker->AssertIsOnWorkerThread();
   }
 
   virtual bool
@@ -2241,17 +2243,17 @@ LoadAllScripts(WorkerPrivate* aWorkerPri
   if (!syncLoopTarget) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   Maybe<ClientInfo> clientInfo;
   Maybe<ServiceWorkerDescriptor> controller;
   if (!aIsMainScript) {
-    clientInfo.emplace(aWorkerPrivate->GetClientInfo());
+    clientInfo = aWorkerPrivate->GetClientInfo();
     controller = aWorkerPrivate->GetController();
   }
 
   RefPtr<ScriptLoaderRunnable> loader =
     new ScriptLoaderRunnable(aWorkerPrivate, syncLoopTarget, aLoadInfos,
                              clientInfo, controller,
                              aIsMainScript, aWorkerScriptType, aRv);
 
@@ -2385,17 +2387,17 @@ LoadMainScript(WorkerPrivate* aWorkerPri
   nsTArray<ScriptLoadInfo> loadInfos;
 
   ScriptLoadInfo* info = loadInfos.AppendElement();
   info->mURL = aScriptURL;
   info->mLoadFlags = aWorkerPrivate->GetLoadFlags();
 
   // We are loading the main script, so the worker's Client must be
   // reserved.
-  info->mReservedClientInfo.emplace(aWorkerPrivate->GetClientInfo());
+  info->mReservedClientInfo = aWorkerPrivate->GetClientInfo();
 
   LoadAllScripts(aWorkerPrivate, loadInfos, true, aWorkerScriptType, aRv);
 }
 
 void
 Load(WorkerPrivate* aWorkerPrivate,
      const nsTArray<nsString>& aScriptURLs, WorkerScriptType aWorkerScriptType,
      ErrorResult& aRv)
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3273,22 +3273,24 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
         MOZ_ASSERT(currentStatus == Killing);
 #else
         currentStatus = Killing;
 #endif
       }
 
       // If we're supposed to die then we should exit the loop.
       if (currentStatus == Killing) {
+        // The ClientSource should be cleared in NotifyInternal() when we reach
+        // or pass Terminating.
+        MOZ_DIAGNOSTIC_ASSERT(!mClientSource);
+
         // Flush uncaught rejections immediately, without
         // waiting for a next tick.
         PromiseDebugging::FlushUncaughtRejections();
 
-        mClientSource = nullptr;
-
         ShutdownGCTimers();
 
         DisableMemoryReporter();
 
         {
           MutexAutoLock lock(mMutex);
 
           mStatus = Dead;
@@ -3495,22 +3497,27 @@ WorkerPrivate::EnsurePerformanceStorage(
 {
   AssertIsOnWorkerThread();
 
   if (!mPerformanceStorage) {
     mPerformanceStorage = PerformanceStorageWorker::Create(this);
   }
 }
 
-const ClientInfo&
+Maybe<ClientInfo>
 WorkerPrivate::GetClientInfo() const
 {
   AssertIsOnWorkerThread();
-  MOZ_DIAGNOSTIC_ASSERT(mClientSource);
-  return mClientSource->Info();
+  Maybe<ClientInfo> clientInfo;
+  if (!mClientSource) {
+    MOZ_DIAGNOSTIC_ASSERT(mStatus >= Terminating);
+    return Move(clientInfo);
+  }
+  clientInfo.emplace(mClientSource->Info());
+  return Move(clientInfo);
 }
 
 const ClientState
 WorkerPrivate::GetClientState() const
 {
   AssertIsOnWorkerThread();
   MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   ClientState state;
@@ -3535,16 +3542,22 @@ WorkerPrivate::Control(const ServiceWork
   MOZ_DIAGNOSTIC_ASSERT(Type() != WorkerTypeService);
   mClientSource->SetController(aServiceWorker);
 }
 
 void
 WorkerPrivate::ExecutionReady()
 {
   AssertIsOnWorkerThread();
+  {
+    MutexAutoLock lock(mMutex);
+    if (mStatus >= Terminating) {
+      return;
+    }
+  }
   MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   mClientSource->WorkerExecutionReady(this);
 }
 
 void
 WorkerPrivate::InitializeGCTimers()
 {
   AssertIsOnWorkerThread();
@@ -4509,18 +4522,19 @@ WorkerPrivate::NotifyInternal(WorkerStat
   {
     MutexAutoLock lock(mMutex);
 
     if (mStatus >= aStatus) {
       return true;
     }
 
     if (aStatus >= Terminating) {
+      MutexAutoUnlock unlock(mMutex);
+      mClientSource.reset();
       if (mScope) {
-        MutexAutoUnlock unlock(mMutex);
         mScope->NoteTerminating();
       }
     }
 
     // Make sure the hybrid event target stops dispatching runnables
     // once we reaching the killing state.
     if (aStatus == Killing) {
       // To avoid deadlock we always acquire the event target mutex before the
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -548,17 +548,17 @@ public:
   EnsureClientSource();
 
   void
   EnsurePerformanceStorage();
 
   void
   EnsurePerformanceCounter();
 
-  const ClientInfo&
+  Maybe<ClientInfo>
   GetClientInfo() const;
 
   const ClientState
   GetClientState() const;
 
   const Maybe<ServiceWorkerDescriptor>
   GetController() const;
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -541,19 +541,17 @@ AbstractThread*
 WorkerGlobalScope::AbstractMainThreadFor(TaskCategory aCategory)
 {
   MOZ_CRASH("AbstractMainThreadFor not supported for workers.");
 }
 
 Maybe<ClientInfo>
 WorkerGlobalScope::GetClientInfo() const
 {
-  Maybe<ClientInfo> info;
-  info.emplace(mWorkerPrivate->GetClientInfo());
-  return Move(info);
+  return mWorkerPrivate->GetClientInfo();
 }
 
 Maybe<ClientState>
 WorkerGlobalScope::GetClientState() const
 {
   Maybe<ClientState> state;
   state.emplace(mWorkerPrivate->GetClientState());
   return Move(state);
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -1870,17 +1870,22 @@ XMLHttpRequestWorker::Open(const nsACStr
 
   if (mProxy) {
     MaybeDispatchPrematureAbortEvents(aRv);
     if (aRv.Failed()) {
       return;
     }
   }
   else {
-    mProxy = new Proxy(this, mWorkerPrivate->GetClientInfo(),
+    Maybe<ClientInfo> clientInfo(mWorkerPrivate->GetClientInfo());
+    if (clientInfo.isNothing()) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+      return;
+    }
+    mProxy = new Proxy(this, clientInfo.ref(),
                        mWorkerPrivate->GetController(), mMozAnon, mMozSystem);
   }
 
   mProxy->mOuterEventStreamId++;
 
   RefPtr<OpenRunnable> runnable =
     new OpenRunnable(mWorkerPrivate, mProxy, aMethod, aUrl, aUser, aPassword,
                      mBackgroundRequest, mWithCredentials,
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1785,17 +1785,17 @@ gfxPlatform::GetLayerDiagnosticTypes()
   }
   if (gfxPrefs::FlashLayerBorders()) {
     type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS;
   }
   return type;
 }
 
 BackendPrefsData
-gfxPlatform::GetBackendPrefs()
+gfxPlatform::GetBackendPrefs() const
 {
   BackendPrefsData data;
 
   data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO);
   data.mContentBitmask = BackendTypeBit(BackendType::CAIRO);
 #ifdef USE_SKIA
   data.mCanvasBitmask |= BackendTypeBit(BackendType::SKIA);
   data.mContentBitmask |= BackendTypeBit(BackendType::SKIA);
@@ -2711,24 +2711,50 @@ gfxPlatform::UsesOffMainThreadCompositin
   }
 
   return result;
 }
 
 bool
 gfxPlatform::UsesTiling() const
 {
-  bool isSkiaPOMTP = XRE_IsContentProcess() &&
-      GetDefaultContentBackend() == BackendType::SKIA &&
-      gfxVars::UseOMTP() &&
-      (gfxPrefs::LayersOMTPPaintWorkers() == -1 ||
+  bool usesSkia = GetDefaultContentBackend() == BackendType::SKIA;
+
+  // We can't just test whether the PaintThread is initialized here because
+  // this function is used when initializing the PaintThread. So instead we
+  // check the conditions that enable OMTP with parallel painting.
+  bool usesPOMTP = XRE_IsContentProcess() &&
+    gfxVars::UseOMTP() &&
+    (gfxPrefs::LayersOMTPPaintWorkers() == -1 ||
       gfxPrefs::LayersOMTPPaintWorkers() > 1);
 
   return gfxPrefs::LayersTilesEnabled() ||
-    (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() && isSkiaPOMTP);
+    (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() &&
+      usesSkia &&
+      usesPOMTP);
+}
+
+bool
+gfxPlatform::ContentUsesTiling() const
+{
+  BackendPrefsData data = GetBackendPrefs();
+  BackendType contentBackend = GetContentBackendPref(data.mContentBitmask);
+  if (contentBackend == BackendType::NONE) {
+    contentBackend = data.mContentDefault;
+  }
+
+  bool contentUsesSkia = contentBackend == BackendType::SKIA;
+  bool contentUsesPOMTP = gfxVars::UseOMTP() &&
+    (gfxPrefs::LayersOMTPPaintWorkers() == -1 ||
+      gfxPrefs::LayersOMTPPaintWorkers() > 1);
+
+  return gfxPrefs::LayersTilesEnabled() ||
+    (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() &&
+      contentUsesSkia &&
+      contentUsesPOMTP);
 }
 
 /***
  * The preference "layout.frame_rate" has 3 meanings depending on the value:
  *
  * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails.
  *  0 = ASAP mode - used during talos testing.
  *  X = Software vsync at a rate of X times per second.
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -587,19 +587,28 @@ public:
 
     virtual mozilla::gfx::SurfaceFormat Optimal2DFormatForContent(gfxContentType aContent);
 
     virtual gfxImageFormat OptimalFormatForContent(gfxContentType aContent);
 
     virtual gfxImageFormat GetOffscreenFormat()
     { return mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32; }
 
+    /**
+     * Returns whether the current process should use tiling for layers.
+     */
     virtual bool UsesTiling() const;
 
     /**
+     * Returns whether the content process will use tiling for layers. This is
+     * only used by about:support.
+     */
+    virtual bool ContentUsesTiling() const;
+
+    /**
      * Returns a logger if one is available and logging is enabled
      */
     static mozilla::LogModule* GetLog(eGfxLog aWhichLog);
 
     int GetScreenDepth() const { return mScreenDepth; }
     mozilla::gfx::IntSize GetScreenSize() const { return mScreenSize; }
 
     /**
@@ -752,17 +761,17 @@ protected:
 
     // Returns whether or not layers should be accelerated by default on this platform.
     virtual bool AccelerateLayersByDefault();
 
     // Returns a prioritized list of available compositor backends for acceleration.
     virtual void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
 
     // Returns preferences of canvas and content backends.
-    virtual BackendPrefsData GetBackendPrefs();
+    virtual BackendPrefsData GetBackendPrefs() const;
 
     /**
      * Initialise the preferred and fallback canvas backends
      * aBackendBitmask specifies the backends which are acceptable to the caller.
      * The backend used is determined by aBackendBitmask and the order specified
      * by the gfx.canvas.azure.backends pref.
      */
     void InitBackendPrefs(BackendPrefsData&& aPrefsData);
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -97,17 +97,17 @@ gfxPlatformMac::gfxPlatformMac()
 }
 
 gfxPlatformMac::~gfxPlatformMac()
 {
     gfxCoreTextShaper::Shutdown();
 }
 
 BackendPrefsData
-gfxPlatformMac::GetBackendPrefs()
+gfxPlatformMac::GetBackendPrefs() const
 {
   BackendPrefsData data;
 
   data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
   data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
   data.mCanvasDefault = BackendType::SKIA;
   data.mContentDefault = BackendType::SKIA;
 
@@ -117,16 +117,22 @@ gfxPlatformMac::GetBackendPrefs()
 bool
 gfxPlatformMac::UsesTiling() const
 {
     // The non-tiling ContentClient requires CrossProcessSemaphore which
     // isn't implemented for OSX.
     return true;
 }
 
+bool
+gfxPlatformMac::ContentUsesTiling() const
+{
+    return UsesTiling();
+}
+
 gfxPlatformFontList*
 gfxPlatformMac::CreatePlatformFontList()
 {
     gfxPlatformFontList* list = new gfxMacPlatformFontList();
     if (NS_SUCCEEDED(list->InitFontList())) {
         return list;
     }
     gfxPlatformFontList::Shutdown();
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -22,16 +22,17 @@ public:
     gfxPlatformMac();
     virtual ~gfxPlatformMac();
 
     static gfxPlatformMac *GetPlatform() {
         return (gfxPlatformMac*) gfxPlatform::GetPlatform();
     }
 
     bool UsesTiling() const override;
+    bool ContentUsesTiling() const override;
 
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& aSize,
                              gfxImageFormat aFormat) override;
 
     gfxFontGroup*
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
@@ -78,17 +79,17 @@ public:
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
 
     // lower threshold on font anti-aliasing
     uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
 protected:
     bool AccelerateLayersByDefault() override;
 
-    BackendPrefsData GetBackendPrefs() override;
+    BackendPrefsData GetBackendPrefs() const override;
 
     bool CheckVariationFontSupport() override;
 
 private:
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override;
 
     // read in the pref value for the lower threshold on font anti-aliasing
     static uint32_t ReadAntiAliasingThreshold();
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -434,17 +434,17 @@ gfxWindowsPlatform::HandleDeviceReset()
 
   InitializeConfig();
   InitializeDevices();
   UpdateANGLEConfig();
   return true;
 }
 
 BackendPrefsData
-gfxWindowsPlatform::GetBackendPrefs()
+gfxWindowsPlatform::GetBackendPrefs() const
 {
   BackendPrefsData data;
 
   data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO) |
                         BackendTypeBit(BackendType::SKIA);
   data.mContentBitmask = BackendTypeBit(BackendType::CAIRO) |
                          BackendTypeBit(BackendType::SKIA);
   data.mCanvasDefault = BackendType::SKIA;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -228,17 +228,17 @@ protected:
     }
     void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends) override;
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override;
 
     void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override;
     void ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData) override;
     void BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut) override;
 
-    BackendPrefsData GetBackendPrefs() override;
+    BackendPrefsData GetBackendPrefs() const override;
 
     bool CheckVariationFontSupport() override;
 
 protected:
     RenderMode mRenderMode;
 
 private:
     void Init();
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -1069,30 +1069,18 @@ static const mozilla::EnumSet<ZealMode> 
     ZealMode::YieldBeforeSweepingShapeTrees
 };
 
 void
 GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
 {
     MOZ_ASSERT(zeal <= unsigned(ZealMode::Limit));
 
-#ifdef ENABLE_WASM_GC
-    // If we run with wasm-gc enabled and there's wasm frames on the stack,
-    // then GCs are suppressed and we should not allow to set the GC zeal,
-    // which presupposes that GC can be run right away.
-    // TODO (bug 1456824) This is temporary and should be removed once proper
-    // GC support is implemented.
-    JSContext* cx = rt->mainContextFromOwnThread();
-    if (cx->options().wasmGc()) {
-        for (FrameIter iter(cx); !iter.done(); ++iter) {
-            if (iter.isWasm())
-                return;
-        }
-    }
-#endif
+    if (temporaryAbortIfWasmGc(rt->mainContextFromOwnThread()))
+        return;
 
     if (verifyPreData)
         VerifyBarriers(rt, PreBarrierVerifier);
 
     if (zeal == 0) {
         if (hasZealMode(ZealMode::GenerationalGC)) {
             evictNursery(JS::gcreason::DEBUG_GC);
             nursery().leaveZealMode();
@@ -8240,16 +8228,23 @@ GCRuntime::clearSelectedForMarking()
 void
 GCRuntime::setDeterministic(bool enabled)
 {
     MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
     deterministicOnly = enabled;
 }
 #endif
 
+#ifdef ENABLE_WASM_GC
+/* static */ bool
+GCRuntime::temporaryAbortIfWasmGc(JSContext* cx) {
+    return cx->options().wasmGc() && cx->suppressGC;
+}
+#endif
+
 #ifdef DEBUG
 
 /* Should only be called manually under gdb */
 void PreventGCDuringInteractiveDebug()
 {
     TlsContext.get()->suppressGC++;
 }
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -282,16 +282,26 @@ class GCRuntime
     void setNextScheduled(uint32_t count);
     void verifyPreBarriers();
     void maybeVerifyPreBarriers(bool always);
     bool selectForMarking(JSObject* object);
     void clearSelectedForMarking();
     void setDeterministic(bool enable);
 #endif
 
+#ifdef ENABLE_WASM_GC
+    // If we run with wasm-gc enabled and there's wasm frames on the stack,
+    // then GCs are suppressed and many APIs should not be available.
+    // TODO (bug 1456824) This is temporary and should be removed once proper
+    // GC support is implemented.
+    static bool temporaryAbortIfWasmGc(JSContext* cx);
+#else
+    static bool temporaryAbortIfWasmGc(JSContext* cx) { return false; }
+#endif
+
     uint64_t nextCellUniqueId() {
         MOZ_ASSERT(nextCellUniqueId_ > 0);
         uint64_t uid = ++nextCellUniqueId_;
         return uid;
     }
 
 #ifdef DEBUG
     bool shutdownCollectedEverything() const {
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -174,30 +174,33 @@ NextNode(VerifyNode* node)
 }
 
 void
 gc::GCRuntime::startVerifyPreBarriers()
 {
     if (verifyPreData || isIncrementalGCInProgress())
         return;
 
+    JSContext* cx = rt->mainContextFromOwnThread();
+    if (temporaryAbortIfWasmGc(cx))
+        return;
+
     if (IsIncrementalGCUnsafe(rt) != AbortReason::None ||
-        rt->mainContextFromOwnThread()->keepAtoms ||
+        cx->keepAtoms ||
         rt->hasHelperThreadZones())
     {
         return;
     }
 
     number++;
 
     VerifyPreTracer* trc = js_new<VerifyPreTracer>(rt);
     if (!trc)
         return;
 
-    JSContext* cx = rt->mainContextFromOwnThread();
     AutoPrepareForTracing prep(cx);
 
     {
         AutoLockGC lock(cx->runtime());
         for (auto chunk = allNonEmptyChunks(lock); !chunk.done(); chunk.next())
             chunk->bitmap.clear();
     }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/gc/block-debugger-findscripts.js
@@ -0,0 +1,29 @@
+if (!wasmGcEnabled()) {
+    quit();
+}
+
+wasmEvalText(`
+    (module
+        (import "global" "func" (result i32))
+        (func (export "func_0") (result i32)
+         call 0 ;; calls the import, which is func #0
+        )
+    )
+`, {
+    global: {
+        func() {
+          var g = newGlobal();
+          var dbg = new Debugger(g);
+          var caught = false;
+          try {
+            dbg.findScripts().filter(isWasm(g, isValidWasmURL, 2));
+          } catch(e) {
+              caught = true;
+              assertEq(/temporarily unavailable/.test(e.toString()), true);
+          }
+          // When this assertion fails, it's time to remove the restriction in
+          // Debugger.findScripts.
+          assertEq(caught, true);
+        }
+    }
+}).exports.func_0();;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/gc/block-verifyprebarriers.js
@@ -0,0 +1,14 @@
+wasmEvalText(`
+    (module
+        (import "global" "func" (result i32))
+        (func (export "func_0") (result i32)
+         call 0
+        )
+    )
+`, {
+    global: {
+        func() {
+            verifyprebarriers();
+        }
+    }
+}).exports.func_0();
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1281,18 +1281,21 @@ MConstant::valueToBoolean(bool* res) con
         return true;
       case MIRType::Symbol:
         *res = true;
         return true;
       case MIRType::String:
         *res = toString()->length() != 0;
         return true;
       case MIRType::Object:
-        *res = !EmulatesUndefined(&toObject());
-        return true;
+        // We have to call EmulatesUndefined but that reads obj->group->clasp
+        // and so it's racy when the object has a lazy group. The main callers
+        // of this (MTest, MNot) already know how to fold the object case, so
+        // just give up.
+        return false;
       default:
         MOZ_ASSERT(IsMagicType(type()));
         return false;
     }
 }
 
 HashNumber
 MWasmFloatConstant::valueHash() const
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1636,21 +1636,22 @@ class MConstant : public MNullaryInstruc
     static MConstant* NewFloat32(TempAllocator& alloc, double d);
     static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
     static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
     static MConstant* Copy(TempAllocator& alloc, MConstant* src) {
         return new(alloc) MConstant(*src);
     }
 
     // Try to convert this constant to boolean, similar to js::ToBoolean.
-    // Returns false if the type is MIRType::Magic*.
+    // Returns false if the type is MIRType::Magic* or MIRType::Object.
     bool MOZ_MUST_USE valueToBoolean(bool* res) const;
 
     // Like valueToBoolean, but returns the result directly instead of using
-    // an outparam. Should not be used if this constant might be a magic value.
+    // an outparam. Should not be used if this constant might be a magic value
+    // or an object.
     bool valueToBooleanInfallible() const {
         bool res;
         MOZ_ALWAYS_TRUE(valueToBoolean(&res));
         return res;
     }
 
 #ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4697,16 +4697,21 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
     }
 };
 
 /* static */ bool
 Debugger::findScripts(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "findScripts", args, dbg);
 
+    if (gc::GCRuntime::temporaryAbortIfWasmGc(cx)) {
+        JS_ReportErrorASCII(cx, "API temporarily unavailable under wasm gc");
+        return false;
+    }
+
     ScriptQuery query(cx, dbg);
     if (!query.init())
         return false;
 
     if (args.length() >= 1) {
         RootedObject queryObject(cx, NonNullObject(cx, args[0]));
         if (!queryObject || !query.parseQuery(queryObject))
             return false;
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -250,23 +250,23 @@ class ObjectGroup : public gc::TenuredCe
                maybePreliminaryObjectsDontCheckGeneration();
     }
 
     inline UnboxedLayout* maybeUnboxedLayout(const AutoSweepObjectGroup& sweep);
     inline UnboxedLayout& unboxedLayout(const AutoSweepObjectGroup& sweep);
 
     UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
         if (addendumKind() == Addendum_UnboxedLayout)
-            return reinterpret_cast<UnboxedLayout*>(addendum_);
+            return &unboxedLayoutDontCheckGeneration();
         return nullptr;
     }
 
     UnboxedLayout& unboxedLayoutDontCheckGeneration() const {
         MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
-        return *maybeUnboxedLayoutDontCheckGeneration();
+        return *reinterpret_cast<UnboxedLayout*>(addendum_);
     }
 
     void setUnboxedLayout(UnboxedLayout* layout) {
         setAddendum(Addendum_UnboxedLayout, layout);
     }
 
     ObjectGroup* maybeOriginalUnboxedGroup() const {
         if (addendumKind() == Addendum_OriginalUnboxedGroup)
@@ -277,23 +277,23 @@ class ObjectGroup : public gc::TenuredCe
     void setOriginalUnboxedGroup(ObjectGroup* group) {
         setAddendum(Addendum_OriginalUnboxedGroup, group);
     }
 
     TypeDescr* maybeTypeDescr() {
         // Note: there is no need to sweep when accessing the type descriptor
         // of an object, as it is strongly held and immutable.
         if (addendumKind() == Addendum_TypeDescr)
-            return reinterpret_cast<TypeDescr*>(addendum_);
+            return &typeDescr();
         return nullptr;
     }
 
     TypeDescr& typeDescr() {
         MOZ_ASSERT(addendumKind() == Addendum_TypeDescr);
-        return *maybeTypeDescr();
+        return *reinterpret_cast<TypeDescr*>(addendum_);
     }
 
     void setTypeDescr(TypeDescr* descr) {
         setAddendum(Addendum_TypeDescr, descr);
     }
 
     JSFunction* maybeInterpretedFunction() {
         // Note: as with type descriptors, there is no need to sweep when
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -2401,22 +2401,19 @@ JSStructuredCloneReader::readHeader()
     if (storedScope < JS::StructuredCloneScope::SameProcessSameThread ||
         storedScope > JS::StructuredCloneScope::DifferentProcessForIndexedDB)
     {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "invalid structured clone scope");
         return false;
     }
 
-    if (storedScope == JS::StructuredCloneScope::SameProcessSameThread &&
-        allowedScope == JS::StructuredCloneScope::DifferentProcessForIndexedDB)
-    {
-        // Bug 1434308 - allow stored IndexedDB clones to contain what is
-        // essentially DifferentProcess data, but labeled as
-        // SameProcessSameThread (because that's what old code wrote.)
+    if (allowedScope == JS::StructuredCloneScope::DifferentProcessForIndexedDB) {
+        // Bug 1434308 and bug 1458320 - the scopes stored in old IndexedDB
+        // clones are incorrect. Treat them as if they were DifferentProcess.
         allowedScope = JS::StructuredCloneScope::DifferentProcess;
         return true;
     }
 
     if (storedScope < allowedScope) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
                                   JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "incompatible structured clone scope");
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -11501,23 +11501,16 @@ nsAdaptorPrintReason(ReflowInput& aReflo
           reflowReasonString = "unknown";
           break;
     }
 
     printf("%s",reflowReasonString);
 }
 
 #endif
-#ifdef DEBUG_LAYOUT
-void
-nsFrame::GetBoxName(nsAutoString& aName)
-{
-  GetFrameName(aName);
-}
-#endif
 
 #ifdef DEBUG
 static void
 GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize,
            char* aResult)
 {
   if (aContent) {
     snprintf(aResult, aResultSize, "%s@%p",
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -674,20 +674,16 @@ protected:
                                       int32_t* aContentOffset,
                                       int32_t* aTarget);
 
   // Fills aCursor with the appropriate information from ui
   static void FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
                                              nsIFrame::Cursor& aCursor);
   NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
 
-#ifdef DEBUG_LAYOUT
-  void GetBoxName(nsAutoString& aName) override;
-#endif
-
   nsBoxLayoutMetrics* BoxMetrics() const;
 
   // Fire DOM event. If no aContent argument use frame's mContent.
   void FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent = nullptr);
 
 private:
   void BoxReflow(nsBoxLayoutState& aState,
                  nsPresContext*    aPresContext,
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -294,19 +294,17 @@ FRAME_STATE_BIT(Generic, 59, NS_FRAME_IS
 
 FRAME_STATE_GROUP(Box, nsBoxFrame)
 
 FRAME_STATE_BIT(Box, 20, NS_STATE_BOX_CHILD_RESERVED)
 FRAME_STATE_BIT(Box, 21, NS_STATE_STACK_NOT_POSITIONED)
 FRAME_STATE_BIT(Box, 22, NS_STATE_IS_HORIZONTAL)
 FRAME_STATE_BIT(Box, 23, NS_STATE_AUTO_STRETCH)
 FRAME_STATE_BIT(Box, 24, NS_STATE_IS_ROOT)
-FRAME_STATE_BIT(Box, 25, NS_STATE_CURRENTLY_IN_DEBUG)
-FRAME_STATE_BIT(Box, 26, NS_STATE_SET_TO_DEBUG)
-FRAME_STATE_BIT(Box, 27, NS_STATE_DEBUG_WAS_SET)
+/* Bits 25, 26, and 27 were used for xul debug flags but are now unused */
 FRAME_STATE_BIT(Box, 28, NS_STATE_MENU_HAS_POPUP_LIST)
 FRAME_STATE_BIT(Box, 29, NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK)
 FRAME_STATE_BIT(Box, 30, NS_STATE_EQUAL_SIZE)
 FRAME_STATE_BIT(Box, 31, NS_STATE_IS_DIRECTION_NORMAL)
 FRAME_STATE_BIT(Box, 60, NS_FRAME_MOUSE_THROUGH_ALWAYS)
 FRAME_STATE_BIT(Box, 61, NS_FRAME_MOUSE_THROUGH_NEVER)
 
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1568,20 +1568,16 @@ nsXULScrollFrame::GetXULBoxAscent(nsBoxL
   ascent += m.top;
 
   return ascent;
 }
 
 nsSize
 nsXULScrollFrame::GetXULPrefSize(nsBoxLayoutState& aState)
 {
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aState);
-#endif
-
   nsSize pref = mHelper.mScrolledFrame->GetXULPrefSize(aState);
 
   ScrollbarStyles styles = GetScrollbarStyles();
 
   // scrolled frames don't have their own margins
 
   if (mHelper.mVScrollbarBox &&
       styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
@@ -1601,20 +1597,16 @@ nsXULScrollFrame::GetXULPrefSize(nsBoxLa
   bool widthSet, heightSet;
   nsIFrame::AddXULPrefSize(this, pref, widthSet, heightSet);
   return pref;
 }
 
 nsSize
 nsXULScrollFrame::GetXULMinSize(nsBoxLayoutState& aState)
 {
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aState);
-#endif
-
   nsSize min = mHelper.mScrolledFrame->GetXULMinSizeForScrollArea(aState);
 
   ScrollbarStyles styles = GetScrollbarStyles();
 
   if (mHelper.mVScrollbarBox &&
       styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
      nsSize vSize = mHelper.mVScrollbarBox->GetXULMinSize(aState);
      AddMargin(mHelper.mVScrollbarBox, vSize);
@@ -1636,20 +1628,16 @@ nsXULScrollFrame::GetXULMinSize(nsBoxLay
   bool widthSet, heightSet;
   nsIFrame::AddXULMinSize(aState, this, min, widthSet, heightSet);
   return min;
 }
 
 nsSize
 nsXULScrollFrame::GetXULMaxSize(nsBoxLayoutState& aState)
 {
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aState);
-#endif
-
   nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
 
   AddBorderAndPadding(maxSize);
   bool widthSet, heightSet;
   nsIFrame::AddXULMaxSize(this, maxSize, widthSet, heightSet);
   return maxSize;
 }
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3740,23 +3740,16 @@ public:
   virtual Halignment GetXULHAlign() const = 0;
 
   bool IsXULHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; }
   bool IsXULNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; }
 
   nsresult XULRedraw(nsBoxLayoutState& aState);
   virtual nsresult XULRelayoutChildAtOrdinal(nsIFrame* aChild)=0;
 
-#ifdef DEBUG_LAYOUT
-  virtual nsresult SetXULDebug(nsBoxLayoutState& aState, bool aDebug)=0;
-  virtual nsresult GetXULDebug(bool& aDebug)=0;
-
-  virtual nsresult XULDumpBox(FILE* out)=0;
-#endif
-
   static bool AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
   static bool AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox,
                             nsSize& aSize, bool& aWidth, bool& aHeightSet);
   static bool AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
   static bool AddXULFlex(nsIFrame* aBox, nscoord& aFlex);
 
   // END OF BOX LAYOUT METHODS
   // The above methods have been migrated from nsIBox and are in the process of
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/MutationEventBinding.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/ServoDeclarationBlock.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "nsIURI.h"
 #include "nsNodeUtils.h"
+#include "nsSMILCSSValueType.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIFrame.h"
 #include "ActiveLayerTracker.h"
 
 using namespace mozilla;
 
 nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(dom::Element* aElement,
                                                            bool aIsSMILOverride)
@@ -175,26 +176,34 @@ nsDOMCSSAttributeDeclaration::GetServoCS
 {
   return {
     mElement->GetURLDataForStyleAttr(aSubjectPrincipal),
     mElement->OwnerDoc()->GetCompatibilityMode(),
     mElement->OwnerDoc()->CSSLoader(),
   };
 }
 
-css::Rule*
-nsDOMCSSAttributeDeclaration::GetParentRule()
+nsresult
+nsDOMCSSAttributeDeclaration::SetSMILValue(const nsCSSPropertyID aPropID,
+                                           const nsSMILValue& aValue)
 {
-  return nullptr;
-}
+  MOZ_ASSERT(mIsSMILOverride);
 
-/* virtual */ nsINode*
-nsDOMCSSAttributeDeclaration::GetParentObject()
-{
-  return mElement;
+  // Convert nsSMILValue to string.
+  //
+  // FIXME(emilio): This roundtrip should go away.
+  nsAutoString valStr;
+  nsSMILCSSValueType::ValueToString(aValue, valStr);
+
+  nsAutoString oldValStr;
+  GetPropertyValue(aPropID, oldValStr);
+  if (valStr.Equals(oldValStr)) {
+    return NS_OK;
+  }
+  return SetPropertyValue(aPropID, valStr, nullptr);
 }
 
 nsresult
 nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID,
                                                const nsAString& aValue,
                                                nsIPrincipal* aSubjectPrincipal)
 {
   // Scripted modifications to style.opacity or style.transform
--- a/layout/style/nsDOMCSSAttrDeclaration.h
+++ b/layout/style/nsDOMCSSAttrDeclaration.h
@@ -9,16 +9,17 @@
 #ifndef nsDOMCSSAttributeDeclaration_h
 #define nsDOMCSSAttributeDeclaration_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/DocGroup.h"
 #include "nsDOMCSSDeclaration.h"
 
 
+class nsSMILValue;
 namespace mozilla {
 namespace dom {
 class DomGroup;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration
@@ -33,19 +34,27 @@ public:
 
   // If GetCSSDeclaration returns non-null, then the decl it returns
   // is owned by our current style rule.
   virtual mozilla::DeclarationBlock* GetCSSDeclaration(Operation aOperation) override;
   virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv,
                                         nsIPrincipal* aSubjectPrincipal) override;
   nsDOMCSSDeclaration::ServoCSSParsingEnvironment
   GetServoCSSParsingEnvironment(nsIPrincipal* aSubjectPrincipal) const final;
-  mozilla::css::Rule* GetParentRule() override;
+  mozilla::css::Rule* GetParentRule() override
+  {
+    return nullptr;
+  }
 
-  virtual nsINode* GetParentObject() override;
+  nsINode* GetParentObject() override
+  {
+    return mElement;
+  }
+
+  nsresult SetSMILValue(const nsCSSPropertyID aPropID, const nsSMILValue&);
 
   nsresult SetPropertyValue(const nsCSSPropertyID aPropID,
                             const nsAString& aValue,
                             nsIPrincipal* aSubjectPrincipal) override;
 
 protected:
   ~nsDOMCSSAttributeDeclaration();
 
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -18,19 +18,17 @@
 #include "nsIURI.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsContentUtils.h"
 #include "nsQueryObject.h"
 #include "mozilla/layers/ScrollLinkedEffectDetector.h"
 
 using namespace mozilla;
 
-nsDOMCSSDeclaration::~nsDOMCSSDeclaration()
-{
-}
+nsDOMCSSDeclaration::~nsDOMCSSDeclaration() = default;
 
 /* virtual */ JSObject*
 nsDOMCSSDeclaration::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return dom::CSS2PropertiesBinding::Wrap(aCx, this, aGivenProto);
 }
 
 NS_IMPL_QUERY_INTERFACE(nsDOMCSSDeclaration,
@@ -265,43 +263,42 @@ nsDOMCSSDeclaration::GetServoCSSParsingE
 
   return {
     sheet->URLData(),
     eCompatibility_FullStandards,
     nullptr,
   };
 }
 
-template<typename GeckoFunc, typename ServoFunc>
+template<typename Func>
 nsresult
 nsDOMCSSDeclaration::ModifyDeclaration(nsIPrincipal* aSubjectPrincipal,
-                                       GeckoFunc aGeckoFunc,
-                                       ServoFunc aServoFunc)
+                                       Func aFunc)
 {
   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_Modify);
   if (!olddecl) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
   RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
 
   bool changed;
-  ServoCSSParsingEnvironment servoEnv = GetServoCSSParsingEnvironment(
-      aSubjectPrincipal);
+  ServoCSSParsingEnvironment servoEnv =
+    GetServoCSSParsingEnvironment(aSubjectPrincipal);
   if (!servoEnv.mUrlExtraData) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  changed = aServoFunc(decl->AsServo(), servoEnv);
+  changed = aFunc(decl->AsServo(), servoEnv);
 
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }
@@ -309,19 +306,16 @@ nsDOMCSSDeclaration::ModifyDeclaration(n
 nsresult
 nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
                                         const nsAString& aPropValue,
                                         bool aIsImportant,
                                         nsIPrincipal* aSubjectPrincipal)
 {
   return ModifyDeclaration(
     aSubjectPrincipal,
-    [&](css::Declaration* decl, CSSParsingEnvironment& env, bool* changed) {
-      MOZ_CRASH("old style system disabled");
-    },
     [&](ServoDeclarationBlock* decl, ServoCSSParsingEnvironment& env) {
       NS_ConvertUTF16toUTF8 value(aPropValue);
       return Servo_DeclarationBlock_SetPropertyById(
         decl->Raw(), aPropID, &value, aIsImportant, env.mUrlExtraData,
         ParsingMode::Default, env.mCompatMode, env.mLoader);
     });
 }
 
@@ -329,19 +323,16 @@ nsresult
 nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
                                               const nsAString& aPropValue,
                                               bool aIsImportant,
                                               nsIPrincipal* aSubjectPrincipal)
 {
   MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
   return ModifyDeclaration(
     aSubjectPrincipal,
-    [&](css::Declaration* decl, CSSParsingEnvironment& env, bool* changed) {
-      MOZ_CRASH("old style system disabled");
-    },
     [&](ServoDeclarationBlock* decl, ServoCSSParsingEnvironment& env) {
       NS_ConvertUTF16toUTF8 property(aPropertyName);
       NS_ConvertUTF16toUTF8 value(aPropValue);
       return Servo_DeclarationBlock_SetProperty(
         decl->Raw(), &property, &value, aIsImportant, env.mUrlExtraData,
         ParsingMode::Default, env.mCompatMode, env.mLoader);
     });
 }
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -223,14 +223,14 @@ protected:
 
   nsresult RemovePropertyInternal(nsCSSPropertyID aPropID);
   nsresult RemovePropertyInternal(const nsAString& aProperty);
 
 protected:
   virtual ~nsDOMCSSDeclaration();
 
 private:
-  template<typename GeckoFunc, typename ServoFunc>
+  template<typename ServoFunc>
   inline nsresult ModifyDeclaration(nsIPrincipal* aSubjectPrincipal,
-                                    GeckoFunc aGeckoFunc, ServoFunc aServoFunc);
+                                    ServoFunc aServoFunc);
 };
 
 #endif // nsDOMCSSDeclaration_h___
--- a/layout/xul/nsBox.cpp
+++ b/layout/xul/nsBox.cpp
@@ -20,118 +20,19 @@
 #include "nsBoxLayout.h"
 #include "FrameLayerBuilder.h"
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/Element.h"
 #include <algorithm>
 
 using namespace mozilla;
 
-#ifdef DEBUG_LAYOUT
-int32_t gIndent = 0;
-#endif
-
-#ifdef DEBUG_LAYOUT
-void
-nsBoxAddIndents()
-{
-    for(int32_t i=0; i < gIndent; i++)
-    {
-        printf(" ");
-    }
-}
-#endif
-
-#ifdef DEBUG_LAYOUT
-void
-nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult)
-{
-   aResult.Append(aAttribute);
-   aResult.AppendLiteral("='");
-   aResult.Append(aValue);
-   aResult.AppendLiteral("' ");
-}
-
-void
-nsBox::ListBox(nsAutoString& aResult)
-{
-    nsAutoString name;
-    GetBoxName(name);
-
-    char addr[100];
-    sprintf(addr, "[@%p] ", static_cast<void*>(this));
-
-    aResult.AppendASCII(addr);
-    aResult.Append(name);
-    aResult.Append(' ');
-
-    nsIContent* content = GetContent();
-
-    // add on all the set attributes
-    if (content && content->IsElement()) {
-      RefPtr<nsDOMAttributeMap> namedMap = content->AsElement()->Attributes();
-
-      uint32_t length = namedMap->Length();
-
-      RefPtr<dom::Attr> attribute;
-      for (uint32_t i = 0; i < length; ++i)
-      {
-        attribute = namedMap->Item(i);
-        attribute->GetName(name);
-        nsAutoString value;
-        attribute->GetValue(value);
-        AppendAttribute(name, value, aResult);
-      }
-    }
-}
-
-nsresult
-nsBox::XULDumpBox(FILE* aFile)
-{
-  nsAutoString s;
-  ListBox(s);
-  fprintf(aFile, "%s", NS_LossyConvertUTF16toASCII(s).get());
-  return NS_OK;
-}
-
-void
-nsBox::PropagateDebug(nsBoxLayoutState& aState)
-{
-  // propagate debug information
-  if (mState & NS_STATE_DEBUG_WAS_SET) {
-    if (mState & NS_STATE_SET_TO_DEBUG)
-      SetXULDebug(aState, true);
-    else
-      SetXULDebug(aState, false);
-  } else if (mState & NS_STATE_IS_ROOT) {
-    SetXULDebug(aState, gDebug);
-  }
-}
-#endif
-
-#ifdef DEBUG_LAYOUT
-void
-nsBox::GetBoxName(nsAutoString& aName)
-{
-  aName.AssignLiteral("Box");
-}
-#endif
-
 nsresult
 nsBox::BeginXULLayout(nsBoxLayoutState& aState)
 {
-#ifdef DEBUG_LAYOUT
-
-  nsBoxAddIndents();
-  printf("XULLayout: ");
-  XULDumpBox(stdout);
-  printf("\n");
-  gIndent++;
-#endif
-
   // mark ourselves as dirty so no child under us
   // can post an incremental layout.
   // XXXldb Is this still needed?
   AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
 
   if (GetStateBits() & NS_FRAME_IS_DIRTY)
   {
     // If the parent is dirty, all the children are dirty (ReflowInput
@@ -142,49 +43,38 @@ nsBox::BeginXULLayout(nsBoxLayoutState& 
   }
 
   // Another copy-over from ReflowInput.
   // Since we are in reflow, we don't need to store these properties anymore.
   DeleteProperty(UsedBorderProperty());
   DeleteProperty(UsedPaddingProperty());
   DeleteProperty(UsedMarginProperty());
 
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aState);
-#endif
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBox::DoXULLayout(nsBoxLayoutState& aState)
 {
   return NS_OK;
 }
 
 nsresult
 nsBox::EndXULLayout(nsBoxLayoutState& aState)
 {
-
-  #ifdef DEBUG_LAYOUT
-      --gIndent;
-  #endif
-
   return SyncLayout(aState);
 }
 
 bool nsBox::gGotTheme = false;
 nsITheme* nsBox::gTheme = nullptr;
 
 nsBox::nsBox(ClassID aID)
   : nsIFrame(aID)
 {
   MOZ_COUNT_CTOR(nsBox);
-  //mX = 0;
-  //mY = 0;
   if (!gGotTheme) {
     gGotTheme = true;
     CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme);
   }
 }
 
 nsBox::~nsBox()
 {
@@ -218,26 +108,22 @@ nsIFrame::GetXULClientRect(nsRect& aClie
   aClientRect.Deflate(borderPadding);
 
   if (aClientRect.width < 0)
      aClientRect.width = 0;
 
   if (aClientRect.height < 0)
      aClientRect.height = 0;
 
- // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0");
-
   return NS_OK;
 }
 
 void
 nsBox::SetXULBounds(nsBoxLayoutState& aState, const nsRect& aRect, bool aRemoveOverflowAreas)
 {
-    NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetXULBounds Size < 0");
-
     nsRect rect(mRect);
 
     uint32_t flags = GetXULLayoutFlags();
 
     uint32_t stateFlags = aState.LayoutFlags();
 
     flags |= stateFlags;
 
@@ -254,29 +140,16 @@ nsBox::SetXULBounds(nsBoxLayoutState& aS
     }
 
     if (!(flags & NS_FRAME_NO_MOVE_VIEW))
     {
       nsContainerFrame::PositionFrameView(this);
       if ((rect.x != aRect.x) || (rect.y != aRect.y))
         nsContainerFrame::PositionChildViews(this);
     }
-
-
-   /*
-    // only if the origin changed
-    if ((rect.x != aRect.x) || (rect.y != aRect.y))  {
-      if (frame->HasView()) {
-        nsContainerFrame::PositionFrameView(presContext, frame,
-                                            frame->GetView());
-      } else {
-        nsContainerFrame::PositionChildViews(presContext, frame);
-      }
-    }
-    */
 }
 
 nsresult
 nsIFrame::GetXULBorderAndPadding(nsMargin& aBorderAndPadding)
 {
   aBorderAndPadding.SizeTo(0, 0, 0, 0);
   nsresult rv = GetXULBorder(aBorderAndPadding);
   if (NS_FAILED(rv))
@@ -928,53 +801,8 @@ nsBox::GetNextXULBox(const nsIFrame* aFr
 
 /*static*/ nsIFrame*
 nsBox::GetParentXULBox(const nsIFrame* aFrame)
 {
   return aFrame->GetParent() &&
     aFrame->GetParent()->IsXULBoxFrame() ? aFrame->GetParent() : nullptr;
 }
 
-#ifdef DEBUG_LAYOUT
-nsresult
-nsBox::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
-{
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsBox::GetDebugBoxAt( const nsPoint& aPoint,
-                      nsIFrame**     aBox)
-{
-  nsRect thisRect(nsPoint(0,0), GetSize());
-  if (!thisRect.Contains(aPoint))
-    return NS_ERROR_FAILURE;
-
-  nsIFrame* child = nsBox::GetChildXULBox(this);
-  nsIFrame* hit = nullptr;
-
-  *aBox = nullptr;
-  while (nullptr != child) {
-    nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit);
-
-    if (NS_SUCCEEDED(rv) && hit) {
-      *aBox = hit;
-    }
-    child = GetNextXULBox(child);
-  }
-
-  // found a child
-  if (*aBox) {
-    return NS_OK;
-  }
-
-  return NS_ERROR_FAILURE;
-}
-
-
-nsresult
-nsBox::GetXULDebug(bool& aDebug)
-{
-  aDebug = false;
-  return NS_OK;
-}
-
-#endif
--- a/layout/xul/nsBox.h
+++ b/layout/xul/nsBox.h
@@ -37,31 +37,21 @@ public:
   virtual nsresult GetXULPadding(nsMargin& aBorderAndPadding) override;
   virtual nsresult GetXULMargin(nsMargin& aMargin) override;
 
   virtual Valignment GetXULVAlign() const override { return vAlign_Top; }
   virtual Halignment GetXULHAlign() const override { return hAlign_Left; }
 
   virtual nsresult XULRelayoutChildAtOrdinal(nsIFrame* aChild) override;
 
-#ifdef DEBUG_LAYOUT
-  NS_IMETHOD GetDebugBoxAt(const nsPoint& aPoint, nsIFrame** aBox) override;
-  virtual nsresult GetXULDebug(bool& aDebug) override;
-  virtual nsresult SetXULDebug(nsBoxLayoutState& aState, bool aDebug) override;
-
-  virtual nsresult XULDumpBox(FILE* out) override;
-  void PropagateDebug(nsBoxLayoutState& aState);
-#endif
-
   nsBox(ClassID aID);
   virtual ~nsBox();
 
   /**
-   * Returns true if this box clips its children, e.g., if this box is an sc
-rollbox.
+   * Returns true if this box clips its children, e.g., if this box is an scrollbox.
   */
   virtual bool DoesClipChildren();
   virtual bool ComputesOwnOverflowArea() = 0;
 
   nsresult SyncLayout(nsBoxLayoutState& aBoxLayoutState);
 
   bool DoesNeedRecalc(const nsSize& aSize);
   bool DoesNeedRecalc(nscoord aCoord);
@@ -79,50 +69,24 @@ rollbox.
   static nscoord BoundsCheck(nscoord aMinSize, nscoord aPrefSize, nscoord aMaxSize);
 
   static nsIFrame* GetChildXULBox(const nsIFrame* aFrame);
   static nsIFrame* GetNextXULBox(const nsIFrame* aFrame);
   static nsIFrame* GetParentXULBox(const nsIFrame* aFrame);
 
 protected:
 
-#ifdef DEBUG_LAYOUT
-  virtual void AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult);
-
-  virtual void ListBox(nsAutoString& aResult);
-#endif
-
   nsresult BeginXULLayout(nsBoxLayoutState& aState);
   NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState);
   nsresult EndXULLayout(nsBoxLayoutState& aState);
 
-#ifdef DEBUG_LAYOUT
-  virtual void GetBoxName(nsAutoString& aName);
-  void PropagateDebug(nsBoxLayoutState& aState);
-#endif
-
   static bool gGotTheme;
   static nsITheme* gTheme;
 
   enum eMouseThrough {
     unset,
     never,
     always
   };
-
-private:
-
-  //nscoord mX;
-  //nscoord mY;
 };
 
-#ifdef DEBUG_LAYOUT
-#define NS_BOX_ASSERTION(box,expr,str) \
-  if (!(expr)) { \
-       box->XULDumpBox(stdout); \
-       NS_DebugBreak(NSDebugAssertion, str, #expr, __FILE__, __LINE__); \
-  }
-#else
-#define NS_BOX_ASSERTION(box,expr,str) {}
-#endif
-
 #endif
 
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -71,33 +71,16 @@
 #include "nsIURI.h"
 
 #include "mozilla/TouchEvents.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
-//define DEBUG_REDRAW
-
-#define DEBUG_SPRING_SIZE 8
-#define DEBUG_BORDER_SIZE 2
-#define COIL_SIZE 8
-
-//#define TEST_SANITY
-
-#ifdef DEBUG_rods
-//#define DO_NOISY_REFLOW
-#endif
-
-#ifdef DEBUG_LAYOUT
-bool nsBoxFrame::gDebug = false;
-nsIFrame* nsBoxFrame::mDebugChild = nullptr;
-#endif
-
 nsIFrame*
 NS_NewBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle, bool aIsRoot, nsBoxLayout* aLayoutManager)
 {
   return new (aPresShell) nsBoxFrame(aStyle, nsBoxFrame::kClassID,
                                      aIsRoot, aLayoutManager);
 }
 
 nsIFrame*
@@ -181,23 +164,16 @@ nsBoxFrame::Init(nsIContent*       aCont
   if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
     AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   }
 
   MarkIntrinsicISizesDirty();
 
   CacheAttributes();
 
-#ifdef DEBUG_LAYOUT
-    // if we are root and this
-  if (mState & NS_STATE_IS_ROOT) {
-    GetDebugPref();
-  }
-#endif
-
   UpdateMouseThrough();
 
   // register access key
   RegUnregAccessKey(true);
 }
 
 void nsBoxFrame::UpdateMouseThrough()
 {
@@ -252,53 +228,18 @@ nsBoxFrame::CacheAttributes()
         RemoveStateBits(NS_STATE_EQUAL_SIZE);
 
   bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
   GetInitialAutoStretch(autostretch);
   if (autostretch)
         AddStateBits(NS_STATE_AUTO_STRETCH);
      else
         RemoveStateBits(NS_STATE_AUTO_STRETCH);
-
-
-#ifdef DEBUG_LAYOUT
-  bool debug = mState & NS_STATE_SET_TO_DEBUG;
-  bool debugSet = GetInitialDebug(debug);
-  if (debugSet) {
-        AddStateBits(NS_STATE_DEBUG_WAS_SET);
-        if (debug)
-            AddStateBits(NS_STATE_SET_TO_DEBUG);
-        else
-            RemoveStateBits(NS_STATE_SET_TO_DEBUG);
-  } else {
-        RemoveStateBits(NS_STATE_DEBUG_WAS_SET);
-  }
-#endif
 }
 
-#ifdef DEBUG_LAYOUT
-bool
-nsBoxFrame::GetInitialDebug(bool& aDebug)
-{
-  if (!GetContent() || !GetContent()->IsElement())
-    return false;
-
-  static Element::AttrValuesArray strings[] =
-    {&nsGkAtoms::_false, &nsGkAtoms::_true, nullptr};
-  int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None,
-      nsGkAtoms::debug, strings, eCaseMatters);
-  if (index >= 0) {
-    aDebug = index == 1;
-    return true;
-  }
-
-  return false;
-}
-#endif
-
 bool
 nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign)
 {
   if (!GetContent() || !GetContent()->IsElement())
     return false;
 
   Element* element = GetContent()->AsElement();
   // XXXdwh Everything inside this if statement is deprecated code.
@@ -767,20 +708,16 @@ nsBoxFrame::GetXULPrefSize(nsBoxLayoutSt
 
   nsSize size(0,0);
   DISPLAY_PREF_SIZE(this, size);
   if (!DoesNeedRecalc(mPrefSize)) {
     size = mPrefSize;
     return size;
   }
 
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aBoxLayoutState);
-#endif
-
   if (IsXULCollapsed())
     return size;
 
   // if the size was not completely redefined in CSS then ask our children
   bool widthSet, heightSet;
   if (!nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet))
   {
     if (mLayoutManager) {
@@ -803,20 +740,16 @@ nsBoxFrame::GetXULPrefSize(nsBoxLayoutSt
 }
 
 nscoord
 nsBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState)
 {
   if (!DoesNeedRecalc(mAscent))
      return mAscent;
 
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aBoxLayoutState);
-#endif
-
   if (IsXULCollapsed())
     return 0;
 
   if (mLayoutManager)
     mAscent = mLayoutManager->GetAscent(this, aBoxLayoutState);
   else
     mAscent = nsBox::GetXULBoxAscent(aBoxLayoutState);
 
@@ -831,20 +764,16 @@ nsBoxFrame::GetXULMinSize(nsBoxLayoutSta
 
   nsSize size(0,0);
   DISPLAY_MIN_SIZE(this, size);
   if (!DoesNeedRecalc(mMinSize)) {
     size = mMinSize;
     return size;
   }
 
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aBoxLayoutState);
-#endif
-
   if (IsXULCollapsed())
     return size;
 
   // if the size was not completely redefined in CSS then ask our children
   bool widthSet, heightSet;
   if (!nsIFrame::AddXULMinSize(aBoxLayoutState, this, size, widthSet, heightSet))
   {
     if (mLayoutManager) {
@@ -872,20 +801,16 @@ nsBoxFrame::GetXULMaxSize(nsBoxLayoutSta
 
   nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
   DISPLAY_MAX_SIZE(this, size);
   if (!DoesNeedRecalc(mMaxSize)) {
     size = mMaxSize;
     return size;
   }
 
-#ifdef DEBUG_LAYOUT
-  PropagateDebug(aBoxLayoutState);
-#endif
-
   if (IsXULCollapsed())
     return size;
 
   // if the size was not completely redefined in CSS then ask our children
   bool widthSet, heightSet;
   if (!nsIFrame::AddXULMaxSize(this, size, widthSet, heightSet))
   {
     if (mLayoutManager) {
@@ -977,42 +902,16 @@ nsBoxFrame::DestroyFrom(nsIFrame* aDestr
   RegUnregAccessKey(false);
 
   // clean up the container box's layout manager and child boxes
   SetXULLayoutManager(nullptr);
 
   nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
 }
 
-#ifdef DEBUG_LAYOUT
-nsresult
-nsBoxFrame::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
-{
-  // see if our state matches the given debug state
-  bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
-  bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
-
-  // if it doesn't then tell each child below us the new debug state
-  if (debugChanged)
-  {
-     if (aDebug) {
-         AddStateBits(NS_STATE_CURRENTLY_IN_DEBUG);
-     } else {
-         RemoveStateBits(NS_STATE_CURRENTLY_IN_DEBUG);
-     }
-
-     SetDebugOnChildList(aState, mFirstChild, aDebug);
-
-    MarkIntrinsicISizesDirty();
-  }
-
-  return NS_OK;
-}
-#endif
-
 /* virtual */ void
 nsBoxFrame::MarkIntrinsicISizesDirty()
 {
   SizeNeedsRecalc(mPrefSize);
   SizeNeedsRecalc(mMinSize);
   SizeNeedsRecalc(mMaxSize);
   CoordNeedsRecalc(mFlex);
   CoordNeedsRecalc(mAscent);
@@ -1070,22 +969,16 @@ nsBoxFrame::InsertFrames(ChildListID    
      mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames);
 
    // Make sure to check box order _after_ notifying the layout
    // manager; otherwise the slice we give the layout manager will
    // just be bogus.  If the layout manager cares about the order, we
    // just lose.
    CheckBoxOrder();
 
-#ifdef DEBUG_LAYOUT
-   // if we are in debug make sure our children are in debug as well.
-   if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
-       SetDebugOnChildList(state, mFrames.FirstChild(), true);
-#endif
-
    PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                                  NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 
 void
 nsBoxFrame::AppendFrames(ChildListID     aListID,
                          nsFrameList&    aFrameList)
@@ -1101,22 +994,16 @@ nsBoxFrame::AppendFrames(ChildListID    
      mLayoutManager->ChildrenAppended(this, state, newFrames);
 
    // Make sure to check box order _after_ notifying the layout
    // manager; otherwise the slice we give the layout manager will
    // just be bogus.  If the layout manager cares about the order, we
    // just lose.
    CheckBoxOrder();
 
-#ifdef DEBUG_LAYOUT
-   // if we are in debug make sure our children are in debug as well.
-   if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
-       SetDebugOnChildList(state, mFrames.FirstChild(), true);
-#endif
-
    // XXXbz why is this NS_FRAME_FIRST_REFLOW check here?
    if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
      PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                                    NS_FRAME_HAS_DIRTY_CHILDREN);
    }
 }
 
 /* virtual */ nsContainerFrame*
@@ -1169,19 +1056,16 @@ nsBoxFrame::AttributeChanged(int32_t aNa
       aAttribute == nsGkAtoms::dir          ||
       aAttribute == nsGkAtoms::mousethrough ||
       aAttribute == nsGkAtoms::equalsize) {
 
     if (aAttribute == nsGkAtoms::align  ||
         aAttribute == nsGkAtoms::valign ||
         aAttribute == nsGkAtoms::orient  ||
         aAttribute == nsGkAtoms::pack    ||
-#ifdef DEBUG_LAYOUT
-        aAttribute == nsGkAtoms::debug   ||
-#endif
         aAttribute == nsGkAtoms::dir) {
 
       mValign = nsBoxFrame::vAlign_Top;
       mHalign = nsBoxFrame::hAlign_Left;
 
       bool orient = true;
       GetInitialOrientation(orient);
       if (orient)
@@ -1201,31 +1085,16 @@ nsBoxFrame::AttributeChanged(int32_t aNa
 
       bool equalSize = false;
       GetInitialEqualSize(equalSize);
       if (equalSize)
         AddStateBits(NS_STATE_EQUAL_SIZE);
       else
         RemoveStateBits(NS_STATE_EQUAL_SIZE);
 
-#ifdef DEBUG_LAYOUT
-      bool debug = mState & NS_STATE_SET_TO_DEBUG;
-      bool debugSet = GetInitialDebug(debug);
-      if (debugSet) {
-        AddStateBits(NS_STATE_DEBUG_WAS_SET);
-
-        if (debug)
-          AddStateBits(NS_STATE_SET_TO_DEBUG);
-        else
-          RemoveStateBits(NS_STATE_SET_TO_DEBUG);
-      } else {
-        RemoveStateBits(NS_STATE_DEBUG_WAS_SET);
-      }
-#endif
-
       bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
       GetInitialAutoStretch(autostretch);
       if (autostretch)
         AddStateBits(NS_STATE_AUTO_STRETCH);
       else
         RemoveStateBits(NS_STATE_AUTO_STRETCH);
     }
     else if (aAttribute == nsGkAtoms::left ||
@@ -1269,63 +1138,16 @@ nsBoxFrame::AttributeChanged(int32_t aNa
     // nsTreeBodyFrame's layout reads this from its parent (this frame).
     PresShell()->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
                                   NS_FRAME_IS_DIRTY);
   }
 
   return rv;
 }
 
-#ifdef DEBUG_LAYOUT
-void
-nsBoxFrame::GetDebugPref()
-{
-  gDebug = Preferences::GetBool("xul.debug.box");
-}
-
-class nsDisplayXULDebug : public nsDisplayItem {
-public:
-  nsDisplayXULDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
-    nsDisplayItem(aBuilder, aFrame) {
-    MOZ_COUNT_CTOR(nsDisplayXULDebug);
-  }
-#ifdef NS_BUILD_REFCNT_LOGGING
-  virtual ~nsDisplayXULDebug() {
-    MOZ_COUNT_DTOR(nsDisplayXULDebug);
-  }
-#endif
-
-  virtual void HitTest(nsDisplayListBuilder* aBuilder, nsRect aRect,
-                       HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
-    nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
-    static_cast<nsBoxFrame*>(mFrame)->
-      DisplayDebugInfoFor(this, rectCenter - ToReferenceFrame());
-    aOutFrames->AppendElement(this);
-  }
-  virtual void Paint(nsDisplayListBuilder* aBuilder
-                     gfxContext* aCtx);
-  NS_DISPLAY_DECL_NAME("XULDebug", TYPE_XUL_DEBUG)
-};
-
-void
-nsDisplayXULDebug::Paint(nsDisplayListBuilder* aBuilder,
-                         gfxContext* aCtx)
-{
-  static_cast<nsBoxFrame*>(mFrame)->
-    PaintXULDebugOverlay(*aCtx->GetDrawTarget(), ToReferenceFrame());
-}
-
-static void
-PaintXULDebugBackground(nsIFrame* aFrame, DrawTarget* aDrawTarget,
-                        const nsRect& aDirtyRect, nsPoint aPt)
-{
-  static_cast<nsBoxFrame*>(aFrame)->PaintXULDebugBackground(aDrawTarget, aPt);
-}
-#endif
-
 void
 nsBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                              const nsDisplayListSet& aLists)
 {
   bool forceLayer = false;
 
   if (GetContent()->IsXULElement()) {
     // forcelayer is only supported on XUL elements with box layout
@@ -1342,26 +1164,16 @@ nsBoxFrame::BuildDisplayList(nsDisplayLi
     }
   }
 
   nsDisplayListCollection tempLists(aBuilder);
   const nsDisplayListSet& destination = forceLayer ? tempLists : aLists;
 
   DisplayBorderBackgroundOutline(aBuilder, destination);
 
-#ifdef DEBUG_LAYOUT
-  if (mState & NS_STATE_CURRENTLY_IN_DEBUG) {
-    destination.BorderBackground()->AppendToTop(
-      MakeDisplayItem<nsDisplayGeneric>(aBuilder, this, PaintXULDebugBackground,
-                       "XULDebugBackground"));
-    destination.Outlines()->AppendToTop(
-      MakeDisplayItem<nsDisplayXULDebug>(aBuilder, this));
-  }
-#endif
-
   Maybe<nsDisplayListBuilder::AutoContainerASRTracker> contASRTracker;
   if (forceLayer) {
     contASRTracker.emplace(aBuilder);
   }
 
   BuildDisplayListForChildren(aBuilder, destination);
 
   // see if we have to draw a selection frame around this container
@@ -1402,486 +1214,24 @@ nsBoxFrame::BuildDisplayListForChildren(
   nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
   // The children should be in the right order
   while (kid) {
     BuildDisplayListForChild(aBuilder, kid, set);
     kid = kid->GetNextSibling();
   }
 }
 
-// REVIEW: PaintChildren did a few things none of which are a big deal
-// anymore:
-// * Paint some debugging rects for this frame.
-// This is done by nsDisplayXULDebugBackground, which goes in the
-// BorderBackground() layer so it isn't clipped by OVERFLOW_CLIP.
-// * Apply OVERFLOW_CLIP to the children.
-// This is now in nsFrame::BuildDisplayListForStackingContext/Child.
-// * Actually paint the children.
-// Moved to BuildDisplayList.
-// * Paint per-kid debug information.
-// This is done by nsDisplayXULDebug, which is in the Outlines()
-// layer so it goes on top. This means it is not clipped by OVERFLOW_CLIP,
-// whereas it did used to respect OVERFLOW_CLIP, but too bad.
-#ifdef DEBUG_LAYOUT
-void
-nsBoxFrame::PaintXULDebugBackground(DrawTarget* aDrawTarget, nsPoint aPt)
-{
-  nsMargin border;
-  GetXULBorder(border);
-
-  nsMargin debugBorder;
-  nsMargin debugMargin;
-  nsMargin debugPadding;
-
-  bool isHorizontal = IsXULHorizontal();
-
-  GetDebugBorder(debugBorder);
-  PixelMarginToTwips(debugBorder);
-
-  GetDebugMargin(debugMargin);
-  PixelMarginToTwips(debugMargin);
-
-  GetDebugPadding(debugPadding);
-  PixelMarginToTwips(debugPadding);
-
-  nsRect inner(mRect);
-  inner.MoveTo(aPt);
-  inner.Deflate(debugMargin);
-  inner.Deflate(border);
-  //nsRect borderRect(inner);
-
-  int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
-
-  ColorPattern color(ToDeviceColor(isHorizontal ? Color(0.f, 0.f, 1.f, 1.f) :
-                                                  Color(1.f, 0.f, 0.f, 1.f)));
-
-  //left
-  nsRect r(inner);
-  r.width = debugBorder.left;
-  aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
-
-  // top
-  r = inner;
-  r.height = debugBorder.top;
-  aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
-
-  //right
-  r = inner;
-  r.x = r.x + r.width - debugBorder.right;
-  r.width = debugBorder.right;
-  aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
-
-  //bottom
-  r = inner;
-  r.y = r.y + r.height - debugBorder.bottom;
-  r.height = debugBorder.bottom;
-  aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
-
-  // If we have dirty children or we are dirty place a green border around us.
-  if (NS_SUBTREE_DIRTY(this)) {
-    nsRect dirty(inner);
-    ColorPattern green(ToDeviceColor(Color(0.f, 1.f, 0.f, 1.f)));
-    aDrawTarget->StrokeRect(NSRectToRect(dirty, appUnitsPerDevPixel), green);
-  }
-}
-
-void
-nsBoxFrame::PaintXULDebugOverlay(DrawTarget& aDrawTarget, nsPoint aPt)
-{
-  nsMargin border;
-  GetXULBorder(border);
-
-  nsMargin debugMargin;
-  GetDebugMargin(debugMargin);
-  PixelMarginToTwips(debugMargin);
-
-  nsRect inner(mRect);
-  inner.MoveTo(aPt);
-  inner.Deflate(debugMargin);
-  inner.Deflate(border);
-
-  nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1);
-
-  kid = nsBox::GetChildXULBox(this);
-  while (nullptr != kid) {
-    bool isHorizontal = IsXULHorizontal();
-
-    nscoord x, y, borderSize, spacerSize;
-
-    nsRect cr(kid->mRect);
-    nsMargin margin;
-    kid->GetXULMargin(margin);
-    cr.Inflate(margin);
-
-    if (isHorizontal)
-    {
-        cr.y = inner.y;
-        x = cr.x;
-        y = cr.y + onePixel;
-        spacerSize = debugBorder.top - onePixel*4;
-    } else {
-        cr.x = inner.x;
-        x = cr.y;
-        y = cr.x + onePixel;
-        spacerSize = debugBorder.left - onePixel*4;
-    }
-
-    nscoord flex = kid->GetXULFlex();
-
-    if (!kid->IsXULCollapsed()) {
-      if (isHorizontal)
-          borderSize = cr.width;
-      else
-          borderSize = cr.height;
-
-      DrawSpacer(GetPresContext(), aDrawTarget, isHorizontal, flex, x, y, borderSize, spacerSize);
-    }
-
-    kid = GetNextXULBox(kid);
-  }
-}
-#endif
-
-#ifdef DEBUG_LAYOUT
-void
-nsBoxFrame::GetBoxName(nsAutoString& aName)
-{
-   GetFrameName(aName);
-}
-#endif
-
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsBoxFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Box"), aResult);
 }
 #endif
 
-#ifdef DEBUG_LAYOUT
-nsresult
-nsBoxFrame::GetXULDebug(bool& aDebug)
-{
-  aDebug = (mState & NS_STATE_CURRENTLY_IN_DEBUG);
-  return NS_OK;
-}
-#endif
-
-// REVIEW: nsBoxFrame::GetFrameForPoint is a problem because of 'mousethrough'
-// attribute support. Here's how it works:
-// * For each child frame F, we determine the target frame T(F) by recursively
-// invoking GetFrameForPoint on the child
-// * Let F' be the last child frame such that T(F') doesn't have mousethrough.
-// If F' exists, return T(F')
-// * Otherwise let F'' be the first child frame such that T(F'') is non-null.
-// If F'' exists, return T(F'')
-// * Otherwise return this frame, if this frame contains the point
-// * Otherwise return null
-// It's not clear how this should work for more complex z-ordering situations.
-// The basic principle seems to be that if a frame F has a descendant
-// 'mousethrough' frame that includes the target position, then F
-// will not receive events (unless it overrides GetFrameForPoint).
-// A 'mousethrough' frame will only receive an event if, after applying that rule,
-// all eligible frames are 'mousethrough'; the bottom-most inner-most 'mousethrough'
-// frame is then chosen (the first eligible frame reached in a
-// traversal of the frame tree --- pre/post is irrelevant since ancestors
-// of the mousethrough frames can't be eligible).
-// IMHO this is very bogus and adds a great deal of complexity for something
-// that is very rarely used. So I'm redefining 'mousethrough' to the following:
-// a frame with mousethrough is transparent to mouse events. This is compatible
-// with the way 'mousethrough' is used in Seamonkey's navigator.xul and
-// Firefox's browser.xul. The only other place it's used is in the 'expander'
-// XBL binding, which in our tree is only used by Thunderbird SMIME Advanced
-// Preferences, and I can't figure out what that does, so I'll have to test it.
-// If it's broken I'll probably just change the binding to use it more sensibly.
-// This new behaviour is implemented in nsDisplayList::HitTest.
-// REVIEW: This debug-box stuff is annoying. I'm just going to put debug boxes
-// in the outline layer and avoid GetDebugBoxAt.
-
-// REVIEW: GetCursor had debug-only event dumping code. I have replaced it
-// with instrumentation in nsDisplayXULDebug.
-
-#ifdef DEBUG_LAYOUT
-void
-nsBoxFrame::DrawLine(DrawTarget& aDrawTarget, bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2)
-{
-    nsPoint p1(x1, y1);
-    nsPoint p2(x2, y2);
-    if (!aHorizontal) {
-      Swap(p1.x, p1.y);
-      Swap(p2.x, p2.y);
-    }
-    ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
-    StrokeLineWithSnapping(p1, p2, PresContext()->AppUnitsPerDevPixel(),
-                           aDrawTarget, color);
-}
-
-void
-nsBoxFrame::FillRect(DrawTarget& aDrawTarget, bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height)
-{
-    Rect rect = NSRectToSnappedRect(aHorizontal ? nsRect(x, y, width, height) :
-                                                  nsRect(y, x, height, width),
-                                    PresContext()->AppUnitsPerDevPixel(),
-                                    aDrawTarget);
-    ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
-    aDrawTarget.FillRect(rect, white);
-}
-
-void
-nsBoxFrame::DrawSpacer(nsPresContext* aPresContext, DrawTarget& aDrawTarget,
-                       bool aHorizontal, int32_t flex, nscoord x, nscoord y,
-                       nscoord size, nscoord spacerSize)
-{
-         nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
-
-     // if we do draw the coils
-        int distance = 0;
-        int center = 0;
-        int offset = 0;
-        int coilSize = COIL_SIZE*onePixel;
-        int halfSpacer = spacerSize/2;
-
-        distance = size;
-        center = y + halfSpacer;
-        offset = x;
-
-        int coils = distance/coilSize;
-
-        int halfCoilSize = coilSize/2;
-
-        if (flex == 0) {
-            DrawLine(aDrawTarget, aHorizontal, x,y + spacerSize/2, x + size, y + spacerSize/2);
-        } else {
-            for (int i=0; i < coils; i++)
-            {
-                   DrawLine(aDrawTarget, aHorizontal, offset, center+halfSpacer, offset+halfCoilSize, center-halfSpacer);
-                   DrawLine(aDrawTarget, aHorizontal, offset+halfCoilSize, center-halfSpacer, offset+coilSize, center+halfSpacer);
-
-                   offset += coilSize;
-            }
-        }
-
-        FillRect(aDrawTarget, aHorizontal, x + size - spacerSize/2, y, spacerSize/2, spacerSize);
-        FillRect(aDrawTarget, aHorizontal, x, y, spacerSize/2, spacerSize);
-}
-
-void
-nsBoxFrame::GetDebugBorder(nsMargin& aInset)
-{
-    aInset.SizeTo(2,2,2,2);
-
-    if (IsXULHorizontal())
-       aInset.top = 10;
-    else
-       aInset.left = 10;
-}
-
-void
-nsBoxFrame::GetDebugMargin(nsMargin& aInset)
-{
-    aInset.SizeTo(2,2,2,2);
-}
-
-void
-nsBoxFrame::GetDebugPadding(nsMargin& aPadding)
-{
-    aPadding.SizeTo(2,2,2,2);
-}
-
-void
-nsBoxFrame::PixelMarginToTwips(nsMargin& aMarginPixels)
-{
-  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
-  aMarginPixels.left   *= onePixel;
-  aMarginPixels.right  *= onePixel;
-  aMarginPixels.top    *= onePixel;
-  aMarginPixels.bottom *= onePixel;
-}
-
-void
-nsBoxFrame::GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* ch)
-{
-    float p2t = aPresContext->ScaledPixelsToTwips();
-
-    char width[100];
-    char height[100];
-
-    if (a.width == NS_INTRINSICSIZE)
-        sprintf(width,"%s","INF");
-    else
-        sprintf(width,"%d", nscoord(a.width/*/p2t*/));
-
-    if (a.height == NS_INTRINSICSIZE)
-        sprintf(height,"%s","INF");
-    else
-        sprintf(height,"%d", nscoord(a.height/*/p2t*/));
-
-
-    sprintf(ch, "(%s%s, %s%s)", width, (b.width != NS_INTRINSICSIZE ? "[SET]" : ""),
-                    height, (b.height != NS_INTRINSICSIZE ? "[SET]" : ""));
-
-}
-
-void
-nsBoxFrame::GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* ch)
-{
-    if (a == NS_INTRINSICSIZE)
-      sprintf(ch, "%d[SET]", b);
-    else
-      sprintf(ch, "%d", a);
-}
-
-nsresult
-nsBoxFrame::DisplayDebugInfoFor(nsIFrame*  aBox,
-                                nsPoint& aPoint)
-{
-    nsBoxLayoutState state(GetPresContext());
-
-    nscoord x = aPoint.x;
-    nscoord y = aPoint.y;
-
-    // get the area inside our border but not our debug margins.
-    nsRect insideBorder(aBox->mRect);
-    insideBorder.MoveTo(0,0):
-    nsMargin border(0,0,0,0);
-    aBox->GetXULBorderAndPadding(border);
-    insideBorder.Deflate(border);
-
-    bool isHorizontal = IsXULHorizontal();
-
-    if (!insideBorder.Contains(nsPoint(x,y)))
-        return NS_ERROR_FAILURE;
-
-    //printf("%%%%%% inside box %%%%%%%\n");
-
-    int count = 0;
-    nsIFrame* child = nsBox::GetChildXULBox(aBox);
-
-    nsMargin m;
-    nsMargin m2;
-    GetDebugBorder(m);
-    PixelMarginToTwips(m);
-
-    GetDebugMargin(m2);
-    PixelMarginToTwips(m2);
-
-    m += m2;
-
-    if ((isHorizontal && y < insideBorder.y + m.top) ||
-        (!isHorizontal && x < insideBorder.x + m.left)) {
-        //printf("**** inside debug border *******\n");
-        while (child)
-        {
-            const nsRect& r = child->mRect;
-
-            // if we are not in the child. But in the spacer above the child.
-            if ((isHorizontal && x >= r.x && x < r.x + r.width) ||
-                (!isHorizontal && y >= r.y && y < r.y + r.height)) {
-                aCursor = NS_STYLE_CURSOR_POINTER;
-                   // found it but we already showed it.
-                    if (mDebugChild == child)
-                        return NS_OK;
-
-                    if (aBox->GetContent()) {
-                      printf("---------------\n");
-                      XULDumpBox(stdout);
-                      printf("\n");
-                    }
-
-                    if (child->GetContent()) {
-                        printf("child #%d: ", count);
-                        child->XULDumpBox(stdout);
-                        printf("\n");
-                    }
-
-                    mDebugChild = child;
-
-                    nsSize prefSizeCSS(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
-                    nsSize minSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
-                    nsSize maxSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
-                    nscoord flexCSS = NS_INTRINSICSIZE;
-
-                    bool widthSet, heightSet;
-                    nsIFrame::AddXULPrefSize(child, prefSizeCSS, widthSet, heightSet);
-                    nsIFrame::AddXULMinSize (state, child, minSizeCSS, widthSet, heightSet);
-                    nsIFrame::AddXULMaxSize (child, maxSizeCSS, widthSet, heightSet);
-                    nsIFrame::AddXULFlex    (child, flexCSS);
-
-                    nsSize prefSize = child->GetXULPrefSize(state);
-                    nsSize minSize = child->GetXULMinSize(state);
-                    nsSize maxSize = child->GetXULMaxSize(state);
-                    nscoord flexSize = child->GetXULFlex();
-                    nscoord ascentSize = child->GetXULBoxAscent(state);
-
-                    char min[100];
-                    char pref[100];
-                    char max[100];
-                    char calc[100];
-                    char flex[100];
-                    char ascent[100];
-
-                    nsSize actualSize;
-                    GetFrameSizeWithMargin(child, actualSize);
-                    nsSize actualSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
-
-                    GetValue(aPresContext, minSize,  minSizeCSS, min);
-                    GetValue(aPresContext, prefSize, prefSizeCSS, pref);
-                    GetValue(aPresContext, maxSize,  maxSizeCSS, max);
-                    GetValue(aPresContext, actualSize, actualSizeCSS, calc);
-                    GetValue(aPresContext, flexSize,  flexCSS, flex);
-                    GetValue(aPresContext, ascentSize,  NS_INTRINSICSIZE, ascent);
-
-
-                    printf("min%s, pref%s, max%s, actual%s, flex=%s, ascent=%s\n\n",
-                        min,
-                        pref,
-                        max,
-                        calc,
-                        flex,
-                        ascent
-                    );
-
-                    return NS_OK;
-            }
-
-          child = GetNextXULBox(child);
-          count++;
-        }
-    } else {
-    }
-
-    mDebugChild = nullptr;
-
-    return NS_OK;
-}
-
-void
-nsBoxFrame::SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug)
-{
-    nsIFrame* child = nsBox::GetChildXULBox(this);
-     while (child)
-     {
-        child->SetXULDebug(aState, aDebug);
-        child = GetNextXULBox(child);
-     }
-}
-
-nsresult
-nsBoxFrame::GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize)
-{
-  nsRect rect(aBox->GetRect());
-  nsMargin margin(0,0,0,0);
-  aBox->GetXULMargin(margin);
-  rect.Inflate(margin);
-  aSize.width = rect.width;
-  aSize.height = rect.height;
-  return NS_OK;
-}
-#endif
-
 // If you make changes to this function, check its counterparts
 // in nsTextBoxFrame and nsXULLabelFrame
 void
 nsBoxFrame::RegUnregAccessKey(bool aDoReg)
 {
   MOZ_ASSERT(mContent);
 
   // only support accesskeys for the following elements
--- a/layout/xul/nsBoxFrame.h
+++ b/layout/xul/nsBoxFrame.h
@@ -61,20 +61,16 @@ public:
 
   virtual nsresult XULRelayoutChildAtOrdinal(nsIFrame* aChild) override;
 
   virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nscoord GetXULFlex() override;
   virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
-#ifdef DEBUG_LAYOUT
-  virtual nsresult SetXULDebug(nsBoxLayoutState& aBoxLayoutState, bool aDebug) override;
-  virtual nsresult GetXULDebug(bool& aDebug) override;
-#endif
   virtual Valignment GetXULVAlign() const override { return mValign; }
   virtual Halignment GetXULHAlign() const override { return mHalign; }
   NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
 
   virtual bool ComputesOwnOverflowArea() override { return false; }
 
   // ----- child and sibling operations ---
 
@@ -141,22 +137,16 @@ public:
   // virtual so nsStackFrame, nsButtonBoxFrame, nsSliderFrame and nsMenuFrame
   // can override it
   virtual void BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                            const nsDisplayListSet& aLists);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override;
 
-#ifdef DEBUG_LAYOUT
-    virtual void SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug);
-    nsresult DisplayDebugInfoFor(nsIFrame*  aBox,
-                                 nsPoint& aPoint);
-#endif
-
   static nsresult LayoutChildAt(nsBoxLayoutState& aState, nsIFrame* aBox, const nsRect& aRect);
 
   /**
    * Utility method to redirect events on descendants to this frame.
    * Supports 'allowevents' attribute on descendant elements to allow those
    * elements and their descendants to receive events.
    */
   void WrapListsInRedirector(nsDisplayListBuilder*   aBuilder,
@@ -177,24 +167,16 @@ public:
 private:
   explicit nsBoxFrame(ComputedStyle* aStyle)
     : nsBoxFrame(aStyle, kClassID, false, nullptr) {}
 protected:
   nsBoxFrame(ComputedStyle* aStyle, ClassID aID, bool aIsRoot = false,
              nsBoxLayout* aLayoutManager = nullptr);
   virtual ~nsBoxFrame();
 
-#ifdef DEBUG_LAYOUT
-    virtual void GetBoxName(nsAutoString& aName) override;
-    void PaintXULDebugBackground(gfxContext& aRenderingContext,
-                                 nsPoint aPt);
-    void PaintXULDebugOverlay(DrawTarget& aRenderingContext,
-                              nsPoint aPt);
-#endif
-
     virtual bool GetInitialEqualSize(bool& aEqualSize);
     virtual void GetInitialOrientation(bool& aIsHorizontal);
     virtual void GetInitialDirection(bool& aIsNormal);
     virtual bool GetInitialHAlignment(Halignment& aHalign);
     virtual bool GetInitialVAlignment(Valignment& aValign);
     virtual bool GetInitialAutoStretch(bool& aStretch);
 
     virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
@@ -217,44 +199,20 @@ protected:
 
 protected:
     void RegUnregAccessKey(bool aDoReg);
 
   void CheckBoxOrder();
 
 private:
 
-#ifdef DEBUG_LAYOUT
-    nsresult SetXULDebug(nsPresContext* aPresContext, bool aDebug);
-    bool GetInitialDebug(bool& aDebug);
-    void GetDebugPref();
-
-    void GetDebugBorder(nsMargin& aInset);
-    void GetDebugPadding(nsMargin& aInset);
-    void GetDebugMargin(nsMargin& aInset);
-
-    nsresult GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize);
-
-    void PixelMarginToTwips(nsMargin& aMarginPixels);
-
-    void GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* value);
-    void GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* value);
-    void DrawSpacer(nsPresContext* aPresContext, DrawTarget& aDrawTarget, bool aHorizontal, int32_t flex, nscoord x, nscoord y, nscoord size, nscoord spacerSize);
-    void DrawLine(DrawTarget& aDrawTarget,  bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2);
-    void FillRect(DrawTarget& aDrawTarget,  bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height);
-#endif
     virtual void UpdateMouseThrough();
 
     void CacheAttributes();
 
     // instance variables.
     Halignment mHalign;
     Valignment mValign;
 
-#ifdef DEBUG_LAYOUT
-    static bool gDebug;
-    static nsIFrame* mDebugChild;
-#endif
-
 }; // class nsBoxFrame
 
 #endif
 
--- a/layout/xul/nsLeafBoxFrame.cpp
+++ b/layout/xul/nsLeafBoxFrame.cpp
@@ -36,25 +36,16 @@ using namespace mozilla;
 nsIFrame*
 NS_NewLeafBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle)
 {
   return new (aPresShell) nsLeafBoxFrame(aStyle);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame)
 
-#ifdef DEBUG_LAYOUT
-void
-nsLeafBoxFrame::GetBoxName(nsAutoString& aName)
-{
-   GetFrameName(aName);
-}
-#endif
-
-
 /**
  * Initialize us. This is a good time to get the alignment of the box
  */
 void
 nsLeafBoxFrame::Init(nsIContent*       aContent,
                      nsContainerFrame* aParent,
                      nsIFrame*         aPrevInFlow)
 {
--- a/layout/xul/nsLeafBoxFrame.h
+++ b/layout/xul/nsLeafBoxFrame.h
@@ -71,20 +71,16 @@ public:
                                     int32_t aModType) override;
 
   virtual bool ComputesOwnOverflowArea() override { return false; }
 
 protected:
 
   NS_IMETHOD DoXULLayout(nsBoxLayoutState& aState) override;
 
-#ifdef DEBUG_LAYOUT
-  virtual void GetBoxName(nsAutoString& aName) override;
-#endif
-
   virtual nscoord GetIntrinsicISize() override;
 
   explicit nsLeafBoxFrame(ComputedStyle* aStyle, ClassID aID = kClassID)
     : nsLeafFrame(aStyle, aID)
   {}
 
 private:
 
--- a/layout/xul/nsMenuFrame.cpp
+++ b/layout/xul/nsMenuFrame.cpp
@@ -764,53 +764,16 @@ nsMenuFrame::DoXULLayout(nsBoxLayoutStat
   if (popupFrame) {
     bool sizeToPopup = IsSizedToPopup(mContent, false);
     popupFrame->LayoutPopup(aState, this, GetAnchor()->GetPrimaryFrame(), sizeToPopup);
   }
 
   return rv;
 }
 
-#ifdef DEBUG_LAYOUT
-nsresult
-nsMenuFrame::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
-{
-  // see if our state matches the given debug state
-  bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
-  bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
-
-  // if it doesn't then tell each child below us the new debug state
-  if (debugChanged)
-  {
-      nsBoxFrame::SetXULDebug(aState, aDebug);
-      nsMenuPopupFrame* popupFrame = GetPopup();
-      if (popupFrame)
-        SetXULDebug(aState, popupFrame, aDebug);
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsMenuFrame::SetXULDebug(nsBoxLayoutState& aState, nsIFrame* aList, bool aDebug)
-{
-      if (!aList)
-          return NS_OK;
-
-      while (aList) {
-        if (aList->IsXULBoxFrame())
-          aList->SetXULDebug(aState, aDebug);
-
-        aList = aList->GetNextSibling();
-      }
-
-      return NS_OK;
-}
-#endif
-
 //
 // Enter
 //
 // Called when the user hits the <Enter>/<Return> keys or presses the
 // shortcut key. If this is a leaf item, the item's action will be executed.
 // In either case, do nothing if the item is disabled.
 //
 nsMenuFrame*
@@ -1329,21 +1292,16 @@ nsMenuFrame::RemoveFrame(ChildListID    
 void
 nsMenuFrame::InsertFrames(ChildListID     aListID,
                           nsIFrame*       aPrevFrame,
                           nsFrameList&    aFrameList)
 {
   if (!HasPopup() && (aListID == kPrincipalList || aListID == kPopupList)) {
     SetPopupFrame(aFrameList);
     if (HasPopup()) {
-#ifdef DEBUG_LAYOUT
-      nsBoxLayoutState state(PresContext());
-      SetXULDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
-#endif
-
       PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
 
   if (aFrameList.IsEmpty())
     return;
@@ -1357,21 +1315,16 @@ nsMenuFrame::InsertFrames(ChildListID   
 
 void
 nsMenuFrame::AppendFrames(ChildListID     aListID,
                           nsFrameList&    aFrameList)
 {
   if (!HasPopup() && (aListID == kPrincipalList || aListID == kPopupList)) {
     SetPopupFrame(aFrameList);
     if (HasPopup()) {
-
-#ifdef DEBUG_LAYOUT
-      nsBoxLayoutState state(PresContext());
-      SetXULDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
-#endif
       PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
 
   if (aFrameList.IsEmpty())
     return;
--- a/layout/xul/nsMenuFrame.h
+++ b/layout/xul/nsMenuFrame.h
@@ -94,20 +94,16 @@ public:
   NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
-#ifdef DEBUG_LAYOUT
-  virtual nsresult SetXULDebug(nsBoxLayoutState& aState, bool aDebug) override;
-#endif
-
   // The following methods are all overridden so that the menupopup
   // can be stored in a separate list, so that it doesn't impact reflow of the
   // actual menu item at all.
   virtual const nsFrameList& GetChildList(ChildListID aList) const override;
   virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
   virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
 
   // Overridden to prevent events from going to children of the menu.
@@ -269,19 +265,16 @@ protected:
   bool ShouldBlink();
   void StartBlinking(mozilla::WidgetGUIEvent* aEvent, bool aFlipChecked);
   void StopBlinking();
   void CreateMenuCommandEvent(mozilla::WidgetGUIEvent* aEvent,
                               bool aFlipChecked);
   void PassMenuCommandEventToPopupManager();
 
 protected:
-#ifdef DEBUG_LAYOUT
-  nsresult SetXULDebug(nsBoxLayoutState& aState, nsIFrame* aList, bool aDebug);
-#endif
   nsresult Notify(nsITimer* aTimer);
 
   bool mIsMenu; // Whether or not we can even have children or not.
   bool mChecked;              // are we checked?
   bool mIgnoreAccelTextChange; // temporarily set while determining the accelerator key
   bool mReflowCallbackPosted;
   nsMenuType mType;
 
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -485,25 +485,16 @@ nsSliderFrame::DoXULLayout(nsBoxLayoutSt
 
   if (!thumbBox) {
     SyncLayout(aState);
     return NS_OK;
   }
 
   EnsureOrient();
 
-#ifdef DEBUG_LAYOUT
-  if (mState & NS_STATE_DEBUG_WAS_SET) {
-      if (mState & NS_STATE_SET_TO_DEBUG)
-          SetXULDebug(aState, true);
-      else
-          SetXULDebug(aState, false);
-  }
-#endif
-
   // get the content area inside our borders
   nsRect clientRect;
   GetXULClientRect(clientRect);
 
   // get the scrollbar
   nsIFrame* scrollbarBox = GetScrollbar();
   nsCOMPtr<nsIContent> scrollbar = GetContentOfBox(scrollbarBox);
 
--- a/layout/xul/nsSprocketLayout.cpp
+++ b/layout/xul/nsSprocketLayout.cpp
@@ -20,23 +20,16 @@
 #include "nsContainerFrame.h"
 #include "nsBoxFrame.h"
 #include "StackArena.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 
 nsBoxLayout* nsSprocketLayout::gInstance = nullptr;
 
-//#define DEBUG_GROW
-
-#define DEBUG_SPRING_SIZE 8
-#define DEBUG_BORDER_SIZE 2
-#define COIL_SIZE 8
-
-
 nsresult
 NS_NewSprocketLayout(nsCOMPtr<nsBoxLayout>& aNewLayout)
 {
   if (!nsSprocketLayout::gInstance) {
     nsSprocketLayout::gInstance = new nsSprocketLayout();
     NS_IF_ADDREF(nsSprocketLayout::gInstance);
   }
   // we have not instance variables so just return our static one.
@@ -485,17 +478,16 @@ nsSprocketLayout::XULLayout(nsIFrame* aB
         child->XULLayout(aState);
 
       // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout.
       // We have to check for this.
       nsRect newChildRect(child->GetRect());
 
       if (!newChildRect.IsEqualInterior(childRect)) {
 #ifdef DEBUG_GROW
-        child->XULDumpBox(stdout);
         printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height);
 #endif
         newChildRect.Inflate(margin);
         childRect.Inflate(margin);
 
         // The child changed size during layout.  The ChildResized method handles this
         // scenario.
         ChildResized(aBox,
@@ -650,19 +642,16 @@ nsSprocketLayout::PopulateBoxSizes(nsIFr
   // used for the equal size flag
   nscoord biggestPrefWidth = 0;
   nscoord biggestMinWidth = 0;
   nscoord smallestMaxWidth = NS_INTRINSICSIZE;
 
   nsFrameState frameState = nsFrameState(0);
   GetFrameState(aBox, frameState);
 
-  //if (frameState & NS_STATE_CURRENTLY_IN_DEBUG)
-  //   printf("In debug\n");
-
   aMinSize = 0;
   aMaxSize = NS_INTRINSICSIZE;
 
   bool isHorizontal;
 
   if (IsXULHorizontal(aBox))
      isHorizontal = true;
   else
--- a/mozglue/misc/Mutex_posix.cpp
+++ b/mozglue/misc/Mutex_posix.cpp
@@ -1,34 +1,73 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/Assertions.h"
 
+#include <algorithm>
 #include <errno.h>
 #include <pthread.h>
 #include <stdio.h>
+#include <unistd.h>
 
 #include "mozilla/PlatformMutex.h"
 #include "MutexPlatformData_posix.h"
 
+#define REPORT_PTHREADS_ERROR(result, msg)      \
+  {                                             \
+    errno = result;                             \
+    perror(msg);                                \
+    MOZ_CRASH(msg);                             \
+  }
+
 #define TRY_CALL_PTHREADS(call, msg)            \
   {                                             \
     int result = (call);                        \
     if (result != 0) {                          \
-      errno = result;                           \
-      perror(msg);                              \
-      MOZ_CRASH(msg);                           \
+      REPORT_PTHREADS_ERROR(result, msg);       \
     }                                           \
   }
 
+#ifdef XP_DARWIN
+
+// CPU count. Read concurrently from multiple threads. Written once during the
+// first mutex initialization; re-initialization is safe hence relaxed ordering
+// is OK.
+static mozilla::Atomic<uint32_t, mozilla::MemoryOrdering::Relaxed> sCPUCount(0);
+
+static void
+EnsureCPUCount()
+{
+  if (sCPUCount) {
+    return;
+  }
+
+  // _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN are common, but not
+  // standard.
+#if defined(_SC_NPROCESSORS_CONF)
+  long n = sysconf(_SC_NPROCESSORS_CONF);
+  sCPUCount = (n > 0) ? uint32_t(n) : 1;
+#elif defined(_SC_NPROCESSORS_ONLN)
+  long n = sysconf(_SC_NPROCESSORS_ONLN);
+  sCPUCount = (n > 0) ? uint32_t(n) : 1;
+#else
+  sCPUCount = 1;
+#endif
+}
+
+#endif // XP_DARWIN
+
 mozilla::detail::MutexImpl::MutexImpl()
+#ifdef XP_DARWIN
+  : averageSpins(0)
+#endif
 {
   pthread_mutexattr_t* attrp = nullptr;
 
   // Linux with glibc and FreeBSD support adaptive mutexes that spin
   // for a short number of tries before sleeping.  NSPR's locks did
   // this, too, and it seems like a reasonable thing to do.
 #if (defined(__linux__) && defined(__GLIBC__)) || defined(__FreeBSD__)
 #define ADAPTIVE_MUTEX_SUPPORTED
@@ -55,29 +94,90 @@ mozilla::detail::MutexImpl::MutexImpl()
 
   TRY_CALL_PTHREADS(pthread_mutex_init(&platformData()->ptMutex, attrp),
                     "mozilla::detail::MutexImpl::MutexImpl: pthread_mutex_init failed");
 
 #if defined(ATTR_REQUIRED)
   TRY_CALL_PTHREADS(pthread_mutexattr_destroy(&attr),
                     "mozilla::detail::MutexImpl::MutexImpl: pthread_mutexattr_destroy failed");
 #endif
+
+#ifdef XP_DARWIN
+  EnsureCPUCount();
+#endif
 }
 
 mozilla::detail::MutexImpl::~MutexImpl()
 {
   TRY_CALL_PTHREADS(pthread_mutex_destroy(&platformData()->ptMutex),
                     "mozilla::detail::MutexImpl::~MutexImpl: pthread_mutex_destroy failed");
 }
 
+inline void
+mozilla::detail::MutexImpl::mutexLock()
+{
+  TRY_CALL_PTHREADS(pthread_mutex_lock(&platformData()->ptMutex),
+                    "mozilla::detail::MutexImpl::mutexLock: pthread_mutex_lock failed");
+}
+
+#ifdef XP_DARWIN
+inline bool
+mozilla::detail::MutexImpl::mutexTryLock()
+{
+  int result = pthread_mutex_trylock(&platformData()->ptMutex);
+  if (result == 0) {
+    return true;
+  }
+
+  if (result == EBUSY) {
+    return false;
+  }
+
+  REPORT_PTHREADS_ERROR(result,
+                        "mozilla::detail::MutexImpl::mutexTryLock: pthread_mutex_trylock failed");
+}
+#endif
+
 void
 mozilla::detail::MutexImpl::lock()
 {
-  TRY_CALL_PTHREADS(pthread_mutex_lock(&platformData()->ptMutex),
-                    "mozilla::detail::MutexImpl::lock: pthread_mutex_lock failed");
+#ifndef XP_DARWIN
+  mutexLock();
+#else
+  // Mutex performance on OSX can be very poor if there's a lot of contention as
+  // this causes excessive context switching. On Linux/FreeBSD we use the
+  // adaptive mutex type (PTHREAD_MUTEX_ADAPTIVE_NP) to address this, but this
+  // isn't available on OSX. The code below is a reimplementation of this
+  // feature.
+
+  MOZ_ASSERT(sCPUCount);
+  if (sCPUCount == 1) {
+    mutexLock();
+    return;
+  }
+
+  if (!mutexTryLock()) {
+    const int32_t SpinLimit = 100;
+
+    int32_t count = 0;
+    int32_t maxSpins = std::min(SpinLimit, 2 * averageSpins + 10);
+    do {
+      if (count >= maxSpins) {
+        mutexLock();
+        break;
+      }
+      asm("pause"); // Hint to the processor that we're spinning.
+      count++;
+    } while (!mutexTryLock());
+
+    // Update moving average.
+    averageSpins += (count - averageSpins) / 8;
+    MOZ_ASSERT(averageSpins >= 0 && averageSpins <= SpinLimit);
+  }
+#endif // XP_DARWIN
 }
 
 void
 mozilla::detail::MutexImpl::unlock()
 {
   TRY_CALL_PTHREADS(pthread_mutex_unlock(&platformData()->ptMutex),
                     "mozilla::detail::MutexImpl::unlock: pthread_mutex_unlock failed");
 }
--- a/mozglue/misc/PlatformMutex.h
+++ b/mozglue/misc/PlatformMutex.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef mozilla_PlatformMutex_h
 #define mozilla_PlatformMutex_h
 
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
 
 #if !defined(XP_WIN)
 # include <pthread.h>
 #endif
 
 namespace mozilla {
@@ -37,23 +38,34 @@ protected:
   MFBT_API void unlock();
 
 private:
   MutexImpl(const MutexImpl&) = delete;
   void operator=(const MutexImpl&) = delete;
   MutexImpl(MutexImpl&&) = delete;
   void operator=(MutexImpl&&) = delete;
 
+  void mutexLock();
+#ifdef XP_DARWIN
+  bool mutexTryLock();
+#endif
+
   PlatformData* platformData();
 
 #if !defined(XP_WIN)
   void* platformData_[sizeof(pthread_mutex_t) / sizeof(void*)];
   static_assert(sizeof(pthread_mutex_t) / sizeof(void*) != 0 &&
                 sizeof(pthread_mutex_t) % sizeof(void*) == 0,
                 "pthread_mutex_t must have pointer alignment");
+#ifdef XP_DARWIN
+  // Moving average of the number of spins it takes to acquire the mutex if we
+  // have to wait. May be accessed by multiple threads concurrently. Getting the
+  // latest value is not essential hence relaxed memory ordering is sufficient.
+  mozilla::Atomic<int32_t, mozilla::MemoryOrdering::Relaxed> averageSpins;
+#endif
 #else
   void* platformData_[6];
 #endif
 
   friend class mozilla::detail::ConditionVariableImpl;
 };
 
 } // namespace detail
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/beetmover-release-source-checksums/kind.yml
@@ -0,0 +1,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/.
+
+loader: taskgraph.loader.single_dep:loader
+
+transforms:
+   - taskgraph.transforms.name_sanity:transforms
+   - taskgraph.transforms.beetmover_source_checksums:transforms
+   - taskgraph.transforms.release_notifications:transforms
+   - taskgraph.transforms.task:transforms
+
+kind-dependencies:
+   - release-source-checksums-signing
+
+job-template:
+   shipping-phase: promote
--- a/taskcluster/ci/config.yml
+++ b/taskcluster/ci/config.yml
@@ -33,18 +33,20 @@ treeherder:
         'X': 'Xpcshell tests'
         'X-e10s': 'Xpcshell tests with e10s'
         'L10n': 'Localised Repacks'
         'L10n-Rpk': 'Localized Repackaged Repacks'
         'BM-L10n': 'Beetmover for locales'
         'BMR-L10n': 'Beetmover repackages for locales'
         'c-Up': 'Balrog submission of complete updates'
         'cs': 'Checksum signing'
+        'css': 'Checksum signing for source'
         'rs': 'Repackage signing'
-        'BMcs': 'Beetmover checksums,'
+        'BMcs': 'Beetmover checksums'
+        'BMcss': 'Beetmover checksums for source'
         'Aries': 'Aries Device Image'
         'Deb7': 'Packages for Debian 7'
         'Deb9': 'Packages for Debian 9'
         'Nexus 5-L': 'Nexus 5-L Device Image'
         'I': 'Docker Image Builds'
         'TL': 'Toolchain builds for Linux 64-bits'
         'TM': 'Toolchain builds for OSX'
         'TMW': 'Toolchain builds for Windows MinGW'
--- a/taskcluster/ci/post-beetmover-checksums-dummy/kind.yml
+++ b/taskcluster/ci/post-beetmover-checksums-dummy/kind.yml
@@ -6,16 +6,17 @@ loader: taskgraph.loader.transform:loade
 
 transforms:
    - taskgraph.transforms.reverse_chunk_deps:transforms
    - taskgraph.transforms.release_notifications:transforms
    - taskgraph.transforms.task:transforms
 
 kind-dependencies:
    - beetmover-checksums
+   - beetmover-release-source-checksums
 
 jobs:
    firefox-promote:
       name: post-beetmover-checksums-dummy
       description: Dummy task to deal with max_dependencies
       run-on-projects: []
       shipping-phase: promote
       shipping-product: firefox
--- a/taskcluster/ci/release-generate-checksums/kind.yml
+++ b/taskcluster/ci/release-generate-checksums/kind.yml
@@ -50,55 +50,55 @@ job-defaults:
       symbol: Rel(GenChcks)
       kind: test
       tier: 1
 
 jobs:
    firefox:
       shipping-product: firefox
       attributes:
-         build_platform: linux64
+         build_platform: firefox-release
          build_type: opt
       run:
          extra-config:
             by-project:
                mozilla-(release|beta):
                   stage_product: "firefox"
                   bucket_name: "net-mozaws-prod-delivery-firefox"
                default:
                   stage_product: "firefox"
                   bucket_name: "net-mozaws-stage-delivery-firefox"
       treeherder:
-         platform: linux64/opt
+         platform: firefox-release/opt
 
    fennec:
       shipping-product: fennec
       attributes:
-         build_platform: android-nightly
+         build_platform: fennec-release
          build_type: opt
       run:
          extra-config:
             by-project:
                mozilla-(release|beta):
                   stage_product: "mobile"
                   bucket_name: "net-mozaws-prod-delivery-archive"
                default:
                   stage_product: "mobile"
                   bucket_name: "net-mozaws-stage-delivery-archive"
       treeherder:
-         platform: Android/opt
+         platform: fennec-release/opt
 
    devedition:
       shipping-product: devedition
       attributes:
-         build_platform: linux64-devedition
+         build_platform: devedition-release
          build_type: opt
       run:
          extra-config:
             by-project:
                mozilla-beta:
                   stage_product: "devedition"
                   bucket_name: "net-mozaws-prod-delivery-archive"
                default:
                   stage_product: "devedition"
                   bucket_name: "net-mozaws-stage-delivery-archive"
       treeherder:
-         platform: linux64-devedition/opt
+         platform: devedition-release/opt
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/release-source-checksums-signing/kind.yml
@@ -0,0 +1,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/.
+
+loader: taskgraph.loader.single_dep:loader
+
+transforms:
+   - taskgraph.transforms.name_sanity:transforms
+   - taskgraph.transforms.source_checksums_signing:transforms
+   - taskgraph.transforms.release_notifications:transforms
+   - taskgraph.transforms.task:transforms
+
+kind-dependencies:
+   - beetmover-source
+
+job-template:
+   shipping-phase: promote
--- a/taskcluster/ci/release-source-signing/kind.yml
+++ b/taskcluster/ci/release-source-signing/kind.yml
@@ -1,13 +1,13 @@
 # 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/.
 
-loader: taskgraph.loader.build_signing:loader
+loader: taskgraph.loader.single_dep:loader
 
 transforms:
    - taskgraph.transforms.name_sanity:transforms
    - taskgraph.transforms.build_signing:transforms
    - taskgraph.transforms.signing:transforms
    - taskgraph.transforms.release_notifications:transforms
    - taskgraph.transforms.task:transforms
 
--- a/taskcluster/ci/release-source/kind.yml
+++ b/taskcluster/ci/release-source/kind.yml
@@ -1,46 +1,62 @@
 # 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/.
 
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
-   - toolchain
+    - toolchain
 
 transforms:
-   - taskgraph.transforms.build:transforms
-   - taskgraph.transforms.build_attrs:transforms
-   - taskgraph.transforms.build_lints:transforms
-   - taskgraph.transforms.use_toolchains:transforms
-   - taskgraph.transforms.release_notifications:transforms
-   - taskgraph.transforms.job:transforms
-   - taskgraph.transforms.task:transforms
+    - taskgraph.transforms.build:transforms
+    - taskgraph.transforms.build_attrs:transforms
+    - taskgraph.transforms.build_lints:transforms
+    - taskgraph.transforms.use_toolchains:transforms
+    - taskgraph.transforms.release_notifications:transforms
+    - taskgraph.transforms.job:transforms
+    - taskgraph.transforms.task:transforms
 
-jobs-from:
-   - source.yml
 
 job-defaults:
-   shipping-phase: promote
-   treeherder:
-      symbol: Src
-   worker-type: aws-provisioner-v1/gecko-{level}-b-linux
-   worker:
-      max-run-time: 3600
-      env:
-         TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/linux64/releng.manifest"
-         PKG_SRCPACK_BASENAME: source
-   run:
-      using: mozharness
-      actions: [package-source]
-      script: "mozharness/scripts/fx_desktop_build.py"
-      config:
-         - builds/releng_sub_linux_configs/64_source.py
-      options: []
-      tooltool-downloads: public
-      need-xvfb: false
-   run-on-projects: []
-   toolchains:
-      - linux64-clang
-      - linux64-gcc
-      - linux64-rust
-      - linux64-sccache
+    shipping-phase: promote
+    treeherder:
+        symbol: Src
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        max-run-time: 3600
+        env:
+            TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/linux64/releng.manifest"
+            PKG_SRCPACK_BASENAME: source
+    run:
+        using: mozharness
+        actions: [package-source]
+        script: "mozharness/scripts/fx_desktop_build.py"
+        config:
+            - builds/releng_sub_linux_configs/64_source.py
+        options: []
+        tooltool-downloads: public
+        need-xvfb: false
+    run-on-projects: []
+    # The build_attrs transform defaults to setting a `skip-unlles-schedules'
+    # optimization based on the task label. The tasks here don't have corresponding
+    # schedules defined in mozbuild.
+    optimization: {}
+
+jobs:
+    firefox-source/opt:
+        description: "Firefox source builder"
+        treeherder:
+            platform: firefox-release/opt
+        shipping-product: firefox
+
+    fennec-source/opt:
+        description: "Fennec source builder"
+        treeherder:
+            platform: fennec-release/opt
+        shipping-product: fennec
+
+    devedition-source/opt:
+        description: "Devedition source builder"
+        treeherder:
+            platform: devedition-release/opt
+        shipping-product: devedition
deleted file mode 100644
--- a/taskcluster/ci/release-source/source.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-linux64-source/opt:
-    description: "Firefox source builder"
-    treeherder:
-        platform: linux64/opt
-    shipping-product: firefox
-
-linux64-fennec-source/opt:
-    description: "Fennec source builder"
-    treeherder:
-        platform: android-api-16/opt
-    shipping-product: fennec
-
-linux64-devedition-source/opt:
-    description: "Devedition source builder"
-    treeherder:
-        platform: linux64-devedition-source/opt
-    shipping-product: devedition
--- a/taskcluster/docs/kinds.rst
+++ b/taskcluster/docs/kinds.rst
@@ -200,22 +200,34 @@ beetmover-source
 Beetmover-source publishes release source. This is part of release promotion.
 
 checksums-signing
 -----------------
 Checksums-signing take as input the checksums file generated by beetmover tasks
 and sign it via the signing scriptworkers. Returns the same file signed and
 additional detached signature.
 
+release-source-checksums-signing
+-------------------------------
+release-source-checksums-signing take as input the checksums file generated by
+source-related beetmover task and sign it via the signing scriptworkers.
+Returns the same file signed and additional detached signature.
+
 beetmover-checksums
 -------------------
 Beetmover, takes specific artifact checksums and pushes it to a location outside
 of Taskcluster's task artifacts (archive.mozilla.org as one place) and in the
 process determines the final location and "pretty" names it (version product name)
 
+beetmover-release-source-checksums
+---------------------------------
+Beetmover, takes source specific artifact checksums and pushes it to a location outside
+of Taskcluster's task artifacts (archive.mozilla.org as one place) and in the
+process determines the final location and "pretty" names it (version product name)
+
 google-play-strings
 -------------------
 Download strings to display on Google Play from https://l10n.mozilla-community.org/stores_l10n/.
 Artifact is then used by push-apk.
 
 push-apk
 --------
 PushApk publishes Android packages onto Google Play Store. Jobs of this kind take
--- a/taskcluster/taskgraph/transforms/beetmover.py
+++ b/taskcluster/taskgraph/transforms/beetmover.py
@@ -139,22 +139,16 @@ UPSTREAM_ARTIFACT_UNSIGNED_PATHS = {
     'linux64-asan-reporter-nightly':
         # ASan reporter builds don't generate the regular crashreporter symbol
         # packages, so we shouldn't try to beetmove them
         filter(lambda a: a != 'target.crashreporter-symbols.zip',
                _DESKTOP_UPSTREAM_ARTIFACTS_UNSIGNED_EN_US + [
                     "host/bin/mar",
                     "host/bin/mbsdiff",
                 ]),
-    'linux64-source': [
-    ],
-    'linux64-devedition-source': [
-    ],
-    'linux64-fennec-source': [
-    ],
     'android-x86-nightly': _MOBILE_UPSTREAM_ARTIFACTS_UNSIGNED_EN_US,
     'android-aarch64-nightly': _MOBILE_UPSTREAM_ARTIFACTS_UNSIGNED_EN_US,
     'android-api-16-nightly': _MOBILE_UPSTREAM_ARTIFACTS_UNSIGNED_EN_US,
     'macosx64-nightly': _DESKTOP_UPSTREAM_ARTIFACTS_UNSIGNED_EN_US + [
         "host/bin/mar",
         "host/bin/mbsdiff",
     ],
     'macosx64-devedition-nightly': _DESKTOP_UPSTREAM_ARTIFACTS_UNSIGNED_EN_US + [
@@ -212,28 +206,16 @@ UPSTREAM_ARTIFACT_SIGNED_PATHS = {
     'linux-devedition-nightly': _DESKTOP_UPSTREAM_ARTIFACTS_SIGNED_EN_US + [
         "target.tar.bz2",
         "target.tar.bz2.asc",
     ],
     'linux64-asan-reporter-nightly': _DESKTOP_UPSTREAM_ARTIFACTS_SIGNED_EN_US + [
         "target.tar.bz2",
         "target.tar.bz2.asc",
     ],
-    'linux64-source': [
-        "source.tar.xz",
-        "source.tar.xz.asc",
-    ],
-    'linux64-devedition-source': [
-        "source.tar.xz",
-        "source.tar.xz.asc",
-    ],
-    'linux64-fennec-source': [
-        "source.tar.xz",
-        "source.tar.xz.asc",
-    ],
     'android-x86-nightly': ["en-US/target.apk"],
     'android-aarch64-nightly': ["en-US/target.apk"],
     'android-api-16-nightly': ["en-US/target.apk"],
     'macosx64-nightly': _DESKTOP_UPSTREAM_ARTIFACTS_SIGNED_EN_US + [
         "target.dmg",
         "target.dmg.asc",
     ],
     'macosx64-devedition-nightly': _DESKTOP_UPSTREAM_ARTIFACTS_SIGNED_EN_US + [
@@ -289,16 +271,24 @@ UPSTREAM_ARTIFACT_SIGNED_PATHS = {
     'win64-nightly-l10n': _DESKTOP_UPSTREAM_ARTIFACTS_SIGNED_L10N + [
         "target.zip",
     ],
     'win64-devedition-nightly-l10n': _DESKTOP_UPSTREAM_ARTIFACTS_SIGNED_L10N + [
         "target.zip",
     ],
 
 }
+# Until bug 1331141 is fixed, if you are adding any new artifacts here that
+# need to be transfered to S3, please be aware you also need to follow-up
+# with a beetmover patch in https://github.com/mozilla-releng/beetmoverscript/.
+# See example in bug 1348286
+UPSTREAM_SOURCE_ARTIFACTS = [
+    "source.tar.xz",
+    "source.tar.xz.asc",
+]
 
 # Voluptuous uses marker objects as dictionary *keys*, but they are not
 # comparable, so we cast all of the keys back to regular strings
 task_description_schema = {str(k): v for k, v in task_description_schema.schema.iteritems()}
 
 transforms = TransformSequence()
 
 # shortcut for a string where task references are allowed
@@ -401,16 +391,27 @@ def generate_upstream_artifacts(job, sig
     build_mapping = UPSTREAM_ARTIFACT_UNSIGNED_PATHS
     signing_mapping = UPSTREAM_ARTIFACT_SIGNED_PATHS
 
     artifact_prefix = get_artifact_prefix(job)
     if locale:
         artifact_prefix = '{}/{}'.format(artifact_prefix, locale)
         platform = "{}-l10n".format(platform)
 
+    if platform.endswith("-source"):
+        return [
+            {
+                "taskId": {"task-reference": signing_task_ref},
+                "taskType": "signing",
+                "paths": ["{}/{}".format(artifact_prefix, p)
+                          for p in UPSTREAM_SOURCE_ARTIFACTS],
+                "locale": locale or "en-US",
+            }
+        ]
+
     upstream_artifacts = []
 
     # Some platforms (like android-api-16-nightly-l10n) may not depend on any unsigned artifact
     if build_mapping[platform]:
         upstream_artifacts.append({
             "taskId": {"task-reference": build_task_ref},
             "taskType": "build",
             "paths": ["{}/{}".format(artifact_prefix, p)
@@ -445,21 +446,18 @@ def generate_upstream_artifacts(job, sig
 
     return upstream_artifacts
 
 
 def craft_release_properties(config, job):
     params = config.params
     build_platform = job['attributes']['build_platform']
     build_platform = build_platform.replace('-nightly', '')
-    if 'fennec-source' in build_platform:
-        # XXX This case is hardcoded to match the current implementation in beetmover
-        build_platform = 'android-api-16'
-    else:
-        build_platform = build_platform.replace('-source', '')
+    if build_platform.endswith("-source"):
+        build_platform = build_platform.replace('-source', '-release')
 
     # XXX This should be explicitly set via build attributes or something
     if 'android' in job['label'] or 'fennec' in job['label']:
         app_name = 'Fennec'
     elif config.graph_config['trust-domain'] == 'comm':
         app_name = 'Thunderbird'
     else:
         # XXX Even DevEdition is called Firefox
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/transforms/beetmover_source_checksums.py
@@ -0,0 +1,166 @@
+# 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/.
+"""
+Transform beetmover-release-source-checksums task into an actual task description.
+"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from taskgraph.transforms.base import TransformSequence
+from taskgraph.transforms.beetmover import craft_release_properties
+from taskgraph.util.attributes import copy_attributes_from_dependent_job
+from taskgraph.util.schema import validate_schema, Schema
+from taskgraph.util.scriptworker import (get_beetmover_bucket_scope,
+                                         get_beetmover_action_scope,
+                                         get_worker_type_for_scope)
+from taskgraph.transforms.task import task_description_schema
+from voluptuous import Any, Required, Optional
+
+# Voluptuous uses marker objects as dictionary *keys*, but they are not
+# comparable, so we cast all of the keys back to regular strings
+task_description_schema = {str(k): v for k, v in task_description_schema.schema.iteritems()}
+
+transforms = TransformSequence()
+
+taskref_or_string = Any(
+    basestring,
+    {Required('task-reference'): basestring})
+
+beetmover_checksums_description_schema = Schema({
+    Required('dependent-task'): object,
+    Required('depname', default='build'): basestring,
+    Optional('label'): basestring,
+    Optional('treeherder'): task_description_schema['treeherder'],
+    Optional('locale'): basestring,
+    Optional('shipping-phase'): task_description_schema['shipping-phase'],
+    Optional('shipping-product'): task_description_schema['shipping-product'],
+})
+
+
+@transforms.add
+def validate(config, jobs):
+    for job in jobs:
+        label = job.get('dependent-task', object).__dict__.get('label', '?no-label?')
+        validate_schema(
+            beetmover_checksums_description_schema, job,
+            "In checksums-signing ({!r} kind) task for {!r}:".format(config.kind, label))
+        yield job
+
+
+@transforms.add
+def make_beetmover_checksums_description(config, jobs):
+    for job in jobs:
+        dep_job = job['dependent-task']
+        attributes = dep_job.attributes
+
+        treeherder = job.get('treeherder', {})
+        treeherder.setdefault('symbol', 'BMcss(N)')
+        dep_th_platform = dep_job.task.get('extra', {}).get(
+            'treeherder', {}).get('machine', {}).get('platform', '')
+        treeherder.setdefault('platform',
+                              "{}/opt".format(dep_th_platform))
+        treeherder.setdefault('tier', 1)
+        treeherder.setdefault('kind', 'build')
+
+        label = job['label']
+        build_platform = attributes.get('build_platform')
+
+        description = "Beetmover submission of checksums for source file"
+
+        extra = {}
+        if build_platform.startswith("android"):
+            extra['product'] = 'fennec'
+        elif 'devedition' in build_platform:
+            extra['product'] = 'devedition'
+        else:
+            extra['product'] = 'firefox'
+
+        dependent_kind = str(dep_job.kind)
+        dependencies = {dependent_kind: dep_job.label}
+        for k, v in dep_job.dependencies.items():
+            if k.startswith('beetmover'):
+                dependencies[k] = v
+
+        attributes = copy_attributes_from_dependent_job(dep_job)
+
+        bucket_scope = get_beetmover_bucket_scope(config)
+        action_scope = get_beetmover_action_scope(config)
+
+        task = {
+            'label': label,
+            'description': description,
+            'worker-type': get_worker_type_for_scope(config, bucket_scope),
+            'scopes': [bucket_scope, action_scope],
+            'dependencies': dependencies,
+            'attributes': attributes,
+            'run-on-projects': dep_job.attributes.get('run_on_projects'),
+            'treeherder': treeherder,
+            'extra': extra,
+        }
+
+        if 'shipping-phase' in job:
+            task['shipping-phase'] = job['shipping-phase']
+
+        if 'shipping-product' in job:
+            task['shipping-product'] = job['shipping-product']
+
+        yield task
+
+
+def generate_upstream_artifacts(refs, platform, locale=None):
+    # Until bug 1331141 is fixed, if you are adding any new artifacts here that
+    # need to be transfered to S3, please be aware you also need to follow-up
+    # with a beetmover patch in https://github.com/mozilla-releng/beetmoverscript/.
+    # See example in bug 1348286
+    common_paths = [
+        "public/target-source.checksums",
+        "public/target-source.checksums.asc",
+    ]
+
+    upstream_artifacts = [{
+        "taskId": {"task-reference": refs["signing"]},
+        "taskType": "signing",
+        "paths": common_paths,
+        "locale": locale or "en-US",
+    }]
+
+    return upstream_artifacts
+
+
+@transforms.add
+def make_beetmover_checksums_worker(config, jobs):
+    for job in jobs:
+        valid_beetmover_job = (len(job["dependencies"]) == 2)
+        if not valid_beetmover_job:
+            raise NotImplementedError("Beetmover checksums must have two dependencies.")
+
+        locale = job["attributes"].get("locale")
+        platform = job["attributes"]["build_platform"]
+
+        refs = {
+            "beetmover": None,
+            "signing": None,
+        }
+        for dependency in job["dependencies"].keys():
+            if dependency.startswith("beetmover"):
+                refs['beetmover'] = "<{}>".format(dependency)
+            else:
+                refs['signing'] = "<{}>".format(dependency)
+        if None in refs.values():
+            raise NotImplementedError(
+                "Beetmover checksums must have a beetmover and signing dependency!")
+
+        worker = {
+            'implementation': 'beetmover',
+            'release-properties': craft_release_properties(config, job),
+            'upstream-artifacts': generate_upstream_artifacts(
+                refs, platform, locale
+            ),
+        }
+
+        if locale:
+            worker["locale"] = locale
+        job["worker"] = worker
+
+        yield job
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/transforms/source_checksums_signing.py
@@ -0,0 +1,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/.
+"""
+Transform the checksums signing task into an actual task description.
+"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from taskgraph.transforms.base import TransformSequence
+from taskgraph.util.attributes import copy_attributes_from_dependent_job
+from taskgraph.util.schema import validate_schema, Schema
+from taskgraph.util.scriptworker import (
+    get_signing_cert_scope,
+    get_worker_type_for_scope,
+)
+from taskgraph.transforms.task import task_description_schema
+from voluptuous import Any, Required, Optional
+
+# Voluptuous uses marker objects as dictionary *keys*, but they are not
+# comparable, so we cast all of the keys back to regular strings
+task_description_schema = {str(k): v for k, v in task_description_schema.schema.iteritems()}
+
+transforms = TransformSequence()
+
+taskref_or_string = Any(
+    basestring,
+    {Required('task-reference'): basestring})
+
+checksums_signing_description_schema = Schema({
+    Required('dependent-task'): object,
+    Required('depname', default='beetmover'): basestring,
+    Optional('label'): basestring,
+    Optional('treeherder'): task_description_schema['treeherder'],
+    Optional('shipping-product'): task_description_schema['shipping-product'],
+    Optional('shipping-phase'): task_description_schema['shipping-phase'],
+})
+
+
+@transforms.add
+def validate(config, jobs):
+    for job in jobs:
+        label = job.get('dependent-task', object).__dict__.get('label', '?no-label?')
+        validate_schema(
+            checksums_signing_description_schema, job,
+            "In checksums-signing ({!r} kind) task for {!r}:".format(config.kind, label))
+        yield job
+
+
+@transforms.add
+def make_checksums_signing_description(config, jobs):
+    for job in jobs:
+        dep_job = job['dependent-task']
+        attributes = dep_job.attributes
+
+        treeherder = job.get('treeherder', {})
+        treeherder.setdefault('symbol', 'css(N)')
+        dep_th_platform = dep_job.task.get('extra', {}).get(
+            'treeherder', {}).get('machine', {}).get('platform', '')
+        treeherder.setdefault('platform',
+                              "{}/opt".format(dep_th_platform))
+        treeherder.setdefault('tier', 1)
+        treeherder.setdefault('kind', 'build')
+
+        label = job['label']
+        description = "Signing of release-source checksums file"
+        dependencies = {"beetmover": dep_job.label}
+
+        attributes = copy_attributes_from_dependent_job(dep_job)
+
+        upstream_artifacts = [{
+            "taskId": {"task-reference": "<beetmover>"},
+            "taskType": "beetmover",
+            "paths": [
+                "public/target-source.checksums",
+            ],
+            "formats": ["gpg"]
+        }]
+
+        signing_cert_scope = get_signing_cert_scope(config)
+
+        task = {
+            'label': label,
+            'description': description,
+            'worker-type': get_worker_type_for_scope(config, signing_cert_scope),
+            'worker': {'implementation': 'scriptworker-signing',
+                       'upstream-artifacts': upstream_artifacts,
+                       'max-run-time': 3600},
+            'scopes': [
+                signing_cert_scope,
+                "project:releng:signing:format:gpg"
+            ],
+            'dependencies': dependencies,
+            'attributes': attributes,
+            'run-on-projects': dep_job.attributes.get('run_on_projects'),
+            'treeherder': treeherder,
+        }
+
+        yield task
--- a/taskcluster/taskgraph/util/scriptworker.py
+++ b/taskcluster/taskgraph/util/scriptworker.py
@@ -440,17 +440,17 @@ def get_release_config(config):
     release_config['next_version'] = str(config.params['next_version'])
     release_config['build_number'] = config.params['build_number']
     return release_config
 
 
 def get_signing_cert_scope_per_platform(build_platform, is_nightly, config):
     if 'devedition' in build_platform:
         return get_devedition_signing_cert_scope(config)
-    elif is_nightly or build_platform in ('linux64-source', 'linux64-fennec-source'):
+    elif is_nightly or build_platform in ('firefox-source', 'fennec-source'):
         return get_signing_cert_scope(config)
     else:
         return add_scope_prefix(config, 'signing:cert:dep-signing')
 
 
 def get_worker_type_for_scope(config, scope):
     """Get the scriptworker type that will accept the given scope.
 
--- a/testing/talos/talos/tests/devtools/addon/content/tests/head.js
+++ b/testing/talos/talos/tests/devtools/addon/content/tests/head.js
@@ -44,17 +44,17 @@ exports.testSetup = function(url) {
   return damp.testSetup(url);
 };
 
 exports.testTeardown = function() {
   return damp.testTeardown();
 };
 
 exports.logTestResult = function(name, value) {
-  damp._results.push(name, value);
+  damp._results.push({ name, value });
 };
 
 function getBrowserWindow() {
   return Services.wm.getMostRecentWindow("navigator:browser");
 }
 exports.getBrowserWindow = getBrowserWindow;
 
 function getActiveTab() {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/CSS2/backgrounds/background-root-010.xht.ini
@@ -0,0 +1,3 @@
+[background-root-010.xht]
+  disabled:
+    if webrender: bug 1453935
--- a/testing/web-platform/meta/css/CSS2/backgrounds/background-root-016.xht.ini
+++ b/testing/web-platform/meta/css/CSS2/backgrounds/background-root-016.xht.ini
@@ -1,4 +1,3 @@
 [background-root-016.xht]
-  expected:
-    if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL
-    if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL
+  disabled:
+    if webrender: bug 1453935
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -445,16 +445,17 @@ var snapshotFormatters = {
     addRowFromKey("features", "webgl2WSIInfo");
     addRowFromKey("features", "webgl2Renderer");
     addRowFromKey("features", "webgl2Version");
     addRowFromKey("features", "webgl2DriverExtensions");
     addRowFromKey("features", "webgl2Extensions");
     addRowFromKey("features", "supportsHardwareH264", "hardwareH264");
     addRowFromKey("features", "direct2DEnabled", "#Direct2D");
     addRowFromKey("features", "usesTiling");
+    addRowFromKey("features", "contentUsesTiling");
     addRowFromKey("features", "offMainThreadPaintEnabled");
     addRowFromKey("features", "offMainThreadPaintWorkerCount");
 
     if ("directWriteEnabled" in data) {
       let message = data.directWriteEnabled;
       if ("directWriteVersion" in data)
         message += " (" + data.directWriteVersion + ")";
       addRow("features", "#DirectWrite", message);
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1243,17 +1243,17 @@
             // autoscrolling on. So instead we do the same math as Gecko.
             const scaleFactor = 60 / Math.round(60 / screen.defaultCSSScaleFactor);
             let minX = left.value / scaleFactor + 0.5 * POPUP_SIZE;
             let maxX = (left.value + width.value) / scaleFactor - 0.5 * POPUP_SIZE;
             let minY = top.value / scaleFactor + 0.5 * POPUP_SIZE;
             let maxY = (top.value + height.value) / scaleFactor - 0.5 * POPUP_SIZE;
             let popupX = Math.max(minX, Math.min(maxX, screenX));
             let popupY = Math.max(minY, Math.min(maxY, screenY));
-            this._autoScrollPopup.openPopup(null, "after_start", popupX, popupY);
+            this._autoScrollPopup.openPopupAtScreen(popupX, popupY);
             this._ignoreMouseEvents = true;
             this._scrolling = true;
             this._startX = screenX;
             this._startY = screenY;
 
             window.addEventListener("mousemove", this, true);
             window.addEventListener("mousedown", this, true);
             window.addEventListener("mouseup", this, true);
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.properties
@@ -96,16 +96,17 @@ unknownFailure = Blocklisted; failure co
 d3d11layersCrashGuard = D3D11 Compositor
 d3d11videoCrashGuard = D3D11 Video Decoder
 d3d9videoCrashGuard = D3D9 Video Decoder
 glcontextCrashGuard = OpenGL
 resetOnNextRestart = Reset on Next Restart
 gpuProcessKillButton = Terminate GPU Process
 gpuDeviceResetButton = Trigger Device Reset
 usesTiling = Uses Tiling
+contentUsesTiling = Uses Tiling (Content)
 offMainThreadPaintEnabled = Off Main Thread Painting Enabled
 offMainThreadPaintWorkerCount = Off Main Thread Painting Worker Count
 
 audioBackend = Audio Backend
 maxAudioChannels = Max Channels
 channelLayout = Preferred Channel Layout
 sampleRate = Preferred Sample Rate
 
--- a/toolkit/modules/Troubleshoot.jsm
+++ b/toolkit/modules/Troubleshoot.jsm
@@ -419,16 +419,17 @@ var dataProviders = {
       adapterDriverDate2: "driverDate2",
       isGPU2Active: null,
 
       D2DEnabled: "direct2DEnabled",
       DWriteEnabled: "directWriteEnabled",
       DWriteVersion: "directWriteVersion",
       cleartypeParameters: "clearTypeParameters",
       UsesTiling: "usesTiling",
+      ContentUsesTiling: "contentUsesTiling",
       OffMainThreadPaintEnabled: "offMainThreadPaintEnabled",
       OffMainThreadPaintWorkerCount: "offMainThreadPaintWorkerCount",
     };
 
     for (let prop in gfxInfoProps) {
       try {
         data[gfxInfoProps[prop] || prop] = gfxInfo[prop];
       } catch (e) {}
--- a/toolkit/modules/tests/browser/browser_Troubleshoot.js
+++ b/toolkit/modules/tests/browser/browser_Troubleshoot.js
@@ -343,16 +343,19 @@ const SNAPSHOT_SCHEMA = {
           type: "boolean",
         },
         directWriteVersion: {
           type: "string",
         },
         usesTiling: {
           type: "boolean",
         },
+        contentUsesTiling: {
+          type: "boolean",
+        },
         offMainThreadPaintEnabled: {
           type: "boolean",
         },
         offMainThreadPaintWorkerCount: {
           type: "number",
         },
         clearTypeParameters: {
           type: "string",
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -1476,16 +1476,23 @@ GfxInfoBase::GetWebRenderEnabled(bool* a
 NS_IMETHODIMP
 GfxInfoBase::GetUsesTiling(bool* aUsesTiling)
 {
   *aUsesTiling = gfxPlatform::GetPlatform()->UsesTiling();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+GfxInfoBase::GetContentUsesTiling(bool* aUsesTiling)
+{
+  *aUsesTiling = gfxPlatform::GetPlatform()->ContentUsesTiling();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 GfxInfoBase::GetOffMainThreadPaintEnabled(bool* aOffMainThreadPaintEnabled)
 {
   *aOffMainThreadPaintEnabled = gfxConfig::IsEnabled(Feature::OMTP);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GfxInfoBase::GetOffMainThreadPaintWorkerCount(int32_t* aOffMainThreadPaintWorkerCount)
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -57,16 +57,17 @@ public:
   NS_IMETHOD GetFeatures(JSContext*, JS::MutableHandle<JS::Value>) override;
   NS_IMETHOD GetFeatureLog(JSContext*, JS::MutableHandle<JS::Value>) override;
   NS_IMETHOD GetActiveCrashGuards(JSContext*, JS::MutableHandle<JS::Value>) override;
   NS_IMETHOD GetContentBackend(nsAString & aContentBackend) override;
   NS_IMETHOD GetUsingGPUProcess(bool *aOutValue) override;
   NS_IMETHOD GetWebRenderEnabled(bool* aWebRenderEnabled) override;
   NS_IMETHOD GetIsHeadless(bool* aIsHeadless) override;
   NS_IMETHOD GetUsesTiling(bool* aUsesTiling) override;
+  NS_IMETHOD GetContentUsesTiling(bool* aUsesTiling) override;
   NS_IMETHOD GetOffMainThreadPaintEnabled(bool* aOffMainThreadPaintEnabled) override;
   NS_IMETHOD GetOffMainThreadPaintWorkerCount(int32_t* aOffMainThreadPaintWorkerCount) override;
 
   // Initialization function. If you override this, you must call this class's
   // version of Init first.
   // We need Init to be called separately from the constructor so we can
   // register as an observer after all derived classes have been constructed
   // and we know we have a non-zero refcount.
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -21,16 +21,17 @@ interface nsIGfxInfo : nsISupports
 
   /*
    * These are valid across all platforms.
    */
   readonly attribute DOMString ContentBackend;
   readonly attribute boolean WebRenderEnabled;
   readonly attribute boolean isHeadless;
   readonly attribute boolean UsesTiling;
+  readonly attribute boolean ContentUsesTiling;
   readonly attribute boolean OffMainThreadPaintEnabled;
   readonly attribute long OffMainThreadPaintWorkerCount;
 
   // XXX: Switch to a list of devices, rather than explicitly numbering them.
 
   /**
    * The name of the display adapter.
    */