merge autoland to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 16 Jan 2017 16:34:19 +0100
changeset 374543 aeda115ca5c37723ec703a2574204952001e40db
parent 374509 7884f9ed756bad6e9d73b8a5adb82d0773daae08 (current diff)
parent 374542 8f52299c4c6366e7d1edfdd4f93aa3f7cfc4eb76 (diff)
child 374564 d4d3a7b6d57e06891f158ccb4bebf507a8d55d32
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge 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