merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Thu, 12 Oct 2017 23:58:31 +0200
changeset 385860 25aad10380b10b6efa50c2b4d97245f078d870a0
parent 385822 46a75c66bb512d652dd883435afe242c22be9ac3 (current diff)
parent 385859 1f4d35d137631cde34f318fac0c33421d5360dc3 (diff)
child 385861 6bcef82b2f30e242d55ac951fe5c1e78a4930dfb
child 385956 1b6a3e8b08935eddd2291d8c1fb83a70dd5e7e47
child 386027 782e1972037f3830bd04cf70ac529969bb796a56
push id32669
push userarchaeopteryx@coole-files.de
push dateThu, 12 Oct 2017 21:58:56 +0000
treeherdermozilla-central@25aad10380b1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
25aad10380b1 / 58.0a1 / 20171012220111 / files
nightly linux64
25aad10380b1 / 58.0a1 / 20171012220111 / files
nightly mac
25aad10380b1 / 58.0a1 / 20171012220111 / files
nightly win32
25aad10380b1 / 58.0a1 / 20171012220111 / files
nightly win64
25aad10380b1 / 58.0a1 / 20171012220111 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: AlcL6XYDkf
build/pgo/profileserver.py
modules/libpref/init/all.js
new file mode 100644
--- /dev/null
+++ b/build/pgo/prefs_override.js
@@ -0,0 +1,2 @@
+// Turn off budget throttling for the profile server
+user_pref("dom.timeout.enable_budget_timer_throttling", false);
old mode 100644
new mode 100755
--- a/build/pgo/profileserver.py
+++ b/build/pgo/profileserver.py
@@ -40,23 +40,29 @@ if __name__ == '__main__':
     locations.add_host(host='127.0.0.1',
                        port=PORT,
                        options='primary,privileged')
 
     with TemporaryDirectory() as profilePath:
         # TODO: refactor this into mozprofile
         prefpath = os.path.join(
             build.topsrcdir, "testing", "profiles", "prefs_general.js")
+        overridepath = os.path.join(
+            build.topsrcdir, "build", "pgo", "prefs_override.js")
+
         prefs = {}
         prefs.update(Preferences.read_prefs(prefpath))
+        prefs.update(Preferences.read_prefs(overridepath))
+
         interpolation = {"server": "%s:%d" % httpd.httpd.server_address,
                          "OOP": "false"}
         prefs = json.loads(json.dumps(prefs) % interpolation)
         for pref in prefs:
             prefs[pref] = Preferences.cast(prefs[pref])
+
         profile = FirefoxProfile(profile=profilePath,
                                  preferences=prefs,
                                  addons=[os.path.join(
                                      build.topsrcdir, 'tools', 'quitter', 'quitter@mozilla.org.xpi')],
                                  locations=locations)
 
         env = os.environ.copy()
         env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -5,16 +5,20 @@
 
 #include "ChromeUtils.h"
 
 #include "jsfriendapi.h"
 #include "WrapperFactory.h"
 
 #include "mozilla/Base64.h"
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/dom/IdleDeadline.h"
+#include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
+#include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 /* static */ void
 ThreadSafeChromeUtils::NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
                                                       JS::Handle<JS::Value> aMap,
                                                       JS::MutableHandle<JS::Value> aRetval,
@@ -259,16 +263,119 @@ ChromeUtils::ShallowClone(GlobalObject& 
   if (aTarget && !JS_WrapObject(cx, &obj)) {
     return;
   }
 
   cleanup.release();
   aRetval.set(obj);
 }
 
+namespace {
+  class IdleDispatchRunnable final : public IdleRunnable
+                                   , public nsITimerCallback
+  {
+  public:
+    NS_DECL_ISUPPORTS_INHERITED
+
+    IdleDispatchRunnable(nsIGlobalObject* aParent,
+                         IdleRequestCallback& aCallback)
+      : IdleRunnable("ChromeUtils::IdleDispatch")
+      , mCallback(&aCallback)
+      , mParent(aParent)
+    {}
+
+    NS_IMETHOD Run() override
+    {
+      if (mCallback) {
+        CancelTimer();
+
+        auto deadline = mDeadline - TimeStamp::ProcessCreation();
+
+        ErrorResult rv;
+        RefPtr<IdleDeadline> idleDeadline =
+          new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
+
+        mCallback->Call(*idleDeadline, rv, "ChromeUtils::IdleDispatch handler");
+        mCallback = nullptr;
+        mParent = nullptr;
+
+        rv.SuppressException();
+        return rv.StealNSResult();
+      }
+      return NS_OK;
+    }
+
+    void SetDeadline(TimeStamp aDeadline) override
+    {
+      mDeadline = aDeadline;
+    }
+
+    NS_IMETHOD Notify(nsITimer* aTimer) override
+    {
+      mTimedOut = true;
+      SetDeadline(TimeStamp::Now());
+      return Run();
+    }
+
+    void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
+    {
+      MOZ_ASSERT(aTarget);
+      MOZ_ASSERT(!mTimer);
+      mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+      if (mTimer) {
+        mTimer->SetTarget(aTarget);
+        mTimer->InitWithCallback(this, aDelay, nsITimer::TYPE_ONE_SHOT);
+      }
+    }
+
+  protected:
+    virtual ~IdleDispatchRunnable()
+    {
+      CancelTimer();
+    }
+
+  private:
+    void CancelTimer()
+    {
+      if (mTimer) {
+        mTimer->Cancel();
+        mTimer = nullptr;
+      }
+    }
+
+    RefPtr<IdleRequestCallback> mCallback;
+    nsCOMPtr<nsIGlobalObject> mParent;
+
+    nsCOMPtr<nsITimer> mTimer;
+
+    TimeStamp mDeadline{};
+    bool mTimedOut = false;
+  };
+
+  NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable, nsITimerCallback)
+} // anonymous namespace
+
+/* static */ void
+ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
+                          IdleRequestCallback& aCallback,
+                          const IdleRequestOptions& aOptions,
+                          ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+  MOZ_ASSERT(global);
+
+  auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
+
+  if (aOptions.mTimeout.WasPassed()) {
+    aRv = NS_IdleDispatchToCurrentThread(runnable.forget(), aOptions.mTimeout.Value());
+  } else {
+    aRv = NS_IdleDispatchToCurrentThread(runnable.forget());
+  }
+}
+
 /* static */ void
 ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
                                       const dom::OriginAttributesDictionary& aAttrs,
                                       nsCString& aSuffix)
 
 {
   OriginAttributes attrs(aAttrs);
   attrs.CreateSuffix(aSuffix);
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -16,16 +16,18 @@ namespace mozilla {
 
 namespace devtools {
 class HeapSnapshot;
 } // namespace devtools
 
 namespace dom {
 
 class ArrayBufferViewOrArrayBuffer;
+class IdleRequestCallback;
+struct IdleRequestOptions;
 class PrecompiledScript;
 class Promise;
 
 class ThreadSafeChromeUtils
 {
 private:
   // Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
   static void SaveHeapSnapshotShared(GlobalObject& global,
@@ -140,14 +142,19 @@ public:
                            bool aUnwrap,
                            nsAString& aRetval);
 
   static void ShallowClone(GlobalObject& aGlobal,
                            JS::HandleObject aObj,
                            JS::HandleObject aTarget,
                            JS::MutableHandleObject aRetval,
                            ErrorResult& aRv);
+
+  static void IdleDispatch(const GlobalObject& global,
+                           IdleRequestCallback& callback,
+                           const IdleRequestOptions& options,
+                           ErrorResult& aRv);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ChromeUtils__
--- a/dom/base/IdleDeadline.cpp
+++ b/dom/base/IdleDeadline.cpp
@@ -12,30 +12,41 @@
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(IdleDeadline, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(IdleDeadline, mWindow, mGlobal)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleDeadline)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleDeadline)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleDeadline)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 IdleDeadline::IdleDeadline(nsPIDOMWindowInner* aWindow, bool aDidTimeout,
                            DOMHighResTimeStamp aDeadline)
   : mWindow(aWindow)
   , mDidTimeout(aDidTimeout)
   , mDeadline(aDeadline)
 {
+  bool hasHadSHO;
+  mGlobal = aWindow->GetDoc()->GetScriptHandlingObject(hasHadSHO);
+}
+
+IdleDeadline::IdleDeadline(nsIGlobalObject* aGlobal, bool aDidTimeout,
+                           DOMHighResTimeStamp aDeadline)
+  : mWindow(nullptr)
+  , mGlobal(aGlobal)
+  , mDidTimeout(aDidTimeout)
+  , mDeadline(aDeadline)
+{
 }
 
 IdleDeadline::~IdleDeadline()
 {
 }
 
 JSObject*
 IdleDeadline::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
@@ -45,24 +56,31 @@ IdleDeadline::WrapObject(JSContext* aCx,
 
 DOMHighResTimeStamp
 IdleDeadline::TimeRemaining()
 {
   if (mDidTimeout) {
     return 0.0;
   }
 
-  RefPtr<Performance> performance = mWindow->GetPerformance();
-  if (!performance) {
-    // If there is no performance object the window is partially torn
-    // down, so we can safely say that there is no time remaining.
-    return 0.0;
+  if (mWindow) {
+    RefPtr<Performance> performance = mWindow->GetPerformance();
+    if (!performance) {
+      // If there is no performance object the window is partially torn
+      // down, so we can safely say that there is no time remaining.
+      return 0.0;
+    }
+
+    return std::max(mDeadline - performance->Now(), 0.0);
   }
 
-  return std::max(mDeadline - performance->Now(), 0.0);
+  // If there's no window, we're in a system scope, and can just use
+  // a high-resolution TimeStamp::Now();
+  auto timestamp = TimeStamp::Now() - TimeStamp::ProcessCreation();
+  return std::max(mDeadline - timestamp.ToMilliseconds(), 0.0);
 }
 
 bool
 IdleDeadline::DidTimeout() const
 {
   return mDidTimeout;
 }
 
--- a/dom/base/IdleDeadline.h
+++ b/dom/base/IdleDeadline.h
@@ -12,44 +12,49 @@
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsWrapperCache.h"
 
+class nsIGlobalObject;
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class IdleDeadline final
   : public nsISupports
   , public nsWrapperCache
 {
 public:
   IdleDeadline(nsPIDOMWindowInner* aWindow, bool aDidTimeout,
                DOMHighResTimeStamp aDeadline);
 
-  nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
+  IdleDeadline(nsIGlobalObject* aGlobal, bool aDidTimeout,
+               DOMHighResTimeStamp aDeadline);
+
+  nsIGlobalObject* GetParentObject() const { return mGlobal; }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   DOMHighResTimeStamp TimeRemaining();
   bool DidTimeout() const;
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IdleDeadline)
 
 private:
   ~IdleDeadline();
 
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  nsCOMPtr<nsIGlobalObject> mGlobal;
   const bool mDidTimeout;
   const DOMHighResTimeStamp mDeadline;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_IdleDeadline_h
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1661,28 +1661,27 @@ WebSocketImpl::Init(JSContext* aCx,
       nsCOMPtr<nsIGlobalObject> globalObject(GetEntryGlobal());
       if (globalObject) {
         principal = globalObject->PrincipalOrNull();
       }
 
       nsCOMPtr<nsPIDOMWindowInner> innerWindow;
 
       while (true) {
-        if (principal) {
-          bool isNullPrincipal = true;
-          isNullPrincipal = principal->GetIsNullPrincipal();
-          if (isNullPrincipal || nsContentUtils::IsSystemPrincipal(principal)) {
-            break;
-          }
+        if (principal && !principal->GetIsNullPrincipal()) {
+          break;
         }
 
         if (!innerWindow) {
           innerWindow = do_QueryInterface(globalObject);
-          if (NS_WARN_IF(!innerWindow)) {
-            return NS_ERROR_DOM_SECURITY_ERR;
+          if (!innerWindow) {
+            // If we are in a XPConnect sandbox or in a JS component,
+            // innerWindow will be null. There is nothing on top of this to be
+            // considered.
+            break;
           }
         }
 
         nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
           innerWindow->GetScriptableParent();
         if (NS_WARN_IF(!parentWindow)) {
           return NS_ERROR_DOM_SECURITY_ERR;
         }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8151,34 +8151,34 @@ nsGlobalWindow::PrintOuter(ErrorResult& 
     if (printSettingsService) {
       bool printSettingsAreGlobal =
         Preferences::GetBool("print.use_global_printsettings", false);
 
       if (printSettingsAreGlobal) {
         printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
 
         nsAutoString printerName;
-        printSettings->GetPrinterName(getter_Copies(printerName));
+        printSettings->GetPrinterName(printerName);
 
         bool shouldGetDefaultPrinterName = printerName.IsEmpty();
 #ifdef MOZ_X11
         // In Linux, GTK backend does not support per printer settings.
         // Calling GetDefaultPrinterName causes a sandbox violation (see Bug 1329216).
         // The printer name is not needed anywhere else on Linux before it gets to the parent.
         // In the parent, we will then query the default printer name if no name is set.
         // Unless we are in the parent, we will skip this part.
         if (!XRE_IsParentProcess()) {
           shouldGetDefaultPrinterName = false;
         }
 #endif
         if (shouldGetDefaultPrinterName) {
-          printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
-          printSettings->SetPrinterName(printerName.get());
+          printSettingsService->GetDefaultPrinterName(printerName);
+          printSettings->SetPrinterName(printerName);
         }
-        printSettingsService->InitPrintSettingsFromPrinter(printerName.get(),
+        printSettingsService->InitPrintSettingsFromPrinter(printerName,
                                                            printSettings);
         printSettingsService->InitPrintSettingsFromPrefs(printSettings,
                                                          true,
                                                          nsIPrintSettings::kInitSaveAll);
       } else {
         printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
       }
 
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -611,16 +611,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
         MOZ_ASSERT(IsDOMObject(wrapper));
         JSAutoCompartment ac(cx, wrapper);
         ReparentWrapper(cx, wrapper, aError);
         if (aError.Failed()) {
           if (wasRegistered) {
             aNode->OwnerDoc()->UnregisterActivityObserver(aNode->AsElement());
           }
           aNode->mNodeInfo.swap(newNodeInfo);
+          if (elem) {
+            elem->NodeInfoChanged(newDoc);
+          }
           if (wasRegistered) {
             aNode->OwnerDoc()->RegisterActivityObserver(aNode->AsElement());
           }
           return nullptr;
         }
       }
     }
   }
new file mode 100644
--- /dev/null
+++ b/dom/base/test/iframe_webSocket_sandbox.html
@@ -0,0 +1,65 @@
+<html><body>
+<iframe id="frame" sandbox="allow-scripts allow-popups"></iframe>
+<script type="application/javascript;version=1.8">
+onmessage = function(e) {
+  parent.postMessage(e.data, '*');
+}
+
+var ifr = document.getElementById('frame');
+
+if (location.search == '?nested') {
+  var url = new URL(location);
+  url.search = "";
+  ifr.src = url.href;
+} else if (location.search == '?popup') {
+  var url = new URL(location);
+  url.search = "?opener";
+
+  ifr.srcdoc = "<html><script>" +
+    "window.open('" + url.href + "', 'foobar');" +
+    "onmessage = function(e) { " +
+    "  parent.postMessage(e.data, '*'); " +
+    "}" +
+  "</scr" + "ipt></html>";
+} else if (location.search == '?opener') {
+  try{
+    var socket = new WebSocket('ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic');
+    socket.onerror = function(e) {
+      opener.postMessage('WS onerror', '*');
+      close();
+    };
+    socket.onopen = function(event) {
+      opener.postMessage('WS onopen', '*');
+      close();
+    };
+  } catch(e) {
+    if (e.name == 'SecurityError') {
+      opener.postMessage('WS Throws!', '*');
+    } else {
+      opener.postMessage('WS Throws something else!', '*');
+    }
+    close();
+  }
+} else {
+  ifr.srcdoc = `
+  <html><script>
+  try{
+    var socket = new WebSocket('ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic');
+    socket.onerror = function(e) {
+      parent.postMessage('WS onerror', '*');
+    };
+    socket.onopen = function(event) {
+      parent.postMessage('WS onopen', '*');
+    };
+  } catch(e) {
+    if (e.name == 'SecurityError') {
+      parent.postMessage('WS Throws!', '*');
+    } else {
+      parent.postMessage('WS Throws something else!', '*');
+    }
+  }
+  </scr`+`ipt>
+  </html>`;
+}
+</script>
+</body></html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -801,16 +801,19 @@ tags = audiochannel
 [test_webaudioNotificationStopOnNavigation.html]
 tags = audiochannel
 [test_websocket_basic.html]
 skip-if = toolkit == 'android'
 [test_websocket_hello.html]
 skip-if = toolkit == 'android'
 [test_websocket_permessage_deflate.html]
 skip-if = toolkit == 'android'
+[test_webSocket_sandbox.html]
+skip-if = toolkit == 'android'
+support-files = iframe_webSocket_sandbox.html
 [test_websocket1.html]
 skip-if = toolkit == 'android'
 [test_websocket2.html]
 skip-if = toolkit == 'android'
 [test_websocket3.html]
 skip-if = toolkit == 'android'
 [test_websocket4.html]
 skip-if = toolkit == 'android'
--- a/dom/base/test/test_bug1222633.html
+++ b/dom/base/test/test_bug1222633.html
@@ -83,18 +83,20 @@ function testChangePrefetchToPreload(url
 };
 
 const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
 const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH;
 const CROSS_ORIGIN = "http://example.com" + SJS_PATH;
 
 SimpleTest.waitForExplicitFinish();
 
+SpecialPowers.pushPrefEnv({"set": [["network.preload", true]]})
+
 // test same origin
-testPreloadEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, false)
+.then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, false))
 .then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, false))
 .then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
 .then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, false))
 
 // test cross origin without CORS
 .then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, true))
 .then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, true))
 .then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
--- a/dom/base/test/test_bug1222633_link_update.html
+++ b/dom/base/test/test_bug1222633_link_update.html
@@ -117,18 +117,20 @@ function testPreloadEventSetCrossOrigin(
 }
 
 const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
 const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH;
 const CROSS_ORIGIN = "http://example.com" + SJS_PATH;
 
 SimpleTest.waitForExplicitFinish();
 
+SpecialPowers.pushPrefEnv({"set": [["network.preload", true]]})
+
 // Test changing as parameter from a wrong to a correct one.
-testPreloadEventAsAttributeChange(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120")
+.then(() => testPreloadEventAsAttributeChange(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120"))
 // Test changing type parameter from a wrong to a correct one for given as parameter.
 .then(() => testPreloadEventAttributeChange(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", "type", "text/vtt", "image/png", false, true))
 // Test changing media parameter from a wrong to a correct one.
 .then(() => testPreloadEventAttributeChange(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", "media", "foo", "all", false, true))
 // Test changing crossorigin parameter.
 .then(() => testPreloadEventSetCrossOrigin(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120&allowOrigin=*"))
 
 .catch((err) => ok(false, "promise rejected: " + err))
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_webSocket_sandbox.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1252751</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="container"></div>
+<iframe id="frame"></iframe>
+<script type="application/javascript;version=1.8">
+var urls = [ "https://example.com/tests/dom/base/test/iframe_webSocket_sandbox.html",
+             "https://example.com/tests/dom/base/test/iframe_webSocket_sandbox.html?nested",
+             "https://example.com/tests/dom/base/test/iframe_webSocket_sandbox.html?popup" ];
+
+onmessage = function(e) {
+  is(e.data, "WS Throws!", "ws://URI cannot be used by a https iframe");
+  runTest();
+}
+
+function runTest() {
+  if (!urls.length) {
+    SimpleTest.finish();
+    return;
+  }
+
+  document.getElementById("frame").src = urls.shift();
+}
+
+SimpleTest.waitForExplicitFinish();
+runTest();
+</script>
+</body>
+</html>
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -386,21 +386,38 @@ static const DOMTokenListSupportedToken 
   "alternate",
   "preconnect",
   "icon",
   "search",
   "preload",
   nullptr
 };
 
+static const DOMTokenListSupportedToken sSupportedRelValuesNoPreload[] = {
+  // Keep this in sync with ToLinkMask in nsStyleLinkElement.cpp.
+  // "import" must come first because it's conditional.
+  "prefetch",
+  "dns-prefetch",
+  "stylesheet",
+  "next",
+  "alternate",
+  "preconnect",
+  "icon",
+  "search",
+  nullptr
+};
 nsDOMTokenList*
 HTMLLinkElement::RelList()
 {
   if (!mRelList) {
-    mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
+    if (Preferences::GetBool("network.preload")) {
+      mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
+    } else {
+      mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValuesNoPreload);
+    }
   }
   return mRelList;
 }
 
 already_AddRefed<nsIURI>
 HTMLLinkElement::GetHrefURI() const
 {
   return GetHrefURIForAnchors();
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -229,16 +229,17 @@ WebAuthnManager::MaybeClearTransaction()
     RefPtr<WebAuthnTransactionChild> c;
     mChild.swap(c);
     c->Send__delete__(c);
   }
 }
 
 WebAuthnManager::~WebAuthnManager()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MaybeClearTransaction();
 }
 
 RefPtr<WebAuthnManager::BackgroundActorPromise>
 WebAuthnManager::GetOrCreateBackgroundActor()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -258,16 +259,17 @@ WebAuthnManager::GetOrCreateBackgroundAc
   return promise;
 }
 
 //static
 WebAuthnManager*
 WebAuthnManager::GetOrCreate()
 {
   MOZ_ASSERT(NS_IsMainThread());
+
   if (gWebAuthnManager) {
     return gWebAuthnManager;
   }
 
   gWebAuthnManager = new WebAuthnManager();
   ClearOnShutdown(&gWebAuthnManager);
   return gWebAuthnManager;
 }
@@ -279,25 +281,26 @@ WebAuthnManager::Get()
   MOZ_ASSERT(NS_IsMainThread());
   return gWebAuthnManager;
 }
 
 already_AddRefed<Promise>
 WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
                                 const MakePublicKeyCredentialOptions& aOptions)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aParent);
 
   MaybeClearTransaction();
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(global, rv);
-  if(rv.Failed()) {
+  if (rv.Failed()) {
     return nullptr;
   }
 
   nsString origin;
   nsCString rpId;
   rv = GetOrigin(aParent, origin, rpId);
   if (NS_WARN_IF(rv.Failed())) {
     promise->MaybeReject(rv);
@@ -511,48 +514,55 @@ WebAuthnManager::MakeCredential(nsPIDOMW
   mInfo = Some(info);
   ListenForVisibilityEvents(aParent, this);
 
   return promise.forget();
 }
 
 void
 WebAuthnManager::StartRegister() {
+  MOZ_ASSERT(NS_IsMainThread());
+
   if (mChild) {
     mChild->SendRequestRegister(mInfo.ref());
   }
 }
 
 void
 WebAuthnManager::StartSign() {
+  MOZ_ASSERT(NS_IsMainThread());
+
   if (mChild) {
     mChild->SendRequestSign(mInfo.ref());
   }
 }
 
 void
 WebAuthnManager::StartCancel() {
+  MOZ_ASSERT(NS_IsMainThread());
+
   if (mChild) {
     mChild->SendRequestCancel();
   }
 }
 
 already_AddRefed<Promise>
 WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
                               const PublicKeyCredentialRequestOptions& aOptions)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aParent);
 
   MaybeClearTransaction();
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(global, rv);
-  if(rv.Failed()) {
+  if (rv.Failed()) {
     return nullptr;
   }
 
   nsString origin;
   nsCString rpId;
   rv = GetOrigin(aParent, origin, rpId);
   if (NS_WARN_IF(rv.Failed())) {
     promise->MaybeReject(rv);
@@ -685,16 +695,17 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
   ListenForVisibilityEvents(aParent, this);
 
   return promise.forget();
 }
 
 void
 WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mTransactionPromise);
   MOZ_ASSERT(mInfo.isSome());
 
   CryptoBuffer regData;
   if (NS_WARN_IF(!regData.Assign(aRegBuffer.Elements(), aRegBuffer.Length()))) {
     Cancel(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
@@ -808,16 +819,17 @@ WebAuthnManager::FinishMakeCredential(ns
   mTransactionPromise->MaybeResolve(credential);
   MaybeClearTransaction();
 }
 
 void
 WebAuthnManager::FinishGetAssertion(nsTArray<uint8_t>& aCredentialId,
                                     nsTArray<uint8_t>& aSigBuffer)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mTransactionPromise);
   MOZ_ASSERT(mInfo.isSome());
 
   CryptoBuffer tokenSignatureData;
   if (NS_WARN_IF(!tokenSignatureData.Assign(aSigBuffer.Elements(),
                                             aSigBuffer.Length()))) {
     Cancel(NS_ERROR_OUT_OF_MEMORY);
     return;
@@ -900,16 +912,17 @@ WebAuthnManager::Cancel(const nsresult& 
   }
 
   MaybeClearTransaction();
 }
 
 NS_IMETHODIMP
 WebAuthnManager::HandleEvent(nsIDOMEvent* aEvent)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aEvent);
 
   nsAutoString type;
   aEvent->GetType(type);
   if (!type.Equals(kVisibilityChange)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -949,19 +962,21 @@ WebAuthnManager::ActorCreated(PBackgroun
   MOZ_ASSERT(constructedMgr == mgr);
   mChild = mgr.forget();
   mPBackgroundCreationPromise.Resolve(NS_OK, __func__);
 }
 
 void
 WebAuthnManager::ActorDestroyed()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   mChild = nullptr;
 }
 
 void
 WebAuthnManager::ActorFailed()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_CRASH("We shouldn't be here!");
 }
 
 }
 }
--- a/dom/webidl/ChromeUtils.webidl
+++ b/dom/webidl/ChromeUtils.webidl
@@ -96,16 +96,25 @@ interface ChromeUtils : ThreadSafeChrome
    * target compartment (or the caller compartment if no target is provided).
    * Property values themeselves are not cloned.
    *
    * Ignores non-enumerable properties, properties on prototypes, and properties
    * with getters or setters.
    */
   [Throws]
   static object shallowClone(object obj, optional object? target = null);
+
+  /**
+   * Dispatches the given callback to the main thread when it would be
+   * otherwise idle. Similar to Window.requestIdleCallback, but not bound to a
+   * particular DOM windw.
+   */
+  [Throws]
+  static void idleDispatch(IdleRequestCallback callback,
+                           optional IdleRequestOptions options);
 };
 
 /**
  * Used by principals and the script security manager to represent origin
  * attributes. The first dictionary is designed to contain the full set of
  * OriginAttributes, the second is used for pattern-matching (i.e. does this
  * OriginAttributesDictionary match the non-empty attributes in this pattern).
  *
--- a/dom/webidl/IdleDeadline.webidl
+++ b/dom/webidl/IdleDeadline.webidl
@@ -2,13 +2,14 @@
 /* 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/.
  *
  * The origin of this IDL file is:
  * https://w3c.github.io/requestidlecallback/
  */
 
-[Func="nsGlobalWindow::IsRequestIdleCallbackEnabled"]
+[Exposed=(Window,System),
+ Func="nsGlobalWindow::IsRequestIdleCallbackEnabled"]
 interface IdleDeadline {
   DOMHighResTimeStamp timeRemaining();
   readonly attribute boolean didTimeout;
 };
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/crashtests/1348882.html
@@ -0,0 +1,18 @@
+<!DOCTYPE>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+function boom() {
+  let r = new Request("#a#a");
+  setTimeout(function(){
+    r.formData();
+    setTimeout(function(){
+      r.blob();
+    }, 0);
+  }, 0);
+}
+addEventListener("DOMContentLoaded", boom);
+</script>
+</head>
+</html>
--- a/dom/workers/test/crashtests/crashtests.list
+++ b/dom/workers/test/crashtests/crashtests.list
@@ -1,5 +1,6 @@
 load 779707.html
 load 943516.html
 load 1153636.html
 load 1158031.html
 load 1228456.html
+load 1348882.html
--- a/dom/xul/templates/nsIXULTemplateBuilder.idl
+++ b/dom/xul/templates/nsIXULTemplateBuilder.idl
@@ -1,25 +1,29 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
-interface nsAtom;  // not a real interface; used in [noscript] methods only
 interface nsIContent;
 interface nsIXULBuilderListener;
 interface nsIXULTemplateResult;
 interface nsIXULTemplateRuleFilter;
 interface nsIXULTemplateQueryProcessor;
 interface nsIRDFResource;
 interface nsIRDFCompositeDataSource;
 interface nsIDOMDataTransfer;
 
+%{C++
+class nsAtom;
+%}
+[ptr] native nsAtomPtr(nsAtom);
+
 /**
  * A template builder, given an input source of data, a template, and a
  * reference point, generates a list of results from the input, and copies
  * part of the template for each result. Templates may generate content
  * recursively, using the same template, but with the previous iteration's
  * results as the reference point. As an example, for an XML datasource the
  * initial reference point would be a specific node in the DOM tree and a
  * template might generate a list of all child nodes. For the next iteration,
@@ -263,17 +267,17 @@ interface nsIXULTemplateBuilder : nsISup
      * intended to be called only by the RDF query processor. If aTag is set,
      * the content must have a tag name that matches aTag. aTag may be ignored
      * for builders that don't generate real DOM content.
      *
      * @param aNode node to check
      * @param aTag tag that must match
      */
     [noscript] boolean hasGeneratedContent(in nsIRDFResource aNode,
-                                           in nsAtom aTag);
+                                           in nsAtomPtr aTag);
 
     /**
      * Adds a rule filter for a given rule, which may be used for specialized
      * rule filtering. Any existing filter on the rule is removed. The default
      * conditions specified inside the <rule> tag are applied before the
      * rule filter is applied, meaning that the filter may be used to further
      * filter out results but not reaccept results that have already been
      * rejected.
--- a/dom/xul/templates/nsIXULTemplateQueryProcessor.idl
+++ b/dom/xul/templates/nsIXULTemplateQueryProcessor.idl
@@ -1,22 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
-interface nsAtom;  // not a real interface; used in [noscript] methods only
 interface nsIArray;
 interface nsISimpleEnumerator;
 interface nsIXULTemplateResult;
 interface nsIXULTemplateRuleFilter;
 interface nsIXULTemplateBuilder;
 
+%{C++
+class nsAtom;
+%}
+[ptr] native nsAtomPtr(nsAtom);
+
 /**
  * A query processor takes a template query and generates results for it given
  * a datasource and a reference point. There is a one-to-one relationship
  * between a template builder and a query processor. The template builder
  * creates the query processor, and there is no other means to retrieve it.
  *
  * A template query is the contents inside a <query> element within the
  * template. The actual syntax is opaque to the template builder and defined
@@ -159,18 +163,18 @@ interface nsIXULTemplateQueryProcessor :
    * @param aQuery <query> node to compile
    * @param aRefVariable the reference variable
    * @param aMemberVariable the member variable
    *
    * @returns a compiled query object
    */
   [noscript] nsISupports compileQuery(in nsIXULTemplateBuilder aBuilder,
                                       in nsIDOMNode aQuery,
-                                      in nsAtom aRefVariable,
-                                      in nsAtom aMemberVariable);
+                                      in nsAtomPtr aRefVariable,
+                                      in nsAtomPtr aMemberVariable);
 
   /**
    * Generate the results of a query and return them in an enumerator. The
    * enumerator must contain nsIXULTemplateResult objects. If there are no
    * results, an empty enumerator must be returned.
    *
    * The datasource will be the same as the one passed to the earlier
    * initializeForBuilding method. The context reference (aRef) is a reference
@@ -218,18 +222,18 @@ interface nsIXULTemplateQueryProcessor :
    * the syntax '+2' to mean add two to the reference.
    *
    * @param aRuleNode rule to add the binding to
    * @param aVar variable that will be bound
    * @param aRef variable that holds reference value
    * @param aExpr expression used to compute the value to assign
    */
   [noscript] void addBinding(in nsIDOMNode aRuleNode,
-                             in nsAtom aVar,
-                             in nsAtom aRef,
+                             in nsAtomPtr aVar,
+                             in nsAtomPtr aRef,
                              in AString aExpr);
 
   /**
    * Translate a ref attribute string into a result. This is used as the
    * reference point by the template builder when generating the first level
    * of content. For recursive generation, the result from the parent
    * generation phase will be used directly as the reference so a translation
    * is not needed. This allows all levels to be generated using objects that
@@ -266,11 +270,11 @@ interface nsIXULTemplateQueryProcessor :
    * @param aLeft the left result to compare
    * @param aRight the right result to compare
    * @param aVar variable to compare
    *
    * @param returns -1 if less, 0 if equal, or 1 if greater
    */
    [noscript] int32_t compareResults(in nsIXULTemplateResult aLeft,
                                      in nsIXULTemplateResult aRight,
-                                     in nsAtom aVar,
+                                     in nsAtomPtr aVar,
                                      in unsigned long aSortHints);
 };
--- a/dom/xul/templates/nsIXULTemplateResult.idl
+++ b/dom/xul/templates/nsIXULTemplateResult.idl
@@ -1,19 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-interface nsAtom;  // not a real interface; used in [noscript] methods only
 interface nsIDOMNode;
 interface nsIRDFResource;
 
+%{C++
+class nsAtom;
+%}
+[ptr] native nsAtomPtr(nsAtom);
+
 /**
  * A single result generated from a template query. Each result is identified
  * by an id, which must be unique within the set of results produced from a
  * query. The result may optionally be identified by an RDF resource.
  *
  * Generally, the result and its id will be able to uniquely identify a node
  * in the source data, such as an RDF or XML node. In other contexts, such as
  * a database query, a result would represent a particular record.
@@ -75,30 +79,30 @@ interface nsIXULTemplateResult : nsISupp
    * attribute within the action body, it will be replaced with the result
    * of this method. The question mark is considered part of the variable
    * name, thus aVar should be ?name and not simply name.
    *
    * @param aVar the variable to look up
    *
    * @return the value for the variable or a null string if it has no value
    */
-  [noscript] AString getBindingFor(in nsAtom aVar);
+  [noscript] AString getBindingFor(in nsAtomPtr aVar);
 
   /**
    * Get an object value for a variable such as ?name for this result. 
    *
    * This method may return null for a variable, even if getBindingFor returns
    * a non-null value for the same variable. This method is provided as a
    * convenience when sorting results.
    *
    * @param aVar the variable to look up
    *
    * @return the value for the variable or null if it has no value
    */
-  [noscript] nsISupports getBindingObjectFor(in nsAtom aVar);
+  [noscript] nsISupports getBindingObjectFor(in nsAtomPtr aVar);
 
   /**
    * Indicate that a particular rule of a query has matched and that output
    * will be generated for it. Both the query as compiled by the query
    * processor's compileQuery method and the XUL <rule> element are supplied.
    * The query must always be one that was compiled by the query processor
    * that created this result. The <rule> element must always be a child of
    * the <query> element that was used to compile the query.
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/crashtests/1383747.html
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <script>
+      try { o1 = window.getSelection() } catch(e) { }
+      try { o2 = document.createElement('map') } catch(e) { };
+      try { o3 = document.createElement('select') } catch(e) { }
+      try { document.documentElement.appendChild(o2) } catch(e) { };
+      try { o2.contentEditable = 'true' } catch(e) { };
+      try { o2.offsetTop } catch(e) { };
+      try { document.replaceChild(document.implementation.createHTMLDocument().documentElement, document.documentElement); } catch(e) { }
+      try { document.documentElement.appendChild(o3) } catch(e) { }
+      try { o1.modify('extend', 'forward', 'word') } catch(e) { }
+    </script>
+  </head>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/crashtests/1383763.html
@@ -0,0 +1,17 @@
+<xsl:stylesheet id='xsl'>
+<script id='script'>
+try { o1 = document.createElement('table') } catch(e) { }
+try { o3 = document.createElement('area') } catch(e) { }
+try { o4 = document.createElement('script'); } catch(e) { }
+try { o5 = document.getSelection() } catch(e) { }
+try { document.implementation.createDocument('', '', null).adoptNode(o1); } catch(e) { }
+try { o1.appendChild(o3) } catch(e) { }
+try { o5.addRange(new Range()); } catch(e) { }
+try { document.documentElement.appendChild(o4) } catch(e) { }
+try { o4.textContent = 'XX' } catch(e) { }
+try { o7 = o4.firstChild } catch(e) { }
+try { o4.parentNode.insertBefore(o7, o4); } catch(e) { }
+try { o5.modify('extend', 'forward', 'line') } catch(e) { }
+try { o5.selectAllChildren(o3) } catch(e) { }
+try { o7.splitText(1) } catch(e) { }
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/crashtests/1384161.html
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <script>
+      try { o1 = document.createElement('caption') } catch(e) { }
+      try { o2 = document.createElement('select') } catch(e) { }
+      try { o3 = document.createElement('map') } catch(e) { }
+      try { o4 = window.getSelection() } catch(e) { }
+      try { document.documentElement.appendChild(o1) } catch(e) { }
+      try { o1.style.display = 'contents' } catch(e) { }
+      try { document.prepend(o2, document) } catch(e) { }
+      try { document.designMode = 'on'; } catch(e) { }
+      try { o3.ownerDocument.execCommand('outdent', false, null) } catch(e) { }
+      try { document.designMode = 'off'; } catch(e) { }
+      try { o4.extend(o2, 0) } catch(e) { }
+    </script>
+  </head>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/crashtests/1393171.html
@@ -0,0 +1,10 @@
+<script>
+window.onload=function(){
+  window.getSelection().addRange(document.createRange());
+  document.getElementById('a').appendChild(document.createElement('option'));
+  window.getSelection().modify('extend','backward','lineboundary');
+}
+</script>
+<div></div>
+<textarea autofocus='true'></textarea>
+<del id='a'>
--- a/editor/libeditor/crashtests/crashtests.list
+++ b/editor/libeditor/crashtests/crashtests.list
@@ -75,13 +75,17 @@ load 1324505.html
 needs-focus load 1343918.html
 load 1345015.html
 load 1348851.html
 load 1350772.html
 load 1364133.html
 load 1366176.html
 load 1375131.html
 load 1381541.html
+load 1383747.html
 load 1383755.html
+load 1383763.html
+load 1384161.html
 load 1388075.html
+load 1393171.html
 load 1402469.html
 load 1402904.html
 load 1405747.html
--- a/gfx/harfbuzz/src/hb-shape-plan.cc
+++ b/gfx/harfbuzz/src/hb-shape-plan.cc
@@ -515,25 +515,27 @@ hb_shape_plan_create_cached2 (hb_face_t 
 
     if (unlikely (!proposal.shaper_func))
       return hb_shape_plan_get_empty ();
   }
 
 
 retry:
   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
-  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
-    if (hb_shape_plan_matches (node->shape_plan, &proposal))
-    {
-      DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
-      return hb_shape_plan_reference (node->shape_plan);
-    }
+
+  /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */
+  if (!hb_coords_present (coords, num_coords))
+    for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
+      if (hb_shape_plan_matches (node->shape_plan, &proposal))
+      {
+        DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
+        return hb_shape_plan_reference (node->shape_plan);
+      }
 
   /* Not found. */
-
   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
 						       user_features, num_user_features,
 						       coords, num_coords,
 						       shaper_list);
 
   /* Don't add to the cache if face is inert. */
   if (unlikely (hb_object_is_inert (face)))
     return shape_plan;
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -54,16 +54,19 @@ parent:
                        WebRenderScrollData aScrollData,
                        OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                        IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   sync SetDisplayListSync(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                           LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                           WebRenderScrollData aScrollData,
                           OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                           IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
+  async EmptyTransaction(FocusTarget focusTarget,
+                         WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
+                         IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   async SetFocusTarget(FocusTarget focusTarget);
   async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems);
   async ParentCommands(WebRenderParentCommand[] commands);
   sync GetSnapshot(PTexture texture);
   async AddPipelineIdForCompositable(PipelineId aImageId, CompositableHandle aHandle, bool aAsync);
   async RemovePipelineIdForCompositable(PipelineId aPipelineId);
   async AddExternalImageIdForCompositable(ExternalImageId aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(ExternalImageId aImageId);
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -36,20 +36,28 @@ ShmSegmentsWriter::Write(Range<uint8_t> 
     memcpy(dstPtr, aBytes.begin().get(), length);
     return range;
   }
 
   int remainingBytesToCopy = length;
 
   size_t srcCursor = 0;
   size_t dstCursor = mCursor;
+  size_t currAllocLen = mSmallAllocs.Length();
 
   while (remainingBytesToCopy > 0) {
     if (dstCursor >= mSmallAllocs.Length() * mChunkSize) {
-      AllocChunk();
+      if (!AllocChunk()) {
+        for (size_t i = mSmallAllocs.Length() ; currAllocLen <= i ; i--) {
+          ipc::Shmem shm = mSmallAllocs.ElementAt(i);
+          mShmAllocator->DeallocShmem(shm);
+          mSmallAllocs.RemoveElementAt(i);
+        }
+        return layers::OffsetRange(0, start, 0);
+      }
       continue;
     }
 
     const size_t dstMaxOffset = mChunkSize * mSmallAllocs.Length();
     const size_t dstBaseOffset = mChunkSize * (mSmallAllocs.Length() - 1);
 
     MOZ_ASSERT(dstCursor >= dstBaseOffset);
     MOZ_ASSERT(dstCursor <= dstMaxOffset);
@@ -70,36 +78,39 @@ ShmSegmentsWriter::Write(Range<uint8_t> 
     MOZ_ASSERT(remainingBytesToCopy >= 0);
   }
 
   mCursor += length;
 
   return layers::OffsetRange(0, start, length);
 }
 
-void
+bool
 ShmSegmentsWriter::AllocChunk()
 {
   ipc::Shmem shm;
   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
   if (!mShmAllocator->AllocShmem(mChunkSize, shmType, &shm)) {
-    gfxCriticalError() << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
-    MOZ_CRASH();
+    gfxCriticalNote << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
+    MOZ_ASSERT(false, "ShmSegmentsWriter fails to allocate chunk");
+    return false;
   }
   mSmallAllocs.AppendElement(shm);
+  return true;
 }
 
 layers::OffsetRange
 ShmSegmentsWriter::AllocLargeChunk(size_t aSize)
 {
   ipc::Shmem shm;
   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
   if (!mShmAllocator->AllocShmem(aSize, shmType, &shm)) {
-    gfxCriticalError() << "ShmSegmentsWriter failed to allocate large chunk of size " << aSize;
-    MOZ_CRASH();
+    gfxCriticalNote << "ShmSegmentsWriter failed to allocate large chunk of size " << aSize;
+    MOZ_ASSERT(false, "ShmSegmentsWriter fails to allocate large chunk");
+    return layers::OffsetRange(0, 0, 0);
   }
   mLargeAllocs.AppendElement(shm);
 
   return layers::OffsetRange(mLargeAllocs.Length(), 0, aSize);
 }
 
 void
 ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs)
@@ -217,67 +228,87 @@ ShmSegmentsReader::Read(const layers::Of
   return aInto.Length() - initialLength == aRange.length();
 }
 
 IpcResourceUpdateQueue::IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator,
                                                size_t aChunkSize)
 : mWriter(Move(aAllocator), aChunkSize)
 {}
 
-void
+bool
 IpcResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
                                  Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpAddImage(aDescriptor, bytes, 0, key));
+  return true;
 }
 
-void
+bool
 IpcResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
                                      Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpAddBlobImage(aDescriptor, bytes, 0, key));
+  return true;
 }
 
 void
 IpcResourceUpdateQueue::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey)
 {
   mUpdates.AppendElement(layers::OpAddExternalImage(aExtId, aKey));
 }
 
-void
+bool
 IpcResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
                                           const ImageDescriptor& aDescriptor,
                                           Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpUpdateImage(aDescriptor, bytes, aKey));
+  return true;
 }
 
-void
+bool
 IpcResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
                                         const ImageDescriptor& aDescriptor,
                                         Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpUpdateBlobImage(aDescriptor, bytes, aKey));
+  return true;
 }
 
 void
 IpcResourceUpdateQueue::DeleteImage(ImageKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteImage(aKey));
 }
 
-void
+bool
 IpcResourceUpdateQueue::AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex)
 {
   auto bytes = mWriter.Write(aBytes);
+  if (!bytes.length()) {
+    return false;
+  }
   mUpdates.AppendElement(layers::OpAddRawFont(bytes, aIndex, aKey));
+  return true;
 }
 
 void
 IpcResourceUpdateQueue::DeleteFont(wr::FontKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteFont(aKey));
 }
 
--- a/gfx/layers/wr/IpcResourceUpdateQueue.h
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.h
@@ -29,17 +29,17 @@ public:
     return Write(Range<uint8_t>((uint8_t*)aValues.begin().get(), aValues.length() * sizeof(T)));
   }
 
   void Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
 
   void Clear();
 
 protected:
-  void AllocChunk();
+  bool AllocChunk();
   layers::OffsetRange AllocLargeChunk(size_t aSize);
 
   nsTArray<ipc::Shmem> mSmallAllocs;
   nsTArray<ipc::Shmem> mLargeAllocs;
   ipc::IShmemAllocator* mShmAllocator;
   size_t mCursor;
   size_t mChunkSize;
 };
@@ -62,43 +62,43 @@ protected:
 class IpcResourceUpdateQueue {
 public:
   // Because we are using shmems, the size should be a multiple of the page size.
   // Each shmem has two guard pages, and the minimum shmem size (at least one Windows)
   // is 64k which is already quite large for a lot of the resources we use here.
   // So we pick 64k - 2 * 4k = 57344 bytes as the defautl alloc
   explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 57344);
 
-  void AddImage(wr::ImageKey aKey,
+  bool AddImage(wr::ImageKey aKey,
                 const ImageDescriptor& aDescriptor,
                 Range<uint8_t> aBytes);
 
-  void AddBlobImage(wr::ImageKey aKey,
+  bool AddBlobImage(wr::ImageKey aKey,
                     const ImageDescriptor& aDescriptor,
                     Range<uint8_t> aBytes);
 
   void AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
 
-  void UpdateImageBuffer(wr::ImageKey aKey,
+  bool UpdateImageBuffer(wr::ImageKey aKey,
                          const ImageDescriptor& aDescriptor,
                          Range<uint8_t> aBytes);
 
-  void UpdateBlobImage(wr::ImageKey aKey,
+  bool UpdateBlobImage(wr::ImageKey aKey,
                        const ImageDescriptor& aDescriptor,
                        Range<uint8_t> aBytes);
 
   void UpdateExternalImage(ImageKey aKey,
                            const ImageDescriptor& aDescriptor,
                            ExternalImageId aExtID,
                            wr::WrExternalImageBufferType aBufferType,
                            uint8_t aChannelIndex = 0);
 
   void DeleteImage(wr::ImageKey aKey);
 
-  void AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
+  bool AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
 
   void DeleteFont(wr::FontKey aKey);
 
   void AddFontInstance(wr::FontInstanceKey aKey,
                        wr::FontKey aFontKey,
                        float aGlyphSize,
                        const wr::FontInstanceOptions* aOptions,
                        const wr::FontInstancePlatformOptions* aPlatformOptions,
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -153,16 +153,38 @@ WebRenderBridgeChild::EndTransaction(con
   }
 
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 void
+WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget,
+                                          uint64_t aTransactionId,
+                                          const mozilla::TimeStamp& aTxnStartTime)
+{
+  MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(mIsInTransaction);
+
+  TimeStamp fwdTime;
+#if defined(ENABLE_FRAME_LATENCY_LOG)
+  fwdTime = TimeStamp::Now();
+#endif
+
+  this->SendEmptyTransaction(aFocusTarget,
+                             mParentCommands, mDestroyedActors,
+                             GetFwdTransactionId(), aTransactionId,
+                             mIdNamespace, aTxnStartTime, fwdTime);
+  mParentCommands.Clear();
+  mDestroyedActors.Clear();
+  mIsInTransaction = false;
+}
+
+void
 WebRenderBridgeChild::ProcessWebRenderParentCommands()
 {
   MOZ_ASSERT(!mDestroyed);
 
   if (mParentCommands.IsEmpty()) {
     return;
   }
   this->SendParentCommands(mParentCommands);
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -70,16 +70,19 @@ public:
   void BeginTransaction();
   void EndTransaction(const wr::LayoutSize& aContentSize,
                       wr::BuiltDisplayList& dl,
                       wr::IpcResourceUpdateQueue& aResources,
                       const gfx::IntSize& aSize,
                       bool aIsSync, uint64_t aTransactionId,
                       const WebRenderScrollData& aScrollData,
                       const mozilla::TimeStamp& aTxnStartTime);
+  void EndEmptyTransaction(const FocusTarget& aFocusTarget,
+                           uint64_t aTransactionId,
+                           const mozilla::TimeStamp& aTxnStartTime);
   void ProcessWebRenderParentCommands();
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   wr::PipelineId GetPipeline() { return mPipelineId; }
 
   // KnowsCompositor
   TextureForwarder* GetTextureForwarder() override;
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -610,16 +610,58 @@ WebRenderBridgeParent::RecvSetDisplayLis
   return RecvSetDisplayList(aSize, Move(aCommands), Move(aToDestroy),
                             aFwdTransactionId, aTransactionId,
                             aContentSize, dl, dlDesc, aScrollData,
                             Move(aResourceUpdates), Move(aSmallShmems), Move(aLargeShmems),
                             aIdNamespace, aTxnStartTime, aFwdTime);
 }
 
 mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
+                                            InfallibleTArray<WebRenderParentCommand>&& aCommands,
+                                            InfallibleTArray<OpDestroy>&& aToDestroy,
+                                            const uint64_t& aFwdTransactionId,
+                                            const uint64_t& aTransactionId,
+                                            const wr::IdNamespace& aIdNamespace,
+                                            const TimeStamp& aTxnStartTime,
+                                            const TimeStamp& aFwdTime)
+{
+  if (mDestroyed) {
+    for (const auto& op : aToDestroy) {
+      DestroyActor(op);
+    }
+    return IPC_OK();
+  }
+
+  AutoProfilerTracing tracing("Paint", "EmptyTransaction");
+  UpdateFwdTransactionId(aFwdTransactionId);
+  AutoClearReadLocks clearLocks(mReadLocks);
+
+  // This ensures that destroy operations are always processed. It is not safe
+  // to early-return without doing so.
+  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
+
+  if (!aCommands.IsEmpty()) {
+    mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
+    ProcessWebRenderParentCommands(aCommands);
+    mCompositorScheduler->ScheduleComposition();
+  }
+
+  mScrollData.SetFocusTarget(aFocusTarget);
+  UpdateAPZ(false);
+
+  // XXX Call DidComposite at correct timing.
+  TimeStamp now = TimeStamp::Now();
+  HoldPendingTransactionId(mWrEpoch, aTransactionId, aTxnStartTime, aFwdTime);
+  mCompositorBridge->DidComposite(wr::AsUint64(mPipelineId), now, now);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetFocusTarget(const FocusTarget& aFocusTarget)
 {
   mScrollData.SetFocusTarget(aFocusTarget);
   UpdateAPZ(false);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -101,16 +101,24 @@ public:
                                                  const wr::BuiltDisplayListDescriptor& dlDesc,
                                                  const WebRenderScrollData& aScrollData,
                                                  nsTArray<OpUpdateResource>&& aResourceUpdates,
                                                  nsTArray<ipc::Shmem>&& aSmallShmems,
                                                  nsTArray<ipc::Shmem>&& aLargeShmems,
                                                  const wr::IdNamespace& aIdNamespace,
                                                  const TimeStamp& aTxnStartTime,
                                                  const TimeStamp& aFwdTime) override;
+  mozilla::ipc::IPCResult RecvEmptyTransaction(const FocusTarget& aFocusTarget,
+                                               InfallibleTArray<WebRenderParentCommand>&& aCommands,
+                                               InfallibleTArray<OpDestroy>&& aToDestroy,
+                                               const uint64_t& aFwdTransactionId,
+                                               const uint64_t& aTransactionId,
+                                               const wr::IdNamespace& aIdNamespace,
+                                               const TimeStamp& aTxnStartTime,
+                                               const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvSetFocusTarget(const FocusTarget& aFocusTarget) override;
   mozilla::ipc::IPCResult RecvParentCommands(nsTArray<WebRenderParentCommand>&& commands) override;
   mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
                                                            const CompositableHandle& aHandle,
                                                            const bool& aAsync) override;
   mozilla::ipc::IPCResult RecvRemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId) override;
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -27,16 +27,33 @@ namespace layers {
 
 void WebRenderCommandBuilder::Destroy()
 {
   mLastCanvasDatas.Clear();
   RemoveUnusedAndResetWebRenderUserData();
 }
 
 void
+WebRenderCommandBuilder::EmptyTransaction()
+{
+  // We need to update canvases that might have changed.
+  for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
+    RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
+    WebRenderCanvasRendererAsync* canvas = canvasData->GetCanvasRenderer();
+    canvas->UpdateCompositableClient();
+  }
+}
+
+bool
+WebRenderCommandBuilder::NeedsEmptyTransaction()
+{
+  return !mLastCanvasDatas.IsEmpty();
+}
+
+void
 WebRenderCommandBuilder::BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                                 wr::IpcResourceUpdateQueue& aResourceUpdates,
                                                 nsDisplayList* aDisplayList,
                                                 nsDisplayListBuilder* aDisplayListBuilder,
                                                 WebRenderScrollData& aScrollData,
                                                 wr::LayoutSize& aContentSize)
 {
   { // scoping for StackingContextHelper RAII
@@ -494,17 +511,19 @@ WebRenderCommandBuilder::GenerateFallbac
       RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, paintSize.ToUnknownSize());
       PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder,
                             fallbackData->mBasicLayerManager, mManager, scale);
       recorder->Finish();
 
       Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
       wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
       wr::ImageDescriptor descriptor(paintSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque);
-      aResources.AddBlobImage(key, descriptor, bytes);
+      if (!aResources.AddBlobImage(key, descriptor, bytes)) {
+        return nullptr;
+      }
       fallbackData->SetKey(key);
     } else {
       fallbackData->CreateImageClientIfNeeded();
       RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
       RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
 
       {
         UpdateImageHelper helper(imageContainer, imageClient, paintSize.ToUnknownSize(), format);
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -35,16 +35,20 @@ class WebRenderCommandBuilder {
 public:
   explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager)
   : mManager(aManager)
   , mLastAsr(nullptr)
   {}
 
   void Destroy();
 
+  void EmptyTransaction();
+
+  bool NeedsEmptyTransaction();
+
   void BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                               wr::IpcResourceUpdateQueue& aResourceUpdates,
                               nsDisplayList* aDisplayList,
                               nsDisplayListBuilder* aDisplayListBuilder,
                               WebRenderScrollData& aScrollData,
                               wr::LayoutSize& aContentSize);
 
   Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -173,31 +173,48 @@ WebRenderLayerManager::BeginTransaction(
 
 bool
 WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   // With the WebRenderLayerManager we reject attempts to set most kind of
   // "pending data" for empty transactions. Any place that attempts to update
   // transforms or scroll offset, for example, will get failure return values
   // back, and will fall back to a full transaction. Therefore the only piece
-  // of "pending" information we need to send in an empty transaction is the
-  // APZ focus state.
-  WrBridge()->SendSetFocusTarget(mFocusTarget);
+  // of "pending" information we need to send in an empty transaction are the
+  // APZ focus state and canvases's CompositableOperations.
+
+  if (aFlags & EndTransactionFlags::END_NO_COMPOSITE && 
+      !mWebRenderCommandBuilder.NeedsEmptyTransaction()) {
+    MOZ_ASSERT(!mTarget);
+    WrBridge()->SendSetFocusTarget(mFocusTarget);
+    return true;
+  }
+
+  LayoutDeviceIntSize size = mWidget->GetClientSize();
+  WrBridge()->BeginTransaction();
+
+  mWebRenderCommandBuilder.EmptyTransaction();
 
-  // We also need to update canvases that might have changed, but this code
-  // as-is causes crashes so comment it out for now.
-  //for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
-  //  RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
-  //  WebRenderCanvasRendererAsync* canvas = canvasData->GetCanvasRenderer();
-  //  canvas->UpdateCompositableClient();
-  //}
+  WrBridge()->ClearReadLocks();
+
+  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
+  TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart();
 
-  if (!(aFlags & EndTransactionFlags::END_NO_COMPOSITE)) {
-    ScheduleComposite();
+  // Skip the synchronization for buffer since we also skip the painting during
+  // device-reset status.
+  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+    if (WrBridge()->GetSyncObject() &&
+        WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
+      WrBridge()->GetSyncObject()->Synchronize();
+    }
   }
+
+  WrBridge()->EndEmptyTransaction(mFocusTarget, mLatestTransactionId, transactionStart);
+
+  MakeSnapshotIfRequired(size);
   return true;
 }
 
 /*static*/ int32_t
 PopulateScrollData(WebRenderScrollData& aTarget, Layer* aLayer)
 {
   MOZ_ASSERT(aLayer);
 
new file mode 100644
--- /dev/null
+++ b/gfx/tests/crashtests/1278305.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<style>
+body {
+  mask: url(#mymask);
+}
+div::after {
+  content: counter(n);
+}
+</style>
+<script>
+window.onload = function(){
+  document.getElementsByTagName('body')[0].animate(
+    [{"transform": "skewy(11rad)"},
+     {"transform": "rotatex(0.125turn)"}],
+    {"fill":"forwards", "iterations": 0.75, "duration": 1});
+};
+</script></head>
+<body><div></div></body>
+</html>
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -126,13 +126,14 @@ skip-if(webrender&&debug) load 944579.ht
 pref(security.fileuri.strict_origin_policy,false) load 950000.html
 load 1034403-1.html
 load 1056516.html
 load 1205900.html
 load 1134549-1.svg
 load balinese-letter-spacing.html
 load 1216832-1.html
 load 1225125-1.html
+load 1278305.html
 load 1308394.html
 load 1317403-1.html # bug 1331533
 load 1325159-1.html
 load 1331683.html
 skip-if(Android) pref(dom.disable_open_during_load,false) load 1343666.html
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1278,16 +1278,25 @@ gfxHarfBuzzShaper::Initialize()
                                 HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 
     mHBFont = hb_font_create(mHBFace);
     hb_font_set_funcs(mHBFont, sHBFontFuncs, &mCallbackData, nullptr);
     hb_font_set_ppem(mHBFont, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
     uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
     hb_font_set_scale(mHBFont, scale, scale);
 
+    const auto& vars = mFont->GetStyle()->variationSettings;
+    size_t len = vars.Length();
+    if (len > 0) {
+        // Fortunately, the hb_variation_t struct is compatible with our
+        // gfxFontFeature, so we can simply cast here.
+        auto hbVars = reinterpret_cast<const hb_variation_t*>(vars.Elements());
+        hb_font_set_variations(mHBFont, hbVars, len);
+    }
+
     return true;
 }
 
 bool
 gfxHarfBuzzShaper::LoadHmtxTable()
 {
     // Read mNumLongHMetrics from metrics-head table without caching its
     // blob, and preload/cache the metrics table.
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -29,16 +29,17 @@ class AutoLockGC;
 class AutoLockHelperThreadState;
 class VerifyPreTracer;
 
 namespace gc {
 
 typedef Vector<ZoneGroup*, 4, SystemAllocPolicy> ZoneGroupVector;
 using BlackGrayEdgeVector = Vector<TenuredCell*, 0, SystemAllocPolicy>;
 
+class AutoCallGCCallbacks;
 class AutoMaybeStartBackgroundAllocation;
 class AutoRunParallelTask;
 class AutoTraceSession;
 class MarkingValidator;
 struct MovingTracer;
 class WeakCacheSweepIterator;
 
 enum IncrementalProgress
@@ -1045,16 +1046,20 @@ class GCRuntime
     gcstats::ZoneGCStats scanZonesBeforeGC();
     void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
     MOZ_MUST_USE IncrementalResult gcCycle(bool nonincrementalByAPI, SliceBudget& budget,
                                            JS::gcreason::Reason reason);
     bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
     void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
                                  AutoLockForExclusiveAccess& lock);
 
+    friend class AutoCallGCCallbacks;
+    void maybeCallBeginCallback();
+    void maybeCallEndCallback();
+
     void pushZealSelectedObjects();
     void purgeRuntime(AutoLockForExclusiveAccess& lock);
     MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock);
     bool prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut,
                                    AutoLockForExclusiveAccess& lock);
     bool shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime,
                                JS::gcreason::Reason reason, bool canAllocateMoreCode);
     void traceRuntimeForMajorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock);
@@ -1403,16 +1408,18 @@ class GCRuntime
     ActiveThreadData<bool> deterministicOnly;
     ActiveThreadData<int> incrementalLimit;
 
     ActiveThreadData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
 #endif
 
     ActiveThreadData<bool> fullCompartmentChecks;
 
+    ActiveThreadData<uint32_t> gcBeginCallbackDepth;
+
     Callback<JSGCCallback> gcCallback;
     Callback<JS::DoCycleCollectionCallback> gcDoCycleCollectionCallback;
     Callback<JSObjectsTenuredCallback> tenuredCallback;
     CallbackVector<JSFinalizeCallback> finalizeCallbacks;
     CallbackVector<JSWeakPointerZonesCallback> updateWeakPointerZonesCallbacks;
     CallbackVector<JSWeakPointerCompartmentCallback> updateWeakPointerCompartmentCallbacks;
 
     MemoryCounter<GCRuntime> mallocCounter;
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -53,16 +53,17 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup*
     nurseryShapes_(group),
     data(group, nullptr),
     isSystem(group, false),
 #ifdef DEBUG
     gcLastSweepGroupIndex(group, 0),
 #endif
     jitZone_(group, nullptr),
     gcScheduled_(false),
+    gcScheduledSaved_(false),
     gcPreserveCode_(group, false),
     keepShapeTables_(group, false),
     listNext_(group, NotOnList)
 {
     /* Ensure that there are no vtables to mess us up here. */
     MOZ_ASSERT(reinterpret_cast<JS::shadow::Zone*>(this) ==
                static_cast<JS::shadow::Zone*>(this));
 
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -690,16 +690,17 @@ struct Zone : public JS::shadow::Zone,
         updateMallocCounter(bytes);
         return p;
     }
 
   private:
     js::ZoneGroupData<js::jit::JitZone*> jitZone_;
 
     js::ActiveThreadData<bool> gcScheduled_;
+    js::ActiveThreadData<bool> gcScheduledSaved_;
     js::ZoneGroupData<bool> gcPreserveCode_;
     js::ZoneGroupData<bool> keepShapeTables_;
 
     // Allow zones to be linked into a list
     friend class js::gc::ZoneList;
     static Zone * const NotOnList;
     js::ZoneGroupOrGCTaskData<Zone*> listNext_;
     bool isOnList() const;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1407058.js
@@ -0,0 +1,16 @@
+"use strict";
+function f() {
+    var o = {};
+    Object.defineProperty(o, "x", {get: undefined, set: undefined});
+    for (var i = 0; i < 20; i++) {
+        var ex = null;
+        try {
+            o.x = 9;
+        } catch (e) {
+            ex = e;
+        }
+        assertEq(ex instanceof TypeError, true);
+        assertEq(o.x, undefined);
+    }
+}
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/enable-profiling-in-import.js
@@ -0,0 +1,9 @@
+var module = new WebAssembly.Module(wasmTextToBinary(`
+    (module
+        (import "global" "func")
+        (func (export "f")
+         call 0
+        )
+    )
+`));
+new WebAssembly.Instance(module, { global: { func: enableGeckoProfiling } }).exports.f();
--- a/js/src/jit/ExecutableAllocator.cpp
+++ b/js/src/jit/ExecutableAllocator.cpp
@@ -123,17 +123,18 @@ ExecutableAllocator::ExecutableAllocator
 }
 
 ExecutableAllocator::~ExecutableAllocator()
 {
     for (size_t i = 0; i < m_smallPools.length(); i++)
         m_smallPools[i]->release(/* willDestroy = */true);
 
     // If this asserts we have a pool leak.
-    MOZ_ASSERT_IF(m_pools.initialized(), m_pools.empty());
+    MOZ_ASSERT_IF(m_pools.initialized() && rt_->gc.shutdownCollectedEverything(),
+                  m_pools.empty());
 }
 
 ExecutablePool*
 ExecutableAllocator::poolForSize(size_t n)
 {
     // Try to fit in an existing small allocator.  Use the pool with the
     // least available space that is big enough (best-fit).  This is the
     // best strategy because (a) it maximizes the chance of the next
--- a/js/src/jit/JSJitFrameIter.h
+++ b/js/src/jit/JSJitFrameIter.h
@@ -298,17 +298,17 @@ class JSJitProfilingFrameIterator
     void fixBaselineReturnAddress();
 
     void moveToCppEntryFrame();
     void moveToWasmFrame(CommonFrameLayout* frame);
     void moveToNextFrame(CommonFrameLayout* frame);
 
   public:
     JSJitProfilingFrameIterator(JSContext* cx,
-                              const JS::ProfilingFrameIterator::RegisterState& state);
+                                const JS::ProfilingFrameIterator::RegisterState& state);
     explicit JSJitProfilingFrameIterator(void* exitFrame);
 
     void operator++();
     bool done() const { return fp_ == nullptr; }
 
     void* fp() const { MOZ_ASSERT(!done()); return fp_; }
     void* stackAddress() const { return fp(); }
     FrameType frameType() const { MOZ_ASSERT(!done()); return type_; }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -936,16 +936,17 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
 #ifdef JS_GC_ZEAL
     zealModeBits(0),
     zealFrequency(0),
     nextScheduled(0),
     deterministicOnly(false),
     incrementalLimit(0),
 #endif
     fullCompartmentChecks(false),
+    gcBeginCallbackDepth(0),
     alwaysPreserveCode(false),
 #ifdef DEBUG
     arenasEmptyAtShutdown(true),
 #endif
     lock(mutexid::GCLock),
     allocTask(rt, emptyChunks_.ref()),
     decommitTask(rt),
     helperState(rt),
@@ -1643,35 +1644,16 @@ GCRuntime::setObjectsTenuredCallback(JSO
 
 void
 GCRuntime::callObjectsTenuredCallback()
 {
     if (tenuredCallback.op)
         tenuredCallback.op(TlsContext.get(), tenuredCallback.data);
 }
 
-namespace {
-
-class AutoNotifyGCActivity {
-  public:
-    explicit AutoNotifyGCActivity(GCRuntime& gc) : gc_(gc) {
-        if (!gc_.isIncrementalGCInProgress())
-            gc_.callGCCallback(JSGC_BEGIN);
-    }
-    ~AutoNotifyGCActivity() {
-        if (!gc_.isIncrementalGCInProgress())
-            gc_.callGCCallback(JSGC_END);
-    }
-
-  private:
-    GCRuntime& gc_;
-};
-
-} // (anon)
-
 bool
 GCRuntime::addFinalizeCallback(JSFinalizeCallback callback, void* data)
 {
     return finalizeCallbacks.ref().append(Callback<JSFinalizeCallback>(callback, data));
 }
 
 void
 GCRuntime::removeFinalizeCallback(JSFinalizeCallback callback)
@@ -7100,30 +7082,77 @@ class AutoScheduleZonesForGC
     ~AutoScheduleZonesForGC() {
         for (ZonesIter zone(rt_, WithAtoms); !zone.done(); zone.next())
             zone->unscheduleGC();
     }
 };
 
 } /* anonymous namespace */
 
+class js::gc::AutoCallGCCallbacks {
+    GCRuntime& gc_;
+
+  public:
+    explicit AutoCallGCCallbacks(GCRuntime& gc) : gc_(gc) {
+        gc_.maybeCallBeginCallback();
+    }
+    ~AutoCallGCCallbacks() {
+        gc_.maybeCallEndCallback();
+    }
+};
+
+void
+GCRuntime::maybeCallBeginCallback()
+{
+    if (isIncrementalGCInProgress())
+        return;
+
+    if (gcBeginCallbackDepth == 0) {
+        // Save scheduled zone information in case the callback changes it.
+        for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
+            zone->gcScheduledSaved_ = zone->gcScheduled_;
+    }
+
+    gcBeginCallbackDepth++;
+
+    callGCCallback(JSGC_BEGIN);
+
+    MOZ_ASSERT(gcBeginCallbackDepth != 0);
+    gcBeginCallbackDepth--;
+
+    if (gcBeginCallbackDepth == 0) {
+        // Restore scheduled zone information again.
+        for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
+            zone->gcScheduled_ = zone->gcScheduledSaved_;
+    }
+}
+
+void
+GCRuntime::maybeCallEndCallback()
+{
+    if (isIncrementalGCInProgress())
+        return;
+
+    callGCCallback(JSGC_END);
+}
+
 /*
  * Run one GC "cycle" (either a slice of incremental GC or an entire
  * non-incremental GC. We disable inlining to ensure that the bottom of the
  * stack with possible GC roots recorded in MarkRuntime excludes any pointers we
  * use during the marking implementation.
  *
  * Returns true if we "reset" an existing incremental GC, which would force us
  * to run another cycle.
  */
 MOZ_NEVER_INLINE GCRuntime::IncrementalResult
 GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason)
 {
-    // Note that the following is allowed to re-enter GC in the finalizer.
-    AutoNotifyGCActivity notify(*this);
+    // Note that GC callbacks are allowed to re-enter GC.
+    AutoCallGCCallbacks callCallbacks(*this);
 
     gcstats::AutoGCSlice agc(stats(), scanZonesBeforeGC(), invocationKind, budget, reason);
 
     minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY_FOR_MAJOR_GC);
 
     AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
 
     majorGCTriggerReason = JS::gcreason::NO_REASON;
--- a/js/src/vm/GeckoProfiler.cpp
+++ b/js/src/vm/GeckoProfiler.cpp
@@ -64,24 +64,33 @@ GeckoProfilerRuntime::setEventMarker(voi
 
 // Get a pointer to the top-most profiling frame, given the exit frame pointer.
 static void*
 GetTopProfilingJitFrame(Activation* act)
 {
     if (!act || !act->isJit())
         return nullptr;
 
-    // For null exitFrame, there is no previous exit frame, just return.
-    uint8_t* jsExitFP = act->asJit()->jsExitFP();
-    if (!jsExitFP)
+    jit::JitActivation* jitActivation = act->asJit();
+
+    // If there is no exit frame set, just return.
+    if (!jitActivation->hasExitFP())
         return nullptr;
 
-    jit::JSJitProfilingFrameIterator iter(jsExitFP);
-    MOZ_ASSERT(!iter.done());
-    return iter.fp();
+    // Skip wasm frames that might be in the way.
+    JitFrameIter iter(jitActivation);
+    while (!iter.done() && iter.isWasm())
+        ++iter;
+
+    if (!iter.isJSJit())
+        return nullptr;
+
+    jit::JSJitProfilingFrameIterator jitIter(iter.asJSJit().fp());
+    MOZ_ASSERT(!jitIter.done());
+    return jitIter.fp();
 }
 
 void
 GeckoProfilerRuntime::enable(bool enabled)
 {
 #ifdef DEBUG
     // All cooperating contexts must have profile stacks installed before the
     // profiler can be enabled. Cooperating threads created while the profiler
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -3130,19 +3130,16 @@ CASE(JSOP_FUNCALL)
                 }
             }
         }
 
         funScript = fun->nonLazyScript();
 
         if (!activation.pushInlineFrame(args, funScript, construct))
             goto error;
-
-        if (createSingleton)
-            REGS.fp()->setCreateSingleton();
     }
 
     SET_SCRIPT(REGS.fp()->script());
 
     {
         TraceLoggerEvent event(TraceLogger_Scripts, script);
         TraceLogStartEvent(logger, event);
         TraceLogStartEvent(logger, TraceLogger_Interpreter);
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -741,17 +741,17 @@ NativeObject::putProperty(JSContext* cx,
 
     /*
      * If the caller wants to allocate a slot, but doesn't care which slot,
      * copy the existing shape's slot into slot so we can match shape, if all
      * other members match.
      */
     bool hadSlot = shape->isDataProperty();
     uint32_t oldSlot = shape->maybeSlot();
-    bool needSlot = !getter && !setter;
+    bool needSlot = Shape::isDataProperty(attrs, getter, setter);
     if (needSlot && slot == SHAPE_INVALID_SLOT && hadSlot)
         slot = oldSlot;
 
     Rooted<UnownedBaseShape*> nbase(cx);
     {
         RootedShape shape(cx, obj->lastProperty());
         nbase = GetBaseShapeForNewShape(cx, shape, id);
         if (!nbase)
@@ -784,17 +784,17 @@ NativeObject::putProperty(JSContext* cx,
     if (obj->inDictionaryMode()) {
         /*
          * Updating some property in a dictionary-mode object. Create a new
          * shape for the existing property, and also generate a new shape for
          * the last property of the dictionary (unless the modified property
          * is also the last property).
          */
         bool updateLast = (shape == obj->lastProperty());
-        bool accessorShape = getter || setter || (attrs & (JSPROP_GETTER | JSPROP_SETTER));
+        bool accessorShape = !Shape::isDataProperty(attrs, getter, setter);
         shape = NativeObject::replaceWithNewEquivalentShape(cx, obj, shape, nullptr,
                                                             accessorShape);
         if (!shape)
             return nullptr;
         if (!updateLast && !NativeObject::generateOwnShape(cx, obj))
             return nullptr;
 
         /*
@@ -867,17 +867,17 @@ NativeObject::putProperty(JSContext* cx,
 /* static */ Shape*
 NativeObject::changeProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
                              unsigned attrs, GetterOp getter, SetterOp setter)
 {
     MOZ_ASSERT(obj->containsPure(shape));
 
     /* Allow only shared (slotless) => unshared (slotful) transition. */
 #ifdef DEBUG
-    bool needSlot = !getter && !setter;
+    bool needSlot = Shape::isDataProperty(attrs, getter, setter);
     MOZ_ASSERT_IF(shape->isDataProperty() != needSlot, needSlot);
 #endif
 
     MarkTypePropertyNonData(cx, obj, shape->propid());
 
     AssertCanChangeAttrs(shape, attrs);
 
     if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1008,19 +1008,23 @@ class Shape : public gc::TenuredCell
                maybeSlot() == aslot &&
                attrs == aattrs &&
                getter() == rawGetter &&
                setter() == rawSetter;
     }
 
     BaseShape* base() const { return base_.get(); }
 
+    static bool isDataProperty(unsigned attrs, GetterOp getter, SetterOp setter) {
+        return !(attrs & (JSPROP_GETTER | JSPROP_SETTER)) && !getter && !setter;
+    }
+
     bool isDataProperty() const {
         MOZ_ASSERT(!isEmptyShape());
-        return !getter() && !setter();
+        return isDataProperty(attrs, getter(), setter());
     }
     uint32_t slot() const { MOZ_ASSERT(isDataProperty() && !hasMissingSlot()); return maybeSlot(); }
     uint32_t maybeSlot() const {
         return slotInfo & SLOT_MASK;
     }
 
     bool isEmptyShape() const {
         MOZ_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
@@ -1471,17 +1475,17 @@ struct StackShape
             flags &= ~Shape::ACCESSOR_SHAPE;
 
         this->rawGetter = rawGetter;
         this->rawSetter = rawSetter;
     }
 
     bool isDataProperty() const {
         MOZ_ASSERT(!JSID_IS_EMPTY(propid));
-        return !rawGetter && !rawSetter;
+        return Shape::isDataProperty(attrs, rawGetter, rawSetter);
     }
     bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
 
     uint32_t slot() const { MOZ_ASSERT(isDataProperty() && !hasMissingSlot()); return slot_; }
     uint32_t maybeSlot() const { return slot_; }
 
     void setSlot(uint32_t slot) {
         MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -558,24 +558,16 @@ AbstractFramePtr::hasInitialEnvironment(
     if (isInterpreterFrame())
         return asInterpreterFrame()->hasInitialEnvironment();
     if (isBaselineFrame())
         return asBaselineFrame()->hasInitialEnvironment();
     return asRematerializedFrame()->hasInitialEnvironment();
 }
 
 inline bool
-AbstractFramePtr::createSingleton() const
-{
-    if (isInterpreterFrame())
-        return asInterpreterFrame()->createSingleton();
-    return false;
-}
-
-inline bool
 AbstractFramePtr::isGlobalFrame() const
 {
     if (isInterpreterFrame())
         return asInterpreterFrame()->isGlobalFrame();
     if (isBaselineFrame())
         return asBaselineFrame()->isGlobalFrame();
     if (isWasmDebugFrame())
         return false;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -265,17 +265,16 @@ class AbstractFramePtr
     inline unsigned numFormalArgs() const;
 
     inline Value* argv() const;
 
     inline bool hasArgs() const;
     inline bool hasArgsObj() const;
     inline ArgumentsObject& argsObj() const;
     inline void initArgsObj(ArgumentsObject& argsobj) const;
-    inline bool createSingleton() const;
 
     inline Value& unaliasedLocal(uint32_t i);
     inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
 
     inline bool prevUpToDate() const;
     inline void setPrevUpToDate() const;
@@ -334,25 +333,22 @@ class InterpreterFrame
         HAS_PUSHED_PROF_FRAME  =       0x80,  /* Gecko Profiler was notified of entry */
 
         /*
          * If set, we entered one of the JITs and ScriptFrameIter should skip
          * this frame.
          */
         RUNNING_IN_JIT         =      0x100,
 
-        /* Miscellaneous state. */
-        CREATE_SINGLETON       =      0x200,  /* Constructed |this| object should be singleton. */
-
         /*
          * If set, this frame has been on the stack when
          * |js::SavedStacks::saveCurrentStack| was called, and so there is a
          * |js::SavedFrame| object cached for this frame.
          */
-        HAS_CACHED_SAVED_FRAME =      0x400,
+        HAS_CACHED_SAVED_FRAME =      0x200,
     };
 
     mutable uint32_t    flags_;         /* bits described by Flags */
     uint32_t            nactual_;       /* number of actual arguments, for function frames */
     JSScript*           script_;        /* the script we're executing */
     JSObject*           envChain_;      /* current environment chain */
     Value               rval_;          /* if HAS_RVAL, return value of the frame */
     ArgumentsObject*    argsObj_;       /* if HAS_ARGS_OBJ, the call's arguments object */
@@ -754,25 +750,16 @@ class InterpreterFrame
         return flags_ & HAS_INITIAL_ENV;
     }
 
     bool hasArgsObj() const {
         MOZ_ASSERT(script()->needsArgsObj());
         return flags_ & HAS_ARGS_OBJ;
     }
 
-    void setCreateSingleton() {
-        MOZ_ASSERT(isConstructing());
-        flags_ |= CREATE_SINGLETON;
-    }
-    bool createSingleton() const {
-        MOZ_ASSERT(isConstructing());
-        return flags_ & CREATE_SINGLETON;
-    }
-
     /*
      * Debugger eval frames.
      *
      * - If evalInFramePrev_ is non-null, frame was created for an "eval in
      *   frame" call, which can push a successor to any live frame; so its
      *   logical "prev" frame is not necessarily the previous frame in memory.
      *   Iteration should treat evalInFramePrev_ as this frame's previous frame.
      *
--- a/js/src/wasm/WasmBuiltins.cpp
+++ b/js/src/wasm/WasmBuiltins.cpp
@@ -287,38 +287,44 @@ WasmReportOutOfBounds()
 static void
 WasmReportUnalignedAccess()
 {
     JSContext* cx = TlsContext.get();
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNALIGNED_ACCESS);
 }
 
 static int32_t
-CoerceInPlace_ToInt32(MutableHandleValue val)
+CoerceInPlace_ToInt32(Value* rawVal)
 {
     JSContext* cx = TlsContext.get();
 
     int32_t i32;
-    if (!ToInt32(cx, val, &i32))
+    RootedValue val(cx, *rawVal);
+    if (!ToInt32(cx, val, &i32)) {
+        *rawVal = PoisonedObjectValue(0x42);
         return false;
-    val.set(Int32Value(i32));
+    }
 
+    *rawVal = Int32Value(i32);
     return true;
 }
 
 static int32_t
-CoerceInPlace_ToNumber(MutableHandleValue val)
+CoerceInPlace_ToNumber(Value* rawVal)
 {
     JSContext* cx = TlsContext.get();
 
     double dbl;
-    if (!ToNumber(cx, val, &dbl))
+    RootedValue val(cx, *rawVal);
+    if (!ToNumber(cx, val, &dbl)) {
+        *rawVal = PoisonedObjectValue(0x42);
         return false;
-    val.set(DoubleValue(dbl));
+    }
 
+    *rawVal = DoubleValue(dbl);
     return true;
 }
 
 static int64_t
 DivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
 {
     int64_t x = ((uint64_t)x_hi << 32) + x_lo;
     int64_t y = ((uint64_t)y_hi << 32) + y_lo;
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -765,16 +765,25 @@ GenerateImportJitExit(MacroAssembler& ma
     masm.loadBaselineOrIonNoArgCheck(callee, callee, nullptr);
 
     Label rejoinBeforeCall;
     masm.bind(&rejoinBeforeCall);
 
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
     masm.callJitNoProfiler(callee);
 
+    // Note that there might be a GC thing in the JSReturnOperand now.
+    // In all the code paths from here:
+    // - either the value is unboxed because it was a primitive and we don't
+    //   need to worry about rooting anymore.
+    // - or the value needs to be rooted, but nothing can cause a GC between
+    //   here and CoerceInPlace, which roots before coercing to a primitive.
+    //   In particular, this is true because wasm::InInterruptibleCode will
+    //   return false when PC is in the jit exit.
+
     // The JIT callee clobbers all registers, including WasmTlsReg and
     // FramePointer, so restore those here. During this sequence of
     // instructions, FP can't be trusted by the profiling frame iterator.
     offsets->untrustedFPStart = masm.currentOffset();
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
 
     masm.loadWasmTlsRegFromFrame();
     masm.moveStackPtrTo(FramePointer);
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -637,27 +637,27 @@ nsPageFrame::PaintHeaderFooter(gfxContex
   nscoord visibleHeight = 0;
   if (fontMet) {
     visibleHeight = fontMet->MaxHeight();
     ascent = fontMet->MaxAscent();
   }
 
   // print document headers and footers
   nsString headerLeft, headerCenter, headerRight;
-  mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
-  mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
-  mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
+  mPD->mPrintSettings->GetHeaderStrLeft(headerLeft);
+  mPD->mPrintSettings->GetHeaderStrCenter(headerCenter);
+  mPD->mPrintSettings->GetHeaderStrRight(headerRight);
   DrawHeaderFooter(aRenderingContext, *fontMet, eHeader,
                    headerLeft, headerCenter, headerRight,
                    rect, ascent, visibleHeight);
 
   nsString footerLeft, footerCenter, footerRight;
-  mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
-  mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
-  mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
+  mPD->mPrintSettings->GetFooterStrLeft(footerLeft);
+  mPD->mPrintSettings->GetFooterStrCenter(footerCenter);
+  mPD->mPrintSettings->GetFooterStrRight(footerRight);
   DrawHeaderFooter(aRenderingContext, *fontMet, eFooter,
                    footerLeft, footerCenter, footerRight,
                    rect, ascent, visibleHeight);
 }
 
 void
 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
 {
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -1006,29 +1006,29 @@ nsPrintEngine::CheckForPrinters(nsIPrint
   if (!XRE_IsParentProcess()) {
     return NS_OK;
   }
 #endif
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   // See if aPrintSettings already has a printer
   nsString printerName;
-  nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName));
+  nsresult rv = aPrintSettings->GetPrinterName(printerName);
   if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
     return NS_OK;
   }
 
   // aPrintSettings doesn't have a printer set. Try to fetch the default.
   nsCOMPtr<nsIPrintSettingsService> printSettingsService =
     do_GetService(sPrintSettingsServiceContractID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
+  rv = printSettingsService->GetDefaultPrinterName(printerName);
   if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
-    rv = aPrintSettings->SetPrinterName(printerName.get());
+    rv = aPrintSettings->SetPrinterName(printerName);
   }
   return rv;
 #endif
 }
 
 //----------------------------------------------------------------------
 // Set up to use the "pluggable" Print Progress Dialog
 void
@@ -1450,31 +1450,18 @@ nsPrintEngine::GetDisplayTitleAndURL(con
     return;
 
   aTitle.Truncate();
   aURLStr.Truncate();
 
   // First check to see if the PrintSettings has defined an alternate title
   // and use that if it did
   if (mPrt->mPrintSettings) {
-    char16_t * docTitleStrPS = nullptr;
-    char16_t * docURLStrPS   = nullptr;
-    mPrt->mPrintSettings->GetTitle(&docTitleStrPS);
-    mPrt->mPrintSettings->GetDocURL(&docURLStrPS);
-
-    if (docTitleStrPS) {
-      aTitle = docTitleStrPS;
-    }
-
-    if (docURLStrPS) {
-      aURLStr = docURLStrPS;
-    }
-
-    free(docTitleStrPS);
-    free(docURLStrPS);
+    mPrt->mPrintSettings->GetTitle(aTitle);
+    mPrt->mPrintSettings->GetDocURL(aURLStr);
   }
 
   nsAutoString docTitle;
   nsAutoString docUrl;
   GetDocumentTitleAndURL(aPO->mDocument, docTitle, docUrl);
 
   if (aURLStr.IsEmpty() && !docUrl.IsEmpty()) {
     aURLStr = docUrl;
@@ -1823,17 +1810,17 @@ nsPrintEngine::SetupToPrintContent()
   }
 
   nsAutoString fileNameStr;
   // check to see if we are printing to a file
   bool isPrintToFile = false;
   printData->mPrintSettings->GetPrintToFile(&isPrintToFile);
   if (isPrintToFile) {
     // On some platforms The BeginDocument needs to know the name of the file.
-    printData->mPrintSettings->GetToFileName(getter_Copies(fileNameStr));
+    printData->mPrintSettings->GetToFileName(fileNameStr);
   }
 
   nsAutoString docTitleStr;
   nsAutoString docURLStr;
   GetDisplayTitleAndURL(printData->mPrintObject, docTitleStr, docURLStr,
                         eDocTitleDefURLDoc);
 
   int32_t startPage = 1;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2107,17 +2107,17 @@ pref("network.ftp.idleConnectionTimeout"
 // 3: XUL directory viewer
 // all other values are treated like 2
 pref("network.dir.format", 2);
 
 // enables the prefetch service (i.e., prefetching of <link rel="next"> and
 // <link rel="prefetch"> URLs).
 pref("network.prefetch-next", true);
 // enables the preloading (i.e., preloading of <link rel="preload"> URLs).
-pref("network.preload", true);
+pref("network.preload", false);
 
 // enables the predictive service
 pref("network.predictor.enabled", true);
 pref("network.predictor.enable-hover-on-ssl", false);
 pref("network.predictor.enable-prefetch", false);
 pref("network.predictor.page-degradation.day", 0);
 pref("network.predictor.page-degradation.week", 5);
 pref("network.predictor.page-degradation.month", 10);
--- a/rdf/base/nsIRDFXMLSerializer.idl
+++ b/rdf/base/nsIRDFXMLSerializer.idl
@@ -2,27 +2,30 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIRDFDataSource.idl"
 
-interface nsAtom;  // not a real interface; used in [noscript] methods only
+%{C++
+class nsAtom;
+%}
+[ptr] native nsAtomPtr(nsAtom);
 
 [scriptable, uuid(8ae1fbf8-1dd2-11b2-bd21-d728069cca92)]
 interface nsIRDFXMLSerializer : nsISupports
 {
     /**
      * Initialize the serializer with the specified datasource.
      * @param aDataSource the datasource from which data will be
      *   serialized
      */
     void init(in nsIRDFDataSource aDataSource);
 
     /**
      * Add the specified namespace to the serializer.
      * @param aPrefix the attribute namespace prefix
      * @param aURI the namespace URI
      */
-    [noscript] void addNameSpace(in nsAtom aPrefix, in DOMString aURI);
+    [noscript] void addNameSpace(in nsAtomPtr aPrefix, in DOMString aURI);
 };
--- a/rdf/base/nsIRDFXMLSink.idl
+++ b/rdf/base/nsIRDFXMLSink.idl
@@ -7,17 +7,20 @@
 
   Interfaces for the RDF/XML sink, which parses RDF/XML into
   a graph representation.
 
 */
 
 #include "nsISupports.idl"
 
-interface nsAtom;  // not a real interface; used in [noscript] methods only
+%{C++
+class nsAtom;
+%}
+[ptr] native nsAtomPtr(nsAtom);
 
 // XXX Until these get scriptable. See nsIRDFXMLSink::AddNameSpace()
 [ref] native nsStringRef(nsString);
 %{C++
 #include "nsStringFwd.h"
 %}
 
 interface nsIRDFXMLSink;
@@ -97,17 +100,17 @@ interface nsIRDFXMLSink : nsISupports
      */
     void endLoad();
 
     /**
      * Add namespace information to the RDF/XML sink.
      * @param aPrefix the namespace prefix
      * @param aURI the namespace URI
      */
-    [noscript] void addNameSpace(in nsAtom aPrefix,
+    [noscript] void addNameSpace(in nsAtomPtr aPrefix,
                                  [const] in nsStringRef aURI);
 
     /**
      * Add an observer that will be notified as the RDF/XML load
      * progresses.
      * <p>
      *
      * Note that the sink will acquire a strong reference to the
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-6fb9c5396d52
+f3766809817b
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc
@@ -10,145 +10,159 @@
 #include "gtest/gtest.h"
 #include "scoped_ptrs.h"
 
 #include "pk11_ecdsa_vectors.h"
 #include "pk11_signature_test.h"
 
 namespace nss_test {
 
-class Pkcs11EcdsaTest : public Pk11SignatureTest {
+class Pkcs11EcdsaTestBase : public Pk11SignatureTest {
  protected:
-  CK_MECHANISM_TYPE mechanism() { return CKM_ECDSA; }
-  SECItem* parameters() { return nullptr; }
+  Pkcs11EcdsaTestBase(SECOidTag hash_oid)
+      : Pk11SignatureTest(CKM_ECDSA, hash_oid) {}
 };
 
-class Pkcs11EcdsaSha256Test : public Pkcs11EcdsaTest {
- protected:
-  SECOidTag hashOID() { return SEC_OID_SHA256; }
+struct Pkcs11EcdsaTestParams {
+  SECOidTag hash_oid_;
+  Pkcs11SignatureTestParams sig_params_;
 };
 
-class Pkcs11EcdsaSha384Test : public Pkcs11EcdsaTest {
- protected:
-  SECOidTag hashOID() { return SEC_OID_SHA384; }
-};
-
-class Pkcs11EcdsaSha512Test : public Pkcs11EcdsaTest {
- protected:
-  SECOidTag hashOID() { return SEC_OID_SHA512; }
+class Pkcs11EcdsaTest
+    : public Pkcs11EcdsaTestBase,
+      public ::testing::WithParamInterface<Pkcs11EcdsaTestParams> {
+ public:
+  Pkcs11EcdsaTest() : Pkcs11EcdsaTestBase(GetParam().hash_oid_) {}
 };
 
-TEST_F(Pkcs11EcdsaSha256Test, VerifyP256) {
-  SIG_TEST_VECTOR_VERIFY(kP256Spki, kP256Data, kP256Signature)
-}
-TEST_F(Pkcs11EcdsaSha256Test, SignAndVerifyP256) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kP256Pkcs8, kP256Spki, kP256Data)
+TEST_P(Pkcs11EcdsaTest, Verify) { Verify(GetParam().sig_params_); }
+
+TEST_P(Pkcs11EcdsaTest, SignAndVerify) {
+  SignAndVerify(GetParam().sig_params_);
 }
 
-TEST_F(Pkcs11EcdsaSha384Test, VerifyP384) {
-  SIG_TEST_VECTOR_VERIFY(kP384Spki, kP384Data, kP384Signature)
-}
-TEST_F(Pkcs11EcdsaSha384Test, SignAndVerifyP384) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kP384Pkcs8, kP384Spki, kP384Data)
-}
+static const Pkcs11EcdsaTestParams kEcdsaVectors[] = {
+    {SEC_OID_SHA256,
+     {DataBuffer(kP256Pkcs8, sizeof(kP256Pkcs8)),
+      DataBuffer(kP256Spki, sizeof(kP256Spki)),
+      DataBuffer(kP256Data, sizeof(kP256Data)),
+      DataBuffer(kP256Signature, sizeof(kP256Signature))}},
+    {SEC_OID_SHA384,
+     {DataBuffer(kP384Pkcs8, sizeof(kP384Pkcs8)),
+      DataBuffer(kP384Spki, sizeof(kP384Spki)),
+      DataBuffer(kP384Data, sizeof(kP384Data)),
+      DataBuffer(kP384Signature, sizeof(kP384Signature))}},
+    {SEC_OID_SHA512,
+     {DataBuffer(kP521Pkcs8, sizeof(kP521Pkcs8)),
+      DataBuffer(kP521Spki, sizeof(kP521Spki)),
+      DataBuffer(kP521Data, sizeof(kP521Data)),
+      DataBuffer(kP521Signature, sizeof(kP521Signature))}}};
 
-TEST_F(Pkcs11EcdsaSha512Test, VerifyP521) {
-  SIG_TEST_VECTOR_VERIFY(kP521Spki, kP521Data, kP521Signature)
-}
-TEST_F(Pkcs11EcdsaSha512Test, SignAndVerifyP521) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kP521Pkcs8, kP521Spki, kP521Data)
-}
+INSTANTIATE_TEST_CASE_P(EcdsaSignVerify, Pkcs11EcdsaTest,
+                        ::testing::ValuesIn(kEcdsaVectors));
+
+class Pkcs11EcdsaSha256Test : public Pkcs11EcdsaTestBase {
+ public:
+  Pkcs11EcdsaSha256Test() : Pkcs11EcdsaTestBase(SEC_OID_SHA256) {}
+};
 
 // Importing a private key in PKCS#8 format must fail when the outer AlgID
 // struct contains neither id-ecPublicKey nor a namedCurve parameter.
 TEST_F(Pkcs11EcdsaSha256Test, ImportNoCurveOIDOrAlgorithmParams) {
-  EXPECT_FALSE(ImportPrivateKey(kP256Pkcs8NoCurveOIDOrAlgorithmParams,
-                                sizeof(kP256Pkcs8NoCurveOIDOrAlgorithmParams)));
+  DataBuffer k(kP256Pkcs8NoCurveOIDOrAlgorithmParams,
+               sizeof(kP256Pkcs8NoCurveOIDOrAlgorithmParams));
+  EXPECT_FALSE(ImportPrivateKey(k));
 };
 
 // Importing a private key in PKCS#8 format must succeed when only the outer
 // AlgID struct contains the namedCurve parameters.
 TEST_F(Pkcs11EcdsaSha256Test, ImportOnlyAlgorithmParams) {
-  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(
-      kP256Pkcs8OnlyAlgorithmParams, sizeof(kP256Pkcs8OnlyAlgorithmParams),
-      kP256Data, sizeof(kP256Data)));
+  DataBuffer k(kP256Pkcs8OnlyAlgorithmParams,
+               sizeof(kP256Pkcs8OnlyAlgorithmParams));
+  DataBuffer data(kP256Data, sizeof(kP256Data));
+  DataBuffer sig;
+  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig));
 };
 
 // Importing a private key in PKCS#8 format must succeed when the outer AlgID
 // struct and the inner ECPrivateKey contain the same namedCurve parameters.
 // The inner curveOID is always ignored, so only the outer one will be used.
 TEST_F(Pkcs11EcdsaSha256Test, ImportMatchingCurveOIDAndAlgorithmParams) {
-  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(
-      kP256Pkcs8MatchingCurveOIDAndAlgorithmParams,
-      sizeof(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams), kP256Data,
-      sizeof(kP256Data)));
+  DataBuffer k(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams,
+               sizeof(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams));
+  DataBuffer data(kP256Data, sizeof(kP256Data));
+  DataBuffer sig;
+  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig));
 };
 
 // Importing a private key in PKCS#8 format must succeed when the outer AlgID
 // struct and the inner ECPrivateKey contain dissimilar namedCurve parameters.
 // The inner curveOID is always ignored, so only the outer one will be used.
 TEST_F(Pkcs11EcdsaSha256Test, ImportDissimilarCurveOIDAndAlgorithmParams) {
-  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(
-      kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams,
-      sizeof(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams), kP256Data,
-      sizeof(kP256Data)));
+  DataBuffer k(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams,
+               sizeof(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams));
+  DataBuffer data(kP256Data, sizeof(kP256Data));
+  DataBuffer sig;
+  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig));
 };
 
 // Importing a private key in PKCS#8 format must fail when the outer ASN.1
 // AlgorithmID struct contains only id-ecPublicKey but no namedCurve parameter.
 TEST_F(Pkcs11EcdsaSha256Test, ImportNoAlgorithmParams) {
-  EXPECT_FALSE(ImportPrivateKey(kP256Pkcs8NoAlgorithmParams,
-                                sizeof(kP256Pkcs8NoAlgorithmParams)));
+  DataBuffer k(kP256Pkcs8NoAlgorithmParams,
+               sizeof(kP256Pkcs8NoAlgorithmParams));
+  EXPECT_FALSE(ImportPrivateKey(k));
 };
 
 // Importing a private key in PKCS#8 format must fail when id-ecPublicKey is
 // given (so we know it's an EC key) but the namedCurve parameter is unknown.
 TEST_F(Pkcs11EcdsaSha256Test, ImportInvalidAlgorithmParams) {
-  EXPECT_FALSE(ImportPrivateKey(kP256Pkcs8InvalidAlgorithmParams,
-                                sizeof(kP256Pkcs8InvalidAlgorithmParams)));
+  DataBuffer k(kP256Pkcs8InvalidAlgorithmParams,
+               sizeof(kP256Pkcs8InvalidAlgorithmParams));
+  EXPECT_FALSE(ImportPrivateKey(k));
 };
 
 // Importing a private key in PKCS#8 format with a point not on the curve will
 // succeed. Using the contained public key however will fail when trying to
 // import it before using it for any operation.
 TEST_F(Pkcs11EcdsaSha256Test, ImportPointNotOnCurve) {
-  ScopedSECKEYPrivateKey privKey(ImportPrivateKey(
-      kP256Pkcs8PointNotOnCurve, sizeof(kP256Pkcs8PointNotOnCurve)));
+  DataBuffer k(kP256Pkcs8PointNotOnCurve, sizeof(kP256Pkcs8PointNotOnCurve));
+  ScopedSECKEYPrivateKey privKey(ImportPrivateKey(k));
   ASSERT_TRUE(privKey);
 
   ScopedSECKEYPublicKey pubKey(SECKEY_ConvertToPublicKey(privKey.get()));
   ASSERT_TRUE(pubKey);
 
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   ASSERT_TRUE(slot);
 
   auto handle = PK11_ImportPublicKey(slot.get(), pubKey.get(), false);
   EXPECT_EQ(handle, static_cast<decltype(handle)>(CK_INVALID_HANDLE));
 };
 
 // Importing a private key in PKCS#8 format must fail when no point is given.
 // PK11 currently offers no APIs to derive raw public keys from private values.
 TEST_F(Pkcs11EcdsaSha256Test, ImportNoPublicKey) {
-  EXPECT_FALSE(
-      ImportPrivateKey(kP256Pkcs8NoPublicKey, sizeof(kP256Pkcs8NoPublicKey)));
+  DataBuffer k(kP256Pkcs8NoPublicKey, sizeof(kP256Pkcs8NoPublicKey));
+  EXPECT_FALSE(ImportPrivateKey(k));
 };
 
 // Importing a public key in SPKI format must fail when id-ecPublicKey is
 // given (so we know it's an EC key) but the namedCurve parameter is missing.
 TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiNoAlgorithmParams) {
-  EXPECT_FALSE(ImportPublicKey(kP256SpkiNoAlgorithmParams,
-                               sizeof(kP256SpkiNoAlgorithmParams)));
+  DataBuffer k(kP256SpkiNoAlgorithmParams, sizeof(kP256SpkiNoAlgorithmParams));
+  EXPECT_FALSE(ImportPublicKey(k));
 }
 
 // Importing a public key in SPKI format with a point not on the curve will
 // succeed. Using the public key however will fail when trying to import
 // it before using it for any operation.
 TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiPointNotOnCurve) {
-  ScopedSECKEYPublicKey pubKey(ImportPublicKey(
-      kP256SpkiPointNotOnCurve, sizeof(kP256SpkiPointNotOnCurve)));
+  DataBuffer k(kP256SpkiPointNotOnCurve, sizeof(kP256SpkiPointNotOnCurve));
+  ScopedSECKEYPublicKey pubKey(ImportPublicKey(k));
   ASSERT_TRUE(pubKey);
 
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   ASSERT_TRUE(slot);
 
   auto handle = PK11_ImportPublicKey(slot.get(), pubKey.get(), false);
   EXPECT_EQ(handle, static_cast<decltype(handle)>(CK_INVALID_HANDLE));
 }
--- a/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc
@@ -7,44 +7,42 @@
 #include <memory>
 #include "nss.h"
 #include "pk11pub.h"
 #include "sechash.h"
 
 #include "gtest/gtest.h"
 #include "scoped_ptrs.h"
 
+#include "pk11_signature_test.h"
 #include "pk11_rsapss_vectors.h"
-#include "pk11_signature_test.h"
 
 namespace nss_test {
 
-class Pkcs11RsaPssVectorTest : public Pk11SignatureTest {
+class Pkcs11RsaPssTest : public Pk11SignatureTest {
  public:
-  Pkcs11RsaPssVectorTest() {
+  Pkcs11RsaPssTest() : Pk11SignatureTest(CKM_RSA_PKCS_PSS, SEC_OID_SHA1) {
     rsaPssParams_.hashAlg = CKM_SHA_1;
     rsaPssParams_.mgf = CKG_MGF1_SHA1;
     rsaPssParams_.sLen = HASH_ResultLenByOidTag(SEC_OID_SHA1);
 
     params_.type = siBuffer;
     params_.data = reinterpret_cast<unsigned char*>(&rsaPssParams_);
     params_.len = sizeof(rsaPssParams_);
   }
 
  protected:
-  CK_MECHANISM_TYPE mechanism() { return CKM_RSA_PKCS_PSS; }
-  SECItem* parameters() { return &params_; }
-  SECOidTag hashOID() { return SEC_OID_SHA1; }
+  const SECItem* parameters() const { return &params_; }
 
  private:
   CK_RSA_PKCS_PSS_PARAMS rsaPssParams_;
   SECItem params_;
 };
 
-TEST_F(Pkcs11RsaPssVectorTest, GenerateAndSignAndVerify) {
+TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) {
   // Sign data with a 1024-bit RSA key, using PSS/SHA-256.
   SECOidTag hashOid = SEC_OID_SHA256;
   CK_MECHANISM_TYPE hashMech = CKM_SHA256;
   CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA256;
   PK11RSAGenParams rsaGenParams = {1024, 0x10001};
 
   // Generate RSA key pair.
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
@@ -90,110 +88,61 @@ TEST_F(Pkcs11RsaPssVectorTest, GenerateA
   // Verification with original data but the wrong signature must fail.
   data.data[0] ^= 0xff;  // Revert previous changes.
   sig.data[0] ^= 0xff;
   rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism(), &params, &sig, &data,
                                 nullptr);
   EXPECT_EQ(rv, SECFailure);
 }
 
-// RSA-PSS test vectors, pss-vect.txt, Example 1.1: A 1024-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature1) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector1Spki, kTestVector1Data, kTestVector1Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify1) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector1Pkcs8, kTestVector1Spki,
-                              kTestVector1Data);
-}
+class Pkcs11RsaPssVectorTest
+    : public Pkcs11RsaPssTest,
+      public ::testing::WithParamInterface<Pkcs11SignatureTestParams> {};
 
-// RSA-PSS test vectors, pss-vect.txt, Example 2.1: A 1025-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature2) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector2Spki, kTestVector2Data, kTestVector2Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify2) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector2Pkcs8, kTestVector2Spki,
-                              kTestVector2Data);
-}
+TEST_P(Pkcs11RsaPssVectorTest, Verify) { Verify(GetParam()); }
+
+TEST_P(Pkcs11RsaPssVectorTest, SignAndVerify) { SignAndVerify(GetParam()); }
 
-// RSA-PSS test vectors, pss-vect.txt, Example 3.1: A 1026-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature3) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector3Spki, kTestVector3Data, kTestVector3Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify3) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector3Pkcs8, kTestVector3Spki,
-                              kTestVector3Data);
-}
-
-// RSA-PSS test vectors, pss-vect.txt, Example 4.1: A 1027-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature4) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector4Spki, kTestVector4Data, kTestVector4Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify4) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector4Pkcs8, kTestVector4Spki,
-                              kTestVector4Data);
-}
-
-// RSA-PSS test vectors, pss-vect.txt, Example 5.1: A 1028-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature5) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector5Spki, kTestVector5Data, kTestVector5Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify5) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector5Pkcs8, kTestVector5Spki,
-                              kTestVector5Data);
-}
+#define VECTOR(pkcs8, spki, data, sig)                                \
+  {                                                                   \
+    DataBuffer(pkcs8, sizeof(pkcs8)), DataBuffer(spki, sizeof(spki)), \
+        DataBuffer(data, sizeof(data)), DataBuffer(sig, sizeof(sig))  \
+  }
+#define VECTOR_N(n)                                                         \
+  VECTOR(kTestVector##n##Pkcs8, kTestVector##n##Spki, kTestVector##n##Data, \
+         kTestVector##n##Sig)
 
-// RSA-PSS test vectors, pss-vect.txt, Example 6.1: A 1029-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature6) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector6Spki, kTestVector6Data, kTestVector6Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify6) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector6Pkcs8, kTestVector6Spki,
-                              kTestVector6Data);
-}
-
-// RSA-PSS test vectors, pss-vect.txt, Example 7.1: A 1030-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature7) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector7Spki, kTestVector7Data, kTestVector7Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify7) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector7Pkcs8, kTestVector7Spki,
-                              kTestVector7Data);
-}
+static const Pkcs11SignatureTestParams kRsaPssVectors[] = {
+    // RSA-PSS test vectors, pss-vect.txt, Example 1.1: A 1024-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(1),
+    // RSA-PSS test vectors, pss-vect.txt, Example 2.1: A 1025-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(2),
+    // RSA-PSS test vectors, pss-vect.txt, Example 3.1: A 1026-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(3),
+    // RSA-PSS test vectors, pss-vect.txt, Example 4.1: A 1027-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(4),
+    // RSA-PSS test vectors, pss-vect.txt, Example 5.1: A 1028-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(5),
+    // RSA-PSS test vectors, pss-vect.txt, Example 6.1: A 1029-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(6),
+    // RSA-PSS test vectors, pss-vect.txt, Example 7.1: A 1030-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(7),
+    // RSA-PSS test vectors, pss-vect.txt, Example 8.1: A 1031-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(8),
+    // RSA-PSS test vectors, pss-vect.txt, Example 9.1: A 1536-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(9),
+    // RSA-PSS test vectors, pss-vect.txt, Example 10.1: A 2048-bit RSA Key Pair
+    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
+    VECTOR_N(10)};
 
-// RSA-PSS test vectors, pss-vect.txt, Example 8.1: A 1031-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature8) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector8Spki, kTestVector8Data, kTestVector8Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify8) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector8Pkcs8, kTestVector8Spki,
-                              kTestVector8Data);
-}
-
-// RSA-PSS test vectors, pss-vect.txt, Example 9.1: A 1536-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature9) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector9Spki, kTestVector9Data, kTestVector9Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify9) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector9Pkcs8, kTestVector9Spki,
-                              kTestVector9Data);
-}
-
-// RSA-PSS test vectors, pss-vect.txt, Example 10.1: A 2048-bit RSA Key Pair
-// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
-TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature10) {
-  SIG_TEST_VECTOR_VERIFY(kTestVector10Spki, kTestVector10Data,
-                         kTestVector10Sig);
-}
-TEST_F(Pkcs11RsaPssVectorTest, SignAndVerify10) {
-  SIG_TEST_VECTOR_SIGN_VERIFY(kTestVector10Pkcs8, kTestVector10Spki,
-                              kTestVector10Data);
-}
+INSTANTIATE_TEST_CASE_P(RsaPssSignVerify, Pkcs11RsaPssVectorTest,
+                        ::testing::ValuesIn(kRsaPssVectors));
 
 }  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_signature_test.h
+++ b/security/nss/gtests/pk11_gtest/pk11_signature_test.h
@@ -4,135 +4,133 @@
 
 #include <memory>
 #include "nss.h"
 #include "pk11pub.h"
 #include "sechash.h"
 
 #include "cpputil.h"
 #include "scoped_ptrs.h"
+#include "databuffer.h"
 
 #include "gtest/gtest.h"
 
 namespace nss_test {
 
+// For test vectors.
+struct Pkcs11SignatureTestParams {
+  const DataBuffer pkcs8_;
+  const DataBuffer spki_;
+  const DataBuffer data_;
+  const DataBuffer signature_;
+};
+
 class Pk11SignatureTest : public ::testing::Test {
  protected:
-  virtual CK_MECHANISM_TYPE mechanism() = 0;
-  virtual SECItem* parameters() = 0;
-  virtual SECOidTag hashOID() = 0;
+  Pk11SignatureTest(CK_MECHANISM_TYPE mechanism, SECOidTag hash_oid)
+      : mechanism_(mechanism), hash_oid_(hash_oid) {}
 
-  ScopedSECKEYPrivateKey ImportPrivateKey(const uint8_t* pkcs8,
-                                          size_t pkcs8_len) {
+  virtual const SECItem* parameters() const { return nullptr; }
+  CK_MECHANISM_TYPE mechanism() const { return mechanism_; }
+
+  ScopedSECKEYPrivateKey ImportPrivateKey(const DataBuffer& pkcs8) {
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     if (!slot) {
+      ADD_FAILURE() << "No slot";
       return nullptr;
     }
 
-    SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8),
-                         static_cast<unsigned int>(pkcs8_len)};
+    SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()),
+                         static_cast<unsigned int>(pkcs8.len())};
 
     SECKEYPrivateKey* key = nullptr;
     SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
         slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key,
         nullptr);
 
     if (rv != SECSuccess) {
       return nullptr;
     }
 
     return ScopedSECKEYPrivateKey(key);
   }
 
-  ScopedSECKEYPublicKey ImportPublicKey(const uint8_t* spki, size_t spki_len) {
-    SECItem spkiItem = {siBuffer, toUcharPtr(spki),
-                        static_cast<unsigned int>(spki_len)};
+  ScopedSECKEYPublicKey ImportPublicKey(const DataBuffer& spki) {
+    SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()),
+                        static_cast<unsigned int>(spki.len())};
 
     ScopedCERTSubjectPublicKeyInfo certSpki(
         SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
 
     return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get()));
   }
 
-  ScopedSECItem ComputeHash(const uint8_t* data, size_t len) {
-    unsigned int hLen = HASH_ResultLenByOidTag(hashOID());
-    ScopedSECItem hash(SECITEM_AllocItem(nullptr, nullptr, hLen));
-    if (!hash) {
-      return nullptr;
-    }
-
-    SECStatus rv = PK11_HashBuf(hashOID(), hash->data, data, len);
-    if (rv != SECSuccess) {
-      return nullptr;
-    }
-
-    return hash;
+  bool ComputeHash(const DataBuffer& data, DataBuffer* hash) {
+    hash->Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(hash_oid_)));
+    SECStatus rv =
+        PK11_HashBuf(hash_oid_, hash->data(), data.data(), data.len());
+    return rv == SECSuccess;
   }
 
-  ScopedSECItem SignHashedData(ScopedSECKEYPrivateKey& privKey,
-                               ScopedSECItem& hash) {
-    unsigned int sLen = PK11_SignatureLen(privKey.get());
-    ScopedSECItem sig(SECITEM_AllocItem(nullptr, nullptr, sLen));
-    if (!sig) {
-      return nullptr;
-    }
-
-    SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism(),
-                                          parameters(), sig.get(), hash.get());
-    if (rv != SECSuccess) {
-      return nullptr;
-    }
-
-    return sig;
+  bool SignHashedData(ScopedSECKEYPrivateKey& privKey, const DataBuffer& hash,
+                      DataBuffer* sig) {
+    SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
+                        static_cast<unsigned int>(hash.len())};
+    int sigLen = PK11_SignatureLen(privKey.get());
+    EXPECT_LT(0, sigLen);
+    sig->Allocate(static_cast<size_t>(sigLen));
+    SECItem sigItem = {siBuffer, toUcharPtr(sig->data()),
+                       static_cast<unsigned int>(sig->len())};
+    SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_,
+                                          parameters(), &sigItem, &hashItem);
+    return rv == SECSuccess;
   }
 
-  ScopedSECItem ImportPrivateKeyAndSignHashedData(const uint8_t* pkcs8,
-                                                  size_t pkcs8_len,
-                                                  const uint8_t* data,
-                                                  size_t data_len) {
-    ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8, pkcs8_len));
+  bool ImportPrivateKeyAndSignHashedData(const DataBuffer& pkcs8,
+                                         const DataBuffer& data,
+                                         DataBuffer* sig) {
+    ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8));
     if (!privKey) {
-      return nullptr;
-    }
-
-    ScopedSECItem hash(ComputeHash(data, data_len));
-    if (!hash) {
-      return nullptr;
+      return false;
     }
 
-    return ScopedSECItem(SignHashedData(privKey, hash));
+    DataBuffer hash;
+    if (!ComputeHash(data, &hash)) {
+      ADD_FAILURE() << "Failed to compute hash";
+      return false;
+    }
+    return SignHashedData(privKey, hash, sig);
   }
 
-  void Verify(const uint8_t* spki, size_t spki_len, const uint8_t* data,
-              size_t data_len, const uint8_t* sig, size_t sig_len) {
-    ScopedSECKEYPublicKey pubKey(ImportPublicKey(spki, spki_len));
+  void Verify(const Pkcs11SignatureTestParams& params, const DataBuffer& sig) {
+    ScopedSECKEYPublicKey pubKey(ImportPublicKey(params.spki_));
     ASSERT_TRUE(pubKey);
 
-    ScopedSECItem hash(ComputeHash(data, data_len));
-    ASSERT_TRUE(hash);
-
-    SECItem sigItem = {siBuffer, toUcharPtr(sig),
-                       static_cast<unsigned int>(sig_len)};
+    DataBuffer hash;
+    ASSERT_TRUE(ComputeHash(params.data_, &hash));
 
     // Verify.
+    SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
+                        static_cast<unsigned int>(hash.len())};
+    SECItem sigItem = {siBuffer, toUcharPtr(sig.data()),
+                       static_cast<unsigned int>(sig.len())};
     SECStatus rv = PK11_VerifyWithMechanism(
-        pubKey.get(), mechanism(), parameters(), &sigItem, hash.get(), nullptr);
+        pubKey.get(), mechanism_, parameters(), &sigItem, &hashItem, nullptr);
     EXPECT_EQ(rv, SECSuccess);
   }
 
-  void SignAndVerify(const uint8_t* pkcs8, size_t pkcs8_len,
-                     const uint8_t* spki, size_t spki_len, const uint8_t* data,
-                     size_t data_len) {
-    ScopedSECItem sig(
-        ImportPrivateKeyAndSignHashedData(pkcs8, pkcs8_len, data, data_len));
-    ASSERT_TRUE(sig);
+  void Verify(const Pkcs11SignatureTestParams& params) {
+    Verify(params, params.signature_);
+  }
 
-    Verify(spki, spki_len, data, data_len, sig->data, sig->len);
+  void SignAndVerify(const Pkcs11SignatureTestParams& params) {
+    DataBuffer sig;
+    ASSERT_TRUE(
+        ImportPrivateKeyAndSignHashedData(params.pkcs8_, params.data_, &sig));
+    Verify(params, sig);
   }
+
+ private:
+  CK_MECHANISM_TYPE mechanism_;
+  SECOidTag hash_oid_;
 };
 
-#define SIG_TEST_VECTOR_VERIFY(spki, data, sig) \
-  Verify(spki, sizeof(spki), data, sizeof(data), sig, sizeof(sig));
-
-#define SIG_TEST_VECTOR_SIGN_VERIFY(pkcs8, spki, data) \
-  SignAndVerify(pkcs8, sizeof(pkcs8), spki, sizeof(spki), data, sizeof(data));
-
 }  // namespace nss_test
--- a/security/nss/gtests/softoken_gtest/softoken_gtest.cc
+++ b/security/nss/gtests/softoken_gtest/softoken_gtest.cc
@@ -1,10 +1,12 @@
 #include <cstdlib>
 
+#include "cert.h"
+#include "certdb.h"
 #include "nspr.h"
 #include "nss.h"
 #include "pk11pub.h"
 #include "secerr.h"
 
 #include "scoped_ptrs.h"
 
 #define GTEST_HAS_RTTI 0
@@ -195,16 +197,120 @@ TEST_F(SoftokenTest, CreateObjectChangeT
   EXPECT_EQ(SEC_ERROR_TOKEN_NOT_LOGGED_IN, PORT_GetError());
   ScopedPK11GenericObject obj(PK11_CreateGenericObject(
       slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
   // Because there's no password we can't logout and the operation should have
   // succeeded.
   EXPECT_NE(nullptr, obj);
 }
 
+// This is just any X509 certificate. Its contents don't matter.
+static unsigned char certDER[] = {
+    0x30, 0x82, 0x01, 0xEF, 0x30, 0x82, 0x01, 0x94, 0xA0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x14, 0x49, 0xC4, 0xC4, 0x4A, 0xB6, 0x86, 0x07, 0xA3, 0x06,
+    0xDC, 0x4D, 0xC8, 0xC3, 0xFE, 0xC7, 0x21, 0x3A, 0x2D, 0xE4, 0xDA, 0x30,
+    0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
+    0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C,
+    0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31,
+    0x35, 0x31, 0x31, 0x32, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
+    0x18, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06,
+    0x03, 0x55, 0x04, 0x03, 0x0C, 0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x82,
+    0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
+    0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82,
+    0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBA, 0x88, 0x51, 0xA8, 0x44,
+    0x8E, 0x16, 0xD6, 0x41, 0xFD, 0x6E, 0xB6, 0x88, 0x06, 0x36, 0x10, 0x3D,
+    0x3C, 0x13, 0xD9, 0xEA, 0xE4, 0x35, 0x4A, 0xB4, 0xEC, 0xF5, 0x68, 0x57,
+    0x6C, 0x24, 0x7B, 0xC1, 0xC7, 0x25, 0xA8, 0xE0, 0xD8, 0x1F, 0xBD, 0xB1,
+    0x9C, 0x06, 0x9B, 0x6E, 0x1A, 0x86, 0xF2, 0x6B, 0xE2, 0xAF, 0x5A, 0x75,
+    0x6B, 0x6A, 0x64, 0x71, 0x08, 0x7A, 0xA5, 0x5A, 0xA7, 0x45, 0x87, 0xF7,
+    0x1C, 0xD5, 0x24, 0x9C, 0x02, 0x7E, 0xCD, 0x43, 0xFC, 0x1E, 0x69, 0xD0,
+    0x38, 0x20, 0x29, 0x93, 0xAB, 0x20, 0xC3, 0x49, 0xE4, 0xDB, 0xB9, 0x4C,
+    0xC2, 0x6B, 0x6C, 0x0E, 0xED, 0x15, 0x82, 0x0F, 0xF1, 0x7E, 0xAD, 0x69,
+    0x1A, 0xB1, 0xD3, 0x02, 0x3A, 0x8B, 0x2A, 0x41, 0xEE, 0xA7, 0x70, 0xE0,
+    0x0F, 0x0D, 0x8D, 0xFD, 0x66, 0x0B, 0x2B, 0xB0, 0x24, 0x92, 0xA4, 0x7D,
+    0xB9, 0x88, 0x61, 0x79, 0x90, 0xB1, 0x57, 0x90, 0x3D, 0xD2, 0x3B, 0xC5,
+    0xE0, 0xB8, 0x48, 0x1F, 0xA8, 0x37, 0xD3, 0x88, 0x43, 0xEF, 0x27, 0x16,
+    0xD8, 0x55, 0xB7, 0x66, 0x5A, 0xAA, 0x7E, 0x02, 0x90, 0x2F, 0x3A, 0x7B,
+    0x10, 0x80, 0x06, 0x24, 0xCC, 0x1C, 0x6C, 0x97, 0xAD, 0x96, 0x61, 0x5B,
+    0xB7, 0xE2, 0x96, 0x12, 0xC0, 0x75, 0x31, 0xA3, 0x0C, 0x91, 0xDD, 0xB4,
+    0xCA, 0xF7, 0xFC, 0xAD, 0x1D, 0x25, 0xD3, 0x09, 0xEF, 0xB9, 0x17, 0x0E,
+    0xA7, 0x68, 0xE1, 0xB3, 0x7B, 0x2F, 0x22, 0x6F, 0x69, 0xE3, 0xB4, 0x8A,
+    0x95, 0x61, 0x1D, 0xEE, 0x26, 0xD6, 0x25, 0x9D, 0xAB, 0x91, 0x08, 0x4E,
+    0x36, 0xCB, 0x1C, 0x24, 0x04, 0x2C, 0xBF, 0x16, 0x8B, 0x2F, 0xE5, 0xF1,
+    0x8F, 0x99, 0x17, 0x31, 0xB8, 0xB3, 0xFE, 0x49, 0x23, 0xFA, 0x72, 0x51,
+    0xC4, 0x31, 0xD5, 0x03, 0xAC, 0xDA, 0x18, 0x0A, 0x35, 0xED, 0x8D, 0x02,
+    0x03, 0x01, 0x00, 0x01, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
+    0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20,
+    0x5C, 0x75, 0x51, 0x9F, 0x13, 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20,
+    0xA3, 0xBC, 0x06, 0x30, 0x91, 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64,
+    0xEC, 0xFD, 0xCB, 0x42, 0x80, 0x0A, 0x70, 0xE6, 0x02, 0x21, 0x00, 0x82,
+    0x12, 0xF7, 0xE5, 0xEA, 0x40, 0x27, 0xFD, 0xF7, 0xC0, 0x0E, 0x25, 0xF3,
+    0x3E, 0x34, 0x95, 0x80, 0xB9, 0xA3, 0x38, 0xE0, 0x56, 0x68, 0xDA, 0xE5,
+    0xC1, 0xF5, 0x37, 0xC7, 0xB5, 0xCE, 0x0D};
+
+struct PasswordPair {
+  const char *mInitialPassword;
+  const char *mSecondPassword;
+};
+
+class SoftokenPasswordChangeTest
+    : public SoftokenTest,
+      public ::testing::WithParamInterface<PasswordPair> {};
+
+TEST_P(SoftokenPasswordChangeTest, KeepTrustAfterPasswordChange) {
+  const PasswordPair &passwords = GetParam();
+  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+  ASSERT_TRUE(slot);
+  // Set a password.
+  EXPECT_EQ(SECSuccess,
+            PK11_InitPin(slot.get(), nullptr, passwords.mInitialPassword));
+  SECItem certDERItem = {siBuffer, certDER, sizeof(certDER)};
+  // Import a certificate.
+  ScopedCERTCertificate cert(CERT_NewTempCertificate(
+      CERT_GetDefaultCertDB(), &certDERItem, nullptr, true, true));
+  EXPECT_TRUE(cert);
+  SECStatus result =
+      PK11_ImportCert(slot.get(), cert.get(), CK_INVALID_HANDLE, "test", false);
+  EXPECT_EQ(SECSuccess, result);
+  // Set a trust value.
+  CERTCertTrust trust = {CERTDB_TRUSTED_CLIENT_CA | CERTDB_NS_TRUSTED_CA |
+                             CERTDB_TRUSTED_CA | CERTDB_VALID_CA,
+                         0, 0};
+  result = CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
+  EXPECT_EQ(SECSuccess, result);
+  // Release the certificate to ensure we get it from the DB rather than an
+  // in-memory cache, below.
+  cert = nullptr;
+  // Change the password.
+  result = PK11_ChangePW(slot.get(), passwords.mInitialPassword,
+                         passwords.mSecondPassword);
+  EXPECT_EQ(SECSuccess, result);
+  // Look up the certificate again.
+  ScopedCERTCertificate newCert(
+      PK11_FindCertFromDERCertItem(slot.get(), &certDERItem, nullptr));
+  EXPECT_TRUE(newCert.get());
+  // The trust should be the same as before.
+  CERTCertTrust newTrust = {0, 0, 0};
+  result = CERT_GetCertTrust(newCert.get(), &newTrust);
+  EXPECT_EQ(SECSuccess, result);
+  EXPECT_EQ(trust.sslFlags, newTrust.sslFlags);
+  EXPECT_EQ(trust.emailFlags, newTrust.emailFlags);
+  EXPECT_EQ(trust.objectSigningFlags, newTrust.objectSigningFlags);
+}
+
+static const PasswordPair PASSWORD_CHANGE_TESTS[] = {
+    {"password", ""},           // non-empty to empty password
+    {"", "password"},           // empty to non-empty password
+    {"password", "password2"},  // non-empty to non-empty password
+};
+
+INSTANTIATE_TEST_CASE_P(SoftokenPasswordChangeTests, SoftokenPasswordChangeTest,
+                        ::testing::ValuesIn(PASSWORD_CHANGE_TESTS));
+
 class SoftokenNoDBTest : public ::testing::Test {};
 
 TEST_F(SoftokenNoDBTest, NeedUserInitNoDB) {
   ASSERT_EQ(SECSuccess, NSS_NoDB_Init("."));
   ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
   ASSERT_TRUE(slot);
   EXPECT_EQ(PR_FALSE, PK11_NeedUserInit(slot.get()));
 
--- a/security/nss/lib/softoken/sftkdb.c
+++ b/security/nss/lib/softoken/sftkdb.c
@@ -35,17 +35,17 @@
  * are endian/length independent except those attributes that pass CK_ULONG.
  *
  * The following functions fixes up the CK_ULONG type attributes so that the data
  * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
  * byte order values (big endian).
  */
 #define BBP 8
 
-static PRBool
+PRBool
 sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)
 {
     switch (type) {
         case CKA_CERTIFICATE_CATEGORY:
         case CKA_CERTIFICATE_TYPE:
         case CKA_CLASS:
         case CKA_JAVA_MIDP_SECURITY_DOMAIN:
         case CKA_KEY_GEN_MECHANISM:
@@ -1365,34 +1365,35 @@ sftkdb_SetAttributeValue(SFTKDBHandle *h
     }
 
     ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
     if (ntemplate == NULL) {
         return CKR_HOST_MEMORY;
     }
 
     /* make sure we don't have attributes that conflict with the existing DB */
-    crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID);
+    crv = sftkdb_checkConflicts(db, object->objclass, ntemplate, count,
+                                objectID);
     if (crv != CKR_OK) {
         goto loser;
     }
 
     arena = PORT_NewArena(256);
     if (arena == NULL) {
         crv = CKR_HOST_MEMORY;
         goto loser;
     }
 
     crv = (*db->sdb_Begin)(db);
     if (crv != CKR_OK) {
         goto loser;
     }
     inTransaction = PR_TRUE;
-    crv = sftkdb_setAttributeValue(arena, handle, db,
-                                   objectID, template, count);
+    crv = sftkdb_setAttributeValue(arena, handle, db, objectID, ntemplate,
+                                   count);
     if (crv != CKR_OK) {
         goto loser;
     }
     crv = (*db->sdb_Commit)(db);
 loser:
     if (crv != CKR_OK && inTransaction) {
         (*db->sdb_Abort)(db);
     }
--- a/security/nss/lib/softoken/sftkdbti.h
+++ b/security/nss/lib/softoken/sftkdbti.h
@@ -44,15 +44,16 @@ SECStatus sftkdb_SignAttribute(PLArenaPo
                                CK_OBJECT_HANDLE objectID,
                                CK_ATTRIBUTE_TYPE attrType,
                                SECItem *plainText, SECItem **sigText);
 SECStatus sftkdb_VerifyAttribute(SECItem *passKey,
                                  CK_OBJECT_HANDLE objectID,
                                  CK_ATTRIBUTE_TYPE attrType,
                                  SECItem *plainText, SECItem *sigText);
 
+PRBool sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type);
 void sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value);
 CK_RV sftkdb_Update(SFTKDBHandle *handle, SECItem *key);
 CK_RV sftkdb_PutAttributeSignature(SFTKDBHandle *handle,
                                    SDB *keyTarget, CK_OBJECT_HANDLE objectID,
                                    CK_ATTRIBUTE_TYPE type, SECItem *signText);
 
 #endif
--- a/security/nss/lib/softoken/sftkpwd.c
+++ b/security/nss/lib/softoken/sftkpwd.c
@@ -921,16 +921,23 @@ sftk_updateMacs(PLArenaPool *arena, SFTK
         SECItem *signText;
         SECItem plainText;
         SECStatus rv;
 
         if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)) {
             continue;
         }
 
+        if (authAttrs[i].ulValueLen == sizeof(CK_ULONG) &&
+            sftkdb_isULONGAttribute(authAttrs[i].type)) {
+            CK_ULONG value = *(CK_ULONG *)authAttrs[i].pValue;
+            sftk_ULong2SDBULong(authAttrs[i].pValue, value);
+            authAttrs[i].ulValueLen = SDB_ULONG_SIZE;
+        }
+
         plainText.data = authAttrs[i].pValue;
         plainText.len = authAttrs[i].ulValueLen;
         rv = sftkdb_SignAttribute(arena, newKey, id,
                                   authAttrs[i].type, &plainText, &signText);
         if (rv != SECSuccess) {
             return CKR_GENERAL_ERROR;
         }
         rv = sftkdb_PutAttributeSignature(handle, keyTarget, id,
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -33,20 +33,16 @@
 // processes and so they will be unloaded if they attempt to load.
 const std::vector<std::wstring> kDllsToUnload = {
   // HitmanPro - SurfRight now part of Sophos (bug 1400637)
   L"hmpalert.dll",
 
   // K7 Computing (bug 1400637)
   L"k7pswsen.dll",
 
-  // Symantec (bug 1400637)
-  L"prntm64.dll",
-  L"sysfer.dll",
-
   // Avast Antivirus (bug 1400637)
   L"snxhk64.dll",
   L"snxhk.dll",
 
   // Webroot SecureAnywhere (bug 1400637)
   L"wrusr.dll",
 };
 
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -240,26 +240,27 @@ HistoryStore.prototype = {
                       + record.uri.spec + ": can't add this URI.");
       return false;
     }
 
     // We dupe visits by date and type. So an incoming visit that has
     // the same timestamp and type as a local one won't get applied.
     // To avoid creating new objects, we rewrite the query result so we
     // can simply check for containment below.
-    let curVisits = [];
+    let curVisitsAsArray = [];
+    let curVisits = new Set();
     try {
-      curVisits = await PlacesSyncUtils.history.fetchVisitsForURL(record.histUri);
+      curVisitsAsArray = await PlacesSyncUtils.history.fetchVisitsForURL(record.histUri);
     } catch (e) {
       this._log.error("Error while fetching visits for URL ${record.histUri}", record.histUri);
     }
 
     let i, k;
-    for (i = 0; i < curVisits.length; i++) {
-      curVisits[i] = curVisits[i].date + "," + curVisits[i].type;
+    for (i = 0; i < curVisitsAsArray.length; i++) {
+      curVisits.add(curVisitsAsArray[i].date + "," + curVisitsAsArray[i].type);
     }
 
     // Walk through the visits, make sure we have sound data, and eliminate
     // dupes. The latter is done by rewriting the array in-place.
     for (i = 0, k = 0; i < record.visits.length; i++) {
       let visit = record.visits[k] = record.visits[i];
 
       if (!visit.date || typeof visit.date != "number" || !Number.isInteger(visit.date)) {
@@ -277,25 +278,25 @@ HistoryStore.prototype = {
 
       // Dates need to be integers. Future and far past dates are clamped to the
       // current date and earliest sensible date, respectively.
       let originalVisitDate = PlacesUtils.toDate(Math.round(visit.date));
       visit.date = PlacesSyncUtils.history.clampVisitDate(originalVisitDate);
 
       let visitDateAsPRTime = PlacesUtils.toPRTime(visit.date);
       let visitKey = visitDateAsPRTime + "," + visit.type;
-      if (curVisits.indexOf(visitKey) != -1) {
+      if (curVisits.has(visitKey)) {
         // Visit is a dupe, don't increment 'k' so the element will be
         // overwritten.
         continue;
       }
 
       // Note the visit key, so that we don't add duplicate visits with
       // clamped timestamps.
-      curVisits.push(visitKey);
+      curVisits.add(visitKey);
 
       visit.transition = visit.type;
       k += 1;
     }
     record.visits.length = k; // truncate array
 
     // No update if there aren't any visits to apply.
     // mozIAsyncHistory::updatePlaces() wants at least one visit.
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -185,17 +185,18 @@ class FirefoxBrowser(Browser):
 
         self.profile = FirefoxProfile(locations=locations,
                                       preferences=preferences)
         self.profile.set_preferences({"marionette.port": self.marionette_port,
                                       "dom.disable_open_during_load": False,
                                       "network.dns.localDomains": ",".join(hostnames),
                                       "network.proxy.type": 0,
                                       "places.history.enabled": False,
-                                      "dom.send_after_paint_to_content": True})
+                                      "dom.send_after_paint_to_content": True,
+                                      "network.preload": True})
         if self.e10s:
             self.profile.set_preferences({"browser.tabs.remote.autostart": True})
 
         if self.test_type == "reftest":
             self.profile.set_preferences({"layout.interruptible-reflow.enabled": False})
 
         if self.leak_check and kwargs.get("check_leaks", True):
             self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks.log")
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -766,29 +766,33 @@ ParentAPIManager = {
   async addListener(data, target) {
     let context = this.getContextById(data.childId);
     if (context.parentMessageManager !== target.messageManager) {
       throw new Error("Got message on unexpected message manager");
     }
 
     let {childId} = data;
     let handlingUserInput = false;
+    let lowPriority = data.path.startsWith("webRequest.");
 
     function listener(...listenerArgs) {
       return context.sendMessage(
         context.parentMessageManager,
         "API:RunListener",
         {
           childId,
           handlingUserInput,
           listenerId: data.listenerId,
           path: data.path,
-          args: new StructuredCloneHolder(listenerArgs),
+          get args() {
+            return new StructuredCloneHolder(listenerArgs);
+          },
         },
         {
+          lowPriority,
           recipient: {childId},
         }).then(result => {
           return result && result.deserialize(global);
         });
     }
 
     context.listenerProxies.set(data.listenerId, listener);
 
--- a/toolkit/components/extensions/MessageChannel.jsm
+++ b/toolkit/components/extensions/MessageChannel.jsm
@@ -107,16 +107,62 @@ Cu.import("resource://gre/modules/Extens
 Cu.import("resource://gre/modules/Services.jsm");
 
 const {
   MessageManagerProxy,
 } = ExtensionUtils;
 
 const {DEBUG} = AppConstants;
 
+// Idle callback timeout for low-priority message dispatch.
+const LOW_PRIORITY_TIMEOUT_MS = 250;
+
+const MESSAGE_MESSAGES = "MessageChannel:Messages";
+const MESSAGE_RESPONSE = "MessageChannel:Response";
+
+// ESLint can't tell that these are referenced, so tell it that they're
+// exported to make it happy.
+/* exported _deferredResult, _makeDeferred */
+var _deferredResult;
+var _makeDeferred = (resolve, reject) => {
+  // We use arrow functions here and refer to the outer variables via
+  // `this`, to avoid a lexical name lookup. Yes, it makes a difference.
+  // No, I don't like it any more than you do.
+  this._deferredResult.resolve = resolve;
+  this._deferredResult.reject = reject;
+};
+
+/**
+ * Helper to create a new Promise without allocating any closures to
+ * receive its resolution functions.
+ *
+ * I know what you're thinking: "This is crazy. There is no possible way
+ * this can be necessary. Just use the ordinary Promise constructor the
+ * way it was meant to be used, you lunatic."
+ *
+ * And, against all odds, it turns out that you're wrong. Creating
+ * lambdas to receive promise resolution functions consistently turns
+ * out to be one of the most expensive parts of message dispatch in this
+ * code.
+ *
+ * So we do the stupid micro-optimization, and try to live with
+ * ourselves for it.
+ *
+ * (See also bug 1404950.)
+ *
+ * @returns {object}
+ */
+let Deferred = () => {
+  let res = {};
+  this._deferredResult = res;
+  res.promise = new Promise(this._makeDeferred);
+  this._deferredResult = null;
+  return res;
+};
+
 /**
  * Handles the mapping and dispatching of messages to their registered
  * handlers. There is one broker per message manager and class of
  * messages. Each class of messages is mapped to one native message
  * name, e.g., "MessageChannel:Message", and is dispatched to handlers
  * based on an internal message name, e.g., "Extension:ExecuteScript".
  */
 class FilteringMessageManager {
@@ -144,42 +190,48 @@ class FilteringMessageManager {
     this.messageManager = messageManager;
 
     this.messageManager.addMessageListener(this.messageName, this, true);
 
     this.handlers = new Map();
   }
 
   /**
-   * Receives a message from our message manager, maps it to a handler, and
-   * passes the result to our message callback.
+   * Receives a set of messages from our message manager, maps each to a
+   * handler, and passes the results to our message callbacks.
    */
   receiveMessage({data, target}) {
-    let handlers = Array.from(this.getHandlers(data.messageName, data.sender || null, data.recipient));
+    data.forEach(msg => {
+      if (msg) {
+        let handlers = Array.from(this.getHandlers(msg.messageName,
+                                                   msg.sender || null,
+                                                   msg.recipient));
 
-    data.target = target;
-    this.callback(handlers, data);
+        msg.target = target;
+        this.callback(handlers, msg);
+      }
+    });
   }
 
   /**
    * Iterates over all handlers for the given message name. If `recipient`
    * is provided, only iterates over handlers whose filters match it.
    *
    * @param {string|number} messageName
    *     The message for which to return handlers.
    * @param {object} sender
    *     The sender data on which to filter handlers.
    * @param {object} recipient
    *     The recipient data on which to filter handlers.
    */
   * getHandlers(messageName, sender, recipient) {
     let handlers = this.handlers.get(messageName) || new Set();
     for (let handler of handlers) {
-      if (MessageChannel.matchesFilter(handler.messageFilterStrict || {}, recipient) &&
-          MessageChannel.matchesFilter(handler.messageFilterPermissive || {}, recipient, false) &&
+      if (MessageChannel.matchesFilter(handler.messageFilterStrict || null, recipient) &&
+          MessageChannel.matchesFilter(handler.messageFilterPermissive || null, recipient, false) &&
           (!handler.filterMessage || handler.filterMessage(sender, recipient))) {
         yield handler;
       }
     }
   }
 
   /**
    * Registers a handler for the given message.
@@ -213,20 +265,96 @@ class FilteringMessageManager {
   removeHandler(messageName, handler) {
     if (this.handlers.has(messageName)) {
       this.handlers.get(messageName).delete(handler);
     }
   }
 }
 
 /**
- * A simplified subclass of FilteringMessageManager that only supports
- * one handler per message, and does not support filtering.
+ * A message dispatch and response manager that wrapse a single native
+ * message manager. Handles dispatching messages through the manager
+ * (optionally coalescing several low-priority messages and dispatching
+ * them during an idle slice), and mapping their responses to the
+ * appropriate response callbacks.
+ *
+ * Note that this is a simplified subclass of FilteringMessageManager
+ * that only supports one handler per message, and does not support
+ * filtering.
  */
 class ResponseManager extends FilteringMessageManager {
+  constructor(messageName, callback, messageManager) {
+    super(messageName, callback, messageManager);
+
+    this.idleMessages = [];
+    this.idleScheduled = false;
+    this.onIdle = this.onIdle.bind(this);
+  }
+
+  /**
+   * Schedules a new idle callback to dispatch pending low-priority
+   * messages, if one is not already scheduled.
+   */
+  scheduleIdleCallback() {
+    if (!this.idleScheduled) {
+      ChromeUtils.idleDispatch(this.onIdle, {timeout: LOW_PRIORITY_TIMEOUT_MS});
+      this.idleScheduled = true;
+    }
+  }
+
+  /**
+   * Called when the event queue is idle, and dispatches any pending
+   * low-priority messages in a single chunk.
+   *
+   * @param {IdleDeadline} deadline
+   */
+  onIdle(deadline) {
+    this.idleScheduled = false;
+
+    let messages = this.idleMessages;
+    this.idleMessages = [];
+
+    let msgs = messages.map(msg => msg.getMessage());
+    try {
+      this.messageManager.sendAsyncMessage(MESSAGE_MESSAGES, msgs);
+    } catch (e) {
+      for (let msg of messages) {
+        msg.reject(e);
+      }
+    }
+  }
+
+  /**
+   * Sends a message through our wrapped message manager, or schedules
+   * it for low-priority dispatch during an idle callback.
+   *
+   * @param {any} message
+   *        The message to send.
+   * @param {object} [options]
+   *        Message dispatch options.
+   * @param {boolean} [options.lowPriority = false]
+   *        If true, dispatches the message in a single chunk with other
+   *        low-priority messages the next time the event queue is idle.
+   */
+  sendMessage(message, options = {}) {
+    if (options.lowPriority) {
+      this.idleMessages.push(message);
+      this.scheduleIdleCallback();
+    } else {
+      this.messageManager.sendAsyncMessage(MESSAGE_MESSAGES, [message.getMessage()]);
+    }
+  }
+
+  receiveMessage({data, target}) {
+    data.target = target;
+
+    this.callback(this.handlers.get(data.messageName),
+                  data);
+  }
+
   * getHandlers(messageName, sender, recipient) {
     let handler = this.handlers.get(messageName);
     if (handler) {
       yield handler;
     }
   }
 
   addHandler(messageName, handler) {
@@ -286,45 +414,140 @@ class FilteringMessageManagerMap extends
    * message manager.
    *
    * @param {nsIMessageListenerManager} target
    *     The message manager for which to return a broker.
    *
    * @returns {FilteringMessageManager}
    */
   get(target) {
-    if (this.has(target)) {
-      return super.get(target);
+    let broker = super.get(target);
+    if (broker) {
+      return broker;
     }
 
-    let broker = new this._constructor(this.messageName, this.callback, target);
+    broker = new this._constructor(this.messageName, this.callback, target);
     this.set(target, broker);
 
     if (target instanceof Ci.nsIDOMEventTarget) {
       let onUnload = event => {
         target.removeEventListener("unload", onUnload);
         this.delete(target);
       };
       target.addEventListener("unload", onUnload);
     }
 
     return broker;
   }
 }
 
-const MESSAGE_MESSAGE = "MessageChannel:Message";
-const MESSAGE_RESPONSE = "MessageChannel:Response";
+/**
+ * Represents a message being sent through a MessageChannel, which may
+ * or may not have been dispatched yet, and is pending a response.
+ *
+ * When a response has been received, or the message has been canceled,
+ * this class is responsible for settling the response promise as
+ * appropriate.
+ *
+ * @param {number} channelId
+ *        The unique ID for this message.
+ * @param {any} message
+ *        The message contents.
+ * @param {object} sender
+ *        An object describing the sender of the message, used by
+ *        `abortResponses` to determine whether the message should be
+ *        aborted.
+ * @param {ResponseManager} broker
+ *        The response broker on which we're expected to receive a
+ *        reply.
+ */
+class PendingMessage {
+  constructor(channelId, message, sender, broker) {
+    this.channelId = channelId;
+    this.message = message;
+    this.sender = sender;
+    this.broker = broker;
+    this.deferred = Deferred();
+
+    MessageChannel.pendingResponses.add(this);
+  }
+
+  /**
+   * Cleans up after this message once we've received or aborted a
+   * response.
+   */
+  cleanup() {
+    if (this.broker) {
+      this.broker.removeHandler(this.channelId, this);
+      MessageChannel.pendingResponses.delete(this);
+
+      this.message = null;
+      this.broker = null;
+    }
+  }
+
+  /**
+   * Returns the promise which will resolve when we've received or
+   * aborted a response to this message.
+   */
+  get promise() {
+    return this.deferred.promise;
+  }
+
+  /**
+   * Resolves the message's response promise, and cleans up.
+   *
+   * @param {any} value
+   */
+  resolve(value) {
+    this.cleanup();
+    this.deferred.resolve(value);
+  }
+
+  /**
+   * Rejects the message's response promise, and cleans up.
+   *
+   * @param {any} value
+   */
+  reject(value) {
+    this.cleanup();
+    this.deferred.reject(value);
+  }
+
+  get messageManager() {
+    return this.broker.messageManager;
+  }
+
+  /**
+   * Returns the contents of the message to be sent over a message
+   * manager, and registers the response with our response broker.
+   *
+   * Returns null if the response has already been canceled, and the
+   * message should not be sent.
+   *
+   * @returns {any}
+   */
+  getMessage() {
+    let msg = null;
+    if (this.broker) {
+      this.broker.addHandler(this.channelId, this);
+      msg = this.message;
+      this.message = null;
+    }
+    return msg;
+  }
+}
 
 this.MessageChannel = {
   init() {
     Services.obs.addObserver(this, "message-manager-close");
     Services.obs.addObserver(this, "message-manager-disconnect");
 
     this.messageManagers = new FilteringMessageManagerMap(
-      MESSAGE_MESSAGE, this._handleMessage.bind(this));
+      MESSAGE_MESSAGES, this._handleMessage.bind(this));
 
     this.responseManagers = new FilteringMessageManagerMap(
       MESSAGE_RESPONSE, this._handleResponse.bind(this),
       ResponseManager);
 
     /**
      * @property {Set<Deferred>} pendingResponses
      * Contains a set of pending responses, either waiting to be
@@ -431,28 +654,31 @@ this.MessageChannel = {
   },
 
   /**
    * Returns true if the properties of the `data` object match those in
    * the `filter` object. Matching is done on a strict equality basis,
    * and the behavior varies depending on the value of the `strict`
    * parameter.
    *
-   * @param {object} filter
+   * @param {object?} filter
    *    The filter object to match against.
    * @param {object} data
    *    The data object being matched.
    * @param {boolean} [strict=true]
    *    If true, all properties in the `filter` object have a
    *    corresponding property in `data` with the same value. If
    *    false, properties present in both objects must have the same
    *    value.
    * @returns {boolean} True if the objects match.
    */
   matchesFilter(filter, data, strict = true) {
+    if (!filter) {
+      return true;
+    }
     if (strict) {
       return Object.keys(filter).every(key => {
         return key in data && data[key] === filter[key];
       });
     }
     return Object.keys(filter).every(key => {
       return !(key in data) || data[key] === filter[key];
     });
@@ -570,71 +796,55 @@ this.MessageChannel = {
    *    `messageFilterPermissive` filters defined by recipients in order
    *    for the message to be received.
    * @param {object} [options.sender]
    *    A structured-clone-compatible object to identify the message
    *    sender. This object may also be used to avoid delivering the
    *    message to the sender, and as a filter to prematurely
    *    abort responses when the sender is being destroyed.
    *    @see `abortResponses`.
-   * @param {integer} [options.responseType=RESPONSE_SINGLE]
+   * @param {boolean} [options.lowPriority = false]
+   *    If true, treat this as a low-priority message, and attempt to
+   *    send it in the same chunk as other messages to the same target
+   *    the next time the event queue is idle. This option reduces
+   *    messaging overhead at the expense of adding some latency.
+   * @param {integer} [options.responseType = RESPONSE_SINGLE]
    *    Specifies the type of response expected. See the `RESPONSE_*`
    *    contents for details.
    * @returns {Promise}
    */
   sendMessage(target, messageName, data, options = {}) {
     let sender = options.sender || {};
     let recipient = options.recipient || {};
     let responseType = options.responseType || this.RESPONSE_SINGLE;
 
     let channelId = ExtensionUtils.getUniqueId();
     let message = {messageName, channelId, sender, recipient, data, responseType};
     data = null;
 
     if (responseType == this.RESPONSE_NONE) {
       try {
-        target.sendAsyncMessage(MESSAGE_MESSAGE, message);
+        target.sendAsyncMessage(MESSAGE_MESSAGES, [message]);
       } catch (e) {
         // Caller is not expecting a reply, so dump the error to the console.
         Cu.reportError(e);
         return Promise.reject(e);
       }
       return Promise.resolve();  // Not expecting any reply.
     }
 
-    let deferred = {};
-    deferred.promise = new Promise((resolve, reject) => {
-      deferred.resolve = resolve;
-      deferred.reject = reject;
-    });
-    deferred.sender = recipient;
-    deferred.messageManager = target;
-    deferred.channelId = channelId;
-
-    // The channel ID is used as the message name when routing responses.
-    // Add a message listener to the response broker, and remove it once
-    // we've gotten (or canceled) a response.
     let broker = this.responseManagers.get(target);
-    broker.addHandler(channelId, deferred);
-
-    this.pendingResponses.add(deferred);
-
-    let cleanup = () => {
-      broker.removeHandler(channelId, deferred);
-      this.pendingResponses.delete(deferred);
-    };
-    deferred.promise.then(cleanup, cleanup);
-
+    let pending = new PendingMessage(channelId, message, recipient, broker);
+    message = null;
     try {
-      target.sendAsyncMessage(MESSAGE_MESSAGE, message);
+      broker.sendMessage(pending, options);
     } catch (e) {
-      deferred.reject(e);
+      pending.reject(e);
     }
-    message = null;
-    return deferred.promise;
+    return pending.promise;
   },
 
   _callHandlers(handlers, data) {
     let responseType = data.responseType;
 
     // At least one handler is required for all response types but
     // RESPONSE_ALL.
     if (handlers.length == 0 && responseType != this.RESPONSE_ALL) {
@@ -776,39 +986,36 @@ this.MessageChannel = {
         cleanup();
         Cu.reportError(e);
       });
   },
 
   /**
    * Handles message callbacks from the response brokers.
    *
-   * Each handler object is a deferred object created by `sendMessage`, and
-   * should be resolved or rejected based on the contents of the response.
-   *
-   * @param {Array<MessageHandler>} handlers
+   * @param {MessageHandler?} handler
+   *        A deferred object created by `sendMessage`, to be resolved
+   *        or rejected based on the contents of the response.
    * @param {object} data
    * @param {nsIMessageSender|{messageManager:nsIMessageSender}} data.target
    */
-  _handleResponse(handlers, data) {
+  _handleResponse(handler, data) {
     // If we have an error at this point, we have handler to report it to,
     // so just log it.
-    if (handlers.length == 0) {
+    if (!handler) {
       if (this.abortedResponses.has(data.messageName)) {
         this.abortedResponses.delete(data.messageName);
         Services.console.logStringMessage(`Ignoring response to aborted listener for ${data.messageName}`);
       } else {
         Cu.reportError(`No matching message response handler for ${data.messageName}`);
       }
-    } else if (handlers.length > 1) {
-      Cu.reportError(`Multiple matching response handlers for ${data.messageName}`);
     } else if (data.result === this.RESULT_SUCCESS) {
-      handlers[0].resolve(data.value);
+      handler.resolve(data.value);
     } else {
-      handlers[0].reject(data.error);
+      handler.reject(data.error);
     }
   },
 
   /**
    * Aborts pending message response for the specific channel.
    *
    * @param {string} channelId
    *    A string for channelId of the response.
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_hsts.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_hsts.html
@@ -49,16 +49,17 @@ add_task(async function test_hsts_reques
     browser.webRequest.onBeforeRedirect.addListener(details => {
       browser.test.assertEq(expect.shift(), "onBeforeRedirect");
     }, {urls});
     browser.webRequest.onResponseStarted.addListener(details => {
       browser.test.assertEq(expect.shift(), "onResponseStarted");
     }, {urls});
     browser.webRequest.onCompleted.addListener(details => {
       browser.test.assertEq(expect.shift(), "onCompleted");
+      browser.test.sendMessage("onCompleted", details.url);
     }, {urls});
     browser.webRequest.onErrorOccurred.addListener(details => {
       browser.test.notifyFail(`onErrorOccurred ${JSON.stringify(details)}`);
     }, {urls});
 
     async function onUpdated(tabId, tabInfo, tab) {
       if (tabInfo.status !== "complete") {
         return;
@@ -79,33 +80,38 @@ add_task(async function test_hsts_reques
   let sample = "https://example.org/tests/toolkit/components/extensions/test/mochitest/file_sample.html";
   extension.sendMessage(`https://${testPath}/redirect_auto.sjs?redirect_uri=${sample}`,
     ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders",
      "onHeadersReceived", "onBeforeRedirect", "onBeforeRequest",
      "onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived",
      "onResponseStarted", "onCompleted"]);
   // redirect_auto adds a query string
   ok((await extension.awaitMessage("tabs-done")).startsWith(sample), "redirection ok");
+  ok((await extension.awaitMessage("onCompleted")).startsWith(sample), "redirection ok");
 
   // priming hsts
   extension.sendMessage(`https://${testPath}/hsts.sjs`,
     ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders",
      "onHeadersReceived", "onResponseStarted", "onCompleted"]);
   is(await extension.awaitMessage("tabs-done"),
      "https://example.org/tests/toolkit/components/extensions/test/mochitest/hsts.sjs",
      "hsts primed");
+  is(await extension.awaitMessage("onCompleted"),
+     "https://example.org/tests/toolkit/components/extensions/test/mochitest/hsts.sjs");
 
   // test upgrade
   extension.sendMessage(`http://${testPath}/hsts.sjs`,
     ["onBeforeRequest", "onBeforeRedirect", "onBeforeRequest",
      "onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived",
      "onResponseStarted", "onCompleted"]);
   is(await extension.awaitMessage("tabs-done"),
      "https://example.org/tests/toolkit/components/extensions/test/mochitest/hsts.sjs",
      "hsts upgraded");
+  is(await extension.awaitMessage("onCompleted"),
+     "https://example.org/tests/toolkit/components/extensions/test/mochitest/hsts.sjs");
 
   await extension.unload();
 });
 </script>
 </head>
 <body>
 
 </body>
--- a/toolkit/components/printingui/ipc/PrintingParent.cpp
+++ b/toolkit/components/printingui/ipc/PrintingParent.cpp
@@ -132,36 +132,35 @@ PrintingParent::ShowPrintDialog(PBrowser
 
   rv = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = settings->SetPrintSilent(printSilently);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString printerName;
-  settings->GetPrinterName(getter_Copies(printerName));
+  settings->GetPrinterName(printerName);
 #ifdef MOZ_X11
   // Requesting the default printer name on Linux has been removed in the child,
   // because it was causing a sandbox violation (see Bug 1329216).
   // If no printer name is set at this point, use the print settings service
   // to get the default printer name.
   if (printerName.IsEmpty()) {
-    mPrintSettingsSvc->GetDefaultPrinterName(getter_Copies(printerName));
-    settings->SetPrinterName(printerName.get());
+    mPrintSettingsSvc->GetDefaultPrinterName(printerName);
+    settings->SetPrinterName(printerName);
   }
-  mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName.get(), settings);
+  mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
 #endif
 
   // If this is for print preview or we are printing silently then we just need
   // to initialize the print settings with anything specific from the printer.
   if (isPrintPreview || printSilently ||
       Preferences::GetBool("print.always_print_silent", printSilently)) {
     settings->SetIsInitializedFromPrinter(false);
-    mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName.get(),
-                                                    settings);
+    mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
   } else {
     rv = pps->ShowPrintDialog(parentWin, wbp, settings);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (isPrintPreview) {
     // For print preview we don't want a RemotePrintJob just the settings.
     rv = mPrintSettingsSvc->SerializeToPrintData(settings, nullptr, aResult);
--- a/toolkit/components/printingui/win/nsPrintDialogUtil.cpp
+++ b/toolkit/components/printingui/win/nsPrintDialogUtil.cpp
@@ -530,17 +530,17 @@ CreateGlobalDevModeAndInit(const nsStrin
 }
 
 //------------------------------------------------------------------
 // helper
 static void GetDefaultPrinterNameFromGlobalPrinters(nsAString &printerName)
 {
   nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1");
   if (prtEnum) {
-    prtEnum->GetDefaultPrinterName(getter_Copies(printerName));
+    prtEnum->GetDefaultPrinterName(printerName);
   }
 }
 
 // Determine whether we have a completely native dialog
 // or whether we cshould extend it
 static bool ShouldExtendPrintDialog()
 {
   nsresult rv;
@@ -565,17 +565,17 @@ ShowNativePrintDialog(HWND              
 {
   //NS_ENSURE_ARG_POINTER(aHWnd);
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   gDialogWasExtended  = false;
 
   // Get the Print Name to be used
   nsString printerName;
-  aPrintSettings->GetPrinterName(getter_Copies(printerName));
+  aPrintSettings->GetPrinterName(printerName);
 
   // If there is no name then use the default printer
   if (printerName.IsEmpty()) {
     GetDefaultPrinterNameFromGlobalPrinters(printerName);
   } else {
     HANDLE hPrinter = nullptr;
     if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())),
                        &hPrinter, nullptr)) {
@@ -691,39 +691,39 @@ ShowNativePrintDialog(HWND              
     // NOTE:
     // As per Microsoft SDK documentation the returned value offset from
     // devnames->wOutputOffset is either "FILE:" or nullptr
     // if the "Print To File" checkbox is checked it MUST be "FILE:"
     // We assert as an extra safety check.
     if (prntdlg.Flags & PD_PRINTTOFILE) {
       char16ptr_t fileName = &(((wchar_t *)devnames)[devnames->wOutputOffset]);
       NS_ASSERTION(wcscmp(fileName, L"FILE:") == 0, "FileName must be `FILE:`");
-      aPrintSettings->SetToFileName(fileName);
+      aPrintSettings->SetToFileName(nsDependentString(fileName));
       aPrintSettings->SetPrintToFile(true);
     } else {
       // clear "print to file" info
       aPrintSettings->SetPrintToFile(false);
-      aPrintSettings->SetToFileName(nullptr);
+      aPrintSettings->SetToFileName(EmptyString());
     }
 
     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
     if (!psWin) {
       return NS_ERROR_FAILURE;
     }
 
     // Setup local Data members
-    psWin->SetDeviceName(device);
-    psWin->SetDriverName(driver);
+    psWin->SetDeviceName(nsDependentString(device));
+    psWin->SetDriverName(nsDependentString(driver));
 
 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
     wprintf(L"printer: driver %s, device %s  flags: %d\n", driver, device, prntdlg.Flags);
 #endif
     // fill the print options with the info from the dialog
 
-    aPrintSettings->SetPrinterName(device);
+    aPrintSettings->SetPrinterName(nsDependentString(device));
 
     if (prntdlg.Flags & PD_SELECTION) {
       aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection);
 
     } else if (prntdlg.Flags & PD_PAGENUMS) {
       aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
       aPrintSettings->SetStartPageRange(prntdlg.nFromPage);
       aPrintSettings->SetEndPageRange(prntdlg.nToPage);
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -95,17 +95,17 @@ nsViewManager::~nsViewManager()
 
   if (gViewManagers->IsEmpty()) {
     // There aren't any more view managers so
     // release the global array of view managers
     delete gViewManagers;
     gViewManagers = nullptr;
   }
 
-  mPresShell = nullptr;
+  MOZ_RELEASE_ASSERT(!mPresShell, "Releasing nsViewManager without having called Destroy on the PresShell!");
 }
 
 // We don't hold a reference to the presentation context because it
 // holds a reference to us.
 nsresult
 nsViewManager::Init(nsDeviceContext* aContext)
 {
   NS_PRECONDITION(nullptr != aContext, "null ptr");
--- a/widget/android/nsDeviceContextAndroid.cpp
+++ b/widget/android/nsDeviceContextAndroid.cpp
@@ -57,17 +57,17 @@ nsDeviceContextSpecAndroid::BeginDocumen
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDeviceContextSpecAndroid::EndDocument()
 {
   nsString targetPath;
   nsCOMPtr<nsIFile> destFile;
-  mPrintSettings->GetToFileName(getter_Copies(targetPath));
+  mPrintSettings->GetToFileName(targetPath);
 
   nsresult rv = NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString destLeafName;
   rv = destFile->GetLeafName(destLeafName);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/widget/android/nsPrintOptionsAndroid.cpp
+++ b/widget/android/nsPrintOptionsAndroid.cpp
@@ -7,18 +7,17 @@
 #include "nsPrintSettingsImpl.h"
 
 class nsPrintSettingsAndroid : public nsPrintSettings {
 public:
   nsPrintSettingsAndroid()
   {
     // The aim here is to set up the objects enough that silent printing works
     SetOutputFormat(nsIPrintSettings::kOutputFormatPDF);
-    SetPrinterName(u"PDF printer");
-    
+    SetPrinterName(NS_LITERAL_STRING("PDF printer"));
   }
 };
 
 nsPrintOptionsAndroid::nsPrintOptionsAndroid()
 {
 }
 
 nsPrintOptionsAndroid::~nsPrintOptionsAndroid()
--- a/widget/cocoa/nsPrintDialogX.mm
+++ b/widget/cocoa/nsPrintDialogX.mm
@@ -510,42 +510,42 @@ static const char sHeaderFooterTags[][4]
   [self addLabel:"pageFootersTitleMac" withFrame:NSMakeRect(0, 0, 151, 22)];
   [self addCenteredLabel:"left" withFrame:NSMakeRect(156, 22, 100, 22)];
   [self addCenteredLabel:"center" withFrame:NSMakeRect(256, 22, 100, 22)];
   [self addCenteredLabel:"right" withFrame:NSMakeRect(356, 22, 100, 22)];
 
   // Lists
   nsString sel;
 
-  mSettings->GetHeaderStrLeft(getter_Copies(sel));
+  mSettings->GetHeaderStrLeft(sel);
   mHeaderLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
                                            selectedItem:sel];
   [self addSubview:mHeaderLeftList];
 
-  mSettings->GetHeaderStrCenter(getter_Copies(sel));
+  mSettings->GetHeaderStrCenter(sel);
   mHeaderCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
                                              selectedItem:sel];
   [self addSubview:mHeaderCenterList];
 
-  mSettings->GetHeaderStrRight(getter_Copies(sel));
+  mSettings->GetHeaderStrRight(sel);
   mHeaderRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
                                             selectedItem:sel];
   [self addSubview:mHeaderRightList];
 
-  mSettings->GetFooterStrLeft(getter_Copies(sel));
+  mSettings->GetFooterStrLeft(sel);
   mFooterLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
                                            selectedItem:sel];
   [self addSubview:mFooterLeftList];
 
-  mSettings->GetFooterStrCenter(getter_Copies(sel));
+  mSettings->GetFooterStrCenter(sel);
   mFooterCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
                                              selectedItem:sel];
   [self addSubview:mFooterCenterList];
 
-  mSettings->GetFooterStrRight(getter_Copies(sel));
+  mSettings->GetFooterStrRight(sel);
   mFooterRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
                                             selectedItem:sel];
   [self addSubview:mFooterRightList];
 }
 
 // Export settings
 
 - (int16_t)chosenFrameSetting
@@ -565,32 +565,32 @@ static const char sHeaderFooterTags[][4]
   NS_ASSERTION(index < NSInteger(ArrayLength(sHeaderFooterTags)), "Index of dropdown is higher than expected!");
   return sHeaderFooterTags[index];
 }
 
 - (void)exportHeaderFooterSettings
 {
   const char* headerFooterStr;
   headerFooterStr = [self headerFooterStringForList:mHeaderLeftList];
-  mSettings->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(headerFooterStr).get());
+  mSettings->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(headerFooterStr));
 
   headerFooterStr = [self headerFooterStringForList:mHeaderCenterList];
-  mSettings->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(headerFooterStr).get());
+  mSettings->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(headerFooterStr));
 
   headerFooterStr = [self headerFooterStringForList:mHeaderRightList];
-  mSettings->SetHeaderStrRight(NS_ConvertUTF8toUTF16(headerFooterStr).get());
+  mSettings->SetHeaderStrRight(NS_ConvertUTF8toUTF16(headerFooterStr));
 
   headerFooterStr = [self headerFooterStringForList:mFooterLeftList];
-  mSettings->SetFooterStrLeft(NS_ConvertUTF8toUTF16(headerFooterStr).get());
+  mSettings->SetFooterStrLeft(NS_ConvertUTF8toUTF16(headerFooterStr));
 
   headerFooterStr = [self headerFooterStringForList:mFooterCenterList];
-  mSettings->SetFooterStrCenter(NS_ConvertUTF8toUTF16(headerFooterStr).get());
+  mSettings->SetFooterStrCenter(NS_ConvertUTF8toUTF16(headerFooterStr));
 
   headerFooterStr = [self headerFooterStringForList:mFooterRightList];
-  mSettings->SetFooterStrRight(NS_ConvertUTF8toUTF16(headerFooterStr).get());
+  mSettings->SetFooterStrRight(NS_ConvertUTF8toUTF16(headerFooterStr));
 }
 
 // Summary
 
 - (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox
 {
   if (![aCheckbox isEnabled])
     return [self localizedString:"summaryNAValue"];
--- a/widget/cocoa/nsPrintSettingsX.h
+++ b/widget/cocoa/nsPrintSettingsX.h
@@ -63,17 +63,17 @@ public:
   nsresult InitAdjustedPaperSize();
 
   void SetInchesScale(float aWidthScale, float aHeightScale);
   void GetInchesScale(float *aWidthScale, float *aHeightScale);
 
   NS_IMETHOD SetScaling(double aScaling) override;
   NS_IMETHOD GetScaling(double *aScaling) override;
 
-  NS_IMETHOD SetToFileName(const char16_t * aToFileName) override;
+  NS_IMETHOD SetToFileName(const nsAString& aToFileName) override;
 
   NS_IMETHOD GetOrientation(int32_t *aOrientation) override;
   NS_IMETHOD SetOrientation(int32_t aOrientation) override;
 
   NS_IMETHOD SetUnwriteableMarginTop(double aUnwriteableMarginTop) override;
   NS_IMETHOD SetUnwriteableMarginLeft(double aUnwriteableMarginLeft) override;
   NS_IMETHOD SetUnwriteableMarginBottom(double aUnwriteableMarginBottom) override;
   NS_IMETHOD SetUnwriteableMarginRight(double aUnwriteableMarginRight) override;
--- a/widget/cocoa/nsPrintSettingsX.mm
+++ b/widget/cocoa/nsPrintSettingsX.mm
@@ -323,33 +323,32 @@ nsPrintSettingsX::GetScaling(double *aSc
   *aScaling = round(*aScaling * 100.0) / 100.0;
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP
-nsPrintSettingsX::SetToFileName(const char16_t *aToFileName)
+nsPrintSettingsX::SetToFileName(const nsAString& aToFileName)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (XRE_IsContentProcess() &&
       Preferences::GetBool("print.print_via_parent")) {
     // On content sandbox, NSPrintJobSavingURL will returns error since
     // sandbox disallows file access.
     return nsPrintSettings::SetToFileName(aToFileName);
   }
 
   NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
 
-  if (aToFileName && aToFileName[0]) {
+  if (!aToFileName.IsEmpty()) {
     NSURL* jobSavingURL =
-        [NSURL fileURLWithPath: nsCocoaUtils::ToNSString(
-                                  nsDependentString(aToFileName))];
+        [NSURL fileURLWithPath: nsCocoaUtils::ToNSString(aToFileName)];
     if (jobSavingURL) {
       [printInfoDict setObject: NSPrintSaveJob forKey: NSPrintJobDisposition];
       [printInfoDict setObject: jobSavingURL forKey: NSPrintJobSavingURL];
     }
     mToFileName = aToFileName;
   } else {
     mToFileName.Truncate();
   }
--- a/widget/gtk/nsDeviceContextSpecG.cpp
+++ b/widget/gtk/nsDeviceContextSpecG.cpp
@@ -58,17 +58,17 @@ public:
 
   void      FreeGlobalPrinters();
   nsresult  InitializeGlobalPrinters();
 
   bool      PrintersAreAllocated()       { return mGlobalPrinterList != nullptr; }
   uint32_t  GetNumPrinters()
     { return mGlobalPrinterList ? mGlobalPrinterList->Length() : 0; }
   nsString* GetStringAt(int32_t aInx)    { return &mGlobalPrinterList->ElementAt(aInx); }
-  void      GetDefaultPrinterName(char16_t **aDefaultPrinterName);
+  void      GetDefaultPrinterName(nsAString& aDefaultPrinterName);
 
 protected:
   GlobalPrinters() {}
 
   static GlobalPrinters mGlobalPrinters;
   static nsTArray<nsString>* mGlobalPrinterList;
 };
 
@@ -241,17 +241,17 @@ ns_release_macro(gpointer aData) {
 /* static */
 gboolean nsDeviceContextSpecGTK::PrinterEnumerator(GtkPrinter *aPrinter,
                                                    gpointer aData) {
   nsDeviceContextSpecGTK *spec = (nsDeviceContextSpecGTK*)aData;
 
   // Find the printer whose name matches the one inside the settings.
   nsString printerName;
   nsresult rv =
-    spec->mPrintSettings->GetPrinterName(getter_Copies(printerName));
+    spec->mPrintSettings->GetPrinterName(printerName);
   if (NS_SUCCEEDED(rv) && !printerName.IsVoid()) {
     NS_ConvertUTF16toUTF8 requestedName(printerName);
     const char* currentName = gtk_printer_get_name(aPrinter);
     if (requestedName.Equals(currentName)) {
       spec->mPrintSettings->SetGtkPrinter(aPrinter);
 
       // Bug 1145916 - attempting to kick off a print job for this printer
       // during this tick of the event loop will result in the printer backend
@@ -323,17 +323,17 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::En
         NewRunnableMethod("nsDeviceContextSpecGTK::EnumeratePrinters",
                           this,
                           &nsDeviceContextSpecGTK::EnumeratePrinters));
     }
   } else {
     // Handle print-to-file ourselves for the benefit of embedders
     nsString targetPath;
     nsCOMPtr<nsIFile> destFile;
-    mPrintSettings->GetToFileName(getter_Copies(targetPath));
+    mPrintSettings->GetToFileName(targetPath);
 
     nsresult rv = NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoString destLeafName;
     rv = destFile->GetLeafName(destLeafName);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -383,28 +383,29 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::Ge
   {
     printers->AppendElement(*GlobalPrinters::GetInstance()->GetStringAt(count++));
   }
   GlobalPrinters::GetInstance()->FreeGlobalPrinters();
 
   return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
 }
 
-NS_IMETHODIMP nsPrinterEnumeratorGTK::GetDefaultPrinterName(char16_t **aDefaultPrinterName)
+NS_IMETHODIMP nsPrinterEnumeratorGTK::GetDefaultPrinterName(nsAString& aDefaultPrinterName)
 {
   DO_PR_DEBUG_LOG(("nsPrinterEnumeratorGTK::GetDefaultPrinterName()\n"));
-  NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
 
   GlobalPrinters::GetInstance()->GetDefaultPrinterName(aDefaultPrinterName);
 
-  DO_PR_DEBUG_LOG(("GetDefaultPrinterName(): default printer='%s'.\n", NS_ConvertUTF16toUTF8(*aDefaultPrinterName).get()));
+  DO_PR_DEBUG_LOG(("GetDefaultPrinterName(): default printer='%s'.\n", NS_ConvertUTF16toUTF8(aDefaultPrinterName).get()));
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
+NS_IMETHODIMP
+nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const nsAString& aPrinterName,
+                                                     nsIPrintSettings *aPrintSettings)
 {
   DO_PR_DEBUG_LOG(("nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter()"));
 
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   /* Set filename */
   nsAutoCString filename;
   const char *path;
@@ -413,17 +414,17 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::In
     path = PR_GetEnv("HOME");
   
   if (path)
     filename = nsPrintfCString("%s/mozilla.pdf", path);
   else
     filename.AssignLiteral("mozilla.pdf");
 
   DO_PR_DEBUG_LOG(("Setting default filename to '%s'\n", filename.get()));
-  aPrintSettings->SetToFileName(NS_ConvertUTF8toUTF16(filename).get());
+  aPrintSettings->SetToFileName(NS_ConvertUTF8toUTF16(filename));
 
   aPrintSettings->SetIsInitializedFromPrinter(true);
 
   return NS_OK;    
 }
 
 //----------------------------------------------------------------------
 nsresult GlobalPrinters::InitializeGlobalPrinters ()
@@ -465,32 +466,32 @@ void GlobalPrinters::FreeGlobalPrinters(
 {
   if (mGlobalPrinterList) {
     delete mGlobalPrinterList;
     mGlobalPrinterList = nullptr;
   }  
 }
 
 void 
-GlobalPrinters::GetDefaultPrinterName(char16_t **aDefaultPrinterName)
+GlobalPrinters::GetDefaultPrinterName(nsAString& aDefaultPrinterName)
 {
-  *aDefaultPrinterName = nullptr;
+  aDefaultPrinterName.Truncate();
   
   bool allocate = !GlobalPrinters::GetInstance()->PrintersAreAllocated();
   
   if (allocate) {
     nsresult rv = GlobalPrinters::GetInstance()->InitializeGlobalPrinters();
     if (NS_FAILED(rv)) {
       return;
     }
   }
   NS_ASSERTION(GlobalPrinters::GetInstance()->PrintersAreAllocated(), "no GlobalPrinters");
 
   if (GlobalPrinters::GetInstance()->GetNumPrinters() == 0)
     return;
   
-  *aDefaultPrinterName = ToNewUnicode(*GlobalPrinters::GetInstance()->GetStringAt(0));
+  aDefaultPrinterName = *GlobalPrinters::GetInstance()->GetStringAt(0);
 
   if (allocate) {  
     GlobalPrinters::GetInstance()->FreeGlobalPrinters();
   }  
 }
 
--- a/widget/gtk/nsPrintDialogGTK.cpp
+++ b/widget/gtk/nsPrintDialogGTK.cpp
@@ -272,38 +272,38 @@ nsPrintDialogWidgetGTK::nsPrintDialogWid
   GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0);
   gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0);
 
 
   // --- Table for making the header and footer options ---
   GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table
   nsString header_footer_str[3];
 
-  aSettings->GetHeaderStrLeft(getter_Copies(header_footer_str[0]));
-  aSettings->GetHeaderStrCenter(getter_Copies(header_footer_str[1]));
-  aSettings->GetHeaderStrRight(getter_Copies(header_footer_str[2]));
+  aSettings->GetHeaderStrLeft(header_footer_str[0]);
+  aSettings->GetHeaderStrCenter(header_footer_str[1]);
+  aSettings->GetHeaderStrRight(header_footer_str[2]);
 
   for (unsigned int i = 0; i < ArrayLength(header_dropdown); i++) {
     header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
     // Those 4 magic numbers in the middle provide the position in the table.
     // The last two numbers mean 2 px padding on every side.
     gtk_table_attach(GTK_TABLE(header_footer_table), header_dropdown[i], i, (i + 1),
                      0, 1, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
   }
 
   const char labelKeys[][7] = {"left", "center", "right"};
   for (unsigned int i = 0; i < ArrayLength(labelKeys); i++) {
     gtk_table_attach(GTK_TABLE(header_footer_table),
                      gtk_label_new(GetUTF8FromBundle(labelKeys[i]).get()),
                      i, (i + 1), 1, 2, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
   }
 
-  aSettings->GetFooterStrLeft(getter_Copies(header_footer_str[0]));
-  aSettings->GetFooterStrCenter(getter_Copies(header_footer_str[1]));
-  aSettings->GetFooterStrRight(getter_Copies(header_footer_str[2]));
+  aSettings->GetFooterStrLeft(header_footer_str[0]);
+  aSettings->GetFooterStrCenter(header_footer_str[1]);
+  aSettings->GetFooterStrRight(header_footer_str[2]);
 
   for (unsigned int i = 0; i < ArrayLength(footer_dropdown); i++) {
     footer_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
     gtk_table_attach(GTK_TABLE(header_footer_table), footer_dropdown[i], i, (i + 1),
                      2, 3, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
   }
   // ---
 
@@ -366,32 +366,32 @@ nsPrintDialogWidgetGTK::ExportFramePrint
     aNS->SetPrintFrameType(nsIPrintSettings::kNoFrames);
 }
 
 void
 nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS)
 {
   const char* header_footer_str;
   header_footer_str = OptionWidgetToString(header_dropdown[0]);
-  aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
+  aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str));
 
   header_footer_str = OptionWidgetToString(header_dropdown[1]);
-  aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
+  aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str));
 
   header_footer_str = OptionWidgetToString(header_dropdown[2]);
-  aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
+  aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str));
 
   header_footer_str = OptionWidgetToString(footer_dropdown[0]);
-  aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
+  aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str));
 
   header_footer_str = OptionWidgetToString(footer_dropdown[1]);
-  aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
+  aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str));
 
   header_footer_str = OptionWidgetToString(footer_dropdown[2]);
-  aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
+  aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str));
 }
 
 nsresult
 nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
 {
   NS_PRECONDITION(aNSSettings, "aSettings must not be null");
   NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
 
@@ -578,20 +578,20 @@ nsPrintDialogServiceGTK::ShowPageSetup(n
   nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
   if (!aNSSettingsGTK)
     return NS_ERROR_FAILURE;
 
   // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word
   nsCOMPtr<nsIPrintSettingsService> psService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
   if (psService) {
     nsString printName;
-    aNSSettings->GetPrinterName(getter_Copies(printName));
+    aNSSettings->GetPrinterName(printName);
     if (printName.IsVoid()) {
-      psService->GetDefaultPrinterName(getter_Copies(printName));
-      aNSSettings->SetPrinterName(printName.get());
+      psService->GetDefaultPrinterName(printName);
+      aNSSettings->SetPrinterName(printName);
     }
     psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
   }
 
   GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings();
   GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup();
 
   GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog(gtkParent, oldPageSetup, gtkSettings);
--- a/widget/gtk/nsPrintSettingsGTK.cpp
+++ b/widget/gtk/nsPrintSettingsGTK.cpp
@@ -404,93 +404,86 @@ nsPrintSettingsGTK::SetOrientation(int32
     gtkOrient = GTK_PAGE_ORIENTATION_PORTRAIT;
 
   gtk_print_settings_set_orientation(mPrintSettings, gtkOrient);
   gtk_page_setup_set_orientation(mPageSetup, gtkOrient);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrintSettingsGTK::GetToFileName(char16_t * *aToFileName)
+nsPrintSettingsGTK::GetToFileName(nsAString& aToFileName)
 {
   // Get the gtk output filename
   const char* gtk_output_uri = gtk_print_settings_get(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI);
   if (!gtk_output_uri) {
-    *aToFileName = ToNewUnicode(mToFileName);
+    aToFileName = mToFileName;
     return NS_OK;
   }
 
   // Convert to an nsIFile
   nsCOMPtr<nsIFile> file;
   nsresult rv = NS_GetFileFromURLSpec(nsDependentCString(gtk_output_uri),
                                       getter_AddRefs(file));
   if (NS_FAILED(rv))
     return rv;
 
   // Extract the path
-  nsAutoString path;
-  rv = file->GetPath(path);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aToFileName = ToNewUnicode(path);
-  return NS_OK;
+  return file->GetPath(aToFileName);
 }
 
 NS_IMETHODIMP
-nsPrintSettingsGTK::SetToFileName(const char16_t * aToFileName)
+nsPrintSettingsGTK::SetToFileName(const nsAString& aToFileName)
 {
-  if (aToFileName[0] == 0) {
+  if (aToFileName.IsEmpty()) {
     mToFileName.SetLength(0);
     gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI,
                            nullptr);
     return NS_OK;
   }
 
-  if (StringEndsWith(nsDependentString(aToFileName), NS_LITERAL_STRING(".ps"))) {
+  if (StringEndsWith(aToFileName, NS_LITERAL_STRING(".ps"))) {
     gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, "ps");
   } else {
     gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, "pdf");
   }
 
   nsCOMPtr<nsIFile> file;
-  nsresult rv = NS_NewLocalFile(nsDependentString(aToFileName), true,
-                                getter_AddRefs(file));
+  nsresult rv = NS_NewLocalFile(aToFileName, true, getter_AddRefs(file));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Convert the nsIFile to a URL
   nsAutoCString url;
   rv = NS_GetURLSpecFromFile(file, url);
   NS_ENSURE_SUCCESS(rv, rv);
 
   gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI, url.get());
   mToFileName = aToFileName;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrintSettingsGTK::GetPrinterName(char16_t * *aPrinter)
+nsPrintSettingsGTK::GetPrinterName(nsAString& aPrinter)
 {
   const char* gtkPrintName = gtk_print_settings_get_printer(mPrintSettings);
   if (!gtkPrintName) {
     if (GTK_IS_PRINTER(mGTKPrinter)) {
       gtkPrintName = gtk_printer_get_name(mGTKPrinter);
     } else {
       // This mimics what nsPrintSettingsImpl does when we try to Get before we Set
-      nsString nullPrintName;
-      *aPrinter = ToNewUnicode(nullPrintName);
+      aPrinter.Truncate();
       return NS_OK;
     }
   }
-  *aPrinter = UTF8ToNewUnicode(nsDependentCString(gtkPrintName));
+  aPrinter = NS_ConvertUTF8toUTF16(gtkPrintName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrintSettingsGTK::SetPrinterName(const char16_t * aPrinter)
+nsPrintSettingsGTK::SetPrinterName(const nsAString& aPrinter)
 {
   NS_ConvertUTF16toUTF8 gtkPrinter(aPrinter);
 
   if (StringBeginsWith(gtkPrinter, NS_LITERAL_CSTRING("CUPS/"))) {
     // Strip off "CUPS/"; GTK might recognize the rest
     gtkPrinter.Cut(0, strlen("CUPS/"));
   }
 
@@ -532,26 +525,25 @@ nsPrintSettingsGTK::GetScaling(double *a
 NS_IMETHODIMP
 nsPrintSettingsGTK::SetScaling(double aScaling)
 {
   gtk_print_settings_set_scale(mPrintSettings, aScaling * 100.0);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrintSettingsGTK::GetPaperName(char16_t * *aPaperName)
+nsPrintSettingsGTK::GetPaperName(nsAString& aPaperName)
 {
-  NS_ENSURE_ARG_POINTER(aPaperName);
   const gchar* name =
     gtk_paper_size_get_name(gtk_page_setup_get_paper_size(mPageSetup));
-  *aPaperName = ToNewUnicode(NS_ConvertUTF8toUTF16(name));
+  aPaperName = NS_ConvertUTF8toUTF16(name);
   return NS_OK;
 }
 NS_IMETHODIMP
-nsPrintSettingsGTK::SetPaperName(const char16_t * aPaperName)
+nsPrintSettingsGTK::SetPaperName(const nsAString& aPaperName)
 {
   NS_ConvertUTF16toUTF8 gtkPaperName(aPaperName);
 
   // Convert these Gecko names to GTK names
   if (gtkPaperName.EqualsIgnoreCase("letter"))
     gtkPaperName.AssignLiteral(GTK_PAPER_NAME_LETTER);
   else if (gtkPaperName.EqualsIgnoreCase("legal"))
     gtkPaperName.AssignLiteral(GTK_PAPER_NAME_LEGAL);
--- a/widget/gtk/nsPrintSettingsGTK.h
+++ b/widget/gtk/nsPrintSettingsGTK.h
@@ -63,34 +63,34 @@ public:
   NS_IMETHOD SetPrintReversed(bool aPrintReversed) override;
 
   NS_IMETHOD GetPrintInColor(bool *aPrintInColor) override;
   NS_IMETHOD SetPrintInColor(bool aPrintInColor) override;
 
   NS_IMETHOD GetOrientation(int32_t *aOrientation) override;
   NS_IMETHOD SetOrientation(int32_t aOrientation) override;
 
-  NS_IMETHOD GetToFileName(char16_t * *aToFileName) override;
-  NS_IMETHOD SetToFileName(const char16_t * aToFileName) override;
+  NS_IMETHOD GetToFileName(nsAString& aToFileName) override;
+  NS_IMETHOD SetToFileName(const nsAString& aToFileName) override;
 
   // Gets/Sets the printer name in the GtkPrintSettings. If no printer name is specified there,
   // you will get back the name of the current internal GtkPrinter.
-  NS_IMETHOD GetPrinterName(char16_t * *aPrinter) override;
-  NS_IMETHOD SetPrinterName(const char16_t * aPrinter) override;
+  NS_IMETHOD GetPrinterName(nsAString& Printer) override;
+  NS_IMETHOD SetPrinterName(const nsAString& aPrinter) override;
 
   // Number of copies is stored/gotten from the GtkPrintSettings.
   NS_IMETHOD GetNumCopies(int32_t *aNumCopies) override;
   NS_IMETHOD SetNumCopies(int32_t aNumCopies) override;
 
   NS_IMETHOD GetScaling(double *aScaling) override;
   NS_IMETHOD SetScaling(double aScaling) override;
 
   // A name recognised by GTK is strongly advised here, as this is used to create a GtkPaperSize.
-  NS_IMETHOD GetPaperName(char16_t * *aPaperName) override;
-  NS_IMETHOD SetPaperName(const char16_t * aPaperName) override;
+  NS_IMETHOD GetPaperName(nsAString& aPaperName) override;
+  NS_IMETHOD SetPaperName(const nsAString& aPaperName) override;
 
   NS_IMETHOD SetUnwriteableMarginInTwips(nsIntMargin& aUnwriteableMargin) override;
   NS_IMETHOD SetUnwriteableMarginTop(double aUnwriteableMarginTop) override;
   NS_IMETHOD SetUnwriteableMarginLeft(double aUnwriteableMarginLeft) override;
   NS_IMETHOD SetUnwriteableMarginBottom(double aUnwriteableMarginBottom) override;
   NS_IMETHOD SetUnwriteableMarginRight(double aUnwriteableMarginRight) override;
 
   NS_IMETHOD GetPaperWidth(double *aPaperWidth) override;
--- a/widget/nsIPrintSettings.idl
+++ b/widget/nsIPrintSettings.idl
@@ -197,51 +197,51 @@ interface nsIPrintSettings : nsISupports
   attribute double  unwriteableMarginRight;
 
   attribute double  scaling;      /* values 0.0 - 1.0 */
   attribute boolean printBGColors; /* Print Background Colors */
   attribute boolean printBGImages; /* Print Background Images */
 
   attribute short   printRange; 
 
-  attribute wstring title;
-  attribute wstring docURL;
+  attribute AString title;
+  attribute AString docURL;
 
-  attribute wstring headerStrLeft;
-  attribute wstring headerStrCenter;
-  attribute wstring headerStrRight;
+  attribute AString headerStrLeft;
+  attribute AString headerStrCenter;
+  attribute AString headerStrRight;
 
-  attribute wstring footerStrLeft;
-  attribute wstring footerStrCenter;
-  attribute wstring footerStrRight;
+  attribute AString footerStrLeft;
+  attribute AString footerStrCenter;
+  attribute AString footerStrRight;
 
   attribute short   howToEnableFrameUI;  /* indicates how to enable the frameset UI            */
   attribute boolean isCancelled;         /* indicates whether the print job has been cancelled */
   attribute short   printFrameTypeUsage; /* indicates whether to use the interal value or not  */
   attribute short   printFrameType;
   attribute boolean printSilent;	     /* print without putting up the dialog */
   attribute boolean shrinkToFit;	     /* shrinks content to fit on page      */
   attribute boolean showPrintProgress;   /* indicates whether the progress dialog should be shown */
 
   /* Additional XP Related */
-  attribute wstring paperName;     /* name of paper */
+  attribute AString paperName;     /* name of paper */
   attribute short   paperData;     /* native data value */
   attribute double  paperWidth;    /* width of the paper in inches or mm */
   attribute double  paperHeight;   /* height of the paper in inches or mm */
   attribute short   paperSizeUnit; /* paper is in inches or mm */
 
   attribute boolean printReversed;
   attribute boolean printInColor;  /* a false means grayscale */
   attribute long    orientation;   /*  see orientation consts */
   attribute long    numCopies;
 
-  attribute wstring printerName;   /* name of destination printer */
+  attribute AString printerName;   /* name of destination printer */
 
   attribute boolean printToFile;
-  attribute wstring toFileName;
+  attribute AString toFileName;
   attribute short   outputFormat;
 
   attribute long    printPageDelay; /* in milliseconds */
 
   attribute long    resolution;     /* print resolution (dpi) */
 
   attribute long    duplex;         /* duplex mode */
 
--- a/widget/nsIPrintSettingsService.idl
+++ b/widget/nsIPrintSettingsService.idl
@@ -53,27 +53,28 @@ interface nsIPrintSettingsService : nsIS
    * (Note: this may not happen if there is an OS specific implementation.)
    *
    */
   readonly attribute nsIPrintSettings newPrintSettings;
 
   /**
    * The name of the last printer used, or else the system default printer.
    */
-  readonly attribute wstring defaultPrinterName;
+  readonly attribute AString defaultPrinterName;
 
   /**
    * Initializes certain settings from the native printer into the PrintSettings
    * if aPrinterName is null then it uses the default printer name if it can
    * These settings include, but are not limited to:
    *   Page Orientation
    *   Page Size
    *   Number of Copies
    */
-  void initPrintSettingsFromPrinter(in wstring aPrinterName, in nsIPrintSettings aPrintSettings);
+  void initPrintSettingsFromPrinter(in AString aPrinterName,
+                                    in nsIPrintSettings aPrintSettings);
 
   /**
    * Reads PrintSettings values from Prefs,
    * the values to be read are indicated by the "flags" arg.
    *
    * aPrintSettings should be initialized with the name of a printer. First
    * it reads in the PrintSettings from the last print job. Then it uses the
    * PrinterName in the PrinterSettings to read any settings that were saved
--- a/widget/nsIPrintSettingsWin.idl
+++ b/widget/nsIPrintSettingsWin.idl
@@ -30,18 +30,18 @@ interface nsIPrintSettingsWin : nsISuppo
    * you own the memory.
    *
    * The following three pieces of data are needed
    * to create a DC for printing. These are typcially 
    * gotten via the PrintDLG call ro can be obtained
    * via the "m_pd" data member of the CPrintDialog
    * in MFC.
    */
-  [noscript] attribute wstring deviceName;
-  [noscript] attribute wstring driverName;
+  [noscript] attribute AString deviceName;
+  [noscript] attribute AString driverName;
 
   [noscript] attribute nsDevMode devMode;
 
   /**
    * On Windows we use the printable width and height for the printing surface.
    * We don't want to have to create native print device contexts in the content
    * process, so we need to store these in the settings.
    * Storing in Inches is most convenient as they are retrieved from the device
--- a/widget/nsIPrinterEnumerator.idl
+++ b/widget/nsIPrinterEnumerator.idl
@@ -13,25 +13,26 @@ interface nsIStringEnumerator;
 interface nsIPrinterEnumerator : nsISupports
 {
   /**
    * The name of the system default printer. This name should also be
    * present in printerNameList below. This is not necessarily gecko's
    * default printer; see nsIPrintSettingsService.defaultPrinterName
    * for that.
    */
-  readonly attribute wstring defaultPrinterName;
+  readonly attribute AString defaultPrinterName;
 
   /**
    * Initializes certain settings from the native printer into the PrintSettings
    * These settings include, but are not limited to:
    *   Page Orientation
    *   Page Size
    *   Number of Copies
    */
-  void initPrintSettingsFromPrinter(in wstring aPrinterName, in nsIPrintSettings aPrintSettings);
+  void initPrintSettingsFromPrinter(in AString aPrinterName,
+                                    in nsIPrintSettings aPrintSettings);
 
   /**
    * The list of printer names
    */
   readonly attribute nsIStringEnumerator printerNameList;
 };
 
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -133,83 +133,52 @@ nsPrintOptions::SerializeToPrintData(nsI
   aSettings->GetUnwriteableMarginRight(&data->unwriteableMarginRight());
 
   aSettings->GetScaling(&data->scaling());
 
   aSettings->GetPrintBGColors(&data->printBGColors());
   aSettings->GetPrintBGImages(&data->printBGImages());
   aSettings->GetPrintRange(&data->printRange());
 
-  // I have no idea if I'm doing this string copying correctly...
-  nsString title;
-  aSettings->GetTitle(getter_Copies(title));
-  data->title() = title;
-
-  nsString docURL;
-  aSettings->GetDocURL(getter_Copies(docURL));
-  data->docURL() = docURL;
-
-  // Header strings...
-  nsString headerStrLeft;
-  aSettings->GetHeaderStrLeft(getter_Copies(headerStrLeft));
-  data->headerStrLeft() = headerStrLeft;
+  aSettings->GetTitle(data->title());
+  aSettings->GetDocURL(data->docURL());
 
-  nsString headerStrCenter;
-  aSettings->GetHeaderStrCenter(getter_Copies(headerStrCenter));
-  data->headerStrCenter() = headerStrCenter;
-
-  nsString headerStrRight;
-  aSettings->GetHeaderStrRight(getter_Copies(headerStrRight));
-  data->headerStrRight() = headerStrRight;
+  aSettings->GetHeaderStrLeft(data->headerStrLeft());
+  aSettings->GetHeaderStrCenter(data->headerStrCenter());
+  aSettings->GetHeaderStrRight(data->headerStrRight());
 
-  // Footer strings...
-  nsString footerStrLeft;
-  aSettings->GetFooterStrLeft(getter_Copies(footerStrLeft));
-  data->footerStrLeft() = footerStrLeft;
-
-  nsString footerStrCenter;
-  aSettings->GetFooterStrCenter(getter_Copies(footerStrCenter));
-  data->footerStrCenter() = footerStrCenter;
-
-  nsString footerStrRight;
-  aSettings->GetFooterStrRight(getter_Copies(footerStrRight));
-  data->footerStrRight() = footerStrRight;
+  aSettings->GetFooterStrLeft(data->footerStrLeft());
+  aSettings->GetFooterStrCenter(data->footerStrCenter());
+  aSettings->GetFooterStrRight(data->footerStrRight());
 
   aSettings->GetHowToEnableFrameUI(&data->howToEnableFrameUI());
   aSettings->GetIsCancelled(&data->isCancelled());
   aSettings->GetPrintFrameTypeUsage(&data->printFrameTypeUsage());
   aSettings->GetPrintFrameType(&data->printFrameType());
   aSettings->GetPrintSilent(&data->printSilent());
   aSettings->GetShrinkToFit(&data->shrinkToFit());
   aSettings->GetShowPrintProgress(&data->showPrintProgress());
 
-  nsString paperName;
-  aSettings->GetPaperName(getter_Copies(paperName));
-  data->paperName() = paperName;
-
+  aSettings->GetPaperName(data->paperName());
   aSettings->GetPaperData(&data->paperData());
   aSettings->GetPaperWidth(&data->paperWidth());
   aSettings->GetPaperHeight(&data->paperHeight());
   aSettings->GetPaperSizeUnit(&data->paperSizeUnit());
 
   aSettings->GetPrintReversed(&data->printReversed());
   aSettings->GetPrintInColor(&data->printInColor());
   aSettings->GetOrientation(&data->orientation());
 
   aSettings->GetNumCopies(&data->numCopies());
 
-  nsString printerName;
-  aSettings->GetPrinterName(getter_Copies(printerName));
-  data->printerName() = printerName;
+  aSettings->GetPrinterName(data->printerName());
 
   aSettings->GetPrintToFile(&data->printToFile());
 
-  nsString toFileName;
-  aSettings->GetToFileName(getter_Copies(toFileName));
-  data->toFileName() = toFileName;
+  aSettings->GetToFileName(data->toFileName());
 
   aSettings->GetOutputFormat(&data->outputFormat());
   aSettings->GetPrintPageDelay(&data->printPageDelay());
   aSettings->GetResolution(&data->resolution());
   aSettings->GetDuplex(&data->duplex());
   aSettings->GetIsInitializedFromPrinter(&data->isInitializedFromPrinter());
   aSettings->GetIsInitializedFromPrefs(&data->isInitializedFromPrefs());
 
@@ -271,56 +240,55 @@ nsPrintOptions::DeserializeToPrintSettin
   settings->SetUnwriteableMarginRight(data.unwriteableMarginRight());
 
   settings->SetScaling(data.scaling());
 
   settings->SetPrintBGColors(data.printBGColors());
   settings->SetPrintBGImages(data.printBGImages());
   settings->SetPrintRange(data.printRange());
 
-  // I have no idea if I'm doing this string copying correctly...
-  settings->SetTitle(data.title().get());
-  settings->SetDocURL(data.docURL().get());
+  settings->SetTitle(data.title());
+  settings->SetDocURL(data.docURL());
 
   // Header strings...
-  settings->SetHeaderStrLeft(data.headerStrLeft().get());
-  settings->SetHeaderStrCenter(data.headerStrCenter().get());
-  settings->SetHeaderStrRight(data.headerStrRight().get());
+  settings->SetHeaderStrLeft(data.headerStrLeft());
+  settings->SetHeaderStrCenter(data.headerStrCenter());
+  settings->SetHeaderStrRight(data.headerStrRight());
 
   // Footer strings...
-  settings->SetFooterStrLeft(data.footerStrLeft().get());
-  settings->SetFooterStrCenter(data.footerStrCenter().get());
-  settings->SetFooterStrRight(data.footerStrRight().get());
+  settings->SetFooterStrLeft(data.footerStrLeft());
+  settings->SetFooterStrCenter(data.footerStrCenter());
+  settings->SetFooterStrRight(data.footerStrRight());
 
   settings->SetHowToEnableFrameUI(data.howToEnableFrameUI());
   settings->SetIsCancelled(data.isCancelled());
   settings->SetPrintFrameTypeUsage(data.printFrameTypeUsage());
   settings->SetPrintFrameType(data.printFrameType());
   settings->SetPrintSilent(data.printSilent());
   settings->SetShrinkToFit(data.shrinkToFit());
   settings->SetShowPrintProgress(data.showPrintProgress());
 
-  settings->SetPaperName(data.paperName().get());
+  settings->SetPaperName(data.paperName());
 
   settings->SetPaperData(data.paperData());
   settings->SetPaperWidth(data.paperWidth());
   settings->SetPaperHeight(data.paperHeight());
   settings->SetPaperSizeUnit(data.paperSizeUnit());
 
   settings->SetPrintReversed(data.printReversed());
   settings->SetPrintInColor(data.printInColor());
   settings->SetOrientation(data.orientation());
 
   settings->SetNumCopies(data.numCopies());
 
-  settings->SetPrinterName(data.printerName().get());
+  settings->SetPrinterName(data.printerName());
 
   settings->SetPrintToFile(data.printToFile());
 
-  settings->SetToFileName(data.toFileName().get());
+  settings->SetToFileName(data.toFileName());
 
   settings->SetOutputFormat(data.outputFormat());
   settings->SetPrintPageDelay(data.printPageDelay());
   settings->SetResolution(data.resolution());
   settings->SetDuplex(data.duplex());
   settings->SetIsInitializedFromPrinter(data.isInitializedFromPrinter());
   settings->SetIsInitializedFromPrefs(data.isInitializedFromPrefs());
 
@@ -528,17 +496,17 @@ nsPrintOptions::ReadPrefs(nsIPrintSettin
 
     if (success) {
       aPS->SetPaperSizeUnit(sizeUnit);
       DUMP_INT(kReadStr, kPrintPaperSizeUnit, sizeUnit);
       aPS->SetPaperWidth(width);
       DUMP_DBL(kReadStr, kPrintPaperWidth, width);
       aPS->SetPaperHeight(height);
       DUMP_DBL(kReadStr, kPrintPaperHeight, height);
-      aPS->SetPaperName(str.get());
+      aPS->SetPaperName(str);
       DUMP_STR(kReadStr, kPrintPaperName, str.get());
 #if defined(XP_WIN)
       if (saveSanitizedSizePrefs) {
         SavePrintSettingsToPrefs(aPS, !aPrinterName.IsEmpty(),
                                  nsIPrintSettings::kInitSavePaperSize);
       }
 #endif
     }
@@ -555,52 +523,52 @@ nsPrintOptions::ReadPrefs(nsIPrintSettin
     if (GETBOOLPREF(kPrintOddPages, &b)) {
       aPS->SetPrintOptions(nsIPrintSettings::kPrintOddPages, b);
       DUMP_BOOL(kReadStr, kPrintOddPages, b);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveHeaderLeft) {
     if (GETSTRPREF(kPrintHeaderStrLeft, str)) {
-      aPS->SetHeaderStrLeft(str.get());
+      aPS->SetHeaderStrLeft(str);
       DUMP_STR(kReadStr, kPrintHeaderStrLeft, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveHeaderCenter) {
     if (GETSTRPREF(kPrintHeaderStrCenter, str)) {
-      aPS->SetHeaderStrCenter(str.get());
+      aPS->SetHeaderStrCenter(str);
       DUMP_STR(kReadStr, kPrintHeaderStrCenter, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveHeaderRight) {
     if (GETSTRPREF(kPrintHeaderStrRight, str)) {
-      aPS->SetHeaderStrRight(str.get());
+      aPS->SetHeaderStrRight(str);
       DUMP_STR(kReadStr, kPrintHeaderStrRight, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveFooterLeft) {
     if (GETSTRPREF(kPrintFooterStrLeft, str)) {
-      aPS->SetFooterStrLeft(str.get());
+      aPS->SetFooterStrLeft(str);
       DUMP_STR(kReadStr, kPrintFooterStrLeft, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveFooterCenter) {
     if (GETSTRPREF(kPrintFooterStrCenter, str)) {
-      aPS->SetFooterStrCenter(str.get());
+      aPS->SetFooterStrCenter(str);
       DUMP_STR(kReadStr, kPrintFooterStrCenter, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveFooterRight) {
     if (GETSTRPREF(kPrintFooterStrRight, str)) {
-      aPS->SetFooterStrRight(str.get());
+      aPS->SetFooterStrRight(str);
       DUMP_STR(kReadStr, kPrintFooterStrRight, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveBGColors) {
     if (GETBOOLPREF(kPrintBGColors, &b)) {
       aPS->SetPrintBGColors(b);
       DUMP_BOOL(kReadStr, kPrintBGColors, b);
@@ -646,17 +614,17 @@ nsPrintOptions::ReadPrefs(nsIPrintSettin
     if (GETBOOLPREF(kPrintToFile, &b)) {
       aPS->SetPrintToFile(b);
       DUMP_BOOL(kReadStr, kPrintToFile, b);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveToFileName) {
     if (GETSTRPREF(kPrintToFileName, str)) {
-      aPS->SetToFileName(str.get());
+      aPS->SetToFileName(str);
       DUMP_STR(kReadStr, kPrintToFileName, str.get());
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSavePageDelay) {
     if (GETINTPREF(kPrintPageDelay, &iVal)) {
       aPS->SetPrintPageDelay(iVal);
       DUMP_INT(kReadStr, kPrintPageDelay, iVal);
@@ -766,17 +734,17 @@ nsPrintOptions::WritePrefs(nsIPrintSetti
     int16_t sizeUnit;
     double width, height;
     nsString name;
 
     if (
       NS_SUCCEEDED(aPS->GetPaperSizeUnit(&sizeUnit)) &&
       NS_SUCCEEDED(aPS->GetPaperWidth(&width)) &&
       NS_SUCCEEDED(aPS->GetPaperHeight(&height)) &&
-      NS_SUCCEEDED(aPS->GetPaperName(getter_Copies(name)))
+      NS_SUCCEEDED(aPS->GetPaperName(name))
     ) {
       DUMP_INT(kWriteStr, kPrintPaperSizeUnit, sizeUnit);
       Preferences::SetInt(GetPrefName(kPrintPaperSizeUnit, aPrinterName),
                           int32_t(sizeUnit));
       DUMP_DBL(kWriteStr, kPrintPaperWidth, width);
       WritePrefDouble(GetPrefName(kPrintPaperWidth, aPrinterName), width);
       DUMP_DBL(kWriteStr, kPrintPaperHeight, height);
       WritePrefDouble(GetPrefName(kPrintPaperHeight, aPrinterName), height);
@@ -817,57 +785,57 @@ nsPrintOptions::WritePrefs(nsIPrintSetti
     if (NS_SUCCEEDED(aPS->GetPrintOptions(nsIPrintSettings::kPrintOddPages,
                                           &b))) {
           DUMP_BOOL(kWriteStr, kPrintOddPages, b);
           Preferences::SetBool(GetPrefName(kPrintOddPages, aPrinterName), b);
         }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveHeaderLeft) {
-    if (NS_SUCCEEDED(aPS->GetHeaderStrLeft(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetHeaderStrLeft(uStr))) {
       DUMP_STR(kWriteStr, kPrintHeaderStrLeft, uStr.get());
       Preferences::SetString(GetPrefName(kPrintHeaderStrLeft, aPrinterName),
                              uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveHeaderCenter) {
-    if (NS_SUCCEEDED(aPS->GetHeaderStrCenter(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetHeaderStrCenter(uStr))) {
       DUMP_STR(kWriteStr, kPrintHeaderStrCenter, uStr.get());
       Preferences::SetString(GetPrefName(kPrintHeaderStrCenter, aPrinterName),
                              uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveHeaderRight) {
-    if (NS_SUCCEEDED(aPS->GetHeaderStrRight(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetHeaderStrRight(uStr))) {
       DUMP_STR(kWriteStr, kPrintHeaderStrRight, uStr.get());
       Preferences::SetString(GetPrefName(kPrintHeaderStrRight, aPrinterName),
                              uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveFooterLeft) {
-    if (NS_SUCCEEDED(aPS->GetFooterStrLeft(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetFooterStrLeft(uStr))) {
       DUMP_STR(kWriteStr, kPrintFooterStrLeft, uStr.get());
       Preferences::SetString(GetPrefName(kPrintFooterStrLeft, aPrinterName),
                              uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveFooterCenter) {
-    if (NS_SUCCEEDED(aPS->GetFooterStrCenter(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetFooterStrCenter(uStr))) {
       DUMP_STR(kWriteStr, kPrintFooterStrCenter, uStr.get());
       Preferences::SetString(GetPrefName(kPrintFooterStrCenter, aPrinterName),
                              uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveFooterRight) {
-    if (NS_SUCCEEDED(aPS->GetFooterStrRight(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetFooterStrRight(uStr))) {
       DUMP_STR(kWriteStr, kPrintFooterStrRight, uStr.get());
       Preferences::SetString(GetPrefName(kPrintFooterStrRight, aPrinterName),
                              uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveBGColors) {
     if (NS_SUCCEEDED(aPS->GetPrintBGColors(&b))) {
@@ -910,31 +878,31 @@ nsPrintOptions::WritePrefs(nsIPrintSetti
       DUMP_INT(kWriteStr, kPrintOrientation, iVal);
       Preferences::SetInt(GetPrefName(kPrintOrientation, aPrinterName), iVal);
     }
   }
 
   // Only the general version of this pref is saved
   if ((aFlags & nsIPrintSettings::kInitSavePrinterName)
       && aPrinterName.IsEmpty()) {
-    if (NS_SUCCEEDED(aPS->GetPrinterName(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetPrinterName(uStr))) {
       DUMP_STR(kWriteStr, kPrinterName, uStr.get());
       Preferences::SetString(kPrinterName, uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSavePrintToFile) {
     if (NS_SUCCEEDED(aPS->GetPrintToFile(&b))) {
       DUMP_BOOL(kWriteStr, kPrintToFile, b);
       Preferences::SetBool(GetPrefName(kPrintToFile, aPrinterName), b);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveToFileName) {
-    if (NS_SUCCEEDED(aPS->GetToFileName(getter_Copies(uStr)))) {
+    if (NS_SUCCEEDED(aPS->GetToFileName(uStr))) {
       DUMP_STR(kWriteStr, kPrintToFileName, uStr.get());
       Preferences::SetString(GetPrefName(kPrintToFileName, aPrinterName), uStr);
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSavePageDelay) {
     if (NS_SUCCEEDED(aPS->GetPrintPageDelay(&iVal))) {
       DUMP_INT(kWriteStr, kPrintPageDelay, iVal);
@@ -980,19 +948,19 @@ nsresult nsPrintOptions::_CreatePrintSet
 {
   // does not initially ref count
   nsPrintSettings * printSettings = new nsPrintSettings();
   NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*_retval = printSettings); // ref count
 
   nsString printerName;
-  nsresult rv = GetDefaultPrinterName(getter_Copies(printerName));
+  nsresult rv = GetDefaultPrinterName(printerName);
   NS_ENSURE_SUCCESS(rv, rv);
-  (*_retval)->SetPrinterName(printerName.get());
+  (*_retval)->SetPrinterName(printerName);
 
   (void)InitPrintSettingsFromPrefs(*_retval, false,
                                    nsIPrintSettings::kInitSaveAll);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1010,17 +978,17 @@ nsPrintOptions::GetGlobalPrintSettings(n
 
 NS_IMETHODIMP
 nsPrintOptions::GetNewPrintSettings(nsIPrintSettings * *aNewPrintSettings)
 {
   return _CreatePrintSettings(aNewPrintSettings);
 }
 
 NS_IMETHODIMP
-nsPrintOptions::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
+nsPrintOptions::GetDefaultPrinterName(nsAString& aDefaultPrinterName)
 {
   nsresult rv;
   nsCOMPtr<nsIPrinterEnumerator> prtEnum =
            do_GetService(NS_PRINTER_ENUMERATOR_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Look up the printer from the last print job
   nsAutoString lastPrinterName;
@@ -1035,43 +1003,42 @@ nsPrintOptions::GetDefaultPrinterName(ch
       while (NS_SUCCEEDED(printers->HasMore(&hasMore)) && hasMore) {
         nsAutoString printer;
         if (NS_SUCCEEDED(printers->GetNext(printer)) && lastPrinterName.Equals(printer)) {
           isValid = true;
           break;
         }
       }
       if (isValid) {
-        *aDefaultPrinterName = ToNewUnicode(lastPrinterName);
+        aDefaultPrinterName = lastPrinterName;
         return NS_OK;
       }
     }
   }
 
   // There is no last printer preference, or it doesn't name a valid printer.
   // Return the default from the printer enumeration.
   return prtEnum->GetDefaultPrinterName(aDefaultPrinterName);
 }
 
 NS_IMETHODIMP
-nsPrintOptions::InitPrintSettingsFromPrinter(const char16_t *aPrinterName,
+nsPrintOptions::InitPrintSettingsFromPrinter(const nsAString& aPrinterName,
                                              nsIPrintSettings *aPrintSettings)
 {
   // Don't get print settings from the printer in the child when printing via
   // parent, these will be retrieved in the parent later in the print process.
   if (XRE_IsContentProcess() && Preferences::GetBool("print.print_via_parent")) {
     return NS_OK;
   }
 
   NS_ENSURE_ARG_POINTER(aPrintSettings);
-  NS_ENSURE_ARG_POINTER(aPrinterName);
 
 #ifdef DEBUG
   nsString printerName;
-  aPrintSettings->GetPrinterName(getter_Copies(printerName));
+  aPrintSettings->GetPrinterName(printerName);
   if (!printerName.Equals(aPrinterName)) {
     NS_WARNING("Printer names should match!");
   }
 #endif
 
   bool isInitialized;
   aPrintSettings->GetIsInitializedFromPrinter(&isInitialized);
   if (isInitialized)
@@ -1100,17 +1067,17 @@ GetAdjustedPrinterName(nsIPrintSettings*
   NS_ENSURE_ARG_POINTER(aPS);
 
   aPrinterName.Truncate();
   if (!aUsePNP)
     return NS_OK;
 
   // Get the Printer Name from the PrintSettings
   // to use as a prefix for Pref Names
-  nsresult rv = aPS->GetPrinterName(getter_Copies(aPrinterName));
+  nsresult rv = aPS->GetPrinterName(aPrinterName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Convert any whitespaces, carriage returns or newlines to _
   // The below algorithm is supposedly faster than using iterators
   NS_NAMED_LITERAL_STRING(replSubstr, "_");
   const char* replaceStr = " \n\r";
 
   int32_t x;
--- a/widget/nsPrintSettingsImpl.cpp
+++ b/widget/nsPrintSettingsImpl.cpp
@@ -187,29 +187,25 @@ NS_IMETHODIMP nsPrintSettings::GetDuplex
   return NS_OK;
 }
 NS_IMETHODIMP nsPrintSettings::SetDuplex(const int32_t aDuplex)
 {
   mDuplex = aDuplex;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetPrinterName(char16_t * *aPrinter)
+NS_IMETHODIMP nsPrintSettings::GetPrinterName(nsAString& aPrinter)
 {
-   NS_ENSURE_ARG_POINTER(aPrinter);
-
-   *aPrinter = ToNewUnicode(mPrinter);
-   NS_ENSURE_TRUE(*aPrinter, NS_ERROR_OUT_OF_MEMORY);
-
+   aPrinter = mPrinter;
    return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::SetPrinterName(const char16_t * aPrinter)
+NS_IMETHODIMP nsPrintSettings::SetPrinterName(const nsAString& aPrinter)
 {
-  if (!aPrinter || !mPrinter.Equals(aPrinter)) {
+  if (!mPrinter.Equals(aPrinter)) {
     mIsInitedFromPrinter = false;
     mIsInitedFromPrefs   = false;
   }
 
   mPrinter.Assign(aPrinter);
   return NS_OK;
 }
 
@@ -232,29 +228,24 @@ NS_IMETHODIMP nsPrintSettings::GetPrintT
   return NS_OK;
 }
 NS_IMETHODIMP nsPrintSettings::SetPrintToFile(bool aPrintToFile)
 {
   mPrintToFile = aPrintToFile;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetToFileName(char16_t * *aToFileName)
+NS_IMETHODIMP nsPrintSettings::GetToFileName(nsAString& aToFileName)
 {
-  //NS_ENSURE_ARG_POINTER(aToFileName);
-  *aToFileName = ToNewUnicode(mToFileName);
+  aToFileName = mToFileName;
   return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettings::SetToFileName(const char16_t * aToFileName)
+NS_IMETHODIMP nsPrintSettings::SetToFileName(const nsAString& aToFileName)
 {
-  if (aToFileName) {
-    mToFileName = aToFileName;
-  } else {
-    mToFileName.SetLength(0);
-  }
+  mToFileName = aToFileName;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPrintSettings::GetOutputFormat(int16_t *aOutputFormat)
 {
   NS_ENSURE_ARG_POINTER(aOutputFormat);
   *aOutputFormat = mOutputFormat;
   return NS_OK;
@@ -496,53 +487,35 @@ NS_IMETHODIMP nsPrintSettings::GetPrintR
   return NS_OK;
 }
 NS_IMETHODIMP nsPrintSettings::SetPrintRange(int16_t aPrintRange)
 {
   mPrintRange = aPrintRange;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetTitle(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::GetTitle(nsAString& aTitle)
 {
-  NS_ENSURE_ARG_POINTER(aTitle);
-  if (!mTitle.IsEmpty()) {
-    *aTitle = ToNewUnicode(mTitle);
-  } else {
-    *aTitle = nullptr;
-  }
+  aTitle = mTitle;
   return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettings::SetTitle(const char16_t * aTitle)
+NS_IMETHODIMP nsPrintSettings::SetTitle(const nsAString& aTitle)
 {
-  if (aTitle) {
-    mTitle = aTitle;
-  } else {
-    mTitle.SetLength(0);
-  }
+  mTitle = aTitle;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetDocURL(char16_t * *aDocURL)
+NS_IMETHODIMP nsPrintSettings::GetDocURL(nsAString& aDocURL)
 {
-  NS_ENSURE_ARG_POINTER(aDocURL);
-  if (!mURL.IsEmpty()) {
-    *aDocURL = ToNewUnicode(mURL);
-  } else {
-    *aDocURL = nullptr;
-  }
+  aDocURL = mURL;
   return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettings::SetDocURL(const char16_t * aDocURL)
+NS_IMETHODIMP nsPrintSettings::SetDocURL(const nsAString& aDocURL)
 {
-  if (aDocURL) {
-    mURL = aDocURL;
-  } else {
-    mURL.SetLength(0);
-  }
+  mURL = aDocURL;
   return NS_OK;
 }
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintSettingsImpl.h
  *	@update 1/12/01 rods
  */
 NS_IMETHODIMP 
@@ -581,113 +554,80 @@ nsPrintSettings::GetPrintOptionsBits(int
 
 NS_IMETHODIMP
 nsPrintSettings::SetPrintOptionsBits(int32_t aBits)
 {
   mPrintOptions = aBits;
   return NS_OK;
 }
 
-nsresult 
-nsPrintSettings::GetMarginStrs(char16_t * *aTitle, 
-                              nsHeaderFooterEnum aType, 
-                              int16_t aJust)
+NS_IMETHODIMP nsPrintSettings::GetHeaderStrLeft(nsAString& aTitle)
 {
-  NS_ENSURE_ARG_POINTER(aTitle);
-  *aTitle = nullptr;
-  if (aType == eHeader) {
-    switch (aJust) {
-      case kJustLeft:   *aTitle = ToNewUnicode(mHeaderStrs[0]);break;
-      case kJustCenter: *aTitle = ToNewUnicode(mHeaderStrs[1]);break;
-      case kJustRight:  *aTitle = ToNewUnicode(mHeaderStrs[2]);break;
-    } //switch
-  } else {
-    switch (aJust) {
-      case kJustLeft:   *aTitle = ToNewUnicode(mFooterStrs[0]);break;
-      case kJustCenter: *aTitle = ToNewUnicode(mFooterStrs[1]);break;
-      case kJustRight:  *aTitle = ToNewUnicode(mFooterStrs[2]);break;
-    } //switch
-  }
+  aTitle = mHeaderStrs[0];
+  return NS_OK;
+}
+NS_IMETHODIMP nsPrintSettings::SetHeaderStrLeft(const nsAString& aTitle)
+{
+  mHeaderStrs[0] = aTitle;
   return NS_OK;
 }
 
-nsresult
-nsPrintSettings::SetMarginStrs(const char16_t * aTitle, 
-                              nsHeaderFooterEnum aType, 
-                              int16_t aJust)
+NS_IMETHODIMP nsPrintSettings::GetHeaderStrCenter(nsAString& aTitle)
 {
-  NS_ENSURE_ARG_POINTER(aTitle);
-  if (aType == eHeader) {
-    switch (aJust) {
-      case kJustLeft:   mHeaderStrs[0] = aTitle;break;
-      case kJustCenter: mHeaderStrs[1] = aTitle;break;
-      case kJustRight:  mHeaderStrs[2] = aTitle;break;
-    } //switch
-  } else {
-    switch (aJust) {
-      case kJustLeft:   mFooterStrs[0] = aTitle;break;
-      case kJustCenter: mFooterStrs[1] = aTitle;break;
-      case kJustRight:  mFooterStrs[2] = aTitle;break;
-    } //switch
-  }
+  aTitle = mHeaderStrs[1];
+  return NS_OK;
+}
+NS_IMETHODIMP nsPrintSettings::SetHeaderStrCenter(const nsAString& aTitle)
+{
+  mHeaderStrs[1] = aTitle;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetHeaderStrLeft(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::GetHeaderStrRight(nsAString& aTitle)
 {
-  return GetMarginStrs(aTitle, eHeader, kJustLeft);
-}
-NS_IMETHODIMP nsPrintSettings::SetHeaderStrLeft(const char16_t * aTitle)
-{
-  return SetMarginStrs(aTitle, eHeader, kJustLeft);
+  aTitle = mHeaderStrs[2];
+  return NS_OK;
 }
-
-NS_IMETHODIMP nsPrintSettings::GetHeaderStrCenter(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::SetHeaderStrRight(const nsAString& aTitle)
 {
-  return GetMarginStrs(aTitle, eHeader, kJustCenter);
-}
-NS_IMETHODIMP nsPrintSettings::SetHeaderStrCenter(const char16_t * aTitle)
-{
-  return SetMarginStrs(aTitle, eHeader, kJustCenter);
+  mHeaderStrs[2] = aTitle;
+  return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetHeaderStrRight(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::GetFooterStrLeft(nsAString& aTitle)
 {
-  return GetMarginStrs(aTitle, eHeader, kJustRight);
+  aTitle = mFooterStrs[0];
+  return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettings::SetHeaderStrRight(const char16_t * aTitle)
+NS_IMETHODIMP nsPrintSettings::SetFooterStrLeft(const nsAString& aTitle)
 {
-  return SetMarginStrs(aTitle, eHeader, kJustRight);
+  mFooterStrs[0] = aTitle;
+  return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetFooterStrLeft(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::GetFooterStrCenter(nsAString& aTitle)
 {
-  return GetMarginStrs(aTitle, eFooter, kJustLeft);
+  aTitle = mFooterStrs[1];
+  return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettings::SetFooterStrLeft(const char16_t * aTitle)
+NS_IMETHODIMP nsPrintSettings::SetFooterStrCenter(const nsAString& aTitle)
 {
-  return SetMarginStrs(aTitle, eFooter, kJustLeft);
+  mFooterStrs[1] = aTitle;
+  return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetFooterStrCenter(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::GetFooterStrRight(nsAString& aTitle)
 {
-  return GetMarginStrs(aTitle, eFooter, kJustCenter);
-}
-NS_IMETHODIMP nsPrintSettings::SetFooterStrCenter(const char16_t * aTitle)
-{
-  return SetMarginStrs(aTitle, eFooter, kJustCenter);
+  aTitle = mFooterStrs[2];
+  return NS_OK;
 }
-
-NS_IMETHODIMP nsPrintSettings::GetFooterStrRight(char16_t * *aTitle)
+NS_IMETHODIMP nsPrintSettings::SetFooterStrRight(const nsAString& aTitle)
 {
-  return GetMarginStrs(aTitle, eFooter, kJustRight);
-}
-NS_IMETHODIMP nsPrintSettings::SetFooterStrRight(const char16_t * aTitle)
-{
-  return SetMarginStrs(aTitle, eFooter, kJustRight);
+  mFooterStrs[2] = aTitle;
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsPrintSettings::GetPrintFrameTypeUsage(int16_t *aPrintFrameTypeUsage)
 {
   NS_ENSURE_ARG_POINTER(aPrintFrameTypeUsage);
   *aPrintFrameTypeUsage = mPrintFrameTypeUsage;
   return NS_OK;
 }
@@ -740,33 +680,24 @@ NS_IMETHODIMP nsPrintSettings::GetShowPr
   return NS_OK;
 }
 NS_IMETHODIMP nsPrintSettings::SetShowPrintProgress(bool aShowPrintProgress)
 {
   mShowPrintProgress = aShowPrintProgress;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettings::GetPaperName(char16_t * *aPaperName)
+NS_IMETHODIMP nsPrintSettings::GetPaperName(nsAString& aPaperName)
 {
-  NS_ENSURE_ARG_POINTER(aPaperName);
-  if (!mPaperName.IsEmpty()) {
-    *aPaperName = ToNewUnicode(mPaperName);
-  } else {
-    *aPaperName = nullptr;
-  }
+  aPaperName = mPaperName;
   return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettings::SetPaperName(const char16_t * aPaperName)
+NS_IMETHODIMP nsPrintSettings::SetPaperName(const nsAString& aPaperName)
 {
-  if (aPaperName) {
-    mPaperName = aPaperName;
-  } else {
-    mPaperName.SetLength(0);
-  }
+  mPaperName = aPaperName;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPrintSettings::GetHowToEnableFrameUI(int16_t *aHowToEnableFrameUI)
 {
   NS_ENSURE_ARG_POINTER(aHowToEnableFrameUI);
   *aHowToEnableFrameUI = mHowToEnableFrameUI;
   return NS_OK;
--- a/widget/nsPrintSettingsImpl.h
+++ b/widget/nsPrintSettingsImpl.h
@@ -37,19 +37,16 @@ protected:
   virtual nsresult _Assign(nsIPrintSettings *aPS);
   
   typedef enum {
     eHeader,
     eFooter
   } nsHeaderFooterEnum;
 
 
-  nsresult GetMarginStrs(char16_t * *aTitle, nsHeaderFooterEnum aType, int16_t aJust);
-  nsresult SetMarginStrs(const char16_t * aTitle, nsHeaderFooterEnum aType, int16_t aJust);
-
   // Members
   nsWeakPtr     mSession; // Should never be touched by Clone or Assign
  
   // mMargin, mEdge, and mUnwriteableMargin are stored in twips
   nsIntMargin   mMargin;
   nsIntMargin   mEdge;
   nsIntMargin   mUnwriteableMargin;
 
--- a/widget/windows/nsDeviceContextSpecWin.cpp
+++ b/widget/windows/nsDeviceContextSpecWin.cpp
@@ -63,17 +63,17 @@ public:
   static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
   ~GlobalPrinters() { FreeGlobalPrinters(); }
 
   void FreeGlobalPrinters();
 
   bool         PrintersAreAllocated() { return mPrinters != nullptr; }
   LPWSTR       GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
   nsresult     EnumeratePrinterList();
-  void         GetDefaultPrinterName(nsString& aDefaultPrinterName);
+  void         GetDefaultPrinterName(nsAString& aDefaultPrinterName);
   uint32_t     GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
 
 protected:
   GlobalPrinters() {}
   nsresult EnumerateNativePrinters();
   void     ReallocatePrinters();
 
   static GlobalPrinters    mGlobalPrinters;
@@ -89,18 +89,16 @@ struct AutoFreeGlobalPrinters
   ~AutoFreeGlobalPrinters() {
     GlobalPrinters::GetInstance()->FreeGlobalPrinters();
   }
 };
 
 //----------------------------------------------------------------------------------
 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
 {
-  mDriverName    = nullptr;
-  mDeviceName    = nullptr;
   mDevMode       = nullptr;
 #ifdef MOZ_ENABLE_SKIA_PDF
   mPrintViaSkPDF          = false;
   mDC                     = NULL;
   mPDFPageCount           = 0;
   mPDFCurrentPageNum      = 0;
   mPrintViaPDFInProgress  = false;
 #endif
@@ -108,46 +106,34 @@ nsDeviceContextSpecWin::nsDeviceContextS
 
 
 //----------------------------------------------------------------------------------
 
 NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
 
 nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
 {
-  SetDeviceName(nullptr);
-  SetDriverName(nullptr);
   SetDevMode(nullptr);
 
   nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
   if (psWin) {
-    psWin->SetDeviceName(nullptr);
-    psWin->SetDriverName(nullptr);
+    psWin->SetDeviceName(EmptyString());
+    psWin->SetDriverName(EmptyString());
     psWin->SetDevMode(nullptr);
   }
 
 #ifdef MOZ_ENABLE_SKIA_PDF
   if (mPrintViaSkPDF ) {
     CleanupPrintViaPDF();
   }
 #endif
   // Free them, we won't need them for a while
   GlobalPrinters::GetInstance()->FreeGlobalPrinters();
 }
 
-
-//------------------------------------------------------------------
-// helper
-static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
-{
-  nsAutoString printerName;
-  GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
-  return ToNewUnicode(printerName);
-}
-
 //----------------------------------------------------------------------------------
 NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
                                            nsIPrintSettings* aPrintSettings,
                                            bool aIsPrintPreview)
 {
   mPrintSettings = aPrintSettings;
 
   nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
@@ -166,91 +152,68 @@ NS_IMETHODIMP nsDeviceContextSpecWin::In
     if ((XRE_IsContentProcess() &&
          Preferences::GetBool("print.print_via_parent")) ||
         mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
       return NS_OK;
     }
 
     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
     if (psWin) {
-      char16_t* deviceName;
-      char16_t* driverName;
-      psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
-      psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
+      nsAutoString deviceName;
+      nsAutoString driverName;
+      psWin->GetDeviceName(deviceName);
+      psWin->GetDriverName(driverName);
 
       LPDEVMODEW devMode;
       psWin->GetDevMode(&devMode);       // creates new memory (makes a copy)
 
-      if (deviceName && driverName && devMode) {
+      if (!deviceName.IsEmpty() && !driverName.IsEmpty() && devMode) {
         // Scaling is special, it is one of the few
         // devMode items that we control in layout
         if (devMode->dmFields & DM_SCALE) {
           double scale = double(devMode->dmScale) / 100.0f;
           if (scale != 1.0) {
             aPrintSettings->SetScaling(scale);
             devMode->dmScale = 100;
           }
         }
 
         SetDeviceName(deviceName);
         SetDriverName(driverName);
         SetDevMode(devMode);
 
-        // clean up
-        free(deviceName);
-        free(driverName);
-
         return NS_OK;
       } else {
         PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
-        if (deviceName) free(deviceName);
-        if (driverName) free(driverName);
         if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
       }
     }
   } else {
     PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
   }
 
   // Get the Printer Name to be used and output format.
-  char16_t * printerName = nullptr;
+  nsAutoString printerName;
   if (mPrintSettings) {
-    mPrintSettings->GetPrinterName(&printerName);
+    mPrintSettings->GetPrinterName(printerName);
   }
 
   // If there is no name then use the default printer
-  if (!printerName || (printerName && !*printerName)) {
-    printerName = GetDefaultPrinterNameFromGlobalPrinters();
+  if (printerName.IsEmpty()) {
+    GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
   }
 
-  NS_ASSERTION(printerName, "We have to have a printer name");
-  if (!printerName || !*printerName) return rv;
+  if (printerName.IsEmpty()) {
+    return rv;
+  }
 
   return GetDataFromPrinter(printerName, mPrintSettings);
 }
 
 //----------------------------------------------------------
-// Helper Function - Free and reallocate the string
-static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
-{
-  if (aStr != nullptr) {
-    if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
-      wcscpy(aStr, aNewStr);
-      return;
-    } else {
-      free(aStr);
-      aStr = nullptr;
-    }
-  }
-
-  if (nullptr != aNewStr) {
-    aStr = (wchar_t*) malloc(sizeof(wchar_t) * (wcslen(aNewStr) + 1));
-    wcscpy(aStr, aNewStr);
-  }
-}
 
 already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget()
 {
   NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
 
 #ifdef MOZ_ENABLE_SKIA_PDF
   if (mPrintViaSkPDF) {
     double width, height;
@@ -261,17 +224,17 @@ already_AddRefed<PrintTarget> nsDeviceCo
 
     // convert twips to points
     width  /= TWIPS_PER_POINT_FLOAT;
     height /= TWIPS_PER_POINT_FLOAT;
     IntSize size = IntSize::Truncate(width, height);
 
     if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
       nsString filename;
-      mPrintSettings->GetToFileName(getter_Copies(filename));
+      mPrintSettings->GetToFileName(filename);
 
       nsAutoCString printFile(NS_ConvertUTF16toUTF8(filename).get());
       auto skStream = MakeUnique<SkFILEWStream>(printFile.get());
       return PrintTargetSkPDF::CreateOrNull(Move(skStream), size);
     }
 
     if (mDevMode) {
       // When printing to a printer via Skia PDF we open a temporary file that
@@ -306,17 +269,17 @@ already_AddRefed<PrintTarget> nsDeviceCo
       auto skStream = MakeUnique<SkFILEWStream>(filePath.get());
       return PrintTargetSkPDF::CreateOrNull(Move(skStream), size);
     }
   }
 #endif
 
   if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
     nsString filename;
-    mPrintSettings->GetToFileName(getter_Copies(filename));
+    mPrintSettings->GetToFileName(filename);
 
     double width, height;
     mPrintSettings->GetEffectivePageSize(&width, &height);
     if (width <= 0 || height <= 0) {
       return nullptr;
     }
 
     // convert twips to points
@@ -334,18 +297,18 @@ already_AddRefed<PrintTarget> nsDeviceCo
     if (NS_FAILED(rv)) {
       return nullptr;
     }
 
     return PrintTargetPDF::CreateOrNull(stream, IntSize::Truncate(width, height));
   }
 
   if (mDevMode) {
-    NS_WARNING_ASSERTION(mDriverName, "No driver!");
-    HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
+    NS_WARNING_ASSERTION(!mDriverName.IsEmpty(), "No driver!");
+    HDC dc = ::CreateDCW(mDriverName.get(), mDeviceName.get(), nullptr, mDevMode);
     if (!dc) {
       gfxCriticalError(gfxCriticalError::DefaultOptions(false))
         << "Failed to create device context in GetSurfaceForPrinter";
       return nullptr;
     }
 
     // The PrintTargetWindows takes over ownership of this DC
     return PrintTargetWindows::CreateOrNull(dc);
@@ -452,18 +415,18 @@ nsDeviceContextSpecWin::BeginDocument(co
                                       int32_t          aEndPage)
 {
 #ifdef MOZ_ENABLE_SKIA_PDF
   if (mPrintViaSkPDF && (mOutputFormat != nsIPrintSettings::kOutputFormatPDF)) {
     // Here we create mDC which we'll draw each page from our temporary PDF file
     // to once we reach EndDocument. The only reason we create it here rather
     // than in EndDocument is so that we don't need to store aTitle and
     // aPrintToFileName as member data.
-    NS_WARNING_ASSERTION(mDriverName, "No driver!");
-    mDC = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
+    NS_WARNING_ASSERTION(!mDriverName.IsEmpty(), "No driver!");
+    mDC = ::CreateDCW(mDriverName.get(), mDeviceName.get(), nullptr, mDevMode);
     if (mDC == NULL) {
       gfxCriticalError(gfxCriticalError::DefaultOptions(false))
         << "Failed to create device context in GetSurfaceForPrinter";
       return NS_ERROR_FAILURE;
     }
 
     const uint32_t DOC_TITLE_LENGTH = MAX_PATH - 1;
     nsString title(aTitle);
@@ -522,25 +485,25 @@ nsDeviceContextSpecWin::EndDocument()
       NS_WARNING("Failed to dispatch to the current thread!");
     }
   }
 #endif
   return rv;
 }
 
 //----------------------------------------------------------------------------------
-void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
+void nsDeviceContextSpecWin::SetDeviceName(const nsAString& aDeviceName)
 {
-  CleanAndCopyString(mDeviceName, aDeviceName);
+  mDeviceName = aDeviceName;
 }
 
 //----------------------------------------------------------------------------------
-void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
+void nsDeviceContextSpecWin::SetDriverName(const nsAString& aDriverName)
 {
-  CleanAndCopyString(mDriverName, aDriverName);
+  mDriverName = aDriverName;
 }
 
 //----------------------------------------------------------------------------------
 void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
 {
   if (mDevMode) {
     ::HeapFree(::GetProcessHeap(), 0, mDevMode);
   }
@@ -555,46 +518,48 @@ nsDeviceContextSpecWin::GetDevMode(LPDEV
   aDevMode = mDevMode;
 }
 
 #define DISPLAY_LAST_ERROR
 
 //----------------------------------------------------------------------------------
 // Setup the object's data member with the selected printer's data
 nsresult
-nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
+nsDeviceContextSpecWin::GetDataFromPrinter(const nsAString& aName,
+                                           nsIPrintSettings* aPS)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
   if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
     rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
     if (NS_FAILED(rv)) {
       PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
       DISPLAY_LAST_ERROR
     }
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsHPRINTER hPrinter = nullptr;
-  wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
+  const nsString& flat = PromiseFlatString(aName);
+  wchar_t* name = (wchar_t*)flat.get(); // Windows APIs use non-const name argument
 
   BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
   if (status) {
     nsAutoPrinter autoPrinter(hPrinter);
 
     LPDEVMODEW   pDevMode;
 
     // Allocate a buffer of the correct size.
     LONG needed = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr,
                                         nullptr, 0);
     if (needed < 0) {
       PR_PL(("**** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't get "
              "size of DEVMODE using DocumentPropertiesW(pDeviceName = \"%s\"). "
              "GetLastEror() = %08x\n",
-             aName ? NS_ConvertUTF16toUTF8(aName).get() : "", GetLastError()));
+             NS_ConvertUTF16toUTF8(aName).get(), GetLastError()));
       return NS_ERROR_FAILURE;
     }
 
     pDevMode = (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
                                        needed);
     if (!pDevMode) return NS_ERROR_FAILURE;
 
     // Get the default DevMode for the printer and modify it for our needs.
@@ -609,17 +574,17 @@ nsDeviceContextSpecWin::GetDataFromPrint
       ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
                                   pDevMode, pDevMode,
                                   DM_IN_BUFFER | DM_OUT_BUFFER);
 
       // We need to copy the final DEVMODE settings back to our print settings,
       // because they may have been set from invalid prefs.
       if (ret == IDOK) {
         // We need to get information from the device as well.
-        nsAutoHDC printerDC(::CreateICW(kDriverName, aName, nullptr, pDevMode));
+        nsAutoHDC printerDC(::CreateICW(kDriverName, name, nullptr, pDevMode));
         if (NS_WARN_IF(!printerDC)) {
           ::HeapFree(::GetProcessHeap(), 0, pDevMode);
           return NS_ERROR_FAILURE;
         }
 
         psWin->CopyFromNative(printerDC, pDevMode);
       }
     }
@@ -630,17 +595,17 @@ nsDeviceContextSpecWin::GetDataFromPrint
       DISPLAY_LAST_ERROR
       return NS_ERROR_FAILURE;
     }
 
     SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
 
     SetDeviceName(aName);
 
-    SetDriverName(kDriverName);
+    SetDriverName(nsDependentString(kDriverName));
 
     rv = NS_OK;
   } else {
     rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
     PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
     DISPLAY_LAST_ERROR
   }
   return rv;
@@ -659,32 +624,29 @@ nsPrinterEnumeratorWin::~nsPrinterEnumer
   // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
 }
 
 NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
 
 //----------------------------------------------------------------------------------
 // Return the Default Printer name
 NS_IMETHODIMP
-nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
+nsPrinterEnumeratorWin::GetDefaultPrinterName(nsAString& aDefaultPrinterName)
 {
-  NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
-
-  *aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
-
+  GlobalPrinters::GetInstance()->GetDefaultPrinterName(aDefaultPrinterName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
+nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const nsAString& aPrinterName,
+                                                     nsIPrintSettings *aPrintSettings)
 {
-  NS_ENSURE_ARG_POINTER(aPrinterName);
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
-  if (!*aPrinterName) {
+  if (aPrinterName.IsEmpty()) {
     return NS_OK;
   }
 
   // When printing to PDF on Windows there is no associated printer driver.
   int16_t outputFormat;
   aPrintSettings->GetOutputFormat(&outputFormat);
   if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
     return NS_OK;
@@ -719,17 +681,18 @@ nsPrinterEnumeratorWin::InitPrintSetting
   devSpecWin->GetDevMode(devmode);
   if (NS_WARN_IF(!devmode)) {
     return NS_ERROR_FAILURE;
   }
 
   aPrintSettings->SetPrinterName(aPrinterName);
 
   // We need to get information from the device as well.
-  char16ptr_t printerName = aPrinterName;
+  const nsString& flat = PromiseFlatString(aPrinterName);
+  char16ptr_t printerName = flat.get();
   HDC dc = ::CreateICW(kDriverName, printerName, nullptr, devmode);
   if (NS_WARN_IF(!dc)) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPrintSettings);
   MOZ_ASSERT(psWin);
   psWin->CopyFromNative(dc, devmode);
@@ -828,17 +791,17 @@ GlobalPrinters::EnumerateNativePrinters(
   }
   PR_PL(("-----------------------\n"));
   return rv;
 }
 
 //------------------------------------------------------------------
 // Uses the GetProfileString to get the default printer from the registry
 void
-GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
+GlobalPrinters::GetDefaultPrinterName(nsAString& aDefaultPrinterName)
 {
   aDefaultPrinterName.Truncate();
   WCHAR szDefaultPrinterName[1024];
   DWORD status = GetProfileStringW(L"windows", L"device", 0,
                                    szDefaultPrinterName,
                                    ArrayLength(szDefaultPrinterName));
   if (status > 0) {
     WCHAR comma = ',';
@@ -848,17 +811,18 @@ GlobalPrinters::GetDefaultPrinterName(ns
     if (*sPtr == comma) {
       *sPtr = 0;
     }
     aDefaultPrinterName = szDefaultPrinterName;
   } else {
     aDefaultPrinterName = EmptyString();
   }
 
-  PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
+  PR_PL(("DEFAULT PRINTER [%s]\n",
+         PromiseFlatString(aDefaultPrinterName).get()));
 }
 
 //----------------------------------------------------------------------------------
 // This goes and gets the list of available printers and puts
 // the default printer at the beginning of the list
 nsresult
 GlobalPrinters::EnumeratePrinterList()
 {
--- a/widget/windows/nsDeviceContextSpecWin.h
+++ b/widget/windows/nsDeviceContextSpecWin.h
@@ -46,38 +46,39 @@ public:
   NS_IMETHOD EndPage() override { return NS_OK; }
 
   NS_IMETHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;
 
   float GetDPI() final;
 
   float GetPrintingScale() final;
 
-  void GetDriverName(wchar_t *&aDriverName) const   { aDriverName = mDriverName;     }
-  void GetDeviceName(wchar_t *&aDeviceName) const   { aDeviceName = mDeviceName;     }
+  void GetDriverName(nsAString& aDriverName) const { aDriverName = mDriverName; }
+  void GetDeviceName(nsAString& aDeviceName) const { aDeviceName = mDeviceName; }
 
   // The GetDevMode will return a pointer to a DevMode
   // whether it is from the Global memory handle or just the DevMode
   // To get the DevMode from the Global memory Handle it must lock it 
   // So this call must be paired with a call to UnlockGlobalHandle
   void GetDevMode(LPDEVMODEW &aDevMode);
 
   // helper functions
-  nsresult GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS = nullptr);
+  nsresult GetDataFromPrinter(const nsAString& aName,
+                              nsIPrintSettings* aPS = nullptr);
 
 protected:
 
-  void SetDeviceName(char16ptr_t aDeviceName);
-  void SetDriverName(char16ptr_t aDriverName);
+  void SetDeviceName(const nsAString& aDeviceName);
+  void SetDriverName(const nsAString& aDriverName);
   void SetDevMode(LPDEVMODEW aDevMode);
 
   virtual ~nsDeviceContextSpecWin();
 
-  wchar_t*      mDriverName;
-  wchar_t*      mDeviceName;
+  nsString mDriverName;
+  nsString mDeviceName;
   LPDEVMODEW mDevMode;
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   int16_t mOutputFormat = nsIPrintSettings::kOutputFormatNative;
 
 #ifdef MOZ_ENABLE_SKIA_PDF
   void  FinishPrintViaPDF();
   void  CleanupPrintViaPDF();
--- a/widget/windows/nsPrintOptionsWin.cpp
+++ b/widget/windows/nsPrintOptionsWin.cpp
@@ -50,28 +50,25 @@ nsPrintOptionsWin::SerializeToPrintData(
     aWBP->GetIsRangeSelection(&data->isRangeSelection());
   }
 
   nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aSettings);
   if (!psWin) {
     return NS_ERROR_FAILURE;
   }
 
-  char16_t* deviceName;
-  char16_t* driverName;
+  nsAutoString deviceName;
+  nsAutoString driverName;
 
-  psWin->GetDeviceName(&deviceName);
-  psWin->GetDriverName(&driverName);
+  psWin->GetDeviceName(deviceName);
+  psWin->GetDriverName(driverName);
 
   data->deviceName().Assign(deviceName);
   data->driverName().Assign(driverName);
 
-  free(deviceName);
-  free(driverName);
-
   // When creating the print dialog on Windows, we only need to send certain
   // print settings information from the parent to the child not vice versa.
   if (XRE_IsParentProcess()) {
     psWin->GetPrintableWidthInInches(&data->printableWidthInInches());
     psWin->GetPrintableHeightInInches(&data->printableHeightInInches());
 
     // A DEVMODE can actually be of arbitrary size. If it turns out that it'll
     // make our IPC message larger than the limit, then we'll error out.
@@ -112,18 +109,18 @@ nsPrintOptionsWin::DeserializeToPrintSet
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(settings);
   if (!settings) {
     return NS_ERROR_FAILURE;
   }
 
   if (XRE_IsContentProcess()) {
-    psWin->SetDeviceName(data.deviceName().get());
-    psWin->SetDriverName(data.driverName().get());
+    psWin->SetDeviceName(data.deviceName());
+    psWin->SetDriverName(data.driverName());
 
     psWin->SetPrintableWidthInInches(data.printableWidthInInches());
     psWin->SetPrintableHeightInInches(data.printableHeightInInches());
 
     if (data.devModeData().IsEmpty()) {
       psWin->SetDevMode(nullptr);
     } else {
       // Check minimum length of DEVMODE data.
--- a/widget/windows/nsPrintSettingsWin.cpp
+++ b/widget/windows/nsPrintSettingsWin.cpp
@@ -149,62 +149,50 @@ nsPrintSettingsWin::nsPrintSettingsWin()
 {
 
 }
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintSettingsWin.h
  *	@update 
  */
-nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS) :
-  mDeviceName(nullptr),
-  mDriverName(nullptr),
-  mDevMode(nullptr)
+nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS)
+  : mDevMode(nullptr)
 {
   *this = aPS;
 }
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintSettingsWin.h
  *	@update 
  */
 nsPrintSettingsWin::~nsPrintSettingsWin()
 {
-  if (mDeviceName) free(mDeviceName);
-  if (mDriverName) free(mDriverName);
   if (mDevMode) ::HeapFree(::GetProcessHeap(), 0, mDevMode);
 }
 
-NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const char16_t * aDeviceName)
+NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const nsAString& aDeviceName)
 {
-  if (mDeviceName) {
-    free(mDeviceName);
-  }
-  mDeviceName = aDeviceName?wcsdup(char16ptr_t(aDeviceName)):nullptr;
+  mDeviceName = aDeviceName;
   return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettingsWin::GetDeviceName(char16_t **aDeviceName)
+NS_IMETHODIMP nsPrintSettingsWin::GetDeviceName(nsAString& aDeviceName)
 {
-  NS_ENSURE_ARG_POINTER(aDeviceName);
-  *aDeviceName = mDeviceName?reinterpret_cast<char16_t*>(wcsdup(mDeviceName)):nullptr;
+  aDeviceName = mDeviceName;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const char16_t * aDriverName)
+NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const nsAString& aDriverName)
 {
-  if (mDriverName) {
-    free(mDriverName);
-  }
-  mDriverName = aDriverName?wcsdup(char16ptr_t(aDriverName)):nullptr;
+  mDriverName = aDriverName;
   return NS_OK;
 }
-NS_IMETHODIMP nsPrintSettingsWin::GetDriverName(char16_t **aDriverName)
+NS_IMETHODIMP nsPrintSettingsWin::GetDriverName(nsAString& aDriverName)
 {
-  NS_ENSURE_ARG_POINTER(aDriverName);
-  *aDriverName = mDriverName?reinterpret_cast<char16_t*>(wcsdup(mDriverName)):nullptr;
+  aDriverName = mDriverName;
   return NS_OK;
 }
 
 void nsPrintSettingsWin::CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode)
 {
   aOutDevMode = nullptr;
   size_t size = aInDevMode->dmSize + aInDevMode->dmDriverExtra;
   aOutDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, size);
@@ -420,31 +408,23 @@ nsPrintSettingsWin::_Clone(nsIPrintSetti
 nsPrintSettingsWin& nsPrintSettingsWin::operator=(const nsPrintSettingsWin& rhs)
 {
   if (this == &rhs) {
     return *this;
   }
 
   ((nsPrintSettings&) *this) = rhs;
 
-  if (mDeviceName) {
-    free(mDeviceName);
-  }
-
-  if (mDriverName) {
-    free(mDriverName);
-  }
-
   // Use free because we used the native malloc to create the memory
   if (mDevMode) {
     ::HeapFree(::GetProcessHeap(), 0, mDevMode);
   }
 
-  mDeviceName = rhs.mDeviceName?wcsdup(rhs.mDeviceName):nullptr;
-  mDriverName = rhs.mDriverName?wcsdup(rhs.mDriverName):nullptr;
+  mDeviceName = rhs.mDeviceName;
+  mDriverName = rhs.mDriverName;
 
   if (rhs.mDevMode) {
     CopyDevMode(rhs.mDevMode, mDevMode);
   } else {
     mDevMode = nullptr;
   }
 
   return *this;
--- a/widget/windows/nsPrintSettingsWin.h
+++ b/widget/windows/nsPrintSettingsWin.h
@@ -42,18 +42,18 @@ public:
    */
   nsPrintSettingsWin& operator=(const nsPrintSettingsWin& rhs);
 
   NS_IMETHOD GetEffectivePageSize(double *aWidth, double *aHeight) override;
 
 protected:
   void CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode);
 
-  wchar_t*      mDeviceName;
-  wchar_t*      mDriverName;
+  nsString      mDeviceName;
+  nsString      mDriverName;
   LPDEVMODEW mDevMode;
   double mPrintableWidthInInches = 0l;
   double mPrintableHeightInInches = 0l;
 };
 
 
 
 #endif /* nsPrintSettingsWin_h__ */
--- a/xpcom/ds/nsAtom.h
+++ b/xpcom/ds/nsAtom.h
@@ -62,17 +62,20 @@ public:
 
   nsStringBuffer* GetStringBuffer() const
   {
     // See the comment on |mString|'s declaration.
     return nsStringBuffer::FromData(mString);
   }
 
   // A hashcode that is better distributed than the actual atom pointer, for
-  // use in situations that need a well-distributed hashcode.
+  // use in situations that need a well-distributed hashcode. It's called hash()
+  // rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because
+  // BloomFilter requires elements to implement a function called hash().
+  //
   uint32_t hash() const
   {
     MOZ_ASSERT(!IsHTML5Atom());
     return mHash;
   }
 
   // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
   // of this type is special.
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -133,68 +133,67 @@ private:
 };
 
 UniquePtr<nsTArray<FakeBufferRefcountHelper>> gFakeBuffers;
 #endif
 
 // This constructor is for dynamic atoms and HTML5 atoms.
 nsAtom::nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
   : mRefCnt(1)
+  , mLength(aString.Length())
+  , mKind(static_cast<uint32_t>(aKind))
+  , mHash(aHash)
 {
-  mLength = aString.Length();
-  SetKind(aKind);
-  MOZ_ASSERT(IsDynamicAtom() || IsHTML5Atom());
+  MOZ_ASSERT(aKind == AtomKind::DynamicAtom || aKind == AtomKind::HTML5Atom);
   RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
   if (buf) {
     mString = static_cast<char16_t*>(buf->Data());
   } else {
     const size_t size = (mLength + 1) * sizeof(char16_t);
     buf = nsStringBuffer::Alloc(size);
     if (MOZ_UNLIKELY(!buf)) {
       // We OOM because atom allocations should be small and it's hard to
       // handle them more gracefully in a constructor.
       NS_ABORT_OOM(size);
     }
     mString = static_cast<char16_t*>(buf->Data());
     CopyUnicodeTo(aString, 0, mString, mLength);
     mString[mLength] = char16_t(0);
   }
 
-  mHash = aHash;
   MOZ_ASSERT_IF(IsDynamicAtom(), mHash == HashString(mString, mLength));
 
-  NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
-  NS_ASSERTION(buf && buf->StorageSize() >= (mLength + 1) * sizeof(char16_t),
-               "enough storage");
-  NS_ASSERTION(Equals(aString), "correct data");
+  MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
+  MOZ_ASSERT(buf && buf->StorageSize() >= (mLength + 1) * sizeof(char16_t),
+             "enough storage");
+  MOZ_ASSERT(Equals(aString), "correct data");
 
   // Take ownership of buffer
   mozilla::Unused << buf.forget();
 }
 
 // This constructor is for static atoms.
 nsAtom::nsAtom(nsStringBuffer* aStringBuffer, uint32_t aLength, uint32_t aHash)
+  : mLength(aLength)
+  , mKind(static_cast<uint32_t>(AtomKind::StaticAtom))
+  , mHash(aHash)
+  , mString(static_cast<char16_t*>(aStringBuffer->Data()))
 {
-  mLength = aLength;
-  SetKind(AtomKind::StaticAtom);
-  mString = static_cast<char16_t*>(aStringBuffer->Data());
-
 #if defined(NS_BUILD_REFCNT_LOGGING)
   MOZ_ASSERT(NS_IsMainThread());
   if (!gFakeBuffers) {
     gFakeBuffers = MakeUnique<nsTArray<FakeBufferRefcountHelper>>();
   }
   gFakeBuffers->AppendElement(aStringBuffer);
 #endif
 
   // Technically we could currently avoid doing this addref by instead making
   // the static atom buffers have an initial refcount of 2.
   aStringBuffer->AddRef();
 
-  mHash = aHash;
   MOZ_ASSERT(mHash == HashString(mString, mLength));
 
   MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
   MOZ_ASSERT(aStringBuffer &&
              aStringBuffer->StorageSize() == (mLength + 1) * sizeof(char16_t),
              "correct storage");
 }