merge autoland to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 16 Jan 2017 16:34:19 +0100
changeset 357567 aeda115ca5c37723ec703a2574204952001e40db
parent 357533 7884f9ed756bad6e9d73b8a5adb82d0773daae08 (current diff)
parent 357566 8f52299c4c6366e7d1edfdd4f93aa3f7cfc4eb76 (diff)
child 357588 d4d3a7b6d57e06891f158ccb4bebf507a8d55d32
push id10621
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 16:02:43 +0000
treeherdermozilla-aurora@dca7b42e6c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
merge autoland to mozilla-central a=merge
ipc/keystore/KeyStore.cpp
ipc/keystore/KeyStore.h
ipc/keystore/KeyStoreConnector.cpp
ipc/keystore/KeyStoreConnector.h
ipc/keystore/moz.build
toolkit/components/printingui/mac/nsPrintingPromptServiceX.mm
--- a/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId.js
@@ -91,16 +91,17 @@ add_task(function* () {
             browser.test.assertTrue(tab != undefined, "Tab found!");
             testTab(data, tab);
           }
 
           let stores = await browser.cookies.getAllCookieStores();
 
           let store = stores.find(store => store.id === tab.cookieStoreId);
           browser.test.assertTrue(!!store, "We have a store for this tab.");
+          browser.test.assertTrue(store.tabIds.includes(tab.id), "tabIds includes this tab.");
 
           await browser.tabs.remove(tab.id);
 
           browser.test.sendMessage("test-done");
         } catch (e) {
           browser.test.fail("An exception has been thrown");
         }
       }
--- a/browser/extensions/mortar/host/common/ppapi-runtime.jsm
+++ b/browser/extensions/mortar/host/common/ppapi-runtime.jsm
@@ -1663,16 +1663,19 @@ class PPAPIInstance {
     return this.id;
   }
 
   viewportActionHandler(message) {
     switch(message.type) {
       case 'setFullscreen':
         this.mm.sendAsyncMessage("ppapi.js:setFullscreen", message.fullscreen);
         break;
+      case 'save':
+        this.mm.sendAsyncMessage("ppapipdf.js:save");
+        break;
       case 'viewport':
       case 'rotateClockwise':
       case 'rotateCounterclockwise':
       case 'selectAll':
       case 'getSelectedText':
       case 'getNamedDestination':
       case 'getPasswordComplete':
         let data = PP_Var.fromJSValue(new Dictionary(message), this);
--- a/browser/extensions/mortar/host/pdf/chrome/js/toolbar.js
+++ b/browser/extensions/mortar/host/pdf/chrome/js/toolbar.js
@@ -189,16 +189,20 @@ class Toolbar {
         this._viewport.page++;
         break;
       case 'zoomIn':
         this._zoomIn();
         break;
       case 'zoomOut':
         this._zoomOut();
         break;
+      case 'download':
+      case 'secondaryDownload':
+        this._viewport.save();
+        break;
       case 'pageRotateCw':
         this._viewport.rotateClockwise();
         break;
       case 'pageRotateCcw':
         this._viewport.rotateCounterClockwise();
         break;
       case 'secondaryToolbarToggle':
         this._secondaryToolbar.toggle();
--- a/browser/extensions/mortar/host/pdf/chrome/js/viewport.js
+++ b/browser/extensions/mortar/host/pdf/chrome/js/viewport.js
@@ -414,16 +414,22 @@ class Viewport {
   }
 
   rotateCounterClockwise() {
     this._doAction({
       type: 'rotateCounterclockwise'
     });
   }
 
+  save() {
+    this._doAction({
+      type: 'save'
+    });
+  }
+
   // A handler for delivering messages to runtime.
   registerActionHandler(handler) {
     if (typeof handler === 'function') {
       this._actionHandler = handler;
     }
   }
 
   /***************************/
--- a/browser/extensions/mortar/host/pdf/ppapi-content-sandbox.js
+++ b/browser/extensions/mortar/host/pdf/ppapi-content-sandbox.js
@@ -4,17 +4,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * This code runs in the sandbox in the content process where the page that
  * loaded the plugin lives. It communicates with the process where the PPAPI
  * implementation lives.
  */
-const { utils: Cu } = Components;
+const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                          "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
+                             "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 let mm = pluginElement.frameLoader.messageManager;
 let containerWindow = pluginElement.ownerDocument.defaultView;
 // Prevent the drag event's default action on the element, to avoid dragging of
 // that element while the user selects text.
 pluginElement.addEventListener("dragstart",
                                function(event) { event.preventDefault(); });
 // For synthetic documents only, prevent the select event's default action on
@@ -87,9 +94,82 @@ mm.addMessageListener("ppapi.js:frameLoa
 mm.addMessageListener("ppapi.js:setFullscreen", ({ data }) => {
   if (data) {
     pluginElement.requestFullscreen();
   } else {
     containerWindow.document.exitFullscreen();
   }
 });
 
+mm.addMessageListener("ppapipdf.js:save", () => {
+  let url = containerWindow.document.location;
+  let filename = "document.pdf";
+  let regex = /[^\/#\?]+\.pdf$/i;
+
+  let result = regex.exec(url.hash) ||
+               regex.exec(url.search) ||
+               regex.exec(url.pathname);
+  if (result) {
+    filename = result[0];
+  }
+
+  let originalUri = NetUtil.newURI(url.href);
+  let extHelperAppSvc =
+        Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
+           getService(Ci.nsIExternalHelperAppService);
+
+  let docIsPrivate =
+    PrivateBrowsingUtils.isContentWindowPrivate(containerWindow);
+  let netChannel = NetUtil.newChannel({
+    uri: originalUri,
+    loadUsingSystemPrincipal: true,
+  });
+
+  if ("nsIPrivateBrowsingChannel" in Ci &&
+      netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
+    netChannel.setPrivate(docIsPrivate);
+  }
+  NetUtil.asyncFetch(netChannel, function(aInputStream, aResult) {
+    if (!Components.isSuccessCode(aResult)) {
+      return;
+    }
+    // Create a nsIInputStreamChannel so we can set the url on the channel
+    // so the filename will be correct.
+    let channel = Cc["@mozilla.org/network/input-stream-channel;1"].
+                     createInstance(Ci.nsIInputStreamChannel);
+    channel.QueryInterface(Ci.nsIChannel);
+    channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
+    channel.contentDispositionFilename = filename;
+    channel.setURI(originalUri);
+    channel.loadInfo = netChannel.loadInfo;
+    channel.contentStream = aInputStream;
+    if ("nsIPrivateBrowsingChannel" in Ci &&
+        channel instanceof Ci.nsIPrivateBrowsingChannel) {
+      channel.setPrivate(docIsPrivate);
+    }
+
+    let listener = {
+      extListener: null,
+      onStartRequest(aRequest, aContext) {
+        var loadContext = containerWindow
+                            .QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIWebNavigation)
+                            .QueryInterface(Ci.nsILoadContext);
+        this.extListener = extHelperAppSvc.doContent(
+          "application/pdf", aRequest, loadContext, false);
+        this.extListener.onStartRequest(aRequest, aContext);
+      },
+      onStopRequest(aRequest, aContext, aStatusCode) {
+        if (this.extListener) {
+          this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
+        }
+      },
+      onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount) {
+        this.extListener
+          .onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
+      }
+    };
+
+    channel.asyncOpen2(listener);
+  });
+});
+
 mm.loadFrameScript("resource://ppapi.js/ppapi-instance.js", true);
--- a/devtools/client/storage/test/browser.ini
+++ b/devtools/client/storage/test/browser.ini
@@ -4,27 +4,29 @@ subsuite = devtools
 support-files =
   storage-cache-error.html
   storage-complex-values.html
   storage-cookies.html
   storage-empty-objectstores.html
   storage-idb-delete-blocked.html
   storage-indexeddb-duplicate-names.html
   storage-listings.html
+  storage-listings-with-fragment.html
   storage-localstorage.html
   storage-overflow.html
   storage-search.html
   storage-secured-iframe.html
   storage-sessionstorage.html
   storage-unsecured-iframe.html
   storage-updates.html
   head.js
   !/devtools/client/framework/test/shared-head.js
 
 [browser_storage_basic.js]
+[browser_storage_basic_with_fragment.js]
 [browser_storage_cache_delete.js]
 [browser_storage_cache_error.js]
 [browser_storage_cookies_delete_all.js]
 [browser_storage_cookies_domain.js]
 [browser_storage_cookies_edit.js]
 [browser_storage_cookies_edit_keyboard.js]
 [browser_storage_cookies_tab_navigation.js]
 [browser_storage_delete.js]
--- a/devtools/client/storage/test/browser_storage_basic.js
+++ b/devtools/client/storage/test/browser_storage_basic.js
@@ -19,26 +19,26 @@
 // These entries are formed by the cookies, local storage, session storage and
 // indexedDB entries created in storage-listings.html,
 // storage-secured-iframe.html and storage-unsecured-iframe.html
 
 "use strict";
 
 const testCases = [
   [
-    ["cookies", "test1.example.org"],
+    ["cookies", "http://test1.example.org"],
     [
       getCookieId("c1", "test1.example.org", "/browser"),
       getCookieId("cs2", ".example.org", "/"),
       getCookieId("c3", "test1.example.org", "/"),
       getCookieId("uc1", ".example.org", "/")
     ]
   ],
   [
-    ["cookies", "sectest1.example.org"],
+    ["cookies", "https://sectest1.example.org"],
     [
       getCookieId("uc1", ".example.org", "/"),
       getCookieId("cs2", ".example.org", "/"),
       getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
     ]
   ],
   [["localStorage", "http://test1.example.org"],
    ["ls1", "ls2"]],
@@ -81,18 +81,18 @@ const testCases = [
     MAIN_DOMAIN + "browser_storage_basic.js"]],
 ];
 
 /**
  * Test that the desired number of tree items are present
  */
 function testTree() {
   let doc = gPanelWindow.document;
-  for (let item of testCases) {
-    ok(doc.querySelector("[data-id='" + JSON.stringify(item[0]) + "']"),
+  for (let [item] of testCases) {
+    ok(doc.querySelector("[data-id='" + JSON.stringify(item) + "']"),
        "Tree item " + item[0] + " should be present in the storage tree");
   }
 }
 
 /**
  * Test that correct table entries are shown for each of the tree item
  */
 function* testTables() {
@@ -102,26 +102,26 @@ function* testTables() {
 
   // First tree item is already selected so no clicking and waiting for update
   for (let id of testCases[0][1]) {
     ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
        "Table item " + id + " should be present");
   }
 
   // Click rest of the tree items and wait for the table to be updated
-  for (let item of testCases.slice(1)) {
-    yield selectTreeItem(item[0]);
+  for (let [treeItem, items] of testCases.slice(1)) {
+    yield selectTreeItem(treeItem);
 
     // Check whether correct number of items are present in the table
     is(doc.querySelectorAll(
          ".table-widget-wrapper:first-of-type .table-widget-cell"
-       ).length, item[1].length, "Number of items in table is correct");
+       ).length, items.length, "Number of items in table is correct");
 
     // Check if all the desired items are present in the table
-    for (let id of item[1]) {
+    for (let id of items) {
       ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
          "Table item " + id + " should be present");
     }
   }
 }
 
 add_task(function* () {
   yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
new file mode 100644
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_basic_with_fragment.js
@@ -0,0 +1,139 @@
+/* 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/. */
+
+/* import-globals-from head.js */
+
+// A second basic test to assert that the storage tree and table corresponding
+// to each item in the storage tree is correctly displayed.
+
+// This test differs from browser_storage_basic.js because the URLs we load
+// include fragments e.g. http://example.com/test.js#abcdefg
+//                                                  ^^^^^^^^
+//                                                  fragment
+
+// Entries that should be present in the tree for this test
+// Format for each entry in the array :
+// [
+//   ["path", "to", "tree", "item"], - The path to the tree item to click formed
+//                                     by id of each item
+//   ["key_value1", "key_value2", ...] - The value of the first (unique) column
+//                                       for each row in the table corresponding
+//                                       to the tree item selected.
+// ]
+// These entries are formed by the cookies, local storage, session storage and
+// indexedDB entries created in storage-listings.html,
+// storage-secured-iframe.html and storage-unsecured-iframe.html
+
+"use strict";
+
+const testCases = [
+  [
+    ["cookies", "http://test1.example.org"],
+    [
+      getCookieId("c1", "test1.example.org", "/browser"),
+      getCookieId("cs2", ".example.org", "/"),
+      getCookieId("c3", "test1.example.org", "/"),
+      getCookieId("uc1", ".example.org", "/")
+    ]
+  ],
+  [
+    ["cookies", "https://sectest1.example.org"],
+    [
+      getCookieId("uc1", ".example.org", "/"),
+      getCookieId("cs2", ".example.org", "/"),
+      getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
+    ]
+  ],
+  [["localStorage", "http://test1.example.org"],
+   ["ls1", "ls2"]],
+  [["localStorage", "http://sectest1.example.org"],
+   ["iframe-u-ls1"]],
+  [["localStorage", "https://sectest1.example.org"],
+   ["iframe-s-ls1"]],
+  [["sessionStorage", "http://test1.example.org"],
+   ["ss1"]],
+  [["sessionStorage", "http://sectest1.example.org"],
+   ["iframe-u-ss1", "iframe-u-ss2"]],
+  [["sessionStorage", "https://sectest1.example.org"],
+   ["iframe-s-ss1"]],
+  [["indexedDB", "http://test1.example.org"],
+   ["idb1 (default)", "idb2 (default)"]],
+  [["indexedDB", "http://test1.example.org", "idb1 (default)"],
+   ["obj1", "obj2"]],
+  [["indexedDB", "http://test1.example.org", "idb2 (default)"],
+   ["obj3"]],
+  [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
+   [1, 2, 3]],
+  [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
+   [1]],
+  [["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
+   []],
+  [["indexedDB", "http://sectest1.example.org"],
+   []],
+  [["indexedDB", "https://sectest1.example.org"],
+   ["idb-s1 (default)", "idb-s2 (default)"]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
+   ["obj-s1"]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
+   ["obj-s2"]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
+   [6, 7]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
+   [16]],
+  [["Cache", "http://test1.example.org", "plop"],
+   [MAIN_DOMAIN + "404_cached_file.js",
+    MAIN_DOMAIN + "browser_storage_basic.js"]],
+];
+
+/**
+ * Test that the desired number of tree items are present
+ */
+function testTree() {
+  let doc = gPanelWindow.document;
+  for (let [item] of testCases) {
+    ok(doc.querySelector("[data-id='" + JSON.stringify(item) + "']"),
+       "Tree item " + item[0] + " should be present in the storage tree");
+  }
+}
+
+/**
+ * Test that correct table entries are shown for each of the tree item
+ */
+function* testTables() {
+  let doc = gPanelWindow.document;
+  // Expand all nodes so that the synthesized click event actually works
+  gUI.tree.expandAll();
+
+  // First tree item is already selected so no clicking and waiting for update
+  for (let id of testCases[0][1]) {
+    ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
+       "Table item " + id + " should be present");
+  }
+
+  // Click rest of the tree items and wait for the table to be updated
+  for (let [treeItem, items] of testCases.slice(1)) {
+    yield selectTreeItem(treeItem);
+
+    // Check whether correct number of items are present in the table
+    is(doc.querySelectorAll(
+         ".table-widget-wrapper:first-of-type .table-widget-cell"
+       ).length, items.length, "Number of items in table is correct");
+
+    // Check if all the desired items are present in the table
+    for (let id of items) {
+      ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
+         "Table item " + id + " should be present");
+    }
+  }
+}
+
+add_task(function* () {
+  yield openTabAndSetupStorage(
+    MAIN_DOMAIN + "storage-listings-with-fragment.html#abc");
+
+  testTree();
+  yield testTables();
+
+  yield finishTests();
+});
--- a/devtools/client/storage/test/browser_storage_cookies_delete_all.js
+++ b/devtools/client/storage/test/browser_storage_cookies_delete_all.js
@@ -39,66 +39,66 @@ function* performDelete(store, rowName, 
 }
 
 add_task(function* () {
   yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
 
   info("test state before delete");
   yield checkState([
     [
-      ["cookies", "test1.example.org"], [
+      ["cookies", "http://test1.example.org"], [
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("c3", "test1.example.org", "/"),
         getCookieId("cs2", ".example.org", "/"),
         getCookieId("uc1", ".example.org", "/")
       ]
     ],
     [
-      ["cookies", "sectest1.example.org"], [
+      ["cookies", "https://sectest1.example.org"], [
         getCookieId("cs2", ".example.org", "/"),
         getCookieId("sc1", "sectest1.example.org",
                     "/browser/devtools/client/storage/test/"),
         getCookieId("uc1", ".example.org", "/")
       ]
     ],
   ]);
 
   info("delete all from domain");
   // delete only cookies that match the host exactly
   let id = getCookieId("c1", "test1.example.org", "/browser");
-  yield performDelete(["cookies", "test1.example.org"], id, false);
+  yield performDelete(["cookies", "http://test1.example.org"], id, false);
 
   info("test state after delete all from domain");
   yield checkState([
     // Domain cookies (.example.org) must not be deleted.
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("cs2", ".example.org", "/"),
         getCookieId("uc1", ".example.org", "/")
       ]
     ],
     [
-      ["cookies", "sectest1.example.org"],
+      ["cookies", "https://sectest1.example.org"],
       [
         getCookieId("cs2", ".example.org", "/"),
         getCookieId("uc1", ".example.org", "/"),
         getCookieId("sc1", "sectest1.example.org",
                     "/browser/devtools/client/storage/test/"),
       ]
     ],
   ]);
 
   info("delete all");
   // delete all cookies for host, including domain cookies
   id = getCookieId("uc1", ".example.org", "/");
-  yield performDelete(["cookies", "sectest1.example.org"], id, true);
+  yield performDelete(["cookies", "http://sectest1.example.org"], id, true);
 
   info("test state after delete all");
   yield checkState([
     // Domain cookies (.example.org) are deleted too, so deleting in sectest1
     // also removes stuff from test1.
-    [["cookies", "test1.example.org"], []],
-    [["cookies", "sectest1.example.org"], []],
+    [["cookies", "http://test1.example.org"], []],
+    [["cookies", "https://sectest1.example.org"], []],
   ]);
 
   yield finishTests();
 });
--- a/devtools/client/storage/test/browser_storage_cookies_domain.js
+++ b/devtools/client/storage/test/browser_storage_cookies_domain.js
@@ -9,17 +9,17 @@
 // Test that cookies with domain equal to full host name are listed.
 // E.g., ".example.org" vs. example.org). Bug 1149497.
 
 add_task(function* () {
   yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("test1", ".test1.example.org", "/browser"),
         getCookieId("test2", "test1.example.org", "/browser"),
         getCookieId("test3", ".test1.example.org", "/browser"),
         getCookieId("test4", "test1.example.org", "/browser"),
         getCookieId("test5", ".test1.example.org", "/browser")
       ]
     ],
--- a/devtools/client/storage/test/browser_storage_delete.js
+++ b/devtools/client/storage/test/browser_storage_delete.js
@@ -9,17 +9,17 @@
 // Test deleting storage items
 
 const TEST_CASES = [
   [["localStorage", "http://test1.example.org"],
    "ls1", "name"],
   [["sessionStorage", "http://test1.example.org"],
    "ss1", "name"],
   [
-    ["cookies", "test1.example.org"],
+    ["cookies", "http://test1.example.org"],
     getCookieId("c1", "test1.example.org", "/browser"), "name"
   ],
   [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
    1, "name"],
   [["Cache", "http://test1.example.org", "plop"],
    MAIN_DOMAIN + "404_cached_file.js", "url"],
 ];
 
--- a/devtools/client/storage/test/browser_storage_delete_tree.js
+++ b/devtools/client/storage/test/browser_storage_delete_tree.js
@@ -13,34 +13,34 @@ add_task(function* () {
 
   let contextMenu = gPanelWindow.document.getElementById("storage-tree-popup");
   let menuDeleteAllItem = contextMenu.querySelector(
     "#storage-tree-popup-delete-all");
 
   info("test state before delete");
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("cs2", ".example.org", "/"),
         getCookieId("c3", "test1.example.org", "/"),
         getCookieId("uc1", ".example.org", "/")
       ]
     ],
     [["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
     [["sessionStorage", "http://test1.example.org"], ["ss1"]],
     [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], [1, 2, 3]],
     [["Cache", "http://test1.example.org", "plop"],
       [MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
   ]);
 
   info("do the delete");
   const deleteHosts = [
-    ["cookies", "test1.example.org"],
+    ["cookies", "http://test1.example.org"],
     ["localStorage", "http://test1.example.org"],
     ["sessionStorage", "http://test1.example.org"],
     ["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
     ["Cache", "http://test1.example.org", "plop"],
   ];
 
   for (let store of deleteHosts) {
     let storeName = store.join(" > ");
@@ -59,17 +59,17 @@ add_task(function* () {
       menuDeleteAllItem.click();
     });
 
     yield eventWait;
   }
 
   info("test state after delete");
   yield checkState([
-    [["cookies", "test1.example.org"], []],
+    [["cookies", "http://test1.example.org"], []],
     [["localStorage", "http://test1.example.org"], []],
     [["sessionStorage", "http://test1.example.org"], []],
     [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], []],
     [["Cache", "http://test1.example.org", "plop"], []],
   ]);
 
   yield finishTests();
 });
--- a/devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js
+++ b/devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js
@@ -38,34 +38,34 @@ add_task(function* () {
   // Check that sidebar shows correct initial value
   yield findVariableViewProperties(initialValue[0], false);
 
   yield findVariableViewProperties(initialValue[1], true);
   // Check if table shows correct initial value
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("c2", "test1.example.org", "/browser")
       ]
     ],
   ]);
   checkCell(c1id, "value", "1.2.3.4.5.6.7");
 
   gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
   yield gUI.once("sidebar-updated");
 
   yield findVariableViewProperties(finalValue[0], false);
   yield findVariableViewProperties(finalValue[1], true);
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("c2", "test1.example.org", "/browser")
       ]
     ],
   ]);
   checkCell(c1id, "value", '{"foo": 4,"bar":6}');
 
@@ -73,17 +73,17 @@ add_task(function* () {
   gWindow.addCookie("c3", "booyeah");
 
   // Wait once for update and another time for value fetching
   yield gUI.once("store-objects-updated");
   yield gUI.once("store-objects-updated");
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("c2", "test1.example.org", "/browser"),
         getCookieId("c3", "test1.example.org",
                     "/browser/devtools/client/storage/test/")
       ]
     ],
   ]);
@@ -95,17 +95,17 @@ add_task(function* () {
   gWindow.addCookie("c4", "booyeah");
 
   // Wait once for update and another time for value fetching
   yield gUI.once("store-objects-updated");
   yield gUI.once("store-objects-updated");
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("c2", "test1.example.org", "/browser"),
         getCookieId("c3", "test1.example.org",
                     "/browser/devtools/client/storage/test/"),
         getCookieId("c4", "test1.example.org",
                     "/browser/devtools/client/storage/test/")
       ]
@@ -117,17 +117,17 @@ add_task(function* () {
 
   // Removing cookies
   gWindow.removeCookie("c1", "/browser");
 
   yield gUI.once("sidebar-updated");
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c2", "test1.example.org", "/browser"),
         getCookieId("c3", "test1.example.org",
                     "/browser/devtools/client/storage/test/"),
         getCookieId("c4", "test1.example.org",
                     "/browser/devtools/client/storage/test/")
       ]
     ],
@@ -140,17 +140,17 @@ add_task(function* () {
 
   // Keep deleting till no rows
   gWindow.removeCookie("c3");
 
   yield gUI.once("store-objects-updated");
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c2", "test1.example.org", "/browser"),
         getCookieId("c4", "test1.example.org",
                     "/browser/devtools/client/storage/test/")
       ]
     ],
   ]);
 
@@ -158,31 +158,31 @@ add_task(function* () {
   yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
 
   gWindow.removeCookie("c2", "/browser");
 
   yield gUI.once("sidebar-updated");
 
   yield checkState([
     [
-      ["cookies", "test1.example.org"],
+      ["cookies", "http://test1.example.org"],
       [
         getCookieId("c4", "test1.example.org",
                     "/browser/devtools/client/storage/test/")
       ]
     ],
   ]);
 
   // Check if next element's value is visible in sidebar
   yield findVariableViewProperties([{name: "c4", value: "booyeah"}]);
 
   gWindow.removeCookie("c4");
 
   yield gUI.once("store-objects-updated");
 
   yield checkState([
-    [["cookies", "test1.example.org"], [ ]],
+    [["cookies", "http://test1.example.org"], [ ]],
   ]);
 
   ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
 
   yield finishTests();
 });
--- a/devtools/client/storage/test/browser_storage_sidebar.js
+++ b/devtools/client/storage/test/browser_storage_sidebar.js
@@ -11,17 +11,17 @@
 //   <do we wait for the async "sidebar-updated" event>,
 //   <is the sidebar open>
 // ]
 
 "use strict";
 
 const testCases = [
   {
-    location: ["cookies", "sectest1.example.org"],
+    location: ["cookies", "https://sectest1.example.org"],
     sidebarHidden: true
   },
   {
     location: getCookieId("cs2", ".example.org", "/"),
     sidebarHidden: false
   },
   {
     sendEscape: true
new file mode 100644
--- /dev/null
+++ b/devtools/client/storage/test/storage-listings-with-fragment.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This test differs from browser_storage_listings.html only because the URLs we load
+include fragments e.g. http://example.com/test.js#abcdefg
+                                                 ^^^^^^^^
+                                                 fragment
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Storage inspector test for listing hosts and storages with URL fragments</title>
+</head>
+<body>
+<iframe src="http://sectest1.example.org/browser/devtools/client/storage/test/storage-unsecured-iframe.html#def"></iframe>
+<iframe src="https://sectest1.example.org:443/browser/devtools/client/storage/test/storage-secured-iframe.html#ghi"></iframe>
+<script type="application/javascript;version=1.7">
+"use strict";
+let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
+let cookieExpiresTime1 = 2000000000000;
+let cookieExpiresTime2 = 2000000001000;
+// Setting up some cookies to eat.
+document.cookie = "c1=foobar; expires=" +
+  new Date(cookieExpiresTime1).toGMTString() + "; path=/browser";
+document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
+document.cookie = "c3=foobar-2; expires=" +
+  new Date(cookieExpiresTime2).toGMTString() + "; path=/";
+// ... and some local storage items ..
+localStorage.setItem("ls1", "foobar");
+localStorage.setItem("ls2", "foobar-2");
+// ... and finally some session storage items too
+sessionStorage.setItem("ss1", "foobar-3");
+dump("added cookies and storage from main page\n");
+
+let idbGenerator = async function() {
+  let request = indexedDB.open("idb1", 1);
+  request.onerror = function() {
+    throw new Error("error opening db connection");
+  };
+  let db = await new Promise(done => {
+    request.onupgradeneeded = event => {
+      let db = event.target.result;
+      let store1 = db.createObjectStore("obj1", { keyPath: "id" });
+      store1.createIndex("name", "name", { unique: false });
+      store1.createIndex("email", "email", { unique: true });
+      let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
+      store1.transaction.oncomplete = () => {
+        done(db);
+      };
+    };
+  });
+
+  // Prevents AbortError
+  await new Promise(done => {
+    request.onsuccess = done;
+  });
+
+  let transaction = db.transaction(["obj1", "obj2"], "readwrite");
+  let store1 = transaction.objectStore("obj1");
+  let store2 = transaction.objectStore("obj2");
+  store1.add({id: 1, name: "foo", email: "foo@bar.com"});
+  store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
+  store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
+  store2.add({
+    id2: 1,
+    name: "foo",
+    email: "foo@bar.com",
+    extra: "baz"
+  });
+  // Prevents AbortError during close()
+  await new Promise(success => {
+    transaction.oncomplete = success;
+  });
+
+  db.close();
+
+  request = indexedDB.open("idb2", 1);
+  let db2 = await new Promise(done => {
+    request.onupgradeneeded = event => {
+      let db2 = event.target.result;
+      let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
+      store3.createIndex("name2", "name2", { unique: true });
+      store3.transaction.oncomplete = () => {
+        done(db2);
+      }
+    };
+  });
+  // Prevents AbortError during close()
+  await new Promise(done => {
+    request.onsuccess = done;
+  });
+  db2.close();
+
+  dump("added indexedDB from main page\n");
+};
+
+function deleteDB(dbName) {
+  return new Promise(resolve => {
+    dump("removing database " + dbName + " from " + document.location + "\n");
+    indexedDB.deleteDatabase(dbName).onsuccess = resolve;
+  });
+}
+
+async function fetchPut(cache, url) {
+  let response = await fetch(url);
+  await cache.put(url, response);
+}
+
+let cacheGenerator = async function() {
+  let cache = await caches.open("plop");
+  await fetchPut(cache, "404_cached_file.js");
+  await fetchPut(cache, "browser_storage_basic.js");
+};
+
+window.setup = function*() {
+  yield idbGenerator();
+
+  if (window.caches) {
+    yield cacheGenerator();
+  }
+};
+
+window.clear = function*() {
+  yield deleteDB("idb1");
+  yield deleteDB("idb2");
+
+  if (window.caches) {
+    yield caches.delete("plop");
+  }
+
+  dump("removed indexedDB and cache data from " + document.location + "\n");
+};
+</script>
+</body>
+</html>
--- a/devtools/client/storage/test/storage-listings.html
+++ b/devtools/client/storage/test/storage-listings.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-Bug 970517 - Storage inspector front end - tests
+Storage inspector front end - tests
 -->
 <head>
   <meta charset="utf-8">
   <title>Storage inspector test for listing hosts and storages</title>
 </head>
 <body>
 <iframe src="http://sectest1.example.org/browser/devtools/client/storage/test/storage-unsecured-iframe.html"></iframe>
 <iframe src="https://sectest1.example.org:443/browser/devtools/client/storage/test/storage-secured-iframe.html"></iframe>
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -121,37 +121,63 @@ StorageActors.defaults = function (typeN
 
     /**
      * Returns a list of currently knwon hosts for the target window. This list
      * contains unique hosts from the window + all inner windows.
      */
     get hosts() {
       let hosts = new Set();
       for (let {location} of this.storageActor.windows) {
-        hosts.add(this.getHostName(location));
+        let host = this.getHostName(location);
+
+        if (host) {
+          hosts.add(host);
+        }
       }
       return hosts;
     },
 
     /**
      * Returns all the windows present on the page. Includes main window + inner
      * iframe windows.
      */
     get windows() {
       return this.storageActor.windows;
     },
 
     /**
-     * Converts the window.location object into host.
+     * Converts the window.location object into a URL (e.g. http://domain.com).
      */
     getHostName(location) {
-      if (location.protocol === "chrome:") {
-        return location.href;
+      if (!location) {
+        // Debugging a legacy Firefox extension... no hostname available and no
+        // storage possible.
+        return null;
       }
-      return location.hostname || location.href;
+
+      switch (location.protocol) {
+        case "data:":
+          // data: URLs do not support storage of any type.
+          return null;
+        case "about:":
+          // Fallthrough.
+        case "chrome:":
+          // Fallthrough.
+        case "file:":
+          return location.protocol + location.pathname;
+        case "resource:":
+          return location.origin + location.pathname;
+        case "moz-extension:":
+          return location.origin;
+        case "javascript:":
+          return location.href;
+        default:
+          // http: or unknown protocol.
+          return `${location.protocol}//${location.host}`;
+      }
     },
 
     initialize(storageActor) {
       protocol.Actor.prototype.initialize.call(this, null);
 
       this.storageActor = storageActor;
 
       this.populateStoresForHosts();
@@ -201,17 +227,17 @@ StorageActors.defaults = function (typeN
      * When a new window is added to the page. This generally means that a new
      * iframe is created, or the current window is completely reloaded.
      *
      * @param {window} window
      *        The window which was added.
      */
     onWindowReady: Task.async(function* (window) {
       let host = this.getHostName(window.location);
-      if (!this.hostVsStores.has(host)) {
+      if (host && !this.hostVsStores.has(host)) {
         yield this.populateStoresForHost(host, window);
         let data = {};
         data[host] = this.getNamesForHost(host);
         this.storageActor.update("added", typeName, data);
       }
     }),
 
     /**
@@ -222,17 +248,17 @@ StorageActors.defaults = function (typeN
      *        The window which was removed.
      */
     onWindowDestroyed(window) {
       if (!window.location) {
         // Nothing can be done if location object is null
         return;
       }
       let host = this.getHostName(window.location);
-      if (!this.hosts.has(host)) {
+      if (host && !this.hosts.has(host)) {
         this.hostVsStores.delete(host);
         let data = {};
         data[host] = [];
         this.storageActor.update("deleted", typeName, data);
       }
     },
 
     form(form, detail) {
@@ -462,22 +488,26 @@ StorageActors.createActor({
   /**
    * Given a cookie object and a host, figure out if the cookie is valid for
    * that host.
    */
   isCookieAtHost(cookie, host) {
     if (cookie.host == null) {
       return host == null;
     }
+
+    host = trimHttpHttps(host);
+
     if (cookie.host.startsWith(".")) {
       return ("." + host).endsWith(cookie.host);
     }
     if (cookie.host === "") {
       return host.startsWith("file://" + cookie.path);
     }
+
     return cookie.host == host;
   },
 
   toStoreObject(cookie) {
     if (!cookie) {
       return null;
     }
 
@@ -709,16 +739,18 @@ StorageActors.createActor({
 
 var cookieHelpers = {
   getCookiesFromHost(host, originAttributes) {
     // Local files have no host.
     if (host.startsWith("file:///")) {
       host = "";
     }
 
+    host = trimHttpHttps(host);
+
     let cookies = Services.cookies.getCookiesFromHost(host, originAttributes);
     let store = [];
 
     while (cookies.hasMoreElements()) {
       let cookie = cookies.getNext().QueryInterface(Ci.nsICookie2);
 
       store.push(cookie);
     }
@@ -843,16 +875,18 @@ var cookieHelpers = {
     // extract the cookie name to remove the correct cookie.
     if (opts.name) {
       let split = opts.name.split(SEPARATOR_GUID);
 
       opts.name = split[0];
       opts.path = split[2];
     }
 
+    host = trimHttpHttps(host);
+
     function hostMatches(cookieHost, matchHost) {
       if (cookieHost == null) {
         return matchHost == null;
       }
       if (cookieHost.startsWith(".")) {
         return ("." + matchHost).endsWith(cookieHost);
       }
       return cookieHost == host;
@@ -1049,38 +1083,31 @@ function getObjectForLocalOrSessionStora
         return [];
       }
       return Object.keys(storage).map(key => ({
         name: key,
         value: storage.getItem(key)
       }));
     },
 
-    getHostName(location) {
-      if (!location.host) {
-        return location.href;
-      }
-      if (location.protocol === "chrome:") {
-        return location.href;
-      }
-      return location.protocol + "//" + location.host;
-    },
-
     populateStoresForHost(host, window) {
       try {
         this.hostVsStores.set(host, window[type]);
       } catch (ex) {
         console.warn(`Failed to enumerate ${type} for host ${host}: ${ex}`);
       }
     },
 
     populateStoresForHosts() {
       this.hostVsStores = new Map();
       for (let window of this.windows) {
-        this.populateStoresForHost(this.getHostName(window.location), window);
+        let host = this.getHostName(window.location);
+        if (host) {
+          this.populateStoresForHost(host, window);
+        }
       }
     },
 
     getFields: Task.async(function* () {
       return [
         { name: "name", editable: true },
         { name: "value", editable: true }
       ];
@@ -1269,26 +1296,16 @@ StorageActors.createActor({
 
   getFields: Task.async(function* () {
     return [
       { name: "url", editable: false },
       { name: "status", editable: false }
     ];
   }),
 
-  getHostName(location) {
-    if (!location.host) {
-      return location.href;
-    }
-    if (location.protocol === "chrome:") {
-      return location.href;
-    }
-    return location.protocol + "//" + location.host;
-  },
-
   populateStoresForHost: Task.async(function* (host) {
     let storeMap = new Map();
     let caches = yield this.getCachesForHost(host);
     try {
       for (let name of (yield caches.keys())) {
         storeMap.set(name, (yield caches.open(name)));
       }
     } catch (ex) {
@@ -1554,26 +1571,16 @@ StorageActors.createActor({
     if (!win) {
       return;
     }
 
     let principal = win.document.nodePrincipal;
     this.removeDBRecord(host, principal, db, store, id);
   }),
 
-  getHostName(location) {
-    if (!location.host) {
-      return location.href;
-    }
-    if (location.protocol === "chrome:") {
-      return location.href;
-    }
-    return location.protocol + "//" + location.host;
-  },
-
   /**
    * This method is overriden and left blank as for indexedDB, this operation
    * cannot be performed synchronously. Thus, the preListStores method exists to
    * do the same task asynchronously.
    */
   populateStoresForHosts() {},
 
   getNamesForHost(host) {
@@ -2405,16 +2412,29 @@ exports.setupParentProcessForIndexedDB =
 
   return {
     onBrowserSwap: setMessageManager,
     onDisconnected: () => setMessageManager(null),
   };
 };
 
 /**
+ * General helpers
+ */
+function trimHttpHttps(url) {
+  if (url.startsWith("http://")) {
+    return url.substr(7);
+  }
+  if (url.startsWith("https://")) {
+    return url.substr(8);
+  }
+  return url;
+}
+
+/**
  * The main Storage Actor.
  */
 let StorageActor = protocol.ActorClassWithSpec(specs.storageSpec, {
   typeName: "storage",
 
   get window() {
     return this.parentActor.window;
   },
--- a/devtools/server/tests/browser/browser_storage_cookies-duplicate-names.js
+++ b/devtools/server/tests/browser/browser_storage_cookies-duplicate-names.js
@@ -6,17 +6,17 @@
 
 // Test that the storage panel is able to display multiple cookies with the same
 // name (and different paths).
 
 const {StorageFront} = require("devtools/shared/fronts/storage");
 Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/server/tests/browser/storage-helpers.js", this);
 
 const TESTDATA = {
-  "test1.example.org": [
+  "http://test1.example.org": [
     {
       name: "name",
       value: "value1",
       expires: 0,
       path: "/",
       host: "test1.example.org",
       isDomain: false,
       isSecure: false,
--- a/devtools/server/tests/browser/browser_storage_dynamic_windows.js
+++ b/devtools/server/tests/browser/browser_storage_dynamic_windows.js
@@ -4,18 +4,18 @@
 
 "use strict";
 
 const {StorageFront} = require("devtools/shared/fronts/storage");
 Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/server/tests/browser/storage-helpers.js", this);
 
 const beforeReload = {
   cookies: {
-    "test1.example.org": ["c1", "cs2", "c3", "uc1"],
-    "sectest1.example.org": ["uc1", "cs2"]
+    "http://test1.example.org": ["c1", "cs2", "c3", "uc1"],
+    "http://sectest1.example.org": ["uc1", "cs2"]
   },
   localStorage: {
     "http://test1.example.org": ["ls1", "ls2"],
     "http://sectest1.example.org": ["iframe-u-ls1"]
   },
   sessionStorage: {
     "http://test1.example.org": ["ss1"],
     "http://sectest1.example.org": ["iframe-u-ss1", "iframe-u-ss2"]
@@ -94,17 +94,22 @@ function testAddIframe(front) {
     let shouldBeEmpty = {
       localStorage: {
         "https://sectest1.example.org": ["iframe-s-ls1"]
       },
       sessionStorage: {
         "https://sectest1.example.org": ["iframe-s-ss1"]
       },
       cookies: {
-        "sectest1.example.org": [
+        "https://sectest1.example.org": [
+          getCookieId("cs2", ".example.org", "/"),
+          getCookieId("sc1", "sectest1.example.org",
+                      "/browser/devtools/server/tests/browser/")
+        ],
+        "http://sectest1.example.org": [
           getCookieId("sc1", "sectest1.example.org",
                       "/browser/devtools/server/tests/browser/")
         ]
       },
       indexedDB: {
         // empty because indexed db creation happens after the page load, so at
         // the time of window-ready, there was no indexed db present.
         "https://sectest1.example.org": []
--- a/devtools/server/tests/browser/browser_storage_listings.js
+++ b/devtools/server/tests/browser/browser_storage_listings.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const {StorageFront} = require("devtools/shared/fronts/storage");
 Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/server/tests/browser/storage-helpers.js", this);
 
 const storeMap = {
   cookies: {
-    "test1.example.org": [
+    "http://test1.example.org": [
       {
         name: "c1",
         value: "foobar",
         expires: 2000000000000,
         path: "/browser",
         host: "test1.example.org",
         isDomain: false,
         isSecure: false,
@@ -33,17 +33,39 @@ const storeMap = {
         value: "foobar-2",
         expires: 2000000001000,
         path: "/",
         host: "test1.example.org",
         isDomain: false,
         isSecure: true,
       }
     ],
-    "sectest1.example.org": [
+
+    "http://sectest1.example.org": [
+      {
+        name: "cs2",
+        value: "sessionCookie",
+        path: "/",
+        host: ".example.org",
+        expires: 0,
+        isDomain: true,
+        isSecure: false,
+      },
+      {
+        name: "sc1",
+        value: "foobar",
+        path: "/browser/devtools/server/tests/browser/",
+        host: "sectest1.example.org",
+        expires: 0,
+        isDomain: false,
+        isSecure: false,
+      }
+    ],
+
+    "https://sectest1.example.org": [
       {
         name: "uc1",
         value: "foobar",
         host: ".example.org",
         path: "/",
         expires: 0,
         isDomain: true,
         isSecure: true,
@@ -323,17 +345,17 @@ function* testStores(data) {
   ok(data.indexedDB, "Indexed DB storage actor is present");
   yield testCookies(data.cookies);
   yield testLocalStorage(data.localStorage);
   yield testSessionStorage(data.sessionStorage);
   yield testIndexedDB(data.indexedDB);
 }
 
 function testCookies(cookiesActor) {
-  is(Object.keys(cookiesActor.hosts).length, 2,
+  is(Object.keys(cookiesActor.hosts).length, 3,
                  "Correct number of host entries for cookies");
   return testCookiesObjects(0, cookiesActor.hosts, cookiesActor);
 }
 
 var testCookiesObjects = Task.async(function* (index, hosts, cookiesActor) {
   let host = Object.keys(hosts)[index];
   let matchItems = data => {
     let cookiesLength = 0;
--- a/devtools/server/tests/browser/browser_storage_updates.js
+++ b/devtools/server/tests/browser/browser_storage_updates.js
@@ -1,17 +1,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const {StorageFront} = require("devtools/shared/fronts/storage");
 const beforeReload = {
-  cookies: ["test1.example.org", "sectest1.example.org"],
+  cookies: ["http://test1.example.org", "https://sectest1.example.org"],
   localStorage: ["http://test1.example.org", "http://sectest1.example.org"],
   sessionStorage: ["http://test1.example.org", "http://sectest1.example.org"],
 };
 
 const TESTS = [
   // index 0
   {
     action: function (win) {
@@ -22,17 +22,17 @@ const TESTS = [
       win.addCookie("c2", "foobar2");
 
       info('win.localStorage.setItem("l1", "foobar1")');
       win.localStorage.setItem("l1", "foobar1");
     },
     expected: {
       added: {
         cookies: {
-          "test1.example.org": [
+          "http://test1.example.org": [
             getCookieId("c1", "test1.example.org",
                         "/browser/devtools/server/tests/browser/"),
             getCookieId("c2", "test1.example.org",
                         "/browser/devtools/server/tests/browser/")
           ]
         },
         localStorage: {
           "http://test1.example.org": ["l1"]
@@ -48,17 +48,17 @@ const TESTS = [
       win.addCookie("c1", "new_foobar1");
 
       info('win.localStorage.setItem("l2", "foobar2")');
       win.localStorage.setItem("l2", "foobar2");
     },
     expected: {
       changed: {
         cookies: {
-          "test1.example.org": [
+          "http://test1.example.org": [
             getCookieId("c1", "test1.example.org",
                         "/browser/devtools/server/tests/browser/"),
           ]
         }
       },
       added: {
         localStorage: {
           "http://test1.example.org": ["l2"]
@@ -77,17 +77,17 @@ const TESTS = [
       win.localStorage.removeItem("l1");
 
       info('win.localStorage.setItem("l3", "foobar3")');
       win.localStorage.setItem("l3", "foobar3");
     },
     expected: {
       deleted: {
         cookies: {
-          "test1.example.org": [
+          "http://test1.example.org": [
             getCookieId("c2", "test1.example.org",
                         "/browser/devtools/server/tests/browser/"),
           ]
         },
         localStorage: {
           "http://test1.example.org": ["l1"]
         }
       },
@@ -118,33 +118,33 @@ const TESTS = [
       win.sessionStorage.setItem("s2", "foobar2");
 
       info('win.localStorage.setItem("l3", "new_foobar3")');
       win.localStorage.setItem("l3", "new_foobar3");
     },
     expected: {
       added: {
         cookies: {
-          "test1.example.org": [
+          "http://test1.example.org": [
             getCookieId("c3", "test1.example.org",
                         "/browser/devtools/server/tests/browser/"),
           ]
         },
         sessionStorage: {
           "http://test1.example.org": ["s1", "s2"]
         }
       },
       changed: {
         localStorage: {
           "http://test1.example.org": ["l3"]
         }
       },
       deleted: {
         cookies: {
-          "test1.example.org": [
+          "http://test1.example.org": [
             getCookieId("c1", "test1.example.org",
                         "/browser/devtools/server/tests/browser/"),
           ]
         },
         localStorage: {
           "http://test1.example.org": ["l2"]
         }
       }
@@ -170,17 +170,17 @@ const TESTS = [
   {
     action: function (win) {
       info("win.clearCookies()");
       win.clearCookies();
     },
     expected: {
       deleted: {
         cookies: {
-          "test1.example.org": [
+          "http://test1.example.org": [
             getCookieId("c3", "test1.example.org",
                         "/browser/devtools/server/tests/browser/"),
           ]
         }
       }
     }
   }
 ];
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -905,18 +905,18 @@ EffectCompositor::GetBaseStyle(nsCSSProp
   // Check whether there is a cached style.
   result = effectSet->GetBaseStyle(aProperty);
   if (!result.IsNull()) {
     return result;
   }
 
   RefPtr<nsStyleContext> styleContextWithoutAnimation =
     aStyleContext->PresContext()->StyleSet()->AsGecko()->
-      ResolveStyleWithoutAnimation(&aElement, aStyleContext,
-                                   eRestyle_AllHintsWithAnimations);
+      ResolveStyleByRemovingAnimation(&aElement, aStyleContext,
+                                      eRestyle_AllHintsWithAnimations);
 
   DebugOnly<bool> success =
     StyleAnimationValue::ExtractComputedValue(aProperty,
                                               styleContextWithoutAnimation,
                                               result);
   MOZ_ASSERT(success, "Should be able to extract computed animation value");
   MOZ_ASSERT(!result.IsNull(), "Should have a valid StyleAnimationValue");
 
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -272,16 +272,18 @@ SpecifiedKeyframeArraysAreEqual(const ns
 void
 KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
 {
   MOZ_ASSERT(aStyleContext);
 
   // Skip updating properties when we are composing style.
   // FIXME: Bug 1324966. Drop this check once we have a function to get
   // nsStyleContext without resolving animating style.
+  MOZ_DIAGNOSTIC_ASSERT(!mIsComposingStyle,
+                        "Should not be called while processing ComposeStyle()");
   if (mIsComposingStyle) {
     return;
   }
 
   nsTArray<AnimationProperty> properties = BuildProperties(aStyleContext);
 
   if (mProperties == properties) {
     return;
@@ -358,17 +360,18 @@ KeyframeEffectReadOnly::GetUnderlyingSty
     // If we have already composed style for the property, we use the style
     // as the underlying style.
     DebugOnly<bool> success = aAnimationRule->GetValue(aProperty, result);
     MOZ_ASSERT(success, "AnimValuesStyleRule::GetValue should not fail");
   } else {
     // If we are composing with composite operation that is not 'replace'
     // and we have not composed style for the property yet, we have to get
     // the base style for the property.
-    RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
+    RefPtr<nsStyleContext> styleContext =
+      GetTargetStyleContextWithoutAnimation();
     result = EffectCompositor::GetBaseStyle(aProperty,
                                             styleContext,
                                             *mTarget->mElement,
                                             mTarget->mPseudoType);
     MOZ_ASSERT(!result.IsNull(), "The base style should be set");
     SetNeedsBaseStyle(aProperty);
   }
 
@@ -438,17 +441,17 @@ KeyframeEffectReadOnly::EnsureBaseStyles
 
     for (const AnimationPropertySegment& segment : property.mSegments) {
       if (segment.mFromComposite == dom::CompositeOperation::Replace &&
           segment.mToComposite == dom::CompositeOperation::Replace) {
         continue;
       }
 
       if (!styleContext) {
-        styleContext = GetTargetStyleContext();
+        styleContext = GetTargetStyleContextWithoutAnimation();
       }
       MOZ_RELEASE_ASSERT(styleContext);
 
       Unused << EffectCompositor::GetBaseStyle(property.mProperty,
                                                styleContext,
                                                *mTarget->mElement,
                                                mTarget->mPseudoType);
       // Make this property as needing a base style so that we send the (now
@@ -459,16 +462,18 @@ KeyframeEffectReadOnly::EnsureBaseStyles
   }
 }
 
 void
 KeyframeEffectReadOnly::ComposeStyle(
   RefPtr<AnimValuesStyleRule>& aStyleRule,
   const nsCSSPropertyIDSet& aPropertiesToSkip)
 {
+  MOZ_DIAGNOSTIC_ASSERT(!mIsComposingStyle,
+                        "Should not be called recursively");
   if (mIsComposingStyle) {
     return;
   }
 
   AutoRestore<bool> isComposingStyle(mIsComposingStyle);
   mIsComposingStyle = true;
 
   ComputedTiming computedTiming = GetComputedTiming();
@@ -895,32 +900,52 @@ KeyframeEffectReadOnly::RequestRestyle(
   nsPresContext* presContext = GetPresContext();
   if (presContext && mTarget && mAnimation) {
     presContext->EffectCompositor()->
       RequestRestyle(mTarget->mElement, mTarget->mPseudoType,
                      aRestyleType, mAnimation->CascadeLevel());
   }
 }
 
+template<KeyframeEffectReadOnly::AnimationStyle aAnimationStyle>
 already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::GetTargetStyleContext()
+KeyframeEffectReadOnly::DoGetTargetStyleContext()
 {
   nsIPresShell* shell = GetPresShell();
   if (!shell) {
     return nullptr;
   }
 
   MOZ_ASSERT(mTarget,
              "Should only have a presshell when we have a target element");
 
   nsIAtom* pseudo = mTarget->mPseudoType < CSSPseudoElementType::Count
                     ? nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType)
                     : nullptr;
-  return nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement,
-                                                       pseudo, shell);
+
+  if (aAnimationStyle == AnimationStyle::Include) {
+    return nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement,
+                                                         pseudo,
+                                                         shell);
+  }
+
+  return nsComputedDOMStyle::GetStyleContextForElementWithoutAnimation(
+    mTarget->mElement, pseudo, shell);
+}
+
+already_AddRefed<nsStyleContext>
+KeyframeEffectReadOnly::GetTargetStyleContext()
+{
+  return DoGetTargetStyleContext<AnimationStyle::Include>();
+}
+
+already_AddRefed<nsStyleContext>
+KeyframeEffectReadOnly::GetTargetStyleContextWithoutAnimation()
+{
+  return DoGetTargetStyleContext<AnimationStyle::Skip>();
 }
 
 #ifdef DEBUG
 void
 DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
 {
   for (auto& p : aAnimationProperties) {
     printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get());
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -404,18 +404,29 @@ protected:
   // have changed, or when the target frame might have changed.
   void MaybeUpdateFrameForCompositor();
 
   // Looks up the style context associated with the target element, if any.
   // We need to be careful to *not* call this when we are updating the style
   // context. That's because calling GetStyleContextForElement when we are in
   // the process of building a style context may trigger various forms of
   // infinite recursion.
+  already_AddRefed<nsStyleContext> GetTargetStyleContext();
+
+  // Similar to the above but ignoring animation rules. We use this to get base
+  // styles (which don't include animation rules).
   already_AddRefed<nsStyleContext>
-  GetTargetStyleContext();
+  GetTargetStyleContextWithoutAnimation();
+
+  enum AnimationStyle {
+    Skip,
+    Include
+  };
+  template<AnimationStyle aAnimationStyle>
+  already_AddRefed<nsStyleContext> DoGetTargetStyleContext();
 
   // A wrapper for marking cascade update according to the current
   // target and its effectSet.
   void MarkCascadeNeedsUpdate();
 
   // Composites |aValueToComposite| using |aCompositeOperation| onto the value
   // for |aProperty| in |aAnimationRule|, or, if there is no suitable value in
   // |aAnimationRule|, uses the base value for the property recorded on the
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1330190-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<span id=a />
+<script>
+addEventListener("DOMContentLoaded", function(){
+  a.animate([{"left": "38%"}], 100);
+  a.appendChild(document.createElement("div"));
+  document.documentElement.classList.remove("reftest-wait");
+});
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1330190-2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<style>
+@keyframes anim {
+}
+
+#o_0:before {
+  animation: anim 10s;
+}
+</style>
+<meta charset="UTF-8">
+<script>
+function boom(){
+  function getPseudoElement() {
+    var anim = document.getAnimations()[0];
+    anim.cancel();
+    return anim.effect.target;
+  }
+
+  var target = getPseudoElement();
+  target.animate([{"perspective": "262ex"}, {}], {duration: 1070, iterationStart: 68, iterationComposite: "accumulate"});
+  target.animate([{"color": "white", "flex": "inherit"}, {"color": "red", "flex": "66% "}], 3439);
+  target.animate([{"font": "icon"}], 1849);
+  setTimeout(function() {
+    document.documentElement.classList.remove("reftest-wait");
+  }, 500);
+}
+document.addEventListener("DOMContentLoaded", boom);
+</script>
+</head>
+<body>
+<div id=o_0></div>
+</body>
+</html>
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -12,10 +12,12 @@ asserts-if(stylo,5) pref(dom.animations-
 asserts-if(stylo,31) pref(dom.animations-api.core.enabled,true) load 1277272-1.html # bug 1324694
 asserts-if(stylo,2) pref(dom.animations-api.core.enabled,true) load 1290535-1.html # bug 1324690
 pref(dom.animations-api.core.enabled,true) load 1304886-1.html
 pref(dom.animations-api.core.enabled,true) load 1322382-1.html
 skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1322291-1.html # bug 1311257
 skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1322291-2.html # bug 1311257
 asserts-if(stylo,0-5) pref(dom.animations-api.core.enabled,true) load 1323114-1.html # bug 1324690
 asserts-if(stylo,0-5) pref(dom.animations-api.core.enabled,true) load 1323114-2.html # bug 1324690
+skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1325193-1.html # bug 1311257
+skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1330190-1.html # bug 1311257
+skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1330190-2.html # bug 1311257
 skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1330513-1.html # bug 1311257
-skip-if(stylo) pref(dom.animations-api.core.enabled,true) load 1325193-1.html # bug 1311257
--- a/dom/base/ScreenOrientation.cpp
+++ b/dom/base/ScreenOrientation.cpp
@@ -363,18 +363,21 @@ ScreenOrientation::LockDeviceOrientation
     return false;
   }
 
   if (NS_WARN_IF(!hal::LockScreenOrientation(aOrientation))) {
     return false;
   }
 
   // We are fullscreen and lock has been accepted.
-  if (aIsFullScreen && !mFullScreenListener) {
-    mFullScreenListener = new FullScreenEventListener();
+  if (aIsFullScreen) {
+    if (!mFullScreenListener) {
+      mFullScreenListener = new FullScreenEventListener();
+    }
+
     aRv = target->AddSystemEventListener(NS_LITERAL_STRING("fullscreenchange"),
                                          mFullScreenListener, /* useCapture = */ true);
     if (NS_WARN_IF(aRv.Failed())) {
       return false;
     }
   }
 
   return true;
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -121,16 +121,17 @@ private:
   DECL_MEDIA_PREF("media.ffvpx.enabled",                      PDMFFVPXEnabled, bool, true);
 #endif
 #ifdef XP_WIN
   DECL_MEDIA_PREF("media.wmf.enabled",                        PDMWMFEnabled, bool, true);
   DECL_MEDIA_PREF("media.wmf.skip-blacklist",                 PDMWMFSkipBlacklist, bool, false);
   DECL_MEDIA_PREF("media.decoder-doctor.wmf-disabled-is-failure", DecoderDoctorWMFDisabledIsFailure, bool, false);
   DECL_MEDIA_PREF("media.wmf.vp9.enabled",                    PDMWMFVP9DecoderEnabled, bool, true);
   DECL_MEDIA_PREF("media.wmf.decoder.thread-count",           PDMWMFThreadCount, int32_t, -1);
+  DECL_MEDIA_PREF("media.wmf.allow-unsupported-resolutions",  PDMWMFAllowUnsupportedResolutions, bool, false);
 #endif
   DECL_MEDIA_PREF("media.decoder.fuzzing.enabled",            PDMFuzzingEnabled, bool, false);
   DECL_MEDIA_PREF("media.decoder.fuzzing.video-output-minimum-interval-ms", PDMFuzzingInterval, uint32_t, 0);
   DECL_MEDIA_PREF("media.decoder.fuzzing.dont-delay-inputexhausted", PDMFuzzingDelayInputExhausted, bool, true);
   DECL_MEDIA_PREF("media.decoder.recycle.enabled",            MediaDecoderCheckRecycling, bool, false);
   DECL_MEDIA_PREF("media.gmp.decoder.enabled",                PDMGMPEnabled, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.aac",                    GMPAACPreferred, uint32_t, 0);
   DECL_MEDIA_PREF("media.gmp.decoder.h264",                   GMPH264Preferred, uint32_t, 0);
--- a/dom/media/encoder/VP8TrackEncoder.cpp
+++ b/dom/media/encoder/VP8TrackEncoder.cpp
@@ -124,17 +124,17 @@ VP8TrackEncoder::Init(int32_t aWidth, in
   } else if (mFrameWidth * mFrameHeight > 640 * 480 && number_of_cores >= 3) {
     config.g_threads = 2; // 2 threads for qHD/HD.
   } else {
     config.g_threads = 1; // 1 thread for VGA or less
   }
 
   // rate control settings
   config.rc_dropframe_thresh = 0;
-  config.rc_end_usage = VPX_CBR;
+  config.rc_end_usage = VPX_VBR;
   config.g_pass = VPX_RC_ONE_PASS;
   // ffmpeg doesn't currently support streams that use resize.
   // Therefore, for safety, we should turn it off until it does.
   config.rc_resize_allowed = 0;
   config.rc_undershoot_pct = 100;
   config.rc_overshoot_pct = 15;
   config.rc_buf_initial_sz = 500;
   config.rc_buf_optimal_sz = 600;
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -15,16 +15,17 @@
 #include "MediaData.h"
 #ifdef MOZ_FMP4
 #include "MP4Stream.h"
 #include "mp4_demuxer/AtomType.h"
 #include "mp4_demuxer/ByteReader.h"
 #endif
 #include "nsAutoPtr.h"
 #include "SourceBufferResource.h"
+#include <algorithm>
 
 extern mozilla::LogModule* GetMediaSourceSamplesLog();
 
 #define STRINGIFY(x) #x
 #define TOSTRING(x) STRINGIFY(x)
 #define MSE_DEBUG(name, arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Debug, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
 #define MSE_DEBUGV(name, arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Verbose, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
 
@@ -343,27 +344,33 @@ public:
   {}
 
   MediaResult IsInitSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsInitSegmentPresent(aData);
     // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
     // file is the 'ftyp' atom followed by a file type. We just check for a
     // vaguely valid 'ftyp' atom.
+    if (aData->Length() < 8) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
     AtomParser parser(mType, aData);
     if (!parser.IsValid()) {
       return MediaResult(
         NS_ERROR_FAILURE,
         RESULT_DETAIL("Invalid Top-Level Box:%s", parser.LastInvalidBox()));
     }
     return parser.StartWithInitSegment() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
 
   MediaResult IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
+    if (aData->Length() < 8) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
     AtomParser parser(mType, aData);
     if (!parser.IsValid()) {
       return MediaResult(
         NS_ERROR_FAILURE,
         RESULT_DETAIL("Invalid Box:%s", parser.LastInvalidBox()));
     }
     return parser.StartWithMediaSegment() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
@@ -391,30 +398,25 @@ private:
 
       while (reader.Remaining() >= 8) {
         uint64_t size = reader.ReadU32();
         const uint8_t* typec = reader.Peek(4);
         mp4_demuxer::AtomType type(reader.ReadU32());
         MSE_DEBUGV(AtomParser ,"Checking atom:'%c%c%c%c' @ %u",
                    typec[0], typec[1], typec[2], typec[3],
                    (uint32_t)reader.Offset() - 8);
-
-        for (const auto& boxType : validBoxes) {
-          if (type == boxType) {
-            mValid = true;
-            break;
-          }
-        }
-        if (!mValid) {
-          // No point continuing.
+        if (std::find(std::begin(validBoxes), std::end(validBoxes), type)
+            == std::end(validBoxes)) {
+          // No valid box found, no point continuing.
           mLastInvalidBox[0] = typec[0];
           mLastInvalidBox[1] = typec[1];
           mLastInvalidBox[2] = typec[2];
           mLastInvalidBox[3] = typec[3];
           mLastInvalidBox[4] = '\0';
+          mValid = false;
           break;
         }
         if (mInitOffset.isNothing() &&
             mp4_demuxer::AtomType(type) == initAtom) {
           mInitOffset = Some(reader.Offset());
         }
         if (mMediaOffset.isNothing() &&
             mp4_demuxer::AtomType(type) == mediaAtom) {
@@ -453,17 +455,17 @@ private:
       return mMediaOffset.isSome() &&
         (mInitOffset.isNothing() || mMediaOffset.ref() < mInitOffset.ref());
     }
     bool IsValid() const { return mValid; }
     const char* LastInvalidBox() const { return mLastInvalidBox; }
   private:
     Maybe<size_t> mInitOffset;
     Maybe<size_t> mMediaOffset;
-    bool mValid = false;
+    bool mValid = true;
     char mLastInvalidBox[5];
   };
 
 public:
   MediaResult ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                          int64_t& aStart,
                                          int64_t& aEnd) override
   {
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -205,17 +205,19 @@ bool
 WMFDecoderModule::Supports(const TrackInfo& aTrackInfo,
                            DecoderDoctorDiagnostics* aDiagnostics) const
 {
   if ((aTrackInfo.mMimeType.EqualsLiteral("audio/mp4a-latm") ||
        aTrackInfo.mMimeType.EqualsLiteral("audio/mp4")) &&
        WMFDecoderModule::HasAAC()) {
     return true;
   }
-  if (MP4Decoder::IsH264(aTrackInfo.mMimeType) && WMFDecoderModule::HasH264()) {
+  if (MP4Decoder::IsH264(aTrackInfo.mMimeType) &&
+      WMFDecoderModule::HasH264() &&
+      !MediaPrefs::PDMWMFAllowUnsupportedResolutions()) {
     const VideoInfo* videoInfo = aTrackInfo.GetAsVideoInfo();
     MOZ_ASSERT(videoInfo);
     // Check Windows format constraints, based on:
     // https://msdn.microsoft.com/en-us/library/windows/desktop/dd797815(v=vs.85).aspx
     if (IsWin8OrLater()) {
       // Windows >7 supports at most 4096x2304.
       if (videoInfo->mImage.width > 4096 || videoInfo->mImage.height > 2304) {
         return false;
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -265,30 +265,64 @@ void
 Compositor::DrawGeometry(const gfx::Rect& aRect,
                          const gfx::IntRect& aClipRect,
                          const EffectChain& aEffectChain,
                          gfx::Float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::Rect& aVisibleRect,
                          const Maybe<gfx::Polygon>& aGeometry)
 {
+  if (aRect.IsEmpty()) {
+    return;
+  }
+
   if (!aGeometry || !SupportsLayerGeometry()) {
     DrawQuad(aRect, aClipRect, aEffectChain,
              aOpacity, aTransform, aVisibleRect);
     return;
   }
 
   // Cull invisible polygons.
   if (aRect.Intersect(aGeometry->BoundingBox()).IsEmpty()) {
     return;
   }
 
   const gfx::Polygon clipped = aGeometry->ClipPolygon(aRect);
 
-  for (gfx::Triangle& triangle : clipped.ToTriangles()) {
+  DrawPolygon(clipped, aRect, aClipRect, aEffectChain,
+              aOpacity, aTransform, aVisibleRect);
+}
+
+void
+Compositor::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                          const gfx::Rect& aRect,
+                          const gfx::IntRect& aClipRect,
+                          const EffectChain& aEffectChain,
+                          gfx::Float aOpacity,
+                          const gfx::Matrix4x4& aTransform,
+                          const gfx::Rect& aVisibleRect)
+{
+  for (const gfx::TexturedTriangle& triangle : aTriangles) {
+    DrawTriangle(triangle, aClipRect, aEffectChain,
+                 aOpacity, aTransform, aVisibleRect);
+  }
+}
+
+void
+Compositor::DrawPolygon(const gfx::Polygon& aPolygon,
+                        const gfx::Rect& aRect,
+                        const gfx::IntRect& aClipRect,
+                        const EffectChain& aEffectChain,
+                        gfx::Float aOpacity,
+                        const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect)
+{
+  nsTArray<gfx::TexturedTriangle> texturedTriangles;
+
+  for (gfx::Triangle& triangle : aPolygon.ToTriangles()) {
     const gfx::Rect intersection = aRect.Intersect(triangle.BoundingBox());
 
     // Cull invisible triangles.
     if (intersection.IsEmpty()) {
       continue;
     }
 
     MOZ_ASSERT(aRect.width > 0.0f && aRect.height > 0.0f);
@@ -306,19 +340,21 @@ Compositor::DrawGeometry(const gfx::Rect
         type == EffectTypes::NV12 || type == EffectTypes::RENDER_TARGET) {
       TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
 
       UpdateTextureCoordinates(texturedTriangle, aRect, intersection,
                                texturedEffect->mTextureCoords);
     }
 
-    DrawTriangle(texturedTriangle, aClipRect, aEffectChain,
-                 aOpacity, aTransform, aVisibleRect);
+    texturedTriangles.AppendElement(Move(texturedTriangle));
   }
+
+  DrawTriangles(texturedTriangles, aRect, aClipRect, aEffectChain,
+                aOpacity, aTransform, aVisibleRect);
 }
 
 void
 Compositor::SlowDrawRect(const gfx::Rect& aRect, const gfx::Color& aColor,
                      const gfx::IntRect& aClipRect,
                      const gfx::Matrix4x4& aTransform, int aStrokeWidth)
 {
   // TODO This should draw a rect using a single draw call but since
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -616,16 +616,31 @@ protected:
                                        gfx::Rect* aOutLayerQuad = nullptr);
 
   gfx::IntRect ComputeBackdropCopyRect(const gfx::Triangle& aTriangle,
                                        const gfx::IntRect& aClipRect,
                                        const gfx::Matrix4x4& aTransform,
                                        gfx::Matrix4x4* aOutTransform,
                                        gfx::Rect* aOutLayerQuad = nullptr);
 
+  virtual void DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                             const gfx::Rect& aRect,
+                             const gfx::IntRect& aClipRect,
+                             const EffectChain& aEffectChain,
+                             gfx::Float aOpacity,
+                             const gfx::Matrix4x4& aTransform,
+                             const gfx::Rect& aVisibleRect);
+
+  virtual void DrawPolygon(const gfx::Polygon& aPolygon,
+                           const gfx::Rect& aRect,
+                           const gfx::IntRect& aClipRect,
+                           const EffectChain& aEffectChain,
+                           gfx::Float aOpacity,
+                           const gfx::Matrix4x4& aTransform,
+                           const gfx::Rect& aVisibleRect);
 
   /**
    * An array of locks that will need to be unlocked after the next composition.
    */
   nsTArray<RefPtr<TextureHost>> mUnlockAfterComposition;
 
   /**
    * An array of TextureHosts that will need to call NotifyNotUsed() after the next composition.
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -351,25 +351,110 @@ BasicCompositor::CreateDataTextureSource
 }
 
 bool
 BasicCompositor::SupportsEffect(EffectTypes aEffect)
 {
   return aEffect != EffectTypes::YCBCR && aEffect != EffectTypes::COMPONENT_ALPHA;
 }
 
+bool
+BasicCompositor::SupportsLayerGeometry() const
+{
+  return gfxPrefs::BasicLayerGeometry();
+}
+
+static RefPtr<gfx::Path>
+BuildPathFromPolygon(const RefPtr<DrawTarget>& aDT,
+                     const gfx::Polygon& aPolygon)
+{
+  RefPtr<PathBuilder> pathBuilder = aDT->CreatePathBuilder();
+  const nsTArray<Point4D>& points = aPolygon.GetPoints();
+
+  pathBuilder->MoveTo(points[0].As2DPoint());
+
+  for (size_t i = 1; i < points.Length(); ++i) {
+    pathBuilder->LineTo(points[i].As2DPoint());
+  }
+
+  pathBuilder->Close();
+  return pathBuilder->Finish();
+}
+
 static void
-DrawSurfaceWithTextureCoords(DrawTarget *aDest,
+DrawSurface(gfx::DrawTarget* aDest,
+            const gfx::Rect& aDestRect,
+            const gfx::Rect& /* aClipRect */,
+            const gfx::Color& aColor,
+            const gfx::DrawOptions& aOptions,
+            gfx::SourceSurface* aMask,
+            const gfx::Matrix* aMaskTransform)
+{
+  FillRectWithMask(aDest, aDestRect, aColor,
+                   aOptions, aMask, aMaskTransform);
+}
+
+static void
+DrawSurface(gfx::DrawTarget* aDest,
+            const gfx::Polygon& aPolygon,
+            const gfx::Rect& aClipRect,
+            const gfx::Color& aColor,
+            const gfx::DrawOptions& aOptions,
+            gfx::SourceSurface* aMask,
+            const gfx::Matrix* aMaskTransform)
+{
+  RefPtr<Path> path = BuildPathFromPolygon(aDest, aPolygon);
+  FillPathWithMask(aDest, path, aClipRect, aColor,
+                   aOptions, aMask, aMaskTransform);
+}
+
+static void
+DrawTextureSurface(gfx::DrawTarget* aDest,
+                   const gfx::Rect& aDestRect,
+                   const gfx::Rect& /* aClipRect */,
+                   gfx::SourceSurface* aSource,
+                   gfx::SamplingFilter aSamplingFilter,
+                   const gfx::DrawOptions& aOptions,
+                   ExtendMode aExtendMode,
+                   gfx::SourceSurface* aMask,
+                   const gfx::Matrix* aMaskTransform,
+                   const Matrix* aSurfaceTransform)
+{
+  FillRectWithMask(aDest, aDestRect, aSource, aSamplingFilter, aOptions,
+                   aExtendMode, aMask, aMaskTransform, aSurfaceTransform);
+}
+
+static void
+DrawTextureSurface(gfx::DrawTarget* aDest,
+                   const gfx::Polygon& aPolygon,
+                   const gfx::Rect& aClipRect,
+                   gfx::SourceSurface* aSource,
+                   gfx::SamplingFilter aSamplingFilter,
+                   const gfx::DrawOptions& aOptions,
+                   ExtendMode aExtendMode,
+                   gfx::SourceSurface* aMask,
+                   const gfx::Matrix* aMaskTransform,
+                   const Matrix* aSurfaceTransform)
+{
+  RefPtr<Path> path = BuildPathFromPolygon(aDest, aPolygon);
+  FillPathWithMask(aDest, path, aClipRect, aSource, aSamplingFilter, aOptions,
+                   aExtendMode, aMask, aMaskTransform, aSurfaceTransform);
+}
+
+template<typename Geometry>
+static void
+DrawSurfaceWithTextureCoords(gfx::DrawTarget* aDest,
+                             const Geometry& aGeometry,
                              const gfx::Rect& aDestRect,
-                             SourceSurface *aSource,
+                             gfx::SourceSurface* aSource,
                              const gfx::Rect& aTextureCoords,
                              gfx::SamplingFilter aSamplingFilter,
-                             const DrawOptions& aOptions,
-                             SourceSurface *aMask,
-                             const Matrix* aMaskTransform)
+                             const gfx::DrawOptions& aOptions,
+                             gfx::SourceSurface* aMask,
+                             const gfx::Matrix* aMaskTransform)
 {
   if (!aSource) {
     gfxWarning() << "DrawSurfaceWithTextureCoords problem " << gfx::hexa(aSource) << " and " << gfx::hexa(aMask);
     return;
   }
 
   // Convert aTextureCoords into aSource's coordinate space
   gfxRect sourceRect(aTextureCoords.x * aSource->GetSize().width,
@@ -387,18 +472,18 @@ DrawSurfaceWithTextureCoords(DrawTarget 
                                   gfx::IntPoint::Truncate(aDestRect.x, aDestRect.y),
                                   gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.y),
                                   gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.YMost()));
 
   // Only use REPEAT if aTextureCoords is outside (0, 0, 1, 1).
   gfx::Rect unitRect(0, 0, 1, 1);
   ExtendMode mode = unitRect.Contains(aTextureCoords) ? ExtendMode::CLAMP : ExtendMode::REPEAT;
 
-  FillRectWithMask(aDest, aDestRect, aSource, aSamplingFilter, aOptions,
-                   mode, aMask, aMaskTransform, &matrix);
+  DrawTextureSurface(aDest, aGeometry, aDestRect, aSource, aSamplingFilter,
+                     aOptions, mode, aMask, aMaskTransform, &matrix);
 }
 
 static void
 SetupMask(const EffectChain& aEffectChain,
           DrawTarget* aDest,
           const IntPoint& aOffset,
           RefPtr<SourceSurface>& aMaskSurface,
           Matrix& aMaskTransform)
@@ -548,16 +633,45 @@ AttemptVideoConvertAndScale(TextureSourc
 void
 BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                           const gfx::IntRect& aClipRect,
                           const EffectChain &aEffectChain,
                           gfx::Float aOpacity,
                           const gfx::Matrix4x4& aTransform,
                           const gfx::Rect& aVisibleRect)
 {
+  DrawGeometry(aRect, aRect, aClipRect, aEffectChain,
+               aOpacity, aTransform, aVisibleRect, true);
+}
+
+void
+BasicCompositor::DrawPolygon(const gfx::Polygon& aPolygon,
+                             const gfx::Rect& aRect,
+                             const gfx::IntRect& aClipRect,
+                             const EffectChain& aEffectChain,
+                             gfx::Float aOpacity,
+                             const gfx::Matrix4x4& aTransform,
+                             const gfx::Rect& aVisibleRect)
+{
+  DrawGeometry(aPolygon, aRect, aClipRect, aEffectChain,
+               aOpacity, aTransform, aVisibleRect, false);
+}
+
+
+template<typename Geometry>
+void
+BasicCompositor::DrawGeometry(const Geometry& aGeometry,
+                              const gfx::Rect& aRect,
+                              const gfx::IntRect& aClipRect,
+                              const EffectChain& aEffectChain,
+                              gfx::Float aOpacity,
+                              const gfx::Matrix4x4& aTransform,
+                              const gfx::Rect& aVisibleRect,
+                              const bool aEnableAA)
+{
   RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;
 
   // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
   // |dest| is a temporary surface.
   RefPtr<DrawTarget> dest = buffer;
 
   AutoRestoreTransform autoRestoreTransform(dest);
 
@@ -608,28 +722,33 @@ BasicCompositor::DrawQuad(const gfx::Rec
     SetupMask(aEffectChain, dest, offset, sourceMask, maskTransform);
   }
 
   CompositionOp blendMode = CompositionOp::OP_OVER;
   if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) {
     blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode;
   }
 
+  const AntialiasMode aaMode =
+    aEnableAA ? AntialiasMode::DEFAULT : AntialiasMode::NONE;
+
+  DrawOptions drawOptions(aOpacity, blendMode, aaMode);
+
   switch (aEffectChain.mPrimaryEffect->mType) {
     case EffectTypes::SOLID_COLOR: {
       EffectSolidColor* effectSolidColor =
         static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
 
       bool unboundedOp = !IsOperatorBoundByMask(blendMode);
       if (unboundedOp) {
         dest->PushClipRect(aRect);
       }
 
-      FillRectWithMask(dest, aRect, effectSolidColor->mColor,
-                       DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform);
+      DrawSurface(dest, aGeometry, aRect, effectSolidColor->mColor,
+                  drawOptions, sourceMask, &maskTransform);
 
       if (unboundedOp) {
         dest->PopClip();
       }
       break;
     }
     case EffectTypes::RGB: {
       TexturedEffect* texturedEffect =
@@ -649,37 +768,37 @@ BasicCompositor::DrawQuad(const gfx::Rec
           gfxWarning() << "Failed to get YCbCr to rgb surface.";
         } else if (source->mFromYCBCR &&
             AttemptVideoScale(source, sourceMask, aOpacity, blendMode,
                               texturedEffect,
                               newTransform, aRect, transformedClipRect,
                               dest, buffer)) {
           // we succeeded in scaling
         } else {
-          DrawSurfaceWithTextureCoords(dest, aRect,
+          DrawSurfaceWithTextureCoords(dest, aGeometry, aRect,
                                        source->GetSurface(dest),
                                        texturedEffect->mTextureCoords,
                                        texturedEffect->mSamplingFilter,
-                                       DrawOptions(aOpacity, blendMode),
+                                       drawOptions,
                                        sourceMask, &maskTransform);
         }
       } else if (source) {
         SourceSurface* srcSurf = source->GetSurface(dest);
         if (srcSurf) {
           RefPtr<DataSourceSurface> srcData = srcSurf->GetDataSurface();
 
           // Yes, we re-create the premultiplied data every time.
           // This might be better with a cache, eventually.
           RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData);
 
-          DrawSurfaceWithTextureCoords(dest, aRect,
+          DrawSurfaceWithTextureCoords(dest, aGeometry, aRect,
                                        premultData,
                                        texturedEffect->mTextureCoords,
                                        texturedEffect->mSamplingFilter,
-                                       DrawOptions(aOpacity, blendMode),
+                                       drawOptions,
                                        sourceMask, &maskTransform);
         }
       } else {
         gfxDevCrash(LogReason::IncompatibleBasicTexturedEffect) << "Bad for basic with " << texturedEffect->mTexture->Name() << " and " << gfx::hexa(sourceMask);
       }
 
       break;
     }
@@ -689,21 +808,21 @@ BasicCompositor::DrawQuad(const gfx::Rec
     }
     case EffectTypes::RENDER_TARGET: {
       EffectRenderTarget* effectRenderTarget =
         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
       RefPtr<BasicCompositingRenderTarget> surface
         = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get());
       RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot();
 
-      DrawSurfaceWithTextureCoords(dest, aRect,
+      DrawSurfaceWithTextureCoords(dest, aGeometry, aRect,
                                    sourceSurf,
                                    effectRenderTarget->mTextureCoords,
                                    effectRenderTarget->mSamplingFilter,
-                                   DrawOptions(aOpacity, blendMode),
+                                   drawOptions,
                                    sourceMask, &maskTransform);
       break;
     }
     case EffectTypes::COMPONENT_ALPHA: {
       MOZ_CRASH("Can't (easily) support component alpha with BasicCompositor!");
       break;
     }
     default: {
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -4,16 +4,18 @@
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BASICCOMPOSITOR_H
 #define MOZILLA_GFX_BASICCOMPOSITOR_H
 
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Triangle.h"
+#include "mozilla/gfx/Polygon.h"
 
 namespace mozilla {
 namespace layers {
 
 class BasicCompositingRenderTarget : public CompositingRenderTarget
 {
 public:
   BasicCompositingRenderTarget(gfx::DrawTarget* aDrawTarget, const gfx::IntRect& aRect)
@@ -75,16 +77,18 @@ public:
   virtual already_AddRefed<DataTextureSource>
   CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) override;
 
   virtual already_AddRefed<DataTextureSource>
   CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture) override;
 
   virtual bool SupportsEffect(EffectTypes aEffect) override;
 
+  bool SupportsLayerGeometry() const override;
+
   virtual void SetRenderTarget(CompositingRenderTarget *aSource) override
   {
     mRenderTarget = static_cast<BasicCompositingRenderTarget*>(aSource);
     mRenderTarget->BindRenderTarget();
   }
   virtual CompositingRenderTarget* GetCurrentRenderTarget() const override
   {
     return mRenderTarget;
@@ -106,17 +110,17 @@ public:
                           gfx::IntRect *aClipRectOut = nullptr,
                           gfx::IntRect *aRenderBoundsOut = nullptr) override;
   virtual void EndFrame() override;
 
   virtual bool SupportsPartialTextureUpdate() override { return true; }
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override { return true; }
   virtual int32_t GetMaxTextureSize() const override;
   virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) override { }
-  
+
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) override {
   }
 
   virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) override { }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const override { return "Basic"; }
 #endif // MOZ_DUMP_PAINTING
@@ -131,16 +135,34 @@ public:
   {
     return mIsPendingEndRemoteDrawing;
   }
 
   virtual void FinishPendingComposite() override;
 
 private:
 
+  template<typename Geometry>
+  void DrawGeometry(const Geometry& aGeometry,
+                    const gfx::Rect& aRect,
+                    const gfx::IntRect& aClipRect,
+                    const EffectChain& aEffectChain,
+                    gfx::Float aOpacity,
+                    const gfx::Matrix4x4& aTransform,
+                    const gfx::Rect& aVisibleRect,
+                    const bool aEnableAA);
+
+  virtual void DrawPolygon(const gfx::Polygon& aPolygon,
+                           const gfx::Rect& aRect,
+                           const gfx::IntRect& aClipRect,
+                           const EffectChain& aEffectChain,
+                           gfx::Float aOpacity,
+                           const gfx::Matrix4x4& aTransform,
+                           const gfx::Rect& aVisibleRect) override;
+
   void TryToEndRemoteDrawing(bool aForceToEnd = false);
 
   bool NeedsToDeferEndRemoteDrawing();
 
   // The final destination surface
   RefPtr<gfx::DrawTarget> mDrawTarget;
   // The current render target for drawing
   RefPtr<BasicCompositingRenderTarget> mRenderTarget;
--- a/gfx/layers/basic/BasicLayersImpl.cpp
+++ b/gfx/layers/basic/BasicLayersImpl.cpp
@@ -201,16 +201,78 @@ FillRectWithMask(DrawTarget* aDT,
                      mask.GetSurface(), &maskTransform);
     return;
   }
 
   FillRectWithMask(aDT, aRect, aSurface, aSamplingFilter, aOptions,
                    ExtendMode::CLAMP);
 }
 
+void
+FillPathWithMask(DrawTarget* aDT,
+                 const Path* aPath,
+                 const Rect& aClipRect,
+                 const Color& aColor,
+                 const DrawOptions& aOptions,
+                 SourceSurface* aMaskSource,
+                 const Matrix* aMaskTransform)
+{
+  if (aMaskSource && aMaskTransform) {
+    aDT->PushClipRect(aClipRect);
+    Matrix oldTransform = aDT->GetTransform();
+
+    aDT->SetTransform(*aMaskTransform);
+    aDT->MaskSurface(ColorPattern(aColor), aMaskSource, Point(), aOptions);
+    aDT->SetTransform(oldTransform);
+    aDT->PopClip();
+    return;
+  }
+
+  aDT->Fill(aPath, ColorPattern(aColor), aOptions);
+}
+
+void
+FillPathWithMask(DrawTarget* aDT,
+                 const Path* aPath,
+                 const Rect& aClipRect,
+                 SourceSurface* aSurface,
+                 SamplingFilter aSamplingFilter,
+                 const DrawOptions& aOptions,
+                 ExtendMode aExtendMode,
+                 SourceSurface* aMaskSource,
+                 const Matrix* aMaskTransform,
+                 const Matrix* aSurfaceTransform)
+{
+  if (aMaskSource && aMaskTransform) {
+    aDT->PushClipRect(aClipRect);
+    Matrix oldTransform = aDT->GetTransform();
+
+    Matrix inverseMask = *aMaskTransform;
+    inverseMask.Invert();
+
+    Matrix transform = oldTransform * inverseMask;
+    if (aSurfaceTransform) {
+      transform = (*aSurfaceTransform) * transform;
+    }
+
+    SurfacePattern source(aSurface, aExtendMode, transform, aSamplingFilter);
+
+    aDT->SetTransform(*aMaskTransform);
+    aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions);
+    aDT->SetTransform(oldTransform);
+    aDT->PopClip();
+    return;
+  }
+
+  aDT->Fill(aPath,
+            SurfacePattern(aSurface, aExtendMode,
+                           aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
+                           aSamplingFilter), aOptions);
+}
+
 BasicImplData*
 ToData(Layer* aLayer)
 {
   return static_cast<BasicImplData*>(aLayer->ImplData());
 }
 
 gfx::CompositionOp
 GetEffectiveOperator(Layer* aLayer)
--- a/gfx/layers/basic/BasicLayersImpl.h
+++ b/gfx/layers/basic/BasicLayersImpl.h
@@ -122,16 +122,36 @@ FillRectWithMask(gfx::DrawTarget* aDT,
 void
 FillRectWithMask(gfx::DrawTarget* aDT,
                  const gfx::Point& aDeviceOffset,
                  const gfx::Rect& aRect,
                  const gfx::Color& aColor,
                  const gfx::DrawOptions& aOptions,
                  Layer* aMaskLayer);
 
+void
+FillPathWithMask(gfx::DrawTarget* aDT,
+                 const gfx::Path* aPath,
+                 const gfx::Rect& aClipRect,
+                 const gfx::Color& aColor,
+                 const gfx::DrawOptions& aOptions,
+                 gfx::SourceSurface* aMaskSource = nullptr,
+                 const gfx::Matrix* aMaskTransform = nullptr);
+void
+FillPathWithMask(gfx::DrawTarget* aDT,
+                 const gfx::Path* aPath,
+                 const gfx::Rect& aClipRect,
+                 gfx::SourceSurface* aSurface,
+                 gfx::SamplingFilter aSamplingFilter,
+                 const gfx::DrawOptions& aOptions,
+                 gfx::ExtendMode aExtendMode,
+                 gfx::SourceSurface* aMaskSource,
+                 const gfx::Matrix* aMaskTransform,
+                 const gfx::Matrix* aSurfaceTransform);
+
 BasicImplData*
 ToData(Layer* aLayer);
 
 /**
  * Returns the operator to be used when blending and compositing this layer.
  * Currently there is no way to specify both a blending and a compositing
  * operator other than normal and source over respectively.
  *
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -424,19 +424,19 @@ RenderLayers(ContainerT* aContainer, Lay
       // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
       // and only fill in that area. However the layer bounds takes into account the base translation
       // for the painted layer whereas the checkerboard region does not. One does not simply
       // intersect areas in different coordinate spaces. So we do this a little more permissively
       // and only fill in the background when we know there is checkerboard, which in theory
       // should only occur transiently.
       EffectChain effectChain(layer);
       effectChain.mPrimaryEffect = new EffectSolidColor(color);
-      aManager->GetCompositor()->DrawQuad(gfx::Rect(layer->GetLayerBounds()), clipRect,
-                                          effectChain, layer->GetEffectiveOpacity(),
-                                          layer->GetEffectiveTransform());
+      aManager->GetCompositor()->DrawGeometry(gfx::Rect(layer->GetLayerBounds()), clipRect,
+                                              effectChain, layer->GetEffectiveOpacity(),
+                                              layer->GetEffectiveTransform(), Nothing());
     }
 
     if (layerToRender->HasLayerBeenComposited()) {
       // Composer2D will compose this layer so skip GPU composition
       // this time. The flag will be reset for the next composition phase
       // at the beginning of LayerManagerComposite::Rener().
       gfx::IntRect clearRect = layerToRender->GetClearRect();
       if (!clearRect.IsEmpty()) {
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -522,16 +522,17 @@ private:
   DECL_GFX_PREF(Once, "layers.tiles.edge-padding",             TileEdgePaddingEnabled, bool, true);
   DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled",          LayerTileFadeInEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.tiles.fade-in.duration-ms",      LayerTileFadeInDuration, uint32_t, 250);
   DECL_GFX_PREF(Live, "layers.transaction.warning-ms",         LayerTransactionWarning, uint32_t, 200);
   DECL_GFX_PREF(Once, "layers.uniformity-info",                UniformityInfo, bool, false);
   DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces",   UseImageOffscreenSurfaces, bool, true);
   DECL_GFX_PREF(Live, "layers.draw-mask-debug",                DrawMaskLayer, bool, false);
   DECL_GFX_PREF(Live, "layers.geometry.opengl.enabled",        OGLLayerGeometry, bool, false);
+  DECL_GFX_PREF(Live, "layers.geometry.basic.enabled",         BasicLayerGeometry, bool, false);
 
   DECL_GFX_PREF(Live, "layout.animation.prerender.partial", PartiallyPrerenderAnimatedContent, bool, false);
   DECL_GFX_PREF(Live, "layout.animation.prerender.viewport-ratio-limit-x", AnimationPrerenderViewportRatioLimitX, float, 1.125f);
   DECL_GFX_PREF(Live, "layout.animation.prerender.viewport-ratio-limit-y", AnimationPrerenderViewportRatioLimitY, float, 1.125f);
   DECL_GFX_PREF(Live, "layout.animation.prerender.absolute-limit-x", AnimationPrerenderAbsoluteLimitX, uint32_t, 4096);
   DECL_GFX_PREF(Live, "layout.animation.prerender.absolute-limit-y", AnimationPrerenderAbsoluteLimitY, uint32_t, 4096);
 
   DECL_GFX_PREF(Live, "layout.css.scroll-behavior.damping-ratio", ScrollBehaviorDampingRatio, float, 1.0f);
deleted file mode 100644
--- a/ipc/keystore/KeyStore.cpp
+++ /dev/null
@@ -1,986 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <fcntl.h>
-#include <limits.h>
-#include <pwd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#if defined(MOZ_WIDGET_GONK)
-#include <android/log.h>
-#define KEYSTORE_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
-#else
-#define KEYSTORE_LOG(args...)  printf(args);
-#endif
-
-#include "KeyStore.h"
-#include "jsfriendapi.h"
-#include "KeyStoreConnector.h"
-#include "MainThreadUtils.h" // For NS_IsMainThread.
-#include "nsICryptoHash.h"
-
-#include "plbase64.h"
-#include "certdb.h"
-#include "ScopedNSSTypes.h"
-
-using namespace mozilla::ipc;
-#if ANDROID_VERSION >= 18
-// After Android 4.3, it uses binder to access keystore instead of unix socket.
-#include <android/log.h>
-#include <binder/BinderService.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <security/keystore/include/keystore/IKeystoreService.h>
-#include <security/keystore/include/keystore/keystore.h>
-
-using namespace android;
-
-namespace android {
-// This class is used to make compiler happy.
-class BpKeystoreService : public BpInterface<IKeystoreService>
-{
-public:
-  BpKeystoreService(const sp<IBinder>& impl)
-    : BpInterface<IKeystoreService>(impl)
-  {
-  }
-
-  virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {return 0;}
-  virtual int32_t test() {return 0;}
-  virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return 0;}
-  virtual int32_t del(const String16& name, int uid) {return 0;}
-  virtual int32_t exist(const String16& name, int uid) {return 0;}
-  virtual int32_t saw(const String16& name, int uid, Vector<String16>* matches) {return 0;}
-  virtual int32_t reset() {return 0;}
-  virtual int32_t password(const String16& password) {return 0;}
-  virtual int32_t lock() {return 0;}
-  virtual int32_t unlock(const String16& password) {return 0;}
-  virtual int32_t zero() {return 0;}
-  virtual int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) {return 0;}
-  virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out, size_t* outLength) {return 0;}
-  virtual int32_t verify(const String16& name, const uint8_t* data, size_t dataLength, const uint8_t* signature, size_t signatureLength) {return 0;}
-  virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {return 0;}
-  virtual int32_t del_key(const String16& name, int uid) {return 0;}
-  virtual int32_t grant(const String16& name, int32_t granteeUid) {return 0;}
-  virtual int32_t ungrant(const String16& name, int32_t granteeUid) {return 0;}
-  virtual int64_t getmtime(const String16& name) {return 0;}
-  virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) {return 0;}
-  virtual int32_t clear_uid(int64_t uid) {return 0;}
-#if ANDROID_VERSION >= 21
-  virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return 0;}
-  virtual int32_t is_hardware_backed(const String16& keyType) {return 0;}
-  virtual int32_t reset_uid(int32_t uid) {return 0;}
-  virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {return 0;}
-  virtual int32_t password_uid(const String16& password, int32_t uid) {return 0;}
-#elif ANDROID_VERSION == 18
-  virtual int32_t generate(const String16& name, int uid, int32_t flags) {return 0;}
-  virtual int32_t is_hardware_backed() {return 0;}
-#else
-  virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return 0;}
-  virtual int32_t is_hardware_backed(const String16& keyType) {return 0;}
-#endif
-};
-
-IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
-
-// Here comes binder requests.
-status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-  switch(code) {
-    case TEST: {
-      CHECK_INTERFACE(IKeystoreService, data, reply);
-      reply->writeNoException();
-      reply->writeInt32(test());
-      return NO_ERROR;
-    } break;
-    case GET: {
-      CHECK_INTERFACE(IKeystoreService, data, reply);
-      String16 name = data.readString16();
-      String8 tmp(name);
-      uint8_t* data = NULL;
-      size_t dataLength = 0;
-      int32_t ret = get(name, &data, &dataLength);
-
-      reply->writeNoException();
-      if (ret == 1) {
-        reply->writeInt32(dataLength);
-        void* buf = reply->writeInplace(dataLength);
-        memcpy(buf, data, dataLength);
-        free(data);
-      } else {
-        reply->writeInt32(-1);
-      }
-      return NO_ERROR;
-    } break;
-    case GET_PUBKEY: {
-      CHECK_INTERFACE(IKeystoreService, data, reply);
-      String16 name = data.readString16();
-      uint8_t* data = nullptr;
-      size_t dataLength = 0;
-      int32_t ret = get_pubkey(name, &data, &dataLength);
-
-      reply->writeNoException();
-      if (dataLength > 0 && data != nullptr) {
-        reply->writeInt32(dataLength);
-        void* buf = reply->writeInplace(dataLength);
-        memcpy(buf, data, dataLength);
-        free(data);
-      } else {
-        reply->writeInt32(-1);
-      }
-      reply->writeInt32(ret);
-      return NO_ERROR;
-    } break;
-    case SIGN: {
-      CHECK_INTERFACE(IKeystoreService, data, reply);
-      String16 name = data.readString16();
-      ssize_t signDataSize = data.readInt32();
-      const uint8_t *signData = nullptr;
-      if (signDataSize >= 0 && (size_t)signDataSize <= data.dataAvail()) {
-        signData = (const uint8_t *)data.readInplace(signDataSize);
-      }
-
-      uint8_t *signResult = nullptr;
-      size_t signResultSize;
-      int32_t ret = sign(name, signData, (size_t)signDataSize, &signResult,
-                         &signResultSize);
-
-      reply->writeNoException();
-      if (signResultSize > 0 && signResult != nullptr) {
-        reply->writeInt32(signResultSize);
-        void* buf = reply->writeInplace(signResultSize);
-        memcpy(buf, signResult, signResultSize);
-        free(signResult);
-      } else {
-        reply->writeInt32(-1);
-      }
-      reply->writeInt32(ret);
-      return NO_ERROR;
-    } break;
-    default:
-      return NO_ERROR;
-  }
-}
-
-// Provide service for binder.
-class KeyStoreService : public BnKeystoreService
-                      , public nsNSSShutDownObject
-{
-public:
-  int32_t test() {
-    uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!mozilla::ipc::checkPermission(callingUid)) {
-      return ::PERMISSION_DENIED;
-    }
-
-    return ::NO_ERROR;
-  }
-
-  int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
-    nsNSSShutDownPreventionLock locker;
-    if (isAlreadyShutDown()) {
-      return ::SYSTEM_ERROR;
-    }
-
-    uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!mozilla::ipc::checkPermission(callingUid)) {
-      return ::PERMISSION_DENIED;
-    }
-
-    String8 certName(name);
-    if (!strncmp(certName.string(), "WIFI_USERKEY_", 13)) {
-      return getPrivateKey(certName.string(), (const uint8_t**)item, itemLength);
-    }
-
-    return getCertificate(certName.string(), (const uint8_t**)item, itemLength);
-  }
-
-  int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
-  int32_t del(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
-  int32_t exist(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
-  int32_t saw(const String16& name, int uid, Vector<String16>* matches) {return ::UNDEFINED_ACTION;}
-  int32_t reset() {return ::UNDEFINED_ACTION;}
-  int32_t password(const String16& password) {return ::UNDEFINED_ACTION;}
-  int32_t lock() {return ::UNDEFINED_ACTION;}
-  int32_t unlock(const String16& password) {return ::UNDEFINED_ACTION;}
-  int32_t zero() {return ::UNDEFINED_ACTION;}
-  int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
-  int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out, size_t* outLength)
-  {
-    nsNSSShutDownPreventionLock locker;
-    if (isAlreadyShutDown()) {
-      return ::SYSTEM_ERROR;
-    }
-
-    uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!mozilla::ipc::checkPermission(callingUid)) {
-      return ::PERMISSION_DENIED;
-    }
-
-    if (data == nullptr) {
-      return ::SYSTEM_ERROR;
-    }
-
-    String8 keyName(name);
-    if (!strncmp(keyName.string(), "WIFI_USERKEY_", 13)) {
-      return signData(keyName.string(), data, length, out, outLength);
-    }
-
-    return ::UNDEFINED_ACTION;
-  }
-
-  int32_t verify(const String16& name, const uint8_t* data, size_t dataLength, const uint8_t* signature, size_t signatureLength) {return ::UNDEFINED_ACTION;}
-  int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
-    nsNSSShutDownPreventionLock locker;
-    if (isAlreadyShutDown()) {
-      return ::SYSTEM_ERROR;
-    }
-
-    uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!mozilla::ipc::checkPermission(callingUid)) {
-      return ::PERMISSION_DENIED;
-    }
-
-    String8 keyName(name);
-    if (!strncmp(keyName.string(), "WIFI_USERKEY_", 13)) {
-      return getPublicKey(keyName.string(), (const uint8_t**)pubkey, pubkeyLength);
-    }
-
-    return ::UNDEFINED_ACTION;
-  }
-
-  int32_t del_key(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
-  int32_t grant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;}
-  int32_t ungrant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;}
-  int64_t getmtime(const String16& name) {return ::UNDEFINED_ACTION;}
-  int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) {return ::UNDEFINED_ACTION;}
-  int32_t clear_uid(int64_t uid) {return ::UNDEFINED_ACTION;}
-#if ANDROID_VERSION >= 21
-  virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return ::UNDEFINED_ACTION;}
-  virtual int32_t is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;}
-  virtual int32_t reset_uid(int32_t uid) {return ::UNDEFINED_ACTION;;}
-  virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {return ::UNDEFINED_ACTION;}
-  virtual int32_t password_uid(const String16& password, int32_t uid) {return ::UNDEFINED_ACTION;}
-#elif ANDROID_VERSION == 18
-  virtual int32_t generate(const String16& name, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
-  virtual int32_t is_hardware_backed() {return ::UNDEFINED_ACTION;}
-#else
-  virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return ::UNDEFINED_ACTION;}
-  virtual int32_t is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;}
-#endif
-
-protected:
-  virtual void virtualDestroyNSSReference() {}
-
-private:
-  ~KeyStoreService() {
-    nsNSSShutDownPreventionLock locker;
-    if (isAlreadyShutDown()) {
-      return;
-    }
-    shutdown(ShutdownCalledFrom::Object);
-  }
-};
-
-} // namespace android
-
-void startKeyStoreService()
-{
-  android::sp<android::IServiceManager> sm = android::defaultServiceManager();
-  android::sp<android::KeyStoreService> keyStoreService = new android::KeyStoreService();
-  sm->addService(String16("android.security.keystore"), keyStoreService);
-}
-#else
-void startKeyStoreService() { return; }
-#endif
-
-static const char *CA_BEGIN = "-----BEGIN ",
-                  *CA_END   = "-----END ",
-                  *CA_TAILER = "-----\n";
-
-namespace mozilla {
-namespace ipc {
-
-static const char* KEYSTORE_ALLOWED_USERS[] = {
-  "root",
-  "wifi",
-  NULL
-};
-static const char* KEYSTORE_ALLOWED_PREFIXES[] = {
-  "WIFI_SERVERCERT_",
-  "WIFI_USERCERT_",
-  "WIFI_USERKEY_",
-  NULL
-};
-
-// Transform base64 certification data into DER format
-void
-FormatCaData(const char *aCaData, int aCaDataLength,
-             const char *aName, const uint8_t **aFormatData,
-             size_t *aFormatDataLength)
-{
-  size_t bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
-                   strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE
-                   + 2;
-  char *buf = (char *)malloc(bufSize);
-  if (!buf) {
-    *aFormatData = nullptr;
-    return;
-  }
-
-  *aFormatDataLength = bufSize;
-  *aFormatData = (const uint8_t *)buf;
-
-  char *ptr = buf;
-  size_t len;
-
-  // Create DER header.
-  len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
-  ptr += len;
-  bufSize -= len;
-
-  // Split base64 data in lines.
-  int copySize;
-  while (aCaDataLength > 0) {
-    copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
-
-    memcpy(ptr, aCaData, copySize);
-    ptr += copySize;
-    aCaData += copySize;
-    aCaDataLength -= copySize;
-    bufSize -= copySize;
-
-    *ptr = '\n';
-    ptr++;
-    bufSize--;
-  }
-
-  // Create DEA tailer.
-  snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
-}
-
-ResponseCode
-getCertificate(const char *aCertName, const uint8_t **aCertData,
-               size_t *aCertDataLength)
-{
-  // certificate name prefix check.
-  if (!aCertName) {
-    return KEY_NOT_FOUND;
-  }
-
-  const char **prefix = KEYSTORE_ALLOWED_PREFIXES;
-  for (; *prefix; prefix++ ) {
-    if (!strncmp(*prefix, aCertName, strlen(*prefix))) {
-      break;
-    }
-  }
-  if (!(*prefix)) {
-    return KEY_NOT_FOUND;
-  }
-
-  // Get cert from NSS by name
-  ScopedCERTCertificate cert(CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
-                                                     aCertName));
-
-  if (!cert) {
-    return KEY_NOT_FOUND;
-  }
-
-  char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
-                                  cert->derCert.len, nullptr);
-  if (!certDER) {
-    return SYSTEM_ERROR;
-  }
-
-  FormatCaData(certDER, strlen(certDER), "CERTIFICATE", aCertData,
-               aCertDataLength);
-  PL_strfree(certDER);
-
-  if (!(*aCertData)) {
-    return SYSTEM_ERROR;
-  }
-
-  return SUCCESS;
-}
-
-ResponseCode getPrivateKey(const char *aKeyName, const uint8_t **aKeyData,
-                           size_t *aKeyDataLength)
-{
-  *aKeyData = nullptr;
-  // Get corresponding user certificate nickname
-  char userCertName[128] = {0};
-  snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13);
-
-  // Get private key from user certificate.
-  ScopedCERTCertificate userCert(
-    CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName));
-  if (!userCert) {
-    return KEY_NOT_FOUND;
-  }
-
-  ScopedSECKEYPrivateKey privateKey(
-    PK11_FindKeyByAnyCert(userCert.get(), nullptr));
-  if (!privateKey) {
-    return KEY_NOT_FOUND;
-  }
-
-  // Export private key in PKCS#12 encrypted format, no password.
-  unsigned char pwstr[] = {0, 0};
-  SECItem password = {siBuffer, pwstr, sizeof(pwstr)};
-  ScopedSECKEYEncryptedPrivateKeyInfo encryptedPrivateKey(
-    PK11_ExportEncryptedPrivKeyInfo(privateKey->pkcs11Slot,
-      SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4, &password, privateKey, 1,
-      privateKey->wincx));
-
-  if (!encryptedPrivateKey) {
-    return KEY_NOT_FOUND;
-  }
-
-  // Decrypt into RSA private key.
-  //
-  // Generate key for PKCS#12 encryption, we use SHA1 with 1 iteration, as the
-  // parameters used in PK11_ExportEncryptedPrivKeyInfo() above.
-  // see: PKCS#12 v1.0, B.2.
-  //
-  uint8_t DSP[192] = {0};
-  memset(DSP, 0x01, 64);        // Diversifier part, ID = 1 for decryption.
-  memset(DSP + 128, 0x00, 64);  // Password part, no password.
-
-  uint8_t *S = &DSP[64];        // Salt part.
-  uint8_t *salt = encryptedPrivateKey->algorithm.parameters.data + 4;
-  int saltLength = (int)encryptedPrivateKey->algorithm.parameters.data[3];
-  if (saltLength <= 0) {
-    return SYSTEM_ERROR;
-  }
-  for (int i = 0; i < 64; i++) {
-    S[i] = salt[i % saltLength];
-  }
-
-  // Generate key by SHA-1
-  nsresult rv;
-  nsCOMPtr<nsICryptoHash> hash =
-    do_CreateInstance("@mozilla.org/security/hash;1", &rv);
-  if (NS_FAILED(rv)) {
-    return SYSTEM_ERROR;
-  }
-
-  rv = hash->Init(nsICryptoHash::SHA1);
-  if (NS_FAILED(rv)) {
-    return SYSTEM_ERROR;
-  }
-
-  rv = hash->Update(DSP, sizeof(DSP));
-  if (NS_FAILED(rv)) {
-    return SYSTEM_ERROR;
-  }
-
-  nsCString hashResult;
-  rv = hash->Finish(false, hashResult);
-  if (NS_FAILED(rv)) {
-    return SYSTEM_ERROR;
-  }
-
-  // First 40-bit as key for RC4.
-  uint8_t key[5];
-  memcpy(key, hashResult.get(), sizeof(key));
-
-  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-  if (!slot) {
-    return SYSTEM_ERROR;
-  }
-
-  SECItem keyItem = {siBuffer, key, sizeof(key)};
-  ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, CKM_RC4, PK11_OriginUnwrap,
-                                            CKA_DECRYPT, &keyItem, nullptr));
-  if (!symKey) {
-    return SYSTEM_ERROR;
-  }
-
-  // Get expected decrypted data size then allocate memory.
-  uint8_t *encryptedData = (uint8_t *)encryptedPrivateKey->encryptedData.data;
-  unsigned int encryptedDataLen = encryptedPrivateKey->encryptedData.len;
-  unsigned int decryptedDataLen = encryptedDataLen;
-  SECStatus srv = PK11_Decrypt(symKey, CKM_RC4, &keyItem, nullptr,
-                               &decryptedDataLen, encryptedDataLen,
-                               encryptedData, encryptedDataLen);
-  if (srv != SECSuccess) {
-    return SYSTEM_ERROR;
-  }
-
-  ScopedSECItem decryptedData(::SECITEM_AllocItem(nullptr, nullptr,
-                                                  decryptedDataLen));
-  if (!decryptedData) {
-    return SYSTEM_ERROR;
-  }
-
-  // Decrypt by RC4.
-  srv = PK11_Decrypt(symKey, CKM_RC4, &keyItem, decryptedData->data,
-                     &decryptedDataLen, decryptedData->len, encryptedData,
-                     encryptedDataLen);
-  if (srv != SECSuccess) {
-    return SYSTEM_ERROR;
-  }
-
-  // Export key in PEM format.
-  char *keyPEM = PL_Base64Encode((const char *)decryptedData->data,
-                                 decryptedDataLen, nullptr);
-
-  if (!keyPEM) {
-    return SYSTEM_ERROR;
-  }
-
-  FormatCaData(keyPEM, strlen(keyPEM), "PRIVATE KEY", aKeyData, aKeyDataLength);
-  PL_strfree(keyPEM);
-
-  if (!(*aKeyData)) {
-    return SYSTEM_ERROR;
-  }
-
-  return SUCCESS;
-}
-
-ResponseCode getPublicKey(const char *aKeyName, const uint8_t **aKeyData,
-                          size_t *aKeyDataLength)
-{
-  *aKeyData = nullptr;
-
-  // Get corresponding user certificate nickname
-  char userCertName[128] = {0};
-  snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13);
-
-  // Get public key from user certificate.
-  ScopedCERTCertificate userCert(
-    CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName));
-  if (!userCert) {
-    return KEY_NOT_FOUND;
-  }
-
-  // Get public key.
-  ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(userCert));
-  if (!publicKey) {
-    return KEY_NOT_FOUND;
-  }
-
-  ScopedSECItem keyItem(PK11_DEREncodePublicKey(publicKey));
-  if (!keyItem) {
-    return KEY_NOT_FOUND;
-  }
-
-  size_t bufSize = keyItem->len;
-  char *buf = (char *)malloc(bufSize);
-  if (!buf) {
-    return SYSTEM_ERROR;
-  }
-
-  memcpy(buf, keyItem->data, bufSize);
-  *aKeyData = (const uint8_t *)buf;
-  *aKeyDataLength = bufSize;
-
-  return SUCCESS;
-}
-
-ResponseCode signData(const char *aKeyName, const uint8_t *data, size_t length,
-                      uint8_t **out, size_t *outLength)
-{
-  *out = nullptr;
-  // Get corresponding user certificate nickname
-  char userCertName[128] = {0};
-  snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13);
-
-  // Get private key from user certificate.
-  ScopedCERTCertificate userCert(
-    CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName));
-  if (!userCert) {
-    return KEY_NOT_FOUND;
-  }
-
-  ScopedSECKEYPrivateKey privateKey(
-    PK11_FindKeyByAnyCert(userCert.get(), nullptr));
-  if (!privateKey) {
-    return KEY_NOT_FOUND;
-  }
-
-  //
-  // Find hash data from incoming data.
-  //
-  // Incoming data might be padded by PKCS-1 format:
-  // 00 01 FF FF ... FF 00 || Hash of length 36
-  // If the padding part exists, we have to ignore them.
-  //
-  uint8_t *hash = (uint8_t *)data;
-  const size_t HASH_LENGTH = 36;
-  if (length < HASH_LENGTH) {
-    return VALUE_CORRUPTED;
-  }
-  if (hash[0] == 0x00 && hash[1] == 0x01 && hash[2] == 0xFF && hash[3] == 0xFF) {
-    hash += 4;
-    while (*hash == 0xFF) {
-      if (hash + HASH_LENGTH > data + length) {
-        return VALUE_CORRUPTED;
-      }
-      hash++;
-    }
-    if (*hash != 0x00) {
-      return VALUE_CORRUPTED;
-    }
-    hash++;
-  }
-  if (hash + HASH_LENGTH != data + length) {
-    return VALUE_CORRUPTED;
-  }
-  SECItem hashItem = {siBuffer, hash, HASH_LENGTH};
-
-  // Sign hash.
-  ScopedSECItem signItem(::SECITEM_AllocItem(nullptr, nullptr,
-                                             PK11_SignatureLen(privateKey)));
-  if (!signItem) {
-    return SYSTEM_ERROR;
-  }
-
-  SECStatus srv;
-  srv = PK11_Sign(privateKey, signItem.get(), &hashItem);
-  if (srv != SECSuccess) {
-    return SYSTEM_ERROR;
-  }
-
-  uint8_t *buf = (uint8_t *)malloc(signItem->len);
-  if (!buf) {
-    return SYSTEM_ERROR;
-  }
-
-  memcpy(buf, signItem->data, signItem->len);
-  *out = buf;
-  *outLength = signItem->len;
-
-  return SUCCESS;
-}
-
-bool
-checkPermission(uid_t uid)
-{
-  struct passwd *userInfo = getpwuid(uid);
-  for (const char **user = KEYSTORE_ALLOWED_USERS; *user; user++ ) {
-    if (!strcmp(*user, userInfo->pw_name)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-//
-// KeyStore
-//
-
-KeyStore::KeyStore()
-: mShutdown(false)
-{
-  MOZ_COUNT_CTOR(KeyStore);
-  ::startKeyStoreService();
-  Listen();
-}
-
-KeyStore::~KeyStore()
-{
-  nsNSSShutDownPreventionLock locker;
-  MOZ_COUNT_DTOR(KeyStore);
-
-  if (isAlreadyShutDown()) {
-    return;
-  }
-
-  shutdown(ShutdownCalledFrom::Object);
-
-  MOZ_ASSERT(!mListenSocket);
-  MOZ_ASSERT(!mStreamSocket);
-}
-
-void
-KeyStore::Shutdown()
-{
-  // We set mShutdown first, so that |OnDisconnect| won't try to reconnect.
-  mShutdown = true;
-
-  if (mStreamSocket) {
-    mStreamSocket->Close();
-    mStreamSocket = nullptr;
-  }
-  if (mListenSocket) {
-    mListenSocket->Close();
-    mListenSocket = nullptr;
-  }
-}
-
-void
-KeyStore::Listen()
-{
-  // We only allocate one |StreamSocket|, but re-use it for every connection.
-  if (mStreamSocket) {
-    mStreamSocket->Close();
-  } else {
-    mStreamSocket = new StreamSocket(this, STREAM_SOCKET);
-  }
-
-  if (!mListenSocket) {
-    // We only ever allocate one |ListenSocket|...
-    mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
-    mListenSocket->Listen(new KeyStoreConnector(KEYSTORE_ALLOWED_USERS),
-                          mStreamSocket);
-  } else {
-    // ... but keep it open.
-    mListenSocket->Listen(mStreamSocket);
-  }
-
-  ResetHandlerInfo();
-}
-
-void
-KeyStore::ResetHandlerInfo()
-{
-  mHandlerInfo.state = STATE_IDLE;
-  mHandlerInfo.command = 0;
-  mHandlerInfo.paramCount = 0;
-  mHandlerInfo.commandPattern = nullptr;
-  for (int i = 0; i < MAX_PARAM; i++) {
-    mHandlerInfo.param[i].length = 0;
-    memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
-  }
-}
-
-bool
-KeyStore::CheckSize(UnixSocketBuffer *aMessage, size_t aExpectSize)
-{
-  return (aMessage->GetSize() >= aExpectSize);
-}
-
-ResponseCode
-KeyStore::ReadCommand(UnixSocketBuffer *aMessage)
-{
-  if (mHandlerInfo.state != STATE_IDLE) {
-    NS_WARNING("Wrong state in ReadCommand()!");
-    return SYSTEM_ERROR;
-  }
-
-  if (!CheckSize(aMessage, 1)) {
-    NS_WARNING("Data size error in ReadCommand()!");
-    return PROTOCOL_ERROR;
-  }
-
-  mHandlerInfo.command = *aMessage->GetData();
-  aMessage->Consume(1);
-
-  // Find corrsponding command pattern
-  const struct ProtocolCommand *command = commands;
-  while (command->command && command->command != mHandlerInfo.command) {
-    command++;
-  }
-
-  if (!command->command) {
-    NS_WARNING("Unsupported command!");
-    return PROTOCOL_ERROR;
-  }
-
-  // Get command pattern.
-  mHandlerInfo.commandPattern = command;
-  if (command->paramNum) {
-    // Read command parameter if needed.
-    mHandlerInfo.state = STATE_READ_PARAM_LEN;
-  } else {
-    mHandlerInfo.state = STATE_PROCESSING;
-  }
-
-  return SUCCESS;
-}
-
-ResponseCode
-KeyStore::ReadLength(UnixSocketBuffer *aMessage)
-{
-  if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
-    NS_WARNING("Wrong state in ReadLength()!");
-    return SYSTEM_ERROR;
-  }
-
-  if (!CheckSize(aMessage, 2)) {
-    NS_WARNING("Data size error in ReadLength()!");
-    return PROTOCOL_ERROR;
-  }
-
-  // Read length of command parameter.
-  // FIXME: Depends on endianess and (sizeof(unsigned short) == 2)
-  unsigned short dataLength;
-  memcpy(&dataLength, aMessage->GetData(), 2);
-  aMessage->Consume(2);
-  mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
-
-  mHandlerInfo.state = STATE_READ_PARAM_DATA;
-
-  return SUCCESS;
-}
-
-ResponseCode
-KeyStore::ReadData(UnixSocketBuffer *aMessage)
-{
-  if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
-    NS_WARNING("Wrong state in ReadData()!");
-    return SYSTEM_ERROR;
-  }
-
-  if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
-    NS_WARNING("Data size error in ReadData()!");
-    return PROTOCOL_ERROR;
-  }
-
-  // Read command parameter.
-  memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
-         aMessage->GetData(),
-         mHandlerInfo.param[mHandlerInfo.paramCount].length);
-  aMessage->Consume(mHandlerInfo.param[mHandlerInfo.paramCount].length);
-  mHandlerInfo.paramCount++;
-
-  if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
-    mHandlerInfo.state = STATE_PROCESSING;
-  } else {
-    mHandlerInfo.state = STATE_READ_PARAM_LEN;
-  }
-
-  return SUCCESS;
-}
-
-// Status response
-void
-KeyStore::SendResponse(ResponseCode aResponse)
-{
-  MOZ_ASSERT(mStreamSocket);
-
-  if (aResponse == NO_RESPONSE)
-    return;
-
-  uint8_t response = (uint8_t)aResponse;
-  UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
-  mStreamSocket->SendSocketData(data);
-}
-
-// Data response
-void
-KeyStore::SendData(const uint8_t *aData, int aLength)
-{
-  MOZ_ASSERT(mStreamSocket);
-
-  unsigned short dataLength = htons(aLength);
-
-  UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
-  mStreamSocket->SendSocketData(length);
-
-  UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
-  mStreamSocket->SendSocketData(data);
-}
-
-// |StreamSocketConsumer|, |ListenSocketConsumer|
-
-void
-KeyStore::ReceiveSocketData(int aIndex, UniquePtr<UnixSocketBuffer>& aMessage)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Handle request.
-  ResponseCode result = SUCCESS;
-  while (aMessage->GetSize() ||
-         mHandlerInfo.state == STATE_PROCESSING) {
-    switch (mHandlerInfo.state) {
-      case STATE_IDLE:
-        result = ReadCommand(aMessage.get());
-        break;
-      case STATE_READ_PARAM_LEN:
-        result = ReadLength(aMessage.get());
-        break;
-      case STATE_READ_PARAM_DATA:
-        result = ReadData(aMessage.get());
-        break;
-      case STATE_PROCESSING:
-        if (mHandlerInfo.command == 'g') {
-          result = SYSTEM_ERROR;
-
-          nsNSSShutDownPreventionLock locker;
-          if (isAlreadyShutDown()) {
-            break;
-          }
-
-          // Get CA
-          const uint8_t *data;
-          size_t dataLength;
-          const char *name = (const char *)mHandlerInfo.param[0].data;
-
-          if (!strncmp(name, "WIFI_USERKEY_", 13)) {
-            result = getPrivateKey(name, &data, &dataLength);
-          } else {
-            result = getCertificate(name, &data, &dataLength);
-          }
-          if (result != SUCCESS) {
-            break;
-          }
-
-          SendResponse(SUCCESS);
-          SendData(data, (int)dataLength);
-
-          free((void *)data);
-        }
-
-        ResetHandlerInfo();
-        break;
-    }
-
-    if (result != SUCCESS) {
-      SendResponse(result);
-      ResetHandlerInfo();
-      return;
-    }
-  }
-}
-
-void
-KeyStore::OnConnectSuccess(int aIndex)
-{
-  if (aIndex == STREAM_SOCKET) {
-    mShutdown = false;
-  }
-}
-
-void
-KeyStore::OnConnectError(int aIndex)
-{
-  if (mShutdown) {
-    return;
-  }
-
-  if (aIndex == STREAM_SOCKET) {
-    // Stream socket error; start listening again
-    Listen();
-  }
-}
-
-void
-KeyStore::OnDisconnect(int aIndex)
-{
-  if (mShutdown) {
-    return;
-  }
-
-  switch (aIndex) {
-    case LISTEN_SOCKET:
-      // Listen socket disconnected; start anew.
-      mListenSocket = nullptr;
-      Listen();
-      break;
-    case STREAM_SOCKET:
-      // Stream socket disconnected; start listening again.
-      Listen();
-      break;
-  }
-}
-
-} // namespace ipc
-} // namespace mozilla
deleted file mode 100644
--- a/ipc/keystore/KeyStore.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_ipc_KeyStore_h
-#define mozilla_ipc_KeyStore_h 1
-
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "cert.h"
-#include "mozilla/ipc/ListenSocket.h"
-#include "mozilla/ipc/ListenSocketConsumer.h"
-#include "mozilla/ipc/StreamSocket.h"
-#include "mozilla/ipc/StreamSocketConsumer.h"
-#include "nsNSSShutDown.h"
-
-namespace mozilla {
-namespace ipc {
-
-enum ResponseCode {
-  SUCCESS           =  1,
-  LOCKED            =  2,
-  UNINITIALIZED     =  3,
-  SYSTEM_ERROR      =  4,
-  PROTOCOL_ERROR    =  5,
-  PERMISSION_DENIED =  6,
-  KEY_NOT_FOUND     =  7,
-  VALUE_CORRUPTED   =  8,
-  UNDEFINED_ACTION  =  9,
-  WRONG_PASSWORD_0  = 10,
-  WRONG_PASSWORD_1  = 11,
-  WRONG_PASSWORD_2  = 12,
-  WRONG_PASSWORD_3  = 13, // MAX_RETRY = 4
-  NO_RESPONSE
-};
-
-void FormatCaData(const uint8_t *aCaData, int aCaDataLength,
-                  const char *aName, const uint8_t **aFormatData,
-                  size_t *aFormatDataLength);
-
-ResponseCode getCertificate(const char *aCertName, const uint8_t **aCertData,
-                            size_t *aCertDataLength);
-ResponseCode getPrivateKey(const char *aKeyName, const uint8_t **aKeyData,
-                           size_t *aKeyDataLength);
-ResponseCode getPublicKey(const char *aKeyName, const uint8_t **aKeyData,
-                          size_t *aKeyDataLength);
-ResponseCode signData(const char *aKeyName, const uint8_t *data, size_t length,
-                      uint8_t **out, size_t *outLength);
-
-bool checkPermission(uid_t uid);
-
-static const int MAX_PARAM = 2;
-static const int KEY_SIZE = ((NAME_MAX - 15) / 2);
-static const int VALUE_SIZE = 32768;
-static const int PASSWORD_SIZE = VALUE_SIZE;
-
-static const int CA_LINE_SIZE = 64;
-
-struct ProtocolCommand {
-  int8_t  command;
-  int     paramNum;
-};
-
-static const struct ProtocolCommand commands[] = {
-  {'g', 1}, // Get CA, command "g CERT_NAME"
-  { 0,  0}
-};
-
-struct ProtocolParam{
-  uint    length;
-  int8_t  data[VALUE_SIZE];
-};
-
-typedef enum {
-  STATE_IDLE,
-  STATE_READ_PARAM_LEN,
-  STATE_READ_PARAM_DATA,
-  STATE_PROCESSING
-} ProtocolHandlerState;
-
-class KeyStore final
-  : public StreamSocketConsumer
-  , public ListenSocketConsumer
-  , public nsNSSShutDownObject
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KeyStore)
-
-  KeyStore();
-
-  void Shutdown();
-
-protected:
-  virtual void virtualDestroyNSSReference() {}
-
-private:
-  enum SocketType {
-    LISTEN_SOCKET,
-    STREAM_SOCKET
-  };
-
-  ~KeyStore();
-
-  struct {
-    ProtocolHandlerState          state;
-    uint8_t                       command;
-    struct ProtocolParam          param[MAX_PARAM];
-    int                           paramCount;
-    const struct ProtocolCommand  *commandPattern;
-  } mHandlerInfo;
-  void ResetHandlerInfo();
-  void Listen();
-
-  bool CheckSize(UnixSocketBuffer *aMessage, size_t aExpectSize);
-  ResponseCode ReadCommand(UnixSocketBuffer *aMessage);
-  ResponseCode ReadLength(UnixSocketBuffer *aMessage);
-  ResponseCode ReadData(UnixSocketBuffer *aMessage);
-  void SendResponse(ResponseCode response);
-  void SendData(const uint8_t *data, int length);
-
-  // Methods for |StreamSocketConsumer|
-  //
-
-  void ReceiveSocketData(int aIndex,
-                         UniquePtr<UnixSocketBuffer>& aMessage) override;
-  void OnConnectSuccess(int aIndex) override;
-  void OnConnectError(int aIndex) override;
-  void OnDisconnect(int aIndex) override;
-
-  bool mShutdown;
-
-  RefPtr<ListenSocket> mListenSocket;
-  RefPtr<StreamSocket> mStreamSocket;
-};
-
-} // namespace ipc
-} // namespace mozilla
-
-#endif // mozilla_ipc_KeyStore_h
deleted file mode 100644
--- a/ipc/keystore/KeyStoreConnector.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "KeyStoreConnector.h"
-#include <fcntl.h>
-#include <pwd.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
-#include "nsThreadUtils.h" // For NS_IsMainThread.
-
-#ifdef MOZ_WIDGET_GONK
-#include <android/log.h>
-#define KEYSTORE_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
-#else
-#define KEYSTORE_LOG(args...)  printf(args);
-#endif
-
-namespace mozilla {
-namespace ipc {
-
-static const char KEYSTORE_SOCKET_PATH[] = "/dev/socket/keystore";
-
-KeyStoreConnector::KeyStoreConnector(const char** const aAllowedUsers)
-  : mAllowedUsers(aAllowedUsers)
-{
-  MOZ_COUNT_CTOR_INHERITED(KeyStoreConnector, UnixSocketConnector);
-}
-
-KeyStoreConnector::~KeyStoreConnector()
-{
-  MOZ_COUNT_DTOR_INHERITED(KeyStoreConnector, UnixSocketConnector);
-}
-
-nsresult
-KeyStoreConnector::CreateSocket(int& aFd) const
-{
-  unlink(KEYSTORE_SOCKET_PATH);
-
-  aFd = socket(AF_LOCAL, SOCK_STREAM, 0);
-  if (aFd < 0) {
-    KEYSTORE_LOG("Could not open KeyStore socket!");
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-KeyStoreConnector::SetSocketFlags(int aFd) const
-{
-  static const int sReuseAddress = 1;
-
-  // Set close-on-exec bit.
-  int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFD));
-  if (flags < 0) {
-    return NS_ERROR_FAILURE;
-  }
-  flags |= FD_CLOEXEC;
-  int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFD, flags));
-  if (res < 0) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Set non-blocking status flag.
-  flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
-  if (flags < 0) {
-    return NS_ERROR_FAILURE;
-  }
-  flags |= O_NONBLOCK;
-  res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags));
-  if (res < 0) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Set socket addr to be reused even if kernel is still waiting to close.
-  res = setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &sReuseAddress,
-                   sizeof(sReuseAddress));
-  if (res < 0) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-KeyStoreConnector::CheckPermission(int aFd) const
-{
-  struct ucred userCred;
-  socklen_t len = sizeof(userCred);
-
-  if (getsockopt(aFd, SOL_SOCKET, SO_PEERCRED, &userCred, &len)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  const struct passwd* userInfo = getpwuid(userCred.uid);
-  if (!userInfo) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (!mAllowedUsers) {
-    return NS_ERROR_FAILURE;
-  }
-
-  for (const char** user = mAllowedUsers; *user; ++user) {
-    if (!strcmp(*user, userInfo->pw_name)) {
-      return NS_OK;
-    }
-  }
-
-  return NS_ERROR_FAILURE;
-}
-
-nsresult
-KeyStoreConnector::CreateAddress(struct sockaddr& aAddress,
-                                 socklen_t& aAddressLength) const
-{
-  struct sockaddr_un* address =
-    reinterpret_cast<struct sockaddr_un*>(&aAddress);
-
-  size_t namesiz = strlen(KEYSTORE_SOCKET_PATH) + 1; // include trailing '\0'
-
-  if (namesiz > sizeof(address->sun_path)) {
-      KEYSTORE_LOG("Address too long for socket struct!");
-      return NS_ERROR_FAILURE;
-  }
-
-  address->sun_family = AF_UNIX;
-  memcpy(address->sun_path, KEYSTORE_SOCKET_PATH, namesiz);
-
-  aAddressLength = offsetof(struct sockaddr_un, sun_path) + namesiz;
-
-  return NS_OK;
-}
-
-// |UnixSocketConnector|
-
-nsresult
-KeyStoreConnector::ConvertAddressToString(const struct sockaddr& aAddress,
-                                          socklen_t aAddressLength,
-                                          nsACString& aAddressString)
-{
-  MOZ_ASSERT(aAddress.sa_family == AF_UNIX);
-
-  const struct sockaddr_un* un =
-    reinterpret_cast<const struct sockaddr_un*>(&aAddress);
-
-  size_t len = aAddressLength - offsetof(struct sockaddr_un, sun_path);
-
-  aAddressString.Assign(un->sun_path, len);
-
-  return NS_OK;
-}
-
-nsresult
-KeyStoreConnector::CreateListenSocket(struct sockaddr* aAddress,
-                                      socklen_t* aAddressLength,
-                                      int& aListenFd)
-{
-  ScopedClose fd;
-
-  nsresult rv = CreateSocket(fd.rwget());
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  rv = SetSocketFlags(fd);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  if (aAddress && aAddressLength) {
-    rv = CreateAddress(*aAddress, *aAddressLength);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-
-  // Allow access for wpa_supplicant (different user, different group)
-  //
-  // TODO: Improve this by setting specific user/group for
-  //       wpa_supplicant by calling |fchmod| and |fchown|.
-  //
-  chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|
-                              S_IRGRP|S_IWGRP|
-                              S_IROTH|S_IWOTH);
-
-  aListenFd = fd.forget();
-
-  return NS_OK;
-}
-
-nsresult
-KeyStoreConnector::AcceptStreamSocket(int aListenFd,
-                                      struct sockaddr* aAddress,
-                                      socklen_t* aAddressLength,
-                                      int& aStreamFd)
-{
-  ScopedClose fd(
-    TEMP_FAILURE_RETRY(accept(aListenFd, aAddress, aAddressLength)));
-  if (fd < 0) {
-    NS_WARNING("Cannot accept file descriptor!");
-    return NS_ERROR_FAILURE;
-  }
-  nsresult rv = SetSocketFlags(fd);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  rv = CheckPermission(fd);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  aStreamFd = fd.forget();
-
-  return NS_OK;
-}
-
-nsresult
-KeyStoreConnector::CreateStreamSocket(struct sockaddr* aAddress,
-                                      socklen_t* aAddressLength,
-                                      int& aStreamFd)
-{
-  MOZ_CRASH("|KeyStoreConnector| does not support creating stream sockets.");
-  return NS_ERROR_FAILURE;
-}
-
-nsresult
-KeyStoreConnector::Duplicate(UnixSocketConnector*& aConnector)
-{
-  aConnector = new KeyStoreConnector(*this);
-
-  return NS_OK;
-}
-
-}
-}
deleted file mode 100644
--- a/ipc/keystore/KeyStoreConnector.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_ipc_KeyStoreConnector_h
-#define mozilla_ipc_KeyStoreConnector_h
-
-#include "mozilla/ipc/UnixSocketConnector.h"
-
-namespace mozilla {
-namespace ipc {
-
-class KeyStoreConnector final : public UnixSocketConnector
-{
-public:
-  KeyStoreConnector(const char** const aAllowedUsers);
-  ~KeyStoreConnector();
-
-  // Methods for |UnixSocketConnector|
-  //
-
-  nsresult ConvertAddressToString(const struct sockaddr& aAddress,
-                                  socklen_t aAddressLength,
-                                  nsACString& aAddressString) override;
-
-  nsresult CreateListenSocket(struct sockaddr* aAddress,
-                              socklen_t* aAddressLength,
-                              int& aListenFd) override;
-
-  nsresult AcceptStreamSocket(int aListenFd,
-                              struct sockaddr* aAddress,
-                              socklen_t* aAddressLength,
-                              int& aStreamFd) override;
-
-  nsresult CreateStreamSocket(struct sockaddr* aAddress,
-                              socklen_t* aAddressLength,
-                              int& aStreamFd) override;
-
-  nsresult Duplicate(UnixSocketConnector*& aConnector) override;
-
-private:
-  nsresult CreateSocket(int& aFd) const;
-  nsresult SetSocketFlags(int aFd) const;
-  nsresult CheckPermission(int aFd) const;
-  nsresult CreateAddress(struct sockaddr& aAddress,
-                         socklen_t& aAddressLength) const;
-
-  const char** const mAllowedUsers;
-};
-
-}
-}
-
-#endif
deleted file mode 100644
--- a/ipc/keystore/moz.build
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXPORTS.mozilla.ipc += [
-  'KeyStore.h'
-]
-
-SOURCES += [
-  'KeyStore.cpp',
-  'KeyStoreConnector.cpp'
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-FINAL_LIBRARY = 'xul'
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -13,17 +13,17 @@ DIRS += [
 
 if CONFIG['MOZ_ENABLE_DBUS']:
     DIRS += ['dbus']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['unixfd', 'unixsocket']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    DIRS += ['hal', 'keystore', 'netd']
+    DIRS += ['hal', 'netd']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     DIRS += ['contentproc']
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['mscom']
 
 DIRS += ['app']
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1330489-sps.js
@@ -0,0 +1,44 @@
+// |jit-test| test-also-wasm-baseline; error: TestComplete
+
+load(libdir + "asserts.js");
+
+if (!wasmIsSupported())
+    throw "TestComplete";
+
+// Single-step profiling currently only works in the ARM simulator
+if (!getBuildConfiguration()["arm-simulator"])
+    throw "TestComplete";
+
+enableSPSProfiling();
+enableSingleStepProfiling();
+
+var g = newGlobal();
+g.parent = this;
+g.eval("Debugger(parent).onExceptionUnwind = function () {};");
+
+let module = new WebAssembly.Module(wasmTextToBinary(`
+    (module
+        (import $imp "a" "b" (result i32))
+        (memory 1 1)
+        (table 2 2 anyfunc)
+        (elem (i32.const 0) $imp $def)
+        (func $def (result i32) (i32.load (i32.const 0)))
+        (type $v2i (func (result i32)))
+        (func $call (param i32) (result i32) (call_indirect $v2i (get_local 0)))
+        (export "call" $call)
+    )
+`));
+
+let instance = new WebAssembly.Instance(module, {
+    a: { b: function () { throw "test"; } }
+});
+
+try {
+    instance.exports.call(0);
+    assertEq(false, true);
+} catch (e) {
+    assertEq(e, "test");
+}
+
+disableSPSProfiling();
+throw "TestComplete";
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1330489.js
@@ -0,0 +1,36 @@
+// |jit-test| test-also-wasm-baseline; error: TestComplete
+
+load(libdir + "asserts.js");
+
+if (!wasmIsSupported())
+    throw "TestComplete";
+
+var g = newGlobal();
+g.parent = this;
+g.eval("Debugger(parent).onExceptionUnwind = function () {};");
+
+let module = new WebAssembly.Module(wasmTextToBinary(`
+    (module
+        (import $imp "a" "b" (result i32))
+        (memory 1 1)
+        (table 2 2 anyfunc)
+        (elem (i32.const 0) $imp $def)
+        (func $def (result i32) (i32.load (i32.const 0)))
+        (type $v2i (func (result i32)))
+        (func $call (param i32) (result i32) (call_indirect $v2i (get_local 0)))
+        (export "call" $call)
+    )
+`));
+
+let instance = new WebAssembly.Instance(module, {
+    a: { b: function () { throw "test"; } }
+});
+
+try {
+    instance.exports.call(0);
+    assertEq(false, true);
+} catch (e) {
+    assertEq(e, "test");
+}
+
+throw "TestComplete";
--- a/js/src/jit-test/tests/wasm/profiling.js
+++ b/js/src/jit-test/tests/wasm/profiling.js
@@ -122,32 +122,32 @@ function testError(code, error, expect)
 }
 
 testError(
 `(module
     (func $foo (unreachable))
     (func (export "") (call $foo))
 )`,
 WebAssembly.RuntimeError,
-["", ">", "1,>", "0,1,>", "trap handling,0,1,>", "inline stub,0,1,>", "trap handling,0,1,>", "inline stub,0,1,>", ""]);
+["", ">", "1,>", "0,1,>", "trap handling,0,1,>", "inline stub,0,1,>", "trap handling,0,1,>", ""]);
 
 testError(
 `(module
     (type $good (func))
     (type $bad (func (param i32)))
     (func $foo (call_indirect $bad (i32.const 1) (i32.const 0)))
     (func $bar (type $good))
     (table anyfunc (elem $bar))
     (export "" $foo)
 )`,
 WebAssembly.RuntimeError,
 // Technically we have this one *one-instruction* interval where
 // the caller is lost (the stack with "1,>"). It's annoying to fix and shouldn't
 // mess up profiles in practice so we ignore it.
-["", ">", "0,>", "1,0,>", "1,>", "trap handling,0,>", "inline stub,0,>", "trap handling,0,>", "inline stub,0,>", ""]);
+["", ">", "0,>", "1,0,>", "1,>", "trap handling,0,>", "inline stub,0,>", "trap handling,0,>", ""]);
 
 (function() {
     var e = wasmEvalText(`
     (module
         (func $foo (result i32) (i32.const 42))
         (export "foo" $foo)
         (func $bar (result i32) (i32.const 13))
         (table 10 anyfunc)
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -540,17 +540,17 @@ FrameIter::settleOnActivation()
             }
 
             nextJitFrame();
             data_.state_ = JIT;
             return;
         }
 
         if (activation->isWasm()) {
-            data_.wasmFrames_ = wasm::FrameIterator(*data_.activations_->asWasm());
+            data_.wasmFrames_ = wasm::FrameIterator(data_.activations_->asWasm());
 
             if (data_.wasmFrames_.done()) {
                 ++data_.activations_;
                 continue;
             }
 
             data_.pc_ = nullptr;
             data_.state_ = WASM;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1712,16 +1712,19 @@ class WasmActivation : public Activation
     // Written by JIT code:
     static unsigned offsetOfEntrySP() { return offsetof(WasmActivation, entrySP_); }
     static unsigned offsetOfFP() { return offsetof(WasmActivation, fp_); }
     static unsigned offsetOfExitReason() { return offsetof(WasmActivation, exitReason_); }
 
     // Read/written from SIGSEGV handler:
     void setResumePC(void* pc) { resumePC_ = pc; }
     void* resumePC() const { return resumePC_; }
+
+    // Used by wasm::FrameIterator during stack unwinding.
+    void unwindFP(uint8_t* fp) { fp_ = fp; }
 };
 
 // A FrameIter walks over the runtime's stack of JS script activations,
 // abstracting over whether the JS scripts were running in the interpreter or
 // different modes of compiled code.
 //
 // FrameIter is parameterized by what it includes in the stack iteration:
 //  - When provided, the optional JSPrincipal argument will cause FrameIter to
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -54,36 +54,38 @@ TlsDataFromFP(void *fp)
 
 FrameIterator::FrameIterator()
   : activation_(nullptr),
     code_(nullptr),
     callsite_(nullptr),
     codeRange_(nullptr),
     fp_(nullptr),
     pc_(nullptr),
+    unwind_(Unwind::False),
     missingFrameMessage_(false)
 {
     MOZ_ASSERT(done());
 }
 
-FrameIterator::FrameIterator(const WasmActivation& activation)
-  : activation_(&activation),
+FrameIterator::FrameIterator(WasmActivation* activation, Unwind unwind)
+  : activation_(activation),
     code_(nullptr),
     callsite_(nullptr),
     codeRange_(nullptr),
-    fp_(activation.fp()),
+    fp_(activation->fp()),
     pc_(nullptr),
+    unwind_(unwind),
     missingFrameMessage_(false)
 {
     if (fp_) {
         settle();
         return;
     }
 
-    void* pc = activation.resumePC();
+    void* pc = activation_->resumePC();
     if (!pc) {
         MOZ_ASSERT(done());
         return;
     }
     pc_ = (uint8_t*)pc;
 
     code_ = activation_->compartment()->wasm.lookupCode(pc);
     MOZ_ASSERT(code_);
@@ -151,16 +153,19 @@ FrameIterator::settle()
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
       case CodeRange::TrapExit:
       case CodeRange::DebugTrap:
       case CodeRange::Inline:
       case CodeRange::FarJumpIsland:
         MOZ_CRASH("Should not encounter an exit during iteration");
     }
+
+    if (unwind_ == Unwind::True)
+        activation_->unwindFP(fp_);
 }
 
 const char*
 FrameIterator::filename() const
 {
     MOZ_ASSERT(!done());
     return code_->metadata().filename.get();
 }
@@ -224,17 +229,19 @@ FrameIterator::instance() const
     return TlsDataFromFP(fp_ + callsite_->stackDepth())->instance;
 }
 
 bool
 FrameIterator::debugEnabled() const
 {
     MOZ_ASSERT(!done() && code_);
     MOZ_ASSERT_IF(!missingFrameMessage_, codeRange_->kind() == CodeRange::Function);
-    return code_->metadata().debugEnabled;
+    // Only non-imported functions can have debug frames.
+    return code_->metadata().debugEnabled &&
+           codeRange_->funcIndex() >= code_->metadata().funcImports.length();
 }
 
 DebugFrame*
 FrameIterator::debugFrame() const
 {
     MOZ_ASSERT(!done() && debugEnabled());
     // The fp() points to wasm::Frame.
     void* buf = static_cast<uint8_t*>(fp_ + callsite_->stackDepth()) - DebugFrame::offsetOfFrame();
--- a/js/src/wasm/WasmFrameIterator.h
+++ b/js/src/wasm/WasmFrameIterator.h
@@ -46,29 +46,34 @@ struct TrapOffset;
 //
 // The one exception is that this iterator may be called from the interrupt
 // callback which may be called asynchronously from asm.js code; in this case,
 // the backtrace may not be correct. That being said, we try our best printing
 // an informative message to the user and at least the name of the innermost
 // function stack frame.
 class FrameIterator
 {
-    const WasmActivation* activation_;
+  public:
+    enum class Unwind { True, False };
+
+  private:
+    WasmActivation* activation_;
     const Code* code_;
     const CallSite* callsite_;
     const CodeRange* codeRange_;
     uint8_t* fp_;
     uint8_t* pc_;
+    Unwind unwind_;
     bool missingFrameMessage_;
 
     void settle();
 
   public:
     explicit FrameIterator();
-    explicit FrameIterator(const WasmActivation& activation);
+    explicit FrameIterator(WasmActivation* activation, Unwind unwind = Unwind::False);
     void operator++();
     bool done() const;
     const char* filename() const;
     const char16_t* displayURL() const;
     bool mutedErrors() const;
     JSAtom* functionDisplayAtom() const;
     unsigned lineOrBytecode() const;
     const CodeRange* codeRange() const { return codeRange_; }
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -1126,27 +1126,34 @@ wasm::GenerateThrowStub(MacroAssembler& 
 {
     masm.haltingAlign(CodeAlignment);
 
     masm.bind(throwLabel);
 
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
+    // The following HandleThrow call sets fp of this WasmActivation to null.
     masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
     if (ShadowStackSpace)
         masm.subFromStackPtr(Imm32(ShadowStackSpace));
-    masm.call(SymbolicAddress::HandleDebugThrow);
+    masm.call(SymbolicAddress::HandleThrow);
 
-    // We are about to pop all frames in this WasmActivation. Set fp to null to
-    // maintain the invariant that fp is either null or pointing to a valid
-    // frame.
     Register scratch = ABINonArgReturnReg0;
     masm.loadWasmActivationFromSymbolicAddress(scratch);
-    masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP()));
+
+#ifdef DEBUG
+    // We are about to pop all frames in this WasmActivation. Checking if fp is
+    // set to null to maintain the invariant that fp is either null or pointing
+    // to a valid frame.
+    Label ok;
+    masm.branchPtr(Assembler::Equal, Address(scratch, WasmActivation::offsetOfFP()), ImmWord(0), &ok);
+    masm.breakpoint();
+    masm.bind(&ok);
+#endif
 
     masm.setFramePushed(FramePushedForEntrySP);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.Pop(scratch);
     masm.PopRegsInMask(NonVolatileRegs);
     MOZ_ASSERT(masm.framePushed() == 0);
 
     masm.mov(ImmWord(0), ReturnReg);
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -98,19 +98,20 @@ WasmHandleExecutionInterrupt()
 
     return success;
 }
 
 static bool
 WasmHandleDebugTrap()
 {
     WasmActivation* activation = JSRuntime::innermostWasmActivation();
+    MOZ_ASSERT(activation);
     JSContext* cx = activation->cx();
 
-    FrameIterator iter(*activation);
+    FrameIterator iter(activation);
     MOZ_ASSERT(iter.debugEnabled());
     const CallSite* site = iter.debugTrapCallsite();
     MOZ_ASSERT(site);
     if (site->kind() == CallSite::EnterFrame) {
         if (!iter.instance()->enterFrameTrapsEnabled())
             return true;
         DebugFrame* frame = iter.debugFrame();
         frame->setIsDebuggee();
@@ -133,22 +134,23 @@ WasmHandleDebugTrap()
         return ok;
     }
     // TODO baseline debug traps
     MOZ_CRASH();
     return true;
 }
 
 static void
-WasmHandleDebugThrow()
+WasmHandleThrow()
 {
     WasmActivation* activation = JSRuntime::innermostWasmActivation();
+    MOZ_ASSERT(activation);
     JSContext* cx = activation->cx();
 
-    for (FrameIterator iter(*activation); !iter.done(); ++iter) {
+    for (FrameIterator iter(activation, FrameIterator::Unwind::True); !iter.done(); ++iter) {
         if (!iter.debugEnabled())
             continue;
 
         DebugFrame* frame = iter.debugFrame();
 
         JSTrapStatus status = Debugger::onExceptionUnwind(cx, frame);
         if (status == JSTRAP_RETURN) {
             // Unexpected trap return -- raising error since throw recovery
@@ -344,18 +346,18 @@ wasm::AddressOf(SymbolicAddress imm, Exc
       case SymbolicAddress::InterruptUint32:
         return cx->runtimeAddressOfInterruptUint32();
       case SymbolicAddress::ReportOverRecursed:
         return FuncCast(WasmReportOverRecursed, Args_General0);
       case SymbolicAddress::HandleExecutionInterrupt:
         return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
       case SymbolicAddress::HandleDebugTrap:
         return FuncCast(WasmHandleDebugTrap, Args_General0);
-      case SymbolicAddress::HandleDebugThrow:
-        return FuncCast(WasmHandleDebugThrow, Args_General0);
+      case SymbolicAddress::HandleThrow:
+        return FuncCast(WasmHandleThrow, Args_General0);
       case SymbolicAddress::ReportTrap:
         return FuncCast(WasmReportTrap, Args_General1);
       case SymbolicAddress::ReportOutOfBounds:
         return FuncCast(WasmReportOutOfBounds, Args_General0);
       case SymbolicAddress::ReportUnalignedAccess:
         return FuncCast(WasmReportUnalignedAccess, Args_General0);
       case SymbolicAddress::CallImport_Void:
         return FuncCast(Instance::callImport_void, Args_General4);
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1012,17 +1012,17 @@ enum class SymbolicAddress
     LogD,
     PowD,
     ATan2D,
     Context,
     InterruptUint32,
     ReportOverRecursed,
     HandleExecutionInterrupt,
     HandleDebugTrap,
-    HandleDebugThrow,
+    HandleThrow,
     ReportTrap,
     ReportOutOfBounds,
     ReportUnalignedAccess,
     CallImport_Void,
     CallImport_I32,
     CallImport_I64,
     CallImport_F64,
     CoerceInPlace_ToInt32,
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -76,8 +76,11 @@ fuzzy-if(cocoaWidget,128,9) == animate-p
 fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
 fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
 fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
 fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
 == snap-perspective-1.html snap-perspective-1-ref.html
 == mask-layer-1.html mask-layer-ref.html
 == mask-layer-2.html mask-layer-ref.html
 == mask-layer-3.html mask-layer-ref.html
+fails-if(winWidget&&layersGPUAccelerated) == split-intersect1.html split-intersect1-ref.html # Bug 1323791: implement DirectX compositor polygon support
+fuzzy(255,150) fails-if(winWidget&&layersGPUAccelerated) == split-intersect2.html split-intersect2-ref.html # Bug 1323791
+fuzzy(255,100) fails-if(winWidget&&layersGPUAccelerated) == split-non-ortho1.html split-non-ortho1-ref.html # Bug 1323791
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-intersect1-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Split intersect 1 ref</title>
+
+<style>
+.container {
+  margin: 0 0;
+  width: 400px;
+  height: 400px;
+}
+
+.shape {
+  margin: 0 0;
+  position: absolute;
+
+  width: 50px;
+  height: 100px;
+}
+
+.first {
+  background-color: rgba(255,0,0,1);
+  left: 58px;
+}
+
+.second {
+  background-color: rgba(0,255,0,1);
+}
+</style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="shape first"></div>
+    <div class="shape second"></div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-intersect1.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Split intersect 1</title>
+
+<style>
+.container {
+  margin: 0 0;
+  width: 400px;
+  height: 400px;
+
+  transform-style: preserve-3d;
+}
+
+.shape {
+  margin: 0 0;
+  position: absolute;
+
+  width: 100px;
+  height: 100px;
+}
+
+.first {
+  background-color: rgba(255,0,0,1);
+}
+
+.second {
+  background-color: rgba(0,255,0,1);
+  transform: rotateY(0.1deg);
+}
+</style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="shape first"></div>
+    <div class="shape second"></div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-intersect2-ref.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Split intersect 2 ref</title>
+
+<style>
+.container {
+  margin: 0 0;
+  width: 400px;
+  height: 400px;
+}
+
+.shape {
+  margin: 0 0;
+  position: absolute;
+}
+
+.red {
+  background-color: rgba(255,0,0,1);
+
+  width: 100px;
+  height: 15px;
+
+  top: 150.5px;
+  left: 73px;
+}
+
+.green1 {
+  background-color: rgba(0,255,0,1);
+
+  width: 30px;
+  height: 42.5px;
+
+  top: 108px;
+  left: 88px;
+}
+
+.green2 {
+  background-color: rgba(0,255,0,1);
+
+  width: 30px;
+  height: 50px;
+
+  top: 158px;
+  left: 88px;
+}
+
+.blue1 {
+  background-color: rgba(0,0,255,1);
+
+  top: 108px;
+  left: 128px;
+
+  width: 30px;
+  height: 42.5px;
+}
+
+.blue2 {
+  background-color: rgba(0,0,255,1);
+
+  width: 30px;
+  height: 50px;
+
+  top: 158px;
+  left: 128px;
+}
+</style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="shape red"></div>
+    <div class="shape green1"></div>
+    <div class="shape green2"></div>
+    <div class="shape blue1"></div>
+    <div class="shape blue2"></div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-intersect2.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Split intersect 2</title>
+
+<style>
+.container {
+  margin: 0 0;
+  width: 400px;
+  height: 400px;
+
+  transform-style: preserve-3d;
+}
+
+.shape {
+  margin: 0 0;
+  position: absolute;
+
+  width: 30px;
+  height: 100px;
+}
+
+.red {
+  background-color: rgba(255,0,0,1);
+  transform: translate(100px, 100px) rotateZ(90deg) rotateY(60deg);
+}
+
+.green {
+  background-color: rgba(0,255,0,1);
+  transform: translate(80px, 100px);
+}
+
+.blue {
+  background-color: rgba(0,0,255,1);
+  transform: translate(120px, 100px);
+}
+</style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="shape red"></div>
+    <div class="shape green"></div>
+    <div class="shape blue"></div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-non-ortho1-ref.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Split non-orthogonal 1 ref</title>
+
+<style>
+.container {
+  margin: 0 0;
+  width: 400px;
+  height: 400px;
+
+  position: absolute;
+  transform-style: preserve-3d;
+}
+
+.shape {
+  margin: 0 0;
+  position: absolute;
+}
+
+.red-square-back {
+  background-color: rgba(255,0,0,1);
+
+  width: 100px;
+  height: 100px;
+
+  top: 50px;
+  left: 50px;
+}
+
+.green-square-back {
+  background-color: rgba(0,255,0,1);
+
+  width: 150px;
+  height: 150px;
+
+  top: 50px;
+  left: 50px;
+
+  transform: rotateZ(45deg);
+}
+
+.red-square-front {
+  background-color: rgba(255,0,0,1);
+
+  width: 50px;
+  height: 50px;
+
+  top: 100px;
+  left: 100px;
+}
+
+.green-square-front {
+  background-color: rgba(0,255,0,1);
+
+  width: 72px;
+  height: 72px;
+
+  top: 63.5px;
+  left: 63.5px;
+
+  transform: rotateZ(45deg);
+}
+
+#canvas {
+  width: 100px
+  height: 100px;
+
+  top: 100px;
+  left: 100px;
+}
+
+</style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="shape red-square-back"></div>
+    <div class="shape green-square-back"></div>
+    <div class="shape red-square-front"></div>
+    <div class="shape green-square-front"></div>
+  </div>
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/split-non-ortho1.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Split non-orthogonal 1</title>
+
+<style>
+.container {
+  margin: 0 0;
+  width: 400px;
+  height: 400px;
+
+  position: absolute;
+  transform-style: preserve-3d;
+}
+
+.shape {
+  margin: 0 0;
+  position: absolute;
+}
+
+.first {
+  background-color: rgba(255,0,0,1);
+
+  width: 100px;
+  height: 100px;
+
+  top: 50px;
+  left: 50px;
+}
+
+.second {
+  background-color: rgba(0,255,0,1);
+
+  width: 150px;
+  height: 150px;
+
+  top: 50px;
+  left: 50px;
+
+  transform: rotateZ(45deg) rotateY(0.1deg);
+}
+</style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="shape second"></div>
+    <div class="shape first"></div>
+  </div>
+</body>
+</html>
--- a/layout/style/CSS.cpp
+++ b/layout/style/CSS.cpp
@@ -60,17 +60,17 @@ CSS::Supports(const GlobalObject& aGloba
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return false;
   }
 
   if (info.mStyleBackendType == StyleBackendType::Servo) {
     NS_ConvertUTF16toUTF8 property(aProperty);
     NS_ConvertUTF16toUTF8 value(aValue);
-    return Servo_CSSSupports(&property, &value);
+    return Servo_CSSSupports2(&property, &value);
   }
 
   nsCSSParser parser;
   return parser.EvaluateSupportsDeclaration(aProperty, aValue, info.mDocURI,
                                             info.mBaseURI, info.mPrincipal);
 }
 
 /* static */ bool
@@ -82,17 +82,18 @@ CSS::Supports(const GlobalObject& aGloba
 
   nsresult rv = GetParsingInfo(aGlobal, info);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return false;
   }
 
   if (info.mStyleBackendType == StyleBackendType::Servo) {
-    MOZ_CRASH("stylo: CSS.supports() with arguments is not yet implemented");
+    NS_ConvertUTF16toUTF8 cond(aCondition);
+    return Servo_CSSSupports(&cond);
   }
 
   nsCSSParser parser;
   return parser.EvaluateSupportsCondition(aCondition, info.mDocURI,
                                           info.mBaseURI, info.mPrincipal);
 }
 
 /* static */ void
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -156,18 +156,20 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemovePropertyById, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property)
 
 // CSS supports()
+SERVO_BINDING_FUNC(Servo_CSSSupports2, bool,
+                   const nsACString* name, const nsACString* value)
 SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
-                   const nsACString* name, const nsACString* value)
+                   const nsACString* cond)
 
 // Computed style data
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox,
                    ServoComputedValuesStrong,
                    ServoComputedValuesBorrowedOrNull parent_style_or_null,
                    nsIAtom* pseudoTag, RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoComputedValuesStrong,
                    RawServoStyleSetBorrowed set,
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -1036,18 +1036,18 @@ CSSAnimationBuilder::GetComputedValue(ns
   nsCSSValue result;
   StyleAnimationValue computedValue;
 
   if (!mStyleWithoutAnimation) {
     MOZ_ASSERT(aPresContext->StyleSet()->IsGecko(),
                "ServoStyleSet should not use nsAnimationManager for "
                "animations");
     mStyleWithoutAnimation = aPresContext->StyleSet()->AsGecko()->
-      ResolveStyleWithoutAnimation(mTarget, mStyleContext,
-                                   eRestyle_AllHintsWithAnimations);
+      ResolveStyleByRemovingAnimation(mTarget, mStyleContext,
+                                      eRestyle_AllHintsWithAnimations);
   }
 
   if (StyleAnimationValue::ExtractComputedValue(aProperty,
                                                 mStyleWithoutAnimation,
                                                 computedValue)) {
     DebugOnly<bool> uncomputeResult =
       StyleAnimationValue::UncomputeValue(aProperty, Move(computedValue),
                                           result);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -443,22 +443,146 @@ nsComputedDOMStyle::GetStyleContextForEl
   }
 
   presShell->FlushPendingNotifications(FlushType::Style);
 
   return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
                                           aStyleType);
 }
 
-/* static */
+namespace {
+class MOZ_STACK_CLASS StyleResolver final
+{
+public:
+  StyleResolver(nsPresContext* aPresContext,
+                nsComputedDOMStyle::AnimationFlag aAnimationFlag)
+    : mAnimationFlag(aAnimationFlag)
+  {
+    MOZ_ASSERT(aPresContext);
+
+    // Nothing to do if we are going to resolve style *with* animation.
+    if (mAnimationFlag == nsComputedDOMStyle::eWithAnimation) {
+      return;
+    }
+
+    // Set SkipAnimationRules flag if we are going to resolve style without
+    // animation.
+    if (aPresContext->RestyleManager()->IsGecko()) {
+      mRestyleManager = aPresContext->RestyleManager()->AsGecko();
+
+      mOldSkipAnimationRules = mRestyleManager->SkipAnimationRules();
+      mRestyleManager->SetSkipAnimationRules(true);
+    } else {
+      NS_WARNING("stylo: can't skip animaition rules yet");
+    }
+  }
+
+  already_AddRefed<nsStyleContext>
+  ResolveWithAnimation(StyleSetHandle aStyleSet,
+                       Element* aElement,
+                       CSSPseudoElementType aType,
+                       nsStyleContext* aParentContext,
+                       nsComputedDOMStyle::StyleType aStyleType,
+                       bool aInDocWithShell)
+  {
+    MOZ_ASSERT(mAnimationFlag == nsComputedDOMStyle::eWithAnimation,
+      "AnimationFlag should be eWithAnimation");
+
+    RefPtr<nsStyleContext> result;
+
+    if (aType != CSSPseudoElementType::NotPseudo) {
+      nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
+      Element* pseudoElement =
+        frame && aInDocWithShell ? frame->GetPseudoElement(aType) : nullptr;
+      result = aStyleSet->ResolvePseudoElementStyle(aElement, aType,
+                                                    aParentContext,
+                                                    pseudoElement);
+    } else {
+      result = aStyleSet->ResolveStyleFor(aElement, aParentContext,
+                                          LazyComputeBehavior::Allow);
+    }
+    if (aStyleType == nsComputedDOMStyle::StyleType::eDefaultOnly) {
+      // We really only want the user and UA rules.  Filter out the other ones.
+      nsTArray< nsCOMPtr<nsIStyleRule> > rules;
+      for (nsRuleNode* ruleNode = result->RuleNode();
+           !ruleNode->IsRoot();
+           ruleNode = ruleNode->GetParent()) {
+        if (ruleNode->GetLevel() == SheetType::Agent ||
+            ruleNode->GetLevel() == SheetType::User) {
+          rules.AppendElement(ruleNode->GetRule());
+        }
+      }
+
+      // We want to build a list of user/ua rules that is in order from least to
+      // most important, so we have to reverse the list.
+      // Integer division to get "stop" is purposeful here: if length is odd, we
+      // don't have to do anything with the middle element of the array.
+      for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
+           i < stop; ++i) {
+        rules[i].swap(rules[length - i - 1]);
+      }
+
+      result = aStyleSet->AsGecko()->ResolveStyleForRules(aParentContext,
+                                                          rules);
+    }
+    return result.forget();
+  }
+
+  already_AddRefed<nsStyleContext>
+  ResolveWithoutAnimation(StyleSetHandle aStyleSet,
+                          Element* aElement,
+                          CSSPseudoElementType aType,
+                          nsStyleContext* aParentContext,
+                          bool aInDocWithShell)
+  {
+    MOZ_ASSERT(!aStyleSet->IsServo(),
+      "Bug 1311257: Servo backend does not support the base value yet");
+    MOZ_ASSERT(mAnimationFlag == nsComputedDOMStyle::eWithoutAnimation,
+      "AnimationFlag should be eWithoutAnimation");
+
+    RefPtr<nsStyleContext> result;
+
+    if (aType != CSSPseudoElementType::NotPseudo) {
+      nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
+      Element* pseudoElement =
+        frame && aInDocWithShell ? frame->GetPseudoElement(aType) : nullptr;
+      result =
+        aStyleSet->AsGecko()->ResolvePseudoElementStyleWithoutAnimation(
+          aElement, aType,
+          aParentContext,
+          pseudoElement);
+    } else {
+      result =
+        aStyleSet->AsGecko()->ResolveStyleWithoutAnimation(aElement,
+                                                           aParentContext);
+    }
+    return result.forget();
+  }
+
+  ~StyleResolver()
+  {
+    if (mRestyleManager) {
+      mRestyleManager->SetSkipAnimationRules(mOldSkipAnimationRules);
+    }
+  }
+
+private:
+  RestyleManager* mRestyleManager = nullptr;
+  bool mOldSkipAnimationRules = false;
+  nsComputedDOMStyle::AnimationFlag mAnimationFlag;
+};
+}
+
 already_AddRefed<nsStyleContext>
-nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
-                                                     nsIAtom* aPseudo,
-                                                     nsIPresShell* aPresShell,
-                                                     StyleType aStyleType)
+nsComputedDOMStyle::DoGetStyleContextForElementNoFlush(
+  Element* aElement,
+  nsIAtom* aPseudo,
+  nsIPresShell* aPresShell,
+  StyleType aStyleType,
+  AnimationFlag aAnimationFlag)
 {
   MOZ_ASSERT(aElement, "NULL element");
   // If the content has a pres shell, we must use it.  Otherwise we'd
   // potentially mix rule trees by using the wrong pres shell's style
   // set.  Using the pres shell from the content also means that any
   // content that's actually *in* a document will get the style from the
   // correct document.
   nsIPresShell *presShell = GetPresShellForContent(aElement);
@@ -512,60 +636,82 @@ nsComputedDOMStyle::GetStyleContextForEl
   if (ServoStyleSet* servoSet = styleSet->GetAsServo()) {
     if (aStyleType == eDefaultOnly) {
       NS_ERROR("stylo: ServoStyleSets cannot supply UA-only styles yet");
       return nullptr;
     }
     return servoSet->ResolveTransientStyle(aElement, type);
   }
 
-  RefPtr<nsStyleContext> sc;
   RefPtr<nsStyleContext> parentContext;
   nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
   // Don't resolve parent context for document fragments.
-  if (parent && parent->IsElement())
+  if (parent && parent->IsElement()) {
     parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
                                                      nullptr, aPresShell,
                                                      aStyleType);
-
-  if (type != CSSPseudoElementType::NotPseudo) {
-    nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
-    Element* pseudoElement =
-      frame && inDocWithShell ? frame->GetPseudoElement(type) : nullptr;
-    sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
-                                             pseudoElement);
-  } else {
-    sc = styleSet->ResolveStyleFor(aElement, parentContext, LazyComputeBehavior::Allow);
-  }
-
-  if (aStyleType == eDefaultOnly) {
-    // We really only want the user and UA rules.  Filter out the other ones.
-    nsTArray< nsCOMPtr<nsIStyleRule> > rules;
-    for (nsRuleNode* ruleNode = sc->RuleNode();
-         !ruleNode->IsRoot();
-         ruleNode = ruleNode->GetParent()) {
-      if (ruleNode->GetLevel() == SheetType::Agent ||
-          ruleNode->GetLevel() == SheetType::User) {
-        rules.AppendElement(ruleNode->GetRule());
-      }
-    }
-
-    // We want to build a list of user/ua rules that is in order from least to
-    // most important, so we have to reverse the list.
-    // Integer division to get "stop" is purposeful here: if length is odd, we
-    // don't have to do anything with the middle element of the array.
-    for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
-         i < stop; ++i) {
-      rules[i].swap(rules[length - i - 1]);
-    }
-
-    sc = styleSet->AsGecko()->ResolveStyleForRules(parentContext, rules);
-  }
-
-  return sc.forget();
+  }
+
+  StyleResolver styleResolver(presContext, aAnimationFlag);
+
+  if (aAnimationFlag == eWithAnimation) {
+    return styleResolver.ResolveWithAnimation(styleSet,
+                                              aElement, type,
+                                              parentContext,
+                                              aStyleType,
+                                              inDocWithShell);
+  }
+
+  return styleResolver.ResolveWithoutAnimation(styleSet,
+                                               aElement, type,
+                                               parentContext,
+                                               inDocWithShell);
+}
+
+
+/* static */
+already_AddRefed<nsStyleContext>
+nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
+                                                     nsIAtom* aPseudo,
+                                                     nsIPresShell* aPresShell,
+                                                     StyleType aStyleType)
+{
+  return DoGetStyleContextForElementNoFlush(aElement,
+                                            aPseudo,
+                                            aPresShell,
+                                            aStyleType,
+                                            eWithAnimation);
+}
+
+/* static */
+already_AddRefed<nsStyleContext>
+nsComputedDOMStyle::GetStyleContextForElementWithoutAnimation(
+  Element* aElement,
+  nsIAtom* aPseudo,
+  nsIPresShell* aPresShell)
+{
+  // If the content has a pres shell, we must use it.  Otherwise we'd
+  // potentially mix rule trees by using the wrong pres shell's style
+  // set.  Using the pres shell from the content also means that any
+  // content that's actually *in* a document will get the style from the
+  // correct document.
+  nsCOMPtr<nsIPresShell> presShell = GetPresShellForContent(aElement);
+  if (!presShell) {
+    presShell = aPresShell;
+    if (!presShell)
+      return nullptr;
+  }
+
+  presShell->FlushPendingNotifications(FlushType::Style);
+
+  return DoGetStyleContextForElementNoFlush(aElement,
+                                            aPseudo,
+                                            presShell,
+                                            eAll,
+                                            eWithoutAnimation);
 }
 
 nsMargin
 nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
 {
   // We want the width/height of whatever parts 'width' or 'height' controls,
   // which can be different depending on the value of the 'box-sizing' property.
   const nsStylePosition* stylePos = StylePosition();
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -84,16 +84,26 @@ public:
     return mContent;
   }
 
   static already_AddRefed<nsStyleContext>
   GetStyleContextForElement(mozilla::dom::Element* aElement, nsIAtom* aPseudo,
                             nsIPresShell* aPresShell,
                             StyleType aStyleType = eAll);
 
+  enum AnimationFlag {
+    eWithAnimation,
+    eWithoutAnimation,
+  };
+  // Similar to the above but ignoring animation rules and with StyleType::eAll.
+  static already_AddRefed<nsStyleContext>
+  GetStyleContextForElementWithoutAnimation(mozilla::dom::Element* aElement,
+                                            nsIAtom* aPseudo,
+                                            nsIPresShell* aPresShell);
+
   static already_AddRefed<nsStyleContext>
   GetStyleContextForElementNoFlush(mozilla::dom::Element* aElement,
                                    nsIAtom* aPseudo,
                                    nsIPresShell* aPresShell,
                                    StyleType aStyleType = eAll);
 
   static nsIPresShell*
   GetPresShellForContent(nsIContent* aContent);
@@ -139,16 +149,23 @@ private:
   void UpdateCurrentStyleSources(bool aNeedsLayoutFlush);
   void ClearCurrentStyleSources();
 
   // Helper functions called by UpdateCurrentStyleSources.
   void ClearStyleContext();
   void SetResolvedStyleContext(RefPtr<nsStyleContext>&& aContext);
   void SetFrameStyleContext(nsStyleContext* aContext);
 
+  static already_AddRefed<nsStyleContext>
+  DoGetStyleContextForElementNoFlush(mozilla::dom::Element* aElement,
+                                     nsIAtom* aPseudo,
+                                     nsIPresShell* aPresShell,
+                                     StyleType aStyleType,
+                                     AnimationFlag aAnimationFlag);
+
 #define STYLE_STRUCT(name_, checkdata_cb_)                              \
   const nsStyle##name_ * Style##name_() {                               \
     return mStyleContext->Style##name_();                               \
   }
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
   already_AddRefed<CSSValue> GetEllipseRadii(const nsStyleCorners& aRadius,
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1346,19 +1346,20 @@ nsStyleSet::ResolveStyleFor(Element* aEl
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aElement->OwnerDoc());
   InitStyleScopes(treeContext, aElement);
   return ResolveStyleFor(aElement, aParentContext, treeContext);
 }
 
 already_AddRefed<nsStyleContext>
-nsStyleSet::ResolveStyleFor(Element* aElement,
-                            nsStyleContext* aParentContext,
-                            TreeMatchContext& aTreeMatchContext)
+nsStyleSet::ResolveStyleForInternal(Element* aElement,
+                                    nsStyleContext* aParentContext,
+                                    TreeMatchContext& aTreeMatchContext,
+                                    AnimationFlag aAnimationFlag)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
   NS_ASSERTION(aElement, "aElement must not be null");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   aTreeMatchContext.ResetForUnvisitedMatching();
   ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
                                 aTreeMatchContext);
@@ -1372,17 +1373,17 @@ nsStyleSet::ResolveStyleFor(Element* aEl
   if (aTreeMatchContext.HaveRelevantLink()) {
     aTreeMatchContext.ResetForVisitedMatching();
     ruleWalker.Reset();
     FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
               &ruleWalker);
     visitedRuleNode = ruleWalker.CurrentNode();
   }
 
-  uint32_t flags = eDoAnimation;
+  uint32_t flags = (aAnimationFlag == eWithAnimation) ? eDoAnimation : eNoFlags;
   if (nsCSSRuleProcessor::IsLink(aElement)) {
     flags |= eIsLink;
   }
   if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
                             HasState(NS_EVENT_STATE_VISITED)) {
     flags |= eIsVisitedLink;
   }
   if (aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup) {
@@ -1390,16 +1391,27 @@ nsStyleSet::ResolveStyleFor(Element* aEl
   }
 
   return GetContext(aParentContext, ruleNode, visitedRuleNode,
                     nullptr, CSSPseudoElementType::NotPseudo,
                     aElement, flags);
 }
 
 already_AddRefed<nsStyleContext>
+nsStyleSet::ResolveStyleFor(Element* aElement,
+                            nsStyleContext* aParentContext,
+                            TreeMatchContext& aTreeMatchContext)
+{
+  return ResolveStyleForInternal(aElement,
+                                 aParentContext,
+                                 aTreeMatchContext,
+                                 eWithAnimation);
+}
+
+already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
                                  const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   // FIXME: Perhaps this should be passed in, but it probably doesn't
   // matter.
@@ -1743,19 +1755,19 @@ nsStyleSet::ResolveStyleWithReplacement(
   }
 
   return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
                     aOldStyleContext->GetPseudo(), pseudoType,
                     elementForAnimation, flags);
 }
 
 already_AddRefed<nsStyleContext>
-nsStyleSet::ResolveStyleWithoutAnimation(dom::Element* aTarget,
-                                         nsStyleContext* aStyleContext,
-                                         nsRestyleHint aWhichToRemove)
+nsStyleSet::ResolveStyleByRemovingAnimation(dom::Element* aTarget,
+                                            nsStyleContext* aStyleContext,
+                                            nsRestyleHint aWhichToRemove)
 {
 #ifdef DEBUG
   CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
 #endif
   MOZ_ASSERT(pseudoType == CSSPseudoElementType::NotPseudo ||
              pseudoType == CSSPseudoElementType::before ||
              pseudoType == CSSPseudoElementType::after,
              "unexpected type for animations");
@@ -1773,16 +1785,44 @@ nsStyleSet::ResolveStyleWithoutAnimation
                                 eSkipStartingAnimations);
 
   restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
 
   return result.forget();
 }
 
 already_AddRefed<nsStyleContext>
+nsStyleSet::ResolveStyleWithoutAnimation(Element* aTarget,
+                                         nsStyleContext* aParentContext)
+{
+  RestyleManager* restyleManager = PresContext()->RestyleManager()->AsGecko();
+
+  TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
+                               aTarget->OwnerDoc());
+  InitStyleScopes(treeContext, aTarget);
+
+  bool oldSkipAnimationRules = restyleManager->SkipAnimationRules();
+  restyleManager->SetSkipAnimationRules(true);
+
+  // Here we can call ResolveStyleForInternal() instead of
+  // ResolveStyleWithReplacement() since we don't need any animation rules
+  // (CSS Animations, Transitions and script animations). That's because
+  // EffectCompositor::GetAnimationRule() skips all of animations rules if
+  // SkipAnimationRules flag is true.
+  RefPtr<nsStyleContext> result = ResolveStyleForInternal(aTarget,
+                                                          aParentContext,
+                                                          treeContext,
+                                                          eWithoutAnimation);
+
+  restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
+
+  return result.forget();
+}
+
+already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleForText(nsIContent* aTextNode,
                                 nsStyleContext* aParentContext)
 {
   MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
   return GetContext(aParentContext, mRuleTree, nullptr,
                     nsCSSAnonBoxes::mozText,
                     CSSPseudoElementType::AnonBox, nullptr, eNoFlags);
 }
@@ -1813,20 +1853,22 @@ void
 nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
 {
   aRuleWalker->SetLevel(SheetType::Agent, false, false);
   if (aElement->IsSVGElement(nsGkAtoms::text))
     aRuleWalker->Forward(mDisableTextZoomStyleRule);
 }
 
 already_AddRefed<nsStyleContext>
-nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
-                                      CSSPseudoElementType aType,
-                                      nsStyleContext* aParentContext,
-                                      Element* aPseudoElement)
+nsStyleSet::ResolvePseudoElementStyleInternal(
+  Element* aParentElement,
+  CSSPseudoElementType aType,
+  nsStyleContext* aParentContext,
+  Element* aPseudoElement,
+  AnimationFlag aAnimationFlag)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
 
   NS_ASSERTION(aType < CSSPseudoElementType::Count,
                "must have pseudo element type");
   NS_ASSERTION(aParentElement, "Must have parent element");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
@@ -1852,31 +1894,60 @@ nsStyleSet::ResolvePseudoElementStyle(El
     visitedRuleNode = ruleWalker.CurrentNode();
   }
 
   // For pseudos, |data.IsLink()| being true means that
   // our parent node is a link.
   uint32_t flags = eNoFlags;
   if (aType == CSSPseudoElementType::before ||
       aType == CSSPseudoElementType::after) {
-    flags |= eDoAnimation;
+    if (aAnimationFlag == eWithAnimation) {
+      flags |= eDoAnimation;
+    }
   } else {
     // Flex and grid containers don't expect to have any pseudo-element children
     // aside from ::before and ::after.  So if we have such a child, we're not
     // actually in a flex/grid container, and we should skip flex/grid item
     // style fixup.
     flags |= eSkipParentDisplayBasedStyleFixup;
   }
 
   return GetContext(aParentContext, ruleNode, visitedRuleNode,
                     nsCSSPseudoElements::GetPseudoAtom(aType), aType,
                     aParentElement, flags);
 }
 
 already_AddRefed<nsStyleContext>
+nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
+                                      CSSPseudoElementType aType,
+                                      nsStyleContext* aParentContext,
+                                      Element* aPseudoElement)
+{
+  return ResolvePseudoElementStyleInternal(aParentElement,
+                                           aType,
+                                           aParentContext,
+                                           aPseudoElement,
+                                           eWithAnimation);
+}
+
+already_AddRefed<nsStyleContext>
+nsStyleSet::ResolvePseudoElementStyleWithoutAnimation(
+  Element* aParentElement,
+  CSSPseudoElementType aType,
+  nsStyleContext* aParentContext,
+  Element* aPseudoElement)
+{
+  return ResolvePseudoElementStyleInternal(aParentElement,
+                                           aType,
+                                           aParentContext,
+                                           aPseudoElement,
+                                           eWithoutAnimation);
+}
+
+already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
                                     CSSPseudoElementType aType,
                                     nsStyleContext* aParentContext)
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
   InitStyleScopes(treeContext, aParentElement);
   return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -176,19 +176,33 @@ class nsStyleSet final
                               nsRestyleHint aReplacements,
                               uint32_t aFlags = 0);
 
   // Resolve style by returning a style context with the specified
   // animation data removed.  It is allowable to remove all animation
   // data with eRestyle_AllHintsWithAnimations, or by using any other
   // hints that are allowed by ResolveStyleWithReplacement.
   already_AddRefed<nsStyleContext>
-    ResolveStyleWithoutAnimation(mozilla::dom::Element* aElement,
-                                 nsStyleContext* aStyleContext,
-                                 nsRestyleHint aWhichToRemove);
+    ResolveStyleByRemovingAnimation(mozilla::dom::Element* aElement,
+                                    nsStyleContext* aStyleContext,
+                                    nsRestyleHint aWhichToRemove);
+
+  // Similar to the above, but resolving style without all animation data in
+  // the first place.
+  already_AddRefed<nsStyleContext>
+    ResolveStyleWithoutAnimation(mozilla::dom::Element* aTarget,
+                                 nsStyleContext* aParentContext);
+
+  // Pseudo-element version of the above, ResolveStyleWithoutAnimation.
+  already_AddRefed<nsStyleContext>
+  ResolvePseudoElementStyleWithoutAnimation(
+    mozilla::dom::Element* aParentElement,
+    mozilla::CSSPseudoElementType aType,
+    nsStyleContext* aParentContext,
+    mozilla::dom::Element* aPseudoElement);
 
   // Get a style context for a text node (which no rules will match).
   //
   // The returned style context will have nsCSSAnonBoxes::mozText as its pseudo.
   //
   // (Perhaps mozText should go away and we shouldn't even create style
   // contexts for such content nodes, when text-combine-upright is not
   // present.  However, not doing any rule matching for them is a first step.)
@@ -521,16 +535,33 @@ private:
   GetContext(nsStyleContext* aParentContext,
              nsRuleNode* aRuleNode,
              nsRuleNode* aVisitedRuleNode,
              nsIAtom* aPseudoTag,
              mozilla::CSSPseudoElementType aPseudoType,
              mozilla::dom::Element* aElementForAnimation,
              uint32_t aFlags);
 
+  enum AnimationFlag {
+    eWithAnimation,
+    eWithoutAnimation,
+  };
+  already_AddRefed<nsStyleContext>
+  ResolveStyleForInternal(mozilla::dom::Element* aElement,
+                          nsStyleContext* aParentContext,
+                          TreeMatchContext& aTreeMatchContext,
+                          AnimationFlag aAnimationFlag);
+
+  already_AddRefed<nsStyleContext>
+  ResolvePseudoElementStyleInternal(mozilla::dom::Element* aParentElement,
+                                    mozilla::CSSPseudoElementType aType,
+                                    nsStyleContext* aParentContext,
+                                    mozilla::dom::Element* aPseudoElement,
+                                    AnimationFlag aAnimationFlag);
+
   nsPresContext* PresContext() { return mRuleTree->PresContext(); }
 
   // The sheets in each array in mSheets are stored with the most significant
   // sheet last.
   // The arrays for ePresHintSheet, eStyleAttrSheet, eTransitionSheet,
   // eAnimationSheet and eSVGAttrAnimationSheet are always empty.
   // (FIXME:  We should reduce the storage needed for them.)
   mozilla::EnumeratedArray<mozilla::SheetType, mozilla::SheetType::Count,
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -553,18 +553,18 @@ nsTransitionManager::StyleContextChanged
   // not stopping or starting right now.
   RefPtr<nsStyleContext> afterChangeStyle;
   if (collection) {
     MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(),
                "ServoStyleSets should not use nsTransitionManager "
                "for transitions");
     nsStyleSet* styleSet = mPresContext->StyleSet()->AsGecko();
     afterChangeStyle =
-      styleSet->ResolveStyleWithoutAnimation(aElement, newStyleContext,
-                                             eRestyle_CSSTransitions);
+      styleSet->ResolveStyleByRemovingAnimation(aElement, newStyleContext,
+                                                eRestyle_CSSTransitions);
   } else {
     afterChangeStyle = newStyleContext;
   }
 
   nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
 
   DebugOnly<bool> startedAny = false;
   // We don't have to update transitions if display:none, although we will
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
@@ -21,16 +21,17 @@ import org.mozilla.gecko.util.GeckoJarRe
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.Build;
 import android.util.Log;
 
 /**
  * This class manages persistence, application, and otherwise handling of
  * user-specified locales.
  *
  * Of note:
  *
@@ -290,16 +291,21 @@ public class BrowserLocaleManager implem
     @Override
     public void updateConfiguration(Context context, Locale locale) {
         Resources res = context.getResources();
         Configuration config = res.getConfiguration();
 
         // We should use setLocale, but it's unexpectedly missing
         // on real devices.
         config.locale = locale;
+        //  LayoutDirection is also updated in setLocale, do this manually.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            config.setLayoutDirection(locale);
+        }
+
         res.updateConfiguration(config, null);
     }
 
     private SharedPreferences getSharedPreferences(Context context) {
         return GeckoSharedPrefs.forApp(context);
     }
 
     /**
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -106,16 +106,17 @@ import android.widget.ListView;
 import android.widget.RelativeLayout;
 import android.widget.SimpleAdapter;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.mozilla.gecko.util.ViewUtil;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.net.URL;
 import java.util.ArrayList;
@@ -1497,16 +1498,19 @@ public abstract class GeckoApp
         if (!ThreadUtils.isOnUiThread()) {
             throw new RuntimeException("onLocaleReady must always be called from the UI thread.");
         }
 
         final Locale loc = Locales.parseLocaleCode(locale);
         if (loc.equals(mLastLocale)) {
             Log.d(LOGTAG, "New locale same as old; onLocaleReady has nothing to do.");
         }
+        BrowserLocaleManager.getInstance().updateConfiguration(GeckoApp.this, loc);
+        ViewUtil.setLayoutDirection(getWindow().getDecorView(), loc);
+        refreshChrome();
 
         // The URL bar hint needs to be populated.
         TextView urlBar = (TextView) findViewById(R.id.url_bar_title);
         if (urlBar != null) {
             final String hint = getResources().getString(R.string.url_bar_default_text);
             urlBar.setHint(hint);
         } else {
             Log.d(LOGTAG, "No URL bar in GeckoApp. Not loading localized hint string.");
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -45,16 +45,17 @@ import org.mozilla.gecko.updater.UpdateS
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.ContextUtils;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.InputOptionsUtils;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.gecko.util.ViewUtil;
 
 import android.annotation.TargetApi;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.NotificationManager;
 import android.content.ContentResolver;
@@ -75,22 +76,26 @@ import android.preference.Preference.OnP
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceGroup;
 import android.preference.SwitchPreference;
 import android.preference.TwoStatePreference;
 import android.support.design.widget.Snackbar;
 import android.support.design.widget.TextInputLayout;
 import android.support.v4.content.LocalBroadcastManager;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.text.TextUtilsCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.app.ActionBar;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.Log;
+import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
@@ -257,16 +262,24 @@ public class GeckoPreferences
             setTitle(title);
         }
     }
 
     private void onLocaleChanged(Locale newLocale) {
         Log.d(LOGTAG, "onLocaleChanged: " + newLocale);
 
         BrowserLocaleManager.getInstance().updateConfiguration(getApplicationContext(), newLocale);
+        //  If activity is not recreated, also update locale to current activity configuration
+        BrowserLocaleManager.getInstance().updateConfiguration(GeckoPreferences.this, newLocale);
+        ViewUtil.setLayoutDirection(getWindow().getDecorView(), newLocale);
+
+        //  Force update navigate up icon by current layout direction
+        final ActionBar actionBar = getSupportActionBar();
+        actionBar.setHomeAsUpIndicator(android.support.v7.appcompat.R.drawable.abc_ic_ab_back_mtrl_am_alpha);
+
         this.lastLocale = newLocale;
 
         if (isMultiPane()) {
             // This takes care of the left pane.
             invalidateHeaders();
 
             // Detach and reattach the current prefs pane so that it
             // reflects the new locale.
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
@@ -354,16 +354,17 @@ public abstract class BrowserToolbar ext
         this.progressBar = progressBar;
     }
 
     public void setTabHistoryController(TabHistoryController tabHistoryController) {
         this.tabHistoryController = tabHistoryController;
     }
 
     public void refresh() {
+        progressBar.setImageDrawable(getResources().getDrawable(R.drawable.progress));
         urlDisplayLayout.dismissSiteIdentityPopup();
     }
 
     public boolean onBackPressed() {
         // If we exit editing mode during the animation,
         // we're put into an inconsistent state (bug 1017276).
         if (isEditing() && !isAnimating()) {
             Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL,
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbarTabletBase.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbarTabletBase.java
@@ -123,16 +123,23 @@ abstract class BrowserToolbarTabletBase 
     @Override
     protected void updateNavigationButtons(final Tab tab) {
         backButton.setEnabled(canDoBack(tab));
         animateForwardButton(
                 canDoForward(tab) ? ForwardButtonAnimation.SHOW : ForwardButtonAnimation.HIDE);
     }
 
     @Override
+    public void refresh() {
+        super.refresh();
+        forwardButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_menu_forward));
+        backButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_menu_back));
+    }
+
+    @Override
     public void setNextFocusDownId(int nextId) {
         super.setNextFocusDownId(nextId);
         backButton.setNextFocusDownId(nextId);
         forwardButton.setNextFocusDownId(nextId);
     }
 
     @Override
     public void setPrivateMode(final boolean isPrivate) {
--- a/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
@@ -1,23 +1,27 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 package org.mozilla.gecko.util;
 
 import android.content.res.TypedArray;
 import android.os.Build;
+import android.support.v4.text.TextUtilsCompat;
 import android.support.v4.view.MarginLayoutParamsCompat;
+import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewGroup;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.R;
 
+import java.util.Locale;
+
 public class ViewUtil {
 
     /**
      * Enable a circular touch ripple for a given view. This is intended for borderless views,
      * such as (3-dot) menu buttons.
      *
      * Because of platform limitations a square ripple is used on Android 4.
      */
@@ -46,9 +50,26 @@ public class ViewUtil {
                 layoutParams.rightMargin = marginStart;
             } else {
                 layoutParams.leftMargin = marginStart;
             }
         } else {
             MarginLayoutParamsCompat.setMarginStart(layoutParams, marginStart);
         }
     }
+
+    /**
+     * Force set layout direction to RTL or LTR by Locale.
+     * @param view
+     * @param locale
+     */
+    public static void setLayoutDirection(View view, Locale locale) {
+        switch (TextUtilsCompat.getLayoutDirectionFromLocale(locale)) {
+            case ViewCompat.LAYOUT_DIRECTION_RTL:
+                ViewCompat.setLayoutDirection(view, ViewCompat.LAYOUT_DIRECTION_RTL);
+                break;
+            case ViewCompat.LAYOUT_DIRECTION_LTR:
+            default:
+                ViewCompat.setLayoutDirection(view, ViewCompat.LAYOUT_DIRECTION_LTR);
+                break;
+        }
+    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/widget/FadedSingleColorTextView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/FadedSingleColorTextView.java
@@ -4,54 +4,63 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.widget;
 
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.LinearGradient;
 import android.graphics.Shader;
-import android.support.v4.view.ViewCompat;
+import android.support.v4.text.BidiFormatter;
 import android.util.AttributeSet;
 import android.view.View;
 
 /**
  * Fades the end of the text by gecko:fadeWidth amount,
  * if the text is too long and requires an ellipsis.
  *
  * This implementation is an improvement over Android's built-in fadingEdge
  * and the fastest of Fennec's implementations. However, it only works for
  * text of one color. It works by applying a linear gradient directly to the text.
  */
 public class FadedSingleColorTextView extends FadedTextView {
     // Shader for the fading edge.
     private FadedTextGradient mTextGradient;
+    private boolean mIsTextDirectionRtl;
 
     public FadedSingleColorTextView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     private void updateGradientShader() {
         final int color = getCurrentTextColor();
         final int width = getAvailableWidth();
 
         final boolean needsNewGradient = (mTextGradient == null ||
                                           mTextGradient.getColor() != color ||
                                           mTextGradient.getWidth() != width);
 
         final boolean needsEllipsis = needsEllipsis();
         if (needsEllipsis && needsNewGradient) {
-            final boolean isRTL = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
-            mTextGradient = new FadedTextGradient(width, fadeWidth, color, isRTL);
+            mTextGradient = new FadedTextGradient(width, fadeWidth, color, mIsTextDirectionRtl);
         }
 
         getPaint().setShader(needsEllipsis ? mTextGradient : null);
     }
 
     @Override
+    public void setText(CharSequence text, BufferType type) {
+        super.setText(text, type);
+        mIsTextDirectionRtl = BidiFormatter.getInstance().isRtl((String) text);
+        if (mIsTextDirectionRtl) {
+            setTextDirection(TEXT_DIRECTION_RTL);
+        }
+    }
+
+    @Override
     public void onDraw(Canvas canvas) {
         updateGradientShader();
         super.onDraw(canvas);
     }
 
     private static class FadedTextGradient extends LinearGradient {
         private final int mWidth;
         private final int mColor;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -342,18 +342,19 @@ pref("media.mp4.enabled", true);
 // decoder works on all platforms.
 pref("media.use-blank-decoder", false);
 #ifdef MOZ_WMF
 pref("media.wmf.enabled", true);
 pref("media.wmf.decoder.thread-count", -1);
 pref("media.wmf.low-latency.enabled", false);
 pref("media.wmf.skip-blacklist", false);
 pref("media.wmf.vp9.enabled", true);
+pref("media.wmf.allow-unsupported-resolutions", false);
 pref("media.windows-media-foundation.allow-d3d11-dxva", true);
-pref("media.wmf.disable-d3d11-for-dlls", "igd11dxva64.dll: 20.19.15.4463, 20.19.15.4454, 20.19.15.4444, 20.19.15.4416, 20.19.15.4390, 20.19.15.4380, 20.19.15.4377, 20.19.15.4364, 20.19.15.4360, 20.19.15.4352, 20.19.15.4331, 20.19.15.4326, 20.19.15.4300; igd10iumd32.dll: 20.19.15.4444, 20.19.15.4424, 20.19.15.4409, 20.19.15.4390, 20.19.15.4380, 20.19.15.4360, 10.18.10.4358, 20.19.15.4331, 20.19.15.4312, 20.19.15.4300, 10.18.15.4281, 10.18.15.4279, 10.18.10.4276, 10.18.15.4268, 10.18.15.4256, 10.18.10.4252, 10.18.15.4248, 10.18.14.4112, 10.18.10.3958, 10.18.10.3496, 10.18.10.3431, 10.18.10.3412, 10.18.10.3355, 9.18.10.3234, 9.18.10.3071, 9.18.10.3055, 9.18.10.3006; igd10umd32.dll: 9.17.10.4229, 9.17.10.3040, 9.17.10.2857, 8.15.10.2274, 8.15.10.2272, 8.15.10.2246, 8.15.10.1840, 8.15.10.1808; igd10umd64.dll: 9.17.10.4229, 9.17.10.2857, 10.18.10.3496; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215, 1.0.10.1224; tosqep64.dll: 1.1.12.201, 1.0.11.215; nvwgf2um.dll: 10.18.13.6510, 10.18.13.5891, 10.18.13.5887, 10.18.13.5582, 10.18.13.5382, 9.18.13.4195, 9.18.13.3165; atidxx32.dll: 21.19.151.3, 21.19.137.1, 21.19.134.1, 20.19.0.32837, 20.19.0.32832, 8.17.10.682, 8.17.10.671, 8.17.10.661, 8.17.10.648, 8.17.10.644, 8.17.10.625, 8.17.10.605, 8.17.10.581, 8.17.10.569, 8.17.10.560, 8.17.10.545, 8.17.10.539, 8.17.10.531, 8.17.10.525, 8.17.10.520, 8.17.10.519, 8.17.10.514, 8.17.10.511, 8.17.10.494, 8.17.10.489, 8.17.10.483, 8.17.10.453, 8.17.10.451, 8.17.10.441, 8.17.10.436, 8.17.10.432, 8.17.10.425, 8.17.10.418, 8.17.10.414, 8.17.10.401, 8.17.10.395, 8.17.10.385, 8.17.10.378, 8.17.10.362, 8.17.10.355, 8.17.10.342, 8.17.10.331, 8.17.10.318, 8.17.10.310, 8.17.10.286, 8.17.10.269, 8.17.10.261, 8.17.10.247, 8.17.10.240, 8.15.10.212; atidxx64.dll: 21.19.151.3, 21.19.137.1, 21.19.134.1, 20.19.0.32832, 8.17.10.682, 8.17.10.661, 8.17.10.644, 8.17.10.625; nvumdshim.dll: 10.18.13.6822");
+pref("media.wmf.disable-d3d11-for-dlls", "igd11dxva64.dll: 20.19.15.4463, 20.19.15.4454, 20.19.15.4444, 20.19.15.4416, 20.19.15.4404, 20.19.15.4390, 20.19.15.4380, 20.19.15.4377, 20.19.15.4364, 20.19.15.4360, 20.19.15.4352, 20.19.15.4331, 20.19.15.4326, 20.19.15.4300; igd10iumd32.dll: 20.19.15.4444, 20.19.15.4424, 20.19.15.4409, 20.19.15.4390, 20.19.15.4380, 20.19.15.4360, 10.18.10.4358, 20.19.15.4331, 20.19.15.4312, 20.19.15.4300, 10.18.15.4281, 10.18.15.4279, 10.18.10.4276, 10.18.15.4268, 10.18.15.4256, 10.18.10.4252, 10.18.15.4248, 10.18.14.4112, 10.18.10.3958, 10.18.10.3496, 10.18.10.3431, 10.18.10.3412, 10.18.10.3355, 9.18.10.3234, 9.18.10.3071, 9.18.10.3055, 9.18.10.3006; igd10umd32.dll: 9.17.10.4229, 9.17.10.3040, 9.17.10.2857, 8.15.10.2274, 8.15.10.2272, 8.15.10.2246, 8.15.10.1840, 8.15.10.1808; igd10umd64.dll: 9.17.10.4229, 9.17.10.2857, 10.18.10.3496; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215, 1.0.10.1224; tosqep64.dll: 1.1.12.201, 1.0.11.215; nvwgf2um.dll: 10.18.13.6510, 10.18.13.5891, 10.18.13.5887, 10.18.13.5582, 10.18.13.5382, 9.18.13.4195, 9.18.13.3165; atidxx32.dll: 21.19.151.3, 21.19.137.1, 21.19.134.1, 20.19.0.32837, 20.19.0.32832, 8.17.10.682, 8.17.10.671, 8.17.10.661, 8.17.10.648, 8.17.10.644, 8.17.10.625, 8.17.10.605, 8.17.10.581, 8.17.10.569, 8.17.10.560, 8.17.10.545, 8.17.10.539, 8.17.10.531, 8.17.10.525, 8.17.10.520, 8.17.10.519, 8.17.10.514, 8.17.10.511, 8.17.10.494, 8.17.10.489, 8.17.10.483, 8.17.10.453, 8.17.10.451, 8.17.10.441, 8.17.10.436, 8.17.10.432, 8.17.10.425, 8.17.10.418, 8.17.10.414, 8.17.10.401, 8.17.10.395, 8.17.10.385, 8.17.10.378, 8.17.10.362, 8.17.10.355, 8.17.10.342, 8.17.10.331, 8.17.10.318, 8.17.10.310, 8.17.10.286, 8.17.10.269, 8.17.10.261, 8.17.10.247, 8.17.10.240, 8.15.10.212; atidxx64.dll: 21.19.151.3, 21.19.137.1, 21.19.134.1, 20.19.0.32832, 8.17.10.682, 8.17.10.661, 8.17.10.644, 8.17.10.625; nvumdshim.dll: 10.18.13.6822");
 pref("media.wmf.disable-d3d9-for-dlls", "igdumd64.dll: 8.15.10.2189, 8.15.10.2119, 8.15.10.2104, 8.15.10.2102, 8.771.1.0; atiumd64.dll: 7.14.10.833, 7.14.10.867, 7.14.10.885, 7.14.10.903, 7.14.10.911, 8.14.10.768, 9.14.10.1001, 9.14.10.1017, 9.14.10.1080, 9.14.10.1128, 9.14.10.1162, 9.14.10.1171, 9.14.10.1183, 9.14.10.1197, 9.14.10.945, 9.14.10.972, 9.14.10.984, 9.14.10.996");
 #endif
 #if defined(MOZ_FFMPEG)
 #if defined(XP_MACOSX)
 pref("media.ffmpeg.enabled", false);
 #else
 pref("media.ffmpeg.enabled", true);
 #endif
@@ -604,16 +605,19 @@ pref("layers.amd-switchable-gfx.enabled"
 pref("layers.async-pan-zoom.enabled", true);
 
 // Whether to enable event region building during painting
 pref("layout.event-regions.enabled", false);
 
 // Whether to enable arbitrary layer geometry for OpenGL compositor
 pref("layers.geometry.opengl.enabled", true);
 
+// Whether to enable arbitrary layer geometry for Basic compositor
+pref("layers.geometry.basic.enabled", true);
+
 // APZ preferences. For documentation/details on what these prefs do, check
 // gfx/layers/apz/src/AsyncPanZoomController.cpp.
 pref("apz.allow_checkerboarding", true);
 pref("apz.allow_immediate_handoff", true);
 pref("apz.allow_zooming", false);
 
 // Whether to lock touch scrolling to one axis at a time
 // 0 = FREE (No locking at all)
@@ -5522,17 +5526,22 @@ pref("dom.maxHardwareConcurrency", 16);
 pref("osfile.reset_worker_delay", 30000);
 #endif
 
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
 pref("dom.webkitBlink.dirPicker.enabled", true);
 pref("dom.webkitBlink.filesystem.enabled", true);
 #endif
 
+#ifdef NIGHTLY_BUILD
 pref("media.block-autoplay-until-in-foreground", true);
+#else
+pref("media.block-autoplay-until-in-foreground", false);
+#endif
+
 #ifdef MOZ_STYLO
 // Is the Servo-backed style system enabled?
 pref("layout.css.servo.enabled", true);
 #endif
 
 // HSTS Priming
 // If a request is mixed-content, send an HSTS priming request to attempt to
 // see if it is available over HTTPS.
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -1576,17 +1576,17 @@ nsHttpChannel::ProcessSingleSecurityHead
     nsAutoCString securityHeader;
     nsresult rv = mResponseHead->GetHeader(atom, securityHeader);
     if (NS_SUCCEEDED(rv)) {
         nsISiteSecurityService* sss = gHttpHandler->GetSSService();
         NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
         // Process header will now discard the headers itself if the channel
         // wasn't secure (whereas before it had to be checked manually)
         uint32_t failureResult;
-        rv = sss->ProcessHeader(aType, mURI, securityHeader.get(), aSSLStatus,
+        rv = sss->ProcessHeader(aType, mURI, securityHeader, aSSLStatus,
                                 aFlags, nullptr, nullptr, &failureResult);
         if (NS_FAILED(rv)) {
             nsAutoString consoleErrorCategory;
             nsAutoString consoleErrorTag;
             switch (aType) {
                 case nsISiteSecurityService::HEADER_HSTS:
                     GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
                     consoleErrorCategory = NS_LITERAL_STRING("Invalid HSTS Headers");
--- a/security/manager/ssl/ContentSignatureVerifier.cpp
+++ b/security/manager/ssl/ContentSignatureVerifier.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Unused.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsISupportsPriority.h"
 #include "nsIURI.h"
 #include "nsNSSComponent.h"
+#include "nsPromiseFlatString.h"
 #include "nsSecurityHeaderParser.h"
 #include "nsStreamUtils.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsXPCOMStrings.h"
 #include "nssb64.h"
 #include "pkix/pkix.h"
 #include "pkix/pkixtypes.h"
 #include "secerr.h"
@@ -428,17 +429,18 @@ nsresult
 ContentSignatureVerifier::ParseContentSignatureHeader(
   const nsACString& aContentSignatureHeader)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // We only support p384 ecdsa according to spec
   NS_NAMED_LITERAL_CSTRING(signature_var, "p384ecdsa");
   NS_NAMED_LITERAL_CSTRING(certChainURL_var, "x5u");
 
-  nsSecurityHeaderParser parser(aContentSignatureHeader.BeginReading());
+  const nsCString& flatHeader = PromiseFlatCString(aContentSignatureHeader);
+  nsSecurityHeaderParser parser(flatHeader);
   nsresult rv = parser.Parse();
   if (NS_FAILED(rv)) {
     CSVerifier_LOG(("CSVerifier: could not parse ContentSignature header\n"));
     return NS_ERROR_FAILURE;
   }
   LinkedList<nsSecurityHeaderDirective>* directives = parser.GetDirectives();
 
   for (nsSecurityHeaderDirective* directive = directives->getFirst();
--- a/security/manager/ssl/ContentSignatureVerifier.h
+++ b/security/manager/ssl/ContentSignatureVerifier.h
@@ -8,16 +8,17 @@
 #ifndef ContentSignatureVerifier_h
 #define ContentSignatureVerifier_h
 
 #include "cert.h"
 #include "CSTrustDomain.h"
 #include "nsIContentSignatureVerifier.h"
 #include "nsIStreamListener.h"
 #include "nsNSSShutDown.h"
+#include "nsString.h"
 #include "ScopedNSSTypes.h"
 
 // 45a5fe2f-c350-4b86-962d-02d5aaaa955a
 #define NS_CONTENTSIGNATUREVERIFIER_CID \
   { 0x45a5fe2f, 0xc350, 0x4b86, \
     { 0x96, 0x2d, 0x02, 0xd5, 0xaa, 0xaa, 0x95, 0x5a } }
 #define NS_CONTENTSIGNATUREVERIFIER_CONTRACTID \
     "@mozilla.org/security/contentsignatureverifier;1"
--- a/security/manager/ssl/PublicKeyPinningService.cpp
+++ b/security/manager/ssl/PublicKeyPinningService.cpp
@@ -4,16 +4,17 @@
 
 #include "PublicKeyPinningService.h"
 
 #include "RootCertificateTelemetryUtils.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Telemetry.h"
+#include "nsDependentString.h"
 #include "nsISiteSecurityService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsSiteSecurityService.h"
 #include "nssb64.h"
 #include "pkix/pkixtypes.h"
 #include "seccomon.h"
 #include "sechash.h"
 
@@ -176,18 +177,18 @@ FindPinningInformation(const char* hostn
   while (!foundEntry && (evalPart = strchr(evalHost, '.'))) {
     MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
            ("pkpin: Querying pinsets for host: '%s'\n", evalHost));
     // Attempt dynamic pins first
     nsresult rv;
     bool found;
     bool includeSubdomains;
     nsTArray<nsCString> pinArray;
-    rv = sssService->GetKeyPinsForHostname(evalHost, time, pinArray,
-                                           &includeSubdomains, &found);
+    rv = sssService->GetKeyPinsForHostname(nsDependentCString(evalHost), time,
+                                           pinArray, &includeSubdomains, &found);
     if (NS_FAILED(rv)) {
       return rv;
     }
     if (found && (evalHost == hostname || includeSubdomains)) {
       MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
              ("pkpin: Found dyn match for host: '%s'\n", evalHost));
       dynamicFingerprints = pinArray;
       return NS_OK;
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -507,28 +507,28 @@ CertErrorRunnable::CheckCertOverrides()
   if (!sss) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p][%p] couldn't get nsISiteSecurityService to check for HSTS/HPKP\n",
             mFdForLogging, this));
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
   nsresult nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS,
-                                    mInfoObject->GetHostNameRaw(),
+                                    mInfoObject->GetHostName(),
                                     mProviderFlags,
                                     nullptr,
                                     &strictTransportSecurityEnabled);
   if (NS_FAILED(nsrv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p][%p] checking for HSTS failed\n", mFdForLogging, this));
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
   nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HPKP,
-                           mInfoObject->GetHostNameRaw(),
+                           mInfoObject->GetHostName(),
                            mProviderFlags,
                            nullptr,
                            &hasPinningInformation);
   if (NS_FAILED(nsrv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p][%p] checking for HPKP failed\n", mFdForLogging, this));
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
--- a/security/manager/ssl/ScopedNSSTypes.h
+++ b/security/manager/ssl/ScopedNSSTypes.h
@@ -13,17 +13,16 @@
 #include <limits>
 #include <memory>
 
 #include "cert.h"
 #include "cms.h"
 #include "cryptohi.h"
 #include "keyhi.h"
 #include "mozilla/Likely.h"
-#include "mozilla/Scoped.h"
 #include "mozilla/UniquePtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "NSSErrorsService.h"
 #include "pk11pub.h"
 #include "pkcs12.h"
 #include "prerror.h"
 #include "prio.h"
@@ -52,22 +51,16 @@ MapSECStatus(SECStatus rv)
 {
   if (rv == SECSuccess) {
     return NS_OK;
   }
 
   return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
 }
 
-// Alphabetical order by NSS type
-// Deprecated: use the equivalent UniquePtr templates instead.
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificate,
-                                          CERTCertificate,
-                                          CERT_DestroyCertificate)
-
 namespace internal {
 
 inline void
 PK11_DestroyContext_true(PK11Context * ctx) {
   PK11_DestroyContext(ctx, true);
 }
 
 } // namespace internal
@@ -171,23 +164,16 @@ private:
 
     return NS_OK;
   }
 
   uint8_t mItemBuf[HASH_LENGTH_MAX];
   SECItem mItem;
 };
 
-// Deprecated: use the equivalent UniquePtr templates instead.
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SlotInfo,
-                                          PK11SlotInfo,
-                                          PK11_FreeSlot)
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SymKey,
-                                          PK11SymKey,
-                                          PK11_FreeSymKey)
 namespace internal {
 
 inline void
 PORT_FreeArena_false(PLArenaPool* arena)
 {
   // PL_FreeArenaPool can't be used because it doesn't actually free the
   // memory, which doesn't work well with memory analysis tools.
   return PORT_FreeArena(arena, false);
@@ -272,30 +258,16 @@ inline void SECKEYEncryptedPrivateKeyInf
 
 inline void VFY_DestroyContext_true(VFYContext * ctx)
 {
   VFY_DestroyContext(ctx, true);
 }
 
 } // namespace internal
 
-// Deprecated: use the equivalent UniquePtr templates instead.
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECItem,
-                                          SECItem,
-                                          internal::SECITEM_FreeItem_true)
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPrivateKey,
-                                          SECKEYPrivateKey,
-                                          SECKEY_DestroyPrivateKey)
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYEncryptedPrivateKeyInfo,
-                                          SECKEYEncryptedPrivateKeyInfo,
-                                          internal::SECKEYEncryptedPrivateKeyInfo_true)
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPublicKey,
-                                          SECKEYPublicKey,
-                                          SECKEY_DestroyPublicKey)
-
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificate,
                                       CERTCertificate,
                                       CERT_DestroyCertificate)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateList,
                                       CERTCertificateList,
                                       CERT_DestroyCertificateList)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificatePolicies,
                                       CERTCertificatePolicies,
--- a/security/manager/ssl/nsISiteSecurityService.idl
+++ b/security/manager/ssl/nsISiteSecurityService.idl
@@ -55,45 +55,45 @@ interface nsISiteSecurityService : nsISu
      * upgraded to HTTPS.
      * The format of the HPKP header is defined by the HPKP specification:
      * https://tools.ietf.org/html/rfc7469
      * and allows a host to specify a subset of trusted anchors to be used
      * in future HTTPS connections.
      *
      * @param aType the type of security header in question.
      * @param aSourceURI the URI of the resource with the HTTP header.
-     * @param aSSLStatus the SSLStatus of the current channel
      * @param aHeader the HTTP response header specifying security data.
+     * @param aSSLStatus the SSLStatus of the current channel.
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
      * @param aMaxAge the parsed max-age directive of the header.
      * @param aIncludeSubdomains the parsed includeSubdomains directive.
      * @param aFailureResult a more specific failure result if NS_ERROR_FAILURE
                              was returned.
      * @return NS_OK            if it succeeds
      *         NS_ERROR_FAILURE if it can't be parsed
      *         NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
      *                          if there are unrecognized tokens in the header.
      */
     void processHeader(in uint32_t aType,
                        in nsIURI aSourceURI,
-                       in string aHeader,
+                       in ACString aHeader,
                        in nsISSLStatus aSSLStatus,
                        in uint32_t aFlags,
                        [optional] out unsigned long long aMaxAge,
                        [optional] out boolean aIncludeSubdomains,
                        [optional] out uint32_t aFailureResult);
 
     /**
      * Same as processHeader but without checking for the security properties
      * of the connection. Use ONLY for testing.
      */
     void unsafeProcessHeader(in uint32_t aType,
                              in nsIURI aSourceURI,
-                             in string aHeader,
+                             in ACString aHeader,
                              in uint32_t aFlags,
                              [optional] out unsigned long long aMaxAge,
                              [optional] out boolean aIncludeSubdomains,
                              [optional] out uint32_t aFailureResult);
 
     /**
      * Given a header type, removes state relating to that header of a host,
      * including the includeSubdomains state that would affect subdomains.
@@ -114,17 +114,17 @@ interface nsISiteSecurityService : nsISu
      * @param aType the type of security state in question.
      * @param aHost the hostname (punycode) to query for state.
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
      * @param aCached true if we have cached information regarding whether or not
      *                  the host is HSTS, false otherwise.
      */
     boolean isSecureHost(in uint32_t aType,
-                         in string aHost,
+                         in ACString aHost,
                          in uint32_t aFlags,
                          [optional] out boolean aCached);
 
     /**
      * Checks whether or not the URI's hostname has a given security state set.
      * For example, for HSTS:
      * The URI is an HSTS URI if either the host has the HSTS state set, or one
      * of its super-domains has the HSTS "includeSubdomains" flag set.
@@ -154,24 +154,24 @@ interface nsISiteSecurityService : nsISu
     void clearPreloads();
 
     /**
      * Returns an array of sha256-hashed key pins for the given domain, if any.
      * If these pins also apply to subdomains of the given domain,
      * aIncludeSubdomains will be true. Pins returned are only for non-built-in
      * pin entries.
      *
-     * @param aHostname the hosname (punycode) to be queried about
-     * @param the time at which the pins should be valid. This is in
+     * @param aHostname the hostname (punycode) to be queried about
+     * @param evalTime the time at which the pins should be valid. This is in
               mozilla::pkix::Time which uses internally seconds since 0 AD.
      * @param aPinArray the set of sha256-hashed key pins for the given domain
      * @param aIncludeSubdomains true if the pins apply to subdomains of the
      *        given domain
      */
-    [noscript] boolean getKeyPinsForHostname(in string aHostname,
+    [noscript] boolean getKeyPinsForHostname(in ACString aHostname,
                                              in mozillaPkixTime evalTime,
                                              out nsCStringTArrayRef aPinArray,
                                              out boolean aIncludeSubdomains);
 
     /**
      * Set public-key pins for a host. The resulting pins will be permanent
      * and visible from private and non-private contexts. These pins replace
      * any already set by this mechanism or those built-in to Gecko.
@@ -179,32 +179,32 @@ interface nsISiteSecurityService : nsISu
      * @param aHost the hostname (punycode) that pins will apply to
      * @param aIncludeSubdomains whether these pins also apply to subdomains
      * @param aExpires the time this pin should expire (millis since epoch)
      * @param aPinCount number of keys being pinnned
      * @param aSha256Pins array of hashed key fingerprints (SHA-256, base64)
      * @param aIsPreload are these key pins for a preload entry? (false by
      *        default)
      */
-     boolean setKeyPins(in string aHost, in boolean aIncludeSubdomains,
+     boolean setKeyPins(in ACString aHost, in boolean aIncludeSubdomains,
                         in int64_t aExpires, in unsigned long aPinCount,
                         [array, size_is(aPinCount)] in string aSha256Pins,
                         [optional] in boolean aIsPreload);
 
     /**
      * Set an HSTS preload entry for a host. The resulting entries will be
      * permanent and visible from private and non-private contexts. These
      * entries replace any already set by this mechanism or those built-in to
      * Gecko.
      *
      * @param aHost the hostname (punycode) that the entry applies to
      * @param aIncludeSubdomains whether this entry also applies to subdomains
      * @param aExpires the time this entry should expire (millis since epoch)
      */
-     boolean setHSTSPreload(in string aHost, in boolean aIncludesSubdomains,
+     boolean setHSTSPreload(in ACString aHost, in boolean aIncludesSubdomains,
                             in int64_t aExpires);
 
     /**
      * Mark a host as declining to provide a given security state so that features
      * such as HSTS priming will not flood a server with requests.
      *
      * @param aURI the nsIURI that this applies to
      * @param aMaxAge lifetime (in seconds) of this negative cache
--- a/security/manager/ssl/nsSecurityHeaderParser.cpp
+++ b/security/manager/ssl/nsSecurityHeaderParser.cpp
@@ -45,18 +45,18 @@ bool
 IsQuotedPairSymbol(signed char chr) {
   return (chr >= 0);
 }
 
 static mozilla::LazyLogModule sSHParserLog("nsSecurityHeaderParser");
 
 #define SHPARSERLOG(args) MOZ_LOG(sSHParserLog, mozilla::LogLevel::Debug, args)
 
-nsSecurityHeaderParser::nsSecurityHeaderParser(const char *aHeader)
-  : mCursor(aHeader)
+nsSecurityHeaderParser::nsSecurityHeaderParser(const nsCString& aHeader)
+  : mCursor(aHeader.get())
   , mError(false)
 {
 }
 
 nsSecurityHeaderParser::~nsSecurityHeaderParser() {
   nsSecurityHeaderDirective *directive;
   while ((directive = mDirectives.popFirst())) {
     delete directive;
--- a/security/manager/ssl/nsSecurityHeaderParser.h
+++ b/security/manager/ssl/nsSecurityHeaderParser.h
@@ -1,18 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsSecurityHeaderParser_h__
-#define nsSecurityHeaderParser_h__
+#ifndef nsSecurityHeaderParser_h
+#define nsSecurityHeaderParser_h
 
-#include "nsString.h"
 #include "mozilla/LinkedList.h"
 #include "nsCOMPtr.h"
+#include "nsString.h"
 
 // Utility class for handing back parsed directives and (optional) values
 class nsSecurityHeaderDirective : public mozilla::LinkedListElement<nsSecurityHeaderDirective> {
 public:
   nsCString mName;
   nsCString mValue;
 };
 
@@ -31,17 +31,19 @@ public:
 //
 //   token          = <token, defined in [RFC2616], Section 2.2>
 //   quoted-string  = <quoted-string, defined in [RFC2616], Section 2.2>/
 //
 // For further reference, see [RFC6797], Section 6.1
 
 class nsSecurityHeaderParser {
 public:
-  explicit nsSecurityHeaderParser(const char *aHeader);
+  // The input to this class must be null-terminated, and must have a lifetime
+  // greater than or equal to the lifetime of the created nsSecurityHeaderParser.
+  explicit nsSecurityHeaderParser(const nsCString& aHeader);
   ~nsSecurityHeaderParser();
 
   // Only call Parse once.
   nsresult Parse();
   // The caller does not take ownership of the memory returned here.
   mozilla::LinkedList<nsSecurityHeaderDirective> *GetDirectives();
 
 private:
@@ -66,9 +68,9 @@ private:
   mozilla::LinkedList<nsSecurityHeaderDirective> mDirectives;
   const char *mCursor;
   nsSecurityHeaderDirective *mDirective;
 
   nsCString mOutput;
   bool mError;
 };
 
-#endif /* nsSecurityHeaderParser_h__ */
+#endif // nsSecurityHeaderParser_h
--- a/security/manager/ssl/nsSiteSecurityService.cpp
+++ b/security/manager/ssl/nsSiteSecurityService.cpp
@@ -16,21 +16,20 @@
 #include "mozilla/Preferences.h"
 #include "nsCRTGlue.h"
 #include "nsISSLStatus.h"
 #include "nsISocketProvider.h"
 #include "nsIURI.h"
 #include "nsIX509Cert.h"
 #include "nsNSSComponent.h"
 #include "nsNetUtil.h"
+#include "nsPromiseFlatString.h"
 #include "nsSecurityHeaderParser.h"
-#include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
-#include "pkix/pkixtypes.h"
 #include "plstr.h"
 #include "prnetdb.h"
 #include "prprf.h"
 
 // A note about the preload list:
 // When a site specifically disables HSTS by sending a header with
 // 'max-age: 0', we keep a "knockout" value that means "we have no information
 // regarding the HSTS state of this host" (any ancestor of "this host" can still
@@ -431,71 +430,76 @@ nsSiteSecurityService::RemoveState(uint3
                                    uint32_t aFlags)
 {
   nsAutoCString hostname;
   GetHost(aURI, hostname);
   return RemoveStateInternal(aType, hostname, aFlags, false);
 }
 
 static bool
-HostIsIPAddress(const char *hostname)
+HostIsIPAddress(const nsCString& hostname)
 {
   PRNetAddr hostAddr;
-  return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
+  PRErrorCode prv = PR_StringToNetAddr(hostname.get(), &hostAddr);
+  return (prv == PR_SUCCESS);
 }
 
 NS_IMETHODIMP
 nsSiteSecurityService::ProcessHeader(uint32_t aType,
                                      nsIURI* aSourceURI,
-                                     const char* aHeader,
+                                     const nsACString& aHeader,
                                      nsISSLStatus* aSSLStatus,
                                      uint32_t aFlags,
                                      uint64_t* aMaxAge,
                                      bool* aIncludeSubdomains,
                                      uint32_t* aFailureResult)
 {
-   // Child processes are not allowed direct access to this.
-   if (!XRE_IsParentProcess()) {
-     MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ProcessHeader");
-   }
+  // Child processes are not allowed direct access to this.
+  if (!XRE_IsParentProcess()) {
+    MOZ_CRASH("Child process: no direct access to "
+              "nsISiteSecurityService::ProcessHeader");
+  }
 
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
   NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
                  aType == nsISiteSecurityService::HEADER_HPKP,
                  NS_ERROR_NOT_IMPLEMENTED);
 
   NS_ENSURE_ARG(aSSLStatus);
-  return ProcessHeaderInternal(aType, aSourceURI, aHeader, aSSLStatus, aFlags,
-                               aMaxAge, aIncludeSubdomains, aFailureResult);
+  return ProcessHeaderInternal(aType, aSourceURI, PromiseFlatCString(aHeader),
+                               aSSLStatus, aFlags, aMaxAge, aIncludeSubdomains,
+                               aFailureResult);
 }
 
 NS_IMETHODIMP
 nsSiteSecurityService::UnsafeProcessHeader(uint32_t aType,
                                            nsIURI* aSourceURI,
-                                           const char* aHeader,
+                                           const nsACString& aHeader,
                                            uint32_t aFlags,
                                            uint64_t* aMaxAge,
                                            bool* aIncludeSubdomains,
                                            uint32_t* aFailureResult)
 {
-   // Child processes are not allowed direct access to this.
-   if (!XRE_IsParentProcess()) {
-     MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::UnsafeProcessHeader");
-   }
+  // Child processes are not allowed direct access to this.
+  if (!XRE_IsParentProcess()) {
+    MOZ_CRASH("Child process: no direct access to "
+              "nsISiteSecurityService::UnsafeProcessHeader");
+  }
 
-  return ProcessHeaderInternal(aType, aSourceURI, aHeader, nullptr, aFlags,
-                               aMaxAge, aIncludeSubdomains, aFailureResult);
+  return ProcessHeaderInternal(aType, aSourceURI, PromiseFlatCString(aHeader),
+                               nullptr, aFlags, aMaxAge, aIncludeSubdomains,
+                               aFailureResult);
 }
 
 nsresult
 nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
                                              nsIURI* aSourceURI,
-                                             const char* aHeader,
+                                             const nsCString& aHeader,
                                              nsISSLStatus* aSSLStatus,
                                              uint32_t aFlags,
                                              uint64_t* aMaxAge,
                                              bool* aIncludeSubdomains,
                                              uint32_t* aFailureResult)
 {
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
@@ -535,17 +539,17 @@ nsSiteSecurityService::ProcessHeaderInte
        }
       return NS_ERROR_FAILURE;
     }
   }
 
   nsAutoCString host;
   nsresult rv = GetHost(aSourceURI, host);
   NS_ENSURE_SUCCESS(rv, rv);
-  if (HostIsIPAddress(host.get())) {
+  if (HostIsIPAddress(host)) {
     /* Don't process headers if a site is accessed by IP address. */
     return NS_OK;
   }
 
   switch (aType) {
     case nsISiteSecurityService::HEADER_HSTS:
       rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
                             aIncludeSubdomains, aFailureResult);
@@ -557,17 +561,17 @@ nsSiteSecurityService::ProcessHeaderInte
     default:
       MOZ_CRASH("unexpected header type");
   }
   return rv;
 }
 
 static uint32_t
 ParseSSSHeaders(uint32_t aType,
-                const char* aHeader,
+                const nsCString& aHeader,
                 bool& foundIncludeSubdomains,
                 bool& foundMaxAge,
                 bool& foundUnrecognizedDirective,
                 uint64_t& maxAge,
                 nsTArray<nsCString>& sha256keys)
 {
   // Strict transport security and Public Key Pinning have very similar
   // Header formats.
@@ -698,27 +702,27 @@ ParseSSSHeaders(uint32_t aType,
       foundUnrecognizedDirective = true;
     }
   }
   return nsISiteSecurityService::Success;
 }
 
 nsresult
 nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
-                                        const char* aHeader,
+                                        const nsCString& aHeader,
                                         nsISSLStatus* aSSLStatus,
                                         uint32_t aFlags,
                                         uint64_t* aMaxAge,
                                         bool* aIncludeSubdomains,
                                         uint32_t* aFailureResult)
 {
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
-  SSSLOG(("SSS: processing HPKP header '%s'", aHeader));
+  SSSLOG(("SSS: processing HPKP header '%s'", aHeader.get()));
   NS_ENSURE_ARG(aSSLStatus);
 
   const uint32_t aType = nsISiteSecurityService::HEADER_HPKP;
   bool foundMaxAge = false;
   bool foundIncludeSubdomains = false;
   bool foundUnrecognizedDirective = false;
   uint64_t maxAge = 0;
   nsTArray<nsCString> sha256keys;
@@ -872,26 +876,26 @@ nsSiteSecurityService::ProcessPKPHeader(
 
   return foundUnrecognizedDirective
            ? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
            : NS_OK;
 }
 
 nsresult
 nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
-                                        const char* aHeader,
+                                        const nsCString& aHeader,
                                         uint32_t aFlags,
                                         uint64_t* aMaxAge,
                                         bool* aIncludeSubdomains,
                                         uint32_t* aFailureResult)
 {
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
-  SSSLOG(("SSS: processing HSTS header '%s'", aHeader));
+  SSSLOG(("SSS: processing HSTS header '%s'", aHeader.get()));
 
   const uint32_t aType = nsISiteSecurityService::HEADER_HSTS;
   bool foundMaxAge = false;
   bool foundIncludeSubdomains = false;
   bool foundUnrecognizedDirective = false;
   uint64_t maxAge = 0;
   nsTArray<nsCString> unusedSHA256keys; // Required for sane internal interface
 
@@ -960,22 +964,22 @@ nsSiteSecurityService::IsSecureURI(uint3
   NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
                  aType == nsISiteSecurityService::HEADER_HPKP,
                  NS_ERROR_NOT_IMPLEMENTED);
 
   nsAutoCString hostname;
   nsresult rv = GetHost(aURI, hostname);
   NS_ENSURE_SUCCESS(rv, rv);
   /* An IP address never qualifies as a secure URI. */
-  if (HostIsIPAddress(hostname.get())) {
+  if (HostIsIPAddress(hostname)) {
     *aResult = false;
     return NS_OK;
   }
 
-  return IsSecureHost(aType, hostname.get(), aFlags, aCached, aResult);
+  return IsSecureHost(aType, hostname, aFlags, aCached, aResult);
 }
 
 int STSPreloadCompare(const void *key, const void *entry)
 {
   const char *keyStr = (const char *)key;
   const nsSTSPreload *preloadEntry = (const nsSTSPreload *)entry;
   return strcmp(keyStr, &kSTSHostTable[preloadEntry->mHostIndex]);
 }
@@ -1104,61 +1108,64 @@ nsSiteSecurityService::HostHasHSTSEntry(
     }
     return true;
   }
 
   return false;
 }
 
 NS_IMETHODIMP
-nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
+nsSiteSecurityService::IsSecureHost(uint32_t aType, const nsACString& aHost,
                                     uint32_t aFlags, bool* aCached,
                                     bool* aResult)
 {
-   // Child processes are not allowed direct access to this.
-   if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
-     MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureHost for non-HSTS entries");
-   }
+  // Child processes are not allowed direct access to this.
+  if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
+    MOZ_CRASH("Child process: no direct access to "
+              "nsISiteSecurityService::IsSecureHost for non-HSTS entries");
+  }
 
-  NS_ENSURE_ARG(aHost);
   NS_ENSURE_ARG(aResult);
 
   // Only HSTS and HPKP are supported at the moment.
   NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
                  aType == nsISiteSecurityService::HEADER_HPKP,
                  NS_ERROR_NOT_IMPLEMENTED);
 
   // set default in case if we can't find any STS information
   *aResult = false;
   if (aCached) {
     *aCached = false;
   }
 
   /* An IP address never qualifies as a secure URI. */
-  if (HostIsIPAddress(aHost)) {
+  const nsCString& flatHost = PromiseFlatCString(aHost);
+  if (HostIsIPAddress(flatHost)) {
     return NS_OK;
   }
 
   if (aType == nsISiteSecurityService::HEADER_HPKP) {
     RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
     if (!certVerifier) {
       return NS_ERROR_FAILURE;
     }
     if (certVerifier->mPinningMode ==
         CertVerifier::PinningMode::pinningDisabled) {
       return NS_OK;
     }
     bool enforceTestMode = certVerifier->mPinningMode ==
                            CertVerifier::PinningMode::pinningEnforceTestMode;
-    return PublicKeyPinningService::HostHasPins(aHost, mozilla::pkix::Now(),
+    return PublicKeyPinningService::HostHasPins(flatHost.get(),
+                                                mozilla::pkix::Now(),
                                                 enforceTestMode, *aResult);
   }
 
   // Holepunch chart.apis.google.com and subdomains.
-  nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
+  nsAutoCString host(
+    PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
   if (host.EqualsLiteral("chart.apis.google.com") ||
       StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) {
     if (aCached) {
       *aCached = true;
     }
     return NS_OK;
   }
 
@@ -1222,35 +1229,38 @@ nsSiteSecurityService::ClearPreloads()
 }
 
 bool entryStateNotOK(SiteHPKPState& state, mozilla::pkix::Time& aEvalTime) {
   return state.mState != SecurityPropertySet || state.IsExpired(aEvalTime) ||
          state.mSHA256keys.Length() < 1;
 }
 
 NS_IMETHODIMP
-nsSiteSecurityService::GetKeyPinsForHostname(const char* aHostname,
+nsSiteSecurityService::GetKeyPinsForHostname(const nsACString& aHostname,
                                              mozilla::pkix::Time& aEvalTime,
                                              /*out*/ nsTArray<nsCString>& pinArray,
                                              /*out*/ bool* aIncludeSubdomains,
-                                             /*out*/ bool* afound) {
-   // Child processes are not allowed direct access to this.
-   if (!XRE_IsParentProcess()) {
-     MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::GetKeyPinsForHostname");
-   }
+                                             /*out*/ bool* afound)
+{
+  // Child processes are not allowed direct access to this.
+  if (!XRE_IsParentProcess()) {
+    MOZ_CRASH("Child process: no direct access to "
+              "nsISiteSecurityService::GetKeyPinsForHostname");
+  }
 
   NS_ENSURE_ARG(afound);
-  NS_ENSURE_ARG(aHostname);
 
-  SSSLOG(("Top of GetKeyPinsForHostname for %s", aHostname));
+  const nsCString& flatHostname = PromiseFlatCString(aHostname);
+  SSSLOG(("Top of GetKeyPinsForHostname for %s", flatHostname.get()));
   *afound = false;
   *aIncludeSubdomains = false;
   pinArray.Clear();
 
-  nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHostname));
+  nsAutoCString host(
+    PublicKeyPinningService::CanonicalizeHostname(flatHostname.get()));
   nsAutoCString storageKey;
   SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
 
   SSSLOG(("storagekey '%s'\n", storageKey.get()));
   mozilla::DataStorageType storageType = mozilla::DataStorage_Persistent;
   nsCString value = mSiteStateStorage->Get(storageKey, storageType);
 
   // decode now
@@ -1274,28 +1284,29 @@ nsSiteSecurityService::GetKeyPinsForHost
   }
   pinArray = foundEntry.mSHA256keys;
   *aIncludeSubdomains = foundEntry.mIncludeSubdomains;
   *afound = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSiteSecurityService::SetKeyPins(const char* aHost, bool aIncludeSubdomains,
+nsSiteSecurityService::SetKeyPins(const nsACString& aHost,
+                                  bool aIncludeSubdomains,
                                   int64_t aExpires, uint32_t aPinCount,
                                   const char** aSha256Pins,
                                   bool aIsPreload,
                                   /*out*/ bool* aResult)
 {
-   // Child processes are not allowed direct access to this.
-   if (!XRE_IsParentProcess()) {
-     MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::SetKeyPins");
-   }
+  // Child processes are not allowed direct access to this.
+  if (!XRE_IsParentProcess()) {
+    MOZ_CRASH("Child process: no direct access to "
+              "nsISiteSecurityService::SetKeyPins");
+  }
 
-  NS_ENSURE_ARG_POINTER(aHost);
   NS_ENSURE_ARG_POINTER(aResult);
   NS_ENSURE_ARG_POINTER(aSha256Pins);
 
   SSSLOG(("Top of SetKeyPins"));
 
   nsTArray<nsCString> sha256keys;
   for (unsigned int i = 0; i < aPinCount; i++) {
     nsAutoCString pin(aSha256Pins[i]);
@@ -1303,37 +1314,41 @@ nsSiteSecurityService::SetKeyPins(const 
     if (!stringIsBase64EncodingOf256bitValue(pin)) {
       return NS_ERROR_INVALID_ARG;
     }
     sha256keys.AppendElement(pin);
   }
   SiteHPKPState dynamicEntry(aExpires, SecurityPropertySet,
                              aIncludeSubdomains, sha256keys);
   // we always store data in permanent storage (ie no flags)
-  nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
+  const nsCString& flatHost = PromiseFlatCString(aHost);
+  nsAutoCString host(
+    PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
   return SetHPKPState(host.get(), dynamicEntry, 0, aIsPreload);
 }
 
 NS_IMETHODIMP
-nsSiteSecurityService::SetHSTSPreload(const char* aHost,
+nsSiteSecurityService::SetHSTSPreload(const nsACString& aHost,
                                       bool aIncludeSubdomains,
                                       int64_t aExpires,
                               /*out*/ bool* aResult)
 {
-   // Child processes are not allowed direct access to this.
-   if (!XRE_IsParentProcess()) {
-     MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::SetHSTSPreload");
-   }
+  // Child processes are not allowed direct access to this.
+  if (!XRE_IsParentProcess()) {
+    MOZ_CRASH("Child process: no direct access to "
+              "nsISiteSecurityService::SetHSTSPreload");
+  }
 
-  NS_ENSURE_ARG_POINTER(aHost);
   NS_ENSURE_ARG_POINTER(aResult);
 
   SSSLOG(("Top of SetHSTSPreload"));
 
-  nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
+  const nsCString& flatHost = PromiseFlatCString(aHost);
+  nsAutoCString host(
+    PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
   return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, host.get(), aExpires,
                       aIncludeSubdomains, 0, SecurityPropertySet, true);
 }
 
 nsresult
 nsSiteSecurityService::SetHPKPState(const char* aHost, SiteHPKPState& entry,
                                     uint32_t aFlags, bool aIsPreload)
 {
--- a/security/manager/ssl/nsSiteSecurityService.h
+++ b/security/manager/ssl/nsSiteSecurityService.h
@@ -127,24 +127,25 @@ protected:
   virtual ~nsSiteSecurityService();
 
 private:
   nsresult GetHost(nsIURI *aURI, nsACString &aResult);
   nsresult SetHSTSState(uint32_t aType, const char* aHost, int64_t maxage,
                         bool includeSubdomains, uint32_t flags,
                         SecurityPropertyState aHSTSState, bool aIsPreload);
   nsresult ProcessHeaderInternal(uint32_t aType, nsIURI* aSourceURI,
-                                 const char* aHeader, nsISSLStatus* aSSLStatus,
+                                 const nsCString& aHeader,
+                                 nsISSLStatus* aSSLStatus,
                                  uint32_t aFlags, uint64_t* aMaxAge,
                                  bool* aIncludeSubdomains,
                                  uint32_t* aFailureResult);
-  nsresult ProcessSTSHeader(nsIURI* aSourceURI, const char* aHeader,
+  nsresult ProcessSTSHeader(nsIURI* aSourceURI, const nsCString& aHeader,
                             uint32_t flags, uint64_t* aMaxAge,
                             bool* aIncludeSubdomains, uint32_t* aFailureResult);
-  nsresult ProcessPKPHeader(nsIURI* aSourceURI, const char* aHeader,
+  nsresult ProcessPKPHeader(nsIURI* aSourceURI, const nsCString& aHeader,
                             nsISSLStatus* aSSLStatus, uint32_t flags,
                             uint64_t* aMaxAge, bool* aIncludeSubdomains,
                             uint32_t* aFailureResult);
   nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
                         bool aIsPreload);
   nsresult RemoveStateInternal(uint32_t aType, const nsAutoCString& aHost,
                                uint32_t aFlags, bool aIsPreload);
   bool HostHasHSTSEntry(const nsAutoCString& aHost,
--- a/security/manager/ssl/tests/gtest/STSParserTest.cpp
+++ b/security/manager/ssl/tests/gtest/STSParserTest.cpp
@@ -1,32 +1,34 @@
 /* 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 <stdio.h>
 
 #include "gtest/gtest.h"
+#include "nsDependentString.h"
 #include "nsNetUtil.h"
 #include "nsISiteSecurityService.h"
 #include "nsIURI.h"
 
 void
 TestSuccess(const char* hdr, bool extraTokens,
             uint64_t expectedMaxAge, bool expectedIncludeSubdomains,
             nsISiteSecurityService* sss)
 {
   nsCOMPtr<nsIURI> dummyUri;
   nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
   ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to create URI";
 
   uint64_t maxAge = 0;
   bool includeSubdomains = false;
   rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
-                                hdr, 0, &maxAge, &includeSubdomains, nullptr);
+                                nsDependentCString(hdr), 0, &maxAge,
+                                &includeSubdomains, nullptr);
   ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to process valid header: " << hdr;
 
   ASSERT_EQ(maxAge, expectedMaxAge) << "Did not correctly parse maxAge";
   EXPECT_EQ(includeSubdomains, expectedIncludeSubdomains) <<
     "Did not correctly parse presence/absence of includeSubdomains";
 
   if (extraTokens) {
     EXPECT_EQ(rv, NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA) <<
@@ -41,17 +43,18 @@ TestSuccess(const char* hdr, bool extraT
 void TestFailure(const char* hdr,
                  nsISiteSecurityService* sss)
 {
   nsCOMPtr<nsIURI> dummyUri;
   nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
   ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to create URI";
 
   rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
-                                hdr, 0, nullptr, nullptr, nullptr);
+                                nsDependentCString(hdr), 0, nullptr, nullptr,
+                                nullptr);
   ASSERT_TRUE(NS_FAILED(rv)) << "Parsed invalid header: " << hdr;
 
   printf("%s\n", hdr);
 }
 
 TEST(psm_STSParser, Test)
 {
     nsresult rv;
--- a/toolkit/components/extensions/ext-cookies.js
+++ b/toolkit/components/extensions/ext-cookies.js
@@ -422,17 +422,17 @@ extensions.registerSchemaAPI("cookies", 
       getAllCookieStores: function() {
         let data = {};
         for (let window of WindowListManager.browserWindows()) {
           let tabs = TabManager.for(extension).getTabs(window);
           for (let tab of tabs) {
             if (!(tab.cookieStoreId in data)) {
               data[tab.cookieStoreId] = [];
             }
-            data[tab.cookieStoreId].push(tab);
+            data[tab.cookieStoreId].push(tab.id);
           }
         }
 
         let result = [];
         for (let key in data) {
           result.push({id: key, tabIds: data[key], incognito: key == PRIVATE_STORE});
         }
         return Promise.resolve(result);
--- a/toolkit/components/extensions/test/mochitest/test_ext_cookies.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies.html
@@ -80,17 +80,18 @@ add_task(function* test_cookies() {
     assertExpected({url: TEST_URL, name: "name1", storeId: STORE_ID}, details);
 
     cookie = await browser.cookies.get({url: TEST_URL, name: "name1"});
     browser.test.assertEq(null, cookie, "removed cookie not found");
 
     let stores = await browser.cookies.getAllCookieStores();
     browser.test.assertEq(1, stores.length, "expected number of stores returned");
     browser.test.assertEq(STORE_ID, stores[0].id, "expected store id returned");
-    browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for store");
+    browser.test.assertEq(1, stores[0].tabIds.length, "one tabId returned for store");
+    browser.test.assertEq("number", typeof stores[0].tabIds[0], "tabId is a number");
 
     {
       let privateWindow = await browser.windows.create({incognito: true});
       let stores = await browser.cookies.getAllCookieStores();
 
       browser.test.assertEq(2, stores.length, "expected number of stores returned");
       browser.test.assertEq(STORE_ID, stores[0].id, "expected store id returned");
       browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for store");
--- a/toolkit/components/printingui/mac/moz.build
+++ b/toolkit/components/printingui/mac/moz.build
@@ -1,16 +1,13 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 UNIFIED_SOURCES += [
+    'nsPrintingPromptService.cpp',
     'nsPrintProgress.cpp',
     'nsPrintProgressParams.cpp',
 ]
 
-SOURCES += [
-    'nsPrintingPromptServiceX.mm',
-]
-
 FINAL_LIBRARY = 'xul'
rename from toolkit/components/printingui/mac/nsPrintingPromptServiceX.mm
rename to toolkit/components/printingui/mac/nsPrintingPromptService.cpp
--- a/toolkit/components/printingui/mac/nsPrintingPromptServiceX.mm
+++ b/toolkit/components/printingui/mac/nsPrintingPromptService.cpp
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintingPromptService.h"
 
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
-#include "nsObjCExceptions.h"
 
 #include "nsIPrintingPromptService.h"
 #include "nsIFactory.h"
 #include "nsIPrintDialogService.h"
 #include "nsPIDOMWindow.h"
 
 //*****************************************************************************
 // nsPrintingPromptService
@@ -33,28 +32,24 @@ nsresult nsPrintingPromptService::Init()
 
 //*****************************************************************************
 // nsPrintingPromptService::nsIPrintingPromptService
 //*****************************************************************************   
 
 NS_IMETHODIMP 
 nsPrintingPromptService::ShowPrintDialog(mozIDOMWindowProxy *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings)
 {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
   nsCOMPtr<nsIPrintDialogService> dlgPrint(do_GetService(
                                            NS_PRINTDIALOGSERVICE_CONTRACTID));
   if (dlgPrint) {
     return dlgPrint->Show(nsPIDOMWindowOuter::From(parent), printSettings,
                           webBrowserPrint);
   }
 
   return NS_ERROR_FAILURE;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP 
 nsPrintingPromptService::ShowProgress(mozIDOMWindowProxy*      parent,
                                       nsIWebBrowserPrint*      webBrowserPrint,    // ok to be null
                                       nsIPrintSettings*        printSettings,      // ok to be null
                                       nsIObserver*             openDialogObserver, // ok to be null
                                       bool                     isForPrinting,
@@ -63,26 +58,23 @@ nsPrintingPromptService::ShowProgress(mo
                                       bool*                  notifyOnOpen)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP 
 nsPrintingPromptService::ShowPageSetup(mozIDOMWindowProxy *parent, nsIPrintSettings *printSettings, nsIObserver *aObs)
 {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   nsCOMPtr<nsIPrintDialogService> dlgPrint(do_GetService(
                                            NS_PRINTDIALOGSERVICE_CONTRACTID));
   if (dlgPrint) {
     return dlgPrint->ShowPageSetup(nsPIDOMWindowOuter::From(parent), printSettings);
   }
 
   return NS_ERROR_FAILURE;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP 
 nsPrintingPromptService::ShowPrinterProperties(mozIDOMWindowProxy *parent, const char16_t *printerName, nsIPrintSettings *printSettings)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -4170,38 +4170,40 @@
     "alert_emails": ["safebrowsing-telemetry@mozilla.org"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "keyed": true,
     "n_values": 16,
     "bug_numbers": [1311910],
     "description": "Server HTTP status code from SafeBrowsing database updates. (0=1xx, 1=200, 2=2xx, 3=204, 4=3xx, 5=400, 6=4xx, 7=403, 8=404, 9=408, 10=413, 11=5xx, 12=502|504|511, 13=503, 14=505, 15=Other). Keyed by provider"
   },
-  "URLCLASSIFIER_COMPLETE_REMOTE_STATUS": {
+  "URLCLASSIFIER_COMPLETE_REMOTE_STATUS2": {
     "alert_emails": ["safebrowsing-telemetry@mozilla.org"],
     "expires_in_version": "never",
     "kind": "enumerated",
+    "keyed": true,
     "n_values": 16,
-    "bug_numbers": [1150921],
-    "description": "Server HTTP status code from remote SafeBrowsing gethash lookups. (0=1xx, 1=200, 2=2xx, 3=204, 4=3xx, 5=400, 6=4xx, 7=403, 8=404, 9=408, 10=413, 11=5xx, 12=502|504|511, 13=503, 14=505, 15=Other)"
+    "bug_numbers": [1150921, 1311926],
+    "description": "Server HTTP status code from remote SafeBrowsing gethash lookups. (0=1xx, 1=200, 2=2xx, 3=204, 4=3xx, 5=400, 6=4xx, 7=403, 8=404, 9=408, 10=413, 11=5xx, 12=502|504|511, 13=503, 14=505, 15=Other). Keyed by provider"
   },
   "URLCLASSIFIER_COMPLETION_ERROR": {
     "alert_emails": ["safebrowsing-telemetry@mozilla.org"],
     "expires_in_version": "59",
     "kind": "enumerated",
     "n_values": 16,
     "bug_numbers": [1276826],
     "description": "SafeBrowsing v4 hash completion error (0 = success, 1 = parsing failure, 2 = unknown threat type)"
   },
-  "URLCLASSIFIER_COMPLETE_TIMEOUT": {
+  "URLCLASSIFIER_COMPLETE_TIMEOUT2": {
     "alert_emails": ["safebrowsing-telemetry@mozilla.org"],
-    "expires_in_version": "56",
-    "kind": "boolean",
-    "bug_numbers": [1172688],
-    "description": "This metric is recorded every time a gethash lookup is performed, `true` is recorded if the lookup times out."
+    "expires_in_version": "59",
+    "kind": "boolean",
+    "keyed": true,
+    "bug_numbers": [1172688, 1311926],
+    "description": "This metric is recorded every time a gethash lookup is performed, `true` is recorded if the lookup times out. Keyed by provider"
   },
   "URLCLASSIFIER_UPDATE_ERROR": {
     "alert_emails": ["safebrowsing-telemetry@mozilla.org"],
     "expires_in_version": "59",
     "kind": "enumerated",
     "keyed": true,
     "n_values": 16,
     "bug_numbers": [1311910],
--- a/toolkit/components/url-classifier/nsUrlClassifierHashCompleter.js
+++ b/toolkit/components/url-classifier/nsUrlClassifierHashCompleter.js
@@ -285,16 +285,18 @@ function HashCompleterRequest(aCompleter
   this._response = "";
   // Whether we have been informed of a shutdown by the quit-application event.
   this._shuttingDown = false;
   this.gethashUrl = aGethashUrl;
 
   // Multiple partial hashes can be associated with the same tables
   // so we use a map here.
   this.tableNames = new Map();
+
+  this.telemetryProvider = "";
 }
 HashCompleterRequest.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver,
                                          Ci.nsIStreamListener,
                                          Ci.nsIObserver,
                                          Ci.nsISupports]),
 
   // This is called by the HashCompleter to add a hash and callback to the
@@ -311,16 +313,21 @@ HashCompleterRequest.prototype = {
       if (0 === this.tableNames.size) {
         // Decide if this request is v4 by the first added partial hash.
         this.isV4 = isTableNameV4;
       } else if (this.isV4 !== isTableNameV4) {
         log('ERROR: Cannot mix "proto" tables with other types within ' +
             'the same gethash URL.');
       }
       this.tableNames.set(aTableName);
+
+      // Assuming all tables with the same gethash URL have the same provider
+      if (this.telemetryProvider == "") {
+        this.telemetryProvider = gUrlUtil.getTelemetryProvider(aTableName);
+      }
     }
   },
 
   fillTableStatesBase64: function HCR_fillTableStatesBase64(aCallback) {
     gDbService.getTables(aTableData => {
       aTableData.split("\n").forEach(line => {
         let p = line.indexOf(";");
         if (-1 === p) {
@@ -371,17 +378,18 @@ HashCompleterRequest.prototype = {
   },
 
   notify: function HCR_notify() {
     // If we haven't gotten onStopRequest, just cancel. This will call us
     // with onStopRequest since we implement nsIStreamListener on the
     // channel.
     if (this._channel && this._channel.isPending()) {
       log("cancelling request to " + this.gethashUrl + "\n");
-      Services.telemetry.getHistogramById("URLCLASSIFIER_COMPLETE_TIMEOUT").add(1);
+      Services.telemetry.getKeyedHistogramById("URLCLASSIFIER_COMPLETE_TIMEOUT2").
+        add(this.telemetryProvider, 1);
       this._channel.cancel(Cr.NS_BINDING_ABORTED);
     }
   },
 
   // Creates an nsIChannel for the request and fills the body.
   openChannel: function HCR_openChannel() {
     let loadFlags = Ci.nsIChannel.INHIBIT_CACHING |
                     Ci.nsIChannel.LOAD_BYPASS_CACHE;
@@ -659,20 +667,20 @@ HashCompleterRequest.prototype = {
       httpStatus = channel.responseStatus;
       if (!success) {
         aStatusCode = Cr.NS_ERROR_ABORT;
       }
     }
     let success = Components.isSuccessCode(aStatusCode);
     log('Received a ' + httpStatus + ' status code from the gethash server (success=' + success + ').');
 
-    let histogram =
-      Services.telemetry.getHistogramById("URLCLASSIFIER_COMPLETE_REMOTE_STATUS");
-    histogram.add(httpStatusToBucket(httpStatus));
-    Services.telemetry.getHistogramById("URLCLASSIFIER_COMPLETE_TIMEOUT").add(0);
+    Services.telemetry.getKeyedHistogramById("URLCLASSIFIER_COMPLETE_REMOTE_STATUS2").
+      add(this.telemetryProvider, httpStatusToBucket(httpStatus));
+    Services.telemetry.getKeyedHistogramById("URLCLASSIFIER_COMPLETE_TIMEOUT2").
+      add(this.telemetryProvider, 0);
 
     // Notify the RequestBackoff once a response is received.
     this._completer.finishRequest(this.gethashUrl, httpStatus);
 
     if (success) {
       try {
         this.handleResponse();
       }
--- a/widget/cocoa/nsPrintDialogX.mm
+++ b/widget/cocoa/nsPrintDialogX.mm
@@ -179,31 +179,35 @@ nsPrintDialogServiceX::Show(nsPIDOMWindo
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP
 nsPrintDialogServiceX::ShowPageSetup(nsPIDOMWindowOuter *aParent,
                                      nsIPrintSettings *aNSSettings)
 {
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
   NS_PRECONDITION(aParent, "aParent must not be null");
   NS_PRECONDITION(aNSSettings, "aSettings must not be null");
   NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
 
   RefPtr<nsPrintSettingsX> settingsX(do_QueryObject(aNSSettings));
   if (!settingsX)
     return NS_ERROR_FAILURE;
 
   NSPrintInfo* printInfo = settingsX->GetCocoaPrintInfo();
   NSPageLayout *pageLayout = [NSPageLayout pageLayout];
   nsCocoaUtils::PrepareForNativeAppModalDialog();
   int button = [pageLayout runModalWithPrintInfo:printInfo];
   nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
 
   return button == NSFileHandlingPanelOKButton ? NS_OK : NS_ERROR_ABORT;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 // Accessory view
 
 @interface PrintPanelAccessoryView (Private)
 
 - (NSString*)localizedString:(const char*)aKey;
 
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -3,17 +3,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
 if toolkit in ('cocoa', 'android', 'gonk', 'uikit'):
     DIRS += [toolkit]
-if toolkit in ('android', 'gonk', 'gtk2', 'gtk3'):
+if toolkit in ('android', 'cocoa', 'gonk', 'gtk2', 'gtk3'):
     EXPORTS += ['nsIPrintDialogService.h']
 
 if toolkit == 'windows':
     DIRS += ['windows']
 
     XPIDL_SOURCES += [
         'nsIJumpListBuilder.idl',
         'nsIJumpListItem.idl',
@@ -33,17 +33,16 @@ elif toolkit == 'cocoa':
         'nsIMacDockSupport.idl',
         'nsIMacWebAppUtils.idl',
         'nsIStandaloneNativeMenu.idl',
         'nsISystemStatusBar.idl',
         'nsITaskbarProgress.idl',
     ]
     EXPORTS += [
         'nsINativeMenuService.h',
-        'nsIPrintDialogService.h',
     ]
 
 TEST_DIRS += ['tests']
 
 # Don't build the DSO under the 'build' directory as windows does.
 #
 # The DSOs get built in the toolkit dir itself.  Do this so that
 # multiple implementations of widget can be built on the same