Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 03 Mar 2017 17:29:54 -0800
changeset 394894 b691557cb7a31c942cbdf3c1388140f60c24fdf9
parent 394893 a4cf39b772dfec2ac2710e51f920789672332106 (current diff)
parent 394819 80c06df83395314697d464f88f8daa98bf05465c (diff)
child 394895 ebbc4be47d0a11590992defeba79340bbc3a761c
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.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 m-c to autoland, a=merge MozReview-Commit-ID: K0Q4b2wzvlJ
devtools/client/aboutdebugging/test/head.js
dom/base/test/test_bug793311.html
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-001-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-001.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-002-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-002.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-003-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-003.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-004-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-004.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-005-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-005.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-006.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-007.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-008-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-008.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-009.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-010-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-010.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-011-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-011.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-012.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-013.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-014-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-014.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-015.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-016-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-016.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-017-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-017.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-018-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-018.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-019-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-019.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-020-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-020.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-021-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-021.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-022-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-022.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-023-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-023.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-024-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-024.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-001-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-001.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-002-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-002.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-003-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-003.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-004-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-004.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-005-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-005.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-006-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-006.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-007-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-007.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-008-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-008.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-009-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-009.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-010.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-011-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-011.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-012.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-013-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-013.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-014-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-014.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-015-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-015.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-016-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-016.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-017-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-017.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-018-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-018.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-019-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-019.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-020-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-020.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-001-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-001.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-002-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-002.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-003-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-003.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-004-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-004.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-005-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-005.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-006-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-006.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-007-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-007.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-008-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-008.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-009-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-009.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-010-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-010.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-011-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-011.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-012-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-012.html
testing/web-platform/mozilla/meta/wasm/conversions.wast.js.html.ini
third_party/rust/core-foundation-0.2.3/.cargo-checksum.json
third_party/rust/core-foundation-0.2.3/.cargo-ok
third_party/rust/core-foundation-0.2.3/Cargo.toml
third_party/rust/core-foundation-0.2.3/src/array.rs
third_party/rust/core-foundation-0.2.3/src/base.rs
third_party/rust/core-foundation-0.2.3/src/boolean.rs
third_party/rust/core-foundation-0.2.3/src/bundle.rs
third_party/rust/core-foundation-0.2.3/src/data.rs
third_party/rust/core-foundation-0.2.3/src/dictionary.rs
third_party/rust/core-foundation-0.2.3/src/error.rs
third_party/rust/core-foundation-0.2.3/src/lib.rs
third_party/rust/core-foundation-0.2.3/src/number.rs
third_party/rust/core-foundation-0.2.3/src/propertylist.rs
third_party/rust/core-foundation-0.2.3/src/runloop.rs
third_party/rust/core-foundation-0.2.3/src/set.rs
third_party/rust/core-foundation-0.2.3/src/string.rs
third_party/rust/core-foundation-0.2.3/src/url.rs
third_party/rust/core-foundation-sys-0.2.3/.cargo-checksum.json
third_party/rust/core-foundation-sys-0.2.3/.cargo-ok
third_party/rust/core-foundation-sys-0.2.3/Cargo.toml
third_party/rust/core-foundation-sys-0.2.3/build.rs
third_party/rust/core-foundation-sys-0.2.3/src/array.rs
third_party/rust/core-foundation-sys-0.2.3/src/base.rs
third_party/rust/core-foundation-sys-0.2.3/src/bundle.rs
third_party/rust/core-foundation-sys-0.2.3/src/data.rs
third_party/rust/core-foundation-sys-0.2.3/src/date.rs
third_party/rust/core-foundation-sys-0.2.3/src/dictionary.rs
third_party/rust/core-foundation-sys-0.2.3/src/error.rs
third_party/rust/core-foundation-sys-0.2.3/src/lib.rs
third_party/rust/core-foundation-sys-0.2.3/src/messageport.rs
third_party/rust/core-foundation-sys-0.2.3/src/number.rs
third_party/rust/core-foundation-sys-0.2.3/src/propertylist.rs
third_party/rust/core-foundation-sys-0.2.3/src/runloop.rs
third_party/rust/core-foundation-sys-0.2.3/src/set.rs
third_party/rust/core-foundation-sys-0.2.3/src/string.rs
third_party/rust/core-foundation-sys-0.2.3/src/url.rs
toolkit/components/extensions/ext-theme.js
--- a/browser/base/content/test/general/browser_save_link-perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_link-perwindowpb.js
@@ -35,17 +35,17 @@ function triggerSave(aWindow, aCallback)
     var destFile = destDir.clone();
 
     MockFilePicker.displayDirectory = destDir;
     MockFilePicker.showCallback = function(fp) {
       info("showCallback");
       fileName = fp.defaultString;
       info("fileName: " + fileName);
       destFile.append(fileName);
-      MockFilePicker.returnFiles = [destFile];
+      MockFilePicker.setFiles([destFile]);
       MockFilePicker.filterIndex = 1; // kSaveAsType_URL
       info("done showCallback");
     };
 
     mockTransferCallback = function(downloadSuccess) {
       info("mockTransferCallback");
       onTransferComplete(aWindow, downloadSuccess, destDir);
       destDir.remove(true);
--- a/browser/base/content/test/general/browser_save_link_when_window_navigates.js
+++ b/browser/base/content/test/general/browser_save_link_when_window_navigates.js
@@ -40,17 +40,17 @@ function triggerSave(aWindow, aCallback)
   var destFile = destDir.clone();
 
   MockFilePicker.displayDirectory = destDir;
   MockFilePicker.showCallback = function(fp) {
     info("showCallback");
     fileName = fp.defaultString;
     info("fileName: " + fileName);
     destFile.append(fileName);
-    MockFilePicker.returnFiles = [destFile];
+    MockFilePicker.setFiles([destFile]);
     MockFilePicker.filterIndex = 1; // kSaveAsType_URL
     info("done showCallback");
   };
 
   mockTransferCallback = function(downloadSuccess) {
     info("mockTransferCallback");
     onTransferComplete(aWindow, downloadSuccess, destDir);
     destDir.remove(true);
--- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
@@ -53,17 +53,17 @@ function promiseImageDownloaded() {
     // Create the folder the image will be saved into.
     var destDir = createTemporarySaveDirectory();
     var destFile = destDir.clone();
 
     MockFilePicker.displayDirectory = destDir;
     MockFilePicker.showCallback = function(fp) {
       fileName = fp.defaultString;
       destFile.append(fileName);
-      MockFilePicker.returnFiles = [destFile];
+      MockFilePicker.setFiles([destFile]);
       MockFilePicker.filterIndex = 1; // kSaveAsType_URL
     };
 
     mockTransferCallback = onTransferComplete;
     mockTransferRegisterer.register();
 
     registerCleanupFunction(function() {
       mockTransferCallback = null;
--- a/browser/base/content/test/general/browser_save_video.js
+++ b/browser/base/content/test/general/browser_save_video.js
@@ -29,17 +29,17 @@ add_task(function* () {
   // Create the folder the video will be saved into.
   var destDir = createTemporarySaveDirectory();
   var destFile = destDir.clone();
 
   MockFilePicker.displayDirectory = destDir;
   MockFilePicker.showCallback = function(fp) {
     fileName = fp.defaultString;
     destFile.append(fileName);
-    MockFilePicker.returnFiles = [destFile];
+    MockFilePicker.setFiles([destFile]);
     MockFilePicker.filterIndex = 1; // kSaveAsType_URL
   };
 
   let transferCompletePromise = new Promise((resolve) => {
     function onTransferComplete(downloadSuccess) {
       ok(downloadSuccess, "Video file should have been downloaded successfully");
 
       is(fileName, "web-video1-expectedName.ogv",
--- a/browser/base/content/test/general/browser_save_video_frame.js
+++ b/browser/base/content/test/general/browser_save_video_frame.js
@@ -80,17 +80,17 @@ add_task(function*() {
 
   // Create the folder the video will be saved into.
   let destDir = createTemporarySaveDirectory();
   let destFile = destDir.clone();
 
   MockFilePicker.displayDirectory = destDir;
   MockFilePicker.showCallback = function(fp) {
     destFile.append(fp.defaultString);
-    MockFilePicker.returnFiles = [destFile];
+    MockFilePicker.setFiles([destFile]);
     MockFilePicker.filterIndex = 1; // kSaveAsType_URL
   };
 
   mockTransferRegisterer.register();
 
   // Make sure that we clean these things up when we're done.
   registerCleanupFunction(function() {
     mockTransferRegisterer.unregister();
--- a/browser/base/content/test/webextensions/browser_permissions_local_file.js
+++ b/browser/base/content/test/webextensions/browser_permissions_local_file.js
@@ -5,19 +5,19 @@ async function installFile(filename) {
                                      .getService(Ci.nsIChromeRegistry);
   let chromeUrl = Services.io.newURI(gTestPath);
   let fileUrl = ChromeRegistry.convertChromeURL(chromeUrl);
   let file = fileUrl.QueryInterface(Ci.nsIFileURL).file;
   file.leafName = filename;
 
   let MockFilePicker = SpecialPowers.MockFilePicker;
   MockFilePicker.init(window);
-  MockFilePicker.returnFiles = [file];
+  MockFilePicker.setFiles([file]);
+  MockFilePicker.afterOpenCallback = MockFilePicker.cleanup;
 
   await BrowserOpenAddonsMgr("addons://list/extension");
   let contentWin = gBrowser.selectedTab.linkedBrowser.contentWindow;
 
   // Do the install...
   contentWin.gViewController.doCommand("cmd_installFromFile");
-  MockFilePicker.cleanup();
 }
 
 add_task(() => testInstallMethod(installFile));
--- a/browser/components/contextualidentity/test/browser/browser.ini
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -8,17 +8,16 @@ support-files =
   worker.js
 
 [browser_aboutURLs.js]
 [browser_eme.js]
 [browser_favicon.js]
 [browser_forgetaboutsite.js]
 [browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
 [browser_forgetAPI_EME_forgetThisSite.js]
-skip-if = e10s # Bug 1315042
 [browser_forgetAPI_quota_clearStoragesForPrincipal.js]
 [browser_newtabButton.js]
 [browser_usercontext.js]
 [browser_usercontextid_tabdrop.js]
 skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
 [browser_windowName.js]
 tags = openwindow
 [browser_windowOpen.js]
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js
@@ -50,17 +50,17 @@ function test() {
                            aGlobalLastDir, aCallback) {
     // Check lastDir preference.
     is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, aDisplayDir.path,
        "LastDir should be the expected display dir");
     // Check gDownloadLastDir value.
     is(gDownloadLastDir.file.path, aDisplayDir.path,
        "gDownloadLastDir should be the expected display dir");
 
-    MockFilePicker.returnFiles = [aFile];
+    MockFilePicker.setFiles([aFile]);
     MockFilePicker.displayDirectory = null;
 
     launcher.saveDestinationAvailable = function(file) {
       ok(!!file, "promptForSaveToFile correctly returned a file");
 
       // File picker should start with expected display dir.
       is(MockFilePicker.displayDirectory.path, aDisplayDir.path,
         "File picker should start with browser.download.lastDir");
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js
@@ -57,17 +57,17 @@ function test() {
                            aGlobalLastDir, aCallback) {
     // Check lastDir preference.
     is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, aDisplayDir.path,
        "LastDir should be the expected display dir");
     // Check gDownloadLastDir value.
     is(gDownloadLastDir.file.path, aDisplayDir.path,
        "gDownloadLastDir should be the expected display dir");
 
-    MockFilePicker.returnFiles = [aFile];
+    MockFilePicker.setFiles([aFile]);
     MockFilePicker.displayDirectory = null;
     aWin.promiseTargetFile(params).then(function() {
       // File picker should start with expected display dir.
       is(MockFilePicker.displayDirectory.path, aDisplayDir.path,
          "File picker should start with browser.download.lastDir");
       // browser.download.lastDir should be modified on not private windows
       is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, aLastDir.path,
          "LastDir should be the expected last dir");
--- a/devtools/client/aboutdebugging/components/addons/controls.js
+++ b/devtools/client/aboutdebugging/components/addons/controls.js
@@ -42,32 +42,33 @@ module.exports = createClass({
   },
 
   loadAddonFromFile() {
     this.setState({ installError: null });
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window,
       Strings.GetStringFromName("selectAddonFromFile2"),
       Ci.nsIFilePicker.modeOpen);
-    let res = fp.show();
-    if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
-      return;
-    }
-    let file = fp.file;
-    // AddonManager.installTemporaryAddon accepts either
-    // addon directory or final xpi file.
-    if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
-      file = file.parent;
-    }
+    fp.open(res => {
+      if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
+        return;
+      }
+      let file = fp.file;
+      // AddonManager.installTemporaryAddon accepts either
+      // addon directory or final xpi file.
+      if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
+        file = file.parent;
+      }
 
-    AddonManager.installTemporaryAddon(file)
-      .catch(e => {
-        console.error(e);
-        this.setState({ installError: e.message });
-      });
+      AddonManager.installTemporaryAddon(file)
+        .catch(e => {
+          console.error(e);
+          this.setState({ installError: e.message });
+        });
+    });
   },
 
   render() {
     let { debugDisabled } = this.props;
 
     return dom.div({ className: "addons-top" },
       dom.div({ className: "addons-controls" },
         dom.div({ className: "addons-options toggle-container-with-text" },
--- a/devtools/client/aboutdebugging/test/browser_addons_install.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_install.js
@@ -18,29 +18,29 @@ add_task(function* () {
 
   // Install the add-on, and verify that it disappears in the about:debugging UI
   yield uninstallAddon({document, id: ADDON_ID, name: ADDON_NAME});
 
   yield closeAboutDebugging(tab);
 });
 
 add_task(function* () {
-  let { tab, document } = yield openAboutDebugging("addons");
+  let { tab, document, window } = yield openAboutDebugging("addons");
   yield waitForInitialAddonList(document);
 
   // Start an observer that looks for the install error before
   // actually doing the install
   let top = document.querySelector(".addons-top");
   let promise = waitForMutation(top, { childList: true });
 
   // Mock the file picker to select a test addon
   let MockFilePicker = SpecialPowers.MockFilePicker;
-  MockFilePicker.init(null);
+  MockFilePicker.init(window);
   let file = getSupportsFile("addons/bad/manifest.json");
-  MockFilePicker.returnFiles = [file.file];
+  MockFilePicker.setFiles([file.file]);
 
   // Trigger the file picker by clicking on the button
   document.getElementById("load-addon-from-file").click();
 
   // Now wait for the install error to appear.
   yield promise;
 
   // And check that it really is there.
--- a/devtools/client/aboutdebugging/test/head.js
+++ b/devtools/client/aboutdebugging/test/head.js
@@ -30,22 +30,23 @@ function* openAboutDebugging(page, win) 
   let url = "about:debugging";
   if (page) {
     url += "#" + page;
   }
 
   let tab = yield addTab(url, { window: win });
   let browser = tab.linkedBrowser;
   let document = browser.contentDocument;
+  let window = browser.contentWindow;
 
   if (!document.querySelector(".app")) {
     yield waitForMutation(document.body, { childList: true });
   }
 
-  return { tab, document };
+  return { tab, document, window };
 }
 
 /**
  * Change url hash for current about:debugging tab, return a promise after
  * new content is loaded.
  * @param  {DOMDocument}  document   container document from current tab
  * @param  {String}       hash       hash for about:debugging
  * @return {Promise}
@@ -139,19 +140,19 @@ function getServiceWorkerList(document) 
 function getTabList(document) {
   return document.querySelector("#tabs .target-list") ||
     document.querySelector("#tabs.targets");
 }
 
 function* installAddon({document, path, name, isWebExtension}) {
   // Mock the file picker to select a test addon
   let MockFilePicker = SpecialPowers.MockFilePicker;
-  MockFilePicker.init(null);
+  MockFilePicker.init(window);
   let file = getSupportsFile(path);
-  MockFilePicker.returnFiles = [file.file];
+  MockFilePicker.setFiles([file.file]);
 
   let addonList = getTemporaryAddonList(document);
   let addonListMutation = waitForMutation(addonList, { childList: true });
 
   let onAddonInstalled;
 
   if (isWebExtension) {
     onAddonInstalled = new Promise(done => {
--- a/devtools/client/canvasdebugger/snapshotslist.js
+++ b/devtools/client/canvasdebugger/snapshotslist.js
@@ -352,48 +352,50 @@ var SnapshotsListView = Heritage.extend(
    * The click listener for the "import" button in this container.
    */
   _onImportButtonClick: function () {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, L10N.getStr("snapshotsList.saveDialogTitle"), Ci.nsIFilePicker.modeOpen);
     fp.appendFilter(L10N.getStr("snapshotsList.saveDialogJSONFilter"), "*.json");
     fp.appendFilter(L10N.getStr("snapshotsList.saveDialogAllFilter"), "*.*");
 
-    if (fp.show() != Ci.nsIFilePicker.returnOK) {
-      return;
-    }
-
-    let channel = NetUtil.newChannel({
-      uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true});
-    channel.contentType = "text/plain";
-
-    NetUtil.asyncFetch(channel, (inputStream, status) => {
-      if (!Components.isSuccessCode(status)) {
-        console.error("Could not import recorded animation frame snapshot file.");
-        return;
-      }
-      try {
-        let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
-        var data = JSON.parse(string);
-      } catch (e) {
-        console.error("Could not read animation frame snapshot file.");
-        return;
-      }
-      if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) {
-        console.error("Unrecognized animation frame snapshot file.");
+    fp.open(rv => {
+      if (rv != Ci.nsIFilePicker.returnOK) {
         return;
       }
 
-      // Add a `isLoadedFromDisk` flag on everything to avoid sending invalid
-      // requests to the backend, since we're not dealing with actors anymore.
-      let snapshotItem = this.addSnapshot();
-      snapshotItem.isLoadedFromDisk = true;
-      data.calls.forEach(e => e.isLoadedFromDisk = true);
+      let channel = NetUtil.newChannel({
+        uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true});
+      channel.contentType = "text/plain";
 
-      this.customizeSnapshot(snapshotItem, data.calls, data);
+      NetUtil.asyncFetch(channel, (inputStream, status) => {
+        if (!Components.isSuccessCode(status)) {
+          console.error("Could not import recorded animation frame snapshot file.");
+          return;
+        }
+        try {
+          let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
+          var data = JSON.parse(string);
+        } catch (e) {
+          console.error("Could not read animation frame snapshot file.");
+          return;
+        }
+        if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) {
+          console.error("Unrecognized animation frame snapshot file.");
+          return;
+        }
+
+        // Add a `isLoadedFromDisk` flag on everything to avoid sending invalid
+        // requests to the backend, since we're not dealing with actors anymore.
+        let snapshotItem = this.addSnapshot();
+        snapshotItem.isLoadedFromDisk = true;
+        data.calls.forEach(e => e.isLoadedFromDisk = true);
+
+        this.customizeSnapshot(snapshotItem, data.calls, data);
+      });
     });
   },
 
   /**
    * The click listener for the "save" button of each item in this container.
    */
   _onSaveButtonClick: function (e) {
     let snapshotItem = this.getItemForElement(e.target);
--- a/devtools/client/jsonview/main.js
+++ b/devtools/client/jsonview/main.js
@@ -45,18 +45,18 @@ var JsonView = {
 
   // Message handlers for events from child processes
 
   /**
    * Save JSON to a file needs to be implemented here
    * in the parent process.
    */
   onSave: function (message) {
-    let value = message.data;
-    let file = JsonViewUtils.getTargetFile();
-    if (file) {
-      JsonViewUtils.saveToFile(file, value);
-    }
+    JsonViewUtils.getTargetFile(file => {
+      if (file) {
+        JsonViewUtils.saveToFile(file, message.data);
+      }
+    });
   }
 };
 
 // Exports from this module
 module.exports.JsonView = JsonView;
--- a/devtools/client/jsonview/utils.js
+++ b/devtools/client/jsonview/utils.js
@@ -18,31 +18,34 @@ const OPEN_FLAGS = {
   TRUNCATE: parseInt("0x20", 16),
   EXCL: parseInt("0x80", 16)
 };
 
 /**
  * Open File Save As dialog and let the user to pick proper file location.
  */
 exports.getTargetFile = function () {
-  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+  return new Promise(resolve => {
+    let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
 
-  let win = getMostRecentBrowserWindow();
-  fp.init(win, null, Ci.nsIFilePicker.modeSave);
-  fp.appendFilter("JSON Files", "*.json; *.jsonp;");
-  fp.appendFilters(Ci.nsIFilePicker.filterText);
-  fp.appendFilters(Ci.nsIFilePicker.filterAll);
-  fp.filterIndex = 0;
+    let win = getMostRecentBrowserWindow();
+    fp.init(win, null, Ci.nsIFilePicker.modeSave);
+    fp.appendFilter("JSON Files", "*.json; *.jsonp;");
+    fp.appendFilters(Ci.nsIFilePicker.filterText);
+    fp.appendFilters(Ci.nsIFilePicker.filterAll);
+    fp.filterIndex = 0;
 
-  let rv = fp.show();
-  if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
-    return fp.file;
-  }
-
-  return null;
+    fp.open(rv => {
+      if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
+        resolve(fp.file);
+      } else {
+        resolve(null);
+      }
+    });
+  });
 };
 
 /**
  * Save JSON to a file
  */
 exports.saveToFile = function (file, jsonString) {
   let foStream = Cc["@mozilla.org/network/file-output-stream;1"]
     .createInstance(Ci.nsIFileOutputStream);
--- a/devtools/client/netmonitor/har/har-utils.js
+++ b/devtools/client/netmonitor/har/har-utils.js
@@ -21,18 +21,16 @@ XPCOMUtils.defineLazyGetter(this, "ZipWr
 XPCOMUtils.defineLazyGetter(this, "LocalFile", function () {
   return new CC("@mozilla.org/file/local;1", "nsILocalFile", "initWithPath");
 });
 
 XPCOMUtils.defineLazyGetter(this, "getMostRecentBrowserWindow", function () {
   return require("sdk/window/utils").getMostRecentBrowserWindow;
 });
 
-const nsIFilePicker = Ci.nsIFilePicker;
-
 const OPEN_FLAGS = {
   RDONLY: parseInt("0x01", 16),
   WRONLY: parseInt("0x02", 16),
   CREATE_FILE: parseInt("0x08", 16),
   APPEND: parseInt("0x10", 16),
   TRUNCATE: parseInt("0x20", 16),
   EXCL: parseInt("0x80", 16)
 };
@@ -47,40 +45,16 @@ function formatDate(date) {
 
   return `${year}-${month}-${day} ${hour}-${minutes}-${seconds}`;
 }
 
 /**
  * Helper API for HAR export features.
  */
 var HarUtils = {
-  /**
-   * Open File Save As dialog and let the user pick the proper file
-   * location for generated HAR log.
-   */
-  getTargetFile: function (fileName, jsonp, compress) {
-    let browser = getMostRecentBrowserWindow();
-
-    let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
-    fp.init(browser, null, nsIFilePicker.modeSave);
-    fp.appendFilter(
-      "HTTP Archive Files", "*.har; *.harp; *.json; *.jsonp; *.zip");
-    fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
-    fp.filterIndex = 1;
-
-    fp.defaultString = this.getHarFileName(fileName, jsonp, compress);
-
-    let rv = fp.show();
-    if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
-      return fp.file;
-    }
-
-    return null;
-  },
-
   getHarFileName: function (defaultFileName, jsonp, compress) {
     let extension = jsonp ? ".harp" : ".har";
 
     let now = new Date();
     let name = defaultFileName.replace(/%date/g, formatDate(now));
     name = name.replace(/\:/gm, "-", "");
     name = name.replace(/\//gm, "_", "");
 
--- a/devtools/client/netmonitor/utils/mdn-utils.js
+++ b/devtools/client/netmonitor/utils/mdn-utils.js
@@ -18,119 +18,159 @@ const SUPPORTED_HEADERS = [
   "Access-Control-Allow-Headers",
   "Access-Control-Allow-Methods",
   "Access-Control-Allow-Origin",
   "Access-Control-Expose-Headers",
   "Access-Control-Max-Age",
   "Access-Control-Request-Headers",
   "Access-Control-Request-Method",
   "Age",
+  "Allow",
+  "Authorization",
   "Cache-Control",
   "Connection",
   "Content-Disposition",
   "Content-Encoding",
   "Content-Language",
   "Content-Length",
   "Content-Location",
+  "Content-Range",
   "Content-Security-Policy",
   "Content-Security-Policy-Report-Only",
   "Content-Type",
   "Cookie",
   "Cookie2",
   "DNT",
   "Date",
   "ETag",
+  "Expect",
   "Expires",
+  "Forwarded",
   "From",
   "Host",
   "If-Match",
   "If-Modified-Since",
   "If-None-Match",
   "If-Range",
   "If-Unmodified-Since",
   "Keep-Alive",
+  "Large-Allocation",
   "Last-Modified",
   "Location",
   "Origin",
   "Pragma",
+  "Proxy-Authenticate",
+  "Proxy-Authorization",
   "Public-Key-Pins",
   "Public-Key-Pins-Report-Only",
+  "Range",
   "Referer",
   "Referrer-Policy",
   "Retry-After",
   "Server",
   "Set-Cookie",
   "Set-Cookie2",
   "Strict-Transport-Security",
   "TE",
   "Tk",
   "Trailer",
   "Transfer-Encoding",
   "Upgrade-Insecure-Requests",
   "User-Agent",
   "Vary",
   "Via",
+  "WWW-Authenticate",
   "Warning",
   "X-Content-Type-Options",
   "X-DNS-Prefetch-Control",
+  "X-Forwarded-For",
+  "X-Forwarded-Host",
+  "X-Forwarded-Proto",
   "X-Frame-Options",
   "X-XSS-Protection"
 ];
 
 /**
  * A mapping of HTTP status codes to external documentation. Any code included
  * here will show a MDN link alongside it.
  */
 const SUPPORTED_HTTP_CODES = [
     "100",
+    "101",
     "200",
     "201",
+    "202",
+    "203",
     "204",
+    "205",
     "206",
+    "300",
     "301",
     "302",
     "303",
     "304",
     "307",
     "308",
+    "400",
+    "401",
+    "403",
     "404",
+    "405",
     "406",
+    "407",
+    "408",
+    "409",
     "410",
+    "411",
     "412",
+    "413",
+    "414",
+    "415",
+    "416",
+    "417",
+    "426",
+    "428",
+    "429",
+    "431",
     "451",
     "500",
     "501",
     "502",
     "503",
-    "504"
+    "504",
+    "505",
+    "511"
 ];
 
+const GA_PARAMS =
+  "?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default";
+
 /**
  * Get the MDN URL for the specified header.
  *
  * @param {string} header Name of the header for the baseURL to use.
  *
  * @return {string} The MDN URL for the header, or null if not available.
  */
 function getHeadersURL(header) {
   const lowerCaseHeader = header.toLowerCase();
   let idx = SUPPORTED_HEADERS.findIndex(item =>
     item.toLowerCase() === lowerCaseHeader);
   return idx > -1 ?
-    `https://developer.mozilla.org/docs/Web/HTTP/Headers/${SUPPORTED_HEADERS[idx]}?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default` : null;
+    `https://developer.mozilla.org/docs/Web/HTTP/Headers/${SUPPORTED_HEADERS[idx] + GA_PARAMS}` : null;
 }
 
 /**
  * Get the MDN URL for the specified HTTP status code.
  *
  * @param {string} HTTP status code for the baseURL to use.
  *
  * @return {string} The MDN URL for the HTTP status code, or null if not available.
  */
 function getHTTPStatusCodeURL(statusCode) {
   let idx = SUPPORTED_HTTP_CODES.indexOf(statusCode);
-  return idx > -1 ? `https://developer.mozilla.org/docs/Web/HTTP/Status/${SUPPORTED_HTTP_CODES[idx]}` : null;
+  return idx > -1 ? `https://developer.mozilla.org/docs/Web/HTTP/Status/${SUPPORTED_HTTP_CODES[idx] + GA_PARAMS}` : null;
 }
 
 module.exports = {
   getHeadersURL,
   getHTTPStatusCodeURL,
 };
--- a/devtools/client/performance/performance-view.js
+++ b/devtools/client/performance/performance-view.js
@@ -354,19 +354,21 @@ var PerformanceView = {
    */
   _onImportButtonClick: function (e) {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, L10N.getStr("recordingsList.importDialogTitle"),
             Ci.nsIFilePicker.modeOpen);
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
 
-    if (fp.show() == Ci.nsIFilePicker.returnOK) {
-      this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
-    }
+    fp.open(rv => {
+      if (rv == Ci.nsIFilePicker.returnOK) {
+        this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
+      }
+    });
   },
 
   /**
    * Fired when a recording is selected. Used to toggle the profiler view state.
    */
   _onRecordingSelected: function (_, recording) {
     if (!recording) {
       this.setState("empty");
--- a/devtools/client/webide/content/newapp.js
+++ b/devtools/client/webide/content/newapp.js
@@ -105,70 +105,73 @@ function doOK() {
   }
 
   let templatelistNode = document.querySelector("#templatelist");
   if (templatelistNode.selectedIndex < 0) {
     console.error("No template selected");
     return false;
   }
 
-  let folder;
-
   /* Chrome mochitest support */
-  let testOptions = window.arguments[0].testOptions;
-  if (testOptions) {
-    folder = testOptions.folder;
-  } else {
-    let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-    fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
-    let res = fp.show();
-    if (res == Ci.nsIFilePicker.returnCancel) {
-      console.error("No directory selected");
-      return false;
+  let promise = new Promise((resolve, reject) => {
+    let testOptions = window.arguments[0].testOptions;
+    if (testOptions) {
+      resolve(testOptions.folder);
+    } else {
+      let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+      fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
+      fp.open(res => {
+        if (res == Ci.nsIFilePicker.returnCancel) {
+          console.error("No directory selected");
+          reject(null);
+        } else {
+          resolve(fp.file);
+        }
+      });
     }
-    folder = fp.file;
-  }
-
-  // Create subfolder with fs-friendly name of project
-  let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
-  let win = Services.wm.getMostRecentWindow("devtools:webide");
-  folder.append(subfolder);
-
-  try {
-    folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-  } catch (e) {
-    win.UI.reportError("error_folderCreationFailed");
-    window.close();
-    return false;
-  }
-
-  // Download boilerplate zip
-  let template = gTemplateList[templatelistNode.selectedIndex];
-  let source = template.file;
-  let target = folder.clone();
-  target.append(subfolder + ".zip");
+  });
 
   let bail = (e) => {
     console.error(e);
     window.close();
   };
 
-  Downloads.fetch(source, target).then(() => {
-    ZipUtils.extractFiles(target, folder);
-    target.remove(false);
-    AppProjects.addPackaged(folder).then((project) => {
-      window.arguments[0].location = project.location;
-      AppManager.validateAndUpdateProject(project).then(() => {
-        if (project.manifest) {
-          project.manifest.name = projectName;
-          AppManager.writeManifest(project).then(() => {
-            AppManager.validateAndUpdateProject(project).then(
-              () => {window.close();}, bail);
-          }, bail);
-        } else {
-          bail("Manifest not found");
-        }
+  promise.then(folder => {
+    // Create subfolder with fs-friendly name of project
+    let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
+    let win = Services.wm.getMostRecentWindow("devtools:webide");
+    folder.append(subfolder);
+
+    try {
+      folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+    } catch (e) {
+      win.UI.reportError("error_folderCreationFailed");
+      window.close();
+      return;
+    }
+
+    // Download boilerplate zip
+    let template = gTemplateList[templatelistNode.selectedIndex];
+    let source = template.file;
+    let target = folder.clone();
+    target.append(subfolder + ".zip");
+    Downloads.fetch(source, target).then(() => {
+      ZipUtils.extractFiles(target, folder);
+      target.remove(false);
+      AppProjects.addPackaged(folder).then((project) => {
+        window.arguments[0].location = project.location;
+        AppManager.validateAndUpdateProject(project).then(() => {
+          if (project.manifest) {
+            project.manifest.name = projectName;
+            AppManager.writeManifest(project).then(() => {
+              AppManager.validateAndUpdateProject(project).then(
+                () => {window.close();}, bail);
+            }, bail);
+          } else {
+            bail("Manifest not found");
+          }
+        }, bail);
       }, bail);
     }, bail);
   }, bail);
 
   return false;
 }
--- a/devtools/client/webide/content/simulator.js
+++ b/devtools/client/webide/content/simulator.js
@@ -284,39 +284,41 @@ var SimulatorEditor = {
     let input = event.target;
     switch (input.name) {
       case "name":
         simulator.options.name = input.value;
         break;
       case "version":
         switch (input.value) {
           case "pick":
-            let file = utils.getCustomBinary(window);
-            if (file) {
-              this.version = file.path;
-            }
-            // Whatever happens, don't stay on the "pick" option.
-            this.updateVersionSelector();
+            utils.getCustomBinary(window).then(file => {
+              if (file) {
+                this.version = file.path;
+              }
+              // Whatever happens, don't stay on the "pick" option.
+              this.updateVersionSelector();
+            });
             break;
           case "custom":
             this.version = input[input.selectedIndex].textContent;
             break;
           default:
             this.version = input.value;
         }
         break;
       case "profile":
         switch (input.value) {
           case "pick":
-            let directory = utils.getCustomProfile(window);
-            if (directory) {
-              this.profile = directory.path;
-            }
-            // Whatever happens, don't stay on the "pick" option.
-            this.updateProfileSelector();
+            utils.getCustomProfile(window).then(directory => {
+              if (directory) {
+                this.profile = directory.path;
+              }
+              // Whatever happens, don't stay on the "pick" option.
+              this.updateProfileSelector();
+            });
             break;
           case "custom":
             this.profile = input[input.selectedIndex].textContent;
             break;
           default:
             this.profile = input.value;
         }
         break;
--- a/devtools/client/webide/modules/project-list.js
+++ b/devtools/client/webide/modules/project-list.js
@@ -87,17 +87,17 @@ ProjectList.prototype = {
       self._telemetry.actionOccurred("webideNewProject");
     }), "creating new app");
   },
 
   importPackagedApp: function (location) {
     let parentWindow = this._parentWindow;
     let UI = this._UI;
     return UI.busyUntil(Task.spawn(function* () {
-      let directory = utils.getPackagedDirectory(parentWindow, location);
+      let directory = yield utils.getPackagedDirectory(parentWindow, location);
 
       if (!directory) {
         // User cancelled directory selection
         return;
       }
 
       yield UI.importAndSelectApp(directory);
     }), "importing packaged app");
--- a/devtools/client/webide/modules/utils.js
+++ b/devtools/client/webide/modules/utils.js
@@ -10,25 +10,30 @@ const Strings = Services.strings.createB
 function doesFileExist(location) {
   let file = new FileUtils.File(location);
   return file.exists();
 }
 exports.doesFileExist = doesFileExist;
 
 function _getFile(location, ...pickerParams) {
   if (location) {
-    return new FileUtils.File(location);
+    return Promise.resolve(new FileUtils.File(location));
   }
   let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
   fp.init(...pickerParams);
-  let res = fp.show();
-  if (res == Ci.nsIFilePicker.returnCancel) {
-    return null;
-  }
-  return fp.file;
+
+  return new Promise(resolve => {
+    fp.open(res => {
+      if (res == Ci.nsIFilePicker.returnCancel) {
+        resolve(null);
+      } else {
+        resolve(fp.file);
+      }
+    });
+  });
 }
 
 function getCustomBinary(window, location) {
   return _getFile(location, window, Strings.GetStringFromName("selectCustomBinary_title"), Ci.nsIFilePicker.modeOpen);
 }
 exports.getCustomBinary = getCustomBinary;
 
 function getCustomProfile(window, location) {
--- a/devtools/client/webide/test/test_simulators.html
+++ b/devtools/client/webide/test/test_simulators.html
@@ -185,28 +185,28 @@
 
           yield set(form.version, sim20.addonID);
 
           ok(!form.version.classList.contains("custom"), "Version selector is not customized after addon change");
           is(form.name.value, customName + "2.0", "Simulator name was updated to new version");
 
           // Pick custom binary, but act like the user aborted the file picker.
 
-          MockFilePicker.returnFiles = [];
+          MockFilePicker.setFiles([]);
           yield set(form.version, "pick");
 
           is(form.version.value, sim20.addonID, "Version selector reverted to last valid choice after customization abort");
           ok(!form.version.classList.contains("custom"), "Version selector is not customized after customization abort");
 
           // Pick custom binary, and actually follow through. (success, verify value = "custom" and textContent = custom path)
 
-          MockFilePicker.useAnyFile();
+          yield MockFilePicker.useAnyFile();
           yield set(form.version, "pick");
 
-          let fakeBinary = MockFilePicker.returnFiles[0];
+          let fakeBinary = MockFilePicker.file;
 
           ok(form.version.value == "custom", "Version selector was set to a new custom binary");
           ok(form.version.classList.contains("custom"), "Version selector is now customized");
           is(form.version.selectedOptions[0].textContent, fakeBinary.path, "Custom option textContent is correct");
 
           yield set(form.version, sim10.addonID);
 
           ok(form.version.classList.contains("custom"), "Version selector remains customized after change back to addon");
@@ -216,25 +216,25 @@
 
           ok(form.version.value == "custom", "Version selector is back to custom");
 
           // Test `profile`.
 
           is(form.profile.value, "default", "Default simulator profile");
           ok(!form.profile.classList.contains("custom"), "Profile selector is not customized");
 
-          MockFilePicker.returnFiles = [];
+          MockFilePicker.setFiles([]);
           yield set(form.profile, "pick");
 
           is(form.profile.value, "default", "Profile selector reverted to last valid choice after customization abort");
           ok(!form.profile.classList.contains("custom"), "Profile selector is not customized after customization abort");
 
           let fakeProfile = FileUtils.getDir("TmpD", []);
 
-          MockFilePicker.returnFiles = [ fakeProfile ];
+          MockFilePicker.setFiles([ fakeProfile ]);
           yield set(form.profile, "pick");
 
           ok(form.profile.value == "custom", "Profile selector was set to a new custom directory");
           ok(form.profile.classList.contains("custom"), "Profile selector is now customized");
           is(form.profile.selectedOptions[0].textContent, fakeProfile.path, "Custom option textContent is correct");
 
           yield set(form.profile, "default");
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2805,37 +2805,16 @@ nsDOMWindowUtils::GetContainerElement(ns
 
   nsCOMPtr<nsIDOMElement> element =
     do_QueryInterface(window->GetFrameElementInternal());
 
   element.forget(aResult);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile,
-                              nsISupports **aDOMFile)
-{
-  if (!aFile) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
-  NS_ENSURE_STATE(window);
-
-  nsPIDOMWindowInner* innerWindow = window->GetCurrentInnerWindow();
-  if (!innerWindow) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(innerWindow, aFile);
-  blob.forget(aDOMFile);
-  return NS_OK;
-}
-
 #ifdef DEBUG
 static bool
 CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion)
 {
   gfx::Matrix transform;
   if (!aLayer->GetTransform().Is2D(&transform) ||
       transform.HasNonIntegerTranslation())
     return false;
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -527,17 +527,16 @@ skip-if = toolkit == 'android' #bug 6870
 [test_bug750096.html]
 [test_bug753278.html]
 [test_bug761120.html]
 [test_bug769117.html]
 [test_bug782342.html]
 [test_bug787778.html]
 [test_bug789315.html]
 [test_bug789856.html]
-[test_bug793311.html]
 [test_bug804395.html]
 [test_bug809003.html]
 [test_bug810494.html]
 [test_bug811701.html]
 [test_bug811701.xhtml]
 [test_bug813919.html]
 [test_bug814576.html]
 [test_bug819051.html]
deleted file mode 100644
--- a/dom/base/test/test_bug793311.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=793311
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 793311</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  /** Test for Bug {793311} **/
-  SimpleTest.waitForExplicitFinish();
-
-  try {
-    SpecialPowers.DOMWindowUtils.wrapDOMFile(null);
-    ok(false, "wrapDOMFile(null) throws an exception");
-  } catch(e) {
-    ok(true, "wrapDOMFile(null) throws an exception");
-  }
-  SimpleTest.finish();
-
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=793311">Mozilla Bug 793311</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
--- a/dom/file/FileBlobImpl.h
+++ b/dom/file/FileBlobImpl.h
@@ -45,16 +45,26 @@ public:
                                  ErrorResult& aRv) override;
 
   virtual bool IsDirectory() const override;
 
   // We always have size and date for this kind of blob.
   virtual bool IsSizeUnknown() const override { return false; }
   virtual bool IsDateUnknown() const override { return false; }
 
+  void SetName(const nsAString& aName)
+  {
+    mName = aName;
+  }
+
+  void SetType(const nsAString& aType)
+  {
+    mContentType = aType;
+  }
+
 protected:
   virtual ~FileBlobImpl() = default;
 
 private:
   // Create slice
   FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
                uint64_t aLength, const nsAString& aContentType);
 
--- a/dom/file/FileCreatorHelper.cpp
+++ b/dom/file/FileCreatorHelper.cpp
@@ -77,17 +77,18 @@ FileCreatorHelper::CreateFileInternal(ns
   int64_t lastModified = 0;
   if (aBag.mLastModified.WasPassed()) {
     lastModifiedPassed = true;
     lastModified = aBag.mLastModified.Value();
   }
 
   RefPtr<BlobImpl> blobImpl;
   aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed,
-                       lastModified, aIsFromNsIFile, getter_AddRefs(blobImpl));
+                       lastModified, aBag.mExistenceCheck, aIsFromNsIFile,
+                       getter_AddRefs(blobImpl));
   if (aRv.Failed()) {
      return nullptr;
   }
 
   RefPtr<File> file = File::Create(aWindow, blobImpl);
   return file.forget();
 }
 
@@ -125,17 +126,18 @@ FileCreatorHelper::SendRequest(nsIFile* 
 
   nsAutoString path;
   aRv = aFile->GetPath(path);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName,
-                          aBag.mLastModified, aIsFromNsIFile);
+                          aBag.mLastModified, aBag.mExistenceCheck,
+                          aIsFromNsIFile);
 }
 
 void
 FileCreatorHelper::ResponseReceived(BlobImpl* aBlobImpl, nsresult aRv)
 {
   if (NS_FAILED(aRv)) {
     mPromise->MaybeReject(aRv);
     return;
@@ -146,38 +148,59 @@ FileCreatorHelper::ResponseReceived(Blob
 }
 
 /* static */ nsresult
 FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath,
                                         const nsAString& aType,
                                         const nsAString& aName,
                                         bool aLastModifiedPassed,
                                         int64_t aLastModified,
+                                        bool aExistenceCheck,
                                         bool aIsFromNsIFile,
                                         BlobImpl** aBlobImpl)
 {
   nsCOMPtr<nsIFile> file;
   nsresult rv = NS_NewLocalFile(aPath, true, getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified,
-                        aIsFromNsIFile, aBlobImpl);
+                        aExistenceCheck, aIsFromNsIFile, aBlobImpl);
 }
 
 /* static */ nsresult
 FileCreatorHelper::CreateBlobImpl(nsIFile* aFile,
                                   const nsAString& aType,
                                   const nsAString& aName,
                                   bool aLastModifiedPassed,
                                   int64_t aLastModified,
+                                  bool aExistenceCheck,
                                   bool aIsFromNsIFile,
                                   BlobImpl** aBlobImpl)
 {
+  if (!aExistenceCheck) {
+    RefPtr<FileBlobImpl> impl = new FileBlobImpl(aFile);
+
+    if (!aName.IsEmpty()) {
+      impl->SetName(aName);
+    }
+
+    if (!aType.IsEmpty()) {
+      impl->SetType(aType);
+    }
+
+    if (aLastModifiedPassed) {
+      impl->SetLastModified(aLastModified);
+    }
+
+    impl.forget(aBlobImpl);
+    return NS_OK;
+  }
+
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
   nsresult rv =
     impl->InitializeChromeFile(aFile, aType, aName, aLastModifiedPassed,
                                aLastModified, aIsFromNsIFile);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
--- a/dom/file/FileCreatorHelper.h
+++ b/dom/file/FileCreatorHelper.h
@@ -46,16 +46,17 @@ public:
 
   // For IPC only
   static nsresult
   CreateBlobImplForIPC(const nsAString& aPath,
                        const nsAString& aType,
                        const nsAString& aName,
                        bool aLastModifiedPassed,
                        int64_t aLastModified,
+                       bool aExistenceCheck,
                        bool aIsFromNsIFile,
                        BlobImpl** aBlobImpl);
 
 private:
   static already_AddRefed<File>
   CreateFileInternal(nsPIDOMWindowInner* aWindow,
                      nsIFile* aFile,
                      const ChromeFilePropertyBag& aBag,
@@ -63,16 +64,17 @@ private:
                      ErrorResult& aRv);
 
   static nsresult
   CreateBlobImpl(nsIFile* aFile,
                  const nsAString& aType,
                  const nsAString& aName,
                  bool aLastModifiedPassed,
                  int64_t aLastModified,
+                 bool aExistenceCheck,
                  bool aIsFromNsIFile,
                  BlobImpl** aBlobImpl);
 
   FileCreatorHelper(Promise* aPromise, nsPIDOMWindowInner* aWindow);
   ~FileCreatorHelper();
 
   void
   SendRequest(nsIFile* aFile, const ChromeFilePropertyBag& aBag,
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1559,22 +1559,16 @@ interface nsIDOMWindowUtils : nsISupport
    * property.
    */
   double computeAnimationDistance(in nsIDOMElement element,
                                   in AString property,
                                   in AString value1,
                                   in AString value2);
 
   /**
-   * Wrap an nsIFile in an DOM File
-   * Returns a File object.
-   */
-  nsISupports wrapDOMFile(in nsIFile aFile);
-
-  /**
    * Get the type of the currently focused html input, if any.
    */
   readonly attribute string focusedInputType;
 
   /**
    * Find the view ID for a given element. This is the reverse of
    * findElementWithViewId().
    */
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3170,30 +3170,32 @@ ContentChild::GetConstructedEventTarget(
 }
 
 void
 ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper,
                                   const nsAString& aFullPath,
                                   const nsAString& aType,
                                   const nsAString& aName,
                                   const Optional<int64_t>& aLastModified,
+                                  bool aExistenceCheck,
                                   bool aIsFromNsIFile)
 {
   MOZ_ASSERT(aHelper);
 
   bool lastModifiedPassed = false;
   int64_t lastModified = 0;
   if (aLastModified.WasPassed()) {
     lastModifiedPassed = true;
     lastModified = aLastModified.Value();
   }
 
   Unused << SendFileCreationRequest(aUUID, nsString(aFullPath), nsString(aType),
                                     nsString(aName), lastModifiedPassed,
-                                    lastModified, aIsFromNsIFile);
+                                    lastModified, aExistenceCheck,
+                                    aIsFromNsIFile);
   mFileCreationPending.Put(aUUID, aHelper);
 }
 
 mozilla::ipc::IPCResult
 ContentChild::RecvFileCreationResponse(const nsID& aUUID,
                                        const FileCreationResult& aResult)
 {
   FileCreatorHelper* helper = mFileCreationPending.GetWeak(aUUID);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -628,17 +628,17 @@ public:
                                              base::ProcessId aOtherPid);
 
   // This method is used by FileCreatorHelper for the creation of a BlobImpl.
   void
   FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper,
                       const nsAString& aFullPath, const nsAString& aType,
                       const nsAString& aName,
                       const Optional<int64_t>& aLastModified,
-                      bool aIsFromNsIFile);
+                      bool aExistenceCheck, bool aIsFromNsIFile);
 
 private:
   static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
   void StartForceKillTimer();
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   virtual void ProcessingError(Result aCode, const char* aReason) override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5140,23 +5140,25 @@ ContentParent::RecvClassifyLocal(const U
 
 mozilla::ipc::IPCResult
 ContentParent::RecvFileCreationRequest(const nsID& aID,
                                        const nsString& aFullPath,
                                        const nsString& aType,
                                        const nsString& aName,
                                        const bool& aLastModifiedPassed,
                                        const int64_t& aLastModified,
+                                       const bool& aExistenceCheck,
                                        const bool& aIsFromNsIFile)
 {
   RefPtr<BlobImpl> blobImpl;
   nsresult rv =
     FileCreatorHelper::CreateBlobImplForIPC(aFullPath, aType, aName,
                                             aLastModifiedPassed,
-                                            aLastModified, aIsFromNsIFile,
+                                            aLastModified, aExistenceCheck,
+                                            aIsFromNsIFile,
                                             getter_AddRefs(blobImpl));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     if (!SendFileCreationResponse(aID, FileCreationErrorResult(rv))) {
       return IPC_FAIL_NO_REASON(this);
     }
 
     return IPC_OK();
   }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1107,16 +1107,17 @@ private:
 
   virtual mozilla::ipc::IPCResult RecvDeleteGetFilesRequest(const nsID& aID) override;
 
   virtual mozilla::ipc::IPCResult
   RecvFileCreationRequest(const nsID& aID, const nsString& aFullPath,
                           const nsString& aType, const nsString& aName,
                           const bool& aLastModifiedPassed,
                           const int64_t& aLastModified,
+                          const bool& aExistenceCheck,
                           const bool& aIsFromNsIFile) override;
 
   virtual mozilla::ipc::IPCResult RecvAccumulateChildHistograms(
     InfallibleTArray<Accumulation>&& aAccumulations) override;
   virtual mozilla::ipc::IPCResult RecvAccumulateChildKeyedHistograms(
     InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
   virtual mozilla::ipc::IPCResult RecvUpdateChildScalars(
     InfallibleTArray<ScalarAction>&& aScalarActions) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1172,17 +1172,18 @@ parent:
      */
      async NotifyLowMemory();
 
      async GetFilesRequest(nsID aID, nsString aDirectory, bool aRecursiveFlag);
      async DeleteGetFilesRequest(nsID aID);
 
      async FileCreationRequest(nsID aID, nsString aFullPath, nsString aType,
                                nsString aName, bool lastModifiedPassed,
-                               int64_t lastModified, bool aIsFromNsIFile);
+                               int64_t lastModified, bool aExistenceCheck,
+                               bool aIsFromNsIFile);
 
      async StoreAndBroadcastBlobURLRegistration(nsCString url, PBlob blob,
                                                 Principal principal);
 
      async UnstoreAndBroadcastBlobURLUnregistration(nsCString url);
 
      async BroadcastLocalStorageChange(nsString documentURI,
                                        nsString key,
--- a/dom/ipc/tests/test_bug1086684.html
+++ b/dom/ipc/tests/test_bug1086684.html
@@ -20,17 +20,17 @@
     function childFrameScript() {
       "use strict";
 
       let { MockFilePicker } =
         Components.utils.import("chrome://specialpowers/content/MockFilePicker.jsm", {});
 
       function parentReady(message) {
         MockFilePicker.init(content);
-        MockFilePicker.returnFiles = [message.data.file];
+        MockFilePicker.setFiles([message.data.file]);
         MockFilePicker.returnValue = MockFilePicker.returnOK;
 
         let input = content.document.getElementById("f");
         input.addEventListener("change", () => {
           MockFilePicker.cleanup();
           let value = input.value;
           message.target.sendAsyncMessage("testBug1086684:childDone", { value });
         });
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -21,16 +21,17 @@ interface File : Blob {
 
 dictionary FilePropertyBag {
   DOMString type = "";
   long long lastModified;
 };
 
 dictionary ChromeFilePropertyBag : FilePropertyBag {
   DOMString name = "";
+  boolean existenceCheck = true;
 };
 
 // Mozilla extensions
 partial interface File {
   [GetterThrows, Deprecated="FileLastModifiedDate"]
   readonly attribute Date lastModifiedDate;
 
   [BinaryName="relativePath", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -5047,17 +5047,17 @@ HTMLEditRules::CheckForInvisibleBR(Eleme
   }
 
   return nullptr;
 }
 
 /**
  * aLists and aTables allow the caller to specify what kind of content to
  * "look inside".  If aTables is Tables::yes, look inside any table content,
- * and insert the inner content into the supplied issupportsarray at offset
+ * and insert the inner content into the supplied nsTArray at offset
  * aIndex.  Similarly with aLists and list content.  aIndex is updated to
  * point past inserted elements.
  */
 void
 HTMLEditRules::GetInnerContent(
                  nsINode& aNode,
                  nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                  int32_t* aIndex,
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -77,17 +77,17 @@ fails-if(Android) needs-focus != spellch
 needs-focus == spellcheck-non-latin-arabic.html spellcheck-non-latin-arabic-ref.html
 needs-focus == spellcheck-non-latin-chinese-simplified.html spellcheck-non-latin-chinese-simplified-ref.html
 needs-focus == spellcheck-non-latin-chinese-traditional.html spellcheck-non-latin-chinese-traditional-ref.html
 needs-focus == spellcheck-non-latin-hebrew.html spellcheck-non-latin-hebrew-ref.html
 needs-focus == spellcheck-non-latin-japanese.html spellcheck-non-latin-japanese-ref.html
 needs-focus == spellcheck-non-latin-korean.html spellcheck-non-latin-korean-ref.html
 == unneeded_scroll.html unneeded_scroll-ref.html
 == caret_on_presshell_reinit.html caret_on_presshell_reinit-ref.html
-fuzzy-if(browserIsRemote,255,3) asserts-if(browserIsRemote,0-2) == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html
+fuzzy-if(browserIsRemote,255,3) asserts-if(browserIsRemote,0-2) asserts-if(webrender&&!browserIsRemote,0-1) == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,102,2824) == 642800.html 642800-ref.html
 == selection_visibility_after_reframe.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-3.html selection_visibility_after_reframe-ref.html
 == 672709.html 672709-ref.html
 == 338427-1.html 338427-1-ref.html
 skip-if(Android) needs-focus == 674212-spellcheck.html 674212-spellcheck-ref.html
 skip-if(Android) needs-focus == 338427-2.html 338427-2-ref.html
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -74,9 +74,9 @@ there is another crate in m-c called moz
 the same folder to store its rust dependencies. If one of the libraries that is
 required by both mozjs_sys and webrender is updated without updating the other
 project's Cargo.lock file, that results in build bustage.
 This means that any time you do this sort of manual update of packages, you need
 to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
 the need to run the cargo update command in js/src as well. Hopefully this will
 be resolved soon.
 
-Latest Commit: edc74274d28b1fa1229a1d1ea05027f57172b992
+Latest Commit: 501e3d79c8a3019762bd8bd2d00eecf7811a84de
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1125,17 +1125,17 @@ CompositorBridgeChild::WillEndTransactio
 
 void
 CompositorBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
 PWebRenderBridgeChild*
-CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*)
+CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*, uint32_t *aIdNamespace)
 {
   WebRenderBridgeChild* child = new WebRenderBridgeChild(aPipelineId);
   child->AddIPDLReference();
   return child;
 }
 
 bool
 CompositorBridgeChild::DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor)
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -218,17 +218,18 @@ public:
 
   PAPZChild* AllocPAPZChild(const uint64_t& aLayersId) override;
   bool DeallocPAPZChild(PAPZChild* aActor) override;
 
   void ProcessingError(Result aCode, const char* aReason) override;
 
   void WillEndTransaction();
 
-  PWebRenderBridgeChild* AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*) override;
+  PWebRenderBridgeChild* AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*,
+                                                    uint32_t*) override;
   bool DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor) override;
 
   uint64_t DeviceResetSequenceNumber() const {
     return mDeviceResetSequenceNumber;
   }
 
 private:
   // Private destructor, to discourage deletion outside of Release():
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1567,17 +1567,18 @@ CompositorBridgeParent::RecvAdoptChild(c
   if (mApzcTreeManager && parent) {
     parent->ChildAdopted(mApzcTreeManager);
   }
   return IPC_OK();
 }
 
 PWebRenderBridgeParent*
 CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
-                                                    TextureFactoryIdentifier* aTextureFactoryIdentifier)
+                                                    TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                                    uint32_t* aIdNamespace)
 {
 #ifndef MOZ_ENABLE_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
   // child process invoking this codepath before it's ready
   MOZ_RELEASE_ASSERT(false);
 #endif
   MOZ_ASSERT(aPipelineId.mHandle == mRootLayerTreeID);
   MOZ_ASSERT(!mWrBridge);
@@ -1586,17 +1587,18 @@ CompositorBridgeParent::AllocPWebRenderB
 
 
   MOZ_ASSERT(mWidget);
   RefPtr<widget::CompositorWidget> widget = mWidget;
   RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(gfxPrefs::WebRenderProfilerEnabled(), this, Move(widget));
   RefPtr<WebRenderCompositableHolder> holder = new WebRenderCompositableHolder();
   MOZ_ASSERT(api); // TODO have a fallback
   api->SetRootPipeline(aPipelineId);
-  mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, Move(api), Move(holder));
+  mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(holder));
+  *aIdNamespace = mWrBridge->GetIdNameSpace();
 
   mCompositorScheduler = mWrBridge->CompositorScheduler();
   MOZ_ASSERT(mCompositorScheduler);
   mWrBridge.get()->AddRef(); // IPDL reference
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   auto pipelineHandle = aPipelineId.mHandle;
   MOZ_ASSERT(sIndirectLayerTrees[pipelineHandle].mWrBridge == nullptr);
   sIndirectLayerTrees[pipelineHandle].mWrBridge = mWrBridge;
@@ -1811,18 +1813,54 @@ CompositorBridgeParent::LayerTreeState::
 {
   return mParent;
 }
 
 void
 CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
                                      TimeStamp& aCompositeEnd)
 {
-  NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
-  mPendingTransaction = 0;
+  if (mWrBridge) {
+    NotifyDidComposite(mWrBridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
+  } else {
+    NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
+    mPendingTransaction = 0;
+  }
+}
+
+void
+CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
+{
+  if (mPaused) {
+    return;
+  }
+  MOZ_ASSERT(mWrBridge);
+
+  if (mWrBridge->PipelineId() == aPipelineId) {
+    uint64_t transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
+    Unused << SendDidComposite(0, transactionId, aCompositeStart, aCompositeEnd);
+
+    nsTArray<ImageCompositeNotificationInfo> notifications;
+    mWrBridge->ExtractImageCompositeNotifications(&notifications);
+    if (!notifications.IsEmpty()) {
+      Unused << ImageBridgeParent::NotifyImageComposites(notifications);
+    }
+    return;
+  }
+
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
+    if (lts->mCrossProcessParent &&
+        lts->mWrBridge &&
+        lts->mWrBridge->PipelineId() == aPipelineId) {
+      CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
+      uint64_t transactionId = lts->mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
+      Unused << cpcp->SendDidComposite(aLayersId, transactionId, aCompositeStart, aCompositeEnd);
+    }
+  });
 }
 
 void
 CompositorBridgeParent::NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
 {
   Unused << SendDidComposite(0, aTransactionId, aCompositeStart, aCompositeEnd);
 
   if (mLayerManager) {
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -31,16 +31,17 @@
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorVsyncSchedulerOwner.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/MetricsSharingController.h"
 #include "mozilla/layers/PCompositorBridgeParent.h"
 #include "mozilla/layers/APZTestData.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "nsISupportsImpl.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class MessageLoop;
 class nsIWidget;
 
 namespace mozilla {
@@ -113,17 +114,17 @@ public:
   virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
 
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   virtual mozilla::ipc::IPCResult RecvSyncWithCompositor() override { return IPC_OK(); }
 
   virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0;
 
-  virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
+  virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
 
   // HostIPCAllocator
   virtual base::ProcessId GetChildProcessId() override;
   virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
 
   // ShmemAllocator
   virtual bool AllocShmem(size_t aSize,
@@ -446,17 +447,18 @@ public:
 
   RefPtr<APZCTreeManager> GetAPZCTreeManager();
 
   CompositorOptions GetOptions() const {
     return mOptions;
   }
 
   PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
-                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier) override;
+                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                                      uint32_t* aIdNamespace) override;
   bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
   static void SetWebRenderProfilerEnabled(bool aEnabled);
 
   static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId);
 private:
 
   void Initialize();
 
@@ -544,17 +546,19 @@ protected:
   /**
    * Return true if current state allows compositing, that is
    * finishing a layers transaction.
    */
   bool CanComposite();
 
   void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
-  virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
+  virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
+
+  void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
   // The indirect layer tree lock must be held before calling this function.
   // Callback should take (LayerTreeState* aState, const uint64_t& aLayersId)
   template <typename Lambda>
   inline void ForEachIndirectLayerTree(const Lambda& aCallback);
 
   RefPtr<HostLayerManager> mLayerManager;
   RefPtr<Compositor> mCompositor;
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -193,17 +193,18 @@ CrossProcessCompositorBridgeParent::Deal
 {
   RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
   controller->Release();
   return true;
 }
 
 PWebRenderBridgeParent*
 CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
-                                                                TextureFactoryIdentifier* aTextureFactoryIdentifier)
+                                                                TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                                                uint32_t *aIdNamespace)
 {
 #ifndef MOZ_ENABLE_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
   // child process invoking this codepath before it's ready
   MOZ_RELEASE_ASSERT(false);
 #endif
   // Check to see if this child process has access to this layer tree.
   if (!LayerTreeOwnerTracker::Get()->IsMapped(aPipelineId.mHandle, OtherPid())) {
@@ -216,22 +217,24 @@ CrossProcessCompositorBridgeParent::Allo
   MOZ_ASSERT(sIndirectLayerTrees.find(pipelineHandle) != sIndirectLayerTrees.end());
   MOZ_ASSERT(sIndirectLayerTrees[pipelineHandle].mWrBridge == nullptr);
   CompositorBridgeParent* cbp = sIndirectLayerTrees[pipelineHandle].mParent;
   WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get();
 
   WebRenderBridgeParent* parent = nullptr;
   RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
   RefPtr<WebRenderCompositableHolder> holder = root->CompositableHolder();
-  parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, Move(api), Move(holder));
+  parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, root->CompositorScheduler(), Move(api), Move(holder));
 
   parent->AddRef(); // IPDL reference
   sIndirectLayerTrees[pipelineHandle].mCrossProcessParent = this;
   sIndirectLayerTrees[pipelineHandle].mWrBridge = parent;
   *aTextureFactoryIdentifier = parent->GetTextureFactoryIdentifier();
+  *aIdNamespace = parent->GetIdNameSpace();
+
   return parent;
 }
 
 bool
 CrossProcessCompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
 {
 #ifndef MOZ_ENABLE_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
@@ -318,18 +321,17 @@ CrossProcessCompositorBridgeParent::DidC
   TimeStamp& aCompositeStart,
   TimeStamp& aCompositeEnd)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
     Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
     layerTree->SetPendingTransactionId(0);
   } else if (WebRenderBridgeParent* wrbridge = sIndirectLayerTrees[aId].mWrBridge) {
-    Unused << SendDidComposite(aId, wrbridge->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
-    wrbridge->SetPendingTransactionId(0);
+    Unused << SendDidComposite(aId, wrbridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
   }
 }
 
 void
 CrossProcessCompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
   uint64_t id = aLayerTree->GetId();
   MOZ_ASSERT(id != 0);
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -147,17 +147,18 @@ public:
   virtual bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
 
   virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
   virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
 
   virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override;
 
   PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
-                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier) override;
+                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                                      uint32_t* aIdNamespace) override;
   bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
 
   void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override;
 
 protected:
   void OnChannelConnected(int32_t pid) override {
     mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();
   }
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -238,17 +238,17 @@ parent:
   async AllPluginsCaptured();
 
   async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id, uint64_t aSerial);
 
   sync SyncWithCompositor();
 
   // The pipelineId is the same as the layersId
   sync PWebRenderBridge(PipelineId pipelineId)
-    returns (TextureFactoryIdentifier textureFactoryIdentifier);
+    returns (TextureFactoryIdentifier textureFactoryIdentifier, uint32_t idNamespace); //XXX: use the WrIdNamespace type
 
 child:
   // Send back Compositor Frame Metrics from APZCs so tiled layers can
   // update progressively.
   async SharedCompositorFrameMetrics(Handle metrics, CrossProcessMutexHandle mutex, uint64_t aLayersId, uint32_t aAPZCId);
   async ReleaseSharedCompositorFrameMetrics(ViewID aId, uint32_t aAPZCId);
 };
 
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -13,38 +13,42 @@ include "mozilla/layers/WebRenderMessage
 include WebRenderMessages;
 include protocol PCompositorBridge;
 include protocol PTexture;
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
+using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
+using WrAuxiliaryListsDescriptor from "mozilla/webrender/webrender_ffi.h";
 
 namespace mozilla {
 namespace layers {
 
 sync protocol PWebRenderBridge
 {
   manager PCompositorBridge;
 
 parent:
   async NewCompositable(CompositableHandle handle, TextureInfo info);
   async ReleaseCompositable(CompositableHandle compositable);
 
   sync Create(IntSize aSize);
-  sync AddImage(IntSize aSize, uint32_t aStride,
-                SurfaceFormat aFormat, ByteBuffer aBytes)
-    returns (ImageKey aOutImageKey);
+  sync AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
+                SurfaceFormat aFormat, ByteBuffer aBytes);
   sync UpdateImage(ImageKey aImageKey, IntSize aSize,
                    SurfaceFormat aFormat, ByteBuffer aBytes);
   sync DeleteImage(ImageKey aImageKey);
+  async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
   async DPBegin(IntSize aSize);
-  async DPEnd(WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
-  sync DPSyncEnd(WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
+  async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
+              ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
+  sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
+                 ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
   sync DPGetSnapshot(PTexture texture);
   async AddExternalImageId(uint64_t aImageId, CompositableHandle aHandle);
   async AddExternalImageIdForCompositable(uint64_t aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(uint64_t aImageId);
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
   async ClearCachedResources();
 
   async Shutdown();
--- a/gfx/layers/ipc/WebRenderMessages.ipdlh
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -21,16 +21,17 @@ using WrGlyphArray from "mozilla/webrend
 using WrMixBlendMode from "mozilla/webrender/webrender_ffi.h";
 using WrBoxShadowClipMode from "mozilla/webrender/webrender_ffi.h";
 using MaybeImageMask from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
 using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageRendering from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
+using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::LayerIntRegion from "Units.h";
 
 namespace mozilla {
 namespace layers {
 
 struct OpDPPushStackingContext {
   WrRect bounds;
   WrRect overflow;
@@ -92,39 +93,33 @@ struct OpDPPushRadialGradient {
 struct OpDPPushImage {
   WrRect bounds;
   WrRect clip;
   MaybeImageMask mask;
   ImageRendering filter;
   ImageKey key;
 };
 
-struct OpDPPushExternalImageId {
-  LayerIntRegion validBufferRegion;
-  WrRect bounds;
-  WrRect clip;
-  MaybeImageMask mask;
-  ImageRendering filter;
+struct OpAddExternalImage {
   uint64_t externalImageId;
+  ImageKey key;
 };
 
 struct OpDPPushIframe {
   WrRect bounds;
   WrRect clip;
   PipelineId pipelineId;
 };
 
 struct OpDPPushText {
   WrRect bounds;
   WrRect clip;
   WrGlyphArray[] glyph_array;
-  uint32_t font_index;
   float glyph_size;
-  ByteBuffer font_buffer;
-  uint32_t font_buffer_length;
+  FontKey key;
 };
 
 struct OpDPPushBoxShadow {
   WrRect rect;
   WrRect clip;
   WrRect box_bounds;
   WrPoint offset;
   WrColor color;
@@ -139,17 +134,20 @@ union WebRenderCommand {
   OpDPPopStackingContext;
   OpDPPushScrollLayer;
   OpDPPopScrollLayer;
   OpDPPushRect;
   OpDPPushBorder;
   OpDPPushLinearGradient;
   OpDPPushRadialGradient;
   OpDPPushImage;
-  OpDPPushExternalImageId;
   OpDPPushIframe;
   OpDPPushText;
   OpDPPushBoxShadow;
+};
+
+union WebRenderParentCommand {
+  OpAddExternalImage;
   CompositableOperation;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -6,22 +6,26 @@
 
 #include "mozilla/layers/WebRenderBridgeChild.h"
 
 #include "gfxPlatform.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/PTextureChild.h"
+#include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
   : mIsInTransaction(false)
+  , mIdNamespace(0)
+  , mResourceId(0)
+  , mPipelineId(aPipelineId)
   , mIPCOpen(false)
   , mDestroyed(false)
 {
 }
 
 void
 WebRenderBridgeChild::Destroy()
 {
@@ -50,40 +54,168 @@ WebRenderBridgeChild::AddWebRenderComman
 
 void
 WebRenderBridgeChild::AddWebRenderCommands(const nsTArray<WebRenderCommand>& aCommands)
 {
   MOZ_ASSERT(mIsInTransaction);
   mCommands.AppendElements(aCommands);
 }
 
+void
+WebRenderBridgeChild::AddWebRenderParentCommand(const WebRenderParentCommand& aCmd)
+{
+  MOZ_ASSERT(mIsInTransaction);
+  mParentCommands.AppendElement(aCmd);
+}
+
+void
+WebRenderBridgeChild::AddWebRenderParentCommands(const nsTArray<WebRenderParentCommand>& aCommands)
+{
+  MOZ_ASSERT(mIsInTransaction);
+  mParentCommands.AppendElements(aCommands);
+}
+
 bool
 WebRenderBridgeChild::DPBegin(const gfx::IntSize& aSize)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(!mIsInTransaction);
 
   UpdateFwdTransactionId();
   this->SendDPBegin(aSize);
   mIsInTransaction = true;
   return true;
 }
 
+wr::BuiltDisplayList
+WebRenderBridgeChild::ProcessWebrenderCommands(const gfx::IntSize &aSize,
+                                               InfallibleTArray<WebRenderCommand>& aCommands)
+{
+  wr::DisplayListBuilder builder(mPipelineId);
+  builder.Begin(ViewAs<LayerPixel>(aSize));
+
+  for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
+    const WebRenderCommand& cmd = aCommands[i];
+
+    switch (cmd.type()) {
+      case WebRenderCommand::TOpDPPushStackingContext: {
+        const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
+        builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPopStackingContext: {
+        builder.PopStackingContext();
+        break;
+      }
+      case WebRenderCommand::TOpDPPushScrollLayer: {
+        const OpDPPushScrollLayer& op = cmd.get_OpDPPushScrollLayer();
+        builder.PushScrollLayer(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr));
+        break;
+      }
+      case WebRenderCommand::TOpDPPopScrollLayer: {
+        builder.PopScrollLayer();
+        break;
+      }
+      case WebRenderCommand::TOpDPPushRect: {
+        const OpDPPushRect& op = cmd.get_OpDPPushRect();
+        builder.PushRect(op.bounds(), op.clip(), op.color());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushBorder: {
+        const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
+        builder.PushBorder(op.bounds(), op.clip(),
+                           op.top(), op.right(), op.bottom(), op.left(),
+                           op.radius());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushLinearGradient: {
+        const OpDPPushLinearGradient& op = cmd.get_OpDPPushLinearGradient();
+        builder.PushLinearGradient(op.bounds(), op.clip(),
+                                   op.startPoint(), op.endPoint(),
+                                   op.stops(), op.extendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushRadialGradient: {
+        const OpDPPushRadialGradient& op = cmd.get_OpDPPushRadialGradient();
+        builder.PushRadialGradient(op.bounds(), op.clip(),
+                                   op.startCenter(), op.endCenter(),
+                                   op.startRadius(), op.endRadius(),
+                                   op.stops(), op.extendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushImage: {
+        const OpDPPushImage& op = cmd.get_OpDPPushImage();
+        builder.PushImage(op.bounds(), op.clip(),
+                          op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
+        break;
+      }
+      case WebRenderCommand::TOpDPPushIframe: {
+        const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
+        builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushText: {
+        const OpDPPushText& op = cmd.get_OpDPPushText();
+        const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
+
+        for (size_t i = 0; i < glyph_array.Length(); i++) {
+          const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
+          builder.PushText(op.bounds(),
+                           op.clip(),
+                           glyph_array[i].color,
+                           op.key(),
+                           Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
+                           op.glyph_size());
+        }
+
+        break;
+      }
+      case WebRenderCommand::TOpDPPushBoxShadow: {
+        const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
+        builder.PushBoxShadow(op.rect(),
+                              op.clip(),
+                              op.box_bounds(),
+                              op.offset(),
+                              op.color(),
+                              op.blur_radius(),
+                              op.spread_radius(),
+                              op.border_radius(),
+                              op.clip_mode());
+        break;
+      }
+      default:
+        NS_RUNTIMEABORT("not reached");
+    }
+  }
+  builder.End();
+  wr::BuiltDisplayList dl;
+  builder.Finalize(dl.dl_desc, dl.dl, dl.aux_desc, dl.aux);
+  return dl;
+}
+
 void
-WebRenderBridgeChild::DPEnd(bool aIsSync, uint64_t aTransactionId)
+WebRenderBridgeChild::DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(mIsInTransaction);
+
+  wr::BuiltDisplayList dl = ProcessWebrenderCommands(aSize, mCommands);
+  ByteBuffer dlData(Move(dl.dl));
+  ByteBuffer auxData(Move(dl.aux));
+
   if (aIsSync) {
-    this->SendDPSyncEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
+    this->SendDPSyncEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
+                        dlData, dl.dl_desc, auxData, dl.aux_desc);
   } else {
-    this->SendDPEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
+    this->SendDPEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
+                    dlData, dl.dl_desc, auxData, dl.aux_desc);
   }
 
   mCommands.Clear();
+  mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 uint64_t
 WebRenderBridgeChild::GetNextExternalImageId()
 {
   static uint32_t sNextID = 1;
@@ -216,17 +348,17 @@ WebRenderBridgeChild::RemoveTextureFromC
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->GetIPDLActor());
   MOZ_RELEASE_ASSERT(aTexture->GetIPDLActor()->GetIPCChannel() == GetIPCChannel());
   if (!aCompositable->IsConnected() || !aTexture->GetIPDLActor()) {
     // We don't have an actor anymore, don't try to use it!
     return;
   }
 
-  AddWebRenderCommand(
+  AddWebRenderParentCommand(
     CompositableOperation(
       aCompositable->GetIPCHandle(),
       OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
 }
 
 void
 WebRenderBridgeChild::UseTextures(CompositableClient* aCompositable,
                                   const nsTArray<TimedTextureClient>& aTextures)
@@ -246,17 +378,17 @@ WebRenderBridgeChild::UseTextures(Compos
     ReadLockDescriptor readLock;
     t.mTextureClient->SerializeReadLock(readLock);
     textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
                                         readLock,
                                         t.mTimeStamp, t.mPictureRect,
                                         t.mFrameID, t.mProducerID));
     GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
-  AddWebRenderCommand(CompositableOperation(aCompositable->GetIPCHandle(),
+  AddWebRenderParentCommand(CompositableOperation(aCompositable->GetIPCHandle(),
                                             OpUseTexture(textures)));
 }
 
 void
 WebRenderBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
                                                 TextureClient* aClientOnBlack,
                                                 TextureClient* aClientOnWhite)
 {
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -27,19 +27,21 @@ class WebRenderBridgeChild final : publi
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderBridgeChild, override)
 
 public:
   explicit WebRenderBridgeChild(const wr::PipelineId& aPipelineId);
 
   void AddWebRenderCommand(const WebRenderCommand& aCmd);
   void AddWebRenderCommands(const nsTArray<WebRenderCommand>& aCommands);
+  void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd);
+  void AddWebRenderParentCommands(const nsTArray<WebRenderParentCommand>& aCommands);
 
   bool DPBegin(const  gfx::IntSize& aSize);
-  void DPEnd(bool aIsSync, uint64_t aTransactionId);
+  void DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId);
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   // KnowsCompositor
   TextureForwarder* GetTextureForwarder() override;
   LayersIPCActor* GetLayersIPCActor() override;
 
   uint64_t AllocExternalImageId(const CompositableHandle& aHandle);
@@ -49,23 +51,33 @@ public:
   /**
    * Clean this up, finishing with SendShutDown() which will cause __delete__
    * to be sent from the parent side.
    */
   void Destroy();
   bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
   bool IsDestroyed() const { return mDestroyed; }
 
+  uint32_t GetNextResourceId() { return ++mResourceId; }
+  uint32_t GetNamespace() { return mIdNamespace; }
+  void SetNamespace(uint32_t aIdNamespace)
+  {
+    mIdNamespace = aIdNamespace;
+  }
+
 private:
   friend class CompositorBridgeChild;
 
   ~WebRenderBridgeChild() {}
 
   uint64_t GetNextExternalImageId();
 
+  wr::BuiltDisplayList ProcessWebrenderCommands(const gfx::IntSize &aSize,
+                                                InfallibleTArray<WebRenderCommand>& aCommands);
+
   // CompositableForwarder
   void Connect(CompositableClient* aCompositable,
                ImageContainer* aImageContainer = nullptr) override;
   void UseTiledLayerBuffer(CompositableClient* aCompositable,
                            const SurfaceDescriptorTiles& aTiledDescriptor) override;
   void UpdateTextureRegion(CompositableClient* aCompositable,
                            const ThebesBufferData& aThebesBufferData,
                            const nsIntRegion& aUpdatedRegion) override;
@@ -94,19 +106,23 @@ private:
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
 
   bool AddOpDestroy(const OpDestroy& aOp);
 
   nsTArray<WebRenderCommand> mCommands;
+  nsTArray<WebRenderParentCommand> mParentCommands;
   nsTArray<OpDestroy> mDestroyedActors;
   nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
   bool mIsInTransaction;
+  uint32_t mIdNamespace;
+  uint32_t mResourceId;
+  wr::PipelineId mPipelineId;
 
   bool mIPCOpen;
   bool mDestroyed;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -16,16 +16,21 @@
 #include "mozilla/layers/CompositorVsyncScheduler.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/WebRenderCompositableHolder.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/widget/CompositorWidget.h"
 
+bool is_in_main_thread()
+{
+  return NS_IsMainThread();
+}
+
 bool is_in_compositor_thread()
 {
   return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
 }
 
 bool is_in_render_thread()
 {
   return mozilla::wr::RenderThread::IsInRenderThread();
@@ -70,51 +75,52 @@ public:
       }
     }
   }
 private:
   WebRenderBridgeParent* mWebRenderBridgeParent;
   InfallibleTArray<OpDestroy>* mActorsToDestroy;
 };
 
+/* static */ uint32_t WebRenderBridgeParent::sIdNameSpace = 0;
+
 WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
                                              const wr::PipelineId& aPipelineId,
                                              widget::CompositorWidget* aWidget,
+                                             CompositorVsyncScheduler* aScheduler,
                                              RefPtr<wr::WebRenderAPI>&& aApi,
                                              RefPtr<WebRenderCompositableHolder>&& aHolder)
   : mCompositorBridge(aCompositorBridge)
   , mPipelineId(aPipelineId)
   , mWidget(aWidget)
-  , mBuilder(Nothing())
   , mApi(aApi)
   , mCompositableHolder(aHolder)
+  , mCompositorScheduler(aScheduler)
   , mChildLayerObserverEpoch(0)
   , mParentLayerObserverEpoch(0)
-  , mPendingTransactionId(0)
+  , mWrEpoch(0)
+  , mIdNameSpace(++sIdNameSpace)
   , mDestroyed(false)
 {
   MOZ_ASSERT(mCompositableHolder);
   if (mWidget) {
+    MOZ_ASSERT(!mCompositorScheduler);
     mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
   }
 }
 
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
 
-  if (mBuilder.isSome()) {
-    return IPC_OK();
-  }
   MOZ_ASSERT(mApi);
-  mBuilder.emplace(LayerIntSize(aSize.width, aSize.height), mPipelineId);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvShutdown()
 {
   if (mDestroyed) {
@@ -128,40 +134,56 @@ WebRenderBridgeParent::RecvShutdown()
 }
 
 void
 WebRenderBridgeParent::Destroy()
 {
   if (mDestroyed) {
     return;
   }
-  MOZ_ASSERT(mBuilder.isSome());
   mDestroyed = true;
   ClearResources();
 }
 
 mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvAddImage(const gfx::IntSize& aSize,
+WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
+				    const gfx::IntSize& aSize,
                                     const uint32_t& aStride,
                                     const gfx::SurfaceFormat& aFormat,
-                                    const ByteBuffer& aBuffer,
-                                    wr::ImageKey* aOutImageKey)
+                                    const ByteBuffer& aBuffer)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   MOZ_ASSERT(mApi);
   wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
-  *aOutImageKey = mApi->AddImageBuffer(descriptor,
-                                       aBuffer.AsSlice());
+  mApi->AddImage(aImageKey, descriptor,
+                 aBuffer.AsSlice());
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey,
+                                      const ByteBuffer& aBuffer,
+                                      const uint32_t& aFontIndex)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mApi);
+  auto slice = aBuffer.AsSlice();
+  mApi->AddRawFont(aFontKey, slice);
+
+  return IPC_OK();
+}
+
+
+
+mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvUpdateImage(const wr::ImageKey& aImageKey,
                                        const gfx::IntSize& aSize,
                                        const gfx::SurfaceFormat& aFormat,
                                        const ByteBuffer& aBuffer)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
@@ -184,234 +206,143 @@ WebRenderBridgeParent::RecvDeleteImage(c
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPBegin(const gfx::IntSize& aSize)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
-  MOZ_ASSERT(mBuilder.isSome());
-  mBuilder.ref().Begin(LayerIntSize(aSize.width, aSize.height));
   return IPC_OK();
 }
 
 void
-WebRenderBridgeParent::HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
+                                 InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
-                                 const uint64_t& aTransactionId)
+                                 const uint64_t& aTransactionId,
+                                 const ByteBuffer& dl,
+                                 const WrBuiltDisplayListDescriptor& dlDesc,
+                                 const ByteBuffer& aux,
+                                 const WrAuxiliaryListsDescriptor& auxDesc)
 {
   UpdateFwdTransactionId(aFwdTransactionId);
 
   if (mDestroyed) {
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
     return;
   }
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvDPEnd without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
-  ProcessWebrenderCommands(aCommands, wr::NewEpoch(aTransactionId));
-
-  // The transaction ID might get reset to 1 if the page gets reloaded, see
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
-  // Otherwise, it should be continually increasing.
-  MOZ_ASSERT(aTransactionId == 1 || aTransactionId > mPendingTransactionId);
-  mPendingTransactionId = aTransactionId;
+  ++mWrEpoch; // Update webrender epoch
+  ProcessWebrenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch),
+                           dl, dlDesc, aux, auxDesc);
+  HoldPendingTransactionId(mWrEpoch, aTransactionId);
 }
 
 mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
+                                 InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
-                                 const uint64_t& aTransactionId)
+                                 const uint64_t& aTransactionId,
+                                 const ByteBuffer& dl,
+                                 const WrBuiltDisplayListDescriptor& dlDesc,
+                                 const ByteBuffer& aux,
+                                 const WrAuxiliaryListsDescriptor& auxDesc)
 {
-  HandleDPEnd(Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
+  HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
+              dl, dlDesc, aux, auxDesc);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvDPSyncEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
+                                     InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                      InfallibleTArray<OpDestroy>&& aToDestroy,
                                      const uint64_t& aFwdTransactionId,
-                                     const uint64_t& aTransactionId)
+                                     const uint64_t& aTransactionId,
+                                     const ByteBuffer& dl,
+                                     const WrBuiltDisplayListDescriptor& dlDesc,
+                                     const ByteBuffer& aux,
+                                     const WrAuxiliaryListsDescriptor& auxDesc)
 {
-  HandleDPEnd(Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
+  HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
+              dl, dlDesc, aux, auxDesc);
   return IPC_OK();
 }
 
 void
-WebRenderBridgeParent::ProcessWebrenderCommands(InfallibleTArray<WebRenderCommand>& aCommands, const wr::Epoch& aEpoch)
+WebRenderBridgeParent::ProcessWebrenderCommands(const gfx::IntSize &aSize,
+                                                InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
+                                                const ByteBuffer& dl,
+                                                const WrBuiltDisplayListDescriptor& dlDesc,
+                                                const ByteBuffer& aux,
+                                                const WrAuxiliaryListsDescriptor& auxDesc)
 {
-  MOZ_ASSERT(mBuilder.isSome());
-  wr::DisplayListBuilder& builder = mBuilder.ref();
   // XXX remove it when external image key is used.
   std::vector<wr::ImageKey> keysToDelete;
 
-  for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
-    const WebRenderCommand& cmd = aCommands[i];
+  for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
+    const WebRenderParentCommand& cmd = aCommands[i];
 
     switch (cmd.type()) {
-      case WebRenderCommand::TOpDPPushStackingContext: {
-        const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
-        builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
-        break;
-      }
-      case WebRenderCommand::TOpDPPopStackingContext: {
-        builder.PopStackingContext();
-        break;
-      }
-      case WebRenderCommand::TOpDPPushScrollLayer: {
-        const OpDPPushScrollLayer& op = cmd.get_OpDPPushScrollLayer();
-        builder.PushScrollLayer(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr));
-        break;
-      }
-      case WebRenderCommand::TOpDPPopScrollLayer: {
-        builder.PopScrollLayer();
-        break;
-      }
-      case WebRenderCommand::TOpDPPushRect: {
-        const OpDPPushRect& op = cmd.get_OpDPPushRect();
-        builder.PushRect(op.bounds(), op.clip(), op.color());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushBorder: {
-        const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
-        builder.PushBorder(op.bounds(), op.clip(),
-                           op.top(), op.right(), op.bottom(), op.left(),
-                           op.radius());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushLinearGradient: {
-        const OpDPPushLinearGradient& op = cmd.get_OpDPPushLinearGradient();
-        builder.PushLinearGradient(op.bounds(), op.clip(),
-                                   op.startPoint(), op.endPoint(),
-                                   op.stops(), op.extendMode());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushRadialGradient: {
-        const OpDPPushRadialGradient& op = cmd.get_OpDPPushRadialGradient();
-        builder.PushRadialGradient(op.bounds(), op.clip(),
-                                   op.startCenter(), op.endCenter(),
-                                   op.startRadius(), op.endRadius(),
-                                   op.stops(), op.extendMode());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushImage: {
-        const OpDPPushImage& op = cmd.get_OpDPPushImage();
-        builder.PushImage(op.bounds(), op.clip(),
-                          op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
-        break;
-      }
-      case WebRenderCommand::TOpDPPushExternalImageId: {
-        const OpDPPushExternalImageId& op = cmd.get_OpDPPushExternalImageId();
+      case WebRenderParentCommand::TOpAddExternalImage: {
+        const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
         MOZ_ASSERT(mExternalImageIds.Get(op.externalImageId()).get());
 
         RefPtr<CompositableHost> host = mExternalImageIds.Get(op.externalImageId());
         if (!host) {
           break;
         }
         RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
         if (!dSurf) {
           break;
         }
 
-        nsIntRegion validBufferRegion = op.validBufferRegion().ToUnknownRegion();
-        IntRect validRect = IntRect(IntPoint(0,0), dSurf->GetSize());
-        if (!validBufferRegion.IsEmpty()) {
-          IntPoint offset = validBufferRegion.GetBounds().TopLeft();
-          validBufferRegion.MoveBy(-offset);
-          validBufferRegion.AndWith(IntRect(IntPoint(0,0), dSurf->GetSize()));
-          validRect = validBufferRegion.GetBounds().ToUnknownRect();
-
-          // XXX Remove it when we can put subimage in WebRender.
-          RefPtr<DrawTarget> target =
-           gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, validRect.Size(), SurfaceFormat::B8G8R8A8);
-          for (auto iter = validBufferRegion.RectIter(); !iter.Done(); iter.Next()) {
-            IntRect regionRect = iter.Get();
-            Rect srcRect(regionRect.x + offset.x, regionRect.y + offset.y, regionRect.width, regionRect.height);
-            Rect dstRect(regionRect.x, regionRect.y, regionRect.width, regionRect.height);
-            target->DrawSurface(dSurf, dstRect, srcRect);
-          }
-          RefPtr<SourceSurface> surf = target->Snapshot();
-          dSurf = surf->GetDataSurface();
-        }
-
         DataSourceSurface::MappedSurface map;
         if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
           break;
         }
 
-        wr::ImageDescriptor descriptor(validRect.Size(), map.mStride, SurfaceFormat::B8G8R8A8);
-        wr::ImageKey key;
-        auto slice = Range<uint8_t>(map.mData, validRect.height * map.mStride);
-        key = mApi->AddImageBuffer(descriptor, slice);
+        IntSize size = dSurf->GetSize();
+        wr::ImageDescriptor descriptor(size, map.mStride, SurfaceFormat::B8G8R8A8);
+        wr::ImageKey key = op.key();
+        auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
+        mApi->AddImage(key, descriptor, slice);
 
-        builder.PushImage(op.bounds(), op.clip(), op.mask().ptrOr(nullptr), op.filter(), key);
         keysToDelete.push_back(key);
         dSurf->Unmap();
         // XXX workaround for releasing Readlock. See Bug 1339625
         if(host->GetType() == CompositableType::CONTENT_SINGLE) {
           host->CleanupResources();
         }
         break;
       }
-      case WebRenderCommand::TOpDPPushIframe: {
-        const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
-        builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
-        break;
-      }
-      case WebRenderCommand::TCompositableOperation: {
+      case WebRenderParentCommand::TCompositableOperation: {
         if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
           NS_ERROR("ReceiveCompositableUpdate failed");
         }
         break;
       }
-      case WebRenderCommand::TOpDPPushText: {
-        const OpDPPushText& op = cmd.get_OpDPPushText();
-        const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
-
-        // TODO: We are leaking the key
-        wr::FontKey fontKey;
-        auto slice = Range<uint8_t>(op.font_buffer().mData, op.font_buffer_length());
-        fontKey = mApi->AddRawFont(slice);
-
-        for (size_t i = 0; i < glyph_array.Length(); i++) {
-          const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
-          builder.PushText(op.bounds(),
-                           op.clip(),
-                           glyph_array[i].color,
-                           fontKey,
-                           Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
-                           op.glyph_size());
-        }
-
+      default: {
+        // other commands are handle on the child
         break;
       }
-      case WebRenderCommand::TOpDPPushBoxShadow: {
-        const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
-        builder.PushBoxShadow(op.rect(),
-                              op.clip(),
-                              op.box_bounds(),
-                              op.offset(),
-                              op.color(),
-                              op.blur_radius(),
-                              op.spread_radius(),
-                              op.border_radius(),
-                              op.clip_mode());
-        break;
-      }
-      default:
-        NS_RUNTIMEABORT("not reached");
     }
   }
-  builder.End(*mApi, aEpoch);
+  mApi->SetRootDisplayList(gfx::Color(0.3f, 0.f, 0.f, 1.f), aEpoch, LayerSize(aSize.width, aSize.height),
+                           mPipelineId,
+                           dlDesc, dl.mData, dl.mLength,
+                           auxDesc, aux.mData, aux.mLength);
 
   ScheduleComposition();
   DeleteOldImages();
 
   // XXX remove it when external image key is used.
   if (!keysToDelete.empty()) {
     mKeysToDelete.swap(keysToDelete);
   }
@@ -454,17 +385,21 @@ WebRenderBridgeParent::RecvDPGetSnapshot
   // We only support B8G8R8A8 for now.
   MOZ_ASSERT(buffer);
   MOZ_ASSERT(bufferTexture->GetFormat() == SurfaceFormat::B8G8R8A8);
   uint32_t buffer_size = size.width * size.height * 4;
 
   // Assert the stride of the buffer is what webrender expects
   MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
 
-  MOZ_ASSERT(mBuilder.isSome());
+  if (mCompositorScheduler->NeedsComposite()) {
+    mCompositorScheduler->CancelCurrentCompositeTask();
+    mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
+  }
+
   mApi->Readback(size, buffer, buffer_size);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvAddExternalImageId(const uint64_t& aImageId,
                                               const CompositableHandle& aHandle)
@@ -551,25 +486,69 @@ void
 WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   Destroy();
 }
 
 void
 WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect)
 {
-  // TODO(bug 1328602) With the RenderThread, calling SetRootStackingContext
-  // should trigger the composition on the render thread.
-  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  mApi->GenerateFrame();
 }
 
 void
-WebRenderBridgeParent::DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd)
+WebRenderBridgeParent::HoldPendingTransactionId(uint32_t aWrEpoch, uint64_t aTransactionId)
+{
+  // The transaction ID might get reset to 1 if the page gets reloaded, see
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
+  // Otherwise, it should be continually increasing.
+  MOZ_ASSERT(aTransactionId == 1 || aTransactionId > LastPendingTransactionId());
+  // Handle TransactionIdAllocator(RefreshDriver) change.
+  if (aTransactionId == 1) {
+    FlushPendingTransactionIds();
+  }
+  mPendingTransactionIds.push(PendingTransactionId(wr::NewEpoch(aWrEpoch), aTransactionId));
+}
+
+uint64_t
+WebRenderBridgeParent::LastPendingTransactionId()
 {
-  mCompositorBridge->NotifyDidComposite(aTransactionId, aStart, aEnd);
+  uint64_t id = 0;
+  if (!mPendingTransactionIds.empty()) {
+    id = mPendingTransactionIds.back().mId;
+  }
+  return id;
+}
+
+uint64_t
+WebRenderBridgeParent::FlushPendingTransactionIds()
+{
+  uint64_t id = 0;
+  while (!mPendingTransactionIds.empty()) {
+    id = mPendingTransactionIds.front().mId;
+    mPendingTransactionIds.pop();
+  }
+  return id;
+}
+
+
+
+uint64_t
+WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch)
+{
+  uint64_t id = 0;
+  while (!mPendingTransactionIds.empty()) {
+    id = mPendingTransactionIds.front().mId;
+    if (mPendingTransactionIds.front().mEpoch == aEpoch) {
+      mPendingTransactionIds.pop();
+      break;
+    }
+    mPendingTransactionIds.pop();
+  }
+  return id;
 }
 
 WebRenderBridgeParent::~WebRenderBridgeParent()
 {
 }
 
 void
 WebRenderBridgeParent::DeleteOldImages()
@@ -578,43 +557,37 @@ WebRenderBridgeParent::DeleteOldImages()
     mApi->DeleteImage(key);
   }
   mKeysToDelete.clear();
 }
 
 void
 WebRenderBridgeParent::ScheduleComposition()
 {
-  MOZ_ASSERT(mApi);
-  // TODO(bug 1328602) should probably send a message to the render
-  // thread and force rendering, although in most cases where this is
-  // called, rendering should be triggered automatically already (maybe
-  // not in the ImageBridge case).
+  if (mCompositorScheduler) {
+    mCompositorScheduler->ScheduleComposition();
+  }
 }
 
 void
 WebRenderBridgeParent::ClearResources()
 {
   DeleteOldImages();
   if (mCompositableHolder) {
     for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
       uint64_t externalImageId = iter.Key();
       mCompositableHolder->RemoveExternalImageId(externalImageId);
     }
   }
   mExternalImageIds.Clear();
 
-  if (mBuilder.isSome()) {
-    mBuilder.reset();
+  if (mWidget && mCompositorScheduler) {
+    mCompositorScheduler->Destroy();
   }
-  if (mCompositorScheduler) {
-    mCompositorScheduler->Destroy();
-    mCompositorScheduler = nullptr;
-  }
-
+  mCompositorScheduler = nullptr;
   mApi = nullptr;
   mCompositorBridge = nullptr;
 }
 
 bool
 WebRenderBridgeParent::ShouldParentObserveEpoch()
 {
   if (mParentLayerObserverEpoch == mChildLayerObserverEpoch) {
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -41,131 +41,171 @@ class WebRenderCompositableHolder;
 class WebRenderBridgeParent final : public PWebRenderBridgeParent
                                   , public CompositorVsyncSchedulerOwner
                                   , public CompositableParentManager
 {
 public:
   WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
                         const wr::PipelineId& aPipelineId,
                         widget::CompositorWidget* aWidget,
+                        CompositorVsyncScheduler* aScheduler,
                         RefPtr<wr::WebRenderAPI>&& aApi,
                         RefPtr<WebRenderCompositableHolder>&& aHolder);
 
   wr::PipelineId PipelineId() { return mPipelineId; }
   wr::WebRenderAPI* GetWebRenderAPI() { return mApi; }
   WebRenderCompositableHolder* CompositableHolder() { return mCompositableHolder; }
   CompositorVsyncScheduler* CompositorScheduler() { return mCompositorScheduler.get(); }
 
   mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
                                               const TextureInfo& aInfo) override;
   mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
 
   mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override;
   mozilla::ipc::IPCResult RecvShutdown() override;
-  mozilla::ipc::IPCResult RecvAddImage(const gfx::IntSize& aSize,
+  mozilla::ipc::IPCResult RecvAddImage(const wr::ImageKey& aImageKey,
+                                       const gfx::IntSize& aSize,
                                        const uint32_t& aStride,
                                        const gfx::SurfaceFormat& aFormat,
-                                       const ByteBuffer& aBuffer,
-                                       wr::ImageKey* aOutImageKey) override;
+                                       const ByteBuffer& aBuffer) override;
+  mozilla::ipc::IPCResult RecvAddRawFont(const wr::FontKey& aFontKey,
+                                         const ByteBuffer& aBuffer,
+                                         const uint32_t& aFontIndex) override;
   mozilla::ipc::IPCResult RecvUpdateImage(const wr::ImageKey& aImageKey,
                                           const gfx::IntSize& aSize,
                                           const gfx::SurfaceFormat& aFormat,
                                           const ByteBuffer& aBuffer) override;
   mozilla::ipc::IPCResult RecvDeleteImage(const wr::ImageKey& a1) override;
   mozilla::ipc::IPCResult RecvDPBegin(const gfx::IntSize& aSize) override;
-  mozilla::ipc::IPCResult RecvDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+  mozilla::ipc::IPCResult RecvDPEnd(const gfx::IntSize& aSize,
+                                    InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                     InfallibleTArray<OpDestroy>&& aToDestroy,
                                     const uint64_t& aFwdTransactionId,
-                                    const uint64_t& aTransactionId) override;
-  mozilla::ipc::IPCResult RecvDPSyncEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                                    const uint64_t& aTransactionId,
+                                    const ByteBuffer& dl,
+                                    const WrBuiltDisplayListDescriptor& dlDesc,
+                                    const ByteBuffer& aux,
+                                    const WrAuxiliaryListsDescriptor& auxDesc) override;
+  mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize,
+                                        InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                         InfallibleTArray<OpDestroy>&& aToDestroy,
                                         const uint64_t& aFwdTransactionId,
-                                        const uint64_t& aTransactionId) override;
+                                        const uint64_t& aTransactionId,
+                                        const ByteBuffer& dl,
+                                        const WrBuiltDisplayListDescriptor& dlDesc,
+                                        const ByteBuffer& aux,
+                                        const WrAuxiliaryListsDescriptor& auxDesc) override;
   mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddExternalImageId(const uint64_t& aImageId,
                                                  const CompositableHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvAddExternalImageIdForCompositable(const uint64_t& aImageId,
                                                                 const CompositableHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvRemoveExternalImageId(const uint64_t& aImageId) override;
   mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
 
   mozilla::ipc::IPCResult RecvClearCachedResources() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void SetWebRenderProfilerEnabled(bool aEnabled);
 
   void Destroy();
 
-  const uint64_t& GetPendingTransactionId() { return mPendingTransactionId; }
-  void SetPendingTransactionId(uint64_t aId) { mPendingTransactionId = aId; }
-
   // CompositorVsyncSchedulerOwner
   bool IsPendingComposite() override { return false; }
   void FinishPendingComposite() override { }
   void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
 
   // CompositableParentManager
   bool IsSameProcess() const override;
   base::ProcessId GetChildProcessId() override;
   void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
   void SendPendingAsyncMessages() override;
   void SetAboutToSendAsyncMessages() override;
 
-  void DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd);
+  void HoldPendingTransactionId(uint32_t aWrEpoch, uint64_t aTransactionId);
+  uint64_t LastPendingTransactionId();
+  uint64_t FlushPendingTransactionIds();
+  uint64_t FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch);
 
   TextureFactoryIdentifier GetTextureFactoryIdentifier();
 
   void AppendImageCompositeNotification(const ImageCompositeNotificationInfo& aNotification)
   {
     MOZ_ASSERT(mWidget);
     mImageCompositeNotifications.AppendElement(aNotification);
   }
 
   void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
   {
     MOZ_ASSERT(mWidget);
     aNotifications->AppendElements(Move(mImageCompositeNotifications));
   }
 
+  uint32_t GetIdNameSpace()
+  {
+    return mIdNameSpace;
+  }
+
 private:
   virtual ~WebRenderBridgeParent();
 
   void DeleteOldImages();
-  void ProcessWebrenderCommands(InfallibleTArray<WebRenderCommand>& commands, const wr::Epoch& aEpoch);
+  void ProcessWebrenderCommands(const gfx::IntSize &aSize, InfallibleTArray<WebRenderParentCommand>& commands, const wr::Epoch& aEpoch,
+                                    const ByteBuffer& dl,
+                                    const WrBuiltDisplayListDescriptor& dlDesc,
+                                    const ByteBuffer& aux,
+                                    const WrAuxiliaryListsDescriptor& auxDesc);
   void ScheduleComposition();
   void ClearResources();
   uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
   bool ShouldParentObserveEpoch();
-  void HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+  void HandleDPEnd(const gfx::IntSize& aSize,
+                   InfallibleTArray<WebRenderParentCommand>&& aCommands,
                    InfallibleTArray<OpDestroy>&& aToDestroy,
                    const uint64_t& aFwdTransactionId,
-                   const uint64_t& aTransactionId);
+                   const uint64_t& aTransactionId,
+                   const ByteBuffer& dl,
+                   const WrBuiltDisplayListDescriptor& dlDesc,
+                   const ByteBuffer& aux,
+                   const WrAuxiliaryListsDescriptor& auxDesc);
 
 private:
+  struct PendingTransactionId {
+    PendingTransactionId(wr::Epoch aEpoch, uint64_t aId)
+      : mEpoch(aEpoch)
+      , mId(aId)
+    {}
+    wr::Epoch mEpoch;
+    uint64_t mId;
+  };
+
   CompositorBridgeParentBase* MOZ_NON_OWNING_REF mCompositorBridge;
   wr::PipelineId mPipelineId;
   RefPtr<widget::CompositorWidget> mWidget;
-  Maybe<wr::DisplayListBuilder> mBuilder;
   RefPtr<wr::WebRenderAPI> mApi;
   RefPtr<WebRenderCompositableHolder> mCompositableHolder;
   RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
   std::vector<wr::ImageKey> mKeysToDelete;
   nsDataHashtable<nsUint64HashKey, RefPtr<CompositableHost>> mExternalImageIds;
   nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
 
   // These fields keep track of the latest layer observer epoch values in the child and the
   // parent. mChildLayerObserverEpoch is the latest epoch value received from the child.
   // mParentLayerObserverEpoch is the latest epoch value that we have told TabParent about
   // (via ObserveLayerUpdate).
   uint64_t mChildLayerObserverEpoch;
   uint64_t mParentLayerObserverEpoch;
 
-  uint64_t mPendingTransactionId;
+  std::queue<PendingTransactionId> mPendingTransactionIds;
+  uint32_t mWrEpoch;
+  uint32_t mIdNameSpace;
 
   bool mDestroyed;
+
+  static uint32_t sIdNameSpace;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_WebRenderBridgeParent_h
--- a/gfx/layers/wr/WebRenderCanvasLayer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasLayer.cpp
@@ -102,17 +102,21 @@ WebRenderCanvasLayer::RenderLayer()
       OpDPPushStackingContext(wr::ToWrRect(relBounds),
                               wr::ToWrRect(overflow),
                               mask,
                               1.0f,
                               GetAnimations(),
                               transform,
                               mixBlendMode,
                               FrameMetrics::NULL_SCROLL_ID));
-  WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, mExternalImageId));
+  WrImageKey key;
+  key.mNamespace = WrBridge()->GetNamespace();
+  key.mHandle = WrBridge()->GetNextResourceId();
+  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId, key));
+  WrBridge()->AddWebRenderCommand(OpDPPushImage(wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, key));
   WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
 }
 
 void
 WebRenderCanvasLayer::AttachCompositable()
 {
   mCanvasClient->Connect();
 }
--- a/gfx/layers/wr/WebRenderDisplayItemLayer.cpp
+++ b/gfx/layers/wr/WebRenderDisplayItemLayer.cpp
@@ -16,22 +16,24 @@ namespace mozilla {
 namespace layers {
 
 void
 WebRenderDisplayItemLayer::RenderLayer()
 {
   if (mItem) {
     // We might have recycled this layer. Throw away the old commands.
     mCommands.Clear();
-    mItem->CreateWebRenderCommands(mCommands, this);
+    mParentCommands.Clear();
+    mItem->CreateWebRenderCommands(mCommands, mParentCommands, this);
   }
   // else we have an empty transaction and just use the
   // old commands.
 
   WrBridge()->AddWebRenderCommands(mCommands);
+  WrBridge()->AddWebRenderParentCommands(mParentCommands);
 }
 
 uint64_t
 WebRenderDisplayItemLayer::SendImageContainer(ImageContainer* aContainer)
 {
   if (mImageContainer != aContainer) {
     AutoLockImage autoLock(aContainer);
     Image* image = autoLock.GetImage();
--- a/gfx/layers/wr/WebRenderDisplayItemLayer.h
+++ b/gfx/layers/wr/WebRenderDisplayItemLayer.h
@@ -34,18 +34,19 @@ protected:
   }
 
 public:
   Layer* GetLayer() override { return this; }
   void RenderLayer() override;
 
 private:
   nsTArray<WebRenderCommand> mCommands;
+  nsTArray<WebRenderParentCommand> mParentCommands;
   RefPtr<ImageClient> mImageClient;
   RefPtr<ImageContainer> mImageContainer;
   uint64_t mExternalImageId;
 
 };
 
 } // namespace layers
 } // namespace mozilla
 
-#endif // GFX_WEBRENDERDisplayItemLayer_H
\ No newline at end of file
+#endif // GFX_WEBRENDERDisplayItemLayer_H
--- a/gfx/layers/wr/WebRenderImageLayer.cpp
+++ b/gfx/layers/wr/WebRenderImageLayer.cpp
@@ -169,16 +169,20 @@ WebRenderImageLayer::RenderLayer()
     OpDPPushStackingContext(wr::ToWrRect(relBounds),
                             wr::ToWrRect(overflow),
                             mask,
                             1.0f,
                             GetAnimations(),
                             transform,
                             mixBlendMode,
                             FrameMetrics::NULL_SCROLL_ID));
-  WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, mExternalImageId));
+  WrImageKey key;
+  key.mNamespace = WrBridge()->GetNamespace();
+  key.mHandle = WrBridge()->GetNextResourceId();
+  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId, key));
+  WrBridge()->AddWebRenderCommand(OpDPPushImage(wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, key));
   WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
 
   //mContainer->SetImageFactory(originalIF);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -124,18 +124,20 @@ WebRenderLayer::buildMaskLayer() {
       //XXX: let's assert that the mask transform is the same as the layer transform
       //transform.PostTranslate(-aDeviceOffset.x, -aDeviceOffset.y);
       {
           RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
           DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::MapType::READ);
           gfx::IntSize size = surface->GetSize();
           MOZ_RELEASE_ASSERT(surface->GetFormat() == SurfaceFormat::A8, "bad format");
           wr::ByteBuffer buf(size.height * map.GetStride(), map.GetData());
-          wr::ImageKey maskKey;
-          WrBridge()->SendAddImage(size, map.GetStride(), SurfaceFormat::A8, buf, &maskKey);
+          WrImageKey maskKey;
+          maskKey.mNamespace = WrBridge()->GetNamespace();
+          maskKey.mHandle = WrBridge()->GetNextResourceId();
+          WrBridge()->SendAddImage(maskKey, size, map.GetStride(), SurfaceFormat::A8, buf);
 
           imageMask.image = maskKey;
           imageMask.rect = wr::ToWrRect(Rect(0, 0, size.width, size.height));
           imageMask.repeat = false;
           WrManager()->AddImageKeyForDiscard(maskKey);
           mask = Some(imageMask);
       }
     }
@@ -212,23 +214,26 @@ void
 WebRenderLayerManager::Initialize(PCompositorBridgeChild* aCBChild,
                                   wr::PipelineId aLayersId,
                                   TextureFactoryIdentifier* aTextureFactoryIdentifier)
 {
   MOZ_ASSERT(mWrChild == nullptr);
   MOZ_ASSERT(aTextureFactoryIdentifier);
 
   TextureFactoryIdentifier textureFactoryIdentifier;
+  uint32_t id_namespace;
   PWebRenderBridgeChild* bridge = aCBChild->SendPWebRenderBridgeConstructor(aLayersId,
-                                                                            &textureFactoryIdentifier);
+                                                                            &textureFactoryIdentifier,
+                                                                            &id_namespace);
   MOZ_ASSERT(bridge);
   mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
   LayoutDeviceIntSize size = mWidget->GetClientSize();
   WrBridge()->SendCreate(size.ToUnknownSize());
   WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
+  WrBridge()->SetNamespace(id_namespace);
   *aTextureFactoryIdentifier = textureFactoryIdentifier;
 }
 
 void
 WebRenderLayerManager::Destroy()
 {
   if (IsDestroyed()) {
     return;
@@ -311,17 +316,17 @@ WebRenderLayerManager::EndTransaction(Dr
     return;
   }
 
   WebRenderLayer::ToWebRenderLayer(mRoot)->RenderLayer();
 
   bool sync = mTarget != nullptr;
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
 
-  WrBridge()->DPEnd(sync, mLatestTransactionId);
+  WrBridge()->DPEnd(size.ToUnknownSize(), sync, mLatestTransactionId);
 
   MakeSnapshotIfRequired(size);
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 }
 
--- a/gfx/layers/wr/WebRenderMessageUtils.h
+++ b/gfx/layers/wr/WebRenderMessageUtils.h
@@ -323,16 +323,55 @@ struct ParamTraits<WrImageMask>
   {
     return ReadParam(aMsg, aIter, &aResult->image)
         && ReadParam(aMsg, aIter, &aResult->rect)
         && ReadParam(aMsg, aIter, &aResult->repeat);
   }
 };
 
 template<>
+struct ParamTraits<WrBuiltDisplayListDescriptor>
+{
+  static void
+  Write(Message* aMsg, const WrBuiltDisplayListDescriptor& aParam)
+  {
+    WriteParam(aMsg, aParam.display_list_items_size);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrBuiltDisplayListDescriptor* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->display_list_items_size);
+  }
+};
+
+template<>
+struct ParamTraits<WrAuxiliaryListsDescriptor>
+{
+  static void
+  Write(Message* aMsg, const WrAuxiliaryListsDescriptor& aParam)
+  {
+    WriteParam(aMsg, aParam.gradient_stops_size);
+    WriteParam(aMsg, aParam.complex_clip_regions_size);
+    WriteParam(aMsg, aParam.filters_size);
+    WriteParam(aMsg, aParam.glyph_instances_size);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrAuxiliaryListsDescriptor* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->gradient_stops_size)
+        && ReadParam(aMsg, aIter, &aResult->complex_clip_regions_size)
+        && ReadParam(aMsg, aIter, &aResult->filters_size)
+        && ReadParam(aMsg, aIter, &aResult->glyph_instances_size);
+  }
+};
+
+
+template<>
 struct ParamTraits<WrImageRendering>
   : public ContiguousEnumSerializer<
         WrImageRendering,
         WrImageRendering::Auto,
         WrImageRendering::Sentinel>
 {
 };
 
--- a/gfx/layers/wr/WebRenderPaintedLayer.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayer.cpp
@@ -228,15 +228,18 @@ WebRenderPaintedLayer::RenderLayer()
       OpDPPushStackingContext(wr::ToWrRect(relBounds),
                               wr::ToWrRect(overflow),
                               mask,
                               1.0f,
                               GetAnimations(),
                               transform,
                               mixBlendMode,
                               FrameMetrics::NULL_SCROLL_ID));
-  WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), wr::ImageRendering::Auto, mExternalImageId));
-
+  WrImageKey key;
+  key.mNamespace = WrBridge()->GetNamespace();
+  key.mHandle = WrBridge()->GetNextResourceId();
+  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId, key));
+  WrBridge()->AddWebRenderCommand(OpDPPushImage(wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), wr::ImageRendering::Auto, key));
   WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderTextLayer.cpp
+++ b/gfx/layers/wr/WebRenderTextLayer.cpp
@@ -35,15 +35,15 @@ WebRenderTextLayer::RenderLayer()
     if (gfxPrefs::LayersDump()) {
         printf_stderr("TextLayer %p using rect=%s, clip=%s\n",
                       this->GetLayer(),
                       Stringify(rect).c_str(),
                       Stringify(clip).c_str());
     }
 
     nsTArray<WebRenderCommand> commands;
-    mGlyphHelper.BuildWebRenderCommands(commands, mGlyphs, mFont,
+    mGlyphHelper.BuildWebRenderCommands(WrBridge(), commands, mGlyphs, mFont,
                                         GetOffsetToParent(), rect, clip);
     WrBridge()->AddWebRenderCommands(commands);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -458,16 +458,17 @@ private:
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.border-layers",         LayersAllowBorderLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.text-layers",           LayersAllowTextLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.bullet-layers",         LayersAllowBulletLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.caret-layers",          LayersAllowCaretLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.outline-layers",        LayersAllowOutlineLayers, bool, false);
   DECL_GFX_PREF(Skip, "layers.allow-d3d9-fallback",            LayersAllowD3D9Fallback, bool, false);
   DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled",     LayersAMDSwitchableGfxEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
   DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
   DECL_GFX_PREF(Live, "layers.child-process-shutdown",         ChildProcessShutdown, bool, true);
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -22,16 +22,17 @@
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/Swizzle.h"
 #include "mozilla/layers/WebRenderMessages.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/Vector.h"
 #include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIClipboardHelper.h"
 #include "nsIFile.h"
 #include "nsIGfxInfo.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsRegion.h"
 #include "nsServiceManagerUtils.h"
@@ -1453,31 +1454,38 @@ WriteFontFileData(const uint8_t* aData, 
 
   helper->mFontData = fontData;
   helper->mFontDataLength = aLength;
   helper->mIndex = aIndex;
   helper->mGlyphSize = aGlyphSize;
 }
 
 void
-WebRenderGlyphHelper::BuildWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+WebRenderGlyphHelper::BuildWebRenderCommands(WebRenderBridgeChild* aBridge,
+                                             nsTArray<WebRenderCommand>& aCommands,
                                              const nsTArray<GlyphArray>& aGlyphs,
                                              ScaledFont* aFont,
                                              const Point& aOffset,
                                              const Rect& aBounds,
                                              const Rect& aClip)
 {
   MOZ_ASSERT(aFont);
   MOZ_ASSERT(!aGlyphs.IsEmpty());
   MOZ_ASSERT((aFont->GetType() == gfx::FontType::DWRITE) ||
               (aFont->GetType() == gfx::FontType::MAC));
 
   aFont->GetFontFileData(&WriteFontFileData, this);
   wr::ByteBuffer fontBuffer(mFontDataLength, mFontData);
 
+  WrFontKey key;
+  key.mNamespace = aBridge->GetNamespace();
+  key.mHandle = aBridge->GetNextResourceId();
+
+  aBridge->SendAddRawFont(key, fontBuffer, mIndex);
+
   nsTArray<WrGlyphArray> wr_glyphs;
   wr_glyphs.SetLength(aGlyphs.Length());
 
   for (size_t i = 0; i < aGlyphs.Length(); i++) {
     GlyphArray glyph_array = aGlyphs[i];
     nsTArray<gfx::Glyph>& glyphs = glyph_array.glyphs();
 
     nsTArray<WrGlyphInstance>& wr_glyph_instances = wr_glyphs[i].glyphs;
@@ -1490,16 +1498,14 @@ WebRenderGlyphHelper::BuildWebRenderComm
       wr_glyph_instances[j].y = glyphs[j].mPosition.y - aOffset.y;
     }
   }
 
   aCommands.AppendElement(OpDPPushText(
                             wr::ToWrRect(aBounds),
                             wr::ToWrRect(aClip),
                             wr_glyphs,
-                            mIndex,
                             mGlyphSize,
-                            fontBuffer,
-                            mFontDataLength));
+                            key));
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -12,25 +12,27 @@
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "nsColor.h"
 #include "nsPrintfCString.h"
 #include "nsRegionFwd.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/CheckedInt.h"
+#include "mozilla/webrender/webrender_ffi.h"
 
 class gfxASurface;
 class gfxDrawable;
 class nsIInputStream;
 class nsIGfxInfo;
 class nsIPresShell;
 
 namespace mozilla {
 namespace layers {
+class WebRenderBridgeChild;
 class GlyphArray;
 struct PlanarYCbCrData;
 class WebRenderCommand;
 } // namespace layers
 namespace image {
 class ImageRegion;
 } // namespace image
 } // namespace mozilla
@@ -320,17 +322,18 @@ public:
 
   ~WebRenderGlyphHelper()
   {
     if (mFontData) {
       free(mFontData);
     }
   }
 
-  void BuildWebRenderCommands(nsTArray<layers::WebRenderCommand>& aCommands,
+  void BuildWebRenderCommands(layers::WebRenderBridgeChild* aChild,
+                              nsTArray<layers::WebRenderCommand>& aCommands,
                               const nsTArray<layers::GlyphArray>& aGlyphs,
                               ScaledFont* aFont,
                               const Point& aOffset,
                               const Rect& aBounds,
                               const Rect& aClip);
 
 public:
   uint8_t* mFontData;
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -1626,17 +1626,22 @@ impl Device {
             ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
         };
 
         let row_length = match stride {
             Some(value) => value / bpp,
             None => width,
         };
 
-        assert!(data.len() as u32 == bpp * row_length * height);
+        // Take the stride into account for all rows, except the last one.
+        let len = bpp * row_length * (height - 1)
+                + width * bpp;
+
+        assert!(data.len() as u32 >= len);
+        let data = &data[0..len as usize];
 
         if let Some(..) = stride {
             gl::pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);
         }
 
         self.bind_texture(DEFAULT_TEXTURE, texture_id);
         self.update_image_for_2d_texture(texture_id.target,
                                          x0 as gl::GLint,
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -4,36 +4,38 @@
 
 use app_units::Au;
 use fnv::FnvHasher;
 use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection};
 use internal_types::{LowLevelFilterOp};
 use internal_types::{RendererFrame};
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
 use clip_scroll_node::ClipScrollNode;
+use clip_scroll_tree::{ClipScrollTree, ScrollStates};
+use profiler::TextureCacheProfileCounters;
 use resource_cache::ResourceCache;
 use scene::{Scene, SceneProperties};
-use clip_scroll_tree::{ClipScrollTree, ScrollStates};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
 use webrender_traits::{AuxiliaryLists, ClipRegion, ColorF, DisplayItem, Epoch, FilterOp};
-use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform};
+use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform, TileOffset};
 use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerState};
 use webrender_traits::{ScrollLocation, ScrollPolicy, ServoScrollRootId, SpecificDisplayItem};
-use webrender_traits::{StackingContext, WorldPoint};
+use webrender_traits::{StackingContext, WorldPoint, ImageDisplayItem, DeviceUintSize};
 
 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
 pub struct FrameId(pub u32);
 
 static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
 
 struct FlattenContext<'a> {
     scene: &'a Scene,
     builder: &'a mut FrameBuilder,
+    resource_cache: &'a mut ResourceCache,
 }
 
 // TODO: doc
 pub struct Frame {
     pub clip_scroll_tree: ClipScrollTree,
     pub pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
     pub pipeline_auxiliary_lists: AuxiliaryListsMap,
     id: FrameId,
@@ -221,17 +223,17 @@ impl Frame {
     pub fn tick_scrolling_bounce_animations(&mut self) {
         self.clip_scroll_tree.tick_scrolling_bounce_animations();
     }
 
     pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
         self.clip_scroll_tree.discard_frame_state_for_pipeline(pipeline_id);
     }
 
-    pub fn create(&mut self, scene: &Scene) {
+    pub fn create(&mut self, scene: &Scene, resource_cache: &mut ResourceCache) {
         let root_pipeline_id = match scene.root_pipeline_id {
             Some(root_pipeline_id) => root_pipeline_id,
             None => return,
         };
 
         let root_pipeline = match scene.pipeline_map.get(&root_pipeline_id) {
             Some(root_pipeline) => root_pipeline,
             None => return,
@@ -271,16 +273,17 @@ impl Frame {
         let mut frame_builder = FrameBuilder::new(root_pipeline.viewport_size,
                                                   background_color,
                                                   self.frame_builder_config);
 
         {
             let mut context = FlattenContext {
                 scene: scene,
                 builder: &mut frame_builder,
+                resource_cache: resource_cache
             };
 
             let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
             let reference_frame_id = self.clip_scroll_tree.root_reference_frame_id();
             let topmost_scroll_layer_id = self.clip_scroll_tree.topmost_scroll_layer_id();
             debug_assert!(reference_frame_id != topmost_scroll_layer_id);
 
             let viewport_rect = LayerRect::new(LayerPoint::zero(), root_pipeline.viewport_size);
@@ -542,23 +545,32 @@ impl Frame {
                          level: i32) {
         while let Some(item) = traversal.next() {
             match item.item {
                 SpecificDisplayItem::WebGL(ref info) => {
                     context.builder.add_webgl_rectangle(item.rect,
                                                         &item.clip, info.context_id);
                 }
                 SpecificDisplayItem::Image(ref info) => {
-                    context.builder.add_image(item.rect,
-                                              &item.clip,
-                                              &info.stretch_size,
-                                              &info.tile_spacing,
-                                              None,
-                                              info.image_key,
-                                              info.image_rendering);
+                    let image = context.resource_cache.get_image_properties(info.image_key);
+                    if let Some(tile_size) = image.tiling {
+                        // The image resource is tiled. We have to generate an image primitive
+                        // for each tile.
+                        let image_size = DeviceUintSize::new(image.descriptor.width, image.descriptor.height);
+                        self.decompose_tiled_image(context, &item, info, image_size, tile_size as u32);
+                    } else {
+                        context.builder.add_image(item.rect,
+                                                  &item.clip,
+                                                  &info.stretch_size,
+                                                  &info.tile_spacing,
+                                                  None,
+                                                  info.image_key,
+                                                  info.image_rendering,
+                                                  None);
+                    }
                 }
                 SpecificDisplayItem::YuvImage(ref info) => {
                     context.builder.add_yuv_image(item.rect,
                                                   &item.clip,
                                                   info.y_image_key,
                                                   info.u_image_key,
                                                   info.v_image_key,
                                                   info.color_space);
@@ -641,39 +653,230 @@ impl Frame {
                                         layer_relative_transform);
                 }
                 SpecificDisplayItem::PopStackingContext |
                 SpecificDisplayItem::PopScrollLayer => return,
             }
         }
     }
 
+    fn decompose_tiled_image(&mut self,
+                             context: &mut FlattenContext,
+                             item: &DisplayItem,
+                             info: &ImageDisplayItem,
+                             image_size: DeviceUintSize,
+                             tile_size: u32) {
+        // The image resource is tiled. We have to generate an image primitive
+        // for each tile.
+        // We need to do this because the image is broken up into smaller tiles in the texture
+        // cache and the image shader is not able to work with this type of sparse representation.
+
+        // The tiling logic works as follows:
+        //
+        //  ###################-+  -+
+        //  #    |    |    |//# |   | image size
+        //  #    |    |    |//# |   |
+        //  #----+----+----+--#-+   |  -+ 
+        //  #    |    |    |//# |   |   | regular tile size
+        //  #    |    |    |//# |   |   |
+        //  #----+----+----+--#-+   |  -+-+
+        //  #////|////|////|//# |   |     | "leftover" height
+        //  ################### |  -+  ---+
+        //  #----+----+----+----+
+        //
+        // In the ascii diagram above, a large image is plit into tiles of almost regular size.
+        // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
+        // the regular tiles and are handled separately in the code see leftover_width/height.
+        // each generated image primitive corresponds to a tile in the texture cache, with the
+        // assumption that the smaller tiles with leftover sizes are sized to fit their own
+        // irregular size in the texture cache.
+
+        // TODO(nical) supporting tiled repeated images isn't implemented yet.
+        // One way to implement this is to have another level of decomposition on top of this one,
+        // and generate a set of image primitive per repetition just like we have a primitive
+        // per tile here.
+        //
+        // For the case where we don't tile along an axis, we can still perform the repetition in
+        // the shader (for this particular axis), and it is worth special-casing for this to avoid
+        // generating many primitives.
+        // This can happen with very tall and thin images used as a repeating background.
+        // Apparently web authors do that...
+
+        let mut stretch_size = info.stretch_size;
+
+        let mut repeat_x = false;
+        let mut repeat_y = false;
+
+        if stretch_size.width < item.rect.size.width {
+            if image_size.width < tile_size {
+                // we don't actually tile in this dimmension so repeating can be done in the shader.
+                repeat_x = true;
+            } else {
+                println!("Unimplemented! repeating a tiled image (x axis)");
+                stretch_size.width = item.rect.size.width;
+            }
+        }
+
+        if stretch_size.height < item.rect.size.height {
+                // we don't actually tile in this dimmension so repeating can be done in the shader.
+            if image_size.height < tile_size {
+                repeat_y = true;
+            } else {
+                println!("Unimplemented! repeating a tiled image (y axis)");
+                stretch_size.height = item.rect.size.height;
+            }
+        }
+
+        let tile_size_f32 = tile_size as f32;
+
+        // Note: this rounds down so it excludes the partially filled tiles on the right and
+        // bottom edges (we handle them separately below).
+        let num_tiles_x = (image_size.width / tile_size) as u16;
+        let num_tiles_y = (image_size.height / tile_size) as u16;
+
+        // Ratio between (image space) tile size and image size.
+        let img_dw = tile_size_f32 / (image_size.width as f32);
+        let img_dh = tile_size_f32 / (image_size.height as f32);
+
+        // Strected size of the tile in layout space.
+        let stretched_tile_size = LayerSize::new(
+            img_dw * stretch_size.width,
+            img_dh * stretch_size.height
+        );
+
+        // The size in pixels of the tiles on the right and bottom edges, smaller
+        // than the regular tile size if the image is not a multiple of the tile size.
+        // Zero means the image size is a multiple of the tile size.
+        let leftover = DeviceUintSize::new(image_size.width % tile_size, image_size.height % tile_size);
+
+        for ty in 0..num_tiles_y {
+            for tx in 0..num_tiles_x {
+                self.add_tile_primitive(context, item, info,
+                                        TileOffset::new(tx, ty),
+                                        stretched_tile_size,
+                                        1.0, 1.0,
+                                        repeat_x, repeat_y);
+            }
+            if leftover.width != 0 {
+                // Tiles on the right edge that are smaller than the tile size.
+                self.add_tile_primitive(context, item, info,
+                                        TileOffset::new(num_tiles_x, ty),
+                                        stretched_tile_size,
+                                        (leftover.width as f32) / tile_size_f32,
+                                        1.0,
+                                        repeat_x, repeat_y);
+            }
+        }
+
+        if leftover.height != 0 {
+            for tx in 0..num_tiles_x {
+                // Tiles on the bottom edge that are smaller than the tile size.
+                self.add_tile_primitive(context, item, info,
+                                        TileOffset::new(tx, num_tiles_y),
+                                        stretched_tile_size,
+                                        1.0,
+                                        (leftover.height as f32) / tile_size_f32,
+                                        repeat_x, repeat_y);
+            }
+
+            if leftover.width != 0 {
+                // Finally, the bottom-right tile with a "leftover" size.
+                self.add_tile_primitive(context, item, info,
+                                        TileOffset::new(num_tiles_x, num_tiles_y),
+                                        stretched_tile_size,
+                                        (leftover.width as f32) / tile_size_f32,
+                                        (leftover.height as f32) / tile_size_f32,
+                                        repeat_x, repeat_y);
+            }
+        }
+    }
+
+    fn add_tile_primitive(&mut self,
+                          context: &mut FlattenContext,
+                          item: &DisplayItem,
+                          info: &ImageDisplayItem,
+                          tile_offset: TileOffset,
+                          stretched_tile_size: LayerSize,
+                          tile_ratio_width: f32,
+                          tile_ratio_height: f32,
+                          repeat_x: bool,
+                          repeat_y: bool) {
+        // If the the image is tiled along a given axis, we can't have the shader compute
+        // the image repetition pattern. In this case we base the primitive's rectangle size
+        // on the stretched tile size which effectively cancels the repetion (and repetition
+        // has to be emulated by generating more primitives).
+        // If the image is not tiling along this axis, we can perform the repetition in the
+        // shader. in this case we use the item's size in the primitive (on that particular
+        // axis).
+        // See the repeat_x/y code below.
+
+        let stretched_size = LayerSize::new(
+            stretched_tile_size.width * tile_ratio_width,
+            stretched_tile_size.height * tile_ratio_height,
+        );
+
+        let mut prim_rect = LayerRect::new(
+            item.rect.origin + LayerPoint::new(
+                tile_offset.x as f32 * stretched_tile_size.width,
+                tile_offset.y as f32 * stretched_tile_size.height,
+            ),
+            stretched_size,
+        );
+
+        if repeat_x {
+            assert_eq!(tile_offset.x, 0);
+            prim_rect.size.width = item.rect.size.width;
+        }
+
+        if repeat_y {
+            assert_eq!(tile_offset.y, 0);
+            prim_rect.size.height = item.rect.size.height;
+        }
+
+        // Fix up the primitive's rect if it overflows the original item rect.
+        if let Some(prim_rect) = prim_rect.intersection(&item.rect) {
+            context.builder.add_image(prim_rect,
+                                      &item.clip,
+                                      &stretched_size,
+                                      &info.tile_spacing,
+                                      None,
+                                      info.image_key,
+                                      info.image_rendering,
+                                      Some(tile_offset));
+        }
+    }
+
     pub fn build(&mut self,
                  resource_cache: &mut ResourceCache,
                  auxiliary_lists_map: &AuxiliaryListsMap,
-                 device_pixel_ratio: f32)
+                 device_pixel_ratio: f32,
+                 texture_cache_profile: &mut TextureCacheProfileCounters)
                  -> RendererFrame {
         self.clip_scroll_tree.update_all_node_transforms();
         let frame = self.build_frame(resource_cache,
                                      auxiliary_lists_map,
-                                     device_pixel_ratio);
+                                     device_pixel_ratio,
+                                     texture_cache_profile);
         resource_cache.expire_old_resources(self.id);
         frame
     }
 
     fn build_frame(&mut self,
                    resource_cache: &mut ResourceCache,
                    auxiliary_lists_map: &AuxiliaryListsMap,
-                   device_pixel_ratio: f32) -> RendererFrame {
+                   device_pixel_ratio: f32,
+                   texture_cache_profile: &mut TextureCacheProfileCounters)
+                   -> RendererFrame {
         let mut frame_builder = self.frame_builder.take();
         let frame = frame_builder.as_mut().map(|builder|
             builder.build(resource_cache,
                           self.id,
                           &self.clip_scroll_tree,
                           auxiliary_lists_map,
-                          device_pixel_ratio)
+                          device_pixel_ratio,
+                          texture_cache_profile)
         );
         self.frame_builder = frame_builder;
 
         let nodes_bouncing_back = self.clip_scroll_tree.collect_nodes_bouncing_back();
         RendererFrame::new(self.pipeline_epoch_map.clone(), nodes_bouncing_back, frame)
     }
 }
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -9,31 +9,31 @@ use gpu_store::GpuStoreAddress;
 use internal_types::{HardwareCompositeOp, SourceTexture};
 use mask_cache::{ClipSource, MaskCacheInfo};
 use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, BoxShadowPrimitiveGpu};
 use prim_store::{GradientPrimitiveCpu, GradientPrimitiveGpu, ImagePrimitiveCpu, ImagePrimitiveGpu};
 use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveGeometry, PrimitiveIndex};
 use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu, RadialGradientPrimitiveGpu};
 use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, TextRunPrimitiveGpu};
 use prim_store::{TexelRect, YuvImagePrimitiveCpu, YuvImagePrimitiveGpu};
-use profiler::FrameProfileCounters;
+use profiler::{FrameProfileCounters, TextureCacheProfileCounters};
 use render_task::{AlphaRenderItem, MaskCacheKey, MaskResult, RenderTask, RenderTaskIndex};
 use render_task::RenderTaskLocation;
 use resource_cache::ResourceCache;
 use clip_scroll_tree::ClipScrollTree;
 use std::{cmp, f32, i32, mem, usize};
 use tiling::{AuxiliaryListsMap, ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
 use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
 use tiling::{RenderTargetContext, RenderTaskCollection, ScrollbarPrimitive, ScrollLayer};
 use tiling::{ScrollLayerIndex, StackingContext, StackingContextIndex};
 use util::{self, pack_as_float, rect_from_points_f, subtract_rect, TransformedRect};
 use util::{RectHelpers, TransformedRectKind};
 use webrender_traits::{as_scroll_parent_rect, BorderDetails, BorderDisplayItem, BorderSide, BorderStyle};
 use webrender_traits::{BoxShadowClipMode, ClipRegion, ColorF, device_length, DeviceIntPoint};
-use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintSize, ExtendMode, FontKey};
+use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintSize, ExtendMode, FontKey, TileOffset};
 use webrender_traits::{FontRenderMode, GlyphOptions, ImageKey, ImageRendering, ItemRange};
 use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
 use webrender_traits::{RepeatMode, ScrollLayerId, ScrollLayerPixel, WebGLContextId, YuvColorSpace};
 
 #[derive(Debug, Clone)]
 struct ImageBorderSegment {
     geom_rect: LayerRect,
     sub_rect: TexelRect,
@@ -412,17 +412,18 @@ impl FrameBuilder {
 
                 for segment in segments {
                     self.add_image(segment.geom_rect,
                                    clip_region,
                                    &segment.stretch_size,
                                    &segment.tile_spacing,
                                    Some(segment.sub_rect),
                                    border.image_key,
-                                   ImageRendering::Auto);
+                                   ImageRendering::Auto,
+                                   None);
                 }
             }
             BorderDetails::Normal(ref border) => {
                 let radius = &border.radius;
                 let left = &border.left;
                 let right = &border.right;
                 let top = &border.top;
                 let bottom = &border.bottom;
@@ -710,18 +711,23 @@ impl FrameBuilder {
                                      color,
                                      PrimitiveFlags::None);
             return;
         }
 
         // The local space box shadow rect. It is the element rect
         // translated by the box shadow offset and inflated by the
         // box shadow spread.
+        let inflate_amount = match clip_mode {
+            BoxShadowClipMode::Outset | BoxShadowClipMode::None => spread_radius,
+            BoxShadowClipMode::Inset => -spread_radius,
+        };
+
         let bs_rect = box_bounds.translate(box_offset)
-                                .inflate(spread_radius, spread_radius);
+                                .inflate(inflate_amount, inflate_amount);
 
         // Get the outer rectangle, based on the blur radius.
         let outside_edge_size = 2.0 * blur_radius;
         let inside_edge_size = outside_edge_size.max(border_radius);
         let edge_size = outside_edge_size + inside_edge_size;
         let outer_rect = bs_rect.inflate(outside_edge_size, outside_edge_size);
 
         // Box shadows are often used for things like text underline and other
@@ -828,20 +834,22 @@ impl FrameBuilder {
 
     pub fn add_image(&mut self,
                      rect: LayerRect,
                      clip_region: &ClipRegion,
                      stretch_size: &LayerSize,
                      tile_spacing: &LayerSize,
                      sub_rect: Option<TexelRect>,
                      image_key: ImageKey,
-                     image_rendering: ImageRendering) {
+                     image_rendering: ImageRendering,
+                     tile: Option<TileOffset>) {
         let prim_cpu = ImagePrimitiveCpu {
             kind: ImagePrimitiveKind::Image(image_key,
                                             image_rendering,
+                                            tile,
                                             *tile_spacing),
             color_texture_id: SourceTexture::Invalid,
             resource_address: GpuStoreAddress(0),
             sub_rect: sub_rect,
         };
 
         let prim_gpu = ImagePrimitiveGpu {
             stretch_size: *stretch_size,
@@ -1079,17 +1087,19 @@ impl FrameBuilder {
         (current_task, next_task_index.0)
     }
 
     pub fn build(&mut self,
                  resource_cache: &mut ResourceCache,
                  frame_id: FrameId,
                  clip_scroll_tree: &ClipScrollTree,
                  auxiliary_lists_map: &AuxiliaryListsMap,
-                 device_pixel_ratio: f32) -> Frame {
+                 device_pixel_ratio: f32,
+                 texture_cache_profile: &mut TextureCacheProfileCounters)
+                 -> Frame {
         profile_scope!("build");
 
         let mut profile_counters = FrameProfileCounters::new();
         profile_counters.total_primitives.set(self.prim_store.prim_count());
 
         resource_cache.begin_frame(frame_id);
 
         let screen_rect = DeviceIntRect::new(
@@ -1116,17 +1126,17 @@ impl FrameBuilder {
                                                       device_pixel_ratio);
 
         let (main_render_task, static_render_task_count) = self.build_render_task();
         let mut render_tasks = RenderTaskCollection::new(static_render_task_count);
 
         let mut required_pass_count = 0;
         main_render_task.max_depth(0, &mut required_pass_count);
 
-        resource_cache.block_until_all_resources_added();
+        resource_cache.block_until_all_resources_added(texture_cache_profile);
 
         for scroll_layer in self.scroll_layer_store.iter() {
             if let Some(ref clip_info) = scroll_layer.clip_cache_info {
                 self.prim_store.resolve_clip_cache(clip_info, resource_cache);
             }
         }
 
         let deferred_resolves = self.prim_store.resolve_primitives(resource_cache,
@@ -1356,17 +1366,17 @@ impl<'a> LayerRectCalculationAndCullingP
         clip_info.update(&scroll_layer.clip_source,
                          &packed_layer.transform,
                          &mut self.frame_builder.prim_store.gpu_data32,
                          self.device_pixel_ratio,
                          auxiliary_lists);
 
         if let Some(mask) = scroll_layer.clip_source.image_mask() {
             // We don't add the image mask for resolution, because layer masks are resolved later.
-            self.resource_cache.request_image(mask.image, ImageRendering::Auto);
+            self.resource_cache.request_image(mask.image, ImageRendering::Auto, None);
         }
     }
 
     fn handle_push_stacking_context(&mut self, stacking_context_index: StackingContextIndex) {
         self.stacking_context_stack.push(stacking_context_index);
 
         // Reset bounding rect to zero. We will calculate it as we collect primitives
         // from various scroll layers. In handle_pop_stacking_context , we use this to
--- a/gfx/webrender/src/freelist.rs
+++ b/gfx/webrender/src/freelist.rs
@@ -10,41 +10,63 @@ pub struct FreeListItemId(u32);
 impl FreeListItemId {
     #[inline]
     pub fn new(value: u32) -> FreeListItemId {
         FreeListItemId(value)
     }
 
     #[inline]
     pub fn value(&self) -> u32 {
-        let FreeListItemId(value) = *self;
-        value
+        self.0
     }
 }
 
 pub trait FreeListItem {
+    fn take(&mut self) -> Self;
     fn next_free_id(&self) -> Option<FreeListItemId>;
     fn set_next_free_id(&mut self, id: Option<FreeListItemId>);
 }
 
+struct FreeListIter<'a, T: 'a> {
+    items: &'a [T],
+    cur_index: Option<FreeListItemId>,
+}
+
+impl<'a, T: FreeListItem> Iterator for FreeListIter<'a, T> {
+    type Item = FreeListItemId;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.cur_index.map(|free_id| {
+            self.cur_index = self.items[free_id.0 as usize].next_free_id();
+            free_id
+        })
+    }
+}
+
 pub struct FreeList<T> {
     items: Vec<T>,
     first_free_index: Option<FreeListItemId>,
     alloc_count: usize,
 }
 
 impl<T: FreeListItem> FreeList<T> {
     pub fn new() -> FreeList<T> {
         FreeList {
             items: Vec::new(),
             first_free_index: None,
             alloc_count: 0,
         }
     }
 
+    fn free_iter(&self) -> FreeListIter<T> {
+        FreeListIter {
+            items: &self.items,
+            cur_index: self.first_free_index,
+        }
+    }
+
     pub fn insert(&mut self, item: T) -> FreeListItemId {
         self.alloc_count += 1;
         match self.first_free_index {
             Some(free_index) => {
                 let FreeListItemId(index) = free_index;
                 let free_item = &mut self.items[index as usize];
                 self.first_free_index = free_item.next_free_id();
                 *free_item = item;
@@ -53,69 +75,49 @@ impl<T: FreeListItem> FreeList<T> {
             None => {
                 let item_id = FreeListItemId(self.items.len() as u32);
                 self.items.push(item);
                 item_id
             }
         }
     }
 
-    #[allow(dead_code)]
-    fn assert_not_in_free_list(&self, id: FreeListItemId) {
-        let FreeListItemId(id) = id;
-        let mut next_free_id = self.first_free_index;
-
-        while let Some(free_id) = next_free_id {
-            let FreeListItemId(index) = free_id;
-            assert!(index != id);
-            let free_item = &self.items[index as usize];
-            next_free_id = free_item.next_free_id();
-        }
-    }
-
     pub fn get(&self, id: FreeListItemId) -> &T {
-        //self.assert_not_in_free_list(id);
-
-        let FreeListItemId(index) = id;
-        &self.items[index as usize]
+        debug_assert_eq!(self.free_iter().find(|&fid| fid==id), None);
+        &self.items[id.0 as usize]
     }
 
     pub fn get_mut(&mut self, id: FreeListItemId) -> &mut T {
-        //self.assert_not_in_free_list(id);
-
-        let FreeListItemId(index) = id;
-        &mut self.items[index as usize]
+        debug_assert_eq!(self.free_iter().find(|&fid| fid==id), None);
+        &mut self.items[id.0 as usize]
     }
 
     #[allow(dead_code)]
     pub fn len(&self) -> usize {
         self.alloc_count
     }
 
-    // TODO(gw): Actually free items from the texture cache!!
-    #[allow(dead_code)]
-    pub fn free(&mut self, id: FreeListItemId) {
+    pub fn free(&mut self, id: FreeListItemId) -> T {
         self.alloc_count -= 1;
         let FreeListItemId(index) = id;
         let item = &mut self.items[index as usize];
+        let data = item.take();
         item.set_next_free_id(self.first_free_index);
         self.first_free_index = Some(id);
+        data
     }
 
     pub fn for_each_item<F>(&mut self, f: F) where F: Fn(&mut T) {
-        let mut free_ids = HashSet::new();
-
-        let mut next_free_id = self.first_free_index;
-        while let Some(free_id) = next_free_id {
-            free_ids.insert(free_id);
-            let FreeListItemId(index) = free_id;
-            let free_item = &self.items[index as usize];
-            next_free_id = free_item.next_free_id();
-        }
+        //TODO: this could be done much faster. Instead of gathering the free
+        // indices into a set, we could re-order the free list to be ascending.
+        // That is an one-time operation with at most O(nf^2), where
+        //    nf = number of elements in the free list
+        // Then this code would just walk both `items` and the ascending free
+        // list, essentially skipping the free indices for free.
+        let free_ids: HashSet<_> = self.free_iter().collect();
 
         for (index, mut item) in self.items.iter_mut().enumerate() {
-            let id = FreeListItemId(index as u32);
-            if !free_ids.contains(&id) {
+            if !free_ids.contains(&FreeListItemId(index as u32)) {
                 f(&mut item);
             }
         }
     }
 }
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -382,16 +382,17 @@ pub enum TextureUpdateOp {
     },
     Update {
         page_pos_x: u32,    // the texture page position which we want to upload
         page_pos_y: u32,
         width: u32,
         height: u32,
         data: Arc<Vec<u8>>,
         stride: Option<u32>,
+        offset: u32,
     },
     UpdateForExternalBuffer {
         rect: DeviceUintRect,
         id: ExternalImageId,
         stride: Option<u32>,
     },
     Grow {
         width: u32,
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -15,17 +15,17 @@ use std::usize;
 use util::TransformedRect;
 use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering, YuvColorSpace};
 use webrender_traits::{ClipRegion, ComplexClipRegion, ItemRange, GlyphKey};
 use webrender_traits::{FontKey, FontRenderMode, WebGLContextId};
 use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize};
 use webrender_traits::{DeviceRect, DevicePoint, DeviceSize};
 use webrender_traits::{LayerRect, LayerSize, LayerPoint};
 use webrender_traits::{LayerToWorldTransform, GlyphInstance, GlyphOptions};
-use webrender_traits::{ExtendMode, GradientStop};
+use webrender_traits::{ExtendMode, GradientStop, TileOffset};
 
 pub const CLIP_DATA_GPU_SIZE: usize = 5;
 pub const MASK_DATA_GPU_SIZE: usize = 1;
 
 /// Stores two coordinates in texel space. The coordinates
 /// are stored in texel coordinates because the texture atlas
 /// may grow. Storing them as texel coords and normalizing
 /// the UVs in the vertex shader means nothing needs to be
@@ -131,17 +131,17 @@ pub struct PrimitiveMetadata {
 #[derive(Debug, Clone)]
 #[repr(C)]
 pub struct RectanglePrimitive {
     pub color: ColorF,
 }
 
 #[derive(Debug)]
 pub enum ImagePrimitiveKind {
-    Image(ImageKey, ImageRendering, LayerSize),
+    Image(ImageKey, ImageRendering, Option<TileOffset>, LayerSize),
     WebGL(WebGLContextId),
 }
 
 #[derive(Debug)]
 pub struct ImagePrimitiveCpu {
     pub kind: ImagePrimitiveKind,
     pub color_texture_id: SourceTexture,
     pub resource_address: GpuStoreAddress,
@@ -833,17 +833,17 @@ impl PrimitiveStore {
 
         PrimitiveIndex(prim_index)
     }
 
     fn resolve_clip_cache_internal(gpu_data32: &mut VertexDataStore<GpuBlock32>,
                                    clip_info: &MaskCacheInfo,
                                    resource_cache: &ResourceCache) {
         if let Some((ref mask, gpu_address)) = clip_info.image {
-            let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto);
+            let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
             let mask_data = gpu_data32.get_slice_mut(gpu_address, MASK_DATA_GPU_SIZE);
             mask_data[0] = GpuBlock32::from(ImageMaskData {
                 uv_rect: DeviceRect::new(cache_item.uv0,
                                          DeviceSize::new(cache_item.uv1.x - cache_item.uv0.x,
                                                          cache_item.uv1.y - cache_item.uv0.y)),
                 local_rect: mask.rect,
             });
         }
@@ -894,17 +894,17 @@ impl PrimitiveStore {
                     });
 
                     text.color_texture_id = texture_id;
                 }
                 PrimitiveKind::Image => {
                     let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];
 
                     let (texture_id, cache_item) = match image_cpu.kind {
-                        ImagePrimitiveKind::Image(image_key, image_rendering, _) => {
+                        ImagePrimitiveKind::Image(image_key, image_rendering, tile_offset, _) => {
                             // Check if an external image that needs to be resolved
                             // by the render thread.
                             let image_properties = resource_cache.get_image_properties(image_key);
 
                             match image_properties.external_id {
                                 Some(external_id) => {
                                     // This is an external texture - we will add it to
                                     // the deferred resolves list to be patched by
@@ -912,17 +912,17 @@ impl PrimitiveStore {
                                     deferred_resolves.push(DeferredResolve {
                                         resource_address: image_cpu.resource_address,
                                         image_properties: image_properties,
                                     });
 
                                     (SourceTexture::External(external_id), None)
                                 }
                                 None => {
-                                    let cache_item = resource_cache.get_cached_image(image_key, image_rendering);
+                                    let cache_item = resource_cache.get_cached_image(image_key, image_rendering, tile_offset);
                                     (cache_item.texture_id, Some(cache_item))
                                 }
                             }
                         }
                         ImagePrimitiveKind::WebGL(context_id) => {
                             let cache_item = resource_cache.get_webgl_texture(&context_id);
                             (cache_item.texture_id, Some(cache_item))
                         }
@@ -947,31 +947,31 @@ impl PrimitiveStore {
                 }
                 PrimitiveKind::YuvImage => {
                     let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
                     let image_gpu: &mut YuvImagePrimitiveGpu = unsafe {
                         mem::transmute(self.gpu_data64.get_mut(metadata.gpu_prim_index))
                     };
 
                     if image_cpu.y_texture_id == SourceTexture::Invalid {
-                        let y_cache_item = resource_cache.get_cached_image(image_cpu.y_key, ImageRendering::Auto);
+                        let y_cache_item = resource_cache.get_cached_image(image_cpu.y_key, ImageRendering::Auto, None);
                         image_cpu.y_texture_id = y_cache_item.texture_id;
                         image_gpu.y_uv0 = y_cache_item.uv0;
                         image_gpu.y_uv1 = y_cache_item.uv1;
                     }
 
                     if image_cpu.u_texture_id == SourceTexture::Invalid {
-                        let u_cache_item = resource_cache.get_cached_image(image_cpu.u_key, ImageRendering::Auto);
+                        let u_cache_item = resource_cache.get_cached_image(image_cpu.u_key, ImageRendering::Auto, None);
                         image_cpu.u_texture_id = u_cache_item.texture_id;
                         image_gpu.u_uv0 = u_cache_item.uv0;
                         image_gpu.u_uv1 = u_cache_item.uv1;
                     }
 
                     if image_cpu.v_texture_id == SourceTexture::Invalid {
-                        let v_cache_item = resource_cache.get_cached_image(image_cpu.v_key, ImageRendering::Auto);
+                        let v_cache_item = resource_cache.get_cached_image(image_cpu.v_key, ImageRendering::Auto, None);
                         image_cpu.v_texture_id = v_cache_item.texture_id;
                         image_gpu.v_uv0 = v_cache_item.uv0;
                         image_gpu.v_uv1 = v_cache_item.uv1;
                     }
                 }
             }
         }
 
@@ -1039,17 +1039,17 @@ impl PrimitiveStore {
 
         if let Some(ref mut clip_info) = metadata.clip_cache_info {
             clip_info.update(&metadata.clip_source,
                              layer_transform,
                              &mut self.gpu_data32,
                              device_pixel_ratio,
                              auxiliary_lists);
             if let &ClipSource::Region(ClipRegion{ image_mask: Some(ref mask), .. }) = metadata.clip_source.as_ref() {
-                resource_cache.request_image(mask.image, ImageRendering::Auto);
+                resource_cache.request_image(mask.image, ImageRendering::Auto, None);
                 prim_needs_resolve = true;
             }
         }
 
         match metadata.prim_kind {
             PrimitiveKind::Rectangle |
             PrimitiveKind::Border  => {}
             PrimitiveKind::BoxShadow => {
@@ -1164,18 +1164,18 @@ impl PrimitiveStore {
                                               text.render_mode,
                                               text.glyph_options);
             }
             PrimitiveKind::Image => {
                 let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];
 
                 prim_needs_resolve = true;
                 match image_cpu.kind {
-                    ImagePrimitiveKind::Image(image_key, image_rendering, tile_spacing) => {
-                        resource_cache.request_image(image_key, image_rendering);
+                    ImagePrimitiveKind::Image(image_key, image_rendering, tile_offset, tile_spacing) => {
+                        resource_cache.request_image(image_key, image_rendering, tile_offset);
 
                         // TODO(gw): This doesn't actually need to be calculated each frame.
                         // It's cheap enough that it's not worth introducing a cache for images
                         // right now, but if we introduce a cache for images for some other
                         // reason then we might as well cache this with it.
                         let image_properties = resource_cache.get_image_properties(image_key);
                         metadata.is_opaque = image_properties.descriptor.is_opaque &&
                                              tile_spacing.width == 0.0 &&
@@ -1183,19 +1183,19 @@ impl PrimitiveStore {
                     }
                     ImagePrimitiveKind::WebGL(..) => {}
                 }
             }
             PrimitiveKind::YuvImage => {
                 let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
                 prim_needs_resolve = true;
 
-                resource_cache.request_image(image_cpu.y_key, ImageRendering::Auto);
-                resource_cache.request_image(image_cpu.u_key, ImageRendering::Auto);
-                resource_cache.request_image(image_cpu.v_key, ImageRendering::Auto);
+                resource_cache.request_image(image_cpu.y_key, ImageRendering::Auto, None);
+                resource_cache.request_image(image_cpu.u_key, ImageRendering::Auto, None);
+                resource_cache.request_image(image_cpu.v_key, ImageRendering::Auto, None);
 
                 // TODO(nical): Currently assuming no tile_spacing for yuv images.
                 metadata.is_opaque = true;
             }
             PrimitiveKind::AlignedGradient => {
                 let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0];
                 if gradient.cache_dirty {
                     let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range);
--- a/gfx/webrender/src/profiler.rs
+++ b/gfx/webrender/src/profiler.rs
@@ -252,28 +252,47 @@ impl FrameProfileCounters {
             visible_primitives: IntProfileCounter::new("Visible Primitives"),
             passes: IntProfileCounter::new("Passes"),
             targets: IntProfileCounter::new("Render Targets"),
         }
     }
 }
 
 #[derive(Clone)]
+pub struct TextureCacheProfileCounters {
+    pub pages_a8: ResourceProfileCounter,
+    pub pages_rgb8: ResourceProfileCounter,
+    pub pages_rgba8: ResourceProfileCounter,
+}
+
+impl TextureCacheProfileCounters {
+    pub fn new() -> TextureCacheProfileCounters {
+        TextureCacheProfileCounters {
+            pages_a8: ResourceProfileCounter::new("Texture A8 cached pages"),
+            pages_rgb8: ResourceProfileCounter::new("Texture RGB8 cached pages"),
+            pages_rgba8: ResourceProfileCounter::new("Texture RGBA8 cached pages"),
+        }
+    }
+}
+
+#[derive(Clone)]
 pub struct BackendProfileCounters {
     pub font_templates: ResourceProfileCounter,
     pub image_templates: ResourceProfileCounter,
     pub total_time: TimeProfileCounter,
+    pub texture_cache: TextureCacheProfileCounters,
 }
 
 impl BackendProfileCounters {
     pub fn new() -> BackendProfileCounters {
         BackendProfileCounters {
             font_templates: ResourceProfileCounter::new("Font Templates"),
             image_templates: ResourceProfileCounter::new("Image Templates"),
             total_time: TimeProfileCounter::new("Backend CPU Time", false),
+            texture_cache: TextureCacheProfileCounters::new(),
         }
     }
 
     pub fn reset(&mut self) {
         self.total_time.reset();
     }
 }
 
@@ -637,16 +656,22 @@ impl Profiler {
         ], debug_renderer, true);
 
         self.draw_counters(&[
             &backend_profile.font_templates,
             &backend_profile.image_templates,
         ], debug_renderer, true);
 
         self.draw_counters(&[
+            &backend_profile.texture_cache.pages_a8,
+            &backend_profile.texture_cache.pages_rgb8,
+            &backend_profile.texture_cache.pages_rgba8,
+        ], debug_renderer, true);
+
+        self.draw_counters(&[
             &renderer_profile.draw_calls,
             &renderer_profile.vertices,
         ], debug_renderer, true);
 
         self.draw_counters(&[
             &backend_profile.total_time,
             &renderer_timers.cpu_time,
             &renderer_timers.gpu_time,
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use byteorder::{LittleEndian, ReadBytesExt};
 use frame::Frame;
 use frame_builder::FrameBuilderConfig;
 use internal_types::{FontTemplate, GLContextHandleWrapper, GLContextWrapper};
 use internal_types::{SourceTexture, ResultMsg, RendererFrame};
-use profiler::BackendProfileCounters;
+use profiler::{BackendProfileCounters, TextureCacheProfileCounters};
 use record::ApiRecordingReceiver;
 use resource_cache::ResourceCache;
 use scene::Scene;
 use std::collections::HashMap;
 use std::io::{Cursor, Read};
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::Sender;
 use texture_cache::TextureCache;
@@ -91,18 +91,17 @@ impl RenderBackend {
             current_bound_webgl_context_id: None,
             recorder: recorder,
             main_thread_dispatcher: main_thread_dispatcher,
             next_webgl_id: 0,
             vr_compositor_handler: vr_compositor_handler
         }
     }
 
-    pub fn run(&mut self) {
-        let mut profile_counters = BackendProfileCounters::new();
+    pub fn run(&mut self, mut profile_counters: BackendProfileCounters) {
         let mut frame_counter: u32 = 0;
 
         loop {
             let msg = self.api_rx.recv();
             profile_scope!("handle_msg");
             match msg {
                 Ok(msg) => {
                     if let Some(ref mut r) = self.recorder {
@@ -121,21 +120,21 @@ impl RenderBackend {
                         ApiMsg::GetGlyphDimensions(glyph_keys, tx) => {
                             let mut glyph_dimensions = Vec::with_capacity(glyph_keys.len());
                             for glyph_key in &glyph_keys {
                                 let glyph_dim = self.resource_cache.get_glyph_dimensions(glyph_key);
                                 glyph_dimensions.push(glyph_dim);
                             };
                             tx.send(glyph_dimensions).unwrap();
                         }
-                        ApiMsg::AddImage(id, descriptor, data) => {
+                        ApiMsg::AddImage(id, descriptor, data, tiling) => {
                             if let ImageData::Raw(ref bytes) = data {
                                 profile_counters.image_templates.inc(bytes.len());
                             }
-                            self.resource_cache.add_image_template(id, descriptor, data);
+                            self.resource_cache.add_image_template(id, descriptor, data, tiling);
                         }
                         ApiMsg::UpdateImage(id, descriptor, bytes) => {
                             self.resource_cache.update_image_template(id, descriptor, bytes);
                         }
                         ApiMsg::DeleteImage(id) => {
                             self.resource_cache.delete_image_template(id);
                         }
                         ApiMsg::CloneApi(sender) => {
@@ -208,57 +207,66 @@ impl RenderBackend {
                             if self.scene.display_lists.get(&pipeline_id).is_none() {
                                 continue;
                             }
 
                             self.build_scene();
                         }
                         ApiMsg::Scroll(delta, cursor, move_phase) => {
                             profile_scope!("Scroll");
-                            let frame = profile_counters.total_time.profile(|| {
-                                if self.frame.scroll(delta, cursor, move_phase) {
-                                    Some(self.render())
-                                } else {
-                                    None
-                                }
-                            });
+                            let frame = {
+                                let counters = &mut profile_counters.texture_cache;
+                                profile_counters.total_time.profile(|| {
+                                    if self.frame.scroll(delta, cursor, move_phase) {
+                                        Some(self.render(counters))
+                                    } else {
+                                        None
+                                    }
+                                })
+                            };
 
                             match frame {
                                 Some(frame) => {
                                     self.publish_frame(frame, &mut profile_counters);
                                     self.notify_compositor_of_new_scroll_frame(true)
                                 }
                                 None => self.notify_compositor_of_new_scroll_frame(false),
                             }
                         }
                         ApiMsg::ScrollLayersWithScrollId(origin, pipeline_id, scroll_root_id) => {
                             profile_scope!("ScrollLayersWithScrollId");
-                            let frame = profile_counters.total_time.profile(|| {
-                                if self.frame.scroll_nodes(origin, pipeline_id, scroll_root_id) {
-                                    Some(self.render())
-                                } else {
-                                    None
-                                }
-                            });
+                            let frame = {
+                                let counters = &mut profile_counters.texture_cache;
+                                profile_counters.total_time.profile(|| {
+                                    if self.frame.scroll_nodes(origin, pipeline_id, scroll_root_id) {
+                                        Some(self.render(counters))
+                                    } else {
+                                        None
+                                    }
+                                })
+                            };
 
                             match frame {
                                 Some(frame) => {
                                     self.publish_frame(frame, &mut profile_counters);
                                     self.notify_compositor_of_new_scroll_frame(true)
                                 }
                                 None => self.notify_compositor_of_new_scroll_frame(false),
                             }
 
                         }
                         ApiMsg::TickScrollingBounce => {
                             profile_scope!("TickScrollingBounce");
-                            let frame = profile_counters.total_time.profile(|| {
-                                self.frame.tick_scrolling_bounce_animations();
-                                self.render()
-                            });
+                            let frame = {
+                                let counters = &mut profile_counters.texture_cache;
+                                profile_counters.total_time.profile(|| {
+                                    self.frame.tick_scrolling_bounce_animations();
+                                    self.render(counters)
+                                })
+                            };
 
                             self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
                         }
                         ApiMsg::TranslatePointToLayerSpace(..) => {
                             panic!("unused api - remove from webrender_traits");
                         }
                         ApiMsg::GetScrollLayerState(tx) => {
                             profile_scope!("GetScrollLayerState");
@@ -341,19 +349,22 @@ impl RenderBackend {
                             //           are completed, optimize the internals of
                             //           animated properties to not require a full
                             //           rebuild of the frame!
                             if let Some(property_bindings) = property_bindings {
                                 self.scene.properties.set_properties(property_bindings);
                                 self.build_scene();
                             }
 
-                            let frame = profile_counters.total_time.profile(|| {
-                                self.render()
-                            });
+                            let frame = {
+                                let counters = &mut profile_counters.texture_cache;
+                                profile_counters.total_time.profile(|| {
+                                    self.render(counters)
+                                })
+                            };
                             if self.scene.root_pipeline_id.is_some() {
                                 self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
                                 frame_counter += 1;
                             }
                         }
                         ApiMsg::ExternalEvent(evt) => {
                             let notifier = self.notifier.lock();
                             notifier.unwrap()
@@ -402,23 +413,26 @@ impl RenderBackend {
         // context at the start of a render frame should
         // incur minimal cost.
         for (_, webgl_context) in &self.webgl_contexts {
             webgl_context.make_current();
             webgl_context.apply_command(WebGLCommand::Flush);
             webgl_context.unbind();
         }
 
-        self.frame.create(&self.scene);
+        self.frame.create(&self.scene, &mut self.resource_cache);
     }
 
-    fn render(&mut self) -> RendererFrame {
+    fn render(&mut self,
+              texture_cache_profile: &mut TextureCacheProfileCounters)
+              -> RendererFrame {
         let frame = self.frame.build(&mut self.resource_cache,
                                      &self.scene.pipeline_auxiliary_lists,
-                                     self.device_pixel_ratio);
+                                     self.device_pixel_ratio,
+                                     texture_cache_profile);
 
         frame
     }
 
     fn publish_frame(&mut self,
                      frame: RendererFrame,
                      profile_counters: &mut BackendProfileCounters) {
         let pending_update = self.resource_cache.pending_updates();
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -62,23 +62,22 @@ pub struct AlphaRenderTask {
     screen_origin: DeviceIntPoint,
     pub opaque_items: Vec<AlphaRenderItem>,
     pub alpha_items: Vec<AlphaRenderItem>,
 }
 
 #[derive(Debug, Copy, Clone)]
 #[repr(C)]
 pub enum MaskSegment {
-    // This must match the SEGMENT_ values
-    // in clip_shared.glsl!
+    // This must match the SEGMENT_ values in clip_shared.glsl!
     All = 0,
-    Corner_TopLeft,
-    Corner_TopRight,
-    Corner_BottomLeft,
-    Corner_BottomRight,
+    TopLeftCorner,
+    TopRightCorner,
+    BottomLeftCorner,
+    BottomRightCorner,
 }
 
 #[derive(Debug, Copy, Clone)]
 #[repr(C)]
 pub enum MaskGeometryKind {
     Default,        // Draw the entire rect
     CornersOnly,    // Draw the corners (simple axis aligned mask)
     // TODO(gw): Add more types here (e.g. 4 rectangles outside the inner rect)
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -679,51 +679,42 @@ impl Renderer {
                                      &mut device,
                                      options.precache_shaders)
         };
 
         let device_max_size = device.max_texture_size();
         let max_texture_size = cmp::min(device_max_size, options.max_texture_size.unwrap_or(device_max_size));
 
         let mut texture_cache = TextureCache::new(max_texture_size);
+        let mut backend_profile_counters = BackendProfileCounters::new();
 
         let white_pixels: Vec<u8> = vec![
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
         ];
         let mask_pixels: Vec<u8> = vec![
             0xff, 0xff,
             0xff, 0xff,
         ];
         // TODO: Ensure that the white texture can never get evicted when the cache supports LRU eviction!
         let white_image_id = texture_cache.new_item_id();
         texture_cache.insert(white_image_id,
-                             ImageDescriptor {
-                                width: 2,
-                                height: 2,
-                                stride: None,
-                                format: ImageFormat::RGBA8,
-                                is_opaque: false,
-                             },
+                             ImageDescriptor::new(2, 2, ImageFormat::RGBA8, false),
                              TextureFilter::Linear,
-                             ImageData::Raw(Arc::new(white_pixels)));
+                             ImageData::Raw(Arc::new(white_pixels)),
+                             &mut backend_profile_counters.texture_cache);
 
         let dummy_mask_image_id = texture_cache.new_item_id();
         texture_cache.insert(dummy_mask_image_id,
-                             ImageDescriptor {
-                                width: 2,
-                                height: 2,
-                                stride: None,
-                                format: ImageFormat::A8,
-                                is_opaque: false,
-                             },
+                             ImageDescriptor::new(2, 2, ImageFormat::A8, false),
                              TextureFilter::Linear,
-                             ImageData::Raw(Arc::new(mask_pixels)));
+                             ImageData::Raw(Arc::new(mask_pixels)),
+                             &mut backend_profile_counters.texture_cache);
 
         let dummy_cache_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
         device.init_texture(dummy_cache_texture_id,
                             1,
                             1,
                             ImageFormat::RGBA8,
                             TextureFilter::Linear,
                             RenderTargetMode::LayerRenderTarget(1),
@@ -810,17 +801,17 @@ impl Renderer {
                                                  workers,
                                                  backend_notifier,
                                                  context_handle,
                                                  config,
                                                  recorder,
                                                  backend_main_thread_dispatcher,
                                                  blob_image_renderer,
                                                  backend_vr_compositor);
-            backend.run();
+            backend.run(backend_profile_counters);
         })};
 
         let renderer = Renderer {
             result_rx: result_rx,
             device: device,
             current_frame: None,
             pending_texture_updates: Vec::new(),
             pending_shader_updates: Vec::new(),
@@ -1118,23 +1109,23 @@ impl Renderer {
                         let texture_id = self.cache_texture_id_map[update.id.0];
                         self.device.resize_texture(texture_id,
                                                    width,
                                                    height,
                                                    format,
                                                    filter,
                                                    mode);
                     }
-                    TextureUpdateOp::Update { page_pos_x, page_pos_y, width, height, data, stride } => {
+                    TextureUpdateOp::Update { page_pos_x, page_pos_y, width, height, data, stride, offset } => {
                         let texture_id = self.cache_texture_id_map[update.id.0];
                         self.device.update_texture(texture_id,
                                                    page_pos_x,
                                                    page_pos_y,
                                                    width, height, stride,
-                                                   data.as_slice());
+                                                   &data[offset as usize..]);
                     }
                     TextureUpdateOp::UpdateForExternalBuffer { rect, id, stride } => {
                         let handler = self.external_image_handler
                                           .as_mut()
                                           .expect("Found external image, but no handler set!");
                         let device = &mut self.device;
                         let cached_id = self.cache_texture_id_map[update.id.0];
 
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -3,32 +3,33 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use device::TextureFilter;
 use fnv::FnvHasher;
 use frame::FrameId;
 use internal_types::{ExternalImageUpdateList, FontTemplate, SourceTexture, TextureUpdateList};
 use platform::font::{FontContext, RasterizedGlyph};
+use profiler::TextureCacheProfileCounters;
 use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
 use std::collections::hash_map::Entry::{self, Occupied, Vacant};
 use std::fmt::Debug;
 use std::hash::BuildHasherDefault;
 use std::hash::Hash;
 use std::mem;
 use std::sync::{Arc, Barrier, Mutex};
 use std::sync::mpsc::{channel, Receiver, Sender};
 use std::thread;
 use texture_cache::{TextureCache, TextureCacheItemId};
 use thread_profiler::register_thread_with_profiler;
 use webrender_traits::{Epoch, FontKey, GlyphKey, ImageKey, ImageFormat, ImageRendering};
 use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
 use webrender_traits::{DevicePoint, DeviceIntSize, ImageDescriptor, ColorF};
-use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance};
+use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance, TileOffset, TileSize};
 use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError};
 use threadpool::ThreadPool;
 use euclid::Point2D;
 
 thread_local!(pub static FONT_CONTEXT: RefCell<FontContext> = RefCell::new(FontContext::new()));
 
 type GlyphCache = ResourceClassCache<RenderedGlyphKey, Option<TextureCacheItemId>>;
 
@@ -87,29 +88,31 @@ impl RenderedGlyphKey {
             glyph_options: glyph_options,
         }
     }
 }
 
 pub struct ImageProperties {
     pub descriptor: ImageDescriptor,
     pub external_id: Option<ExternalImageId>,
+    pub tiling: Option<TileSize>,
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
 enum State {
     Idle,
     AddResources,
     QueryResources,
 }
 
 struct ImageResource {
     data: ImageData,
     descriptor: ImageDescriptor,
     epoch: Epoch,
+    tiling: Option<TileSize>,
 }
 
 struct CachedImageInfo {
     texture_cache_id: TextureCacheItemId,
     epoch: Epoch,
 }
 
 pub struct ResourceClassCache<K,V> {
@@ -172,16 +175,17 @@ impl<K,V> ResourceClassCache<K,V> where 
         }
     }
 }
 
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 struct ImageRequest {
     key: ImageKey,
     rendering: ImageRendering,
+    tile: Option<TileOffset>,
 }
 
 struct GlyphRasterJob {
     key: RenderedGlyphKey,
     result: Option<RasterizedGlyph>,
 }
 
 struct WebGLTexture {
@@ -254,27 +258,29 @@ impl ResourceCache {
             .send(GlyphCacheMsg::AddFont(font_key, template.clone()))
             .unwrap();
         self.font_templates.insert(font_key, template);
     }
 
     pub fn add_image_template(&mut self,
                               image_key: ImageKey,
                               descriptor: ImageDescriptor,
-                              data: ImageData) {
+                              data: ImageData,
+                              mut tiling: Option<TileSize>) {
         if descriptor.width > self.max_texture_size() || descriptor.height > self.max_texture_size() {
-            // TODO: we need to support handle this case gracefully, cf. issue #620.
-            println!("Warning: texture size ({} {}) larger than the maximum size",
-                     descriptor.width, descriptor.height);
+            // We aren't going to be able to upload a texture this big, so tile it, even
+            // if tiling was not requested.
+            tiling = Some(512);
         }
 
         let resource = ImageResource {
             descriptor: descriptor,
             data: data,
             epoch: Epoch(0),
+            tiling: tiling,
         };
 
         self.image_templates.insert(image_key, resource);
     }
 
     pub fn update_image_template(&mut self,
                                  image_key: ImageKey,
                                  descriptor: ImageDescriptor,
@@ -296,16 +302,17 @@ impl ResourceCache {
                 Epoch(0)
             }
         };
 
         let resource = ImageResource {
             descriptor: descriptor,
             data: ImageData::new(bytes),
             epoch: next_epoch,
+            tiling: None,
         };
 
         self.image_templates.insert(image_key, resource);
     }
 
     pub fn delete_image_template(&mut self, image_key: ImageKey) {
         let value = self.image_templates.remove(&image_key);
 
@@ -334,21 +341,26 @@ impl ResourceCache {
     pub fn update_webgl_texture(&mut self, id: WebGLContextId, texture_id: SourceTexture, size: DeviceIntSize) {
         let webgl_texture = self.webgl_textures.get_mut(&id).unwrap();
 
         // Update new texture id and size
         webgl_texture.id = texture_id;
         webgl_texture.size = size;
     }
 
-    pub fn request_image(&mut self, key: ImageKey, rendering: ImageRendering) {
+    pub fn request_image(&mut self,
+                         key: ImageKey,
+                         rendering: ImageRendering,
+                         tile: Option<TileOffset>) {
+
         debug_assert!(self.state == State::AddResources);
         let request = ImageRequest {
             key: key,
             rendering: rendering,
+            tile: tile,
         };
 
         let template = self.image_templates.get(&key).unwrap();
         if let ImageData::Blob(ref data) = template.data {
             if let Some(ref mut renderer) = self.blob_image_renderer {
                 let same_epoch = match self.cached_images.resources.get(&request) {
                     Some(entry) => entry.epoch == template.epoch,
                     None => false,
@@ -467,21 +479,23 @@ impl ResourceCache {
                 *entry.insert(dimensions)
             }
         }
     }
 
     #[inline]
     pub fn get_cached_image(&self,
                             image_key: ImageKey,
-                            image_rendering: ImageRendering) -> CacheItem {
+                            image_rendering: ImageRendering,
+                            tile: Option<TileOffset>) -> CacheItem {
         debug_assert!(self.state == State::QueryResources);
         let key = ImageRequest {
             key: image_key,
             rendering: image_rendering,
+            tile: tile,
         };
         let image_info = &self.cached_images.get(&key, self.current_frame_id);
         let item = self.texture_cache.get(image_info.texture_cache_id);
         CacheItem {
             texture_id: SourceTexture::TextureCache(item.texture_id),
             uv0: DevicePoint::new(item.pixel_rect.top_left.x as f32,
                                   item.pixel_rect.top_left.y as f32),
             uv1: DevicePoint::new(item.pixel_rect.bottom_right.x as f32,
@@ -496,16 +510,17 @@ impl ResourceCache {
             ImageData::ExternalHandle(id) => Some(id),
             // raw and externalBuffer are all use resource_cache.
             ImageData::Raw(..) | ImageData::ExternalBuffer(..) | ImageData::Blob(..) => None,
         };
 
         ImageProperties {
             descriptor: image_template.descriptor,
             external_id: external_id,
+            tiling: image_template.tiling,
         }
     }
 
     #[inline]
     pub fn get_webgl_texture(&self, context_id: &WebGLContextId) -> CacheItem {
         let webgl_texture = &self.webgl_textures[context_id];
         CacheItem {
             texture_id: webgl_texture.id,
@@ -524,17 +539,18 @@ impl ResourceCache {
     pub fn begin_frame(&mut self, frame_id: FrameId) {
         debug_assert!(self.state == State::Idle);
         self.state = State::AddResources;
         self.current_frame_id = frame_id;
         let glyph_cache = self.cached_glyphs.take().unwrap();
         self.glyph_cache_tx.send(GlyphCacheMsg::BeginFrame(frame_id, glyph_cache)).ok();
     }
 
-    pub fn block_until_all_resources_added(&mut self) {
+    pub fn block_until_all_resources_added(&mut self,
+                                           texture_cache_profile: &mut TextureCacheProfileCounters) {
         profile_scope!("block_until_all_resources_added");
 
         debug_assert!(self.state == State::AddResources);
         self.state = State::QueryResources;
 
         // Tell the glyph cache thread that all glyphs have been requested
         // and block, waiting for any pending glyphs to be rasterized. In the
         // future, we will expand this to have a timeout. If the glyph rasterizing
@@ -558,19 +574,21 @@ impl ResourceCache {
                                 let image_id = self.texture_cache.new_item_id();
                                 self.texture_cache.insert(image_id,
                                                           ImageDescriptor {
                                                               width: glyph.width,
                                                               height: glyph.height,
                                                               stride: None,
                                                               format: ImageFormat::RGBA8,
                                                               is_opaque: false,
+                                                              offset: 0,
                                                           },
                                                           TextureFilter::Linear,
-                                                          ImageData::Raw(Arc::new(glyph.bytes)));
+                                                          ImageData::Raw(Arc::new(glyph.bytes)),
+                                                          texture_cache_profile);
                                 Some(image_id)
                             } else {
                                 None
                             }
                         });
 
                         cache.insert(job.key, image_id, self.current_frame_id);
                     }
@@ -578,26 +596,28 @@ impl ResourceCache {
                     self.cached_glyphs = Some(cache);
                     break;
                 }
             }
         }
 
         let mut image_requests = mem::replace(&mut self.pending_image_requests, Vec::new());
         for request in image_requests.drain(..) {
-            self.finalize_image_request(request, None);
+            self.finalize_image_request(request, None, texture_cache_profile);
         }
 
         let mut blob_image_requests = mem::replace(&mut self.blob_image_requests, HashSet::new());
         if self.blob_image_renderer.is_some() {
             for request in blob_image_requests.drain() {
                 match self.blob_image_renderer.as_mut().unwrap()
                                                 .resolve_blob_image(request.key) {
                     Ok(image) => {
-                        self.finalize_image_request(request, Some(ImageData::new(image.data)));
+                        self.finalize_image_request(request,
+                                                    Some(ImageData::new(image.data)),
+                                                    texture_cache_profile);
                     }
                     // TODO(nical): I think that we should handle these somewhat gracefully,
                     // at least in the out-of-memory scenario.
                     Err(BlobImageError::Oom) => {
                         // This one should be recoverable-ish.
                         panic!("Failed to render a vector image (OOM)");
                     }
                     Err(BlobImageError::InvalidKey) => {
@@ -610,17 +630,20 @@ impl ResourceCache {
                     Err(BlobImageError::Other(msg)) => {
                         panic!("Vector image error {}", msg);
                     }
                 }
             }
         }
     }
 
-    fn finalize_image_request(&mut self, request: ImageRequest, image_data: Option<ImageData>) {
+    fn finalize_image_request(&mut self,
+                              request: ImageRequest,
+                              image_data: Option<ImageData>,
+                              texture_cache_profile: &mut TextureCacheProfileCounters) {
         let image_template = &self.image_templates[&request.key];
         let image_data = image_data.unwrap_or_else(||{
             image_template.data.clone()
         });
 
         match image_template.data {
             ImageData::ExternalHandle(..) => {
                 // external handle doesn't need to update the texture_cache.
@@ -645,20 +668,60 @@ impl ResourceCache {
                     Vacant(entry) => {
                         let image_id = self.texture_cache.new_item_id();
 
                         let filter = match request.rendering {
                             ImageRendering::Pixelated => TextureFilter::Nearest,
                             ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
                         };
 
-                        self.texture_cache.insert(image_id,
-                                                  image_template.descriptor,
-                                                  filter,
-                                                  image_data);
+                        if let Some(tile) = request.tile {
+                            let tile_size = image_template.tiling.unwrap() as u32;
+                            let image_descriptor = image_template.descriptor.clone();
+                            let stride = image_descriptor.compute_stride();
+                            let bpp = image_descriptor.format.bytes_per_pixel().unwrap();
+
+                            // Storage for the tiles on the right and bottom edges is shrunk to
+                            // fit the image data (See decompose_tiled_image in frame.rs).
+                            let actual_width = if (tile.x as u32) < image_descriptor.width / tile_size {
+                                tile_size
+                            } else {
+                                image_descriptor.width % tile_size
+                            };
+
+                            let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size {
+                                tile_size
+                            } else {
+                                image_descriptor.height % tile_size
+                            };
+
+                            let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride
+                                                                 + tile.x as u32 * tile_size * bpp;
+
+                            let tile_descriptor = ImageDescriptor {
+                                width: actual_width,
+                                height: actual_height,
+                                stride: Some(stride),
+                                offset: offset,
+                                format: image_descriptor.format,
+                                is_opaque: image_descriptor.is_opaque,
+                            };
+
+                            self.texture_cache.insert(image_id,
+                                                      tile_descriptor,
+                                                      filter,
+                                                      image_data,
+                                                      texture_cache_profile);
+                        } else {
+                            self.texture_cache.insert(image_id,
+                                                      image_template.descriptor,
+                                                      filter,
+                                                      image_data,
+                                                      texture_cache_profile);
+                        }
 
                         entry.insert(CachedImageInfo {
                             texture_cache_id: image_id,
                             epoch: image_template.epoch,
                         });
                     }
                 }
             }
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use device::TextureFilter;
 use fnv::FnvHasher;
 use freelist::{FreeList, FreeListItem, FreeListItemId};
 use internal_types::{TextureUpdate, TextureUpdateOp};
 use internal_types::{CacheTextureId, RenderTargetMode, TextureUpdateList, RectUv};
+use profiler::TextureCacheProfileCounters;
 use std::cmp::{self, Ordering};
 use std::collections::HashMap;
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
 use std::mem;
 use std::slice::Iter;
 use time;
 use util;
@@ -89,65 +90,39 @@ impl TexturePage {
             let candidate_area = candidate_rect.size.width * candidate_rect.size.height;
             smallest_index_and_area = Some((candidate_index, candidate_area));
             break
         }
 
         smallest_index_and_area.map(|(index, _)| FreeListIndex(bin, index))
     }
 
+    /// Find a suitable rect in the free list. We choose the smallest such rect
+    /// in terms of area (Best-Area-Fit, BAF).
     fn find_index_of_best_rect(&self, requested_dimensions: &DeviceUintSize)
                                -> Option<FreeListIndex> {
-        match FreeListBin::for_size(requested_dimensions) {
-            FreeListBin::Large => {
-                self.find_index_of_best_rect_in_bin(FreeListBin::Large, requested_dimensions)
-            }
-            FreeListBin::Medium => {
-                match self.find_index_of_best_rect_in_bin(FreeListBin::Medium,
-                                                          requested_dimensions) {
-                    Some(index) => Some(index),
-                    None => {
-                        self.find_index_of_best_rect_in_bin(FreeListBin::Large,
-                                                            requested_dimensions)
-                    }
-                }
-            }
-            FreeListBin::Small => {
-                match self.find_index_of_best_rect_in_bin(FreeListBin::Small,
-                                                          requested_dimensions) {
-                    Some(index) => Some(index),
-                    None => {
-                        match self.find_index_of_best_rect_in_bin(FreeListBin::Medium,
-                                                                  requested_dimensions) {
-                            Some(index) => Some(index),
-                            None => {
-                                self.find_index_of_best_rect_in_bin(FreeListBin::Large,
-                                                                    requested_dimensions)
-                            }
-                        }
-                    }
+        let bin = FreeListBin::for_size(requested_dimensions);
+        for &target_bin in &[FreeListBin::Small, FreeListBin::Medium, FreeListBin::Large] {
+            if bin <= target_bin {
+                if let Some(index) = self.find_index_of_best_rect_in_bin(target_bin,
+                                                                         requested_dimensions) {
+                    return Some(index);
                 }
             }
         }
+        None
+    }
+
+    pub fn can_allocate(&self, requested_dimensions: &DeviceUintSize) -> bool {
+        self.find_index_of_best_rect(requested_dimensions).is_some()
     }
 
     pub fn allocate(&mut self,
                     requested_dimensions: &DeviceUintSize) -> Option<DeviceUintPoint> {
-        // First, try to find a suitable rect in the free list. We choose the smallest such rect
-        // in terms of area (Best-Area-Fit, BAF).
-        let mut index = self.find_index_of_best_rect(requested_dimensions);
-
-        // If one couldn't be found and we're dirty, coalesce rects and try again.
-        if index.is_none() && self.dirty {
-            self.coalesce();
-            index = self.find_index_of_best_rect(requested_dimensions)
-        }
-
-        // If a rect still can't be found, fail.
-        let index = match index {
+        let index = match self.find_index_of_best_rect(requested_dimensions) {
             None => return None,
             Some(index) => index,
         };
 
         // Remove the rect from the free list and decide how to guillotine it. We choose the split
         // that results in the single largest area (Min Area Split Rule, MINAS).
         let chosen_rect = self.free_list.remove(index);
         let candidate_free_rect_to_right =
@@ -194,17 +169,21 @@ impl TexturePage {
         // Bump the allocation counter.
         self.allocations += 1;
 
         // Return the result.
         Some(chosen_rect.origin)
     }
 
     #[inline(never)]
-    fn coalesce(&mut self) {
+    pub fn coalesce(&mut self) -> bool {
+        if !self.dirty {
+            return false
+        }
+
         // Iterate to a fixed point or until a timeout is reached.
         let deadline = time::precise_time_ns() + COALESCING_TIMEOUT;
         let mut free_list = mem::replace(&mut self.free_list, FreeRectList::new()).into_vec();
         let mut changed = false;
 
         // Combine rects that have the same width and are adjacent.
         let mut new_free_list = Vec::new();
         free_list.sort_by(|a, b| {
@@ -213,17 +192,17 @@ impl TexturePage {
                 ordering => ordering,
             }
         });
         for work_index in 0..free_list.len() {
             if work_index % COALESCING_TIMEOUT_CHECKING_INTERVAL == 0 &&
                     time::precise_time_ns() >= deadline {
                 self.free_list = FreeRectList::from_slice(&free_list[..]);
                 self.dirty = true;
-                return
+                return true
             }
 
             if free_list[work_index].size.width == 0 {
                 continue
             }
             for candidate_index in (work_index + 1)..free_list.len() {
                 if free_list[work_index].size.width != free_list[candidate_index].size.width ||
                         free_list[work_index].origin.x != free_list[candidate_index].origin.x {
@@ -250,17 +229,17 @@ impl TexturePage {
                 ordering => ordering,
             }
         });
         for work_index in 0..free_list.len() {
             if work_index % COALESCING_TIMEOUT_CHECKING_INTERVAL == 0 &&
                     time::precise_time_ns() >= deadline {
                 self.free_list = FreeRectList::from_slice(&free_list[..]);
                 self.dirty = true;
-                return
+                return true
             }
 
             if free_list[work_index].size.height == 0 {
                 continue
             }
             for candidate_index in (work_index + 1)..free_list.len() {
                 if free_list[work_index].size.height !=
                         free_list[candidate_index].size.height ||
@@ -275,17 +254,18 @@ impl TexturePage {
                     free_list[candidate_index].size.height = 0
                 }
             }
             new_free_list.push(free_list[work_index])
         }
         free_list = new_free_list;
 
         self.free_list = FreeRectList::from_slice(&free_list[..]);
-        self.dirty = changed
+        self.dirty = changed;
+        changed
     }
 
     pub fn clear(&mut self) {
         self.free_list = FreeRectList::new();
         self.free_list.push(&DeviceUintRect::new(
             DeviceUintPoint::zero(),
             self.texture_size));
         self.allocations = 0;
@@ -386,17 +366,17 @@ impl FreeRectList {
         self.small.extend(self.large.drain(..));
         self.small
     }
 }
 
 #[derive(Debug, Clone, Copy)]
 struct FreeListIndex(FreeListBin, usize);
 
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
 enum FreeListBin {
     Small,
     Medium,
     Large,
 }
 
 impl FreeListBin {
     pub fn for_size(size: &DeviceUintSize) -> FreeListBin {
@@ -423,16 +403,22 @@ pub struct TextureCacheItem {
     pub texture_size: DeviceUintSize,
 
     // The size of the allocated rectangle.
     pub allocated_rect: DeviceUintRect,
 }
 
 // Structure squat the width/height fields to maintain the free list information :)
 impl FreeListItem for TextureCacheItem {
+    fn take(&mut self) -> Self {
+        let data = self.clone();
+        self.texture_id = CacheTextureId(0);
+        data
+    }
+
     fn next_free_id(&self) -> Option<FreeListItemId> {
         if self.allocated_rect.size.width == 0 {
             debug_assert_eq!(self.allocated_rect.size.height, 0);
             None
         } else {
             debug_assert_eq!(self.allocated_rect.size.width, 1);
             Some(FreeListItemId::new(self.allocated_rect.size.height))
         }
@@ -575,36 +561,29 @@ impl TextureCache {
     pub fn pending_updates(&mut self) -> TextureUpdateList {
         mem::replace(&mut self.pending_updates, TextureUpdateList::new())
     }
 
     // TODO(gw): This API is a bit ugly (having to allocate an ID and
     //           then use it). But it has to be that way for now due to
     //           how the raster_jobs code works.
     pub fn new_item_id(&mut self) -> TextureCacheItemId {
-        let new_item = TextureCacheItem {
-            pixel_rect: RectUv {
-                top_left: DeviceIntPoint::zero(),
-                top_right: DeviceIntPoint::zero(),
-                bottom_left: DeviceIntPoint::zero(),
-                bottom_right: DeviceIntPoint::zero(),
-            },
-            allocated_rect: DeviceUintRect::zero(),
-            texture_size: DeviceUintSize::zero(),
-            texture_id: CacheTextureId(0),
-        };
+        let new_item = TextureCacheItem::new(CacheTextureId(0),
+                                             DeviceUintRect::zero(),
+                                             &DeviceUintSize::zero());
         self.items.insert(new_item)
     }
 
     pub fn allocate(&mut self,
                     image_id: TextureCacheItemId,
                     requested_width: u32,
                     requested_height: u32,
                     format: ImageFormat,
-                    filter: TextureFilter)
+                    filter: TextureFilter,
+                    profile: &mut TextureCacheProfileCounters)
                     -> AllocationResult {
         let requested_size = DeviceUintSize::new(requested_width, requested_height);
 
         // TODO(gw): For now, anything that requests nearest filtering
         //           just fails to allocate in a texture page, and gets a standalone
         //           texture. This isn't ideal, as it causes lots of batch breaks,
         //           but is probably rare enough that it can be fixed up later (it's also
         //           fairly trivial to implement, just tedious).
@@ -619,95 +598,113 @@ impl TextureCache {
 
             return AllocationResult {
                 item: self.items.get(image_id).clone(),
                 kind: AllocationKind::Standalone,
             }
         }
 
         let mode = RenderTargetMode::SimpleRenderTarget;
-        let page_list = match format {
-            ImageFormat::A8 => &mut self.arena.pages_a8,
-            ImageFormat::RGBA8 => &mut self.arena.pages_rgba8,
-            ImageFormat::RGB8 => &mut self.arena.pages_rgb8,
+        let (page_list, page_profile) = match format {
+            ImageFormat::A8 => (&mut self.arena.pages_a8, &mut profile.pages_a8),
+            ImageFormat::RGBA8 => (&mut self.arena.pages_rgba8, &mut profile.pages_rgba8),
+            ImageFormat::RGB8 => (&mut self.arena.pages_rgb8, &mut profile.pages_rgb8),
             ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
         };
 
         // TODO(gw): Handle this sensibly (support failing to render items that can't fit?)
         assert!(requested_size.width < self.max_texture_size);
         assert!(requested_size.height < self.max_texture_size);
 
-        // Loop until an allocation succeeds, growing or adding new
-        // texture pages as required.
-        loop {
-            let location = page_list.last_mut().and_then(|last_page| {
-                last_page.allocate(&requested_size)
-            });
-
-            if let Some(location) = location {
-                let page = page_list.last_mut().unwrap();
-
-                let requested_rect = DeviceUintRect::new(location, requested_size);
-                let cache_item = TextureCacheItem::new(page.texture_id,
-                                                       requested_rect,
-                                                       &page.texture_size);
-                *self.items.get_mut(image_id) = cache_item;
-
-                return AllocationResult {
-                    item: self.items.get(image_id).clone(),
-                    kind: AllocationKind::TexturePage,
-                }
+        let mut page_id = None; //using ID here to please the borrow checker
+        for (i, page) in page_list.iter_mut().enumerate() {
+            if page.can_allocate(&requested_size) {
+                page_id = Some(i);
+                break;
             }
-
-            if !page_list.is_empty() && page_list.last().unwrap().can_grow(self.max_texture_size) {
-                let last_page = page_list.last_mut().unwrap();
-                // Grow the texture.
-                let new_width = cmp::min(last_page.texture_size.width * 2, self.max_texture_size);
-                let new_height = cmp::min(last_page.texture_size.height * 2, self.max_texture_size);
+            // try to coalesce it
+            if page.coalesce() && page.can_allocate(&requested_size) {
+                page_id = Some(i);
+                break;
+            }
+            if page.can_grow(self.max_texture_size) {
+                // try to grow it
+                let new_width = cmp::min(page.texture_size.width * 2, self.max_texture_size);
+                let new_height = cmp::min(page.texture_size.height * 2, self.max_texture_size);
                 let texture_size = DeviceUintSize::new(new_width, new_height);
                 self.pending_updates.push(TextureUpdate {
-                    id: last_page.texture_id,
+                    id: page.texture_id,
                     op: texture_grow_op(texture_size, format, mode),
                 });
-                last_page.grow(texture_size);
+
+                let extra_texels = new_width * new_height - page.texture_size.width * page.texture_size.height;
+                let extra_bytes = extra_texels * format.bytes_per_pixel().unwrap_or(0);
+                page_profile.inc(extra_bytes as usize);
+
+                page.grow(texture_size);
 
                 self.items.for_each_item(|item| {
-                    if item.texture_id == last_page.texture_id {
+                    if item.texture_id == page.texture_id {
                         item.texture_size = texture_size;
                     }
                 });
 
-                continue;
+                if page.can_allocate(&requested_size) {
+                    page_id = Some(i);
+                    break;
+                }
             }
+        }
 
-            // We need a new page.
-            let texture_size = initial_texture_size(self.max_texture_size);
-            let free_texture_levels_entry = self.free_texture_levels.entry(format);
-            let mut free_texture_levels = match free_texture_levels_entry {
-                Entry::Vacant(entry) => entry.insert(Vec::new()),
-                Entry::Occupied(entry) => entry.into_mut(),
-            };
-            if free_texture_levels.is_empty() {
-                let texture_id = self.cache_id_list.allocate();
+        let mut page = match page_id {
+            Some(index) => &mut page_list[index],
+            None => {
+                let init_texture_size = initial_texture_size(self.max_texture_size);
+                let texture_size = DeviceUintSize::new(cmp::max(requested_width, init_texture_size.width),
+                                                       cmp::max(requested_height, init_texture_size.height));
+                let extra_bytes = texture_size.width * texture_size.height * format.bytes_per_pixel().unwrap_or(0);
+                page_profile.inc(extra_bytes as usize);
+
+                let free_texture_levels_entry = self.free_texture_levels.entry(format);
+                let mut free_texture_levels = match free_texture_levels_entry {
+                    Entry::Vacant(entry) => entry.insert(Vec::new()),
+                    Entry::Occupied(entry) => entry.into_mut(),
+                };
+                if free_texture_levels.is_empty() {
+                    let texture_id = self.cache_id_list.allocate();
 
-                let update_op = TextureUpdate {
-                    id: texture_id,
-                    op: texture_create_op(texture_size, format, mode),
-                };
-                self.pending_updates.push(update_op);
+                    let update_op = TextureUpdate {
+                        id: texture_id,
+                        op: texture_create_op(texture_size, format, mode),
+                    };
+                    self.pending_updates.push(update_op);
+
+                    free_texture_levels.push(FreeTextureLevel {
+                        texture_id: texture_id,
+                    });
+                }
+                let free_texture_level = free_texture_levels.pop().unwrap();
+                let texture_id = free_texture_level.texture_id;
 
-                free_texture_levels.push(FreeTextureLevel {
-                    texture_id: texture_id,
-                });
-            }
-            let free_texture_level = free_texture_levels.pop().unwrap();
-            let texture_id = free_texture_level.texture_id;
+                let page = TexturePage::new(texture_id, texture_size);
+                page_list.push(page);
+                page_list.last_mut().unwrap()
+            },
+        };
 
-            let page = TexturePage::new(texture_id, texture_size);
-            page_list.push(page);
+        let location = page.allocate(&requested_size)
+                           .expect("All the checks have passed till now, there is no way back.");
+        let cache_item = TextureCacheItem::new(page.texture_id,
+                                               DeviceUintRect::new(location, requested_size),
+                                               &page.texture_size);
+        *self.items.get_mut(image_id) = cache_item.clone();
+
+        AllocationResult {
+            item: cache_item,
+            kind: AllocationKind::TexturePage,
         }
     }
 
     pub fn update(&mut self,
                   image_id: TextureCacheItemId,
                   descriptor: ImageDescriptor,
                   data: ImageData) {
         let existing_item = self.items.get(image_id);
@@ -726,47 +723,50 @@ impl TextureCache {
             ImageData::Raw(bytes) => {
                 TextureUpdateOp::Update {
                     page_pos_x: existing_item.allocated_rect.origin.x,
                     page_pos_y: existing_item.allocated_rect.origin.y,
                     width: descriptor.width,
                     height: descriptor.height,
                     data: bytes,
                     stride: descriptor.stride,
+                    offset: descriptor.offset,
                 }
             }
         };
 
         let update_op = TextureUpdate {
             id: existing_item.texture_id,
             op: op,
         };
 
         self.pending_updates.push(update_op);
     }
 
     pub fn insert(&mut self,
                   image_id: TextureCacheItemId,
                   descriptor: ImageDescriptor,
                   filter: TextureFilter,
-                  data: ImageData) {
+                  data: ImageData,
+                  profile: &mut TextureCacheProfileCounters) {
         if let ImageData::Blob(..) = data {
             panic!("must rasterize the vector image before adding to the cache");
         }
 
         let width = descriptor.width;
         let height = descriptor.height;
         let format = descriptor.format;
         let stride = descriptor.stride;
 
         let result = self.allocate(image_id,
                                    width,
                                    height,
                                    format,
-                                   filter);
+                                   filter,
+                                   profile);
 
         match result.kind {
             AllocationKind::TexturePage => {
                 match data {
                     ImageData::ExternalHandle(..) => {
                         panic!("External handle should not go through texture_cache.");
                     }
                     ImageData::Blob(..) => {
@@ -777,16 +777,17 @@ impl TextureCache {
                             id: result.item.texture_id,
                             op: TextureUpdateOp::Update {
                                 page_pos_x: result.item.allocated_rect.origin.x,
                                 page_pos_y: result.item.allocated_rect.origin.y,
                                 width: result.item.allocated_rect.size.width,
                                 height: result.item.allocated_rect.size.height,
                                 data: bytes,
                                 stride: stride,
+                                offset: descriptor.offset,
                             },
                         };
 
                         self.pending_updates.push(update_op);
                     }
                     ImageData::ExternalBuffer(id) => {
                         let update_op = TextureUpdate {
                             id: result.item.texture_id,
@@ -826,33 +827,29 @@ impl TextureCache {
         }
     }
 
     pub fn get(&self, id: TextureCacheItemId) -> &TextureCacheItem {
         self.items.get(id)
     }
 
     pub fn free(&mut self, id: TextureCacheItemId) {
-        {
-            let item = self.items.get(id);
-            match self.arena.texture_page_for_id(item.texture_id) {
-                Some(texture_page) => texture_page.free(&item.allocated_rect),
-                None => {
-                    // This is a standalone texture allocation. Just push it back onto the free
-                    // list.
-                    self.pending_updates.push(TextureUpdate {
-                        id: item.texture_id,
-                        op: TextureUpdateOp::Free,
-                    });
-                    self.cache_id_list.free(item.texture_id);
-                }
+        let item = self.items.free(id);
+        match self.arena.texture_page_for_id(item.texture_id) {
+            Some(texture_page) => texture_page.free(&item.allocated_rect),
+            None => {
+                // This is a standalone texture allocation. Just push it back onto the free
+                // list.
+                self.pending_updates.push(TextureUpdate {
+                    id: item.texture_id,
+                    op: TextureUpdateOp::Free,
+                });
+                self.cache_id_list.free(item.texture_id);
             }
         }
-
-        self.items.free(id)
     }
 }
 
 fn texture_create_op(texture_size: DeviceUintSize, format: ImageFormat, mode: RenderTargetMode)
                      -> TextureUpdateOp {
     TextureUpdateOp::Create {
         width: texture_size.width,
         height: texture_size.height,
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -803,41 +803,41 @@ impl ClipBatcher {
                             segment: MaskSegment::All as i32,
                             ..instance
                         });
                     }
                     MaskGeometryKind::CornersOnly => {
                         self.rectangles.extend(&[
                             CacheClipInstance {
                                 address: GpuStoreAddress(offset),
-                                segment: MaskSegment::Corner_TopLeft as i32,
+                                segment: MaskSegment::TopLeftCorner as i32,
                                 ..instance
                             },
                             CacheClipInstance {
                                 address: GpuStoreAddress(offset),
-                                segment: MaskSegment::Corner_TopRight as i32,
+                                segment: MaskSegment::TopRightCorner as i32,
                                 ..instance
                             },
                             CacheClipInstance {
                                 address: GpuStoreAddress(offset),
-                                segment: MaskSegment::Corner_BottomLeft as i32,
+                                segment: MaskSegment::BottomLeftCorner as i32,
                                 ..instance
                             },
                             CacheClipInstance {
                                 address: GpuStoreAddress(offset),
-                                segment: MaskSegment::Corner_BottomRight as i32,
+                                segment: MaskSegment::BottomRightCorner as i32,
                                 ..instance
                             },
                         ]);
                     }
                 }
             }
 
             if let Some((ref mask, address)) = info.image {
-                let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto);
+                let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
                 self.images.entry(cache_item.texture_id)
                            .or_insert(Vec::new())
                            .push(CacheClipInstance {
                     address: address,
                     ..instance
                 })
             }
         }
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -1,25 +1,17 @@
 [package]
 name = "webrender_bindings"
 version = "0.1.0"
 authors = ["The Mozilla Project Developers"]
 license = "MPL-2.0"
 
 [dependencies]
-webrender_traits = {path = "../webrender_traits", version = "0.19"}
+webrender_traits = {path = "../webrender_traits", version = "0.20.0"}
 euclid = "0.11"
 app_units = "0.4"
 gleam = "0.2"
-fnv="1.0"
 
 [dependencies.webrender]
 path = "../webrender"
-version = "0.19"
+version = "0.19.0"
 default-features = false
 features = ["codegen"]
-
-[target.'cfg(target_os = "macos")'.dependencies]
-core-foundation = "0.2.2"
-
-[target.'cfg(target_os = "windows")'.dependencies]
-kernel32-sys = "0.2"
-winapi = "0.2.8"
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -155,20 +155,17 @@ static void
 NotifyDidRender(layers::CompositorBridgeParentBase* aBridge,
                 WrRenderedEpochs* aEpochs,
                 TimeStamp aStart,
                 TimeStamp aEnd)
 {
   WrPipelineId pipeline;
   WrEpoch epoch;
   while (wr_rendered_epochs_next(aEpochs, &pipeline, &epoch)) {
-    // TODO - Currently each bridge seems to  only have one pipeline but at some
-    // point we should pass make sure we only notify bridges that have the
-    // corresponding pipeline id.
-    aBridge->NotifyDidComposite(epoch.mHandle, aStart, aEnd);
+    aBridge->NotifyDidCompositeToPipeline(pipeline, epoch, aStart, aEnd);
   }
   wr_rendered_epochs_delete(aEpochs);
 }
 
 void
 RenderThread::UpdateAndRender(wr::WindowId aWindowId)
 {
   MOZ_ASSERT(IsInRenderThread());
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -9,16 +9,29 @@
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 namespace mozilla {
 namespace wr {
 
+WrExternalImage LockExternalImage(void* aObj, WrExternalImageId aId)
+{
+  return WrExternalImage { /*WrExternalImageIdType::TextureHandle, */0.0f, 0.0f, 0.0f, 0.0f, 0 };
+}
+
+void UnlockExternalImage(void* aObj, WrExternalImageId aId)
+{
+}
+
+void ReleaseExternalImage(void* aObj, WrExternalImageId aId)
+{
+}
+
 RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread,
                          RefPtr<gl::GLContext>&& aGL,
                          RefPtr<widget::CompositorWidget>&& aWidget,
                          wr::WindowId aWindowId,
                          WrRenderer* aWrRenderer,
                          layers::CompositorBridgeParentBase* aBridge)
   : mThread(aThread)
   , mGL(aGL)
@@ -36,16 +49,27 @@ RendererOGL::RendererOGL(RefPtr<RenderTh
 }
 
 RendererOGL::~RendererOGL()
 {
   MOZ_COUNT_DTOR(RendererOGL);
   wr_renderer_delete(mWrRenderer);
 }
 
+WrExternalImageHandler
+RendererOGL::GetExternalImageHandler()
+{
+  return WrExternalImageHandler {
+    this,
+    LockExternalImage,
+    UnlockExternalImage,
+    ReleaseExternalImage,
+  };
+}
+
 void
 RendererOGL::Update()
 {
   wr_renderer_update(mWrRenderer);
 }
 
 bool
 RendererOGL::Render()
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -33,17 +33,23 @@ namespace wr {
 
 /// Owns the WebRender renderer and GL context.
 ///
 /// There is one renderer per window, all owned by the render thread.
 /// This class is a similar abstraction to CompositorOGL except that it is used
 /// on the render thread instead of the compositor thread.
 class RendererOGL
 {
+  friend WrExternalImage LockExternalImage(void* aObj, WrExternalImageId aId);
+  friend void UnlockExternalImage(void* aObj, WrExternalImageId aId);
+  friend void ReleaseExternalImage(void* aObj, WrExternalImageId aId);
+
 public:
+  WrExternalImageHandler GetExternalImageHandler();
+
   /// This can be called on the render thread only.
   void Update();
 
   /// This can be called on the render thread only.
   bool Render();
 
   /// This can be called on the render thread only.
   bool RenderToTarget(gfx::DrawTarget& aTarget);
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -46,28 +46,32 @@ public:
     if (!gl || !gl->MakeCurrent()) {
       return;
     }
 
     gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, mMaxTextureSize);
     *mUseANGLE = gl->IsANGLE();
 
     WrRenderer* wrRenderer = nullptr;
-    if (!wr_window_new(aWindowId, gl.get(), this->mEnableProfiler, nullptr, mWrApi, &wrRenderer)) {
+    if (!wr_window_new(aWindowId, gl.get(), this->mEnableProfiler, mWrApi, &wrRenderer)) {
       return;
     }
     MOZ_ASSERT(wrRenderer);
 
     RefPtr<RenderThread> thread = &aRenderThread;
     auto renderer = MakeUnique<RendererOGL>(Move(thread),
                                             Move(gl),
                                             Move(mCompositorWidget),
                                             aWindowId,
                                             wrRenderer,
                                             mBridge);
+    if (wrRenderer && renderer) {
+      WrExternalImageHandler handler = renderer->GetExternalImageHandler();
+      wr_renderer_set_external_image_handler(wrRenderer, &handler);
+    }
 
     aRenderThread.AddRenderer(aWindowId, Move(renderer));
   }
 
 private:
   WrAPI** mWrApi;
   GLint* mMaxTextureSize;
   bool* mUseANGLE;
@@ -130,35 +134,59 @@ WebRenderAPI::Create(bool aEnableProfile
 
   if (!wrApi) {
     return nullptr;
   }
 
   return RefPtr<WebRenderAPI>(new WebRenderAPI(wrApi, id, maxTextureSize, useANGLE)).forget();
 }
 
+WrIdNamespace
+WebRenderAPI::GetNamespace() {
+  return wr_api_get_namespace(mWrApi);
+}
+
 WebRenderAPI::~WebRenderAPI()
 {
   layers::SynchronousTask task("Destroy WebRenderAPI");
   auto event = MakeUnique<RemoveRenderer>(&task);
   RunOnRenderThread(Move(event));
   task.Wait();
 
   wr_api_delete(mWrApi);
 }
 
 void
+WebRenderAPI::GenerateFrame()
+{
+  wr_api_generate_frame(mWrApi);
+}
+
+void
 WebRenderAPI::SetRootDisplayList(gfx::Color aBgColor,
                                  Epoch aEpoch,
                                  LayerSize aViewportSize,
-                                 DisplayListBuilder& aBuilder)
+				 WrPipelineId pipeline_id,
+				 WrBuiltDisplayListDescriptor dl_descriptor,
+				 uint8_t *dl_data,
+				 size_t dl_size,
+				 WrAuxiliaryListsDescriptor aux_descriptor,
+				 uint8_t *aux_data,
+				 size_t aux_size)
 {
-  wr_api_set_root_display_list(mWrApi, aBuilder.mWrState,
-                               aEpoch,
-                               aViewportSize.width, aViewportSize.height);
+    wr_api_set_root_display_list(mWrApi,
+				 aEpoch,
+				 aViewportSize.width, aViewportSize.height,
+                                 pipeline_id,
+                                 dl_descriptor,
+                                 dl_data,
+                                 dl_size,
+                                 aux_descriptor,
+                                 aux_data,
+                                 aux_size);
 }
 
 void
 WebRenderAPI::Readback(gfx::IntSize size,
                        uint8_t *buffer,
                        uint32_t buffer_size)
 {
     class Readback : public RendererEvent
@@ -204,34 +232,50 @@ WebRenderAPI::Readback(gfx::IntSize size
 }
 
 void
 WebRenderAPI::SetRootPipeline(PipelineId aPipeline)
 {
   wr_api_set_root_pipeline(mWrApi, aPipeline);
 }
 
-ImageKey
-WebRenderAPI::AddImageBuffer(const ImageDescriptor& aDescritptor,
-                             Range<uint8_t> aBytes)
+void
+WebRenderAPI::AddImage(ImageKey key, const ImageDescriptor& aDescritptor,
+                       Range<uint8_t> aBytes)
 {
-  return ImageKey(wr_api_add_image(mWrApi,
-                                   &aDescritptor,
-                                   &aBytes[0], aBytes.length()));
+  wr_api_add_image(mWrApi,
+                   key,
+                   &aDescritptor,
+                   &aBytes[0], aBytes.length());
 }
 
-ImageKey
-WebRenderAPI::AddExternalImageHandle(gfx::IntSize aSize,
+void
+WebRenderAPI::AddExternalImageHandle(ImageKey key,
+                                     gfx::IntSize aSize,
                                      gfx::SurfaceFormat aFormat,
                                      uint64_t aHandle)
 {
   auto format = SurfaceFormatToWrImageFormat(aFormat).value();
-  return ImageKey(wr_api_add_external_image_texture(mWrApi,
-                                                    aSize.width, aSize.height, format,
-                                                    aHandle));
+  wr_api_add_external_image_handle(mWrApi,
+                                   key,
+                                   aSize.width, aSize.height, format,
+                                   aHandle);
+}
+
+void
+WebRenderAPI::AddExternalImageBuffer(ImageKey key,
+                                     gfx::IntSize aSize,
+                                     gfx::SurfaceFormat aFormat,
+                                     uint64_t aHandle)
+{
+  auto format = SurfaceFormatToWrImageFormat(aFormat).value();
+  wr_api_add_external_image_buffer(mWrApi,
+                                   key,
+                                   aSize.width, aSize.height, format,
+                                   aHandle);
 }
 
 void
 WebRenderAPI::UpdateImageBuffer(ImageKey aKey,
                                 const ImageDescriptor& aDescritptor,
                                 Range<uint8_t> aBytes)
 {
   wr_api_update_image(mWrApi,
@@ -241,20 +285,20 @@ WebRenderAPI::UpdateImageBuffer(ImageKey
 }
 
 void
 WebRenderAPI::DeleteImage(ImageKey aKey)
 {
   wr_api_delete_image(mWrApi, aKey);
 }
 
-wr::FontKey
-WebRenderAPI::AddRawFont(Range<uint8_t> aBytes)
+void
+WebRenderAPI::AddRawFont(wr::FontKey key, Range<uint8_t> aBytes)
 {
-  return wr::FontKey(wr_api_add_raw_font(mWrApi, &aBytes[0], aBytes.length()));
+  wr_api_add_raw_font(mWrApi, key, &aBytes[0], aBytes.length());
 }
 
 void
 WebRenderAPI::DeleteFont(wr::FontKey aKey)
 {
   printf("XXX - WebRender does not seem to implement deleting a font! Leaking it...\n");
 }
 
@@ -293,38 +337,51 @@ WebRenderAPI::SetProfilerEnabled(bool aE
 
 void
 WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent)
 {
   auto event = reinterpret_cast<uintptr_t>(aEvent.release());
   wr_api_send_external_event(mWrApi, event);
 }
 
-DisplayListBuilder::DisplayListBuilder(const LayerIntSize& aSize, PipelineId aId)
+DisplayListBuilder::DisplayListBuilder(PipelineId aId)
 {
   MOZ_COUNT_CTOR(DisplayListBuilder);
-  mWrState = wr_state_new(aSize.width, aSize.height, aId);
+  mWrState = wr_state_new(aId);
 }
 
 DisplayListBuilder::~DisplayListBuilder()
 {
   MOZ_COUNT_DTOR(DisplayListBuilder);
   wr_state_delete(mWrState);
 }
 
 void
 DisplayListBuilder::Begin(const LayerIntSize& aSize)
 {
   wr_dp_begin(mWrState, aSize.width, aSize.height);
 }
 
 void
-DisplayListBuilder::End(WebRenderAPI& aApi, Epoch aEpoch)
+DisplayListBuilder::End()
 {
-  wr_dp_end(mWrState, aApi.mWrApi, aEpoch);
+  wr_dp_end(mWrState);
+}
+
+void
+DisplayListBuilder::Finalize(WrBuiltDisplayListDescriptor& dl_descriptor,
+                             wr::VecU8& dl_data,
+                             WrAuxiliaryListsDescriptor& aux_descriptor,
+                             wr::VecU8& aux_data)
+{
+    wr_api_finalize_builder(mWrState,
+                            dl_descriptor,
+                            dl_data.inner,
+                            aux_descriptor,
+                            aux_data.inner);
 }
 
 void
 DisplayListBuilder::PushStackingContext(const WrRect& aBounds,
                                         const WrRect& aOverflow,
                                         const WrImageMask* aMask,
                                         const float aOpacity,
                                         const gfx::Matrix4x4& aTransform,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -24,57 +24,75 @@ class CompositorBridgeParentBase;
 }
 
 namespace wr {
 
 class DisplayListBuilder;
 class RendererOGL;
 class RendererEvent;
 
+
+
 class WebRenderAPI
 {
   NS_INLINE_DECL_REFCOUNTING(WebRenderAPI);
 
 public:
   /// This can be called on the compositor thread only.
   static already_AddRefed<WebRenderAPI> Create(bool aEnableProfiler,
                                                layers::CompositorBridgeParentBase* aBridge,
                                                RefPtr<widget::CompositorWidget>&& aWidget);
 
   wr::WindowId GetId() const { return mId; }
 
+  void GenerateFrame();
+
   void SetRootDisplayList(gfx::Color aBgColor,
-                          wr::Epoch aEpoch,
+                          Epoch aEpoch,
                           LayerSize aViewportSize,
-                          DisplayListBuilder& aBuilder);
+                          WrPipelineId pipeline_id,
+                          WrBuiltDisplayListDescriptor dl_descriptor,
+                          uint8_t *dl_data,
+                          size_t dl_size,
+                          WrAuxiliaryListsDescriptor aux_descriptor,
+                          uint8_t *aux_data,
+                          size_t aux_size);
 
   void SetRootPipeline(wr::PipelineId aPipeline);
 
-  wr::ImageKey AddImageBuffer(const ImageDescriptor& aDescriptor,
-                              Range<uint8_t> aBytes);
+  void AddImage(wr::ImageKey aKey,
+                const ImageDescriptor& aDescriptor,
+                Range<uint8_t> aBytes);
 
-  wr::ImageKey AddExternalImageHandle(gfx::IntSize aSize,
-                                      gfx::SurfaceFormat aFormat,
-                                      uint64_t aHandle);
+  void AddExternalImageHandle(ImageKey key,
+                              gfx::IntSize aSize,
+                              gfx::SurfaceFormat aFormat,
+                              uint64_t aHandle);
+
+  void AddExternalImageBuffer(ImageKey key,
+                              gfx::IntSize aSize,
+                              gfx::SurfaceFormat aFormat,
+                              uint64_t aHandle);
 
   void UpdateImageBuffer(wr::ImageKey aKey,
                          const ImageDescriptor& aDescriptor,
                          Range<uint8_t> aBytes);
 
   void DeleteImage(wr::ImageKey aKey);
 
-  wr::FontKey AddRawFont(Range<uint8_t> aBytes);
+  void AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes);
 
   void DeleteFont(wr::FontKey aKey);
 
   void SetProfilerEnabled(bool aEnabled);
 
   void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
   void Readback(gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
 
+  WrIdNamespace GetNamespace();
   GLint GetMaxTextureSize() const { return mMaxTextureSize; }
   bool GetUseANGLE() const { return mUseANGLE; }
 
 protected:
   WebRenderAPI(WrAPI* aRawApi, wr::WindowId aId, GLint aMaxTextureSize, bool aUseANGLE)
     : mWrApi(aRawApi)
     , mId(aId)
     , mMaxTextureSize(aMaxTextureSize)
@@ -91,24 +109,28 @@ protected:
   friend class DisplayListBuilder;
 };
 
 /// This is a simple C++ wrapper around WrState defined in the rust bindings.
 /// We may want to turn this into a direct wrapper on top of WebRenderFrameBuilder
 /// instead, so the interface may change a bit.
 class DisplayListBuilder {
 public:
-  DisplayListBuilder(const LayerIntSize& aSize, wr::PipelineId aId);
+  explicit DisplayListBuilder(wr::PipelineId aId);
   DisplayListBuilder(DisplayListBuilder&&) = default;
 
   ~DisplayListBuilder();
 
   void Begin(const LayerIntSize& aSize);
 
-  void End(WebRenderAPI& aApi, wr::Epoch aEpoch);
+  void End();
+  void Finalize(WrBuiltDisplayListDescriptor& dl_descriptor,
+                wr::VecU8& dl_data,
+                WrAuxiliaryListsDescriptor& aux_descriptor,
+                wr::VecU8& aux_data);
 
   void PushStackingContext(const WrRect& aBounds, // TODO: We should work with strongly typed rects
                            const WrRect& aOverflow,
                            const WrImageMask* aMask, // TODO: needs a wrapper.
                            const float aOpacity,
                            const gfx::Matrix4x4& aTransform,
                            const WrMixBlendMode& aMixBlendMode);
 
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -5,16 +5,19 @@
 
 #ifndef GFX_WEBRENDERTYPES_H
 #define GFX_WEBRENDERTYPES_H
 
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/gfx/Tools.h"
+#include "mozilla/Range.h"
+#include "Units.h"
+#include "nsStyleConsts.h"
 
 typedef mozilla::Maybe<WrImageMask> MaybeImageMask;
 
 namespace mozilla {
 namespace wr {
 
 typedef WrGradientExtendMode GradientExtendMode;
 typedef WrMixBlendMode MixBlendMode;
@@ -230,24 +233,68 @@ static inline WrRect ToWrRect(const gfx:
 static inline WrPoint ToWrPoint(const gfx::Point& point)
 {
   WrPoint p;
   p.x = point.x;
   p.y = point.y;
   return p;
 }
 
+static inline WrExternalImageId ToWrExternalImageId(uint64_t aID)
+{
+  WrExternalImageId id;
+  id.id = aID;
+  return id;
+}
+
+struct VecU8 {
+  WrVecU8 inner;
+  VecU8() {
+    inner.data = nullptr;
+    inner.capacity = 0;
+  }
+  VecU8(VecU8&) = delete;
+  VecU8(VecU8&& src) {
+    inner = src.inner;
+    src.inner.data = nullptr;
+    src.inner.capacity = 0;
+  }
+
+  ~VecU8() {
+    if (inner.data) {
+      wr_vec_u8_free(inner);
+    }
+  }
+};
+
 struct ByteBuffer
 {
   ByteBuffer(size_t aLength, uint8_t* aData)
     : mLength(aLength)
     , mData(aData)
     , mOwned(false)
   {}
 
+  // XXX: this is a bit of hack that assumes
+  // the allocators are the same
+  explicit ByteBuffer(VecU8&& vec)
+  {
+    if (vec.inner.capacity) {
+      mLength = vec.inner.length;
+      mData = vec.inner.data;
+      vec.inner.data = nullptr;
+      vec.inner.capacity = 0;
+      mOwned = true;
+    } else {
+      mOwned = false;
+      mData = nullptr;
+      mLength = 0;
+    }
+  }
+
   ByteBuffer()
     : mLength(0)
     , mData(nullptr)
     , mOwned(false)
   {}
 
   bool
   Allocate(size_t aLength)
@@ -278,12 +325,19 @@ struct ByteBuffer
           !(memcmp(mData, other.mData, mLength));
   }
 
   size_t mLength;
   uint8_t* mData;
   bool mOwned;
 };
 
+struct BuiltDisplayList {
+  VecU8 dl;
+  WrBuiltDisplayListDescriptor dl_desc;
+  VecU8 aux;
+  WrAuxiliaryListsDescriptor aux_desc;
+};
+
 } // namespace wr
 } // namespace mozilla
 
 #endif /* GFX_WEBRENDERTYPES_H */
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,21 +1,23 @@
 use std::ffi::CString;
 use std::{mem, slice};
 use std::path::PathBuf;
 use std::os::raw::{c_void, c_char};
 use gleam::gl;
 use webrender_traits::{BorderSide, BorderStyle, BorderRadius, BorderWidths, BorderDetails, NormalBorder};
 use webrender_traits::{PipelineId, ClipRegion, PropertyBinding};
 use webrender_traits::{Epoch, ExtendMode, ColorF, GlyphInstance, GradientStop, ImageDescriptor};
-use webrender_traits::{FilterOp, ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, RendererKind, MixBlendMode};
+use webrender_traits::{FilterOp, ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, MixBlendMode};
 use webrender_traits::{ExternalImageId, RenderApi, FontKey};
 use webrender_traits::{DeviceUintSize, ExternalEvent};
 use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
-use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId};
+use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId, IdNamespace};
+use webrender_traits::{BuiltDisplayListDescriptor, AuxiliaryListsDescriptor};
+use webrender_traits::{BuiltDisplayList, AuxiliaryLists};
 use webrender::renderer::{Renderer, RendererOptions};
 use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use app_units::Au;
 use euclid::TypedPoint2D;
 
 extern crate webrender_traits;
 
@@ -43,31 +45,68 @@ macro_rules! check_ffi_type {
 
 check_ffi_type!(_pipeline_id_repr struct PipelineId as (u32, u32));
 check_ffi_type!(_image_key_repr struct ImageKey as (u32, u32));
 check_ffi_type!(_font_key_repr struct FontKey as (u32, u32));
 check_ffi_type!(_epoch_repr struct Epoch as (u32));
 check_ffi_type!(_image_format_repr enum ImageFormat as u32);
 check_ffi_type!(_border_style_repr enum BorderStyle as u32);
 check_ffi_type!(_image_rendering_repr enum ImageRendering as u32);
+check_ffi_type!(_namespace_id_repr struct IdNamespace as (u32));
 
 #[repr(C)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct WrWindowId(u64);
 
 #[repr(C)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct WrImageDescriptor {
     pub format: ImageFormat,
     pub width: u32,
     pub height: u32,
     pub stride: u32,
     pub is_opaque: bool,
 }
 
+impl WrImageDescriptor {
+    pub fn to_descriptor(&self) -> ImageDescriptor {
+        ImageDescriptor {
+            width: self.width,
+            height: self.height,
+            stride: if self.stride != 0 { Some(self.stride) } else { None },
+            format: self.format,
+            is_opaque: self.is_opaque,
+            offset: 0,
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WrVecU8 {
+    ptr: *mut u8,
+    length: usize,
+    capacity: usize
+}
+
+impl WrVecU8 {
+    fn to_vec(self) -> Vec<u8> {
+        unsafe { Vec::from_raw_parts(self.ptr, self.length, self.capacity) }
+    }
+    fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
+        let w = WrVecU8{ptr: v.as_mut_ptr(), length: v.len(), capacity: v.capacity()};
+        mem::forget(v);
+        w
+    }
+}
+
+#[no_mangle]
+pub extern fn wr_vec_u8_free(v: WrVecU8) {
+    v.to_vec();
+}
+
 fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void{
 
     extern  {
         fn get_proc_address_from_glcontext(glcontext_ptr: *mut c_void, procname: *const c_char) -> *const c_void;
     }
 
     let symbol_name = CString::new(name).unwrap();
     let symbol = unsafe {
@@ -81,16 +120,17 @@ fn get_proc_address(glcontext_ptr: *mut 
     }
 
     symbol as *const _
 }
 
 extern  {
     fn is_in_compositor_thread() -> bool;
     fn is_in_render_thread() -> bool;
+    fn is_in_main_thread() -> bool;
 }
 
 #[no_mangle]
 pub extern fn wr_renderer_update(renderer: &mut Renderer) {
     renderer.update();
 }
 
 #[no_mangle]
@@ -116,65 +156,123 @@ pub unsafe extern fn wr_renderer_readbac
 }
 
 #[no_mangle]
 pub extern fn wr_renderer_set_profiler_enabled(renderer: &mut Renderer, enabled: bool) {
     renderer.set_profiler_enabled(enabled);
 }
 
 #[no_mangle]
+pub extern fn wr_renderer_set_external_image_handler(renderer: &mut Renderer,
+                                                     external_image_handler: *mut WrExternalImageHandler) {
+    if !external_image_handler.is_null() {
+        renderer.set_external_image_handler(Box::new(
+            unsafe {
+                WrExternalImageHandler {
+                    external_image_obj: (*external_image_handler).external_image_obj,
+                    lock_func: (*external_image_handler).lock_func,
+                    unlock_func: (*external_image_handler).unlock_func,
+                    release_func: (*external_image_handler).release_func,
+                }
+            }));
+    }
+}
+
+#[no_mangle]
 pub extern fn wr_renderer_current_epoch(renderer: &mut Renderer,
                                         pipeline_id: PipelineId,
                                         out_epoch: &mut Epoch) -> bool {
     if let Some(epoch) = renderer.current_epoch(pipeline_id) {
         *out_epoch = epoch;
         return true;
     }
     return false;
 }
 
 #[no_mangle]
 pub unsafe extern fn wr_renderer_delete(renderer: *mut Renderer) {
     Box::from_raw(renderer);
 }
 
 #[no_mangle]
+pub unsafe extern fn wr_api_get_namespace(api: &mut RenderApi) -> IdNamespace
+{
+    api.id_namespace
+}
+
+#[no_mangle]
 pub unsafe extern fn wr_api_delete(api: *mut RenderApi) {
     let api = Box::from_raw(api);
     api.shut_down();
 }
 
 #[no_mangle]
+pub unsafe extern fn wr_api_finalize_builder(state: &mut WrState,
+                                             dl_descriptor: &mut BuiltDisplayListDescriptor,
+                                             dl_data: &mut WrVecU8,
+                                             aux_descriptor: &mut AuxiliaryListsDescriptor,
+                                             aux_data: &mut WrVecU8)
+{
+    let frame_builder = mem::replace(&mut state.frame_builder,
+                                     WebRenderFrameBuilder::new(state.pipeline_id));
+    let (_, dl, aux) = frame_builder.dl_builder.finalize();
+    //XXX: get rid of the copies here
+    *dl_data = WrVecU8::from_vec(dl.data().to_owned());
+    *dl_descriptor = dl.descriptor().clone();
+    *aux_data = WrVecU8::from_vec(aux.data().to_owned());
+    *aux_descriptor = aux.descriptor().clone();
+}
+
+#[no_mangle]
 pub unsafe extern fn wr_api_set_root_display_list(api: &mut RenderApi,
-                                                  state: &mut WrState,
                                                   epoch: Epoch,
                                                   viewport_width: f32,
-                                                  viewport_height: f32) {
+                                                  viewport_height: f32,
+                                                  pipeline_id: PipelineId,
+                                                  dl_descriptor: BuiltDisplayListDescriptor,
+                                                  dl_data: *mut u8,
+                                                  dl_size: usize,
+                                                  aux_descriptor: AuxiliaryListsDescriptor,
+                                                  aux_data: *mut u8,
+                                                  aux_size: usize) {
     let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
-    let frame_builder = mem::replace(&mut state.frame_builder,
-                                     WebRenderFrameBuilder::new(state.pipeline_id));
     // See the documentation of set_root_display_list in api.rs. I don't think
     // it makes a difference in gecko at the moment(until APZ is figured out)
     // but I suppose it is a good default.
     let preserve_frame_state = true;
-    //let (dl_builder, aux_builder) = fb.dl_builder.finalize();
+
+    let dl_slice = slice::from_raw_parts(dl_data, dl_size);
+    let mut dl_vec = Vec::new();
+    // XXX: see if we can get rid of the copy here
+    dl_vec.extend_from_slice(dl_slice);
+    let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
+
+    let aux_slice = slice::from_raw_parts(aux_data, aux_size);
+    let mut aux_vec = Vec::new();
+    // XXX: see if we can get rid of the copy here
+    aux_vec.extend_from_slice(aux_slice);
+    let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
+
     api.set_root_display_list(Some(root_background_color),
                               epoch,
                               LayoutSize::new(viewport_width, viewport_height),
-                              frame_builder.dl_builder,
+                              (pipeline_id, dl, aux),
                               preserve_frame_state);
-    api.generate_frame(None);
+}
+
+#[no_mangle]
+pub extern fn wr_api_generate_frame(api: &mut RenderApi) {
+  api.generate_frame(None);
 }
 
 // Call MakeCurrent before this.
 #[no_mangle]
 pub extern fn wr_window_new(window_id: WrWindowId,
                             gl_context: *mut c_void,
                             enable_profiler: bool,
-                            external_image_handler: *mut WrExternalImageHandler,
                             out_api: &mut *mut RenderApi,
                             out_renderer: &mut *mut Renderer) -> bool {
     assert!(unsafe { is_in_render_thread() });
 
     let recorder: Option<Box<ApiRecordingReceiver>> = if ENABLE_RECORDING {
         let name = format!("wr-record-{}.bin", window_id.0);
         Some(Box::new(BinaryRecorder::new(&PathBuf::from(name))))
     } else {
@@ -184,77 +282,64 @@ pub extern fn wr_window_new(window_id: W
     gl::load_with(|symbol| get_proc_address(gl_context, symbol));
     gl::clear_color(0.3, 0.0, 0.0, 1.0);
 
     let version = gl::get_string(gl::VERSION);
 
     println!("WebRender - OpenGL version new {}", version);
 
     let opts = RendererOptions {
-        enable_aa: false,
+        enable_aa: true,
+        enable_subpixel_aa: true,
         enable_profiler: enable_profiler,
         recorder: recorder,
         .. Default::default()
     };
 
-    let (mut renderer, sender) = match Renderer::new(opts) {
+    let (renderer, sender) = match Renderer::new(opts) {
         Ok((renderer, sender)) => { (renderer, sender) }
         Err(e) => {
             println!(" Failed to create a Renderer: {:?}", e);
             return false;
         }
     };
 
     renderer.set_render_notifier(Box::new(CppNotifier { window_id: window_id }));
 
-    if !external_image_handler.is_null() {
-        renderer.set_external_image_handler(Box::new(
-            unsafe {
-                WrExternalImageHandler {
-                    external_image_obj: (*external_image_handler).external_image_obj,
-                    lock_func: (*external_image_handler).lock_func,
-                    unlock_func: (*external_image_handler).unlock_func,
-                    release_func: (*external_image_handler).release_func,
-                }
-            }));
-    }
-
     *out_api = Box::into_raw(Box::new(sender.create_api()));
     *out_renderer = Box::into_raw(Box::new(renderer));
 
     return true;
 }
 
 #[no_mangle]
-pub extern fn wr_state_new(width: u32, height: u32, pipeline_id: PipelineId) -> *mut WrState {
-    assert!(unsafe { is_in_compositor_thread() });
+pub extern fn wr_state_new(pipeline_id: PipelineId) -> *mut WrState {
+    assert!(unsafe { is_in_main_thread() });
 
     let state = Box::new(WrState {
-        size: (width, height),
         pipeline_id: pipeline_id,
         z_index: 0,
         frame_builder: WebRenderFrameBuilder::new(pipeline_id),
     });
 
     Box::into_raw(state)
 }
 
 #[no_mangle]
 pub extern fn wr_state_delete(state:*mut WrState) {
-    assert!(unsafe { is_in_compositor_thread() });
+    assert!(unsafe { is_in_main_thread() });
 
     unsafe {
         Box::from_raw(state);
     }
 }
 
 #[no_mangle]
 pub extern fn wr_dp_begin(state: &mut WrState, width: u32, height: u32) {
-    assert!( unsafe { is_in_compositor_thread() });
-    state.size = (width, height);
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.list.clear();
     state.z_index = 0;
 
     let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(width as f32, height as f32));
 
     state.frame_builder.dl_builder.push_stacking_context(
         webrender_traits::ScrollPolicy::Scrollable,
         bounds,
@@ -263,33 +348,19 @@ pub extern fn wr_dp_begin(state: &mut Wr
         PropertyBinding::Value(LayoutTransform::identity()),
         LayoutTransform::identity(),
         webrender_traits::MixBlendMode::Normal,
         Vec::new(),
     );
 }
 
 #[no_mangle]
-pub extern fn wr_dp_end(state: &mut WrState, api: &mut RenderApi, epoch: u32) {
-    assert!( unsafe { is_in_compositor_thread() });
-    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
-    let pipeline_id = state.pipeline_id;
-    let (width, height) = state.size;
-
+pub extern fn wr_dp_end(state: &mut WrState) {
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_stacking_context();
-
-    let fb = mem::replace(&mut state.frame_builder, WebRenderFrameBuilder::new(pipeline_id));
-
-    let preserve_frame_state = true;
-    api.set_root_display_list(Some(root_background_color),
-                              Epoch(epoch),
-                              LayoutSize::new(width as f32, height as f32),
-                              fb.dl_builder,
-                              preserve_frame_state);
-    api.generate_frame(None);
 }
 
 #[no_mangle]
 pub unsafe extern fn wr_renderer_flush_rendered_epochs(renderer: &mut Renderer) -> *mut Vec<(PipelineId, Epoch)> {
     let map = renderer.flush_rendered_epochs();
     let pipeline_epochs = Box::new(map.into_iter().collect());
     return Box::into_raw(pipeline_epochs);
 }
@@ -365,33 +436,31 @@ impl WebRenderFrameBuilder {
         WebRenderFrameBuilder {
             root_pipeline_id: root_pipeline_id,
             dl_builder: webrender_traits::DisplayListBuilder::new(root_pipeline_id),
         }
     }
 }
 
 pub struct WrState {
-    size: (u32, u32),
     pipeline_id: PipelineId,
     z_index: i32,
     frame_builder: WebRenderFrameBuilder,
 }
 
-#[repr(C)]
-enum WrExternalImageType {
-    TEXTURE_HANDLE,
-
-    // TODO(Jerry): handle shmem or cpu raw buffers.
-    //// MEM_OR_SHMEM,
-}
+// TODO(Jerry): handle shmem or cpu raw buffers.
+//#[repr(C)]
+//enum WrExternalImageType {
+//    TextureHandle,
+//    MemOrShmem,
+//}
 
 #[repr(C)]
 struct WrExternalImageStruct {
-    image_type: WrExternalImageType,
+    //image_type: WrExternalImageType,
 
     // Texture coordinate
     u0: f32,
     v0: f32,
     u1: f32,
     v1: f32,
 
     // external buffer handle
@@ -413,26 +482,27 @@ pub struct WrExternalImageHandler {
     unlock_func: UnlockExternalImageCallback,
     release_func: ReleaseExternalImageCallback,
 }
 
 impl ExternalImageHandler for WrExternalImageHandler {
     fn lock(&mut self, id: ExternalImageId) -> ExternalImage {
         let image = (self.lock_func)(self.external_image_obj, id);
 
-        match image.image_type {
-            WrExternalImageType::TEXTURE_HANDLE =>
+        // TODO(Jerry): handle shmem or cpu raw buffers.
+        //match image.image_type {
+        //    WrExternalImageType::TextureHandle =>
                 ExternalImage {
                     u0: image.u0,
                     v0: image.v0,
                     u1: image.u1,
                     v1: image.v1,
                     source: ExternalImageSource::NativeTexture(image.handle)
-                },
-        }
+                }
+        //}
     }
 
     fn unlock(&mut self, id: ExternalImageId) {
         (self.unlock_func)(self.external_image_obj, id);
     }
 
     fn release(&mut self, id: ExternalImageId) {
         (self.release_func)(self.external_image_obj, id);
@@ -524,21 +594,21 @@ impl WrGradientExtendMode
             WrGradientExtendMode::Repeat => ExtendMode::Repeat,
         }
     }
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_stacking_context(state:&mut WrState, bounds: WrRect, overflow: WrRect, mask: *const WrImageMask, opacity: f32, transform: &LayoutTransform, mix_blend_mode: WrMixBlendMode)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.z_index += 1;
 
     let bounds = bounds.to_rect();
-    let mut overflow = overflow.to_rect();
+    let overflow = overflow.to_rect();
     let mix_blend_mode = mix_blend_mode.to_mix_blend_mode();
     //println!("stacking context: {:?} {:?} {:?} {:?} {:?}", state.pipeline_id, bounds, overflow, mask, transform);
     // convert from the C type to the Rust type
     let mask = unsafe { mask.as_ref().map(|&WrImageMask{image, ref rect,repeat}| ImageMask{image: image, rect: rect.to_rect(), repeat: repeat}) };
 
     let clip_region2 = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], None);
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], mask);
 
@@ -557,17 +627,17 @@ pub extern fn wr_dp_push_stacking_contex
                                   filters);
     state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, ServoScrollRootId(1));
 
 }
 
 #[no_mangle]
 pub extern fn wr_dp_pop_stacking_context(state: &mut WrState)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
     state.frame_builder.dl_builder.pop_stacking_context();
     //println!("pop_stacking {:?}", state.pipeline_id);
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_scroll_layer(state: &mut WrState, bounds: WrRect, overflow: WrRect, mask: Option<&WrImageMask>)
 {
@@ -576,66 +646,72 @@ pub extern fn wr_dp_push_scroll_layer(st
     let mask = mask.map(|&WrImageMask{image, ref rect,repeat}| ImageMask{image: image, rect: rect.to_rect(), repeat: repeat});
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], mask);
     state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, ServoScrollRootId(1));
 }
 
 #[no_mangle]
 pub extern fn wr_dp_pop_scroll_layer(state: &mut WrState)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
 }
 
 #[no_mangle]
 pub extern fn wr_api_set_root_pipeline(api: &mut RenderApi, pipeline_id: PipelineId) {
     api.set_root_pipeline(pipeline_id);
     api.generate_frame(None);
 }
 
 #[no_mangle]
-pub extern fn wr_api_add_image(api: &mut RenderApi, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) -> ImageKey {
+pub extern fn wr_api_generate_image_key(api: &mut RenderApi) -> ImageKey
+{
+    api.generate_image_key()
+}
+
+#[no_mangle]
+pub extern fn wr_api_add_image(api: &mut RenderApi, image_key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
     assert!( unsafe { is_in_compositor_thread() });
     let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
-    let image_key = api.generate_image_key();
     api.add_image(
         image_key,
-        ImageDescriptor {
-            width: descriptor.width,
-            height: descriptor.height,
-            stride: if descriptor.stride != 0 { Some(descriptor.stride) } else { None },
-            format: descriptor.format,
-            is_opaque: descriptor.is_opaque,
-        },
-        ImageData::new(bytes)
+        descriptor.to_descriptor(),
+        ImageData::new(bytes),
+        None
     );
-    image_key
 }
 
 #[no_mangle]
-pub extern fn wr_api_add_external_image_texture(api: &mut RenderApi, width: u32, height: u32, format: ImageFormat, external_image_id: u64) -> ImageKey {
+pub extern fn wr_api_add_external_image_handle(api: &mut RenderApi, image_key: ImageKey, width: u32, height: u32, format: ImageFormat, external_image_id: u64) {
     assert!( unsafe { is_in_compositor_thread() });
-    unimplemented!(); // TODO
-    //api.add_image(ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false}, ImageData::External(ExternalImageId(external_image_id)))
+    api.add_image(image_key,
+                  ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false, offset: 0},
+                  ImageData::ExternalHandle(ExternalImageId(external_image_id)),
+                  None
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_api_add_external_image_buffer(api: &mut RenderApi, image_key: ImageKey, width: u32, height: u32, format: ImageFormat, external_image_id: u64) {
+    assert!( unsafe { is_in_compositor_thread() });
+    api.add_image(image_key,
+                  ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false, offset: 0},
+                  ImageData::ExternalBuffer(ExternalImageId(external_image_id)),
+                  None
+    );
 }
 
 #[no_mangle]
 pub extern fn wr_api_update_image(api: &mut RenderApi, key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
     assert!( unsafe { is_in_compositor_thread() });
     let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
 
     api.update_image(
         key,
-        ImageDescriptor {
-            width: descriptor.width,
-            height: descriptor.height,
-            stride: if descriptor.stride != 0 { Some(descriptor.stride) } else { None },
-            format: descriptor.format,
-            is_opaque: descriptor.is_opaque,
-        },
+        descriptor.to_descriptor(),
         bytes
     );
 }
 #[no_mangle]
 pub extern fn wr_api_delete_image(api: &mut RenderApi, key: ImageKey) {
     assert!( unsafe { is_in_compositor_thread() });
     api.delete_image(key)
 }
@@ -645,48 +721,48 @@ pub extern fn wr_api_send_external_event
     assert!(unsafe { is_in_compositor_thread() });
 
     api.send_external_event(ExternalEvent::from_raw(evt));
 }
 
 
 #[no_mangle]
 pub extern fn wr_dp_push_rect(state: &mut WrState, rect: WrRect, clip: WrRect, color: WrColor) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
 
     state.frame_builder.dl_builder.push_rect(
                                     rect.to_rect(),
                                     clip_region,
                                     color.to_color());
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrRect,
                                     box_bounds: WrRect, offset: WrPoint, color: WrColor,
                                     blur_radius: f32, spread_radius: f32, border_radius: f32,
                                     clip_mode: WrBoxShadowClipMode) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
     state.frame_builder.dl_builder.push_box_shadow(rect.to_rect(),
                                                    clip_region,
                                                    box_bounds.to_rect(),
                                                    offset.to_point(),
                                                    color.to_color(),
                                                    blur_radius,
                                                    spread_radius,
                                                    border_radius,
                                                    clip_mode.to_box_shadow_clip_mode());
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_border(state: &mut WrState, rect: WrRect, clip: WrRect,
                                 top: WrBorderSide, right: WrBorderSide, bottom: WrBorderSide, left: WrBorderSide,
                                 radius: WrBorderRadius) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
     let border_widths = BorderWidths {
         left: left.width,
         top: top.width,
         right: right.width,
         bottom: bottom.width
     };
     let border_details = BorderDetails::Normal(NormalBorder {
@@ -703,17 +779,17 @@ pub extern fn wr_dp_push_border(state: &
                                     border_details);
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_linear_gradient(state: &mut WrState, rect: WrRect, clip: WrRect,
                                          start_point: WrPoint, end_point: WrPoint,
                                          stops: * const WrGradientStop, stops_count: usize,
                                          extend_mode: WrGradientExtendMode) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let stops = WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
 
     state.frame_builder.dl_builder.push_gradient(
                                     rect.to_rect(),
                                     clip_region,
                                     start_point.to_point(),
@@ -724,17 +800,17 @@ pub extern fn wr_dp_push_linear_gradient
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_radial_gradient(state: &mut WrState, rect: WrRect, clip: WrRect,
                                          start_center: WrPoint, end_center: WrPoint,
                                          start_radius: f32, end_radius: f32,
                                          stops: * const WrGradientStop, stops_count: usize,
                                          extend_mode: WrGradientExtendMode) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let stops = WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
 
     state.frame_builder.dl_builder.push_radial_gradient(
                                     rect.to_rect(),
                                     clip_region,
                                     start_center.to_point(),
@@ -743,17 +819,17 @@ pub extern fn wr_dp_push_radial_gradient
                                     end_radius,
                                     stops,
                                     extend_mode.to_gradient_extend_mode()
                                     );
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_iframe(state: &mut WrState, rect: WrRect, clip: WrRect, pipeline_id: PipelineId) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(),
                                                                      Vec::new(),
                                                                      None);
     state.frame_builder.dl_builder.push_iframe(rect.to_rect(),
                                                clip_region,
                                                pipeline_id);
 }
@@ -893,17 +969,17 @@ impl WrImageMask
     pub fn to_image_mask(&self) -> ImageMask
     {
         ImageMask { image: self.image, rect: self.rect.to_rect(), repeat: self.repeat }
     }
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_image(state:&mut WrState, bounds: WrRect, clip : WrRect, mask: *const WrImageMask, filter: ImageRendering, key: ImageKey) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let bounds = bounds.to_rect();
     let clip = clip.to_rect();
 
     //println!("push_image bounds {:?} clip {:?}", bounds, clip);
     // convert from the C type to the Rust type, mapping NULL to None
     let mask = unsafe { mask.as_ref().map(|m| m.to_image_mask()) };
     let image_rendering = filter;
@@ -913,46 +989,51 @@ pub extern fn wr_dp_push_image(state:&mu
         bounds,
         clip_region,
         bounds.size,
         bounds.size,
         image_rendering,
         key
     );
 }
+#[no_mangle]
+pub extern fn wr_api_generate_font_key(api: &mut RenderApi) -> FontKey
+{
+    api.generate_font_key()
+}
 
 #[no_mangle]
 pub extern fn wr_api_add_raw_font(api: &mut RenderApi,
+                                  key: FontKey,
                                   font_buffer: *mut u8,
-                                  buffer_size: usize) -> FontKey
+                                  buffer_size: usize)
 {
     assert!( unsafe { is_in_compositor_thread() });
 
     let font_slice = unsafe {
         slice::from_raw_parts(font_buffer, buffer_size as usize)
     };
     let mut font_vector = Vec::new();
     font_vector.extend_from_slice(font_slice);
 
-    let font_key = api.generate_font_key();
-    api.add_raw_font(font_key, font_vector);
-    font_key
+    api.add_raw_font(key, font_vector);
 }
 
+
 #[no_mangle]
 pub extern fn wr_dp_push_text(state: &mut WrState,
                               bounds: WrRect,
                               clip: WrRect,
                               color: WrColor,
                               font_key: FontKey,
                               glyphs: *mut GlyphInstance,
                               glyph_count: u32,
                               glyph_size: f32)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let glyph_slice = unsafe {
         slice::from_raw_parts(glyphs, glyph_count as usize)
     };
     let mut glyph_vector = Vec::new();
     glyph_vector.extend_from_slice(&glyph_slice);
 
     let colorf = ColorF::new(color.r, color.g, color.b, color.a);
--- a/gfx/webrender_bindings/src/lib.rs
+++ b/gfx/webrender_bindings/src/lib.rs
@@ -1,21 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#![deny(warnings)]
+
 extern crate webrender;
 extern crate webrender_traits;
 extern crate euclid;
 extern crate app_units;
 extern crate gleam;
-extern crate fnv;
-
-#[cfg(target_os="macos")]
-extern crate core_foundation;
-
-#[cfg(target_os="windows")]
-extern crate kernel32;
-#[cfg(target_os="windows")]
-extern crate winapi;
 
 #[allow(non_snake_case)]
 pub mod bindings;
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -2,19 +2,19 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WR_h
 #define WR_h
 
-#include "mozilla/layers/LayersMessages.h"
 #include "mozilla/gfx/Types.h"
-
+#include "nsTArray.h"
+#include "mozilla/gfx/Point.h"
 // ---
 #define WR_DECL_FFI_1(WrType, t1)                 \
 struct WrType {                                   \
   t1 mHandle;                                     \
   bool operator==(const WrType& rhs) const {      \
     return mHandle == rhs.mHandle;                \
   }                                               \
   bool operator!=(const WrType& rhs) const {      \
@@ -44,30 +44,32 @@ struct WrType {                         
 
 
 extern "C" {
 
 // If you modify any of the declarations below, make sure to update the
 // serialization code in WebRenderMessageUtils.h and the rust bindings.
 
 WR_DECL_FFI_1(WrEpoch, uint32_t)
+WR_DECL_FFI_1(WrIdNamespace, uint32_t)
 WR_DECL_FFI_1(WrWindowId, uint64_t)
 
 WR_DECL_FFI_2(WrPipelineId, uint32_t, uint32_t)
 WR_DECL_FFI_2(WrImageKey, uint32_t, uint32_t)
 WR_DECL_FFI_2(WrFontKey, uint32_t, uint32_t)
 
 #undef WR_DECL_FFI_1
 #undef WR_DECL_FFI_2
 
 // ----
 // Functions invoked from Rust code
 // ----
 
 bool is_in_compositor_thread();
+bool is_in_main_thread();
 bool is_in_render_thread();
 void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
 
 // -----
 // Enums used in C++ code with corresponding enums in Rust code
 // -----
 enum class WrBoxShadowClipMode: uint32_t {
   None,
@@ -108,22 +110,24 @@ enum class WrImageRendering: uint32_t
 {
   Auto        = 0,
   CrispEdges  = 1,
   Pixelated   = 2,
 
   Sentinel /* this must be last, for IPC serialization purposes */
 };
 
-enum class WrExternalImageIdType
-{
-  TEXTURE_HANDLE, // Currently, we only support gl texture handle.
-  // TODO(Jerry): handle shmem or cpu raw buffers.
-  //// MEM_OR_SHMEM,
-};
+// TODO(Jerry): handle shmem or cpu raw buffers.
+//enum class WrExternalImageIdType: uint32_t
+//{
+//  TextureHandle = 0,
+//  MemOrShmem    = 1,
+//
+//  Sentinel /* this must be last, for IPC serialization purposes */
+//};
 
 enum class WrMixBlendMode: uint32_t
 {
   Normal      = 0,
   Multiply    = 1,
   Screen      = 2,
   Overlay     = 3,
   Darken      = 4,
@@ -293,58 +297,75 @@ struct WrImageMask
   bool repeat;
 
   bool operator==(const WrImageMask& aRhs) const
   {
     return image == aRhs.image && rect == aRhs.rect && repeat == aRhs.repeat;
   }
 };
 
-struct WrExternalImageIdId
+struct WrExternalImageId
 {
   WrImageIdType id;
 };
 
-struct WrExternalImageId
+struct WrExternalImage
 {
-  WrExternalImageIdType type;
+  //WrExternalImageIdType type;
 
   // Texture coordinate
   float u0, v0;
   float u1, v1;
 
   // external buffer handle
   uint32_t handle;
 
   // TODO(Jerry): handle shmem or cpu raw buffers.
   //// shmem or memory buffer
   //// uint8_t* buff;
   //// size_t size;
 };
 
-typedef WrExternalImageId (*LockExternalImageCallback)(void*, WrExternalImageIdId);
-typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageIdId);
-typedef void (*ReleaseExternalImageCallback)(void*, WrExternalImageIdId);
+typedef WrExternalImage (*LockExternalImageCallback)(void*, WrExternalImageId);
+typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageId);
+typedef void (*ReleaseExternalImageCallback)(void*, WrExternalImageId);
 
-struct WrExternalImageIdHandler
+struct WrExternalImageHandler
 {
-  void* ExternalImageObj;
+  void* renderer_obj;
   LockExternalImageCallback lock_func;
   UnlockExternalImageCallback unlock_func;
   ReleaseExternalImageCallback release_func;
 };
 
 struct WrImageDescriptor {
     WrImageFormat format;
     uint32_t width;
     uint32_t height;
     uint32_t stride;
     bool is_opaque;
 };
 
+struct WrBuiltDisplayListDescriptor {
+    size_t display_list_items_size;
+};
+
+struct WrAuxiliaryListsDescriptor {
+    size_t gradient_stops_size;
+    size_t complex_clip_regions_size;
+    size_t filters_size;
+    size_t glyph_instances_size;
+};
+
+struct WrVecU8 {
+    uint8_t *data;
+    size_t length;
+    size_t capacity;
+};
+
 // -----
 // Functions exposed by the webrender API
 // -----
 
 // Some useful defines to stub out webrender binding functions for when we
 // build gecko without webrender. We try to tell the compiler these functions
 // are unreachable in that case, but VC++ emits a warning if it finds any
 // unreachable functions invoked from destructors. That warning gets turned into
@@ -363,16 +384,21 @@ struct WrImageDescriptor {
 
 // Structs defined in Rust, but opaque to C++ code.
 struct WrRenderedEpochs;
 struct WrRenderer;
 struct WrState;
 struct WrAPI;
 
 WR_INLINE void
+wr_renderer_set_external_image_handler(WrRenderer* renderer,
+                                       WrExternalImageHandler* handler)
+WR_FUNC;
+
+WR_INLINE void
 wr_renderer_update(WrRenderer* renderer)
 WR_FUNC;
 
 WR_INLINE void
 wr_renderer_render(WrRenderer* renderer, uint32_t width, uint32_t height)
 WR_FUNC;
 
 WR_INLINE void
@@ -398,68 +424,77 @@ wr_rendered_epochs_next(WrRenderedEpochs
 
 WR_INLINE void
 wr_rendered_epochs_delete(WrRenderedEpochs* pipeline_epochs) WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE bool
 wr_window_new(WrWindowId window_id,
               void* aGLContext,
               bool enable_profiler,
-              WrExternalImageIdHandler* handler,
               WrAPI** out_api,
               WrRenderer** out_renderer)
 WR_FUNC;
 
 WR_INLINE void
 wr_api_delete(WrAPI* api)
 WR_DESTRUCTOR_SAFE_FUNC;
 
-WR_INLINE WrImageKey
-wr_api_add_image(WrAPI* api, const WrImageDescriptor* descriptor, uint8_t *buffer, size_t buffer_size)
+WR_INLINE void
+wr_api_add_image(WrAPI* api, WrImageKey key, const WrImageDescriptor* descriptor, uint8_t *buffer, size_t buffer_size)
 WR_FUNC;
 
-WR_INLINE WrImageKey
-wr_api_add_external_image_texture(WrAPI* api, uint32_t width, uint32_t height,
-                                  WrImageFormat format, uint64_t external_image_id)
+WR_INLINE void
+wr_api_add_external_image_handle(WrAPI* api, WrImageKey key, uint32_t width, uint32_t height,
+                                 WrImageFormat format, uint64_t external_image_id)
 WR_FUNC;
 
-//TODO(Jerry): handle shmem in WR
-//// WR_INLINE WrImageKey
-//// wr_api_add_external_image_buffer(WrAPI* api, uint32_t width, uint32_t height, uint32_t stride,
-////                                  WrImageFormat format, uint8_t *bytes, size_t size)
-//// WR_FUNC;
+WR_INLINE void
+wr_api_add_external_image_buffer(WrAPI* api, WrImageKey key, uint32_t width, uint32_t height,
+                                 WrImageFormat format, uint64_t external_image_id)
+WR_FUNC;
 
 WR_INLINE void
 wr_api_update_image(WrAPI* api, WrImageKey key,
                     const WrImageDescriptor* descriptor,
                     uint8_t *bytes, size_t size)
 WR_FUNC;
 
 WR_INLINE void
 wr_api_delete_image(WrAPI* api, WrImageKey key)
 WR_FUNC;
 
 WR_INLINE void
 wr_api_set_root_pipeline(WrAPI* api, WrPipelineId pipeline_id)
 WR_FUNC;
 
 WR_INLINE void
-wr_api_set_root_display_list(WrAPI* api, WrState* state, WrEpoch epoch, float w, float h)
+wr_api_set_root_display_list(WrAPI* api, WrEpoch epoch, float w, float h,
+                             WrPipelineId pipeline_id,
+                             WrBuiltDisplayListDescriptor dl_descriptor,
+                             uint8_t *dl_data,
+                             size_t dl_size,
+                             WrAuxiliaryListsDescriptor aux_descriptor,
+                             uint8_t *aux_data,
+                             size_t aux_size)
+WR_FUNC;
+
+WR_INLINE void
+wr_api_generate_frame(WrAPI* api)
 WR_FUNC;
 
 WR_INLINE void
 wr_api_send_external_event(WrAPI* api, uintptr_t evt)
 WR_DESTRUCTOR_SAFE_FUNC;
 
-WR_INLINE WrFontKey
-wr_api_add_raw_font(WrAPI* api, uint8_t* font_buffer, size_t buffer_size)
+WR_INLINE void
+wr_api_add_raw_font(WrAPI* api, WrFontKey key, uint8_t* font_buffer, size_t buffer_size)
 WR_FUNC;
 
 WR_INLINE WrState*
-wr_state_new(uint32_t width, uint32_t height, WrPipelineId pipeline_id)
+wr_state_new(WrPipelineId pipeline_id)
 WR_FUNC;
 
 WR_INLINE void
 wr_state_delete(WrState* state)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE void
 wr_dp_push_stacking_context(WrState *wrState, WrRect bounds,
@@ -483,17 +518,17 @@ wr_dp_pop_scroll_layer(WrState *wrState)
 WR_FUNC;
 
 
 WR_INLINE void
 wr_dp_begin(WrState* wrState, uint32_t width, uint32_t height)
 WR_FUNC;
 
 WR_INLINE void
-wr_dp_end(WrState* builder, WrAPI* api, WrEpoch epoch)
+wr_dp_end(WrState* wrState)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_rect(WrState* wrState, WrRect bounds, WrRect clip,
                 WrColor color)
 WR_FUNC;
 
 WR_INLINE void
@@ -541,13 +576,29 @@ WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_box_shadow(WrState* wrState, WrRect rect, WrRect clip,
                       WrRect box_bounds, WrPoint offset, WrColor color,
                       float blur_radius, float spread_radius, float border_radius,
                       WrBoxShadowClipMode clip_mode)
 WR_FUNC;
 
+WR_INLINE WrIdNamespace
+wr_api_get_namespace(WrAPI* api)
+WR_FUNC;
+
+WR_INLINE void
+wr_api_finalize_builder(WrState* wrState,
+                        WrBuiltDisplayListDescriptor& dl_descriptor,
+                        WrVecU8& dl_data,
+                        WrAuxiliaryListsDescriptor& aux_descriptor,
+                        WrVecU8& aux_data)
+WR_FUNC;
+
+WR_INLINE void
+wr_vec_u8_free(WrVecU8 dl_data)
+WR_FUNC;
+
 #undef WR_FUNC
 #undef WR_DESTRUCTOR_SAFE_FUNC
 } // extern "C"
 
 #endif // WR_h
--- a/gfx/webrender_traits/Cargo.toml
+++ b/gfx/webrender_traits/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "webrender_traits"
-version = "0.19.0"
+version = "0.20.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 build = "build.rs"
 
 [features]
 default = ["codegen"]
 nightly = ["euclid/unstable", "serde/unstable"]
--- a/gfx/webrender_traits/src/api.rs
+++ b/gfx/webrender_traits/src/api.rs
@@ -4,18 +4,19 @@
 
 use byteorder::{LittleEndian, WriteBytesExt};
 use channel::{self, MsgSender, PayloadHelperMethods, PayloadSender};
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use std::cell::Cell;
 use {ApiMsg, ColorF, DisplayListBuilder, Epoch, ImageDescriptor};
 use {FontKey, IdNamespace, ImageKey, NativeFontHandle, PipelineId};
 use {RenderApiSender, ResourceId, ScrollEventPhase, ScrollLayerState, ScrollLocation, ServoScrollRootId};
-use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand};
+use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand, TileSize};
 use {DeviceIntSize, DynamicProperties, LayoutPoint, LayoutSize, WorldPoint, PropertyBindingKey, PropertyBindingId};
+use {BuiltDisplayList, AuxiliaryLists};
 use VRCompositorCommand;
 use ExternalEvent;
 use std::marker::PhantomData;
 
 impl RenderApiSender {
     pub fn new(api_sender: MsgSender<ApiMsg>,
                payload_sender: PayloadSender)
                -> RenderApiSender {
@@ -87,18 +88,19 @@ impl RenderApi {
         let new_id = self.next_unique_id();
         ImageKey::new(new_id.0, new_id.1)
     }
 
     /// Adds an image identified by the `ImageKey`.
     pub fn add_image(&self,
                      key: ImageKey,
                      descriptor: ImageDescriptor,
-                     data: ImageData) {
-        let msg = ApiMsg::AddImage(key, descriptor, data);
+                     data: ImageData,
+                     tiling: Option<TileSize>) {
+        let msg = ApiMsg::AddImage(key, descriptor, data, tiling);
         self.api_sender.send(msg).unwrap();
     }
 
     /// Updates a specific image.
     ///
     /// Currently doesn't support changing dimensions or format by updating.
     // TODO: Support changing dimensions (and format) during image update?
     pub fn update_image(&self,
@@ -151,20 +153,18 @@ impl RenderApi {
     ///                           id, this setting determines if frame state (such as scrolling
     ///                           position) should be preserved for this new display list.
     ///
     /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
     pub fn set_root_display_list(&self,
                                  background_color: Option<ColorF>,
                                  epoch: Epoch,
                                  viewport_size: LayoutSize,
-                                 builder: DisplayListBuilder,
+                                 (pipeline_id, display_list, auxiliary_lists): (PipelineId, BuiltDisplayList, AuxiliaryLists),
                                  preserve_frame_state: bool) {
-        let pipeline_id = builder.pipeline_id;
-        let (display_list, auxiliary_lists) = builder.finalize();
         let msg = ApiMsg::SetRootDisplayList(background_color,
                                              epoch,
                                              pipeline_id,
                                              viewport_size,
                                              display_list.descriptor().clone(),
                                              *auxiliary_lists.descriptor(),
                                              preserve_frame_state);
         self.api_sender.send(msg).unwrap();
--- a/gfx/webrender_traits/src/display_list.rs
+++ b/gfx/webrender_traits/src/display_list.rs
@@ -3,28 +3,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use std::mem;
 use std::slice;
 use {AuxiliaryLists, AuxiliaryListsDescriptor, BorderDisplayItem};
 use {BoxShadowClipMode, BoxShadowDisplayItem, BuiltDisplayList};
 use {BuiltDisplayListDescriptor, ClipRegion, ComplexClipRegion, ColorF};
-use {DisplayItem, DisplayListMode, ExtendMode, FilterOp, YuvColorSpace};
+use {DisplayItem, ExtendMode, FilterOp, YuvColorSpace};
 use {FontKey, GlyphInstance, GradientDisplayItem, RadialGradientDisplayItem, GradientStop, IframeDisplayItem};
 use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, ItemRange, MixBlendMode, PipelineId};
 use {PushScrollLayerItem, PushStackingContextDisplayItem, RectangleDisplayItem, ScrollLayerId};
 use {ScrollPolicy, ServoScrollRootId, SpecificDisplayItem, StackingContext, TextDisplayItem};
 use {WebGLContextId, WebGLDisplayItem, YuvImageDisplayItem};
 use {LayoutTransform, LayoutPoint, LayoutRect, LayoutSize};
 use {BorderDetails, BorderWidths, GlyphOptions, PropertyBinding};
 
 impl BuiltDisplayListDescriptor {
     pub fn size(&self) -> usize {
-        self.display_list_items_size + self.display_items_size
+        self.display_list_items_size
     }
 }
 
 impl BuiltDisplayList {
     pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList {
         BuiltDisplayList {
             data: data,
             descriptor: descriptor,
@@ -43,27 +43,25 @@ impl BuiltDisplayList {
         unsafe {
             convert_blob_to_pod(&self.data[0..self.descriptor.display_list_items_size])
         }
     }
 }
 
 #[derive(Clone)]
 pub struct DisplayListBuilder {
-    pub mode: DisplayListMode,
     pub list: Vec<DisplayItem>,
     auxiliary_lists_builder: AuxiliaryListsBuilder,
     pub pipeline_id: PipelineId,
     next_scroll_layer_id: usize,
 }
 
 impl DisplayListBuilder {
     pub fn new(pipeline_id: PipelineId) -> DisplayListBuilder {
         DisplayListBuilder {
-            mode: DisplayListMode::Default,
             list: Vec::new(),
             auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
             pipeline_id: pipeline_id,
             next_scroll_layer_id: 0,
         }
     }
 
     pub fn print_display_list(&mut self) {
@@ -360,26 +358,25 @@ impl DisplayListBuilder {
     pub fn new_clip_region(&mut self,
                            rect: &LayoutRect,
                            complex: Vec<ComplexClipRegion>,
                            image_mask: Option<ImageMask>)
                            -> ClipRegion {
         ClipRegion::new(rect, complex, image_mask, &mut self.auxiliary_lists_builder)
     }
 
-    pub fn finalize(self) -> (BuiltDisplayList, AuxiliaryLists) {
+    pub fn finalize(self) -> (PipelineId, BuiltDisplayList, AuxiliaryLists) {
         unsafe {
             let blob = convert_pod_to_blob(&self.list).to_vec();
             let display_list_items_size = blob.len();
 
-            (BuiltDisplayList {
+            (self.pipeline_id,
+             BuiltDisplayList {
                  descriptor: BuiltDisplayListDescriptor {
-                     mode: self.mode,
                      display_list_items_size: display_list_items_size,
-                     display_items_size: 0,
                  },
                  data: blob,
              },
              self.auxiliary_lists_builder.finalize())
         }
     }
 }
 
--- a/gfx/webrender_traits/src/types.rs
+++ b/gfx/webrender_traits/src/types.rs
@@ -19,24 +19,26 @@ use std::sync::Arc;
 #[cfg(target_os = "windows")] use dwrote::FontDescriptor;
 
 #[derive(Debug, Copy, Clone)]
 pub enum RendererKind {
     Native,
     OSMesa,
 }
 
+pub type TileSize = u16;
+
 #[derive(Clone, Deserialize, Serialize)]
 pub enum ApiMsg {
     AddRawFont(FontKey, Vec<u8>),
     AddNativeFont(FontKey, NativeFontHandle),
     /// Gets the glyph dimensions
     GetGlyphDimensions(Vec<GlyphKey>, MsgSender<Vec<Option<GlyphDimensions>>>),
     /// Adds an image from the resource cache.
-    AddImage(ImageKey, ImageDescriptor, ImageData),
+    AddImage(ImageKey, ImageDescriptor, ImageData, Option<TileSize>),
     /// Updates the the resource cache with the new image data.
     UpdateImage(ImageKey, ImageDescriptor, Vec<u8>),
     /// Drops an image from the resource cache.
     DeleteImage(ImageKey),
     CloneApi(MsgSender<IdNamespace>),
     /// Supplies a new frame to WebRender.
     ///
     /// After receiving this message, WebRender will read the display list, followed by the
@@ -161,16 +163,17 @@ pub struct AuxiliaryLists {
     data: Vec<u8>,
     descriptor: AuxiliaryListsDescriptor,
 }
 
 /// Describes the memory layout of the auxiliary lists.
 ///
 /// Auxiliary lists consist of some number of gradient stops, complex clip regions, filters, and
 /// glyph instances, in that order.
+#[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
 pub struct AuxiliaryListsDescriptor {
     gradient_stops_size: usize,
     complex_clip_regions_size: usize,
     filters_size: usize,
     glyph_instances_size: usize,
 }
 
@@ -282,24 +285,21 @@ pub struct BuiltDisplayList {
     data: Vec<u8>,
     descriptor: BuiltDisplayListDescriptor,
 }
 
 /// Describes the memory layout of a display list.
 ///
 /// A display list consists of some number of display list items, followed by a number of display
 /// items.
+#[repr(C)]
 #[derive(Copy, Clone, Deserialize, Serialize)]
 pub struct BuiltDisplayListDescriptor {
-    pub mode: DisplayListMode,
-
     /// The size in bytes of the display list items in this display list.
     display_list_items_size: usize,
-    /// The size in bytes of the display items in this display list.
-    display_items_size: usize,
 }
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ColorF {
     pub r: f32,
     pub g: f32,
     pub b: f32,
@@ -358,19 +358,37 @@ impl ColorU {
 }
 
 #[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ImageDescriptor {
     pub format: ImageFormat,
     pub width: u32,
     pub height: u32,
     pub stride: Option<u32>,
+    pub offset: u32,
     pub is_opaque: bool,
 }
 
+impl ImageDescriptor {
+    pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self {
+        ImageDescriptor {
+            width: width,
+            height: height,
+            format: format,
+            stride: None,
+            offset: 0,
+            is_opaque: is_opaque,
+        }
+    }
+
+    pub fn compute_stride(&self) -> u32 {
+        self.stride.unwrap_or(self.width * self.format.bytes_per_pixel().unwrap())
+    }
+}
+
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ImageMask {
     pub image: ImageKey,
     pub rect: LayoutRect,
     pub repeat: bool,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
@@ -390,24 +408,16 @@ pub struct ComplexClipRegion {
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct DisplayItem {
     pub item: SpecificDisplayItem,
     pub rect: LayoutRect,
     pub clip: ClipRegion,
 }
 
-#[repr(u32)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub enum DisplayListMode {
-    Default                 = 0,
-    PseudoFloat             = 1,
-    PseudoPositionedContent = 2,
-}
-
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
 pub struct Epoch(pub u32);
 
 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
 pub enum ExtendMode {
     Clamp,
     Repeat,
--- a/gfx/webrender_traits/src/units.rs
+++ b/gfx/webrender_traits/src/units.rs
@@ -68,16 +68,20 @@ pub type ScrollLayerSize = TypedSize2D<f
 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub struct WorldPixel;
 
 pub type WorldRect = TypedRect<f32, WorldPixel>;
 pub type WorldPoint = TypedPoint2D<f32, WorldPixel>;
 pub type WorldSize = TypedSize2D<f32, WorldPixel>;
 pub type WorldPoint4D = TypedPoint4D<f32, WorldPixel>;
 
+/// Offset in number of tiles.
+#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct Tiles;
+pub type TileOffset = TypedPoint2D<u16, Tiles>;
 
 pub type LayoutTransform = TypedMatrix4D<f32, LayoutPixel, LayoutPixel>;
 pub type LayerTransform = TypedMatrix4D<f32, LayerPixel, LayerPixel>;
 pub type LayerToScrollTransform = TypedMatrix4D<f32, LayerPixel, ScrollLayerPixel>;
 pub type ScrollToLayerTransform = TypedMatrix4D<f32, ScrollLayerPixel, LayerPixel>;
 pub type LayerToWorldTransform = TypedMatrix4D<f32, LayerPixel, WorldPixel>;
 pub type WorldToLayerTransform = TypedMatrix4D<f32, WorldPixel, LayerPixel>;
 pub type ScrollToWorldTransform = TypedMatrix4D<f32, ScrollLayerPixel, WorldPixel>;
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2565,30 +2565,35 @@ GCMarker::sizeOfExcludingThis(mozilla::M
     size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
     for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
         size += zone->gcGrayRoots().sizeOfExcludingThis(mallocSizeOf);
     return size;
 }
 
 #ifdef DEBUG
 Zone*
-GCMarker::stackContainsCrossZonePointerTo(const TenuredCell* target) const
+GCMarker::stackContainsCrossZonePointerTo(const Cell* target) const
 {
     MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
 
+    Zone* targetZone = target->asTenured().zone();
+
     for (MarkStackIter iter(stack); !iter.done(); iter.next()) {
         if (iter.peekTag() != MarkStack::ObjectTag)
             continue;
 
         auto source = iter.peekPtr().as<JSObject>();
-        if (source->is<ProxyObject>() &&
-            source->as<ProxyObject>().target() == static_cast<const Cell*>(target) &&
-            source->zone() != target->zone())
+        Zone* sourceZone = source->zone();
+        if (sourceZone == targetZone)
+            continue;
+
+        if ((source->is<ProxyObject>() && source->as<ProxyObject>().target() == target) ||
+            Debugger::isDebuggerCrossCompartmentEdge(source, target))
         {
-            return source->zone();
+            return sourceZone;
         }
     }
 
     return nullptr;
 }
 #endif // DEBUG
 
 
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -299,17 +299,17 @@ class GCMarker : public JSTracer
     void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
 #ifdef DEBUG
 
     bool shouldCheckCompartments() { return strictCompartmentChecking; }
 
-    Zone* stackContainsCrossZonePointerTo(const gc::TenuredCell* cell) const;
+    Zone* stackContainsCrossZonePointerTo(const gc::Cell* cell) const;
 
 #endif
 
     void markEphemeronValues(gc::Cell* markedCell, gc::WeakEntryVector& entry);
 
     static GCMarker* fromTracer(JSTracer* trc) {
         MOZ_ASSERT(trc->isMarkingTracer());
         return static_cast<GCMarker*>(trc);
--- a/js/src/jit-test/tests/wasm/conversion.js
+++ b/js/src/jit-test/tests/wasm/conversion.js
@@ -84,16 +84,23 @@ function testTrap(resultType, opcode, pa
     testConversion('f32', 'convert_s', 'i64', 0, 0.0);
     testConversion('f32', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f32', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
     testConversion('f32', 'convert_s', 'i64', "0x11db9e76a2483", 314159275180032.0);
     testConversion('f32', 'convert_s', 'i64', "0x7fffffff", 2147483648.0); // closesth approx.
     testConversion('f32', 'convert_s', 'i64', "0x80000000", 2147483648.0);
     testConversion('f32', 'convert_s', 'i64', "0x80000001", 2147483648.0); // closesth approx.
 
+    // Interesting values at the boundaries.
+    testConversion('f32', 'convert_s', 'i64', "0x358a09a000000002", 3857906751034621952);
+    testConversion('f32', 'convert_s', 'i64', "0x8000004000000001", -9223371487098961920);
+    testConversion('f32', 'convert_s', 'i64', "0xffdfffffdfffffff", -9007200328482816);
+    testConversion('f32', 'convert_s', 'i64', "0x0020000020000001", 9007200328482816);
+    testConversion('f32', 'convert_s', 'i64', "0x7fffff4000000001", 9223371487098961920);
+
     testConversion('f64', 'convert_s', 'i64', 1, 1.0);
     testConversion('f64', 'convert_s', 'i64', -1, -1.0);
     testConversion('f64', 'convert_s', 'i64', 0, 0.0);
     testConversion('f64', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f64', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
     testConversion('f64', 'convert_s', 'i64', "0x10969d374b968e", 4669201609102990);
     testConversion('f64', 'convert_s', 'i64', "0x7fffffff", 2147483647.0);
     testConversion('f64', 'convert_s', 'i64', "0x80000000", 2147483648.0);
@@ -101,22 +108,34 @@ function testTrap(resultType, opcode, pa
 
     testConversion('f32', 'convert_u', 'i64', 1, 1.0);
     testConversion('f32', 'convert_u', 'i64', 0, 0.0);
     testConversion('f32', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f32', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
 
+    // Interesting values at the boundaries.
+    testConversion('f32', 'convert_u', 'i64', "0x100404900000008", 72128280609685500);
+    testConversion('f32', 'convert_u', 'i64', "0x7fffff4000000001", 9223371487098962000);
+    testConversion('f32', 'convert_u', 'i64', "0x0020000020000001", 9007200328482816);
+    testConversion('f32', 'convert_u', 'i64', "0x7fffffbfffffffff", 9223371487098961920);
+    testConversion('f32', 'convert_u', 'i64', "0x8000008000000001", 9223373136366403584);
+    testConversion('f32', 'convert_u', 'i64', "0xfffffe8000000001", 18446742974197923840);
+
     testConversion('f64', 'convert_u', 'i64', 1, 1.0);
     testConversion('f64', 'convert_u', 'i64', 0, 0.0);
     testConversion('f64', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f64', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f64', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f64', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462603027743000.0);
+    testConversion('f64', 'convert_u', 'i64', "0xbf869c3369c26401", 13800889852755077000);
+    testConversion('f64', 'convert_u', 'i64', "0x7fffff4000000001", 9223371212221054976);
+    testConversion('f64', 'convert_u', 'i64', "0x8000008000000001", 9223372586610589696);
+    testConversion('f64', 'convert_u', 'i64', "0xfffffe8000000001", 18446742424442109952);
 
     testConversion('i64', 'trunc_s', 'f64', 0.0, 0);
     testConversion('i64', 'trunc_s', 'f64', "-0.0", 0);
     testConversion('i64', 'trunc_s', 'f64', 1.0, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.1, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.5, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.99, 1);
     testConversion('i64', 'trunc_s', 'f64', 40.1, 40);
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -801,16 +801,21 @@ enum ABIFunctionType
     Args_Double_None = ArgType_Double << RetType_Shift,
 
     // int f(double)
     Args_Int_Double = Args_General0 | (ArgType_Double << ArgType_Shift),
 
     // float f(float)
     Args_Float32_Float32 = (ArgType_Float32 << RetType_Shift) | (ArgType_Float32 << ArgType_Shift),
 
+    // float f(int, int)
+    Args_Float32_IntInt = (ArgType_Float32 << RetType_Shift) |
+        (ArgType_General << (ArgType_Shift * 1)) |
+        (ArgType_General << (ArgType_Shift * 2)),
+
     // double f(double)
     Args_Double_Double = Args_Double_None | (ArgType_Double << ArgType_Shift),
 
     // double f(int)
     Args_Double_Int = Args_Double_None | (ArgType_General << ArgType_Shift),
 
     // double f(int, int)
     Args_Double_IntInt = Args_Double_Int | (ArgType_General << (ArgType_Shift * 2)),
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -1552,23 +1552,20 @@ DoCompareFallback(JSContext* cx, void* p
             ICStub* objectStub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));
             if (!objectStub)
                 return false;
 
             stub->addNewStub(objectStub);
             return true;
         }
 
-        if ((lhs.isObject() || lhs.isNull() || lhs.isUndefined()) &&
-            (rhs.isObject() || rhs.isNull() || rhs.isUndefined()) &&
-            !stub->hasStub(ICStub::Compare_ObjectWithUndefined))
-        {
-            JitSpew(JitSpew_BaselineIC, "  Generating %s(Obj/Null/Undef, Obj/Null/Undef) stub",
+        if (lhs.isNullOrUndefined() || rhs.isNullOrUndefined()) {
+            JitSpew(JitSpew_BaselineIC, "  Generating %s(Null/Undef or X, Null/Undef or X) stub",
                     CodeName[op]);
-            bool lhsIsUndefined = lhs.isNull() || lhs.isUndefined();
+            bool lhsIsUndefined = lhs.isNullOrUndefined();
             bool compareWithNull = lhs.isNull() || rhs.isNull();
             ICCompare_ObjectWithUndefined::Compiler compiler(cx, op, engine,
                                                              lhsIsUndefined, compareWithNull);
             ICStub* objectStub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));
             if (!objectStub)
                 return false;
 
             stub->addNewStub(objectStub);
@@ -1805,24 +1802,41 @@ ICCompare_ObjectWithUndefined::Compiler:
         masm.bind(&emulatesUndefined);
         masm.moveValue(BooleanValue(op == JSOP_EQ), R0);
         EmitReturnFromIC(masm);
     }
 
     masm.bind(&notObject);
 
     // Also support null == null or undefined == undefined comparisons.
+    Label differentTypes;
     if (compareWithNull)
-        masm.branchTestNull(Assembler::NotEqual, objectOperand, &failure);
+        masm.branchTestNull(Assembler::NotEqual, objectOperand, &differentTypes);
     else
-        masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &failure);
+        masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &differentTypes);
 
     masm.moveValue(BooleanValue(op == JSOP_STRICTEQ || op == JSOP_EQ), R0);
     EmitReturnFromIC(masm);
 
+    masm.bind(&differentTypes);
+    // Also support null == undefined or undefined == null.
+    Label neverEqual;
+    if (compareWithNull)
+        masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &neverEqual);
+    else
+        masm.branchTestNull(Assembler::NotEqual, objectOperand, &neverEqual);
+
+    masm.moveValue(BooleanValue(op == JSOP_EQ || op == JSOP_STRICTNE), R0);
+    EmitReturnFromIC(masm);
+
+    // null/undefined can only be equal to null/undefined or emulatesUndefined.
+    masm.bind(&neverEqual);
+    masm.moveValue(BooleanValue(op == JSOP_NE || op == JSOP_STRICTNE), R0);
+    EmitReturnFromIC(masm);
+
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 //
 // Compare_Int32WithBoolean
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3021,40 +3021,42 @@ CodeGeneratorARM::visitOutOfLineWasmTrun
                                          ool->isUnsigned(), ool->rejoin(),
                                          ool->trapOffset());
 }
 
 void
 CodeGeneratorARM::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
-    FloatRegister output = ToFloatRegister(lir->output());
 
     MInt64ToFloatingPoint* mir = lir->mir();
     MIRType toType = mir->type();
 
     // We are free to clobber all registers, since this is a call instruction.
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(input.low);
     regs.take(input.high);
     Register temp = regs.takeAny();
 
     masm.setupUnalignedABICall(temp);
     masm.passABIArg(input.high);
     masm.passABIArg(input.low);
-    if (lir->mir()->isUnsigned())
-        masm.callWithABI(wasm::SymbolicAddress::Uint64ToFloatingPoint, MoveOp::DOUBLE);
-    else
-        masm.callWithABI(wasm::SymbolicAddress::Int64ToFloatingPoint, MoveOp::DOUBLE);
-
-    MOZ_ASSERT_IF(toType == MIRType::Double, output == ReturnDoubleReg);
-    if (toType == MIRType::Float32) {
-        MOZ_ASSERT(output == ReturnFloat32Reg);
-        masm.convertDoubleToFloat32(ReturnDoubleReg, output);
-    }
+
+    bool isUnsigned = mir->isUnsigned();
+    wasm::SymbolicAddress callee = toType == MIRType::Float32
+                                   ? (isUnsigned ? wasm::SymbolicAddress::Uint64ToFloat32
+                                                 : wasm::SymbolicAddress::Int64ToFloat32)
+                                   : (isUnsigned ? wasm::SymbolicAddress::Uint64ToDouble
+                                                 : wasm::SymbolicAddress::Int64ToDouble);
+
+    masm.callWithABI(callee, toType == MIRType::Float32 ? MoveOp::FLOAT32 : MoveOp::DOUBLE);
+
+    DebugOnly<FloatRegister> output(ToFloatRegister(lir->output()));
+    MOZ_ASSERT_IF(toType == MIRType::Double, output.value == ReturnDoubleReg);
+    MOZ_ASSERT_IF(toType == MIRType::Float32, output.value == ReturnFloat32Reg);
 }
 
 void
 CodeGeneratorARM::visitCopySignF(LCopySignF* ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->getOperand(0));
     FloatRegister rhs = ToFloatRegister(ins->getOperand(1));
     FloatRegister output = ToFloatRegister(ins->getDef(0));
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -2433,16 +2433,17 @@ typedef double (*Prototype_Double_Double
 typedef double (*Prototype_Double_Int)(int32_t arg0);
 typedef double (*Prototype_Double_IntInt)(int32_t arg0, int32_t arg1);
 typedef int32_t (*Prototype_Int_Double)(double arg0);
 typedef int64_t (*Prototype_Int64_Double)(double arg0);
 typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
 typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
                                                  int32_t arg3);
 typedef float (*Prototype_Float32_Float32)(float arg0);
+typedef float (*Prototype_Float32_IntInt)(int arg0, int arg1);
 
 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
 
 typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
 typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
@@ -2620,16 +2621,23 @@ Simulator::softwareInterrupt(SimInstruct
             else
                 fval0 = mozilla::BitwiseCast<float>(arg0);
             Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
             float fresult = target(fval0);
             scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultFloat(fresult);
             break;
           }
+          case Args_Float32_IntInt: {
+            Prototype_Float32_IntInt target = reinterpret_cast<Prototype_Float32_IntInt>(external);
+            float fresult = target(arg0, arg1);
+            scratchVolatileRegisters(/* scratchFloat = true */);
+            setCallResultFloat(fresult);
+            break;
+          }
           case Args_Double_Int: {
             Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
             double dresult = target(arg0);
             scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Double_IntInt: {
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -734,27 +734,31 @@ CodeGeneratorX64::visitWasmTruncateToInt
 }
 
 void
 CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     FloatRegister output = ToFloatRegister(lir->output());
 
-    MIRType outputType = lir->mir()->type();
+    MInt64ToFloatingPoint* mir = lir->mir();
+    bool isUnsigned = mir->isUnsigned();
+
+    MIRType outputType = mir->type();
     MOZ_ASSERT(outputType == MIRType::Double || outputType == MIRType::Float32);
+    MOZ_ASSERT(isUnsigned == !lir->getTemp(0)->isBogusTemp());
 
     if (outputType == MIRType::Double) {
-        if (lir->mir()->isUnsigned())
-            masm.convertUInt64ToDouble(input, output, Register::Invalid());
+        if (isUnsigned)
+            masm.convertUInt64ToDouble(input, output, ToRegister(lir->getTemp(0)));
         else
             masm.convertInt64ToDouble(input, output);
     } else {
-        if (lir->mir()->isUnsigned())
-            masm.convertUInt64ToFloat32(input, output, Register::Invalid());
+        if (isUnsigned)
+            masm.convertUInt64ToFloat32(input, output, ToRegister(lir->getTemp(0)));
         else
             masm.convertInt64ToFloat32(input, output);
     }
 }
 
 void
 CodeGeneratorX64::visitNotI64(LNotI64* lir)
 {
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -480,16 +480,17 @@ LIRGeneratorX64::visitWasmTruncateToInt6
 
 void
 LIRGeneratorX64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
-    define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), LDefinition::BogusTemp()), ins);
+    LDefinition maybeTemp = ins->isUnsigned() ? temp() : LDefinition::BogusTemp();
+    define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
 LIRGeneratorX64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     defineInt64(new(alloc()) LExtendInt32ToInt64(useAtStart(ins->input())), ins);
 }
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -88,71 +88,75 @@ MacroAssemblerX64::convertInt64ToFloat32
     zeroFloat32(output);
 
     vcvtsq2ss(input.reg, output, output);
 }
 
 bool
 MacroAssemblerX64::convertUInt64ToDoubleNeedsTemp()
 {
-    return false;
+    return true;
 }
 
 void
 MacroAssemblerX64::convertUInt64ToDouble(Register64 input, FloatRegister output, Register temp)
 {
-    MOZ_ASSERT(temp == Register::Invalid());
-
     // Zero the output register to break dependencies, see convertInt32ToDouble.
     zeroDouble(output);
 
     // If the input's sign bit is not set we use vcvtsq2sd directly.
-    // Else, we divide by 2, convert to double, and multiply the result by 2.
+    // Else, we divide by 2 and keep the LSB, convert to double, and multiply
+    // the result by 2.
     Label done;
     Label isSigned;
 
     testq(input.reg, input.reg);
     j(Assembler::Signed, &isSigned);
     vcvtsq2sd(input.reg, output, output);
     jump(&done);
 
     bind(&isSigned);
 
     ScratchRegisterScope scratch(asMasm());
     mov(input.reg, scratch);
+    mov(input.reg, temp);
     shrq(Imm32(1), scratch);
+    andq(Imm32(1), temp);
+    orq(temp, scratch);
+
     vcvtsq2sd(scratch, output, output);
     vaddsd(output, output, output);
 
     bind(&done);
 }
 
 void
 MacroAssemblerX64::convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp)
 {
-    MOZ_ASSERT(temp == Register::Invalid());
-
     // Zero the output register to break dependencies, see convertInt32ToDouble.
     zeroFloat32(output);
 
-    // If the input's sign bit is not set we use vcvtsq2ss directly.
-    // Else, we divide by 2, convert to float, and multiply the result by 2.
+    // See comment in convertUInt64ToDouble.
     Label done;
     Label isSigned;
 
     testq(input.reg, input.reg);
     j(Assembler::Signed, &isSigned);
     vcvtsq2ss(input.reg, output, output);
     jump(&done);
 
     bind(&isSigned);
 
     ScratchRegisterScope scratch(asMasm());
     mov(input.reg, scratch);
+    mov(input.reg, temp);
     shrq(Imm32(1), scratch);
+    andq(Imm32(1), temp);
+    orq(temp, scratch);
+
     vcvtsq2ss(scratch, output, output);
     vaddss(output, output, output);
 
     bind(&done);
 }
 
 void
 MacroAssemblerX64::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -633,18 +633,21 @@ LIRGeneratorX86::visitWasmTruncateToInt6
 
 void
 LIRGeneratorX86::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
-    LDefinition maybeTemp =
-        (ins->isUnsigned() && AssemblerX86Shared::HasSSE3()) ? temp() : LDefinition::BogusTemp();
+    LDefinition maybeTemp = (ins->isUnsigned() &&
+                             ((ins->type() == MIRType::Double && AssemblerX86Shared::HasSSE3()) ||
+                              ins->type() == MIRType::Float32))
+                            ? temp()
+                            : LDefinition::BogusTemp();
 
     define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
 LIRGeneratorX86::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     if (ins->isUnsigned()) {
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -57,17 +57,17 @@ MacroAssemblerX86::convertUInt64ToDouble
         double add_constant = 18446744073709551616.0; // 2^64
         store64(Imm64(mozilla::BitwiseCast<uint64_t>(add_constant)), Address(esp, 0));
         fld(Operand(esp, 0));
         faddp();
         bind(&notNegative);
 
         fstp(Operand(esp, 0));
         vmovsd(Address(esp, 0), dest);
-        asMasm().freeStack(2*sizeof(intptr_t));
+        asMasm().freeStack(2 * sizeof(intptr_t));
         return;
     }
 
     // Following operation uses entire 128-bit of dest XMM register.
     // Currently higher 64-bit is free when we have access to lower 64-bit.
     MOZ_ASSERT(dest.size() == 8);
     FloatRegister dest128 = FloatRegister(dest.encoding(), FloatRegisters::Simd128);
 
@@ -898,31 +898,69 @@ MacroAssemblerX86::convertInt64ToDouble(
     zeroDouble(output);
 
     asMasm().Push(input.high);
     asMasm().Push(input.low);
     fild(Operand(esp, 0));
 
     fstp(Operand(esp, 0));
     vmovsd(Address(esp, 0), output);
-    asMasm().freeStack(2*sizeof(intptr_t));
+    asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::convertInt64ToFloat32(Register64 input, FloatRegister output)
 {
-    convertInt64ToDouble(input, output);
-    convertDoubleToFloat32(output, output);
+    // Zero the output register to break dependencies, see convertInt32ToDouble.
+    zeroDouble(output);
+
+    asMasm().Push(input.high);
+    asMasm().Push(input.low);
+    fild(Operand(esp, 0));
+
+    fstp32(Operand(esp, 0));
+    vmovss(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp)
 {
-    convertUInt64ToDouble(input, output.asDouble(), temp);
-    convertDoubleToFloat32(output, output);
+    // Zero the dest register to break dependencies, see convertInt32ToDouble.
+    zeroDouble(output);
+
+    // Set the FPU precision to 80 bits.
+    asMasm().reserveStack(2 * sizeof(intptr_t));
+    fnstcw(Operand(esp, 0));
+    load32(Operand(esp, 0), temp);
+    orl(Imm32(0x300), temp);
+    store32(temp, Operand(esp, sizeof(intptr_t)));
+    fldcw(Operand(esp, sizeof(intptr_t)));
+
+    asMasm().Push(input.high);
+    asMasm().Push(input.low);
+    fild(Operand(esp, 0));
+
+    Label notNegative;
+    asMasm().branch32(Assembler::NotSigned, input.high, Imm32(0), &notNegative);
+    double add_constant = 18446744073709551616.0; // 2^64
+    uint64_t add_constant_u64 = mozilla::BitwiseCast<uint64_t>(add_constant);
+    store64(Imm64(add_constant_u64), Address(esp, 0));
+
+    fld(Operand(esp, 0));
+    faddp();
+    bind(&notNegative);
+
+    fstp32(Operand(esp, 0));
+    vmovss(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(intptr_t));
+
+    // Restore FPU precision to the initial value.
+    fldcw(Operand(esp, 0));
+    asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                              Label* oolRejoin, FloatRegister tempReg)
 {
     Label fail, convert;
     Register temp = output.high;
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -63,17 +63,17 @@ class CompartmentChecker
     }
 
     void checkZone(JS::Zone* z) {
         if (compartment && z != compartment->zone())
             fail(compartment->zone(), z);
     }
 
     void check(JSObject* obj) {
-        MOZ_ASSERT_IF(obj, IsInsideNursery(obj) || !obj->asTenured().isMarked(gc::GRAY));
+        MOZ_ASSERT(JS::ObjectIsNotGray(obj));
         if (obj)
             check(obj->compartment());
     }
 
     template<typename T>
     void check(const Rooted<T>& rooted) {
         check(rooted.get());
     }
@@ -95,17 +95,17 @@ class CompartmentChecker
         if (compartment) {
             JSRuntime* rt = compartment->runtimeFromAnyThread();
             MOZ_ASSERT(rt->gc.atomMarking.atomIsMarked(compartment->zone(), cell));
         }
 #endif
     }
 
     void check(JSString* str) {
-        MOZ_ASSERT(!str->isMarked(gc::GRAY));
+        MOZ_ASSERT(JS::CellIsNotGray(str));
         if (str->isAtom()) {
             checkAtom(str);
         } else {
             checkZone(str->zone());
         }
     }
 
     void check(JS::Symbol* symbol) {
@@ -156,17 +156,17 @@ class CompartmentChecker
     }
 
     void check(jsid id) {
         if (JSID_IS_GCTHING(id))
             checkAtom(JSID_TO_GCTHING(id).asCell());
     }
 
     void check(JSScript* script) {
-        MOZ_ASSERT_IF(script, !script->isMarked(gc::GRAY));
+        MOZ_ASSERT(JS::CellIsNotGray(script));
         if (script)
             check(script->compartment());
     }
 
     void check(InterpreterFrame* fp);
     void check(AbstractFramePtr frame);
     void check(SavedStacks* stacks);
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -11705,16 +11705,38 @@ JS::dbg::GetDebuggeeGlobals(JSContext* c
     }
 
     for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront())
         vector.infallibleAppend(static_cast<JSObject*>(r.front()));
 
     return true;
 }
 
+#ifdef DEBUG
+/* static */ bool
+Debugger::isDebuggerCrossCompartmentEdge(JSObject* obj, const gc::Cell* target)
+{
+    MOZ_ASSERT(target);
+
+    auto cls = obj->getClass();
+    const gc::Cell* referent = nullptr;
+    if (cls == &DebuggerScript_class) {
+        referent = GetScriptReferentCell(obj);
+    } else if (cls == &DebuggerSource_class) {
+        referent = GetSourceReferentRawObject(obj);
+    } else if (obj->is<DebuggerObject>()) {
+        referent = static_cast<gc::Cell*>(obj->as<DebuggerObject>().getPrivate());
+    } else if (obj->is<DebuggerEnvironment>()) {
+        referent = static_cast<gc::Cell*>(obj->as<DebuggerEnvironment>().getPrivate());
+    }
+
+    return referent == target;
+}
+#endif
+
 
 /*** JS::dbg::GarbageCollectionEvent **************************************************************/
 
 namespace JS {
 namespace dbg {
 
 /* static */ GarbageCollectionEvent::Ptr
 GarbageCollectionEvent::Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t gcNumber)
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -831,16 +831,19 @@ class Debugger : private mozilla::Linked
      * returns true. If not, it returns false.
      */
     static void traceIncomingCrossCompartmentEdges(JSTracer* tracer);
     static MOZ_MUST_USE bool markIteratively(GCMarker* marker);
     static void traceAllForMovingGC(JSTracer* trc);
     static void sweepAll(FreeOp* fop);
     static void detachAllDebuggersFromGlobal(FreeOp* fop, GlobalObject* global);
     static void findZoneEdges(JS::Zone* v, gc::ZoneComponentFinder& finder);
+#ifdef DEBUG
+    static bool isDebuggerCrossCompartmentEdge(JSObject* obj, const js::gc::Cell* cell);
+#endif
 
     // Checks it the current compartment is allowed to execute code.
     static inline MOZ_MUST_USE bool checkNoExecute(JSContext* cx, HandleScript script);
 
     /*
      * JSTrapStatus Overview
      * ---------------------
      *
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -3225,21 +3225,23 @@ class BaseCompiler
 # else
         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI64");
 # endif
         return true;
     }
 #endif // FLOAT_TO_I64_CALLOUT
 
 #ifndef I64_TO_FLOAT_CALLOUT
-    bool convertI64ToFloatNeedsTemp(bool isUnsigned) const {
+    bool convertI64ToFloatNeedsTemp(ValType to, bool isUnsigned) const {
 # if defined(JS_CODEGEN_X86)
-        return isUnsigned && AssemblerX86Shared::HasSSE3();
+        return isUnsigned &&
+               ((to == ValType::F64 && AssemblerX86Shared::HasSSE3()) ||
+               to == ValType::F32);
 # else
-        return false;
+        return isUnsigned;
 # endif
     }
 
     void convertI64ToF32(RegI64 src, bool isUnsigned, RegF32 dest, RegI32 temp) {
 # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         if (isUnsigned)
             masm.convertUInt64ToFloat32(src, dest, temp);
         else
@@ -5019,17 +5021,17 @@ BaseCompiler::emitConvertI64ToF32()
 }
 
 void
 BaseCompiler::emitConvertU64ToF32()
 {
     RegI64 r0 = popI64();
     RegF32 f0 = needF32();
     RegI32 temp;
-    if (convertI64ToFloatNeedsTemp(IsUnsigned(true)))
+    if (convertI64ToFloatNeedsTemp(ValType::F32, IsUnsigned(true)))
         temp = needI32();
     convertI64ToF32(r0, IsUnsigned(true), f0, temp);
     if (temp != Register::Invalid())
         freeI32(temp);
     freeI64(r0);
     pushF32(f0);
 }
 #endif
@@ -5076,17 +5078,17 @@ BaseCompiler::emitConvertI64ToF64()
 }
 
 void
 BaseCompiler::emitConvertU64ToF64()
 {
     RegI64 r0 = popI64();
     RegF64 d0 = needF64();
     RegI32 temp;
-    if (convertI64ToFloatNeedsTemp(IsUnsigned(true)))
+    if (convertI64ToFloatNeedsTemp(ValType::F64, IsUnsigned(true)))
         temp = needI32();
     convertI64ToF64(r0, IsUnsigned(true), d0, temp);
     if (temp != Register::Invalid())
         freeI32(temp);
     freeI64(r0);
     pushF64(d0);
 }
 #endif // I64_TO_FLOAT_CALLOUT
@@ -5966,31 +5968,25 @@ BaseCompiler::emitConvertInt64ToFloating
 
     masm.setupUnalignedABICall(temp);
 # ifdef JS_NUNBOX32
     masm.passABIArg(input.high);
     masm.passABIArg(input.low);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitConvertInt64ToFloatingCallout");
 # endif
-    masm.callWithABI(callee, MoveOp::DOUBLE);
+    masm.callWithABI(callee, resultType == ValType::F32 ? MoveOp::FLOAT32 : MoveOp::DOUBLE);
 
     freeI32(temp);
     freeI64(input);
 
-    RegF64 rv = captureReturnedF64(call);
-
-    if (resultType == ValType::F32) {
-        RegF32 rv2 = needF32();
-        masm.convertDoubleToFloat32(rv, rv2);
-        freeF64(rv);
-        pushF32(rv2);
-    } else {
-        pushF64(rv);
-    }
+    if (resultType == ValType::F32)
+        pushF32(captureReturnedF32(call));
+    else
+        pushF64(captureReturnedF64(call));
 
     return true;
 }
 #endif // I64_TO_FLOAT_CALLOUT
 
 #ifdef FLOAT_TO_I64_CALLOUT
 // `Callee` always takes a double, so a float32 input must be converted.
 bool
@@ -7115,25 +7111,25 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitConversion(emitConvertF64ToF32, ValType::F64, ValType::F32));
           case uint16_t(Op::F32ConvertSI32):
             CHECK_NEXT(emitConversion(emitConvertI32ToF32, ValType::I32, ValType::F32));
           case uint16_t(Op::F32ConvertUI32):
             CHECK_NEXT(emitConversion(emitConvertU32ToF32, ValType::I32, ValType::F32));
           case uint16_t(Op::F32ConvertSI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Int64ToFloatingPoint,
+                                                SymbolicAddress::Int64ToFloat32,
                                                 ValType::I64, ValType::F32));
 #else
             CHECK_NEXT(emitConversion(emitConvertI64ToF32, ValType::I64, ValType::F32));
 #endif
           case uint16_t(Op::F32ConvertUI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Uint64ToFloatingPoint,
+                                                SymbolicAddress::Uint64ToFloat32,
                                                 ValType::I64, ValType::F32));
 #else
             CHECK_NEXT(emitConversion(emitConvertU64ToF32, ValType::I64, ValType::F32));
 #endif
           case uint16_t(Op::F32ReinterpretI32):
             CHECK_NEXT(emitConversion(emitReinterpretI32AsF32, ValType::I32, ValType::F32));
           case uint16_t(Op::F32Load):
             CHECK_NEXT(emitLoad(ValType::F32, Scalar::Float32));
@@ -7180,25 +7176,25 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitConversion(emitConvertF32ToF64, ValType::F32, ValType::F64));
           case uint16_t(Op::F64ConvertSI32):
             CHECK_NEXT(emitConversion(emitConvertI32ToF64, ValType::I32, ValType::F64));
           case uint16_t(Op::F64ConvertUI32):
             CHECK_NEXT(emitConversion(emitConvertU32ToF64, ValType::I32, ValType::F64));
           case uint16_t(Op::F64ConvertSI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Int64ToFloatingPoint,
+                                                SymbolicAddress::Int64ToDouble,
                                                 ValType::I64, ValType::F64));
 #else
             CHECK_NEXT(emitConversion(emitConvertI64ToF64, ValType::I64, ValType::F64));
 #endif
           case uint16_t(Op::F64ConvertUI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Uint64ToFloatingPoint,
+                                                SymbolicAddress::Uint64ToDouble,
                                                 ValType::I64, ValType::F64));
 #else
             CHECK_NEXT(emitConversion(emitConvertU64ToF64, ValType::I64, ValType::F64));
 #endif
           case uint16_t(Op::F64Load):
             CHECK_NEXT(emitLoad(ValType::F64, Scalar::Float64));
           case uint16_t(Op::F64Store):
             CHECK_NEXT(emitStore(ValType::F64, Scalar::Float64));
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -338,29 +338,43 @@ TruncateDoubleToUint64(double input)
     // Note: UINT64_MAX is not representable in double. It is actually UINT64_MAX + 1.
     // Therefore also sending the failure value.
     if (input >= double(UINT64_MAX) || input <= -1.0 || IsNaN(input))
         return 0x8000000000000000;
     return uint64_t(input);
 }
 
 static double
-Int64ToFloatingPoint(int32_t x_hi, uint32_t x_lo)
+Int64ToDouble(int32_t x_hi, uint32_t x_lo)
 {
     int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
     return double(x);
 }
 
+static float
+Int64ToFloat32(int32_t x_hi, uint32_t x_lo)
+{
+    int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
+    return float(x);
+}
+
 static double
-Uint64ToFloatingPoint(int32_t x_hi, uint32_t x_lo)
+Uint64ToDouble(int32_t x_hi, uint32_t x_lo)
 {
     uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
     return double(x);
 }
 
+static float
+Uint64ToFloat32(int32_t x_hi, uint32_t x_lo)
+{
+    uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
+    return float(x);
+}
+
 template <class F>
 static inline void*
 FuncCast(F* pf, ABIFunctionType type)
 {
     void *pv = JS_FUNC_TO_DATA_PTR(void*, pf);
 #ifdef JS_SIMULATOR
     pv = Simulator::RedirectNativeFunction(pv, type);
 #endif
@@ -408,20 +422,24 @@ wasm::AddressOf(SymbolicAddress imm, JSC
       case SymbolicAddress::ModI64:
         return FuncCast(ModI64, Args_General4);
       case SymbolicAddress::UModI64:
         return FuncCast(UModI64, Args_General4);
       case SymbolicAddress::TruncateDoubleToUint64:
         return FuncCast(TruncateDoubleToUint64, Args_Int64_Double);
       case SymbolicAddress::TruncateDoubleToInt64:
         return FuncCast(TruncateDoubleToInt64, Args_Int64_Double);
-      case SymbolicAddress::Uint64ToFloatingPoint:
-        return FuncCast(Uint64ToFloatingPoint, Args_Double_IntInt);
-      case SymbolicAddress::Int64ToFloatingPoint:
-        return FuncCast(Int64ToFloatingPoint, Args_Double_IntInt);
+      case SymbolicAddress::Uint64ToDouble:
+        return FuncCast(Uint64ToDouble, Args_Double_IntInt);
+      case SymbolicAddress::Uint64ToFloat32:
+        return FuncCast(Uint64ToFloat32, Args_Float32_IntInt);
+      case SymbolicAddress::Int64ToDouble:
+        return FuncCast(Int64ToDouble, Args_Double_IntInt);
+      case SymbolicAddress::Int64ToFloat32:
+        return FuncCast(Int64ToFloat32, Args_Float32_IntInt);
 #if defined(JS_CODEGEN_ARM)
       case SymbolicAddress::aeabi_idivmod:
         return FuncCast(__aeabi_idivmod, Args_General2);
       case SymbolicAddress::aeabi_uidivmod:
         return FuncCast(__aeabi_uidivmod, Args_General2);
       case SymbolicAddress::AtomicCmpXchg:
         return FuncCast(atomics_cmpxchg_asm_callout, Args_General5);
       case SymbolicAddress::AtomicXchg:
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1030,18 +1030,20 @@ enum class SymbolicAddress
     CoerceInPlace_ToInt32,
     CoerceInPlace_ToNumber,
     DivI64,
     UDivI64,
     ModI64,
     UModI64,
     TruncateDoubleToInt64,
     TruncateDoubleToUint64,
-    Uint64ToFloatingPoint,
-    Int64ToFloatingPoint,
+    Uint64ToFloat32,
+    Uint64ToDouble,
+    Int64ToFloat32,
+    Int64ToDouble,
     GrowMemory,
     CurrentMemory,
     Limit
 };
 
 void*
 AddressOf(SymbolicAddress imm, JSContext* cx);
 
--- a/layout/forms/test/test_bug536567_perwindowpb.html
+++ b/layout/forms/test/test_bug536567_perwindowpb.html
@@ -111,17 +111,17 @@ function runTest() {
     runTest();
   } else if (test == "clear history") {
     Services.obs.notifyObservers(null, "browser:purge-session-history", "");
     testIndex++;
     runTest();
   } else {
     var file = dirs[test[2]].clone();
     file.append("file.file");
-    MockFilePicker.returnFiles = [file];
+    MockFilePicker.setFiles([file]);
     content.setAttribute('src', domains[test[0]] + '/chrome/layout/forms/test/bug536567_subframe.html');
   }
 }
 
 function endTest() {
   for(var i = 0; i < dirs.length - 1; i++) {
     dirs[i].remove(true);
   }
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -31,16 +31,17 @@
 #include "nsBidiUtils.h"
 #include "CounterStyleManager.h"
 
 #include "imgIContainer.h"
 #include "ImageLayers.h"
 #include "imgRequestProxy.h"
 #include "nsIURI.h"
 #include "SVGImageContext.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
 
 #include <algorithm>
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 using namespace mozilla;
@@ -223,16 +224,17 @@ public:
     , mListStyleType(listStyleType)
   {
     MOZ_ASSERT(IsTextType());
   }
 
   void
   CreateWebRenderCommands(nsDisplayItem* aItem,
                           nsTArray<layers::WebRenderCommand>& aCommands,
+                          nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                           layers::WebRenderDisplayItemLayer* aLayer);
 
   DrawResult
   Paint(nsRenderingContext& aRenderingContext, nsPoint aPt,
         const nsRect& aDirtyRect, uint32_t aFlags,
         bool aDisableSubpixelAA, nsIFrame* aFrame);
 
   bool
@@ -269,16 +271,17 @@ public:
 
   bool
   IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags);
 
 private:
   void
   CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                   nsTArray<layers::WebRenderCommand>& aCommands,
+                                  nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                   layers::WebRenderDisplayItemLayer* aLayer);
 
   void
   CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                  nsTArray<layers::WebRenderCommand>& aCommands,
                                  layers::WebRenderDisplayItemLayer* aLayer);
 
   void
@@ -310,20 +313,21 @@ private:
 
   // Store the type of list-style-type.
   int32_t mListStyleType;
 };
 
 void
 BulletRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
                                         nsTArray<layers::WebRenderCommand>& aCommands,
+                                        nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                         layers::WebRenderDisplayItemLayer* aLayer)
 {
   if (IsImageType()) {
-    CreateWebRenderCommandsForImage(aItem, aCommands, aLayer);
+    CreateWebRenderCommandsForImage(aItem, aCommands, aParentCommands, aLayer);
   } else if (IsPathType()) {
     CreateWebRenderCommandsForPath(aItem, aCommands, aLayer);
   } else {
     MOZ_ASSERT(IsTextType());
     CreateWebRenderCommandsForText(aItem, aCommands, aLayer);
   }
 }
 
@@ -427,16 +431,17 @@ BulletRenderer::IsImageContainerAvailabl
   MOZ_ASSERT(IsImageType());
 
   return mImage->IsImageContainerAvailable(aManager, aFlags);
 }
 
 void
 BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                                 nsTArray<layers::WebRenderCommand>& aCommands,
+                                                nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                 layers::WebRenderDisplayItemLayer* aLayer)
 {
   MOZ_ASSERT(IsImageType());
 
   if (!mImage) {
      return;
   }
 
@@ -455,23 +460,30 @@ BulletRenderer::CreateWebRenderCommandsF
   uint64_t externalImageId = layer->SendImageContainer(container);
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   Rect destRect =
     NSRectToRect(mDest, appUnitsPerDevPixel);
   Rect destRectTransformed = aLayer->RelativeToParent(destRect);
   IntRect dest = RoundedToInt(destRectTransformed);
 
-  aCommands.AppendElement(layers::OpDPPushExternalImageId(
-                            LayerIntRegion(),
+  WrImageKey key;
+  key.mNamespace = layer->WrBridge()->GetNamespace();
+  key.mHandle = layer->WrBridge()->GetNextResourceId();
+  aParentCommands.AppendElement(layers::OpAddExternalImage(
+                                externalImageId,
+                                key));
+  aCommands.AppendElement(layers::OpDPPushImage(
                             wr::ToWrRect(dest),
                             wr::ToWrRect(dest),
                             Nothing(),
                             WrImageRendering::Auto,
-                            externalImageId));
+                            key));
+
+
 }
 
 void
 BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                                nsTArray<layers::WebRenderCommand>& aCommands,
                                                layers::WebRenderDisplayItemLayer* aLayer)
 {
   MOZ_ASSERT(IsPathType());
@@ -491,17 +503,17 @@ BulletRenderer::CreateWebRenderCommandsF
   layers::WebRenderDisplayItemLayer* layer = static_cast<layers::WebRenderDisplayItemLayer*>(aLayer);
   nsDisplayListBuilder* builder = layer->GetDisplayListBuilder();
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   bool dummy;
   Rect destRect =
     NSRectToRect(aItem->GetBounds(builder, &dummy), appUnitsPerDevPixel);
   Rect destRectTransformed = aLayer->RelativeToParent(destRect);
 
-  mGlyphHelper.BuildWebRenderCommands(aCommands, mGlyphs, mFont, aLayer->GetOffsetToParent(),
+  mGlyphHelper.BuildWebRenderCommands(layer->WrBridge(), aCommands, mGlyphs, mFont, aLayer->GetOffsetToParent(),
                                       destRectTransformed, destRectTransformed);
 }
 
 class nsDisplayBullet final : public nsDisplayItem {
 public:
   nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
     , mDisableSubpixelAA(false)
@@ -525,16 +537,17 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aParameters) override;
 
   virtual void CreateWebRenderCommands(nsTArray<layers::WebRenderCommand>& aCommands,
+                                       nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                        layers::WebRenderDisplayItemLayer* aLayer) override;
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) override {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
@@ -638,22 +651,23 @@ nsDisplayBullet::BuildLayer(nsDisplayLis
     return nullptr;
   }
 
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 void
 nsDisplayBullet::CreateWebRenderCommands(nsTArray<layers::WebRenderCommand>& aCommands,
+                                         nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                          layers::WebRenderDisplayItemLayer* aLayer)
 {
   if (!mBulletRenderer)
     return;
 
-  mBulletRenderer->CreateWebRenderCommands(this, aCommands, aLayer);
+  mBulletRenderer->CreateWebRenderCommands(this, aCommands, aParentCommands, aLayer);
 }
 
 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
                             nsRenderingContext* aCtx)
 {
   uint32_t flags = imgIContainer::FLAG_NONE;
   if (aBuilder->ShouldSyncDecodeImages()) {
     flags |= imgIContainer::FLAG_SYNC_DECODE;
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1436,16 +1436,35 @@ nsCSSRendering::GetShadowRect(const nsRe
   Sides skipSides = aForFrame->GetSkipSides();
   frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
 
   // Explicitly do not need to account for the spread radius here
   // Webrender does it for us or PaintBoxShadow will for non-WR
   return frameRect;
 }
 
+bool
+nsCSSRendering::GetBorderRadii(const nsRect& aFrameRect,
+                               const nsRect& aBorderRect,
+                               nsIFrame* aFrame,
+                               RectCornerRadii& aOutRadii)
+{
+  const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
+  nscoord twipsRadii[8];
+  NS_ASSERTION(aBorderRect.Size() == aFrame->VisualBorderRectRelativeToSelf().Size(),
+              "unexpected size");
+  nsSize sz = aFrameRect.Size();
+  bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
+  if (hasBorderRadius) {
+    ComputePixelRadii(twipsRadii, twipsPerPixel, &aOutRadii);
+  }
+
+  return hasBorderRadius;
+}
+
 void
 nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
                                     nsRenderingContext& aRenderingContext,
                                     nsIFrame* aForFrame,
                                     const nsRect& aFrameArea,
                                     const nsRect& aDirtyRect,
                                     float aOpacity)
 {
@@ -1654,83 +1673,121 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
                                       aDirtyRect,
                                       skipGfxRect);
       renderContext->Restore();
     }
 
   }
 }
 
+nsRect
+nsCSSRendering::GetBoxShadowInnerPaddingRect(nsIFrame* aFrame,
+                                             const nsRect& aFrameArea)
+{
+  Sides skipSides = aFrame->GetSkipSides();
+  nsRect frameRect =
+    ::BoxDecorationRectForBorder(aFrame, aFrameArea, skipSides);
+
+  nsRect paddingRect = frameRect;
+  nsMargin border = aFrame->GetUsedBorder();
+  paddingRect.Deflate(border);
+  return paddingRect;
+}
+
+bool
+nsCSSRendering::CanPaintBoxShadowInner(nsIFrame* aFrame)
+{
+  nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
+  if (!shadows)
+    return false;
+
+  if (aFrame->IsThemed() && aFrame->GetContent() &&
+      !nsContentUtils::IsChromeDoc(aFrame->GetContent()->GetUncomposedDoc())) {
+    // There's no way of getting hold of a shape corresponding to a
+    // "padding-box" for native-themed widgets, so just don't draw
+    // inner box-shadows for them. But we allow chrome to paint inner
+    // box shadows since chrome can be aware of the platform theme.
+    return false;
+  }
+
+  return true;
+}
+
+bool
+nsCSSRendering::GetShadowInnerRadii(nsIFrame* aFrame,
+                                    const nsRect& aFrameArea,
+                                    RectCornerRadii& aOutInnerRadii)
+{
+  // Get any border radius, since box-shadow must also have rounded corners
+  // if the frame does.
+  nscoord twipsRadii[8];
+  nsRect frameRect =
+    ::BoxDecorationRectForBorder(aFrame, aFrameArea, aFrame->GetSkipSides());
+  nsSize sz = frameRect.Size();
+  nsMargin border = aFrame->GetUsedBorder();
+  bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
+  const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
+
+  RectCornerRadii borderRadii;
+
+  hasBorderRadius = GetBorderRadii(frameRect, aFrameArea, aFrame, borderRadii);
+  if (hasBorderRadius) {
+    ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
+
+    Float borderSizes[4] = {
+      Float(border.top / twipsPerPixel),
+      Float(border.right / twipsPerPixel),
+      Float(border.bottom / twipsPerPixel),
+      Float(border.left / twipsPerPixel)
+    };
+    nsCSSBorderRenderer::ComputeInnerRadii(borderRadii,
+                                           borderSizes,
+                                           &aOutInnerRadii);
+  }
+
+  return hasBorderRadius;
+}
+
 void
 nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
                                     nsRenderingContext& aRenderingContext,
                                     nsIFrame* aForFrame,
                                     const nsRect& aFrameArea)
 {
-  nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
-  if (!shadows)
+  if (!CanPaintBoxShadowInner(aForFrame)) {
     return;
-  if (aForFrame->IsThemed() && aForFrame->GetContent() &&
-      !nsContentUtils::IsChromeDoc(aForFrame->GetContent()->GetUncomposedDoc())) {
-    // There's no way of getting hold of a shape corresponding to a
-    // "padding-box" for native-themed widgets, so just don't draw
-    // inner box-shadows for them. But we allow chrome to paint inner
-    // box shadows since chrome can be aware of the platform theme.
-    return;
-  }
-
+  }
+
+  nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
   NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
                aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
 
-  Sides skipSides = aForFrame->GetSkipSides();
-  nsRect frameRect =
-    ::BoxDecorationRectForBorder(aForFrame, aFrameArea, skipSides);
-  nsRect paddingRect = frameRect;
-  nsMargin border = aForFrame->GetUsedBorder();
-  paddingRect.Deflate(border);
-
-  // Get any border radius, since box-shadow must also have rounded corners
-  // if the frame does.
-  nscoord twipsRadii[8];
-  nsSize sz = frameRect.Size();
-  bool hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
-  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  nsRect paddingRect = GetBoxShadowInnerPaddingRect(aForFrame, aFrameArea);
 
   RectCornerRadii innerRadii;
-  if (hasBorderRadius) {
-    RectCornerRadii borderRadii;
-
-    ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
-    Float borderSizes[4] = {
-      Float(border.top / twipsPerPixel),
-      Float(border.right / twipsPerPixel),
-      Float(border.bottom / twipsPerPixel),
-      Float(border.left / twipsPerPixel)
-    };
-    nsCSSBorderRenderer::ComputeInnerRadii(borderRadii, borderSizes,
-                                           &innerRadii);
-  }
+  bool hasBorderRadius = GetShadowInnerRadii(aForFrame,
+                                             aFrameArea,
+                                             innerRadii);
+
+  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (!shadowItem->mInset)
       continue;
 
     // shadowPaintRect: the area to paint on the temp surface
     // shadowClipRect: the area on the temporary surface within shadowPaintRect
     //                 that we will NOT paint in
     nscoord blurRadius = shadowItem->mRadius;
     nsMargin blurMargin =
       nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
     nsRect shadowPaintRect = paddingRect;
     shadowPaintRect.Inflate(blurMargin);
 
-    Rect shadowPaintGfxRect = NSRectToRect(shadowPaintRect, twipsPerPixel);
-    shadowPaintGfxRect.RoundOut();
-
     // Round the spread radius to device pixels (by truncation).
     // This mostly matches what we do for borders, except that we don't round
     // up values between zero and one device pixels to one device pixel.
     // This way of rounding is symmetric around zero, which makes sense for
     // the spread radius.
     int32_t spreadDistance = shadowItem->mSpread / twipsPerPixel;
     nscoord spreadDistanceAppUnits = aPresContext->DevPixelsToAppUnits(spreadDistance);
 
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -370,21 +370,31 @@ struct nsCSSRendering {
    */
   static void Init();
   
   /**
    * Clean up any static variables used by nsCSSRendering.
    */
   static void Shutdown();
   
+  static bool GetShadowInnerRadii(nsIFrame* aFrame,
+                                  const nsRect& aFrameArea,
+                                  RectCornerRadii& aOutInnerRadii);
+  static nsRect GetBoxShadowInnerPaddingRect(nsIFrame* aFrame,
+                                             const nsRect& aFrameArea);
+  static bool CanPaintBoxShadowInner(nsIFrame* aFrame);
   static void PaintBoxShadowInner(nsPresContext* aPresContext,
                                   nsRenderingContext& aRenderingContext,
                                   nsIFrame* aForFrame,
                                   const nsRect& aFrameArea);
 
+  static bool GetBorderRadii(const nsRect& aFrameRect,
+                             const nsRect& aBorderRect,
+                             nsIFrame* aFrame,
+                             RectCornerRadii& aOutRadii);
   static nsRect GetShadowRect(const nsRect aFrameArea,
                               bool aNativeTheme,
                               nsIFrame* aForFrame);
   static mozilla::gfx::Color GetShadowColor(nsCSSShadowItem* aShadow,
                                    nsIFrame* aFrame,
                                    float aOpacity);
   // Returns if the frame has a themed frame.
   // aMaybeHasBorderRadius will return false if we can early detect
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4143,16 +4143,17 @@ nsDisplayOutline::BuildLayer(nsDisplayLi
                              LayerManager* aManager,
                              const ContainerLayerParameters& aContainerParameters)
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 void
 nsDisplayOutline::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                          nsTArray<WebRenderParentCommand>& aParentCommands,
                                           WebRenderDisplayItemLayer* aLayer)
 {
   MOZ_ASSERT(mBorderRenderer.isSome());
 
   Rect outlineTransformedRect = aLayer->RelativeToParent(mBorderRenderer->mOuterRect);
 
   nsCSSBorderRenderer* br = mBorderRenderer.ptr();
   WrBorderSide side[4];
@@ -4422,16 +4423,17 @@ nsDisplayCaret::Paint(nsDisplayListBuild
                       nsRenderingContext* aCtx) {
   // Note: Because we exist, we know that the caret is visible, so we don't
   // need to check for the caret's visibility.
   mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
 }
 
 void
 nsDisplayCaret::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                         WebRenderDisplayItemLayer* aLayer) {
   using namespace mozilla::layers;
   int32_t contentOffset;
   nsIFrame* frame = mCaret->GetFrame(&contentOffset);
   if (!frame) {
     return;
   }
   NS_ASSERTION(frame == mFrame, "We're referring different frame");
@@ -4830,16 +4832,17 @@ nsDisplayBoxShadowOuter::BuildLayer(nsDi
                                     LayerManager* aManager,
                                     const ContainerLayerParameters& aContainerParameters)
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }