Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Thu, 08 Mar 2018 20:43:00 +0200
changeset 407222 1d01aa7f63ad
parent 407221 5b2d608c1924 (current diff)
parent 407187 55d91695f4bb (diff)
child 407223 5a255b87cb3d
push id33596
push userncsoregi@mozilla.com
push date2018-03-09 00:18 +0000
treeherdermozilla-central@31a33fc61956 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
testing/web-platform/meta/webdriver/tests/actions/key.py.ini
third_party/rust/futures/FAQ.md
third_party/rust/futures/src/stack.rs
third_party/rust/futures/src/stream/mod.rs
third_party/rust/futures/src/task_impl/data.rs
third_party/rust/futures/src/task_impl/task_rc.rs
third_party/rust/futures/src/task_impl/unpark_mutex.rs
third_party/rust/futures/tests/support/mod.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -51,17 +51,17 @@ dependencies = [
 [[package]]
 name = "audioipc"
 version = "0.2.1"
 dependencies = [
  "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -71,33 +71,33 @@ dependencies = [
 
 [[package]]
 name = "audioipc-client"
 version = "0.3.0"
 dependencies = [
  "audioipc 0.2.1",
  "cubeb-backend 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "audioipc-server"
 version = "0.2.2"
 dependencies = [
  "audioipc 0.2.1",
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -639,25 +639,25 @@ name = "fuchsia-zircon-sys"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "futures"
-version = "0.1.13"
+version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "futures-cpupool"
-version = "0.1.5"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "fxhash"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1834,42 +1834,42 @@ dependencies = [
 ]
 
 [[package]]
 name = "tokio-core"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "tokio-io"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "tokio-uds"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2274,18 +2274,18 @@ dependencies = [
 "checksum euclid 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2744c002882c67d0f6d6e8cfdf16eae729dc27744d312745132e62218b7de5c"
 "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ebc04f19019fff1f2d627b5581574ead502f80c48c88900575a46e0840fe5d0"
 "checksum freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "398b8a11884898184d55aca9806f002b3cf68f0e860e0cbb4586f834ee39b0e7"
 "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
 "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
 "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
-"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
-"checksum futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a283c84501e92cade5ea673a2a7ca44f71f209ccdd302a3e0896f50083d2c5ff"
+"checksum futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0bab5b5e94f5c31fc764ba5dd9ad16568aae5d4825538c01d6bca680c9bf94a7"
+"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum gl_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5c19cde55637681450c92f7a05ea16c78e2b6d0587e601ec1ebdab6960854b"
 "checksum gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "959c818d9bbe9f7b7db55dce0bc44673c4da4f4ee122536c40550f984c3b8017"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6718,23 +6718,17 @@ var CanvasPermissionPromptHelper = {
     }
 
     let uri = Services.io.newURI(aData);
     if (gBrowser.selectedBrowser !== browser) {
       // Must belong to some other window.
       return;
     }
 
-    let message = {};
-    let header = gNavigatorBundle.getFormattedString("canvas.siteprompt", ["<>"], 1);
-
-    header = header.split("<>");
-    message.start = header[0];
-    message.host = uri.asciiHost;
-    message.end = header[1];
+    let message = gNavigatorBundle.getFormattedString("canvas.siteprompt", ["<>"], 1);
 
     function setCanvasPermission(aURI, aPerm, aPersistent) {
       Services.perms.add(aURI, "canvas", aPerm,
                           aPersistent ? Ci.nsIPermissionManager.EXPIRE_NEVER
                                       : Ci.nsIPermissionManager.EXPIRE_SESSION);
     }
 
     let mainAction = {
@@ -6760,17 +6754,18 @@ var CanvasPermissionPromptHelper = {
       show: !PrivateBrowsingUtils.isWindowPrivate(window)
     };
     if (checkbox.show) {
       checkbox.checked = true;
       checkbox.label = gBrowserBundle.GetStringFromName("canvas.remember");
     }
 
     let options = {
-      checkbox
+      checkbox,
+      name: uri.asciiHost,
     };
     PopupNotifications.show(browser, aTopic, message, this._notificationIcon,
                             mainAction, secondaryActions, options);
   }
 };
 
 function CanCloseWindow() {
   // Avoid redundant calls to canClose from showing multiple
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -23,22 +23,22 @@ window._gBrowser = {
 
     this.mPanelContainer = document.getElementById("tabbrowser-tabpanels");
     this.addEventListener = this.mPanelContainer.addEventListener.bind(this.mPanelContainer);
     this.removeEventListener = this.mPanelContainer.removeEventListener.bind(this.mPanelContainer);
     this.dispatchEvent = this.mPanelContainer.dispatchEvent.bind(this.mPanelContainer);
 
     this.initialBrowser = document.getElementById("tabbrowser-initialBrowser");
 
+    this.tabbox = document.getElementById("tabbrowser-tabbox");
+
     this.tabContainer = document.getElementById("tabbrowser-tabs");
 
     this.tabs = this.tabContainer.childNodes;
 
-    this.tabbox = document.getElementById("tabbrowser-tabbox");
-
     this.closingTabsEnum = { ALL: 0, OTHER: 1, TO_END: 2 };
 
     this._visibleTabs = null;
 
     this.mCurrentTab = null;
 
     this._lastRelatedTabMap = new WeakMap();
 
--- a/browser/base/content/test/popupNotifications/head.js
+++ b/browser/base/content/test/popupNotifications/head.js
@@ -124,31 +124,32 @@ function showNotification(notifyObj) {
 function dismissNotification(popup) {
   info("Dismissing notification " + popup.childNodes[0].id);
   executeSoon(() => EventUtils.synthesizeKey("KEY_Escape"));
 }
 
 function BasicNotification(testId) {
   this.browser = gBrowser.selectedBrowser;
   this.id = "test-notification-" + testId;
-  this.message = "This is popup notification for " + testId;
+  this.message = testId + ": Will you allow <> to perform this action?";
   this.anchorID = null;
   this.mainAction = {
     label: "Main Action",
     accessKey: "M",
     callback: () => this.mainActionClicked = true
   };
   this.secondaryActions = [
     {
       label: "Secondary Action",
       accessKey: "S",
       callback: () => this.secondaryActionClicked = true
     }
   ];
   this.options = {
+    name: "http://example.com",
     eventCallback: eventName => {
       switch (eventName) {
         case "dismissed":
           this.dismissalCallbackTriggered = true;
           break;
         case "showing":
           this.showingCallbackTriggered = true;
           break;
@@ -199,23 +200,23 @@ function checkPopup(popup, notifyObj) {
   let icon = document.getAnonymousElementByAttribute(notification, "class",
                                                      "popup-notification-icon");
   if (notifyObj.id == "geolocation") {
     isnot(icon.boxObject.width, 0, "icon for geo displayed");
     ok(popup.anchorNode.classList.contains("notification-anchor-icon"),
        "notification anchored to icon");
   }
 
-  if (typeof notifyObj.message == "string") {
-    is(notification.getAttribute("label"), notifyObj.message, "message matches");
-  } else {
-    is(notification.getAttribute("label"), notifyObj.message.start, "message matches");
-    is(notification.getAttribute("hostname"), notifyObj.message.host, "message matches");
-    is(notification.getAttribute("endlabel"), notifyObj.message.end, "message matches");
-  }
+  let description = notifyObj.message.split("<>");
+  let text = {};
+  text.start = description[0];
+  text.end = description[1];
+  is(notification.getAttribute("label"), text.start, "message matches");
+  is(notification.getAttribute("name"), notifyObj.options.name, "message matches");
+  is(notification.getAttribute("endlabel"), text.end, "message matches");
 
   is(notification.id, notifyObj.id + "-notification", "id matches");
   if (notifyObj.mainAction) {
     is(notification.getAttribute("buttonlabel"), notifyObj.mainAction.label,
        "main action label matches");
     is(notification.getAttribute("buttonaccesskey"),
        notifyObj.mainAction.accessKey, "main action accesskey matches");
     is(notification.getAttribute("buttonhighlight"),
--- a/browser/components/customizableui/test/browser_panelUINotifications_fullscreen.js
+++ b/browser/components/customizableui/test/browser_panelUINotifications_fullscreen.js
@@ -14,16 +14,17 @@ add_task(async function testFullscreen()
 
   isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
   let notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
   is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
   let doorhanger = notifications[0];
   is(doorhanger.id, "appMenu-update-manual-notification", "PanelUI is displaying the update-manual notification.");
 
   let popuphiddenPromise = BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popuphidden");
+  document.documentElement.focus();
   EventUtils.synthesizeKey("KEY_F11");
   await popuphiddenPromise;
   await new Promise(executeSoon);
   is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
 
   FullScreen.showNavToolbox();
   is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is displaying on PanelUI button.");
 
--- a/browser/components/extensions/test/browser/browser_ext_devtools_network.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_network.js
@@ -175,16 +175,18 @@ add_task(async function test_devtools_ne
   extension.sendMessage("navigate");
 
   // Wait till the navigation is complete and request
   // added into the net panel.
   await Promise.all([
     extension.awaitMessage("tabUpdated"),
     extension.awaitMessage("onNavigatedFired"),
     extension.awaitMessage("onRequestFinished"),
+    extension.awaitMessage("onRequestFinished-callbackExecuted"),
+    extension.awaitMessage("onRequestFinished-promiseResolved"),
     waitForRequestAdded(toolbox),
   ]);
 
   // Get HAR, it should not be empty now.
   const getHARPromise = extension.awaitMessage("getHAR-result");
   extension.sendMessage("getHAR");
   const getHARResult = await getHARPromise;
   is(getHARResult.log.entries.length, 1, "HAR log should not be empty");
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -317,25 +317,16 @@ var ExtensionsUI = {
     let info2 = Object.assign({appName}, info);
 
     let strings = ExtensionData.formatPermissionStrings(info2, bundle);
     strings.addonName = info.addon.name;
     return strings;
   },
 
   showPermissionsPrompt(browser, strings, icon, histkey) {
-    let message = {};
-    // Create the notification header element.
-    let header = strings.header;
-    header = header.split("<>");
-    message.start = header[0];
-    // Use the host element to display addon name in addon permission prompts.
-    message.host = strings.addonName;
-    message.end = header[1];
-
     function eventCallback(topic) {
       let doc = this.browser.ownerDocument;
       if (topic == "showing") {
         let textEl = doc.getElementById("addon-webext-perm-text");
         textEl.textContent = strings.text;
         textEl.hidden = !strings.text;
 
         let listIntroEl = doc.getElementById("addon-webext-perm-intro");
@@ -358,16 +349,17 @@ var ExtensionsUI = {
       return false;
     }
 
     let popupOptions = {
       hideClose: true,
       popupIconURL: icon || DEFAULT_EXTENSION_ICON,
       persistent: true,
       eventCallback,
+      name: strings.addonName,
     };
 
     let win = browser.ownerGlobal;
     return new Promise(resolve => {
       let action = {
         label: strings.acceptText,
         accessKey: strings.acceptKey,
         callback: () => {
@@ -385,43 +377,35 @@ var ExtensionsUI = {
             if (histkey) {
               this.histogram.add(histkey + "Rejected");
             }
             resolve(false);
           },
         },
       ];
 
-      win.PopupNotifications.show(browser, "addon-webext-permissions", message,
-                                  "addons-notification-icon",
-                                  action, secondaryActions, popupOptions);
+      win.PopupNotifications.show(browser, "addon-webext-permissions", strings.header,
+                                  "addons-notification-icon", action,
+                                  secondaryActions, popupOptions);
     });
   },
 
   showDefaultSearchPrompt(browser, strings, icon) {
-    let message = {};
-    // Create the notification header element.
-    let header = strings.text;
-    header = header.split("<>");
-    message.start = header[0];
-    // Use the host element to display addon name in addon notification prompts.
-    message.host = strings.addonName;
-    message.end = header[1];
-
     return new Promise(resolve => {
       let popupOptions = {
         hideClose: true,
         popupIconURL: icon || DEFAULT_EXTENSION_ICON,
         persistent: false,
         removeOnDismissal: true,
         eventCallback(topic) {
           if (topic == "removed") {
             resolve(false);
           }
-        }
+        },
+        name: strings.addonName,
       };
 
       let action = {
         label: strings.acceptText,
         accessKey: strings.acceptKey,
         disableHighlight: true,
         callback: () => {
           resolve(true);
@@ -433,40 +417,32 @@ var ExtensionsUI = {
           accessKey: strings.cancelKey,
           callback: () => {
             resolve(false);
           },
         },
       ];
 
       let win = browser.ownerGlobal;
-      win.PopupNotifications.show(browser, "addon-webext-defaultsearch", message,
-                                  "addons-notification-icon",
-                                  action, secondaryActions, popupOptions);
+      win.PopupNotifications.show(browser, "addon-webext-defaultsearch", strings.text,
+                                  "addons-notification-icon", action,
+                                  secondaryActions, popupOptions);
     });
   },
 
   showInstallNotification(target, addon) {
     let win = target.ownerGlobal;
     let popups = win.PopupNotifications;
 
     let brandBundle = win.document.getElementById("bundle_brand");
     let appName = brandBundle.getString("brandShortName");
     let bundle = win.gNavigatorBundle;
 
-    // Create the notification header element.
-    let message = {};
-    let header = bundle.getFormattedString("addonPostInstall.message1",
-                                          ["<>", appName]);
-    header = header.split("<>");
-    message.start = header[0];
-    // Use the host element to display addon name in addon permission prompts.
-    message.host = addon.name;
-    message.end = header[1];
-
+    let message = bundle.getFormattedString("addonPostInstall.message1",
+                                            ["<>", appName]);
     return new Promise(resolve => {
       let action = {
         label: bundle.getString("addonPostInstall.okay.label"),
         accessKey: bundle.getString("addonPostInstall.okay.key"),
         callback: resolve,
       };
 
       let icon = addon.isWebExtension ?
@@ -475,17 +451,18 @@ var ExtensionsUI = {
       let options = {
         hideClose: true,
         timeout: Date.now() + 30000,
         popupIconURL: icon,
         eventCallback(topic) {
           if (topic == "dismissed") {
             resolve();
           }
-        }
+        },
+        name: addon.name,
       };
 
       popups.show(target, "addon-installed", message, "addons-notification-icon",
                   action, null, options);
     });
   },
 };
 
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -167,19 +167,19 @@ var PermissionPromptPrototype = {
    *
    * @return {string}
    */
   get anchorID() {
     return "default-notification-icon";
   },
 
   /**
-   * The message to show the user in the PopupNotification. This
-   * is usually a string describing the permission that is being
-   * requested.
+   * The message to show to the user in the PopupNotification. A string
+   * with "<>" as a placeholder that is usually replaced by an addon name
+   * or a host name, formatted in bold, to describe the permission that is being requested.
    *
    * Subclasses must override this.
    *
    * @return {string}
    */
   get message() {
     throw new Error("Not implemented.");
   },
@@ -426,17 +426,18 @@ GeolocationPermissionPrompt.prototype = 
   get permissionKey() {
     return "geo";
   },
 
   get popupOptions() {
     let pref = "browser.geolocation.warning.infoURL";
     let options = {
       learnMoreURL: Services.urlFormatter.formatURLPref(pref),
-      displayURI: false
+      displayURI: false,
+      name: this.principal.URI.hostPort,
     };
 
     if (this.principal.URI.schemeIs("file")) {
       options.checkbox = { show: false };
     } else {
       // Don't offer "always remember" action in PB mode
       options.checkbox = {
         show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
@@ -454,32 +455,22 @@ GeolocationPermissionPrompt.prototype = 
     return "geolocation";
   },
 
   get anchorID() {
     return "geo-notification-icon";
   },
 
   get message() {
-    let message = {};
     if (this.principal.URI.schemeIs("file")) {
-      message.start = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
-    } else {
-      let header = gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
-                                                    ["<>"], 1);
-      header = header.split("<>");
-      message.end = header[1];
-      message.start = header[0];
+      return gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
+    }
 
-      message.host = "<>";
-      try {
-        message.host = this.principal.URI.hostPort;
-      } catch (ex) { }
-    }
-    return message;
+    return gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
+                                                  ["<>"], 1);
   },
 
   get promptActions() {
     // We collect Telemetry data on Geolocation prompts and how users
     // respond to them. The probe keys are a bit verbose, so let's alias them.
     const SHARE_LOCATION =
       Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_SHARE_LOCATION;
     const ALWAYS_SHARE =
@@ -543,43 +534,32 @@ DesktopNotificationPermissionPrompt.prot
   },
 
   get popupOptions() {
     let learnMoreURL =
       Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
 
     return {
       learnMoreURL,
-      displayURI: false
+      displayURI: false,
+      name: this.principal.URI.hostPort,
     };
   },
 
   get notificationID() {
     return "web-notifications";
   },
 
   get anchorID() {
     return "web-notifications-notification-icon";
   },
 
   get message() {
-    let message = {};
-
-    message.host = "<>";
-    try {
-      message.host = this.principal.URI.hostPort;
-    } catch (ex) { }
-
-    let header = gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
+    return gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
                                                     ["<>"], 1);
-    header = header.split("<>");
-    message.end = header[1];
-    message.start = header[0];
-
-    return message;
   },
 
   get promptActions() {
     let actions = [
       {
         label: gBrowserBundle.GetStringFromName("webNotifications.allow"),
         accessKey:
           gBrowserBundle.GetStringFromName("webNotifications.allow.accesskey"),
@@ -636,43 +616,32 @@ PersistentStoragePermissionPrompt.protot
       checkbox.checked = true;
       checkbox.label = gBrowserBundle.GetStringFromName("persistentStorage.remember");
     }
     let learnMoreURL =
       Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
     return {
       checkbox,
       learnMoreURL,
-      displayURI: false
+      displayURI: false,
+      name: this.principal.URI.hostPort,
     };
   },
 
   get notificationID() {
     return "persistent-storage";
   },
 
   get anchorID() {
     return "persistent-storage-notification-icon";
   },
 
   get message() {
-    let message = {};
-
-    message.host = "<>";
-    try {
-      message.host = this.principal.URI.hostPort;
-    } catch (ex) {}
-
-    let header = gBrowserBundle.formatStringFromName("persistentStorage.allowWithSite",
+    return gBrowserBundle.formatStringFromName("persistentStorage.allowWithSite",
                                                     ["<>"], 1);
-    header = header.split("<>");
-    message.end = header[1];
-    message.start = header[0];
-
-    return message;
   },
 
   get promptActions() {
     return [
       {
         label: gBrowserBundle.GetStringFromName("persistentStorage.allow"),
         accessKey:
           gBrowserBundle.GetStringFromName("persistentStorage.allow.accesskey"),
@@ -714,17 +683,18 @@ MIDIPermissionPrompt.prototype = {
 
   get permissionKey() {
     return this.permName;
   },
 
   get popupOptions() {
     // TODO (bug 1433235) We need a security/permissions explanation URL for this
     let options = {
-      displayURI: false
+      displayURI: false,
+      name: this.principal.URI.hostPort,
     };
 
     if (this.principal.URI.schemeIs("file")) {
       options.checkbox = { show: false };
     } else {
       // Don't offer "always remember" action in PB mode
       options.checkbox = {
         show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
@@ -742,40 +712,29 @@ MIDIPermissionPrompt.prototype = {
     return "midi";
   },
 
   get anchorID() {
     return "midi-notification-icon";
   },
 
   get message() {
-    let message = {};
+    let message;
     if (this.principal.URI.schemeIs("file")) {
       if (this.isSysexPerm) {
-        message.start = gBrowserBundle.formatStringFromName("midi.shareSysexWithFile.message");
-      } else {
-        message.start = gBrowserBundle.formatStringFromName("midi.shareWithFile.message");
-      }
-    } else {
-      let header;
-      if (this.isSysexPerm) {
-        header = gBrowserBundle.formatStringFromName("midi.shareSysexWithSite.message",
-                                                     ["<>"], 1);
+        message = gBrowserBundle.formatStringFromName("midi.shareSysexWithFile.message");
       } else {
-        header = gBrowserBundle.formatStringFromName("midi.shareWithSite.message",
-                                                     ["<>"], 1);
+        message = gBrowserBundle.formatStringFromName("midi.shareWithFile.message");
       }
-      header = header.split("<>");
-      message.end = header[1];
-      message.start = header[0];
-
-      message.host = "<>";
-      try {
-        message.host = this.principal.URI.hostPort;
-      } catch (ex) { }
+    } else if (this.isSysexPerm) {
+      message = gBrowserBundle.formatStringFromName("midi.shareSysexWithSite.message",
+                                                    ["<>"], 1);
+    } else {
+      message = gBrowserBundle.formatStringFromName("midi.shareWithSite.message",
+                                                    ["<>"], 1);
     }
     return message;
   },
 
   get promptActions() {
     return [{
         label: gBrowserBundle.GetStringFromName("midi.Allow.label"),
         accessKey: gBrowserBundle.GetStringFromName("midi.Allow.accesskey"),
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -359,18 +359,17 @@ function prompt(aBrowser, aRequest) {
 
   let uri;
   try {
     // This fails for principals that serialize to "null", e.g. file URIs.
     uri = Services.io.newURI(aRequest.origin);
   } catch (e) {
     uri = Services.io.newURI(aRequest.documentURI);
   }
-  let message = {};
-  message.host = getHost(uri);
+
   let chromeDoc = aBrowser.ownerDocument;
   let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
 
   // Mind the order, because for simplicity we're iterating over the list using
   // "includes()". This allows the rotation of string identifiers. We list the
   // full identifiers here so they can be cross-referenced more easily.
   let joinedRequestTypes = requestTypes.join("And");
   let stringId = [
@@ -381,20 +380,17 @@ function prompt(aBrowser, aRequest) {
     "getUserMedia.shareAudioCapture2.message",
     // Combinations of the above request types last.
     "getUserMedia.shareCameraAndMicrophone2.message",
     "getUserMedia.shareCameraAndAudioCapture2.message",
     "getUserMedia.shareScreenAndMicrophone3.message",
     "getUserMedia.shareScreenAndAudioCapture3.message",
   ].find(id => id.includes(joinedRequestTypes));
 
-  let header = stringBundle.getFormattedString(stringId, ["<>"], 1);
-  header = header.split("<>");
-  message.end = header[1];
-  message.start = header[0];
+  let message = stringBundle.getFormattedString(stringId, ["<>"], 1);
 
   let notification; // Used by action callbacks.
   let mainAction = {
     label: stringBundle.getString("getUserMedia.allow.label"),
     accessKey: stringBundle.getString("getUserMedia.allow.accesskey"),
     // The real callback will be set during the "showing" event. The
     // empty function here is so that PopupNotifications.show doesn't
     // reject the action.
@@ -419,16 +415,17 @@ function prompt(aBrowser, aRequest) {
                               SitePermissions.BLOCK, scope, notification.browser);
       }
     }
   ];
 
   let productName = gBrandBundle.GetStringFromName("brandShortName");
 
   let options = {
+    name: getHost(uri),
     persistent: true,
     hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
     eventCallback(aTopic, aNewBrowser) {
       if (aTopic == "swapping")
         return true;
 
       let doc = this.browser.ownerDocument;
 
--- a/devtools/client/netmonitor/initializer.js
+++ b/devtools/client/netmonitor/initializer.js
@@ -100,54 +100,39 @@ window.Netmonitor = {
 
   // Support for WebExtensions API
 
   /**
    * Support for `devtools.network.getHAR` (get collected data as HAR)
    */
   getHar() {
     let { HarExporter } = require("devtools/client/netmonitor/src/har/har-exporter");
-    let {
-      getLongString,
-      getTabTarget,
-      getTimingMarker,
-      requestData,
-    } = connector;
-    let { form: { title, url } } = getTabTarget();
     let state = store.getState();
 
     let options = {
-      getString: getLongString,
+      connector,
       items: getSortedRequests(state),
-      requestData,
-      getTimingMarker,
-      title: title || url,
     };
 
     return HarExporter.getHar(options);
   },
 
   /**
    * Support for `devtools.network.onRequestFinished`. A hook for
    * every finished HTTP request used by WebExtensions API.
    */
   onRequestAdded(event, requestId) {
     let listeners = this.toolbox.getRequestFinishedListeners();
     if (!listeners.size) {
       return;
     }
 
     let { HarExporter } = require("devtools/client/netmonitor/src/har/har-exporter");
-    let { getLongString, getTabTarget, requestData } = connector;
-    let { form: { title, url } } = getTabTarget();
-
     let options = {
-      getString: getLongString,
-      requestData,
-      title: title || url,
+      connector,
       includeResponseBodies: false,
       items: [getDisplayedRequestById(store.getState(), requestId)],
     };
 
     // Build HAR for specified request only.
     HarExporter.getHar(options).then(har => {
       let harEntry = har.log.entries[0];
       delete harEntry.pageref;
--- a/devtools/client/netmonitor/src/connector/chrome-connector.js
+++ b/devtools/client/netmonitor/src/connector/chrome-connector.js
@@ -38,16 +38,20 @@ class ChromeConnector {
   pause() {
     this.disconnect();
   }
 
   resume() {
     this.setup();
   }
 
+  enableActions(enable) {
+    // TODO : implement.
+  }
+
   /**
    * currently all events are about "navigation" is not support on CDP
    */
   willNavigate() {
     this.actions.batchReset();
     this.actions.clearRequests();
   }
 
--- a/devtools/client/netmonitor/src/connector/firefox-connector.js
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -122,16 +122,20 @@ class FirefoxConnector {
     }
     if (this.webConsoleClient) {
       this.webConsoleClient.off("networkEvent");
       this.webConsoleClient.off("networkEventUpdate");
       this.webConsoleClient.off("docEvent");
     }
   }
 
+  enableActions(enable) {
+    this.dataProvider.enableActions(enable);
+  }
+
   willNavigate() {
     if (!Services.prefs.getBoolPref("devtools.netmonitor.persistlog")) {
       this.actions.batchReset();
       this.actions.clearRequests();
     } else {
       // If the log is persistent, just clear all accumulated timing markers.
       this.actions.clearTimingMarkers();
     }
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -17,16 +17,17 @@ const { fetchHeaders } = require("../uti
  * so it's possible to determine whether all has been fetched
  * or not.
  */
 class FirefoxDataProvider {
   constructor({webConsoleClient, actions}) {
     // Options
     this.webConsoleClient = webConsoleClient;
     this.actions = actions;
+    this.actionsEnabled = true;
 
     // Internal properties
     this.payloadQueue = new Map();
 
     // Map[key string => Promise] used by `requestData` to prevent requesting the same
     // request data twice.
     this.lazyRequestData = new Map();
 
@@ -34,33 +35,42 @@ class FirefoxDataProvider {
     this.getLongString = this.getLongString.bind(this);
 
     // Event handlers
     this.onNetworkEvent = this.onNetworkEvent.bind(this);
     this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
   }
 
   /**
+   * Enable/disable firing redux actions (enabled by default).
+   *
+   * @param {boolean} enable Set to true to fire actions.
+   */
+  enableActions(enable) {
+    this.actionsEnabled = enable;
+  }
+
+  /**
    * Add a new network request to application state.
    *
    * @param {string} id request id
    * @param {object} data data payload will be added to application state
    */
   async addRequest(id, data) {
     let {
       method,
       url,
       isXHR,
       cause,
       startedDateTime,
       fromCache,
       fromServiceWorker,
     } = data;
 
-    if (this.actions.addRequest) {
+    if (this.actionsEnabled && this.actions.addRequest) {
       await this.actions.addRequest(id, {
         // Convert the received date/time string to a unix timestamp.
         startedMillis: Date.parse(startedDateTime),
         method,
         url,
         isXHR,
         cause,
 
@@ -115,17 +125,17 @@ class FirefoxDataProvider {
       responseContentObj,
       requestHeadersObj,
       responseHeadersObj,
       postDataObj,
       requestCookiesObj,
       responseCookiesObj
     );
 
-    if (this.actions.updateRequest) {
+    if (this.actionsEnabled && this.actions.updateRequest) {
       await this.actions.updateRequest(id, payload, true);
     }
 
     return payload;
   }
 
   async fetchResponseContent(responseContent) {
     let payload = {};
@@ -372,17 +382,17 @@ class FirefoxDataProvider {
 
     if (!payload.requestHeadersAvailable || !payload.requestCookiesAvailable ||
         !payload.eventTimingsAvailable || !payload.responseContentAvailable) {
       return;
     }
 
     this.payloadQueue.delete(actor);
 
-    if (this.actions.updateRequest) {
+    if (this.actionsEnabled && this.actions.updateRequest) {
       await this.actions.updateRequest(actor, payload, true);
     }
 
     // This event is fired only once per request, once all the properties are fetched
     // from `onNetworkEventUpdate`. There should be no more RDP requests after this.
     emit(EVENTS.PAYLOAD_READY, actor);
   }
 
@@ -409,17 +419,17 @@ class FirefoxDataProvider {
       return promise;
     }
     // Fetch the data
     promise = this._requestData(actor, method).then(async (payload) => {
       // Remove the request from the cache, any new call to requestData will fetch the
       // data again.
       this.lazyRequestData.delete(key);
 
-      if (this.actions.updateRequest) {
+      if (this.actionsEnabled && this.actions.updateRequest) {
         await this.actions.updateRequest(actor, {
           ...payload,
           // Lockdown *Available property once we fetch data from back-end.
           // Using this as a flag to prevent fetching arrived data again.
           [`${method}Available`]: false,
         }, true);
       }
 
--- a/devtools/client/netmonitor/src/connector/index.js
+++ b/devtools/client/netmonitor/src/connector/index.js
@@ -66,16 +66,20 @@ class Connector {
   pause() {
     return this.connector.pause();
   }
 
   resume() {
     return this.connector.resume();
   }
 
+  enableActions() {
+    this.connector.enableActions(...arguments);
+  }
+
   // Public API
 
   getLongString() {
     return this.connector.getLongString(...arguments);
   }
 
   getNetworkRequest() {
     return this.connector.getNetworkRequest(...arguments);
--- a/devtools/client/netmonitor/src/har/har-builder.js
+++ b/devtools/client/netmonitor/src/har/har-builder.js
@@ -10,16 +10,19 @@ const { LocalizationHelper } = require("
 const { CurlUtils } = require("devtools/client/shared/curl");
 const {
   getFormDataSections,
   getUrlQuery,
   parseQueryString,
 } = require("../utils/request-utils");
 const { buildHarLog } = require("./har-builder-utils");
 const L10N = new LocalizationHelper("devtools/client/locales/har.properties");
+const {
+  TIMING_KEYS
+} = require("../constants");
 
 /**
  * This object is responsible for building HAR file. See HAR spec:
  * https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HAR/Overview.html
  * http://www.softwareishard.com/blog/har-12-spec/
  *
  * @param {Object} options configuration object
  *
@@ -96,28 +99,40 @@ HarBuilder.prototype = {
   },
 
   buildEntry: async function (log, file) {
     let page = this.getPage(log, file);
 
     let entry = {};
     entry.pageref = page.id;
     entry.startedDateTime = dateToJSON(new Date(file.startedMillis));
-    entry.time = file.endedMillis - file.startedMillis;
 
     let eventTimings = file.eventTimings;
     if (!eventTimings && this._options.requestData) {
       eventTimings = await this._options.requestData(file.id, "eventTimings");
     }
 
     entry.request = await this.buildRequest(file);
     entry.response = await this.buildResponse(file);
     entry.cache = this.buildCache(file);
     entry.timings = eventTimings ? eventTimings.timings : {};
 
+    // Calculate total time by summing all timings. Note that
+    // `file.totalTime` can't be used since it doesn't have to
+    // correspond to plain summary of individual timings.
+    // With TCP Fast Open and TLS early data sending data can
+    // start at the same time as connect (we can send data on
+    // TCP syn packet). Also TLS handshake can carry application
+    // data thereby overlapping a sending data period and TLS
+    // handshake period.
+    entry.time = TIMING_KEYS.reduce((sum, type) => {
+      let time = entry.timings[type];
+      return (typeof time != "undefined") ? (sum + time) : sum;
+    }, 0);
+
     // Security state isn't part of HAR spec, and so create
     // custom field that needs to use '_' prefix.
     entry._securityState = file.securityState;
 
     if (file.remoteAddress) {
       entry.serverIPAddress = file.remoteAddress;
     }
 
--- a/devtools/client/netmonitor/src/har/har-collector.js
+++ b/devtools/client/netmonitor/src/har/har-collector.js
@@ -378,20 +378,17 @@ HarCollector.prototype = {
    * Handles additional information received for a "eventTimings" packet.
    *
    * @param object response
    *        The message received from the server.
    */
   onEventTimings: function (response) {
     let file = this.getFile(response.from);
     file.eventTimings = response;
-
-    let totalTime = response.totalTime;
-    file.totalTime = totalTime;
-    file.endedMillis = file.startedMillis + totalTime;
+    file.totalTime = response.totalTime;
   },
 
   // Helpers
 
   getLongHeaders: function (headers) {
     for (let header of headers) {
       if (typeof header.value == "object") {
         try {
--- a/devtools/client/netmonitor/src/har/har-exporter.js
+++ b/devtools/client/netmonitor/src/har/har-exporter.js
@@ -181,20 +181,44 @@ const HarExporter = {
   },
 
   /**
    * Build HAR data object. This object contains all HTTP data
    * collected by the Network panel. The process is asynchronous
    * since it can involve additional RDP communication (e.g. resolving
    * long strings).
    */
-  buildHarData: function (options) {
+  buildHarData: async function (options) {
+    let { connector } = options;
+    let {
+      getTabTarget,
+    } = connector;
+    let {
+      form: { title, url }
+    } = getTabTarget();
+
+    // Disconnect from redux actions/store.
+    connector.enableActions(false);
+
+    options = {
+      ...options,
+      title: title || url,
+      getString: connector.getLongString,
+      getTimingMarker: connector.getTimingMarker,
+      requestData: connector.requestData,
+    };
+
     // Build HAR object from collected data.
     let builder = new HarBuilder(options);
-    return builder.build();
+    let result = await builder.build();
+
+    // Connect to redux actions again.
+    connector.enableActions(true);
+
+    return result;
   },
 
   /**
    * Build JSON string from the HAR data object.
    */
   stringify: function (har) {
     if (!har) {
       return null;
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
@@ -42,16 +42,17 @@ add_task(async function () {
   is(har.log.pages.length, 1, "There must be one page");
   is(har.log.entries.length, 1, "There must be one request");
 
   let page = har.log.pages[0];
   ok("onContentLoad" in page.pageTimings, "There must be onContentLoad time");
   ok("onLoad" in page.pageTimings, "There must be onLoad time");
 
   let entry = har.log.entries[0];
+  ok(entry.time > 0, "Check the total time");
   is(entry.request.method, "GET", "Check the method");
   is(entry.request.url, SIMPLE_URL, "Check the URL");
   is(entry.request.headers.length, 9, "Check number of request headers");
   is(entry.response.status, 200, "Check response status");
   is(entry.response.statusText, "OK", "Check response status text");
   is(entry.response.headers.length, 6, "Check number of response headers");
   is(entry.response.content.mimeType, // eslint-disable-line
     "text/html", "Check response content type"); // eslint-disable-line
--- a/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js
+++ b/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js
@@ -404,27 +404,16 @@ class RequestListContextMenu {
     // This will not work in launchpad
     // document.execCommand(‘cut’/‘copy’) was denied because it was not called from
     // inside a short running user-generated event handler.
     // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
     return HarExporter.save(this.getDefaultHarOptions(sortedRequests));
   }
 
   getDefaultHarOptions(sortedRequests) {
-    let {
-      getLongString,
-      getTabTarget,
-      requestData,
-      getTimingMarker,
-    } = this.props.connector;
-    let { form: { title, url } } = getTabTarget();
-
     return {
-      getString: getLongString,
+      connector: this.props.connector,
       items: sortedRequests,
-      requestData,
-      getTimingMarker,
-      title: title || url,
     };
   }
 }
 
 module.exports = RequestListContextMenu;
--- a/devtools/client/shared/inplace-editor.js
+++ b/devtools/client/shared/inplace-editor.js
@@ -1521,75 +1521,75 @@ InplaceEditor.prototype = {
 };
 
 /**
  * Copy text-related styles from one element to another.
  */
 function copyTextStyles(from, to) {
   let win = from.ownerDocument.defaultView;
   let style = win.getComputedStyle(from);
-  let getCssText = name => style.getPropertyCSSValue(name).cssText;
 
-  to.style.fontFamily = getCssText("font-family");
-  to.style.fontSize = getCssText("font-size");
-  to.style.fontWeight = getCssText("font-weight");
-  to.style.fontStyle = getCssText("font-style");
+  to.style.fontFamily = style.fontFamily;
+  to.style.fontSize = style.fontSize;
+  to.style.fontWeight = style.fontWeight;
+  to.style.fontStyle = style.fontStyle;
 }
 
 /**
  * Copy all styles which could have an impact on the element size.
  */
 function copyAllStyles(from, to) {
   let win = from.ownerDocument.defaultView;
   let style = win.getComputedStyle(from);
-  let getCssText = name => style.getPropertyCSSValue(name).cssText;
 
   copyTextStyles(from, to);
-  to.style.lineHeight = getCssText("line-height");
+  to.style.lineHeight = style.lineHeight;
 
   // If box-sizing is set to border-box, box model styles also need to be
   // copied.
-  let boxSizing = getCssText("box-sizing");
+  let boxSizing = style.boxSizing;
   if (boxSizing === "border-box") {
     to.style.boxSizing = boxSizing;
     copyBoxModelStyles(from, to);
   }
 }
 
 /**
  * Copy box model styles that can impact width and height measurements when box-
  * sizing is set to "border-box" instead of "content-box".
  *
  * @param {DOMNode} from
  *        the element from which styles are copied
  * @param {DOMNode} to
  *        the element on which copied styles are applied
  */
 function copyBoxModelStyles(from, to) {
+  let properties = [
+    // Copy all paddings.
+    "paddingTop",
+    "paddingRight",
+    "paddingBottom",
+    "paddingLeft",
+    // Copy border styles.
+    "borderTopStyle",
+    "borderRightStyle",
+    "borderBottomStyle",
+    "borderLeftStyle",
+    // Copy border widths.
+    "borderTopWidth",
+    "borderRightWidth",
+    "borderBottomWidth",
+    "borderLeftWidth"
+  ];
+
   let win = from.ownerDocument.defaultView;
   let style = win.getComputedStyle(from);
-  let getCssText = name => style.getPropertyCSSValue(name).cssText;
-
-  // Copy all paddings.
-  to.style.paddingTop = getCssText("padding-top");
-  to.style.paddingRight = getCssText("padding-right");
-  to.style.paddingBottom = getCssText("padding-bottom");
-  to.style.paddingLeft = getCssText("padding-left");
-
-  // Copy border styles.
-  to.style.borderTopStyle = getCssText("border-top-style");
-  to.style.borderRightStyle = getCssText("border-right-style");
-  to.style.borderBottomStyle = getCssText("border-bottom-style");
-  to.style.borderLeftStyle = getCssText("border-left-style");
-
-  // Copy border widths.
-  to.style.borderTopWidth = getCssText("border-top-width");
-  to.style.borderRightWidth = getCssText("border-right-width");
-  to.style.borderBottomWidth = getCssText("border-bottom-width");
-  to.style.borderLeftWidth = getCssText("border-left-width");
+  for (let property of properties) {
+    to.style[property] = style[property];
+  }
 }
 
 /**
  * Trigger a focus change similar to pressing tab/shift-tab.
  */
 function moveFocus(win, direction) {
   return focusManager.moveFocus(win, null, direction, 0);
 }
--- a/devtools/client/shared/test/browser_inplace-editor_maxwidth.js
+++ b/devtools/client/shared/test/browser_inplace-editor_maxwidth.js
@@ -92,18 +92,17 @@ let testMaxWidth = Task.async(function* 
  * Retrieve the current number of lines displayed in the provided textarea.
  *
  * @param {DOMNode} textarea
  * @return {Number} the number of lines
  */
 function getLines(textarea) {
   let win = textarea.ownerDocument.defaultView;
   let style = win.getComputedStyle(textarea);
-  let lineHeight = style.getPropertyCSSValue("line-height").cssText;
-  return Math.floor(textarea.clientHeight / parseFloat(lineHeight));
+  return Math.floor(textarea.clientHeight / parseFloat(style.lineHeight));
 }
 
 /**
  * Verify that the provided textarea has no vertical or horizontal scrollbar.
  *
  * @param {DOMNode} textarea
  */
 function checkScrollbars(textarea) {
--- a/devtools/client/webconsole/utils.js
+++ b/devtools/client/webconsole/utils.js
@@ -91,20 +91,20 @@ var WebConsoleUtils = {
    * @param nsIDOMNode from
    *        The target node.
    * @param nsIDOMNode to
    *        The destination node.
    */
   copyTextStyles: function (from, to) {
     let win = from.ownerDocument.defaultView;
     let style = win.getComputedStyle(from);
-    to.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
-    to.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
-    to.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
-    to.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
+    to.style.fontFamily = style.fontFamily;
+    to.style.fontSize = style.fontSize;
+    to.style.fontWeight = style.fontWeight;
+    to.style.fontStyle = style.fontStyle;
   },
 
   /**
    * Determine if the given request mixes HTTP with HTTPS content.
    *
    * @param string request
    *        Location of the requested content.
    * @param string location
--- a/devtools/server/actors/highlighters/flexbox.js
+++ b/devtools/server/actors/highlighters/flexbox.js
@@ -456,23 +456,23 @@ class FlexboxHighlighter extends AutoRef
     this.ctx.save();
     this.ctx.translate(offset - canvasX, offset - canvasY);
     this.ctx.lineWidth = lineWidth;
     this.ctx.strokeStyle = DEFAULT_COLOR;
 
     let { bounds } = this.currentQuads.content[0];
     let flexLines = this.currentNode.getAsFlexContainer().getLines();
     let computedStyle = getComputedStyle(this.currentNode);
-    let direction = computedStyle.getPropertyValue("flex-direction");
+    let isColumn = computedStyle.getPropertyValue("flex-direction").startsWith("column");
     let options = { matrix: this.currentMatrix };
 
     for (let flexLine of flexLines) {
       let { crossStart, crossSize } = flexLine;
 
-      if (direction.startsWith("column")) {
+      if (isColumn) {
         clearRect(this.ctx, crossStart, 0, crossStart + crossSize, bounds.height,
           this.currentMatrix);
 
         // Avoid drawing the start flex line when they overlap with the flex container.
         if (crossStart != 0) {
           drawLine(this.ctx, crossStart, 0, crossStart, bounds.height, options);
           this.ctx.stroke();
         }
@@ -506,81 +506,69 @@ class FlexboxHighlighter extends AutoRef
   }
 
   renderJustifyContent() {
     if (!this.currentQuads.content || !this.currentQuads.content[0]) {
       return;
     }
 
     let { bounds } = this.currentQuads.content[0];
-    let flexItems = this.currentNode.children;
     let flexLines = this.currentNode.getAsFlexContainer().getLines();
     let computedStyle = getComputedStyle(this.currentNode);
-    let direction = computedStyle.getPropertyValue("flex-direction");
+    let isColumn = computedStyle.getPropertyValue("flex-direction").startsWith("column");
 
     // Render the justify-content area by first highlighting all the content, and
     // clearing the occupied and margin areas of the flex item.
 
     // First, highlight all the content.
     for (let flexLine of flexLines) {
       let { crossStart, crossSize } = flexLine;
 
-      if (direction.startsWith("column")) {
+      if (isColumn) {
         this.drawJustifyContent(crossStart, 0, crossStart + crossSize, bounds.height);
       } else {
         this.drawJustifyContent(0, crossStart, bounds.width, crossStart + crossSize);
       }
     }
 
-    for (let flexItem of flexItems) {
-      let quads = getAdjustedQuads(this.win, flexItem, "border");
+    // Then, cut all the items out of this content area.
+    for (let flexLine of flexLines) {
+      let flexItems = flexLine.getItems();
 
-      if (!quads.length) {
-        continue;
-      }
+      for (let flexItem of flexItems) {
+        let { node } = flexItem;
+
+        let quads = getAdjustedQuads(this.win, node, "margin");
 
-      // Adjust the flex item bounds relative to the current quads.
-      let { bounds: flexItemBounds } = quads[0];
-      let left = Math.round(flexItemBounds.left - bounds.left);
-      let top = Math.round(flexItemBounds.top - bounds.top);
-      let right = Math.round(flexItemBounds.right - bounds.left);
-      let bottom = Math.round(flexItemBounds.bottom - bounds.top);
-      let flexItemComputedStyle = getComputedStyle(flexItem);
+        if (!quads.length) {
+          continue;
+        }
 
-      // Clear the occupied and margin areas of the flex item.
-      for (let flexLine of flexLines) {
+        // Adjust the flex item bounds relative to the current quads.
+        let { bounds: flexItemBounds } = quads[0];
+        let left = Math.round(flexItemBounds.left - bounds.left);
+        let top = Math.round(flexItemBounds.top - bounds.top);
+        let right = Math.round(flexItemBounds.right - bounds.left);
+        let bottom = Math.round(flexItemBounds.bottom - bounds.top);
+
+        // Clear the occupied and margin areas of the flex item.
         let { crossStart, crossSize } = flexLine;
         crossSize = Math.round(crossSize);
         crossStart = Math.round(crossStart);
 
-        if (direction.startsWith("column") &&
-            crossStart <= left &&
-            left <= right &&
-            right <= crossSize + crossStart) {
-          // Remove the margin area for justify-content
-          let marginTop = Math.round(parseFloat(
-            flexItemComputedStyle.getPropertyValue("margin-top")));
-          let marginBottom = Math.round(parseFloat(
-            flexItemComputedStyle.getPropertyValue("margin-bottom")));
-          clearRect(this.ctx, crossStart, top - marginTop, crossSize + crossStart,
-            bottom + marginBottom, this.currentMatrix);
-          break;
-        } else if (crossStart <= top &&
-                   top <= bottom &&
-                   bottom <= crossSize + crossStart) {
-          let marginLeft = Math.round(parseFloat(
-            flexItemComputedStyle.getPropertyValue("margin-left")));
-          let marginRight = Math.round(parseFloat(
-            flexItemComputedStyle.getPropertyValue("margin-right")));
-          clearRect(this.ctx, left - marginLeft, crossStart, right + marginRight,
-            crossSize + crossStart, this.currentMatrix);
-          break;
+        if (isColumn) {
+          clearRect(this.ctx, crossStart, top, crossSize + crossStart, bottom,
+            this.currentMatrix);
+        } else {
+          clearRect(this.ctx, left, crossStart, right, crossSize + crossStart,
+            this.currentMatrix);
         }
       }
     }
+
     this.ctx.restore();
   }
 
   _update() {
     setIgnoreLayoutChanges(true);
 
     let root = this.getElement("root");
 
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -597,23 +597,16 @@ Animation::Finish(ErrorResult& aRv)
 
 void
 Animation::Play(ErrorResult& aRv, LimitBehavior aLimitBehavior)
 {
   PlayNoUpdate(aRv, aLimitBehavior);
   PostUpdate();
 }
 
-void
-Animation::Pause(ErrorResult& aRv)
-{
-  PauseNoUpdate(aRv);
-  PostUpdate();
-}
-
 // https://drafts.csswg.org/web-animations/#reverse-an-animation
 void
 Animation::Reverse(ErrorResult& aRv)
 {
   if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
@@ -1219,17 +1212,17 @@ Animation::PlayNoUpdate(ErrorResult& aRv
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
   if (IsRelevant()) {
     nsNodeUtils::AnimationChanged(this);
   }
 }
 
 // https://drafts.csswg.org/web-animations/#pause-an-animation
 void
-Animation::PauseNoUpdate(ErrorResult& aRv)
+Animation::Pause(ErrorResult& aRv)
 {
   if (IsPausedOrPausing()) {
     return;
   }
 
   AutoMutationBatchForAnimation mb(*this);
 
   // If we are transitioning from idle, fill in the current time
@@ -1266,16 +1259,18 @@ Animation::PauseNoUpdate(ErrorResult& aR
   } else {
     TriggerOnNextTick(Nullable<TimeDuration>());
   }
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
   if (IsRelevant()) {
     nsNodeUtils::AnimationChanged(this);
   }
+
+  PostUpdate();
 }
 
 // https://drafts.csswg.org/web-animations/#play-an-animation
 void
 Animation::ResumeAt(const TimeDuration& aReadyTime)
 {
   // This method is only expected to be called for an animation that is
   // waiting to play. We can easily adapt it to handle other states
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -401,17 +401,16 @@ public:
    * exist when we would normally go to queue events on the next tick.
    */
   virtual void MaybeQueueCancelEvent(const StickyTimeDuration& aActiveTime) {};
 
 protected:
   void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
   void CancelNoUpdate();
   void PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior);
-  void PauseNoUpdate(ErrorResult& aRv);
   void ResumeAt(const TimeDuration& aReadyTime);
   void PauseAt(const TimeDuration& aReadyTime);
   void FinishPendingAt(const TimeDuration& aReadyTime)
   {
     if (mPendingState == PendingState::PlayPending) {
       ResumeAt(aReadyTime);
     } else if (mPendingState == PendingState::PausePending) {
       PauseAt(aReadyTime);
--- a/dom/animation/AnimationEffectReadOnly.h
+++ b/dom/animation/AnimationEffectReadOnly.h
@@ -46,19 +46,19 @@ public:
   {
     return nullptr;
   }
 
   nsISupports* GetParentObject() const { return mDocument; }
 
   bool IsCurrent() const;
   bool IsInEffect() const;
-  bool IsActiveDurationZero() const
+  bool HasFiniteActiveDuration() const
   {
-    return !SpecifiedTiming().ActiveDuration();
+    return SpecifiedTiming().ActiveDuration() != TimeDuration::Forever();
   }
 
   already_AddRefed<AnimationEffectTimingReadOnly> Timing();
   const TimingParams& SpecifiedTiming() const
   {
     return mTiming->AsTimingParams();
   }
   void SetSpecifiedTiming(const TimingParams& aTiming);
--- a/dom/animation/ComputedTimingFunction.h
+++ b/dom/animation/ComputedTimingFunction.h
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ComputedTimingFunction_h
 #define mozilla_ComputedTimingFunction_h
 
 #include "nsSMILKeySpline.h"  // nsSMILKeySpline
-#include "nsStyleStruct.h"    // nsTimingFunction
+#include "nsTimingFunction.h"
 
 namespace mozilla {
 
 class ComputedTimingFunction
 {
 public:
   static ComputedTimingFunction
   CubicBezier(double x1, double y1, double x2, double y2)
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1468,16 +1468,23 @@ KeyframeEffectReadOnly::CanThrottle() co
 
     const bool isVisibilityHidden =
       !frame->IsVisibleOrMayHaveVisibleDescendants();
     if (isVisibilityHidden ||
         frame->IsScrolledOutOfView()) {
       // If there are transform change hints, unthrottle the animation
       // periodically since it might affect the overflow region.
       if (HasTransformThatMightAffectOverflow()) {
+        // Don't throttle finite transform animations since the animation might
+        // suddenly come into view and if it was throttled it will be
+        // out-of-sync.
+        if (HasFiniteActiveDuration()) {
+          return false;
+        }
+
         return isVisibilityHidden
           ? CanThrottleTransformChangesInScrollable(*frame)
           : CanThrottleTransformChanges(*frame);
       }
       return true;
     }
   }
 
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -399,17 +399,17 @@ waitForAllPaints(() => {
         return;
       }
 
       await SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] });
 
       var parentElement = addDiv(null,
         { style: 'overflow-y: scroll; height: 20px;' });
       var div = addDiv(null,
-        { style: 'animation: rotate 100s; position: relative; top: 100px;' });
+        { style: 'animation: rotate 100s infinite; position: relative; top: 100px;' });
       parentElement.appendChild(div);
       var animation = div.getAnimations()[0];
       var timeAtStart = document.timeline.currentTime;
 
       ok(!animation.isRunningOnCompositor,
          'The transform animation is not running on the compositor');
 
       var markers;
@@ -445,17 +445,17 @@ waitForAllPaints(() => {
       await SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] });
 
       // Make sure we start from the state right after requestAnimationFrame.
       await waitForFrame();
 
       var parentElement = addDiv(null,
         { style: 'overflow-y: scroll; height: 20px;' });
       var div = addDiv(null,
-        { style: 'animation: rotate 100s; position: relative; top: 100px;' });
+        { style: 'animation: rotate 100s infinite; position: relative; top: 100px;' });
       parentElement.appendChild(div);
       var animation = div.getAnimations()[0];
       var timeAtStart = document.timeline.currentTime;
 
       ok(!animation.isRunningOnCompositor,
          'The transform animation is not running on the compositor');
 
       var markers;
@@ -498,17 +498,17 @@ waitForAllPaints(() => {
       // conformant Promise micro task.
       if (isAndroid) {
         return;
       }
 
       var parentElement = addDiv(null,
         { style: 'overflow: hidden;' });
       var div = addDiv(null,
-        { style: 'animation: move-in 100s;' });
+        { style: 'animation: move-in 100s infinite;' });
       parentElement.appendChild(div);
       var animation = div.getAnimations()[0];
       var timeAtStart = document.timeline.currentTime;
 
       ok(!animation.isRunningOnCompositor,
          'The transform animation on out of view element ' +
          'is not running on the compositor');
 
@@ -543,17 +543,17 @@ waitForAllPaints(() => {
       }
 
       // Make sure we start from the state right after requestAnimationFrame.
       await waitForFrame();
 
       var parentElement = addDiv(null,
         { style: 'overflow: hidden;' });
       var div = addDiv(null,
-        { style: 'animation: move-in 100s;' });
+        { style: 'animation: move-in 100s infinite;' });
       parentElement.appendChild(div);
       var animation = div.getAnimations()[0];
       var timeAtStart = document.timeline.currentTime;
 
       ok(!animation.isRunningOnCompositor,
          'The transform animation on out of view element ' +
          'is not running on the compositor');
 
@@ -580,16 +580,37 @@ waitForAllPaints(() => {
          'Transform animation running on out of view element ' +
          'should be unthrottled after around 200ms have elapsed. now: ' +
          now + ' start time: ' + timeAtStart);
 
       await ensureElementRemoval(parentElement);
     }
   );
 
+  add_task(async function finite_transform_animations_in_out_of_view_element() {
+    var parentElement = addDiv(null, { style: 'overflow: hidden;' });
+    var div = addDiv(null);
+    var animation =
+      div.animate({ transform: [ 'translateX(120%)', 'translateX(100%)' ] },
+                                // This animation will move a bit but
+                                // will remain out-of-view.
+                  100 * MS_PER_SEC);
+    parentElement.appendChild(div);
+
+    await animation.ready;
+    ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
+
+    var markers = await observeStyling(20);
+    is(markers.length, 20,
+       'Finite transform animation in out-of-view element should never be ' +
+       'throttled');
+
+    await ensureElementRemoval(parentElement);
+  });
+
   add_task(async function restyling_main_thread_animations_in_scrolled_out_element() {
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var div = addDiv(null,
       { style: 'animation: background-color 100s; position: relative; top: 20px;' });
     parentElement.appendChild(div);
     var animation = div.getAnimations()[0];
 
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -7423,17 +7423,17 @@ nsGlobalWindowInner::PromiseDocumentFlus
   RefPtr<Promise> resultPromise = Promise::Create(global, aError);
   if (aError.Failed()) {
     return nullptr;
   }
 
   UniquePtr<PromiseDocumentFlushedResolver> flushResolver(
     new PromiseDocumentFlushedResolver(resultPromise, aCallback));
 
-  if (!shell->NeedStyleFlush() && !shell->NeedLayoutFlush()) {
+  if (!shell->NeedFlush(FlushType::Style)) {
     flushResolver->Call();
     return resultPromise.forget();
   }
 
   if (!mObservingDidRefresh) {
     bool success = shell->AddPostRefreshObserver(this);
     if (!success) {
       aError.Throw(NS_ERROR_FAILURE);
@@ -7518,21 +7518,20 @@ nsGlobalWindowInner::DidRefresh()
     mObservingDidRefresh = false;
   });
 
   MOZ_ASSERT(mDoc);
 
   nsIPresShell* shell = mDoc->GetShell();
   MOZ_ASSERT(shell);
 
-  if (shell->NeedStyleFlush() || shell->NeedLayoutFlush()) {
+  if (shell->NeedStyleFlush() || shell->HasPendingReflow()) {
     // By the time our observer fired, something has already invalidated
-    // style or layout - or perhaps we're still in the middle of a flush that
-    // was interrupted. In either case, we'll wait until the next refresh driver
-    // tick instead and try again.
+    // style and maybe layout. We'll wait until the next refresh driver
+    // tick instead.
     rejectionGuard.release();
     return;
   }
 
   bool success = shell->RemovePostRefreshObserver(this);
   if (!success) {
     return;
   }
--- a/dom/base/test/browser_promiseDocumentFlushed.js
+++ b/dom/base/test/browser_promiseDocumentFlushed.js
@@ -26,30 +26,26 @@ const gWindowUtils = window.QueryInterfa
                            .getInterface(Ci.nsIDOMWindowUtils);
 
 /**
  * Asserts that no style or layout flushes are required by the
  * current window.
  */
 function assertNoFlushesRequired() {
   Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
-            "No style flushes are required.");
-  Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
-            "No layout flushes are required.");
+            "No flushes are required.");
 }
 
 /**
  * Asserts that the DOM has been dirtied, and so style and layout flushes
  * are required.
  */
 function assertFlushesRequired() {
-  Assert.ok(gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
-            "Style flush required.");
   Assert.ok(gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
-            "Layout flush required.");
+            "Style and layout flushes are required.");
 }
 
 /**
  * Removes style changes from dirtyTheDOM() from the browser window,
  * and resolves once the refresh driver ticks.
  */
 async function cleanTheDOM() {
   gNavToolbox.style.padding = "";
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -787,20 +787,16 @@ class RTCPeerConnection {
   createOffer(optionsOrOnSucc, onErr, options) {
     let onSuccess = null;
     if (typeof optionsOrOnSucc == "function") {
       onSuccess = optionsOrOnSucc;
     } else {
       options = optionsOrOnSucc;
     }
 
-    // Spec language implies that this needs to happen as if it were called
-    // before createOffer, so we do this as early as possible.
-    this._ensureTransceiversForOfferToReceive(options);
-
     // This entry-point handles both new and legacy call sig. Decipher which one
     if (onSuccess) {
       return this._legacy(onSuccess, onErr, () => this._createOffer(options));
     }
 
     return this._async(() => this._createOffer(options));
   }
 
@@ -841,16 +837,17 @@ class RTCPeerConnection {
         } else if (transceiver.direction == "recvonly") {
           transceiver.setDirectionInternal("inactive");
         }
       });
   }
 
   async _createOffer(options) {
     this._checkClosed();
+    this._ensureTransceiversForOfferToReceive(options);
     this._syncTransceivers();
     let origin = Cu.getWebIDLCallerPrincipal().origin;
     return this._chain(async () => {
       let haveAssertion;
       if (this._localIdp.enabled) {
         haveAssertion = this._getIdentityAssertion(origin);
       }
       await this._getPermission();
--- a/dom/media/tests/mochitest/test_peerConnection_close.html
+++ b/dom/media/tests/mochitest/test_peerConnection_close.html
@@ -73,16 +73,20 @@
       var candidate = new RTCIceCandidate({ candidate: "dummy",
                                                sdpMid: "test",
                                                sdpMLineIndex: 3 });
 
       var doesFail = (p, msg) => p.then(generateErrorCallback(msg),
                                         r => is(r.name, "InvalidStateError", msg));
       Promise.all([
         [pc.createOffer(), "createOffer"],
+        [pc.createOffer({offerToReceiveAudio: true}), "createOffer({offerToReceiveAudio: true})"],
+        [pc.createOffer({offerToReceiveAudio: false}), "createOffer({offerToReceiveAudio: false})"],
+        [pc.createOffer({offerToReceiveVideo: true}), "createOffer({offerToReceiveVideo: true})"],
+        [pc.createOffer({offerToReceiveVideo: false}), "createOffer({offerToReceiveVideo: false})"],
         [pc.createAnswer(), "createAnswer"],
         [pc.setLocalDescription(offer), "setLocalDescription"],
         [pc.setRemoteDescription(answer), "setRemoteDescription"],
         [pc.addIceCandidate(candidate), "addIceCandidate"],
         [new Promise((y, n) => pc.createOffer(y, n)), "Legacy createOffer"],
         [new Promise((y, n) => pc.createAnswer(y, n)), "Legacy createAnswer"],
         [new Promise((y, n) => pc.setLocalDescription(offer, y, n)), "Legacy setLocalDescription"],
         [new Promise((y, n) => pc.setRemoteDescription(answer, y, n)), "Legacy setRemoteDescription"],
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -349,25 +349,16 @@ SVGAnimationElement::AfterSetAttr(int32_
 
 bool
 SVGAnimationElement::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~eANIMATION);
 }
 
 //----------------------------------------------------------------------
-// SVGTests methods
-
-bool
-SVGAnimationElement::IsInChromeDoc() const
-{
-  return nsContentUtils::IsChromeDoc(OwnerDoc());
-}
-
-//----------------------------------------------------------------------
 // SVG utility methods
 
 void
 SVGAnimationElement::ActivateByHyperlink()
 {
   FlushAnimations();
 
   // The behavior for when the target is an animation element is defined in
--- a/dom/svg/SVGAnimationElement.h
+++ b/dom/svg/SVGAnimationElement.h
@@ -83,17 +83,16 @@ public:
   float GetCurrentTime();
   float GetSimpleDuration(ErrorResult& rv);
   void BeginElement(ErrorResult& rv) { BeginElementAt(0.f, rv); }
   void BeginElementAt(float offset, ErrorResult& rv);
   void EndElement(ErrorResult& rv) { EndElementAt(0.f, rv); }
   void EndElementAt(float offset, ErrorResult& rv);
 
   // SVGTests
-  virtual bool IsInChromeDoc() const override;
   nsSVGElement* AsSVGElement() final { return this; }
 
  protected:
   // nsSVGElement overrides
 
   void UpdateHrefTarget(nsIContent* aNodeForContext,
                         const nsAString& aHrefStr);
   void AnimationTargetChanged();
--- a/dom/svg/SVGGraphicsElement.cpp
+++ b/dom/svg/SVGGraphicsElement.cpp
@@ -26,16 +26,10 @@ SVGGraphicsElement::SVGGraphicsElement(a
   : SVGGraphicsElementBase(aNodeInfo)
 {
 }
 
 SVGGraphicsElement::~SVGGraphicsElement()
 {
 }
 
-bool
-SVGGraphicsElement::IsInChromeDoc() const
-{
-  return nsContentUtils::IsChromeDoc(OwnerDoc());
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/svg/SVGGraphicsElement.h
+++ b/dom/svg/SVGGraphicsElement.h
@@ -21,16 +21,15 @@ class SVGGraphicsElement : public SVGGra
 protected:
   explicit SVGGraphicsElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   ~SVGGraphicsElement();
 
 public:
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
-  bool IsInChromeDoc() const override;
   nsSVGElement* AsSVGElement() final { return this; }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGGraphicsElement_h
--- a/dom/svg/SVGSymbolElement.cpp
+++ b/dom/svg/SVGSymbolElement.cpp
@@ -37,19 +37,10 @@ SVGSymbolElement::~SVGSymbolElement()
 {
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSymbolElement)
 
-//----------------------------------------------------------------------
-// SVGTests methods
-
-bool
-SVGSymbolElement::IsInChromeDoc() const
-{
-  return nsContentUtils::IsChromeDoc(OwnerDoc());
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/svg/SVGSymbolElement.h
+++ b/dom/svg/SVGSymbolElement.h
@@ -27,17 +27,14 @@ protected:
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override;
-
-  // SVGTests
-  bool IsInChromeDoc() const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGSymbolElement_h
--- a/dom/svg/SVGTests.cpp
+++ b/dom/svg/SVGTests.cpp
@@ -46,17 +46,18 @@ SVGTests::SystemLanguage()
 {
   return DOMSVGStringList::GetDOMWrapper(
            &mStringListAttributes[LANGUAGE], AsSVGElement(), true, LANGUAGE);
 }
 
 bool
 SVGTests::HasExtension(const nsAString& aExtension)
 {
-  return nsSVGFeatures::HasExtension(aExtension, IsInChromeDoc());
+  return nsSVGFeatures::HasExtension(aExtension,
+                                     AsSVGElement()->IsInChromeDocument());
 }
 
 bool
 SVGTests::IsConditionalProcessingAttribute(const nsAtom* aAttribute) const
 {
   for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
     if (aAttribute == *sStringListNames[i]) {
       return true;
@@ -113,17 +114,18 @@ SVGTests::PassesConditionalProcessingTes
   // go beyond the feature set defined in the SVG specification.
   // Each extension is identified by a URI reference.
   // For now, claim that mozilla's SVG implementation supports XHTML and MathML.
   if (mStringListAttributes[EXTENSIONS].IsExplicitlySet()) {
     if (mStringListAttributes[EXTENSIONS].IsEmpty()) {
       return false;
     }
     for (uint32_t i = 0; i < mStringListAttributes[EXTENSIONS].Length(); i++) {
-      if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i], IsInChromeDoc())) {
+      if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i],
+                                       AsSVGElement()->IsInChromeDocument())) {
         return false;
       }
     }
   }
 
   if (aAcceptLangs == kIgnoreSystemLanguage) {
     return true;
   }
--- a/dom/svg/SVGTests.h
+++ b/dom/svg/SVGTests.h
@@ -91,19 +91,23 @@ public:
   void MaybeInvalidate();
 
   // WebIDL
   already_AddRefed<DOMSVGStringList> RequiredFeatures();
   already_AddRefed<DOMSVGStringList> RequiredExtensions();
   already_AddRefed<DOMSVGStringList> SystemLanguage();
   bool HasExtension(const nsAString& aExtension);
 
-  virtual bool IsInChromeDoc() const = 0;
   virtual nsSVGElement* AsSVGElement() = 0;
 
+  const nsSVGElement* AsSVGElement() const
+  {
+    return const_cast<SVGTests*>(this)->AsSVGElement();
+  }
+
 protected:
   virtual ~SVGTests() {}
 
 private:
   enum { FEATURES, EXTENSIONS, LANGUAGE };
   SVGStringList mStringListAttributes[3];
   static nsStaticAtom** sStringListNames[3];
 };
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -619,48 +619,30 @@ EditorBase::GetIsDocumentEditable(bool* 
 {
   NS_ENSURE_ARG_POINTER(aIsDocumentEditable);
   nsCOMPtr<nsIDocument> doc = GetDocument();
   *aIsDocumentEditable = doc && IsModifiable();
 
   return NS_OK;
 }
 
-already_AddRefed<nsIDocument>
-EditorBase::GetDocument()
-{
-  nsCOMPtr<nsIDocument> document = mDocument;
-  return document.forget();
-}
-
 already_AddRefed<nsIDOMDocument>
 EditorBase::GetDOMDocument()
 {
   nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(mDocument);
   return domDocument.forget();
 }
 
 NS_IMETHODIMP
 EditorBase::GetDocument(nsIDOMDocument** aDoc)
 {
   *aDoc = GetDOMDocument().take();
   return *aDoc ? NS_OK : NS_ERROR_NOT_INITIALIZED;
 }
 
-already_AddRefed<nsIPresShell>
-EditorBase::GetPresShell()
-{
-  nsCOMPtr<nsIDocument> document = GetDocument();
-  if (NS_WARN_IF(!document)) {
-    return nullptr;
-  }
-  nsCOMPtr<nsIPresShell> presShell = document->GetShell();
-  return presShell.forget();
-}
-
 already_AddRefed<nsIWidget>
 EditorBase::GetWidget()
 {
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, nullptr);
   nsPresContext* pc = ps->GetPresContext();
   NS_ENSURE_TRUE(pc, nullptr);
   nsCOMPtr<nsIWidget> widget = pc->GetRootWidget();
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -234,21 +234,24 @@ public:
   virtual nsresult Init(nsIDocument& doc,
                         Element* aRoot,
                         nsISelectionController* aSelCon,
                         uint32_t aFlags,
                         const nsAString& aInitialValue);
 
   bool IsInitialized() const { return !!mDocument; }
   already_AddRefed<nsIDOMDocument> GetDOMDocument();
-  already_AddRefed<nsIDocument> GetDocument();
-  already_AddRefed<nsIPresShell> GetPresShell();
-  nsPresContext* GetPresContext()
+  nsIDocument* GetDocument() const { return mDocument; }
+  nsIPresShell* GetPresShell() const
   {
-    RefPtr<nsIPresShell> presShell = GetPresShell();
+    return mDocument ? mDocument->GetShell() : nullptr;
+  }
+  nsPresContext* GetPresContext() const
+  {
+    nsIPresShell* presShell = GetPresShell();
     return presShell ? presShell->GetPresContext() : nullptr;
   }
   already_AddRefed<nsIWidget> GetWidget();
   nsISelectionController* GetSelectionController() const
   {
     if (mSelectionController) {
       return mSelectionController;
     }
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -294,25 +294,25 @@ EditorEventListener::UninstallFromEditor
   elmP->RemoveEventListenerByType(this,
                                   NS_LITERAL_STRING("compositionstart"),
                                   TrustedEventsAtSystemGroupBubble());
   elmP->RemoveEventListenerByType(this,
                                   NS_LITERAL_STRING("compositionend"),
                                   TrustedEventsAtSystemGroupBubble());
 }
 
-already_AddRefed<nsIPresShell>
-EditorEventListener::GetPresShell()
+nsIPresShell*
+EditorEventListener::GetPresShell() const
 {
   MOZ_ASSERT(!DetachedFromEditor());
   return mEditorBase->GetPresShell();
 }
 
 nsPresContext*
-EditorEventListener::GetPresContext()
+EditorEventListener::GetPresContext() const
 {
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   return presShell ? presShell->GetPresContext() : nullptr;
 }
 
 nsIContent*
 EditorEventListener::GetFocusedRootContent()
 {
--- a/editor/libeditor/EditorEventListener.h
+++ b/editor/libeditor/EditorEventListener.h
@@ -71,18 +71,18 @@ protected:
   nsresult Blur(InternalFocusEvent* aBlurEvent);
   nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
   nsresult DragOver(nsIDOMDragEvent* aDragEvent);
   nsresult DragExit(nsIDOMDragEvent* aDragEvent);
   nsresult Drop(nsIDOMDragEvent* aDragEvent);
 
   bool CanDrop(nsIDOMDragEvent* aEvent);
   void CleanupDragDropCaret();
-  already_AddRefed<nsIPresShell> GetPresShell();
-  nsPresContext* GetPresContext();
+  nsIPresShell* GetPresShell() const;
+  nsPresContext* GetPresContext() const;
   nsIContent* GetFocusedRootContent();
   // Returns true if IME consumes the mouse event.
   bool NotifyIMEOfMouseButtonEvent(WidgetMouseEvent* aMouseEvent);
   bool EditorHasFocus();
   bool IsFileControlTextBox();
   bool ShouldHandleNativeKeyBindings(WidgetKeyboardEvent* aKeyboardEvent);
   nsresult HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent);
 
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -425,18 +425,18 @@ mozInlineSpellStatus::FillNoCheckRangeFr
                                    getter_AddRefs(mNoCheckRange));
 }
 
 // mozInlineSpellStatus::GetDocument
 //
 //    Returns the nsIDOMDocument object for the document for the
 //    current spellchecker.
 
-already_AddRefed<nsIDocument>
-mozInlineSpellStatus::GetDocument()
+nsIDocument*
+mozInlineSpellStatus::GetDocument() const
 {
   if (!mSpellChecker->mTextEditor) {
     return nullptr;
   }
 
   return mSpellChecker->mTextEditor->GetDocument();
 }
 
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -99,17 +99,17 @@ public:
   // Contains the offset passed in to HandleNavigationEvent
   int32_t mNewNavigationPositionOffset;
 
 protected:
   nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil);
 
   nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
 
-  already_AddRefed<nsIDocument> GetDocument();
+  nsIDocument* GetDocument() const;
   already_AddRefed<nsRange> PositionToCollapsedRange(nsINode* aNode,
                                                      uint32_t aOffset);
 };
 
 class mozInlineSpellChecker final : public nsIInlineSpellChecker,
                                     public nsIDOMEventListener,
                                     public nsSupportsWeakReference
 {
--- a/gfx/angle/moz.build.common
+++ b/gfx/angle/moz.build.common
@@ -1,6 +1,7 @@
 AllowCompilerWarnings()
 
-CXXFLAGS += CONFIG['SSE2_FLAGS']
+if CONFIG['INTEL_ARCHITECTURE']:
+    CXXFLAGS += CONFIG['SSE2_FLAGS']
 DEFINES['__NDK_FPABI__'] = ''
 DEFINES['constexpr14'] = ''
 DEFINES['ANGLE_SKIP_DXGI_1_2_CHECK'] = True
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -38,17 +38,16 @@
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
 #include "mozilla/layers/LayersTypes.h"  // for TextureDumpMode
 #include "mozilla/layers/PersistentBufferProvider.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowableLayer
 #include "nsAString.h"
 #include "nsCSSValue.h"                 // for nsCSSValue::Array, etc
 #include "nsDisplayList.h"              // for nsDisplayItem
 #include "nsPrintfCString.h"            // for nsPrintfCString
-#include "nsStyleStruct.h"              // for nsTimingFunction, etc
 #include "protobuf/LayerScopePacket.pb.h"
 #include "mozilla/Compression.h"
 #include "TreeTraversal.h"              // for ForEachNode
 
 #include <list>
 #include <set>
 
 uint8_t gLayerManagerLayerBuilder;
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -235,17 +235,17 @@ APZCTreeManager::APZCTreeManager(uint64_
   RefPtr<APZCTreeManager> self(this);
   NS_DispatchToMainThread(
     NS_NewRunnableFunction("layers::APZCTreeManager::APZCTreeManager", [self] {
       self->mFlushObserver = new CheckerboardFlushObserver(self);
     }));
   AsyncPanZoomController::InitializeGlobalState();
   mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
 #if defined(MOZ_WIDGET_ANDROID)
-  mToolbarAnimator = new AndroidDynamicToolbarAnimator();
+  mToolbarAnimator = new AndroidDynamicToolbarAnimator(this);
 #endif // (MOZ_WIDGET_ANDROID)
 }
 
 APZCTreeManager::~APZCTreeManager()
 {
 }
 
 void
@@ -2020,16 +2020,20 @@ APZCTreeManager::AdjustScrollForSurfaceS
   }
 }
 
 void
 APZCTreeManager::ClearTree()
 {
   APZThreadUtils::AssertOnSamplerThread();
 
+#if defined(MOZ_WIDGET_ANDROID)
+  mToolbarAnimator->ClearTreeManager();
+#endif
+
   // Ensure that no references to APZCs are alive in any lingering input
   // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
   // the InputQueue.
   APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
     "layers::InputQueue::Clear", mInputQueue, &InputQueue::Clear));
 
   RecursiveMutexAutoLock lock(mTreeLock);
 
@@ -2981,23 +2985,16 @@ APZCTreeManager::GetAPZTestData(uint64_t
   if (it == mTestData.end()) {
     return false;
   }
   *aOutData = *(it->second);
   return true;
 }
 
 #if defined(MOZ_WIDGET_ANDROID)
-void
-APZCTreeManager::InitializeDynamicToolbarAnimator(const int64_t& aRootLayerTreeId)
-{
-  MOZ_ASSERT(mToolbarAnimator);
-  mToolbarAnimator->Initialize(aRootLayerTreeId);
-}
-
 AndroidDynamicToolbarAnimator*
 APZCTreeManager::GetAndroidDynamicToolbarAnimator()
 {
   return mToolbarAnimator;
 }
 #endif // defined(MOZ_WIDGET_ANDROID)
 
 } // namespace layers
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -712,17 +712,16 @@ private:
   // protected by the mTestDataLock.
   std::unordered_map<uint64_t, UniquePtr<APZTestData>> mTestData;
   mutable mozilla::Mutex mTestDataLock;
 
   static float sDPI;
 
 #if defined(MOZ_WIDGET_ANDROID)
 public:
-  void InitializeDynamicToolbarAnimator(const int64_t& aRootLayerTreeId);
   AndroidDynamicToolbarAnimator* GetAndroidDynamicToolbarAnimator();
 
 private:
   RefPtr<AndroidDynamicToolbarAnimator> mToolbarAnimator;
 #endif // defined(MOZ_WIDGET_ANDROID)
 };
 
 } // namespace layers
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
@@ -34,18 +34,19 @@ static const int32_t MOVE_TOOLBAR_DOWN  
 static const int32_t MOVE_TOOLBAR_UP    = -1;    // Multiplier to move the toolbar up
 static const float   SHRINK_FACTOR      = 0.95f; // Amount to shrink the either the full content for small pages or the amount left
                                                  // See: PageTooSmallEnsureToolbarVisible()
 } // namespace
 
 namespace mozilla {
 namespace layers {
 
-AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator()
+AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator(APZCTreeManager* aApz)
   : mRootLayerTreeId(0)
+  , mApz(aApz)
   // Read/Write Compositor Thread, Read only Controller thread
   , mToolbarState(eToolbarVisible)
   , mPinnedFlags(0)
   // Controller thread only
   , mControllerScrollingRootContent(false)
   , mControllerDragThresholdReached(false)
   , mControllerCancelTouchTracking(false)
   , mControllerDragChangedDirection(false)
@@ -90,16 +91,23 @@ AndroidDynamicToolbarAnimator::Initializ
 
   // Send queued messages that were posted before Initialize() was called.
   for (QueuedMessage* message = mCompositorQueuedMessages.getFirst(); message != nullptr; message = message->getNext()) {
     uiController->ToolbarAnimatorMessageFromCompositor(message->mMessage);
   }
   mCompositorQueuedMessages.clear();
 }
 
+void
+AndroidDynamicToolbarAnimator::ClearTreeManager()
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  mApz = nullptr;
+}
+
 static bool
 GetTouchY(MultiTouchInput& multiTouch, ScreenIntCoord* value)
 {
   MOZ_ASSERT(value);
   if (multiTouch.mTouches.Length() == 1) {
     *value = multiTouch.mTouches[0].mScreenPoint.y;
     return true;
   }
@@ -338,31 +346,32 @@ AndroidDynamicToolbarAnimator::UpdateAni
   if ((mToolbarState != eToolbarAnimating) || mCompositorShutdown) {
     return false;
   }
 
   CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
   if (!parent) {
     return false;
   }
+  MOZ_ASSERT(mApz); // because parent is non-null
 
   AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
   if (!manager) {
     return false;
   }
 
   if (mCompositorSurfaceHeight != mCompositorCompositionSize.height) {
     // Waiting for the composition to resize
     if (mCompositorWaitForPageResize && mCompositorAnimationStarted) {
       mCompositorWaitForPageResize = false;
     } else {
       return true;
     }
   } else if (!mCompositorAnimationStarted) {
-    parent->GetAPZCTreeManager()->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)(-mCompositorToolbarHeight)));
+    mApz->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)(-mCompositorToolbarHeight)));
     manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
     mCompositorAnimationStarted = true;
     mCompositorReceivedFirstPaint = false;
     mCompositorToolbarShowRequested = false;
     // Reset the start time so the toolbar does not jump on the first animation frame
     mCompositorAnimationStartTimeStamp = aCurrentFrame;
     // Since the delta time for this frame will be zero. Just return, the animation will start on the next frame.
     return true;
@@ -407,17 +416,17 @@ AndroidDynamicToolbarAnimator::UpdateAni
     mCompositorToolbarHeight = 0;
   }
 
   if (continueAnimating) {
     manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
   } else {
     if (mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) {
       if (!mCompositorReceivedFirstPaint) {
-        parent->GetAPZCTreeManager()->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)mCompositorMaxToolbarHeight));
+        mApz->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)mCompositorMaxToolbarHeight));
       }
       manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
     } else {
       manager->SetFixedLayerMargins(0, 0);
     }
   }
 
   if (!continueAnimating) {
@@ -628,19 +637,18 @@ AndroidDynamicToolbarAnimator::ProcessTo
     // If there was no delta left over, the event was completely consumed.
     if (deltaRemainder == 0) {
       status = nsEventStatus_eConsumeNoDefault;
     }
 
     uint32_t timeDelta = aTimeStamp - mControllerLastEventTimeStamp;
     if (mControllerLastEventTimeStamp && timeDelta && aDelta) {
       float speed = -(float)aDelta / (float)timeDelta;
-      CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
-      if (parent) {
-        parent->GetAPZCTreeManager()->ProcessTouchVelocity(aTimeStamp, speed);
+      if (mApz) {
+        mApz->ProcessTouchVelocity(aTimeStamp, speed);
       }
     }
   }
 
   return status;
 }
 
 void
@@ -885,19 +893,18 @@ AndroidDynamicToolbarAnimator::StartComp
     mToolbarState = eToolbarAnimating;
     if (initialToolbarState != eToolbarAnimating) {
       mCompositorAnimationStarted = false;
     }
     // Let the controller know we are starting an animation so it may clear the AnimationStartPending flag.
     NotifyControllerAnimationStarted();
     // Only reset the time stamp and start compositor animation if not already animating.
     if (initialToolbarState != eToolbarAnimating) {
-      CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
-      if (parent) {
-        mCompositorAnimationStartTimeStamp = parent->GetAPZCTreeManager()->GetFrameTime();
+      if (mApz) {
+        mCompositorAnimationStartTimeStamp = mApz->GetFrameTime();
       }
       // Kick the compositor to start the animation if we aren't already animating.
       RequestComposite();
     }
   }
 }
 
 void
@@ -928,18 +935,19 @@ AndroidDynamicToolbarAnimator::StopCompo
 
   if (mToolbarState == eToolbarAnimating) {
     if (mCompositorAnimationStarted) {
       mCompositorAnimationStarted = false;
       CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
       if (parent) {
         AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
         if (manager) {
-            parent->GetAPZCTreeManager()->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)(mCompositorToolbarHeight)));
-            RequestComposite();
+          MOZ_ASSERT(mApz);
+          mApz->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)(mCompositorToolbarHeight)));
+          RequestComposite();
         }
       }
     }
     mToolbarState = eToolbarUnlocked;
   }
 
   NotifyControllerAnimationStopped(mCompositorToolbarHeight);
 }
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.h
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.h
@@ -17,16 +17,17 @@
 #include "mozilla/Maybe.h"
 #include "mozilla/TimeStamp.h"
 #include "nsISupports.h"
 
 namespace mozilla {
 namespace layers {
 
 struct FrameMetrics;
+class APZCTreeManager;
 class CompositorOGL;
 
 /*
  * The AndroidDynamicToolbarAnimator is responsible for calculating the position
  * and drawing the static snapshot of the toolbar. The animator lives in both
  * compositor thread and controller thread. It intercepts input events in the
  * controller thread and determines if the intercepted touch events will cause
  * the toolbar to move or be animated. Once the proper conditions have been met,
@@ -46,18 +47,19 @@ class CompositorOGL;
  * toolbar be hidden in order to unlock the static snapshot and begin translating it.
  *
  * See Bug 1335895 for more details.
  */
 
 class AndroidDynamicToolbarAnimator {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidDynamicToolbarAnimator);
-  AndroidDynamicToolbarAnimator();
+  explicit AndroidDynamicToolbarAnimator(APZCTreeManager* aApz);
   void Initialize(uint64_t aRootLayerTreeId);
+  void ClearTreeManager();
   // Used to intercept events to determine if the event affects the toolbar.
   // May apply translation to touch events if the toolbar is visible.
   // Returns nsEventStatus_eIgnore when the event is not consumed and
   // nsEventStatus_eConsumeNoDefault when the event was used to translate the
   // toolbar.
   nsEventStatus ReceiveInputEvent(InputData& aEvent, const ScreenPoint& aScrollOffset);
   void SetMaxToolbarHeight(ScreenIntCoord aHeight);
   // When a pinned reason is set to true, the animator will prevent
@@ -162,16 +164,17 @@ protected:
   // Returns true if the page scroll offset is near the bottom.
   bool ScrollOffsetNearBottom() const;
   // Returns true if toolbar is not completely visible nor completely hidden.
   bool ToolbarInTransition();
   void QueueMessage(int32_t aMessage);
 
   // Read only Compositor and Controller threads after Initialize()
   uint64_t mRootLayerTreeId;
+  MOZ_NON_OWNING_REF APZCTreeManager* mApz;
 
   // Read/Write Compositor Thread, Read only Controller thread
   Atomic<StaticToolbarState> mToolbarState; // Current toolbar state.
   Atomic<uint32_t> mPinnedFlags;            // The toolbar should not be moved or animated unless no flags are set
 
   // Controller thread only
   bool mControllerScrollingRootContent; // Set to true when the root content is being scrolled
   bool mControllerDragThresholdReached; // Set to true when the drag threshold has been passed in a single drag
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -67,17 +67,17 @@
 #include "mozilla/FloatingPoint.h"      // for FuzzyEquals*
 #include "nsAlgorithm.h"                // for clamped
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsIDOMWindowUtils.h"          // for nsIDOMWindowUtils
 #include "nsMathUtils.h"                // for NS_hypot
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsStyleConsts.h"
-#include "nsStyleStruct.h"              // for nsTimingFunction
+#include "nsTimingFunction.h"
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "nsThreadUtils.h"              // for NS_IsMainThread
 #include "nsViewportInfo.h"             // for kViewportMinScale, kViewportMaxScale
 #include "prsystem.h"                   // for PR_GetPhysicalMemorySize
 #include "SharedMemoryBasic.h"          // for SharedMemoryBasic
 #include "ScrollSnap.h"                 // for ScrollSnapUtils
 #include "ScrollAnimationPhysics.h"     // for ComputeAcceleratedWheelDelta
 #include "WheelScrollAnimation.h"
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -34,17 +34,16 @@
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "UnitTransforms.h"             // for TransformTo
 #include "gfxPrefs.h"
 #if defined(MOZ_WIDGET_ANDROID)
 # include <android/log.h>
-# include "apz/src/APZCTreeManager.h"
 # include "mozilla/layers/UiCompositorControllerParent.h"
 # include "mozilla/widget/AndroidCompositorWidget.h"
 #endif
 #include "GeckoProfiler.h"
 #include "FrameUniformityData.h"
 #include "TreeTraversal.h"              // for ForEachNode, BreadthFirstSearch
 #include "VsyncSource.h"
 
@@ -935,17 +934,17 @@ AsyncCompositionManager::ApplyAsyncConte
           if (!(*aOutFoundRoot)) {
             *aOutFoundRoot = metrics.IsRootContent() ||       /* RCD */
                   (layer->GetParent() == nullptr &&          /* rootmost metrics */
                    i + 1 >= layer->GetScrollMetadataCount());
             if (*aOutFoundRoot) {
               mRootScrollableId = metrics.GetScrollId();
               Compositor* compositor = mLayerManager->GetCompositor();
               if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
-                AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
+                AndroidDynamicToolbarAnimator* animator = bridge->GetAndroidDynamicToolbarAnimator();
                 MOZ_ASSERT(animator);
                 if (mIsFirstPaint) {
                   animator->UpdateRootFrameMetrics(metrics);
                   animator->FirstPaint();
                   mIsFirstPaint = false;
                 }
                 if (mLayersUpdated) {
                   animator->NotifyLayersUpdated();
@@ -1402,17 +1401,17 @@ AsyncCompositionManager::TransformShadow
   MOZ_ASSERT(aVsyncRate != TimeDuration::Forever());
   if (aVsyncRate != TimeDuration::Forever()) {
     nextFrame += aVsyncRate;
   }
 
 #if defined(MOZ_WIDGET_ANDROID)
   Compositor* compositor = mLayerManager->GetCompositor();
   if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
-    AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
+    AndroidDynamicToolbarAnimator* animator = bridge->GetAndroidDynamicToolbarAnimator();
     MOZ_ASSERT(animator);
     wantNextFrame |= animator->UpdateAnimation(nextFrame);
   }
 #endif // defined(MOZ_WIDGET_ANDROID)
 
   // Reset the previous time stamp if we don't already have any running
   // animations to avoid using the time which is far behind for newly
   // started animations.
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -52,17 +52,16 @@
 #include "nsDebug.h"                    // for NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegion.h"                   // for nsIntRegion, etc
 #if defined(MOZ_WIDGET_ANDROID)
 #include <android/log.h>
 #include <android/native_window.h>
-#include "apz/src/APZCTreeManager.h"
 #include "mozilla/widget/AndroidCompositorWidget.h"
 #include "opengl/CompositorOGL.h"
 #include "GLConsts.h"
 #include "GLContextEGL.h"
 #include "GLContextProvider.h"
 #include "mozilla/Unused.h"
 #include "mozilla/widget/AndroidCompositorWidget.h"
 #include "ScopedGLHelpers.h"
@@ -1167,33 +1166,33 @@ LayerManagerComposite::GetContentShiftFo
 {
   ScreenCoord result(0.0f);
   // If GetTargetContext return is not null we are not drawing to the screen so there will not be any content offset.
   if (mCompositor->GetTargetContext() != nullptr) {
     return result;
   }
 
   if (CompositorBridgeParent* bridge = mCompositor->GetCompositorBridgeParent()) {
-    AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
+    AndroidDynamicToolbarAnimator* animator = bridge->GetAndroidDynamicToolbarAnimator();
     MOZ_RELEASE_ASSERT(animator);
     result.value = (float)animator->GetCurrentContentOffset().value;
   }
   return result;
 }
 
 void
 LayerManagerComposite::RenderToolbar()
 {
   // If GetTargetContext return is not null we are not drawing to the screen so don't draw the toolbar.
   if (mCompositor->GetTargetContext() != nullptr) {
     return;
   }
 
   if (CompositorBridgeParent* bridge = mCompositor->GetCompositorBridgeParent()) {
-    AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
+    AndroidDynamicToolbarAnimator* animator = bridge->GetAndroidDynamicToolbarAnimator();
     MOZ_RELEASE_ASSERT(animator);
 
     animator->UpdateToolbarSnapshotTexture(mCompositor->AsCompositorOGL());
 
     int32_t toolbarHeight = animator->GetCurrentToolbarHeight();
     if (toolbarHeight == 0) {
       return;
     }
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1183,20 +1183,20 @@ bool
 CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
 {
   RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
   controller->Release();
   return true;
 }
 
 #if defined(MOZ_WIDGET_ANDROID)
-RefPtr<APZCTreeManager>
-CompositorBridgeParent::GetAPZCTreeManager()
+AndroidDynamicToolbarAnimator*
+CompositorBridgeParent::GetAndroidDynamicToolbarAnimator()
 {
-  return mApzcTreeManager;
+  return mApzcTreeManager ? mApzcTreeManager->GetAndroidDynamicToolbarAnimator() : nullptr;
 }
 #endif
 
 RefPtr<APZSampler>
 CompositorBridgeParent::GetAPZSampler()
 {
   return mApzSampler;
 }
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -459,17 +459,17 @@ public:
   void AllocateAPZCTreeManagerParent(const MonitorAutoLock& aProofOfLayerTreeStateLock,
                                      const uint64_t& aLayersId,
                                      LayerTreeState& aLayerTreeStateToUpdate);
 
   PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
   bool DeallocPAPZParent(PAPZParent* aActor) override;
 
 #if defined(MOZ_WIDGET_ANDROID)
-  RefPtr<APZCTreeManager> GetAPZCTreeManager();
+  AndroidDynamicToolbarAnimator* GetAndroidDynamicToolbarAnimator();
 #endif
   RefPtr<APZSampler> GetAPZSampler();
 
   CompositorOptions GetOptions() const {
     return mOptions;
   }
 
   TimeDuration GetVsyncInterval() const {
@@ -486,20 +486,16 @@ public:
   Maybe<TimeStamp> GetTestingTimeStamp() const;
 
   static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId);
 
 #if defined(MOZ_WIDGET_ANDROID)
   gfx::IntSize GetEGLSurfaceSize() {
     return mEGLSurfaceSize;
   }
-
-  uint64_t GetRootLayerTreeId() {
-    return mRootLayerTreeID;
-  }
 #endif // defined(MOZ_WIDGET_ANDROID)
 
 private:
 
   void Initialize();
 
   /**
    * Called during destruction in order to release resources as early as possible.
--- a/gfx/layers/ipc/LayerAnimationUtils.cpp
+++ b/gfx/layers/ipc/LayerAnimationUtils.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerAnimationUtils.h"
 #include "mozilla/ComputedTimingFunction.h" // For ComputedTimingFunction
 #include "mozilla/layers/LayersMessages.h" // For TimingFunction etc.
+#include "nsTimingFunction.h"
 
 namespace mozilla {
 namespace layers {
 
 /* static */ Maybe<ComputedTimingFunction>
 AnimationUtils::TimingFunctionToComputedTimingFunction(
   const TimingFunction& aTimingFunction)
 {
--- a/gfx/layers/ipc/UiCompositorControllerParent.cpp
+++ b/gfx/layers/ipc/UiCompositorControllerParent.cpp
@@ -275,21 +275,21 @@ UiCompositorControllerParent::Initialize
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   AddRef();
   LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(mRootLayerTreeId);
   MOZ_ASSERT(state);
   MOZ_ASSERT(state->mParent);
   state->mUiControllerParent = this;
 #if defined(MOZ_WIDGET_ANDROID)
-  RefPtr<APZCTreeManager> manager = state->mParent->GetAPZCTreeManager();
-  // Since this is called from the UI thread. It is possible the compositor has already
-  // started shutting down and the APZCTreeManager could be a nullptr.
-  if (manager) {
-    manager->InitializeDynamicToolbarAnimator(mRootLayerTreeId);
+  AndroidDynamicToolbarAnimator* animator = state->mParent->GetAndroidDynamicToolbarAnimator();
+  // It is possible the compositor has already started shutting down and
+  // the AndroidDynamicToolbarAnimator could be a nullptr.
+  if (animator) {
+    animator->Initialize(mRootLayerTreeId);
   }
 #endif
 }
 
 void
 UiCompositorControllerParent::Open(Endpoint<PUiCompositorControllerParent>&& aEndpoint)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -55,219 +55,218 @@ class EventDispatchingCallback;
 
 // A set type for tracking visible frames, for use by the visibility code in
 // PresShell. The set contains nsIFrame* pointers.
 typedef nsTHashtable<nsPtrHashKey<nsIFrame>> VisibleFrames;
 
 // A hash table type for tracking visible regions, for use by the visibility
 // code in PresShell. The mapping is from view IDs to regions in the
 // coordinate system of that view's scrolled frame.
-typedef nsClassHashtable<nsUint64HashKey, mozilla::CSSIntRegion> VisibleRegions;
+typedef nsClassHashtable<nsUint64HashKey, CSSIntRegion> VisibleRegions;
 
 // This is actually pref-controlled, but we use this value if we fail
 // to get the pref for any reason.
 #ifdef MOZ_WIDGET_ANDROID
 #define PAINTLOCK_EVENT_DELAY 250
 #else
 #define PAINTLOCK_EVENT_DELAY 5
 #endif
 
 class PresShell final : public nsIPresShell,
                         public nsISelectionController,
                         public nsIObserver,
                         public nsSupportsWeakReference
 {
-protected:
-  typedef mozilla::layers::FocusTarget FocusTarget;
+  typedef layers::FocusTarget FocusTarget;
 
 public:
   PresShell();
 
   // nsISupports
   NS_DECL_ISUPPORTS
 
   static bool AccessibleCaretEnabled(nsIDocShell* aDocShell);
 
   void Init(nsIDocument* aDocument, nsPresContext* aPresContext,
-            nsViewManager* aViewManager, mozilla::StyleSetHandle aStyleSet);
-  virtual void Destroy() override;
+            nsViewManager* aViewManager, StyleSetHandle aStyleSet);
+  void Destroy() override;
 
-  virtual void UpdatePreferenceStyles() override;
+  void UpdatePreferenceStyles() override;
 
   NS_IMETHOD GetSelection(RawSelectionType aRawSelectionType,
                           nsISelection** aSelection) override;
   dom::Selection* GetDOMSelection(RawSelectionType aRawSelectionType) override;
-  virtual mozilla::dom::Selection*
-    GetCurrentSelection(SelectionType aSelectionType) override;
-  virtual already_AddRefed<nsISelectionController>
-            GetSelectionControllerForFocusedContent(
-              nsIContent** aFocusedContent = nullptr) override;
+
+  dom::Selection* GetCurrentSelection(SelectionType aSelectionType) override;
+
+  already_AddRefed<nsISelectionController>
+    GetSelectionControllerForFocusedContent(
+      nsIContent** aFocusedContent = nullptr) override;
 
   NS_IMETHOD SetDisplaySelection(int16_t aToggle) override;
   NS_IMETHOD GetDisplaySelection(int16_t *aToggle) override;
   NS_IMETHOD ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
                                      SelectionRegion aRegion,
                                      int16_t aFlags) override;
   NS_IMETHOD RepaintSelection(RawSelectionType aRawSelectionType) override;
 
-  virtual nsresult Initialize() override;
-  virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight,
-                                nscoord aOldWidth = 0, nscoord aOldHeight = 0,
-                                ResizeReflowOptions aOptions =
-                                ResizeReflowOptions::eBSizeExact) override;
-  virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
-                                              nscoord aOldWidth, nscoord aOldHeight,
-                                              ResizeReflowOptions aOptions =
-                                              ResizeReflowOptions::eBSizeExact) override;
-  virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override;
-  virtual nsCanvasFrame* GetCanvasFrame() const override;
+  nsresult Initialize() override;
+  nsresult ResizeReflow(nscoord aWidth, nscoord aHeight,
+                        nscoord aOldWidth = 0, nscoord aOldHeight = 0,
+                        ResizeReflowOptions aOptions =
+                        ResizeReflowOptions::eBSizeExact) override;
+  nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
+                                      nscoord aOldWidth, nscoord aOldHeight,
+                                      ResizeReflowOptions aOptions =
+                                      ResizeReflowOptions::eBSizeExact) override;
+  nsIPageSequenceFrame* GetPageSequenceFrame() const override;
+  nsCanvasFrame* GetCanvasFrame() const override;
 
-  virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
+  void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
                                 nsFrameState aBitToAdd,
                                 ReflowRootHandling aRootHandling =
                                   eInferFromBitToAdd) override;
-  virtual void FrameNeedsToContinueReflow(nsIFrame *aFrame) override;
-  virtual void CancelAllPendingReflows() override;
-  virtual void DoFlushPendingNotifications(mozilla::FlushType aType) override;
-  virtual void DoFlushPendingNotifications(mozilla::ChangesToFlush aType) override;
-  virtual void DestroyFramesForAndRestyle(mozilla::dom::Element* aElement) override;
+  void FrameNeedsToContinueReflow(nsIFrame *aFrame) override;
+  void CancelAllPendingReflows() override;
+  void DoFlushPendingNotifications(FlushType aType) override;
+  void DoFlushPendingNotifications(ChangesToFlush aType) override;
+  void DestroyFramesForAndRestyle(dom::Element* aElement) override;
 
   /**
    * Post a callback that should be handled after reflow has finished.
    */
-  virtual nsresult PostReflowCallback(nsIReflowCallback* aCallback) override;
-  virtual void CancelReflowCallback(nsIReflowCallback* aCallback) override;
+  nsresult PostReflowCallback(nsIReflowCallback* aCallback) override;
+  void CancelReflowCallback(nsIReflowCallback* aCallback) override;
 
-  virtual void ClearFrameRefs(nsIFrame* aFrame) override;
-  virtual already_AddRefed<gfxContext> CreateReferenceRenderingContext() override;
-  virtual nsresult GoToAnchor(const nsAString& aAnchorName, bool aScroll,
+  void ClearFrameRefs(nsIFrame* aFrame) override;
+  already_AddRefed<gfxContext> CreateReferenceRenderingContext() override;
+  nsresult GoToAnchor(const nsAString& aAnchorName, bool aScroll,
                               uint32_t aAdditionalScrollFlags = 0) override;
-  virtual nsresult ScrollToAnchor() override;
+  nsresult ScrollToAnchor() override;
 
-  virtual nsresult ScrollContentIntoView(nsIContent* aContent,
+  nsresult ScrollContentIntoView(nsIContent* aContent,
                                                      ScrollAxis  aVertical,
                                                      ScrollAxis  aHorizontal,
                                                      uint32_t    aFlags) override;
-  virtual bool ScrollFrameRectIntoView(nsIFrame*     aFrame,
+  bool ScrollFrameRectIntoView(nsIFrame*     aFrame,
                                        const nsRect& aRect,
                                        ScrollAxis    aVertical,
                                        ScrollAxis    aHorizontal,
                                        uint32_t      aFlags) override;
-  virtual nsRectVisibility GetRectVisibility(nsIFrame *aFrame,
+  nsRectVisibility GetRectVisibility(nsIFrame *aFrame,
                                              const nsRect &aRect,
                                              nscoord aMinTwips) const override;
 
-  virtual void SetIgnoreFrameDestruction(bool aIgnore) override;
-  virtual void NotifyDestroyingFrame(nsIFrame* aFrame) override;
+  void SetIgnoreFrameDestruction(bool aIgnore) override;
+  void NotifyDestroyingFrame(nsIFrame* aFrame) override;
 
-  virtual nsresult CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState) override;
+  nsresult CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState) override;
 
-  virtual void UnsuppressPainting() override;
+  void UnsuppressPainting() override;
 
-  virtual nsresult GetAgentStyleSheets(
-      nsTArray<RefPtr<mozilla::StyleSheet>>& aSheets) override;
-  virtual nsresult SetAgentStyleSheets(
-      const nsTArray<RefPtr<mozilla::StyleSheet>>& aSheets) override;
+  nsresult GetAgentStyleSheets(
+      nsTArray<RefPtr<StyleSheet>>& aSheets) override;
+  nsresult SetAgentStyleSheets(
+      const nsTArray<RefPtr<StyleSheet>>& aSheets) override;
 
-  virtual nsresult AddOverrideStyleSheet(mozilla::StyleSheet* aSheet) override;
-  virtual nsresult RemoveOverrideStyleSheet(mozilla::StyleSheet* aSheet) override;
+  nsresult AddOverrideStyleSheet(StyleSheet* aSheet) override;
+  nsresult RemoveOverrideStyleSheet(StyleSheet* aSheet) override;
 
-  virtual nsresult HandleEventWithTarget(
-                                 mozilla::WidgetEvent* aEvent,
+  nsresult HandleEventWithTarget(WidgetEvent* aEvent,
                                  nsIFrame* aFrame,
                                  nsIContent* aContent,
                                  nsEventStatus* aStatus,
                                  bool aIsHandlingNativeEvent = false,
                                  nsIContent** aTargetContent = nullptr) override;
-  virtual nsIFrame* GetEventTargetFrame() override;
-  virtual already_AddRefed<nsIContent> GetEventTargetContent(
-                                                     mozilla::WidgetEvent* aEvent) override;
+  nsIFrame* GetEventTargetFrame() override;
+  already_AddRefed<nsIContent>
+    GetEventTargetContent(WidgetEvent* aEvent) override;
 
-  virtual void NotifyCounterStylesAreDirty() override;
+  void NotifyCounterStylesAreDirty() override;
 
-  virtual void ReconstructFrames(void) override;
-  virtual void Freeze() override;
-  virtual void Thaw() override;
-  virtual void FireOrClearDelayedEvents(bool aFireEvents) override;
+  void ReconstructFrames(void) override;
+  void Freeze() override;
+  void Thaw() override;
+  void FireOrClearDelayedEvents(bool aFireEvents) override;
 
-  virtual nsresult RenderDocument(const nsRect& aRect, uint32_t aFlags,
-                                              nscolor aBackgroundColor,
-                                              gfxContext* aThebesContext) override;
+  nsresult RenderDocument(const nsRect& aRect,
+                          uint32_t aFlags,
+                          nscolor aBackgroundColor,
+                          gfxContext* aThebesContext) override;
 
-  virtual already_AddRefed<SourceSurface>
+  already_AddRefed<SourceSurface>
   RenderNode(nsIDOMNode* aNode,
              nsIntRegion* aRegion,
-             const mozilla::LayoutDeviceIntPoint aPoint,
-             mozilla::LayoutDeviceIntRect* aScreenRect,
+             const LayoutDeviceIntPoint aPoint,
+             LayoutDeviceIntRect* aScreenRect,
              uint32_t aFlags) override;
 
-  virtual already_AddRefed<SourceSurface>
+  already_AddRefed<SourceSurface>
   RenderSelection(nsISelection* aSelection,
-                  const mozilla::LayoutDeviceIntPoint aPoint,
-                  mozilla::LayoutDeviceIntRect* aScreenRect,
+                  const LayoutDeviceIntPoint aPoint,
+                  LayoutDeviceIntRect* aScreenRect,
                   uint32_t aFlags) override;
 
-  virtual already_AddRefed<nsPIDOMWindowOuter> GetRootWindow() override;
+  already_AddRefed<nsPIDOMWindowOuter> GetRootWindow() override;
 
-  virtual already_AddRefed<nsPIDOMWindowOuter> GetFocusedDOMWindowInOurWindow() override;
+  already_AddRefed<nsPIDOMWindowOuter> GetFocusedDOMWindowInOurWindow() override;
 
-  virtual LayerManager* GetLayerManager() override;
+  LayerManager* GetLayerManager() override;
 
-  virtual bool AsyncPanZoomEnabled() override;
+  bool AsyncPanZoomEnabled() override;
 
-  virtual void SetIgnoreViewportScrolling(bool aIgnore) override;
+  void SetIgnoreViewportScrolling(bool aIgnore) override;
 
-  virtual nsresult SetResolution(float aResolution) override {
+  nsresult SetResolution(float aResolution) override {
     return SetResolutionImpl(aResolution, /* aScaleToResolution = */ false);
   }
-  virtual nsresult SetResolutionAndScaleTo(float aResolution) override {
+  nsresult SetResolutionAndScaleTo(float aResolution) override {
     return SetResolutionImpl(aResolution, /* aScaleToResolution = */ true);
   }
-  virtual bool ScaleToResolution() const override;
-  virtual float GetCumulativeResolution() override;
-  virtual float GetCumulativeNonRootScaleResolution() override;
-  virtual void SetRestoreResolution(float aResolution,
-                                    mozilla::LayoutDeviceIntSize aDisplaySize) override;
+  bool ScaleToResolution() const override;
+  float GetCumulativeResolution() override;
+  float GetCumulativeNonRootScaleResolution() override;
+  void SetRestoreResolution(float aResolution,
+                            LayoutDeviceIntSize aDisplaySize) override;
 
   //nsIViewObserver interface
 
-  virtual void Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
-                     uint32_t aFlags) override;
-  virtual nsresult HandleEvent(nsIFrame* aFrame,
-                               mozilla::WidgetGUIEvent* aEvent,
-                               bool aDontRetargetEvents,
-                               nsEventStatus* aEventStatus) override;
-  virtual nsresult HandleDOMEventWithTarget(
-                                 nsIContent* aTargetContent,
-                                 mozilla::WidgetEvent* aEvent,
-                                 nsEventStatus* aStatus) override;
-  virtual nsresult HandleDOMEventWithTarget(nsIContent* aTargetContent,
-                                                        nsIDOMEvent* aEvent,
-                                                        nsEventStatus* aStatus) override;
-  virtual bool ShouldIgnoreInvalidation() override;
-  virtual void WillPaint() override;
-  virtual void WillPaintWindow() override;
-  virtual void DidPaintWindow() override;
-  virtual void ScheduleViewManagerFlush(PaintType aType = PAINT_DEFAULT) override;
-  virtual void DispatchSynthMouseMove(mozilla::WidgetGUIEvent* aEvent,
-                                      bool aFlushOnHoverChange) override;
-  virtual void ClearMouseCaptureOnView(nsView* aView) override;
-  virtual bool IsVisible() override;
+  void Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
+             uint32_t aFlags) override;
+  nsresult HandleEvent(nsIFrame* aFrame,
+                       WidgetGUIEvent* aEvent,
+                       bool aDontRetargetEvents,
+                       nsEventStatus* aEventStatus) override;
+  nsresult HandleDOMEventWithTarget(nsIContent* aTargetContent,
+                                    WidgetEvent* aEvent,
+                                    nsEventStatus* aStatus) override;
+  nsresult HandleDOMEventWithTarget(nsIContent* aTargetContent,
+                                    nsIDOMEvent* aEvent,
+                                    nsEventStatus* aStatus) override;
+  bool ShouldIgnoreInvalidation() override;
+  void WillPaint() override;
+  void WillPaintWindow() override;
+  void DidPaintWindow() override;
+  void ScheduleViewManagerFlush(PaintType aType = PAINT_DEFAULT) override;
+  void DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
+                              bool aFlushOnHoverChange) override;
+  void ClearMouseCaptureOnView(nsView* aView) override;
+  bool IsVisible() override;
 
-  virtual already_AddRefed<mozilla::AccessibleCaretEventHub> GetAccessibleCaretEventHub() const override;
+  already_AddRefed<AccessibleCaretEventHub> GetAccessibleCaretEventHub() const override;
 
   // caret handling
-  virtual already_AddRefed<nsCaret> GetCaret() const override;
+  already_AddRefed<nsCaret> GetCaret() const override;
   NS_IMETHOD SetCaretEnabled(bool aInEnable) override;
   NS_IMETHOD SetCaretReadOnly(bool aReadOnly) override;
   NS_IMETHOD GetCaretEnabled(bool *aOutEnabled) override;
   NS_IMETHOD SetCaretVisibilityDuringSelection(bool aVisibility) override;
   NS_IMETHOD GetCaretVisible(bool *_retval) override;
-  virtual void SetCaret(nsCaret *aNewCaret) override;
-  virtual void RestoreCaret() override;
+  void SetCaret(nsCaret *aNewCaret) override;
+  void RestoreCaret() override;
 
   NS_IMETHOD SetSelectionFlags(int16_t aInEnable) override;
   NS_IMETHOD GetSelectionFlags(int16_t *aOutEnable) override;
 
   // nsISelectionController
 
   NS_IMETHOD PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend) override;
   NS_IMETHOD CharacterMove(bool aForward, bool aExtend) override;
@@ -280,18 +279,18 @@ public:
   NS_IMETHOD PageMove(bool aForward, bool aExtend) override;
   NS_IMETHOD ScrollPage(bool aForward) override;
   NS_IMETHOD ScrollLine(bool aForward) override;
   NS_IMETHOD ScrollCharacter(bool aRight) override;
   NS_IMETHOD CompleteScroll(bool aForward) override;
   NS_IMETHOD CompleteMove(bool aForward, bool aExtend) override;
   NS_IMETHOD SelectAll() override;
   NS_IMETHOD CheckVisibility(nsIDOMNode *node, int16_t startOffset, int16_t EndOffset, bool *_retval) override;
-  virtual nsresult CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset,
-                                          int16_t aEndOffset, bool* aRetval) override;
+  nsresult CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset,
+                                  int16_t aEndOffset, bool* aRetval) override;
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
   NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
   NS_DECL_NSIDOCUMENTOBSERVER_BEGINLOAD
   NS_DECL_NSIDOCUMENTOBSERVER_ENDLOAD
   NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATECHANGED
   NS_DECL_NSIDOCUMENTOBSERVER_DOCUMENTSTATESCHANGED
@@ -305,72 +304,72 @@ public:
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   NS_DECL_NSIOBSERVER
 
 #ifdef MOZ_REFLOW_PERF
-  virtual void DumpReflows() override;
-  virtual void CountReflows(const char * aName, nsIFrame * aFrame) override;
-  virtual void PaintCount(const char * aName,
-                                      gfxContext* aRenderingContext,
-                                      nsPresContext* aPresContext,
-                                      nsIFrame * aFrame,
-                                      const nsPoint& aOffset,
-                                      uint32_t aColor) override;
-  virtual void SetPaintFrameCount(bool aOn) override;
-  virtual bool IsPaintingFrameCounts() override;
+  void DumpReflows() override;
+  void CountReflows(const char * aName, nsIFrame * aFrame) override;
+  void PaintCount(const char * aName,
+                  gfxContext* aRenderingContext,
+                  nsPresContext* aPresContext,
+                  nsIFrame * aFrame,
+                  const nsPoint& aOffset,
+                  uint32_t aColor) override;
+  void SetPaintFrameCount(bool aOn) override;
+  bool IsPaintingFrameCounts() override;
 #endif
 
 #ifdef DEBUG
-  virtual void ListStyleContexts(FILE *out, int32_t aIndent = 0) override;
+  void ListStyleContexts(FILE *out, int32_t aIndent = 0) override;
 
-  virtual void ListStyleSheets(FILE *out, int32_t aIndent = 0) override;
-  virtual void VerifyStyleTree() override;
+  void ListStyleSheets(FILE *out, int32_t aIndent = 0) override;
+  void VerifyStyleTree() override;
 #endif
 
-  static mozilla::LazyLogModule gLog;
+  static LazyLogModule gLog;
 
-  virtual void DisableNonTestMouseEvents(bool aDisable) override;
+  void DisableNonTestMouseEvents(bool aDisable) override;
 
-  virtual void UpdateCanvasBackground() override;
+  void UpdateCanvasBackground() override;
 
-  virtual void AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
-                                            nsDisplayList& aList,
-                                            nsIFrame* aFrame,
-                                            const nsRect& aBounds,
-                                            nscolor aBackstopColor,
-                                            uint32_t aFlags) override;
+  void AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
+                                    nsDisplayList& aList,
+                                    nsIFrame* aFrame,
+                                    const nsRect& aBounds,
+                                    nscolor aBackstopColor,
+                                    uint32_t aFlags) override;
 
-  virtual void AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
-                                             nsDisplayList& aList,
-                                             nsIFrame* aFrame,
-                                             const nsRect& aBounds) override;
+  void AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
+                                     nsDisplayList& aList,
+                                     nsIFrame* aFrame,
+                                     const nsRect& aBounds) override;
 
-  virtual nscolor ComputeBackstopColor(nsView* aDisplayRoot) override;
+  nscolor ComputeBackstopColor(nsView* aDisplayRoot) override;
 
-  virtual nsresult SetIsActive(bool aIsActive) override;
+  nsresult SetIsActive(bool aIsActive) override;
 
-  virtual bool GetIsViewportOverridden() override {
+  bool GetIsViewportOverridden() override {
     return (mMobileViewportManager != nullptr);
   }
 
-  virtual bool IsLayoutFlushObserver() override
+  bool IsLayoutFlushObserver() override
   {
     return GetPresContext()->RefreshDriver()->
       IsLayoutFlushObserver(this);
   }
 
-  virtual void LoadComplete() override;
+  void LoadComplete() override;
 
-  virtual void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes)
+  void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes)
     const override;
-  size_t SizeOfTextRuns(mozilla::MallocSizeOf aMallocSizeOf) const;
+  size_t SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const;
 
   // This data is stored as a content property (nsGkAtoms::scrolling) on
   // mContentToScrollTo when we have a pending ScrollIntoView.
   struct ScrollIntoViewData {
     ScrollAxis mContentScrollVAxis;
     ScrollAxis mContentScrollHAxis;
     uint32_t   mContentToScrollToFlags;
   };
@@ -387,57 +386,56 @@ public:
   void RebuildApproximateFrameVisibility(nsRect* aRect = nullptr,
                                          bool aRemoveOnly = false) override;
 
   void EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) override;
   void RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) override;
 
   bool AssumeAllFramesVisible() override;
 
-  virtual bool CanDispatchEvent(
-      const mozilla::WidgetGUIEvent* aEvent = nullptr) const override;
+  bool CanDispatchEvent(const WidgetGUIEvent* aEvent = nullptr) const override;
 
   void SetNextPaintCompressed() { mNextPaintCompressed = true; }
 
-  void NotifyStyleSheetServiceSheetAdded(mozilla::StyleSheet* aSheet,
+  void NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
                                          uint32_t aSheetType) override;
-  void NotifyStyleSheetServiceSheetRemoved(mozilla::StyleSheet* aSheet,
+  void NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
                                            uint32_t aSheetType) override;
 
-  virtual bool HasHandledUserInput() const override {
+  bool HasHandledUserInput() const override {
     return mHasHandledUserInput;
   }
 
-  virtual void FireResizeEvent() override;
+  void FireResizeEvent() override;
 
   static PresShell* GetShellForEventTarget(nsIFrame* aFrame,
                                            nsIContent* aContent);
   static PresShell* GetShellForTouchEvent(WidgetGUIEvent* aEvent);
 
-protected:
-  virtual ~PresShell();
+private:
+  ~PresShell();
 
   void HandlePostedReflowCallbacks(bool aInterruptible);
   void CancelPostedReflowCallbacks();
 
   void ScheduleBeforeFirstPaint();
   void UnsuppressAndInvalidate();
 
   void WillCauseReflow() {
     nsContentUtils::AddScriptBlocker();
     ++mChangeNestCount;
   }
   nsresult DidCauseReflow();
   friend class ::nsAutoCauseReflowNotifier;
   friend class ::AutoPointerEventTargetUpdater;
 
-  nsresult DispatchEventToDOM(mozilla::WidgetEvent* aEvent,
+  nsresult DispatchEventToDOM(WidgetEvent* aEvent,
                               nsEventStatus* aStatus,
                               nsPresShellEventCB* aEventCB);
-  void DispatchTouchEventToDOM(mozilla::WidgetEvent* aEvent,
+  void DispatchTouchEventToDOM(WidgetEvent* aEvent,
                                nsEventStatus* aStatus,
                                nsPresShellEventCB* aEventCB,
                                bool aTouchIsNew);
 
   void     WillDoReflow();
 
   /**
    * Callback handler for whether reflow happened.
@@ -519,32 +517,31 @@ protected:
   nsStyleSet* CloneStyleSet(nsStyleSet* aSet);
 #endif
   ServoStyleSet* CloneStyleSet(ServoStyleSet* aSet);
   bool VerifyIncrementalReflow();
   bool mInVerifyReflow;
   void ShowEventTargetDebug();
 #endif
 
-  void RecordStyleSheetChange(mozilla::StyleSheet* aStyleSheet,
-                              StyleSheet::ChangeType);
+  void RecordStyleSheetChange(StyleSheet* aStyleSheet, StyleSheet::ChangeType);
 
   void RemovePreferenceStyles();
 
   // methods for painting a range to an offscreen buffer
 
   // given a display list, clip the items within the list to
   // the range
   nsRect ClipListToRange(nsDisplayListBuilder *aBuilder,
                          nsDisplayList* aList,
                          nsRange* aRange);
 
   // create a RangePaintInfo for the range aRange containing the
   // display list needed to paint the range to a surface
-  mozilla::UniquePtr<RangePaintInfo>
+  UniquePtr<RangePaintInfo>
   CreateRangePaintInfo(nsIDOMRange* aRange,
                        nsRect& aSurfaceRect,
                        bool aForPrimarySelection);
 
   /*
    * Paint the items to a new surface and return it.
    *
    * aSelection - selection being painted, if any
@@ -552,42 +549,42 @@ protected:
    * aArea - area that the surface occupies, relative to the root frame
    * aPoint - reference point, typically the mouse position
    * aScreenRect - [out] set to the area of the screen the painted area should
    *               be displayed at
    * aFlags - set RENDER_AUTO_SCALE to scale down large images, but it must not
    *          be set if a custom image was specified
    */
   already_AddRefed<SourceSurface>
-  PaintRangePaintInfo(const nsTArray<mozilla::UniquePtr<RangePaintInfo>>& aItems,
+  PaintRangePaintInfo(const nsTArray<UniquePtr<RangePaintInfo>>& aItems,
                       nsISelection* aSelection,
                       nsIntRegion* aRegion,
                       nsRect aArea,
-                      const mozilla::LayoutDeviceIntPoint aPoint,
-                      mozilla::LayoutDeviceIntRect* aScreenRect,
+                      const LayoutDeviceIntPoint aPoint,
+                      LayoutDeviceIntRect* aScreenRect,
                       uint32_t aFlags);
 
   /**
    * Methods to handle changes to user and UA sheet lists that we get
    * notified about.
    */
   void AddUserSheet(StyleSheet* aSheet);
   void AddAgentSheet(StyleSheet* aSheet);
   void AddAuthorSheet(StyleSheet* aSheet);
-  void RemoveSheet(mozilla::SheetType aType, StyleSheet* aSheet);
+  void RemoveSheet(SheetType aType, StyleSheet* aSheet);
 
   // Hide a view if it is a popup
   void HideViewIfPopup(nsView* aView);
 
   // Utility method to restore the root scrollframe state
   void RestoreRootScrollPosition();
 
   void MaybeReleaseCapturingContent();
 
-  nsresult HandleRetargetedEvent(mozilla::WidgetEvent* aEvent,
+  nsresult HandleRetargetedEvent(WidgetEvent* aEvent,
                                  nsEventStatus* aStatus,
                                  nsIContent* aTarget)
   {
     PushCurrentEventInfo(nullptr, nullptr);
     mCurrentEventContent = aTarget;
     nsresult rv = NS_OK;
     if (GetCurrentEventFrame()) {
       rv = HandleEventInternal(aEvent, aStatus, true);
@@ -602,41 +599,41 @@ protected:
     virtual ~DelayedEvent() { }
     virtual void Dispatch() { }
     virtual bool IsKeyPressEvent() { return false; }
   };
 
   class DelayedInputEvent : public DelayedEvent
   {
   public:
-    virtual void Dispatch() override;
+    void Dispatch() override;
 
   protected:
     DelayedInputEvent();
-    virtual ~DelayedInputEvent();
+    ~DelayedInputEvent() override;
 
-    mozilla::WidgetInputEvent* mEvent;
+    WidgetInputEvent* mEvent;
   };
 
   class DelayedMouseEvent : public DelayedInputEvent
   {
   public:
-    explicit DelayedMouseEvent(mozilla::WidgetMouseEvent* aEvent);
+    explicit DelayedMouseEvent(WidgetMouseEvent* aEvent);
   };
 
   class DelayedKeyEvent : public DelayedInputEvent
   {
   public:
-    explicit DelayedKeyEvent(mozilla::WidgetKeyboardEvent* aEvent);
-    virtual bool IsKeyPressEvent() override;
+    explicit DelayedKeyEvent(WidgetKeyboardEvent* aEvent);
+    bool IsKeyPressEvent() override;
   };
 
   // Check if aEvent is a mouse event and record the mouse location for later
   // synth mouse moves.
-  void RecordMouseLocation(mozilla::WidgetGUIEvent* aEvent);
+  void RecordMouseLocation(WidgetGUIEvent* aEvent);
   class nsSynthMouseMoveEvent final : public nsARefreshObserver {
   public:
     nsSynthMouseMoveEvent(PresShell* aPresShell, bool aFromScroll)
       : mPresShell(aPresShell), mFromScroll(aFromScroll) {
       NS_ASSERTION(mPresShell, "null parameter");
     }
 
   private:
@@ -650,17 +647,17 @@ protected:
 
     void Revoke() {
       if (mPresShell) {
         mPresShell->GetPresContext()->RefreshDriver()->
           RemoveRefreshObserver(this, FlushType::Display);
         mPresShell = nullptr;
       }
     }
-    virtual void WillRefresh(mozilla::TimeStamp aTime) override {
+    void WillRefresh(TimeStamp aTime) override {
       if (mPresShell) {
         RefPtr<PresShell> shell = mPresShell;
         shell->ProcessSynthMouseMoveEvent(mFromScroll);
       }
     }
   private:
     PresShell* mPresShell;
     bool mFromScroll;
@@ -669,26 +666,26 @@ protected:
 
   void QueryIsActive();
   nsresult UpdateImageLockingState();
 
   bool InZombieDocument(nsIContent *aContent);
   already_AddRefed<nsIPresShell> GetParentPresShellForEventHandling();
   nsIContent* GetCurrentEventContent();
   nsIFrame* GetCurrentEventFrame();
-  nsresult RetargetEventToParent(mozilla::WidgetGUIEvent* aEvent,
+  nsresult RetargetEventToParent(WidgetGUIEvent* aEvent,
                                  nsEventStatus* aEventStatus);
   void PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent);
   void PopCurrentEventInfo();
   /**
    * @param aIsHandlingNativeEvent      true when the caller (perhaps) handles
    *                                    an event which is caused by native
    *                                    event.  Otherwise, false.
    */
-  nsresult HandleEventInternal(mozilla::WidgetEvent* aEvent,
+  nsresult HandleEventInternal(WidgetEvent* aEvent,
                                nsEventStatus* aStatus,
                                bool aIsHandlingNativeEvent);
 
   /*
    * This and the next two helper methods are used to target and position the
    * context menu when the keyboard shortcut is used to open it.
    *
    * If another menu is open, the context menu is opened relative to the
@@ -697,62 +694,62 @@ protected:
    * Otherwise, if a selectable list such as a listbox is focused, the
    * current item within the menu is opened relative to this item.
    * Otherwise, the context menu is opened at the topleft corner of the
    * view.
    *
    * Returns true if the context menu event should fire and false if it should
    * not.
    */
-  bool AdjustContextMenuKeyEvent(mozilla::WidgetMouseEvent* aEvent);
+  bool AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent);
 
   //
   bool PrepareToUseCaretPosition(nsIWidget* aEventWidget,
-                                 mozilla::LayoutDeviceIntPoint& aTargetPt);
+                                 LayoutDeviceIntPoint& aTargetPt);
 
   // Get the selected item and coordinates in device pixels relative to root
   // document's root view for element, first ensuring the element is onscreen
   void GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl,
                                            nsIContent **aTargetToUse,
-                                           mozilla::LayoutDeviceIntPoint& aTargetPt,
+                                           LayoutDeviceIntPoint& aTargetPt,
                                            nsIWidget *aRootWidget);
 
-  virtual void SynthesizeMouseMove(bool aFromScroll) override;
+  void SynthesizeMouseMove(bool aFromScroll) override;
 
   PresShell* GetRootPresShell();
 
   nscolor GetDefaultBackgroundColorToDraw();
 
   DOMHighResTimeStamp GetPerformanceNow();
 
   // The callback for the mPaintSuppressionTimer timer.
   static void sPaintSuppressionCallback(nsITimer* aTimer, void* aPresShell);
 
   // The callback for the mReflowContinueTimer timer.
   static void sReflowContinueCallback(nsITimer* aTimer, void* aPresShell);
   bool ScheduleReflowOffTimer();
 
   // Widget notificiations
-  virtual void WindowSizeMoveDone() override;
-  virtual void SysColorChanged() override { mPresContext->SysColorChanged(); }
-  virtual void ThemeChanged() override { mPresContext->ThemeChanged(); }
-  virtual void BackingScaleFactorChanged() override { mPresContext->UIResolutionChanged(); }
-  virtual nsIDocument* GetPrimaryContentDocument() override;
+  void WindowSizeMoveDone() override;
+  void SysColorChanged() override { mPresContext->SysColorChanged(); }
+  void ThemeChanged() override { mPresContext->ThemeChanged(); }
+  void BackingScaleFactorChanged() override { mPresContext->UIResolutionChanged(); }
+  nsIDocument* GetPrimaryContentDocument() override;
 
-  virtual void PausePainting() override;
-  virtual void ResumePainting() override;
+  void PausePainting() override;
+  void ResumePainting() override;
 
   //////////////////////////////////////////////////////////////////////////////
   // Approximate frame visibility tracking implementation.
   //////////////////////////////////////////////////////////////////////////////
 
   void UpdateApproximateFrameVisibility();
   void DoUpdateApproximateFrameVisibility(bool aRemoveOnly);
 
-  void ClearApproximatelyVisibleFramesList(const Maybe<mozilla::OnNonvisible>& aNonvisibleAction
+  void ClearApproximatelyVisibleFramesList(const Maybe<OnNonvisible>& aNonvisibleAction
                                              = Nothing());
   static void ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear);
   static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList,
                                                    Maybe<VisibleRegions>& aVisibleRegions);
   void MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
                                                const nsRect& aRect,
                                                Maybe<VisibleRegions>& aVisibleRegions,
                                                bool aRemoveOnly = false);
@@ -766,140 +763,139 @@ protected:
   // that we last did an approximate frame visibility update.
   VisibleFrames mApproximatelyVisibleFrames;
 
   nsresult SetResolutionImpl(float aResolution, bool aScaleToResolution);
 
 #ifdef DEBUG
   // The reflow root under which we're currently reflowing.  Null when
   // not in reflow.
-  nsIFrame*                 mCurrentReflowRoot;
-  uint32_t                  mUpdateCount;
+  nsIFrame* mCurrentReflowRoot;
+  uint32_t mUpdateCount;
 #endif
 
 #ifdef MOZ_REFLOW_PERF
-  ReflowCountMgr*           mReflowCountMgr;
+  ReflowCountMgr* mReflowCountMgr;
 #endif
 
   // This is used for synthetic mouse events that are sent when what is under
   // the mouse pointer may have changed without the mouse moving (eg scrolling,
   // change to the document contents).
   // It is set only on a presshell for a root document, this value represents
   // the last observed location of the mouse relative to that root document. It
   // is set to (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if the mouse isn't
   // over our window or there is no last observed mouse location for some
   // reason.
-  nsPoint                   mMouseLocation;
+  nsPoint mMouseLocation;
   // This is an APZ state variable that tracks the target guid for the last
   // mouse event that was processed (corresponding to mMouseLocation). This is
   // needed for the synthetic mouse events.
-  mozilla::layers::ScrollableLayerGuid mMouseEventTargetGuid;
+  layers::ScrollableLayerGuid mMouseEventTargetGuid;
 
   // mStyleSet owns it but we maintain a ref, may be null
-  RefPtr<mozilla::StyleSheet> mPrefStyleSheet;
+  RefPtr<StyleSheet> mPrefStyleSheet;
 
   // Set of frames that we should mark with NS_FRAME_HAS_DIRTY_CHILDREN after
   // we finish reflowing mCurrentReflowRoot.
   nsTHashtable<nsPtrHashKey<nsIFrame> > mFramesToDirty;
 
   // Reflow roots that need to be reflowed.
-  nsTArray<nsIFrame*>       mDirtyRoots;
+  nsTArray<nsIFrame*> mDirtyRoots;
 
   nsTArray<nsAutoPtr<DelayedEvent> > mDelayedEvents;
 private:
-  nsIFrame*                 mCurrentEventFrame;
-  nsCOMPtr<nsIContent>      mCurrentEventContent;
-  nsTArray<nsIFrame*>       mCurrentEventFrameStack;
-  nsCOMArray<nsIContent>    mCurrentEventContentStack;
-protected:
+  nsIFrame* mCurrentEventFrame;
+  nsCOMPtr<nsIContent> mCurrentEventContent;
+  nsTArray<nsIFrame*> mCurrentEventFrameStack;
+  nsCOMArray<nsIContent> mCurrentEventContentStack;
   nsRevocableEventPtr<nsSynthMouseMoveEvent> mSynthMouseMoveEvent;
-  nsCOMPtr<nsIContent>      mLastAnchorScrolledTo;
-  RefPtr<nsCaret>         mCaret;
-  RefPtr<nsCaret>         mOriginalCaret;
-  nsCallbackEventRequest*   mFirstCallbackEventRequest;
-  nsCallbackEventRequest*   mLastCallbackEventRequest;
+  nsCOMPtr<nsIContent> mLastAnchorScrolledTo;
+  RefPtr<nsCaret> mCaret;
+  RefPtr<nsCaret> mOriginalCaret;
+  nsCallbackEventRequest* mFirstCallbackEventRequest;
+  nsCallbackEventRequest* mLastCallbackEventRequest;
 
-  mozilla::TouchManager     mTouchManager;
+  TouchManager mTouchManager;
 
   RefPtr<ZoomConstraintsClient> mZoomConstraintsClient;
   RefPtr<MobileViewportManager> mMobileViewportManager;
 
-  RefPtr<mozilla::AccessibleCaretEventHub> mAccessibleCaretEventHub;
+  RefPtr<AccessibleCaretEventHub> mAccessibleCaretEventHub;
 
   // This timer controls painting suppression.  Until it fires
   // or all frames are constructed, we won't paint anything but
   // our <body> background and scrollbars.
-  nsCOMPtr<nsITimer>        mPaintSuppressionTimer;
+  nsCOMPtr<nsITimer> mPaintSuppressionTimer;
 
-  nsCOMPtr<nsITimer>        mDelayedPaintTimer;
+  nsCOMPtr<nsITimer> mDelayedPaintTimer;
 
   // The `performance.now()` value when we last started to process reflows.
-  DOMHighResTimeStamp       mLastReflowStart;
+  DOMHighResTimeStamp mLastReflowStart;
 
-  mozilla::TimeStamp        mLoadBegin;  // used to time loads
+  TimeStamp mLoadBegin;  // used to time loads
 
   // Information needed to properly handle scrolling content into view if the
   // pre-scroll reflow flush can be interrupted.  mContentToScrollTo is
   // non-null between the initial scroll attempt and the first time we finish
   // processing all our dirty roots.  mContentToScrollTo has a content property
   // storing the details for the scroll operation, see ScrollIntoViewData above.
-  nsCOMPtr<nsIContent>      mContentToScrollTo;
+  nsCOMPtr<nsIContent> mContentToScrollTo;
 
-  nscoord                   mLastAnchorScrollPositionY;
+  nscoord mLastAnchorScrollPositionY;
 
   // Information about live content (which still stay in DOM tree).
   // Used in case we need re-dispatch event after sending pointer event,
   // when target of pointer event was deleted during executing user handlers.
-  nsCOMPtr<nsIContent>      mPointerEventTarget;
+  nsCOMPtr<nsIContent> mPointerEventTarget;
 
   // The focus sequence number of the last processed input event
-  uint64_t                  mAPZFocusSequenceNumber;
+  uint64_t mAPZFocusSequenceNumber;
   // The focus information needed for async keyboard scrolling
-  FocusTarget               mAPZFocusTarget;
+  FocusTarget mAPZFocusTarget;
 
-  bool                      mDocumentLoading : 1;
-  bool                      mIgnoreFrameDestruction : 1;
-  bool                      mHaveShutDown : 1;
-  bool                      mLastRootReflowHadUnconstrainedBSize : 1;
-  bool                      mNoDelayedMouseEvents : 1;
-  bool                      mNoDelayedKeyEvents : 1;
+  bool mDocumentLoading : 1;
+  bool mIgnoreFrameDestruction : 1;
+  bool mHaveShutDown : 1;
+  bool mLastRootReflowHadUnconstrainedBSize : 1;
+  bool mNoDelayedMouseEvents : 1;
+  bool mNoDelayedKeyEvents : 1;
 
   // Indicates that it is safe to unlock painting once all pending reflows
   // have been processed.
-  bool                      mShouldUnsuppressPainting : 1;
+  bool mShouldUnsuppressPainting : 1;
 
-  bool                      mResizeEventPending : 1;
+  bool mResizeEventPending : 1;
 
-  bool                      mApproximateFrameVisibilityVisited : 1;
+  bool mApproximateFrameVisibilityVisited : 1;
 
-  bool                      mNextPaintCompressed : 1;
+  bool mNextPaintCompressed : 1;
 
-  bool                      mHasCSSBackgroundColor : 1;
+  bool mHasCSSBackgroundColor : 1;
 
   // Whether content should be scaled by the resolution amount. If this is
   // not set, a transform that scales by the inverse of the resolution is
   // applied to rendered layers.
-  bool                      mScaleToResolution : 1;
+  bool mScaleToResolution : 1;
 
   // Whether the last chrome-only escape key event is consumed.
-  bool                      mIsLastChromeOnlyEscapeKeyConsumed : 1;
+  bool mIsLastChromeOnlyEscapeKeyConsumed : 1;
 
   // Whether the widget has received a paint message yet.
-  bool                      mHasReceivedPaintMessage : 1;
+  bool mHasReceivedPaintMessage : 1;
 
-  bool                      mIsLastKeyDownCanceled : 1;
+  bool mIsLastKeyDownCanceled : 1;
 
   // Whether we have ever handled a user input event
-  bool                      mHasHandledUserInput : 1;
+  bool mHasHandledUserInput : 1;
 
-  static bool               sDisableNonTestMouseEvents;
+  static bool sDisableNonTestMouseEvents;
 
-  mozilla::TimeStamp        mLastOSWake;
+  TimeStamp mLastOSWake;
 
-  static mozilla::TimeStamp sLastInputCreated;
-  static mozilla::TimeStamp sLastInputProcessed;
+  static TimeStamp sLastInputCreated;
+  static TimeStamp sLastInputProcessed;
 
-  static bool               sProcessInteractable;
+  static bool sProcessInteractable;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_PresShell_h
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -615,22 +615,16 @@ public:
 
   void ObserveStyleFlushes()
   {
     if (!ObservingStyleFlushes())
       DoObserveStyleFlushes();
   }
 
   bool NeedStyleFlush() const { return mNeedStyleFlush; }
-  /**
-   * Returns true if we might need to flush layout, even if we haven't scheduled
-   * one yet (as opposed to HasPendingReflow, which returns true if a flush is
-   * scheduled or will soon be scheduled).
-   */
-  bool NeedLayoutFlush() const { return mNeedLayoutFlush; }
 
   /**
    * Callbacks will be called even if reflow itself fails for
    * some reason.
    */
   virtual nsresult PostReflowCallback(nsIReflowCallback* aCallback) = 0;
   virtual void CancelReflowCallback(nsIReflowCallback* aCallback) = 0;
 
@@ -1639,20 +1633,16 @@ public:
   bool IsNeverPainting() {
     return mIsNeverPainting;
   }
 
   void SetNeverPainting(bool aNeverPainting) {
     mIsNeverPainting = aNeverPainting;
   }
 
-  /**
-   * True if a reflow event has been scheduled, or is going to be scheduled
-   * to run in the future.
-   */
   bool HasPendingReflow() const
     { return mObservingLayoutFlushes || mReflowContinueTimer; }
 
   void SyncWindowProperties(nsView* aView);
 
   virtual nsIDocument* GetPrimaryContentDocument() = 0;
 
   // aSheetType is one of the nsIStyleSheetService *_SHEET constants.
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1988,20 +1988,19 @@ Gecko_CopyShapeSourceFrom(mozilla::Style
 
 void
 Gecko_DestroyShapeSource(mozilla::StyleShapeSource* aShape)
 {
   aShape->~StyleShapeSource();
 }
 
 void
-Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* aShape, ServoBundledURI aURI)
+Gecko_StyleShapeSource_SetURLValue(StyleShapeSource* aShape, URLValue* aURL)
 {
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
-  aShape->SetURL(url.get());
+  aShape->SetURL(aURL);
 }
 
 void
 Gecko_NewBasicShape(mozilla::StyleShapeSource* aShape,
                     mozilla::StyleBasicShapeType aType)
 {
   aShape->SetBasicShape(MakeUnique<mozilla::StyleBasicShape>(aType),
                         StyleGeometryBox::NoBox);
@@ -2022,33 +2021,31 @@ Gecko_ResetFilters(nsStyleEffects* effec
 
 void
 Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest)
 {
   aDest->mFilters = aSrc->mFilters;
 }
 
 void
-Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* aEffects, ServoBundledURI aURI)
+Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* aEffects, URLValue* aURL)
 {
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
-  aEffects->SetURL(url.get());
+  aEffects->SetURL(aURL);
 }
 
 void
 Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* aDest, const nsStyleSVGPaint* aSrc)
 {
   *aDest = *aSrc;
 }
 
 void
-Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* aPaint, ServoBundledURI aURI)
+Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* aPaint, URLValue* aURL)
 {
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
-  aPaint->SetPaintServer(url.get());
+  aPaint->SetPaintServer(aURL);
 }
 
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* aPaint)
 {
   aPaint->SetNone();
 }
 
 void
@@ -2081,16 +2078,25 @@ Gecko_nsStyleSVG_CopyContextProperties(n
 
 css::URLValue*
 Gecko_NewURLValue(ServoBundledURI aURI)
 {
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   return url.forget().take();
 }
 
+MOZ_DEFINE_MALLOC_SIZE_OF(GeckoURLValueMallocSizeOf)
+
+size_t
+Gecko_URLValue_SizeOfIncludingThis(URLValue* aURL)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  return aURL->SizeOfIncludingThis(GeckoURLValueMallocSizeOf);
+}
+
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLValue, CSSURLValue);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray*
 Gecko_NewCSSShadowArray(uint32_t aLen)
@@ -2232,22 +2238,20 @@ Gecko_CSSValue_SetArray(nsCSSValueBorrow
 {
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   RefPtr<nsCSSValue::Array> array
     = nsCSSValue::Array::Create(aLength);
   aCSSValue->SetArrayValue(array, eCSSUnit_Array);
 }
 
 void
-Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut aCSSValue,
-                      ServoBundledURI aURI)
+Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut aCSSValue, URLValue* aURL)
 {
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
-  aCSSValue->SetURLValue(url.get());
+  aCSSValue->SetURLValue(aURL);
 }
 
 void
 Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut aCSSValue,
                       int32_t aInteger, nsCSSUnit aUnit)
 {
   aCSSValue->SetIntValue(aInteger, aUnit);
 }
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -521,32 +521,33 @@ void Gecko_ResetStyleCoord(nsStyleUnit* 
 void Gecko_SetStyleCoordCalcValue(nsStyleUnit* unit, nsStyleUnion* value, nsStyleCoord::CalcValue calc);
 
 void Gecko_CopyShapeSourceFrom(mozilla::StyleShapeSource* dst, const mozilla::StyleShapeSource* src);
 
 void Gecko_DestroyShapeSource(mozilla::StyleShapeSource* shape);
 void Gecko_NewBasicShape(mozilla::StyleShapeSource* shape,
                          mozilla::StyleBasicShapeType type);
 void Gecko_NewShapeImage(mozilla::StyleShapeSource* shape);
-void Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* shape, ServoBundledURI uri);
+void Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* shape, mozilla::css::URLValue* uri);
 
 void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);
 void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest);
-void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* effects, ServoBundledURI uri);
+void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* effects, mozilla::css::URLValue* uri);
 
 void Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* dest, const nsStyleSVGPaint* src);
-void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, ServoBundledURI uri);
+void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, mozilla::css::URLValue* uri);
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* paint);
 
 void Gecko_nsStyleSVG_SetDashArrayLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* dst, const nsStyleSVG* src);
 void Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* dst, const nsStyleSVG* src);
 
 mozilla::css::URLValue* Gecko_NewURLValue(ServoBundledURI uri);
+size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(RawGeckoURLExtraData, URLExtraData);
 
 void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
@@ -574,17 +575,17 @@ void Gecko_CSSValue_SetCalc(nsCSSValueBo
 void Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut css_value, int32_t len);
 void Gecko_CSSValue_SetString(nsCSSValueBorrowedMut css_value,
                               const uint8_t* string, uint32_t len, nsCSSUnit unit);
 void Gecko_CSSValue_SetStringFromAtom(nsCSSValueBorrowedMut css_value,
                                       nsAtom* atom, nsCSSUnit unit);
 // Take an addrefed nsAtom and set it to the nsCSSValue
 void Gecko_CSSValue_SetAtomIdent(nsCSSValueBorrowedMut css_value, nsAtom* atom);
 void Gecko_CSSValue_SetArray(nsCSSValueBorrowedMut css_value, int32_t len);
-void Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut css_value, ServoBundledURI uri);
+void Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut css_value, mozilla::css::URLValue* uri);
 void Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut css_value, int32_t integer, nsCSSUnit unit);
 void Gecko_CSSValue_SetFloat(nsCSSValueBorrowedMut css_value, float value, nsCSSUnit unit);
 void Gecko_CSSValue_SetPair(nsCSSValueBorrowedMut css_value,
                             nsCSSValueBorrowed xvalue, nsCSSValueBorrowed yvalue);
 void Gecko_CSSValue_SetList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_SetPairList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_InitSharedList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -62,16 +62,17 @@ EXPORTS += [
     'nsStyleContext.h',
     'nsStyleContextInlines.h',
     'nsStyleCoord.h',
     'nsStyleStruct.h',
     'nsStyleStructFwd.h',
     'nsStyleStructInlines.h',
     'nsStyleTransformMatrix.h',
     'nsStyleUtil.h',
+    'nsTimingFunction.h',
 ]
 
 if CONFIG['MOZ_OLD_STYLE']:
     EXPORTS += [
         'nsCSSRuleProcessor.h',
         'nsIStyleRule.h',
         'nsIStyleRuleProcessor.h',
         'nsMediaList.h',
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -106,33 +106,33 @@ CSSAnimation::PlayFromJS(ErrorResult& aR
 }
 
 void
 CSSAnimation::PlayFromStyle()
 {
   mIsStylePaused = false;
   if (!mPauseShouldStick) {
     ErrorResult rv;
-    PlayNoUpdate(rv, Animation::LimitBehavior::Continue);
+    Animation::Play(rv, Animation::LimitBehavior::Continue);
     // play() should not throw when LimitBehavior is Continue
     MOZ_ASSERT(!rv.Failed(), "Unexpected exception playing animation");
   }
 }
 
 void
 CSSAnimation::PauseFromStyle()
 {
   // Check if the pause state is being overridden
   if (mIsStylePaused) {
     return;
   }
 
   mIsStylePaused = true;
   ErrorResult rv;
-  PauseNoUpdate(rv);
+  Animation::Pause(rv);
   // pause() should only throw when *all* of the following conditions are true:
   // - we are in the idle state, and
   // - we have a negative playback rate, and
   // - we have an infinitely repeating animation
   // The first two conditions will never happen under regular style processing
   // but could happen if an author made modifications to the Animation object
   // and then updated animation-play-state. It's an unusual case and there's
   // no obvious way to pass on the exception information so we just silently
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -26,16 +26,17 @@
 #include "nsCoord.h"
 #include "nsMargin.h"
 #include "nsFont.h"
 #include "nsStyleAutoArray.h"
 #include "nsStyleCoord.h"
 #include "nsStyleConsts.h"
 #include "nsChangeHint.h"
 #include "nsPresContext.h"
+#include "nsTimingFunction.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsTArray.h"
 #include "nsCSSValue.h"
 #include "imgRequestProxy.h"
 #include "Orientation.h"
 #include "CounterStyleManager.h"
 #include <cstddef> // offsetof()
@@ -2091,129 +2092,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   }
 
   bool IsVisibleOrCollapsed() const {
     return ((mVisible == NS_STYLE_VISIBILITY_VISIBLE) ||
             (mVisible == NS_STYLE_VISIBILITY_COLLAPSE));
   }
 };
 
-struct nsTimingFunction
-{
-
-  enum class Type {
-    Ease,         // ease
-    Linear,       // linear
-    EaseIn,       // ease-in
-    EaseOut,      // ease-out
-    EaseInOut,    // ease-in-out
-    StepStart,    // step-start and steps(..., start)
-    StepEnd,      // step-end, steps(..., end) and steps(...)
-    CubicBezier,  // cubic-bezier()
-    Frames,       // frames()
-  };
-
-  // Whether the timing function type is represented by a spline,
-  // and thus will have mFunc filled in.
-  static bool IsSplineType(Type aType)
-  {
-    return aType != Type::StepStart &&
-           aType != Type::StepEnd &&
-           aType != Type::Frames;
-  }
-
-  explicit nsTimingFunction(int32_t aTimingFunctionType
-                              = NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE)
-  {
-    AssignFromKeyword(aTimingFunctionType);
-  }
-
-  nsTimingFunction(float x1, float y1, float x2, float y2)
-    : mType(Type::CubicBezier)
-  {
-    mFunc.mX1 = x1;
-    mFunc.mY1 = y1;
-    mFunc.mX2 = x2;
-    mFunc.mY2 = y2;
-  }
-
-  enum class Keyword { Implicit, Explicit };
-
-  nsTimingFunction(Type aType, uint32_t aStepsOrFrames)
-    : mType(aType)
-  {
-    MOZ_ASSERT(mType == Type::StepStart ||
-               mType == Type::StepEnd ||
-               mType == Type::Frames,
-               "wrong type");
-    mStepsOrFrames = aStepsOrFrames;
-  }
-
-  nsTimingFunction(const nsTimingFunction& aOther)
-  {
-    *this = aOther;
-  }
-
-  Type mType;
-  union {
-    struct {
-      float mX1;
-      float mY1;
-      float mX2;
-      float mY2;
-    } mFunc;
-    struct {
-      uint32_t mStepsOrFrames;
-    };
-  };
-
-  nsTimingFunction&
-  operator=(const nsTimingFunction& aOther)
-  {
-    if (&aOther == this) {
-      return *this;
-    }
-
-    mType = aOther.mType;
-
-    if (HasSpline()) {
-      mFunc.mX1 = aOther.mFunc.mX1;
-      mFunc.mY1 = aOther.mFunc.mY1;
-      mFunc.mX2 = aOther.mFunc.mX2;
-      mFunc.mY2 = aOther.mFunc.mY2;
-    } else {
-      mStepsOrFrames = aOther.mStepsOrFrames;
-    }
-
-    return *this;
-  }
-
-  bool operator==(const nsTimingFunction& aOther) const
-  {
-    if (mType != aOther.mType) {
-      return false;
-    }
-    if (HasSpline()) {
-      return mFunc.mX1 == aOther.mFunc.mX1 && mFunc.mY1 == aOther.mFunc.mY1 &&
-             mFunc.mX2 == aOther.mFunc.mX2 && mFunc.mY2 == aOther.mFunc.mY2;
-    }
-    return mStepsOrFrames == aOther.mStepsOrFrames;
-  }
-
-  bool operator!=(const nsTimingFunction& aOther) const
-  {
-    return !(*this == aOther);
-  }
-
-  bool HasSpline() const { return IsSplineType(mType); }
-
-private:
-  void AssignFromKeyword(int32_t aTimingFunctionType);
-};
-
 namespace mozilla {
 
 struct StyleTransition
 {
   StyleTransition() { /* leaves uninitialized; see also SetInitialValues */ }
   explicit StyleTransition(const StyleTransition& aCopy);
 
   void SetInitialValues();
new file mode 100644
--- /dev/null
+++ b/layout/style/nsTimingFunction.h
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsTimingFunction_h
+#define nsTimingFunction_h
+
+#include "nsStyleConsts.h"
+
+struct nsTimingFunction
+{
+  enum class Type {
+    Ease,         // ease
+    Linear,       // linear
+    EaseIn,       // ease-in
+    EaseOut,      // ease-out
+    EaseInOut,    // ease-in-out
+    StepStart,    // step-start and steps(..., start)
+    StepEnd,      // step-end, steps(..., end) and steps(...)
+    CubicBezier,  // cubic-bezier()
+    Frames,       // frames()
+  };
+
+  // Whether the timing function type is represented by a spline,
+  // and thus will have mFunc filled in.
+  static bool IsSplineType(Type aType)
+  {
+    return aType != Type::StepStart &&
+           aType != Type::StepEnd &&
+           aType != Type::Frames;
+  }
+
+  explicit nsTimingFunction(int32_t aTimingFunctionType
+                              = NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE)
+  {
+    AssignFromKeyword(aTimingFunctionType);
+  }
+
+  nsTimingFunction(float x1, float y1, float x2, float y2)
+    : mType(Type::CubicBezier)
+  {
+    mFunc.mX1 = x1;
+    mFunc.mY1 = y1;
+    mFunc.mX2 = x2;
+    mFunc.mY2 = y2;
+  }
+
+  enum class Keyword { Implicit, Explicit };
+
+  nsTimingFunction(Type aType, uint32_t aStepsOrFrames)
+    : mType(aType)
+  {
+    MOZ_ASSERT(mType == Type::StepStart ||
+               mType == Type::StepEnd ||
+               mType == Type::Frames,
+               "wrong type");
+    mStepsOrFrames = aStepsOrFrames;
+  }
+
+  nsTimingFunction(const nsTimingFunction& aOther)
+  {
+    *this = aOther;
+  }
+
+  Type mType;
+  union {
+    struct {
+      float mX1;
+      float mY1;
+      float mX2;
+      float mY2;
+    } mFunc;
+    struct {
+      uint32_t mStepsOrFrames;
+    };
+  };
+
+  nsTimingFunction&
+  operator=(const nsTimingFunction& aOther)
+  {
+    if (&aOther == this) {
+      return *this;
+    }
+
+    mType = aOther.mType;
+
+    if (HasSpline()) {
+      mFunc.mX1 = aOther.mFunc.mX1;
+      mFunc.mY1 = aOther.mFunc.mY1;
+      mFunc.mX2 = aOther.mFunc.mX2;
+      mFunc.mY2 = aOther.mFunc.mY2;
+    } else {
+      mStepsOrFrames = aOther.mStepsOrFrames;
+    }
+
+    return *this;
+  }
+
+  bool operator==(const nsTimingFunction& aOther) const
+  {
+    if (mType != aOther.mType) {
+      return false;
+    }
+    if (HasSpline()) {
+      return mFunc.mX1 == aOther.mFunc.mX1 && mFunc.mY1 == aOther.mFunc.mY1 &&
+             mFunc.mX2 == aOther.mFunc.mX2 && mFunc.mY2 == aOther.mFunc.mY2;
+    }
+    return mStepsOrFrames == aOther.mStepsOrFrames;
+  }
+
+  bool operator!=(const nsTimingFunction& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  bool HasSpline() const { return IsSplineType(mType); }
+
+private:
+  void AssignFromKeyword(int32_t aTimingFunctionType);
+};
+
+#endif // nsTimingFunction_h
--- a/media/audioipc/README_MOZILLA
+++ b/media/audioipc/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the audioipc-2
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The audioipc-2 git repository is: https://github.com/djg/audioipc-2.git
 
-The git commit ID used was 79c1622259b03ef58744da5e6501f95be81272cb (2018-03-03 08:55:52 +1000)
+The git commit ID used was 7e866e5ba304b271ab4c504a354ed7aa628343b8 (2018-03-06 09:37:35 +1300)
--- a/media/audioipc/audioipc/Cargo.toml
+++ b/media/audioipc/audioipc/Cargo.toml
@@ -6,18 +6,17 @@ authors = [
         "Dan Glastonbury <dan.glastonbury@gmail.com>"
         ]
 description = "Remote Cubeb IPC"
 
 [dependencies]
 cubeb = "0.4"
 bincode = "0.9"
 bytes = "0.4"
-# rayon-core in Gecko uses futures 0.1.13
-futures = "=0.1.13"
+futures = "0.1.18"
 iovec = "0.1"
 libc = "0.2"
 log = "^0.3.6"
 memmap = "0.5.2"
 scoped-tls = "0.1"
 serde = "1.*.*"
 serde_derive = "1.*.*"
 tokio-core = "0.1"
--- a/media/audioipc/audioipc/src/rpc/client/proxy.rs
+++ b/media/audioipc/audioipc/src/rpc/client/proxy.rs
@@ -88,17 +88,17 @@ impl<R, Q> ClientProxy<R, Q> {
         // The response to returned from the rpc client task over a
         // oneshot channel.
         let (tx, rx) = oneshot::channel();
 
         // If send returns an Err, its because the other side has been dropped.
         // By ignoring it, we are just dropping the `tx`, which will mean the
         // rx will return Canceled when polled. In turn, that is translated
         // into a BrokenPipe, which conveys the proper error.
-        let _ = self.tx.send((request, tx));
+        let _ = self.tx.unbounded_send((request, tx));
 
         Response { inner: rx }
     }
 }
 
 impl<R, Q> fmt::Debug for ClientProxy<R, Q>
 where
     R: fmt::Debug,
--- a/media/audioipc/client/Cargo.toml
+++ b/media/audioipc/client/Cargo.toml
@@ -6,16 +6,14 @@ authors = [
         "Dan Glastonbury <dan.glastonbury@gmail.com>"
         ]
 description = "Cubeb Backend for talking to remote cubeb server."
 
 [dependencies]
 audioipc = { path="../audioipc" }
 cubeb-backend = "0.4"
 foreign-types = "0.3"
-# rayon-core in Gecko uses futures 0.1.13
-futures = { version="=0.1.13", default-features=false, features=["use_std"] }
-# futures-cpupool 0.1.5 matches futures 0.1.13
-futures-cpupool = { version="=0.1.5", default-features=false }
+futures = { version="0.1.18", default-features=false, features=["use_std"] }
+futures-cpupool = { version="0.1.5", default-features=false }
 libc = "0.2"
 log = "^0.3.6"
 tokio-core = "0.1"
-tokio-uds = "0.1.7"
\ No newline at end of file
+tokio-uds = "0.1.7"
--- a/media/audioipc/server/Cargo.toml
+++ b/media/audioipc/server/Cargo.toml
@@ -10,16 +10,15 @@ description = "Remote cubeb server"
 [dependencies]
 audioipc = { path = "../audioipc" }
 cubeb = "0.4"
 bytes = "0.4"
 lazycell = "^0.4"
 libc = "0.2"
 log = "^0.3.6"
 slab = "0.3.0"
-# rayon-core in Gecko uses futures 0.1.13
-futures = "=0.1.13"
+futures = "0.1.18"
 tokio-core = "0.1"
 tokio-uds = "0.1.7"
 
 [dependencies.error-chain]
 version = "0.11.0"
-default-features = false
\ No newline at end of file
+default-features = false
--- a/netwerk/base/nsISocketTransport.idl
+++ b/netwerk/base/nsISocketTransport.idl
@@ -240,16 +240,25 @@ interface nsISocketTransport : nsITransp
     /**
      * If set, do not use TRR for resolving the host name. Intended only for
      * retries or other scenarios when TRR is deemed likely to have returned a
      * wrong adddress.
      */
     const unsigned long DISABLE_TRR = (1 << 8);
 
     /**
+     * Values for the connectionFlags
+     *
+     * When using BYPASS_CACHE, setting this bit will invalidate the existing
+     * cached entry immediately while the new resolve is being done to avoid
+     * other users from using stale content in the mean time.
+     */
+    const unsigned long REFRESH_CACHE = (1 << 9);
+
+    /**
      * An opaque flags for non-standard behavior of the TLS system.
      * It is unlikely this will need to be set outside of telemetry studies
      * relating to the TLS implementation.
      */
     attribute unsigned long tlsFlags;
 
     /**
      * Socket QoS/ToS markings. Valid values are IPTOS_DSCP_AFxx or
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -1101,16 +1101,18 @@ nsSocketTransport::ResolveHost()
     nsCOMPtr<nsIDNSService> dns = do_GetService(kDNSServiceCID, &rv);
     if (NS_FAILED(rv)) return rv;
 
     mResolving = true;
 
     uint32_t dnsFlags = 0;
     if (mConnectionFlags & nsSocketTransport::BYPASS_CACHE)
         dnsFlags = nsIDNSService::RESOLVE_BYPASS_CACHE;
+    if (mConnectionFlags & nsSocketTransport::REFRESH_CACHE)
+        dnsFlags = nsIDNSService::RESOLVE_REFRESH_CACHE;
     if (mConnectionFlags & nsSocketTransport::DISABLE_IPV6)
         dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
     if (mConnectionFlags & nsSocketTransport::DISABLE_IPV4)
         dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
     if (mConnectionFlags & nsSocketTransport::DISABLE_TRR)
         dnsFlags |= nsIDNSService::RESOLVE_DISABLE_TRR;
 
     NS_ASSERTION(!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV6) ||
@@ -1804,20 +1806,21 @@ nsSocketTransport::RecoverFromError()
                 mState = STATE_CLOSED;
                 mConnectionFlags &= ~(DISABLE_IPV6 | DISABLE_IPV4);
                 tryAgain = true;
             } else if (!(mConnectionFlags & DISABLE_TRR)) {
                 bool trrEnabled;
                 mDNSRecord->IsTRR(&trrEnabled);
                 if (trrEnabled) {
                     // Drop state to closed.  This will trigger a new round of
-                    // DNS resolving.
+                    // DNS resolving. Bypass the cache this time since the
+                    // cached data came from TRR and failed already!
                     SOCKET_LOG(("  failed to connect with TRR enabled, try w/o\n"));
                     mState = STATE_CLOSED;
-                    mConnectionFlags |= DISABLE_TRR;
+                    mConnectionFlags |= DISABLE_TRR | BYPASS_CACHE | REFRESH_CACHE;
                     tryAgain = true;
                 }
             }
         }
     }
 
     // prepare to try again.
     if (tryAgain) {
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -219,16 +219,22 @@ nsHostRecord::Cancel()
     }
     if (mTrrAAAA) {
         mTrrAAAA->Cancel();
         mTrrAAAA = nullptr;
     }
 }
 
 void
+nsHostRecord::Invalidate()
+{
+    mDoomed = true;
+}
+
+void
 nsHostRecord::SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, unsigned int grace)
 {
     mValidStart = now;
     mGraceStart = now + TimeDuration::FromSeconds(valid);
     mValidEnd = now + TimeDuration::FromSeconds(valid + grace);
 }
 
 void
@@ -732,18 +738,19 @@ nsHostResolver::ResolveHost(const char  
                             uint16_t                flags,
                             uint16_t                af,
                             const char             *netInterface,
                             nsResolveHostCallback  *aCallback)
 {
     NS_ENSURE_TRUE(host && *host, NS_ERROR_UNEXPECTED);
     NS_ENSURE_TRUE(netInterface, NS_ERROR_UNEXPECTED);
 
-    LOG(("Resolving host [%s%s%s]%s.\n", LOG_HOST(host, netInterface),
-         flags & RES_BYPASS_CACHE ? " - bypassing cache" : ""));
+    LOG(("Resolving host [%s%s%s]%s%s.\n", LOG_HOST(host, netInterface),
+         flags & RES_BYPASS_CACHE ? " - bypassing cache" : "",
+         flags & RES_REFRESH_CACHE ? " - refresh cache" : ""));
 
     // ensure that we are working with a valid hostname before proceeding.  see
     // bug 304904 for details.
     if (!net_IsValidHostName(nsDependentCString(host)))
         return NS_ERROR_UNKNOWN_HOST;
 
     RefPtr<nsResolveHostCallback> callback(aCallback);
     // if result is set inside the lock, then we need to issue the
@@ -917,16 +924,20 @@ nsHostResolver::ResolveHost(const char  
                     }
                 }
                 // If no valid address was found in the cache or this is an
                 // AF_UNSPEC request, then start a new lookup.
                 if (!result) {
                     LOG(("  No usable address in cache for host [%s%s%s].",
                          LOG_HOST(host, netInterface)));
 
+                    if (flags & RES_REFRESH_CACHE) {
+                        rec->Invalidate();
+                    }
+
                     // Add callback to the list of pending callbacks.
                     rec->mCallbacks.insertBack(callback);
                     rec->flags = flags;
                     rv = NameLookup(rec);
                     Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
                                           METHOD_NETWORK_FIRST);
                     if (NS_FAILED(rv) && callback->isInList()) {
                         callback->remove();
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -138,16 +138,19 @@ public:
     // mValidEnd, and mGraceStart). valid and grace are durations in seconds.
     void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid,
                        unsigned int grace);
     void CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecord);
 
     // Checks if the record is usable (not expired and has a value)
     bool HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags = 0) const;
 
+    // Mark hostrecord as not usable
+    void Invalidate();
+
     // hold addr_info_lock when calling the blacklist functions
     bool   Blacklisted(mozilla::net::NetAddr *query);
     void   ResetBlacklist();
     void   ReportUnusable(mozilla::net::NetAddr *addr);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     enum DnsPriority {
@@ -366,17 +369,18 @@ public:
         RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME,
         RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM,
         RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW,
         RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE,
         //RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used
         RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE,
         //RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used
         RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION,
-        RES_DISABLE_TRR = nsIDNSService::RESOLVE_DISABLE_TRR
+        RES_DISABLE_TRR = nsIDNSService::RESOLVE_DISABLE_TRR,
+        RES_REFRESH_CACHE = nsIDNSService::RESOLVE_REFRESH_CACHE
     };
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     /**
      * Flush the DNS cache.
      */
     void FlushCache();
--- a/netwerk/dns/nsIDNSService.idl
+++ b/netwerk/dns/nsIDNSService.idl
@@ -234,9 +234,14 @@ interface nsIDNSService : nsISupports
      */
     const unsigned long RESOLVE_ALLOW_NAME_COLLISION = (1 << 8);
 
     /**
      * If set, do not use TRR for resolving the host name.
      */
     const unsigned long RESOLVE_DISABLE_TRR = (1 << 9);
 
+    /**
+     * if set (together with RESOLVE_BYPASS_CACHE), invalidate the DNS
+     * existing cache entry first (if existing) then make a new resolve.
+     */
+    const unsigned long RESOLVE_REFRESH_CACHE = (1 << 10);
 };
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -183,24 +183,24 @@ function BookmarkQuery(collection, id) {
   Bookmark.call(this, collection, id, "query");
 }
 BookmarkQuery.prototype = {
   __proto__: Bookmark.prototype,
   _logName: "Sync.Record.BookmarkQuery",
 
   toSyncBookmark() {
     let info = Bookmark.prototype.toSyncBookmark.call(this);
-    info.folder = this.folderName;
+    info.folder = this.folderName || undefined; // empty string -> undefined
     info.query = this.queryId;
     return info;
   },
 
   fromSyncBookmark(item) {
     Bookmark.prototype.fromSyncBookmark.call(this, item);
-    this.folderName = item.folder;
+    this.folderName = item.folder || undefined; // empty string -> undefined
     this.queryId = item.query;
   },
 };
 
 Utils.deferGetSet(BookmarkQuery,
                   "cleartext",
                   ["folderName", "queryId"]);
 
--- a/services/sync/tests/unit/test_bookmark_record.js
+++ b/services/sync/tests/unit/test_bookmark_record.js
@@ -35,8 +35,27 @@ add_task(async function test_bookmark_re
 
   _("Decrypting the record");
 
   let payload = await bookmarkItem.decrypt(keyBundle);
   Assert.equal(payload.stuff, "my payload here");
   Assert.equal(bookmarkItem.getTypeObject(bookmarkItem.type), Bookmark);
   Assert.notEqual(payload, bookmarkItem.payload); // wrap.data.payload is the encrypted one
 });
+
+add_task(async function test_query_foldername() {
+  // Bug 1443388
+  let checks = [
+    ["foo", "foo"],
+    ["", undefined]
+  ];
+  for (let [inVal, outVal] of checks) {
+    let bmk1 = new BookmarkQuery("bookmarks", Utils.makeGUID());
+    bmk1.fromSyncBookmark({url: Services.io.newURI("https://example.com"), folder: inVal});
+    Assert.strictEqual(bmk1.folderName, outVal);
+
+    // other direction
+    let bmk2 = new BookmarkQuery("bookmarks", Utils.makeGUID());
+    bmk2.folderName = inVal;
+    let record = bmk2.toSyncBookmark();
+    Assert.strictEqual(record.folder, outVal);
+  }
+});
--- a/servo/components/script/stylesheet_loader.rs
+++ b/servo/components/script/stylesheet_loader.rs
@@ -29,17 +29,17 @@ use std::mem;
 use std::sync::Mutex;
 use std::sync::atomic::AtomicBool;
 use style::media_queries::MediaList;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, SharedRwLock};
 use style::stylesheets::{CssRules, ImportRule, Namespaces, Stylesheet, StylesheetContents, Origin};
 use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
 use style::stylesheets::import_rule::ImportSheet;
-use style::values::specified::url::SpecifiedUrl;
+use style::values::CssUrl;
 
 pub trait StylesheetOwner {
     /// Returns whether this element was inserted by the parser (i.e., it should
     /// trigger a document-load-blocking load).
     fn parser_inserted(&self) -> bool;
 
     /// Which referrer policy should loads triggered by this owner follow, or
     /// `None` for the default.
@@ -271,17 +271,17 @@ impl<'a> StylesheetLoader<'a> {
     }
 }
 
 impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> {
     /// Request a stylesheet after parsing a given `@import` rule, and return
     /// the constructed `@import` rule.
     fn request_stylesheet(
         &self,
-        url: SpecifiedUrl,
+        url: CssUrl,
         source_location: SourceLocation,
         context: &ParserContext,
         lock: &SharedRwLock,
         media: Arc<Locked<MediaList>>,
     ) -> Arc<Locked<ImportRule>> {
         let sheet = Arc::new(Stylesheet {
             contents: StylesheetContents {
                 rules: CssRules::new(Vec::new(), lock),
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -12,17 +12,17 @@ use app_units::Au;
 use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible};
 use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetLayerImageImageValue};
 use gecko_bindings::bindings::{Gecko_InitializeImageCropRect, Gecko_SetImageElement};
 use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
 use gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
 use std::f32::consts::PI;
 use stylesheets::{Origin, RulesMutateError};
-use values::computed::{Angle, CalcLengthOrPercentage, ComputedUrl, Gradient, Image};
+use values::computed::{Angle, CalcLengthOrPercentage, ComputedImageUrl, Gradient, Image};
 use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto, Percentage, TextAlign};
 use values::generics::box_::VerticalAlign;
 use values::generics::grid::{TrackListValue, TrackSize};
 use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
 use values::generics::rect::Rect;
 
 impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
     fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
@@ -150,22 +150,22 @@ impl nsStyleImage {
     /// Set a given Servo `Image` value into this `nsStyleImage`.
     pub fn set(&mut self, image: Image) {
         match image {
             GenericImage::Gradient(boxed_gradient) => {
                 self.set_gradient(*boxed_gradient)
             },
             GenericImage::Url(ref url) => {
                 unsafe {
-                    Gecko_SetLayerImageImageValue(self, url.image_value.clone().unwrap().get());
+                    Gecko_SetLayerImageImageValue(self, url.image_value.get());
                 }
             },
             GenericImage::Rect(ref image_rect) => {
                 unsafe {
-                    Gecko_SetLayerImageImageValue(self, image_rect.url.image_value.clone().unwrap().get());
+                    Gecko_SetLayerImageImageValue(self, image_rect.url.image_value.get());
                     Gecko_InitializeImageCropRect(self);
 
                     // Set CropRect
                     let ref mut rect = *self.mCropRect.mPtr;
                     image_rect.top.to_gecko_style_coord(&mut rect.data_at_mut(0));
                     image_rect.right.to_gecko_style_coord(&mut rect.data_at_mut(1));
                     image_rect.bottom.to_gecko_style_coord(&mut rect.data_at_mut(2));
                     image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
@@ -414,23 +414,21 @@ impl nsStyleImage {
                 use gecko_string_cache::Atom;
                 let atom = Gecko_GetImageElement(self);
                 Some(GenericImage::Element(Atom::from(atom)))
             },
             _ => panic!("Unexpected image type")
         }
     }
 
-    unsafe fn get_image_url(self: &nsStyleImage) -> ComputedUrl {
+    unsafe fn get_image_url(self: &nsStyleImage) -> ComputedImageUrl {
         use gecko_bindings::bindings::Gecko_GetURLValue;
         let url_value = Gecko_GetURLValue(self);
-        let mut url = ComputedUrl::from_url_value_data(url_value.as_ref().unwrap())
-                                    .expect("Could not convert to ComputedUrl");
-        url.build_image_value();
-        url
+        ComputedImageUrl::from_url_value_data(url_value.as_ref().unwrap())
+            .expect("Could not convert to ComputedUrl")
     }
 
     unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> {
         use gecko::values::convert_nscolor_to_rgba;
         use gecko_bindings::bindings::Gecko_GetGradientImageValue;
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1373,32 +1373,32 @@ extern "C" {
 }
 extern "C" {
     pub fn Gecko_NewBasicShape(shape: *mut StyleShapeSource, type_: StyleBasicShapeType);
 }
 extern "C" {
     pub fn Gecko_NewShapeImage(shape: *mut StyleShapeSource);
 }
 extern "C" {
-    pub fn Gecko_StyleShapeSource_SetURLValue(shape: *mut StyleShapeSource, uri: ServoBundledURI);
+    pub fn Gecko_StyleShapeSource_SetURLValue(shape: *mut StyleShapeSource, uri: *mut URLValue);
 }
 extern "C" {
     pub fn Gecko_ResetFilters(effects: *mut nsStyleEffects, new_len: usize);
 }
 extern "C" {
     pub fn Gecko_CopyFiltersFrom(aSrc: *mut nsStyleEffects, aDest: *mut nsStyleEffects);
 }
 extern "C" {
-    pub fn Gecko_nsStyleFilter_SetURLValue(effects: *mut nsStyleFilter, uri: ServoBundledURI);
+    pub fn Gecko_nsStyleFilter_SetURLValue(effects: *mut nsStyleFilter, uri: *mut URLValue);
 }
 extern "C" {
     pub fn Gecko_nsStyleSVGPaint_CopyFrom(dest: *mut nsStyleSVGPaint, src: *const nsStyleSVGPaint);
 }
 extern "C" {
-    pub fn Gecko_nsStyleSVGPaint_SetURLValue(paint: *mut nsStyleSVGPaint, uri: ServoBundledURI);
+    pub fn Gecko_nsStyleSVGPaint_SetURLValue(paint: *mut nsStyleSVGPaint, uri: *mut URLValue);
 }
 extern "C" {
     pub fn Gecko_nsStyleSVGPaint_Reset(paint: *mut nsStyleSVGPaint);
 }
 extern "C" {
     pub fn Gecko_nsStyleSVG_SetDashArrayLength(svg: *mut nsStyleSVG, len: u32);
 }
 extern "C" {
@@ -1409,16 +1409,19 @@ extern "C" {
 }
 extern "C" {
     pub fn Gecko_nsStyleSVG_CopyContextProperties(dst: *mut nsStyleSVG, src: *const nsStyleSVG);
 }
 extern "C" {
     pub fn Gecko_NewURLValue(uri: ServoBundledURI) -> *mut URLValue;
 }
 extern "C" {
+    pub fn Gecko_URLValue_SizeOfIncludingThis(url: *mut URLValue) -> usize;
+}
+extern "C" {
     pub fn Gecko_AddRefCSSURLValueArbitraryThread(aPtr: *mut URLValue);
 }
 extern "C" {
     pub fn Gecko_ReleaseCSSURLValueArbitraryThread(aPtr: *mut URLValue);
 }
 extern "C" {
     pub fn Gecko_AddRefURLExtraDataArbitraryThread(aPtr: *mut RawGeckoURLExtraData);
 }
@@ -1517,17 +1520,17 @@ extern "C" {
 }
 extern "C" {
     pub fn Gecko_CSSValue_SetAtomIdent(css_value: nsCSSValueBorrowedMut, atom: *mut nsAtom);
 }
 extern "C" {
     pub fn Gecko_CSSValue_SetArray(css_value: nsCSSValueBorrowedMut, len: i32);
 }
 extern "C" {
-    pub fn Gecko_CSSValue_SetURL(css_value: nsCSSValueBorrowedMut, uri: ServoBundledURI);
+    pub fn Gecko_CSSValue_SetURL(css_value: nsCSSValueBorrowedMut, uri: *mut URLValue);
 }
 extern "C" {
     pub fn Gecko_CSSValue_SetInt(css_value: nsCSSValueBorrowedMut, integer: i32, unit: nsCSSUnit);
 }
 extern "C" {
     pub fn Gecko_CSSValue_SetFloat(css_value: nsCSSValueBorrowedMut, value: f32, unit: nsCSSUnit);
 }
 extern "C" {
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -1,98 +1,78 @@
 /* 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/. */
 
 //! Common handling for the specified value CSS url() values.
 
+use cssparser::Parser;
+use gecko_bindings::bindings;
 use gecko_bindings::structs::{ServoBundledURI, URLExtraData};
 use gecko_bindings::structs::mozilla::css::URLValueData;
 use gecko_bindings::structs::root::{nsStyleImageRequest, RustString};
-use gecko_bindings::structs::root::mozilla::css::ImageValue;
+use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
 use gecko_bindings::sugar::refptr::RefPtr;
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
-use parser::ParserContext;
+use parser::{Parse, ParserContext};
 use servo_arc::{Arc, RawOffsetArc};
 use std::mem;
 use style_traits::ParseError;
 
-/// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls.
+/// A CSS url() value for gecko.
 #[css(function = "url")]
 #[derive(Clone, Debug, PartialEq, ToCss)]
-pub struct SpecifiedUrl {
+pub struct CssUrl {
     /// The URL in unresolved string form.
     ///
     /// Refcounted since cloning this should be cheap and data: uris can be
     /// really large.
     serialization: Arc<String>,
 
     /// The URL extra data.
     #[css(skip)]
     pub extra_data: RefPtr<URLExtraData>,
+}
 
-    /// Cache ImageValue, if any, so that we can reuse it while rematching a
-    /// a property with this specified url value.
-    #[css(skip)]
-    pub image_value: Option<RefPtr<ImageValue>>,
-}
-trivial_to_computed_value!(SpecifiedUrl);
-
-impl SpecifiedUrl {
+impl CssUrl {
     /// Try to parse a URL from a string value that is a valid CSS token for a
     /// URL.
     ///
     /// Returns `Err` in the case that extra_data is incomplete.
     pub fn parse_from_string<'a>(url: String,
                                  context: &ParserContext)
                                  -> Result<Self, ParseError<'a>> {
-        Ok(SpecifiedUrl {
+        Ok(CssUrl {
             serialization: Arc::new(url),
             extra_data: context.url_data.clone(),
-            image_value: None,
         })
     }
 
     /// Returns true if the URL is definitely invalid. We don't eagerly resolve
     /// URLs in gecko, so we just return false here.
     /// use its |resolved| status.
     pub fn is_invalid(&self) -> bool {
         false
     }
 
     /// Convert from URLValueData to SpecifiedUrl.
-    pub unsafe fn from_url_value_data(url: &URLValueData)
-                                       -> Result<SpecifiedUrl, ()> {
-        Ok(SpecifiedUrl {
+    unsafe fn from_url_value_data(url: &URLValueData) -> Result<Self, ()> {
+        Ok(CssUrl {
             serialization: if url.mUsingRustString {
                 let arc_type = url.mStrings.mRustString.as_ref()
                     as *const _ as
                     *const RawOffsetArc<String>;
                 Arc::from_raw_offset((*arc_type).clone())
             } else {
                 Arc::new(url.mStrings.mString.as_ref().to_string())
             },
             extra_data: url.mExtraData.to_safe(),
-            image_value: None,
         })
     }
 
-    /// Convert from nsStyleImageRequest to SpecifiedUrl.
-    pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result<SpecifiedUrl, ()> {
-        if image_request.mImageValue.mRawPtr.is_null() {
-            return Err(());
-        }
-
-        let image_value = image_request.mImageValue.mRawPtr.as_ref().unwrap();
-        let ref url_value_data = image_value._base;
-        let mut result = Self::from_url_value_data(url_value_data)?;
-        result.build_image_value();
-        Ok(result)
-    }
-
     /// Returns true if this URL looks like a fragment.
     /// See https://drafts.csswg.org/css-values/#local-urls
     pub fn is_fragment(&self) -> bool {
         self.as_str().chars().next().map_or(false, |c| c == '#')
     }
 
     /// Return the resolved url as string, or the empty string if it's invalid.
     ///
@@ -113,46 +93,163 @@ impl SpecifiedUrl {
         let arc_offset = Arc::into_raw_offset(self.serialization.clone());
         ServoBundledURI {
             mURLString: unsafe {
                 mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset)
             },
             mExtraData: self.extra_data.get(),
         }
     }
-
-    /// Build and carry an image value on request.
-    pub fn build_image_value(&mut self) {
-        use gecko_bindings::bindings::Gecko_ImageValue_Create;
+}
 
-        debug_assert_eq!(self.image_value, None);
-        self.image_value = {
-            unsafe {
-                let ptr = Gecko_ImageValue_Create(self.for_ffi());
-                // We do not expect Gecko_ImageValue_Create returns null.
-                debug_assert!(!ptr.is_null());
-                Some(RefPtr::from_addrefed(ptr))
-            }
-        }
+impl Parse for CssUrl {
+    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+        let url = input.expect_url()?;
+        Self::parse_from_string(url.as_ref().to_owned(), context)
     }
 }
 
-impl MallocSizeOf for SpecifiedUrl {
+impl Eq for CssUrl {}
+
+impl MallocSizeOf for CssUrl {
     fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
-        use gecko_bindings::bindings::Gecko_ImageValue_SizeOfIncludingThis;
-
-        let mut n = 0;
-
         // XXX: measure `serialization` once bug 1397971 lands
 
         // We ignore `extra_data`, because RefPtr is tricky, and there aren't
         // many of them in practise (sharing is common).
 
-        if let Some(ref image_value) = self.image_value {
-            // Although this is a RefPtr, this is the primary reference because
-            // SpecifiedUrl is responsible for creating the image_value. So we
-            // measure unconditionally here.
-            n += unsafe { Gecko_ImageValue_SizeOfIncludingThis(image_value.clone().get()) };
-        }
+        0
+    }
+}
+
+/// A specified url() value for general usage.
+#[derive(Clone, Debug, ToCss)]
+pub struct SpecifiedUrl {
+    /// The specified url value.
+    pub url: CssUrl,
+    /// Gecko's URLValue so that we can reuse it while rematching a
+    /// property with this specified value.
+    #[css(skip)]
+    pub url_value: RefPtr<URLValue>,
+}
+trivial_to_computed_value!(SpecifiedUrl);
+
+impl SpecifiedUrl {
+    fn from_css_url(url: CssUrl) -> Self {
+        let url_value = unsafe {
+            let ptr = bindings::Gecko_NewURLValue(url.for_ffi());
+            // We do not expect Gecko_NewURLValue returns null.
+            debug_assert!(!ptr.is_null());
+            RefPtr::from_addrefed(ptr)
+        };
+        SpecifiedUrl { url, url_value }
+    }
 
+    /// Convert from URLValueData to SpecifiedUrl.
+    pub unsafe fn from_url_value_data(url: &URLValueData) -> Result<Self, ()> {
+        CssUrl::from_url_value_data(url).map(Self::from_css_url)
+    }
+}
+
+impl PartialEq for SpecifiedUrl {
+    fn eq(&self, other: &Self) -> bool {
+        self.url.eq(&other.url)
+    }
+}
+
+impl Eq for SpecifiedUrl {}
+
+impl Parse for SpecifiedUrl {
+    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+        CssUrl::parse(context, input).map(Self::from_css_url)
+    }
+}
+
+impl MallocSizeOf for SpecifiedUrl {
+    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+        let mut n = self.url.size_of(ops);
+        // Although this is a RefPtr, this is the primary reference because
+        // SpecifiedUrl is responsible for creating the url_value. So we
+        // measure unconditionally here.
+        n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) };
         n
     }
 }
+
+/// A specified url() value for image.
+///
+/// This exists so that we can construct `ImageValue` and reuse it.
+#[derive(Clone, Debug, ToCss)]
+pub struct SpecifiedImageUrl {
+    /// The specified url value.
+    pub url: CssUrl,
+    /// Gecko's ImageValue so that we can reuse it while rematching a
+    /// property with this specified value.
+    #[css(skip)]
+    pub image_value: RefPtr<ImageValue>,
+}
+trivial_to_computed_value!(SpecifiedImageUrl);
+
+impl SpecifiedImageUrl {
+    fn from_css_url(url: CssUrl) -> Self {
+        let image_value = unsafe {
+            let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi());
+            // We do not expect Gecko_ImageValue_Create returns null.
+            debug_assert!(!ptr.is_null());
+            RefPtr::from_addrefed(ptr)
+        };
+        SpecifiedImageUrl { url, image_value }
+    }
+
+    /// Parse a URL from a string value. See SpecifiedUrl::parse_from_string.
+    pub fn parse_from_string<'a>(
+        url: String,
+        context: &ParserContext
+    ) -> Result<Self, ParseError<'a>> {
+        CssUrl::parse_from_string(url, context).map(Self::from_css_url)
+    }
+
+    /// Convert from URLValueData to SpecifiedUrl.
+    pub unsafe fn from_url_value_data(url: &URLValueData) -> Result<Self, ()> {
+        CssUrl::from_url_value_data(url).map(Self::from_css_url)
+    }
+
+    /// Convert from nsStyleImageRequest to SpecifiedUrl.
+    pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result<Self, ()> {
+        if image_request.mImageValue.mRawPtr.is_null() {
+            return Err(());
+        }
+
+        let image_value = image_request.mImageValue.mRawPtr.as_ref().unwrap();
+        let url_value_data = &image_value._base;
+        Self::from_url_value_data(url_value_data)
+    }
+}
+
+impl Parse for SpecifiedImageUrl {
+    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+        CssUrl::parse(context, input).map(Self::from_css_url)
+    }
+}
+
+impl PartialEq for SpecifiedImageUrl {
+    fn eq(&self, other: &Self) -> bool {
+        self.url.eq(&other.url)
+    }
+}
+
+impl Eq for SpecifiedImageUrl {}
+
+impl MallocSizeOf for SpecifiedImageUrl {
+    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+        let mut n = self.url.size_of(ops);
+        // Although this is a RefPtr, this is the primary reference because
+        // SpecifiedUrl is responsible for creating the image_value. So we
+        // measure unconditionally here.
+        n += unsafe { bindings::Gecko_ImageValue_SizeOfIncludingThis(self.image_value.get()) };
+        n
+    }
+}
+
+/// The computed value of a CSS `url()`.
+pub type ComputedUrl = SpecifiedUrl;
+/// The computed value of a CSS `url()` for image.
+pub type ComputedImageUrl = SpecifiedImageUrl;
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -207,17 +207,17 @@ impl nsCSSValue {
 
     /// Set to a number value
     pub fn set_number(&mut self, number: f32) {
         unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) }
     }
 
     /// Set to a url value
     pub fn set_url(&mut self, url: &SpecifiedUrl) {
-        unsafe { bindings::Gecko_CSSValue_SetURL(self, url.for_ffi()) }
+        unsafe { bindings::Gecko_CSSValue_SetURL(self, url.url_value.get()) }
     }
 
     /// Set to an array of given length
     pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
         unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
         unsafe { self.mValue.mArray.as_mut().as_mut() }.unwrap()
     }
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -691,17 +691,17 @@ def set_gecko_property(ffi_name, expr):
             SVGPaintKind::ContextFill => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill;
             }
             SVGPaintKind::ContextStroke => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke;
             }
             SVGPaintKind::PaintServer(url) => {
                 unsafe {
-                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.for_ffi());
+                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.url_value.get());
                 }
             }
             SVGPaintKind::Color(color) => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
                 unsafe {
                     *paint.mPaint.mColor.as_mut() = convert_rgba_to_nscolor(&color);
                 }
             }
@@ -931,28 +931,19 @@ def set_gecko_property(ffi_name, expr):
                         .expect("Failed to clone ${ident}");
         BorderCornerRadius::new(width, height)
     }
 </%def>
 
 <%def name="impl_css_url(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
-        use gecko_bindings::sugar::refptr::RefPtr;
         match v {
             Either::First(url) => {
-                let refptr = unsafe {
-                    let ptr = bindings::Gecko_NewURLValue(url.for_ffi());
-                    if ptr.is_null() {
-                        self.gecko.${gecko_ffi_name}.clear();
-                        return;
-                    }
-                    RefPtr::from_addrefed(ptr)
-                };
-                self.gecko.${gecko_ffi_name}.set_move(refptr)
+                self.gecko.${gecko_ffi_name}.set_move(url.url_value.clone())
             }
             Either::Second(_none) => {
                 unsafe {
                     self.gecko.${gecko_ffi_name}.clear();
                 }
             }
         }
     }
@@ -4067,18 +4058,17 @@ fn static_assert() {
         match image {
             longhands::list_style_image::computed_value::T(Either::Second(_none)) => {
                 unsafe {
                     Gecko_SetListStyleImageNone(&mut self.gecko);
                 }
             }
             longhands::list_style_image::computed_value::T(Either::First(ref url)) => {
                 unsafe {
-                    Gecko_SetListStyleImageImageValue(&mut self.gecko,
-                                                      url.image_value.clone().unwrap().get());
+                    Gecko_SetListStyleImageImageValue(&mut self.gecko, url.image_value.get());
                 }
                 // We don't need to record this struct as uncacheable, like when setting
                 // background-image to a url() value, since only properties in reset structs
                 // are re-used from the applicable declaration cache, and the List struct
                 // is an inherited struct.
             }
         }
     }
@@ -4087,27 +4077,27 @@ fn static_assert() {
         unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); }
     }
 
     pub fn reset_list_style_image(&mut self, other: &Self) {
         self.copy_list_style_image_from(other)
     }
 
     pub fn clone_list_style_image(&self) -> longhands::list_style_image::computed_value::T {
-        use values::specified::url::SpecifiedUrl;
+        use values::specified::url::SpecifiedImageUrl;
         use values::{Either, None_};
 
         longhands::list_style_image::computed_value::T(
             match self.gecko.mListStyleImage.mRawPtr.is_null() {
                 true => Either::Second(None_),
                 false => {
                     unsafe {
                         let ref gecko_image_request = *self.gecko.mListStyleImage.mRawPtr;
-                        Either::First(SpecifiedUrl::from_image_request(gecko_image_request)
-                                      .expect("mListStyleImage could not convert to SpecifiedUrl"))
+                        Either::First(SpecifiedImageUrl::from_image_request(gecko_image_request)
+                                      .expect("mListStyleImage could not convert to SpecifiedImageUrl"))
                     }
                 }
             }
         )
     }
 
     pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T, device: &Device) {
         use gecko_bindings::bindings::Gecko_SetCounterStyleToString;
@@ -4439,17 +4429,17 @@ fn static_assert() {
                         }
                     }
 
                     let gecko_shadow = init_shadow(gecko_filter);
                     gecko_shadow.mArray[0].set_from_simple_shadow(shadow);
                 },
                 Url(ref url) => {
                     unsafe {
-                        bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.for_ffi());
+                        bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.url_value.get());
                     }
                 },
             }
         }
     }
 
     pub fn copy_filter_from(&mut self, other: &Self) {
         unsafe {
@@ -4965,17 +4955,17 @@ fn static_assert() {
         // clean up existing struct
         unsafe { Gecko_DestroyShapeSource(${ident}) };
         ${ident}.mType = StyleShapeSourceType::None;
 
         match v {
             % if ident == "clip_path":
             ShapeSource::ImageOrUrl(ref url) => {
                 unsafe {
-                    bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.for_ffi())
+                    bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.url_value.get())
                 }
             }
             % elif ident == "shape_outside":
             ShapeSource::ImageOrUrl(image) => {
                 unsafe {
                     bindings::Gecko_NewShapeImage(${ident});
                     let style_image = &mut *${ident}.mShapeImage.mPtr;
                     style_image.set(image);
@@ -5285,18 +5275,20 @@ clip-path
             CursorKind::MozZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT,
         } as u8;
 
         unsafe {
             Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
         }
         for i in 0..v.images.len() {
             unsafe {
-                Gecko_SetCursorImageValue(&mut self.gecko.mCursorImages[i],
-                                          v.images[i].url.clone().image_value.unwrap().get());
+                Gecko_SetCursorImageValue(
+                    &mut self.gecko.mCursorImages[i],
+                    v.images[i].url.image_value.get(),
+                );
             }
 
             // We don't need to record this struct as uncacheable, like when setting
             // background-image to a url() value, since only properties in reset structs
             // are re-used from the applicable declaration cache, and the Pointing struct
             // is an inherited struct.
 
             match v.images[i].hotspot {
@@ -5321,17 +5313,17 @@ clip-path
 
     pub fn reset_cursor(&mut self, other: &Self) {
         self.copy_cursor_from(other)
     }
 
     pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T {
         use values::computed::pointing::CursorImage;
         use style_traits::cursor::CursorKind;
-        use values::specified::url::SpecifiedUrl;
+        use values::specified::url::SpecifiedImageUrl;
 
         let keyword = match self.gecko.mCursor as u32 {
             structs::NS_STYLE_CURSOR_AUTO => CursorKind::Auto,
             structs::NS_STYLE_CURSOR_NONE => CursorKind::None,
             structs::NS_STYLE_CURSOR_DEFAULT => CursorKind::Default,
             structs::NS_STYLE_CURSOR_POINTER => CursorKind::Pointer,
             structs::NS_STYLE_CURSOR_CONTEXT_MENU => CursorKind::ContextMenu,
             structs::NS_STYLE_CURSOR_HELP => CursorKind::Help,
@@ -5366,18 +5358,18 @@ clip-path
             structs::NS_STYLE_CURSOR_ZOOM_IN => CursorKind::ZoomIn,
             structs::NS_STYLE_CURSOR_ZOOM_OUT => CursorKind::ZoomOut,
             _ => panic!("Found unexpected value in style struct for cursor property"),
         };
 
         let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| {
             let url = unsafe {
                 let gecko_image_request = gecko_cursor_image.mImage.mRawPtr.as_ref().unwrap();
-                SpecifiedUrl::from_image_request(&gecko_image_request)
-                    .expect("mCursorImages.mImage could not convert to SpecifiedUrl")
+                SpecifiedImageUrl::from_image_request(&gecko_image_request)
+                    .expect("mCursorImages.mImage could not convert to SpecifiedImageUrl")
             };
 
             let hotspot =
                 if gecko_cursor_image.mHaveHotspot {
                     Some((gecko_cursor_image.mHotspotX, gecko_cursor_image.mHotspotY))
                 } else {
                     None
                 };
@@ -5545,18 +5537,20 @@ clip-path
                                 &name,
                                 &sep,
                                 style.clone(),
                                 device,
                             );
                         }
                         ContentItem::Url(ref url) => {
                             unsafe {
-                                bindings::Gecko_SetContentDataImageValue(&mut self.gecko.mContents[i],
-                                    url.image_value.clone().unwrap().get())
+                                bindings::Gecko_SetContentDataImageValue(
+                                    &mut self.gecko.mContents[i],
+                                    url.image_value.get(),
+                                )
                             }
                         }
                     }
                 }
             }
         }
     }
 
@@ -5573,17 +5567,17 @@ clip-path
 
     pub fn clone_content(&self) -> longhands::content::computed_value::T {
         use Atom;
         use gecko::conversions::string_from_chars_pointer;
         use gecko_bindings::structs::nsStyleContentType::*;
         use values::computed::counters::{Content, ContentItem};
         use values::{CustomIdent, Either};
         use values::generics::CounterStyleOrNone;
-        use values::specified::url::SpecifiedUrl;
+        use values::specified::url::SpecifiedImageUrl;
         use values::specified::Attr;
 
         if self.gecko.mContents.is_empty() {
             return Content::Normal;
         }
 
         if self.gecko.mContents.len() == 1 &&
            self.gecko.mContents[0].mType == eStyleContentType_AltContent {
@@ -5636,18 +5630,18 @@ clip-path
                             ContentItem::Counters(ident, separator.into_boxed_str(), style)
                         }
                     },
                     eStyleContentType_Image => {
                         unsafe {
                             let gecko_image_request =
                                 &**gecko_content.mContent.mImage.as_ref();
                             ContentItem::Url(
-                                SpecifiedUrl::from_image_request(gecko_image_request)
-                                    .expect("mContent could not convert to SpecifiedUrl")
+                                SpecifiedImageUrl::from_image_request(gecko_image_request)
+                                    .expect("mContent could not convert to SpecifiedImageUrl")
                             )
                         }
                     },
                     _ => panic!("Found unexpected value in style struct for content property"),
                 }
             }).collect::<Vec<_>>().into_boxed_slice()
         )
     }
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -606,17 +606,16 @@
                          gecko_ffi_name="mAppearance",
                          gecko_constant_prefix="ThemeWidgetType_NS_THEME",
                          products="gecko",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)",
                          animation_value_type="discrete")}
 
 ${helpers.predefined_type("-moz-binding", "UrlOrNone", "Either::Second(None_)",
                           products="gecko",
-                          boxed= product == "gecko",
                           animation_value_type="none",
                           gecko_ffi_name="mBinding",
                           spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)")}
 
 ${helpers.single_keyword("-moz-orient",
                           "inline block horizontal vertical",
                           products="gecko",
                           gecko_ffi_name="mOrient",
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -109,29 +109,26 @@
 ${helpers.single_keyword("clip-rule", "nonzero evenodd",
                          products="gecko",
                          gecko_enum_prefix="StyleFillRule",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}
 
 ${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
                           products="gecko",
-                          boxed= product == "gecko",
                           animation_value_type="discrete",
                           spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
 
 ${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
                           products="gecko",
-                          boxed= product == "gecko",
                           animation_value_type="discrete",
                           spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
 
 ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
                           products="gecko",
-                          boxed= product == "gecko",
                           animation_value_type="discrete",
                           spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
 
 ${helpers.predefined_type("paint-order", "SVGPaintOrder", "computed::SVGPaintOrder::normal()",
                           products="gecko",
                           animation_value_type="discrete",
                           spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder")}
 
--- a/servo/components/style/properties/longhand/list.mako.rs
+++ b/servo/components/style/properties/longhand/list.mako.rs
@@ -42,17 +42,16 @@
                               servo_restyle_damage="rebuild_and_reflow")}
 % endif
 
 ${helpers.predefined_type("list-style-image",
                           "ListStyleImage",
                           initial_value="specified::ListStyleImage::none()",
                           initial_specified_value="specified::ListStyleImage::none()",
                           animation_value_type="discrete",
-                          boxed=product == "gecko",
                           spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image",
                           servo_restyle_damage="rebuild_and_reflow")}
 
 ${helpers.predefined_type("quotes",
                           "Quotes",
                           "computed::Quotes::get_initial_value()",
                           animation_value_type="discrete",
                           spec="https://drafts.csswg.org/css-content/#propdef-quotes",
--- a/servo/components/style/servo/url.rs
+++ b/servo/components/style/servo/url.rs
@@ -1,57 +1,58 @@
 /* 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/. */
 
 //! Common handling for the specified value CSS url() values.
 
-use parser::ParserContext;
+use cssparser::Parser;
+use parser::{Parse, ParserContext};
 use servo_url::ServoUrl;
 use std::fmt::{self, Write};
 // Note: We use std::sync::Arc rather than servo_arc::Arc here because the
 // nonzero optimization is important in keeping the size of SpecifiedUrl below
 // the threshold.
 use std::sync::Arc;
 use style_traits::{CssWriter, ParseError, ToCss};
-use values::computed::{Context, ToComputedValue, ComputedUrl};
+use values::computed::{Context, ToComputedValue};
 
-/// A specified url() value for servo.
+/// A CSS url() value for servo.
 ///
 /// Servo eagerly resolves SpecifiedUrls, which it can then take advantage of
 /// when computing values. In contrast, Gecko uses a different URL backend, so
 /// eagerly resolving with rust-url would be duplicated work.
 ///
 /// However, this approach is still not necessarily optimal: See
 /// <https://bugzilla.mozilla.org/show_bug.cgi?id=1347435#c6>
 #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
-pub struct SpecifiedUrl {
+pub struct CssUrl {
     /// The original URI. This might be optional since we may insert computed
     /// values of images into the cascade directly, and we don't bother to
     /// convert their serialization.
     ///
     /// Refcounted since cloning this should be cheap and data: uris can be
     /// really large.
     #[ignore_malloc_size_of = "Arc"]
     original: Option<Arc<String>>,
 
     /// The resolved value for the url, if valid.
     resolved: Option<ServoUrl>,
 }
 
-impl SpecifiedUrl {
+impl CssUrl {
     /// Try to parse a URL from a string value that is a valid CSS token for a
     /// URL. Never fails - the API is only fallible to be compatible with the
     /// gecko version.
     pub fn parse_from_string<'a>(url: String,
                                  context: &ParserContext)
                                  -> Result<Self, ParseError<'a>> {
         let serialization = Arc::new(url);
         let resolved = context.url_data.join(&serialization).ok();
-        Ok(SpecifiedUrl {
+        Ok(CssUrl {
             original: Some(serialization),
             resolved: resolved,
         })
     }
 
     /// Returns true if the URL is definitely invalid. For Servo URLs, we can
     /// use its |resolved| status.
     pub fn is_invalid(&self) -> bool {
@@ -82,40 +83,49 @@ impl SpecifiedUrl {
             Some(ref url) => url.as_str(),
             None => "",
         }
     }
 
     /// Creates an already specified url value from an already resolved URL
     /// for insertion in the cascade.
     pub fn for_cascade(url: ServoUrl) -> Self {
-        SpecifiedUrl {
+        CssUrl {
             original: None,
             resolved: Some(url),
         }
     }
 
     /// Gets a new url from a string for unit tests.
     pub fn new_for_testing(url: &str) -> Self {
-        SpecifiedUrl {
+        CssUrl {
             original: Some(Arc::new(url.into())),
             resolved: ServoUrl::parse(url).ok(),
         }
     }
 }
 
-impl PartialEq for SpecifiedUrl {
+impl Parse for CssUrl {
+    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+        let url = input.expect_url()?;
+        Self::parse_from_string(url.as_ref().to_owned(), context)
+    }
+}
+
+impl PartialEq for CssUrl {
     fn eq(&self, other: &Self) -> bool {
         // TODO(emilio): maybe we care about equality of the specified values if
         // present? Seems not.
         self.resolved == other.resolved
     }
 }
 
-impl ToCss for SpecifiedUrl {
+impl Eq for CssUrl {}
+
+impl ToCss for CssUrl {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
         let string = match self.original {
             Some(ref original) => &**original,
             None => match self.resolved {
                 Some(ref url) => url.as_str(),
@@ -127,16 +137,19 @@ impl ToCss for SpecifiedUrl {
         };
 
         dest.write_str("url(")?;
         string.to_css(dest)?;
         dest.write_str(")")
     }
 }
 
+/// A specified url() value for servo.
+pub type SpecifiedUrl = CssUrl;
+
 impl ToComputedValue for SpecifiedUrl {
     type ComputedValue = ComputedUrl;
 
     // If we can't resolve the URL from the specified one, we fall back to the original
     // but still return it as a ComputedUrl::Invalid
     fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
         match self.resolved {
             Some(ref url) => ComputedUrl::Valid(url.clone()),
@@ -158,8 +171,48 @@ impl ToComputedValue for SpecifiedUrl {
             ComputedUrl::Invalid(ref url) => SpecifiedUrl {
                 original: Some(url.clone()),
                 resolved: None,
             }
         }
     }
 }
 
+/// A specified image url() value for servo.
+pub type SpecifiedImageUrl = CssUrl;
+
+/// The computed value of a CSS `url()`, resolved relative to the stylesheet URL.
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
+pub enum ComputedUrl {
+    /// The `url()` was invalid or it wasn't specified by the user.
+    Invalid(#[ignore_malloc_size_of = "Arc"] Arc<String>),
+    /// The resolved `url()` relative to the stylesheet URL.
+    Valid(ServoUrl),
+}
+
+impl ComputedUrl {
+    /// Returns the resolved url if it was valid.
+    pub fn url(&self) -> Option<&ServoUrl> {
+        match *self {
+            ComputedUrl::Valid(ref url) => Some(url),
+            _ => None,
+        }
+    }
+}
+
+impl ToCss for ComputedUrl {
+    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+    where
+        W: Write,
+    {
+        let string = match *self {
+            ComputedUrl::Valid(ref url) => url.as_str(),
+            ComputedUrl::Invalid(ref invalid_string) => invalid_string,
+        };
+
+        dest.write_str("url(")?;
+        string.to_css(dest)?;
+        dest.write_str(")")
+    }
+}
+
+/// The computed value of a CSS `url()` for image.
+pub type ComputedImageUrl = ComputedUrl;
--- a/servo/components/style/stylesheets/document_rule.rs
+++ b/servo/components/style/stylesheets/document_rule.rs
@@ -12,17 +12,17 @@ use malloc_size_of::{MallocSizeOfOps, Ma
 use media_queries::Device;
 use parser::{Parse, ParserContext};
 use servo_arc::Arc;
 use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
 use std::fmt::{self, Write};
 use str::CssStringWriter;
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use stylesheets::CssRules;
-use values::specified::url::SpecifiedUrl;
+use values::CssUrl;
 
 #[derive(Debug)]
 /// A @-moz-document rule
 pub struct DocumentRule {
     /// The parsed condition
     pub condition: DocumentCondition,
     /// Child rules
     pub rules: Arc<Locked<CssRules>>,
@@ -70,17 +70,17 @@ impl DeepCloneWithLock for DocumentRule 
     }
 }
 
 /// A URL matching function for a `@document` rule's condition.
 #[derive(Clone, Debug, ToCss)]
 pub enum UrlMatchingFunction {
     /// Exact URL matching function. It evaluates to true whenever the
     /// URL of the document being styled is exactly the URL given.
-    Url(SpecifiedUrl),
+    Url(CssUrl),
     /// URL prefix matching function. It evaluates to true whenever the
     /// URL of the document being styled has the argument to the
     /// function as an initial substring (which is true when the two
     /// strings are equal). When the argument is the empty string,
     /// it evaluates to true for all documents.
     #[css(function)]
     UrlPrefix(String),
     /// Domain matching function. It evaluates to true whenever the URL
@@ -125,17 +125,17 @@ impl UrlMatchingFunction {
         if input.try(|input| input.expect_function_matching("url-prefix")).is_ok() {
             parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix)
         } else if input.try(|input| input.expect_function_matching("domain")).is_ok() {
             parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::Domain)
         } else if input.try(|input| input.expect_function_matching("regexp")).is_ok() {
             input.parse_nested_block(|input| {
                 Ok(UrlMatchingFunction::Regexp(input.expect_string()?.as_ref().to_owned()))
             })
-        } else if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
+        } else if let Ok(url) = input.try(|input| CssUrl::parse(context, input)) {
             Ok(UrlMatchingFunction::Url(url))
         } else {
             Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
         }
     }
 
     #[cfg(feature = "gecko")]
     /// Evaluate a URL matching function.
--- a/servo/components/style/stylesheets/import_rule.rs
+++ b/servo/components/style/stylesheets/import_rule.rs
@@ -8,17 +8,17 @@
 
 use cssparser::SourceLocation;
 use media_queries::MediaList;
 use shared_lock::{DeepCloneWithLock, DeepCloneParams, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
 use std::fmt::{self, Write};
 use str::CssStringWriter;
 use style_traits::{CssWriter, ToCss};
 use stylesheets::{StylesheetContents, StylesheetInDocument};
-use values::specified::url::SpecifiedUrl;
+use values::CssUrl;
 
 /// A sheet that is held from an import rule.
 #[cfg(feature = "gecko")]
 #[derive(Debug)]
 pub struct ImportSheet(pub ::gecko::data::GeckoStyleSheet);
 
 #[cfg(feature = "gecko")]
 impl DeepCloneWithLock for ImportSheet {
@@ -75,17 +75,17 @@ impl DeepCloneWithLock for ImportSheet {
 }
 
 /// The [`@import`][import] at-rule.
 ///
 /// [import]: https://drafts.csswg.org/css-cascade-3/#at-import
 #[derive(Debug)]
 pub struct ImportRule {
     /// The `<url>` this `@import` rule is loading.
-    pub url: SpecifiedUrl,
+    pub url: CssUrl,
 
     /// The stylesheet is always present.
     ///
     /// It contains an empty list of rules and namespace set that is updated
     /// when it loads.
     pub stylesheet: ImportSheet,
 
     /// The line and column of the rule's source code.
--- a/servo/components/style/stylesheets/loader.rs
+++ b/servo/components/style/stylesheets/loader.rs
@@ -6,24 +6,24 @@
 //! for `@import` rules.
 
 use cssparser::SourceLocation;
 use media_queries::MediaList;
 use parser::ParserContext;
 use servo_arc::Arc;
 use shared_lock::{Locked, SharedRwLock};
 use stylesheets::import_rule::ImportRule;
-use values::specified::url::SpecifiedUrl;
+use values::CssUrl;
 
 /// The stylesheet loader is the abstraction used to trigger network requests
 /// for `@import` rules.
 pub trait StylesheetLoader {
     /// Request a stylesheet after parsing a given `@import` rule, and return
     /// the constructed `@import` rule.
     fn request_stylesheet(
         &self,
-        url: SpecifiedUrl,
+        url: CssUrl,
         location: SourceLocation,
         context: &ParserContext,
         lock: &SharedRwLock,
         media: Arc<Locked<MediaList>>,
     ) -> Arc<Locked<ImportRule>>;
 }
--- a/servo/components/style/stylesheets/rule_parser.rs
+++ b/servo/components/style/stylesheets/rule_parser.rs
@@ -23,20 +23,18 @@ use stylesheets::{CssRule, CssRules, Css
 use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
 use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
 use stylesheets::document_rule::DocumentCondition;
 use stylesheets::font_feature_values_rule::parse_family_name_list;
 use stylesheets::keyframes_rule::parse_keyframe_list;
 use stylesheets::stylesheet::Namespaces;
 use stylesheets::supports_rule::SupportsCondition;
 use stylesheets::viewport_rule;
-use values::CustomIdent;
-use values::KeyframesName;
+use values::{CssUrl, CustomIdent, KeyframesName};
 use values::computed::font::FamilyName;
-use values::specified::url::SpecifiedUrl;
 
 /// The parser for the top-level rules in a stylesheet.
 pub struct TopLevelRuleParser<'a, R: 'a> {
     /// The origin of the stylesheet we're parsing.
     pub stylesheet_origin: Origin,
     /// A reference to the lock we need to use to create rules.
     pub shared_lock: &'a SharedRwLock,
     /// A reference to a stylesheet loader if applicable, for `@import` rules.
@@ -129,17 +127,17 @@ pub enum AtRuleBlockPrelude {
     Page(SourceLocation),
     /// A @document rule, with its conditional.
     Document(DocumentCondition, SourceLocation),
 }
 
 /// A rule prelude for at-rule without block.
 pub enum AtRuleNonBlockPrelude {
     /// A @import rule prelude.
-    Import(SpecifiedUrl, Arc<Locked<MediaList>>, SourceLocation),
+    Import(CssUrl, Arc<Locked<MediaList>>, SourceLocation),
     /// A @namespace rule prelude.
     Namespace(Option<Prefix>, Namespace, SourceLocation),
 }
 
 
 #[cfg(feature = "gecko")]
 fn register_namespace(ns: &Namespace) -> i32 {
     use gecko_bindings::bindings;
@@ -169,23 +167,23 @@ impl<'a, 'i, R: ParseErrorReporter> AtRu
             "import" => {
                 if self.state > State::Imports {
                     // "@import must be before any rule but @charset"
                     self.had_hierarchy_error = true;
                     return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
                 }
 
                 let url_string = input.expect_url_or_string()?.as_ref().to_owned();
-                let specified_url = SpecifiedUrl::parse_from_string(url_string, &self.context)?;
+                let url = CssUrl::parse_from_string(url_string, &self.context)?;
 
                 let media = parse_media_query_list(&self.context, input,
                                                    self.error_context.error_reporter);
                 let media = Arc::new(self.shared_lock.wrap(media));
 
-                let prelude = AtRuleNonBlockPrelude::Import(specified_url, media, location);
+                let prelude = AtRuleNonBlockPrelude::Import(url, media, location);
                 return Ok(AtRuleType::WithoutBlock(prelude));
             },
             "namespace" => {
                 if self.state > State::Namespaces {
                     // "@namespace must be before any rule but @charset and @import"
                     self.had_hierarchy_error = true;
                     return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
                 }
@@ -223,22 +221,22 @@ impl<'a, 'i, R: ParseErrorReporter> AtRu
     ) -> Result<CssRule, ParseError<'i>> {
         AtRuleParser::parse_block(&mut self.nested(), prelude, input)
             .map(|rule| { self.state = State::Body; rule })
     }
 
     #[inline]
     fn rule_without_block(&mut self, prelude: AtRuleNonBlockPrelude) -> CssRule {
         match prelude {
-            AtRuleNonBlockPrelude::Import(specified_url, media, location) => {
+            AtRuleNonBlockPrelude::Import(url, media, location) => {
                 let loader =
                     self.loader.expect("Expected a stylesheet loader for @import");
 
                 let import_rule = loader.request_stylesheet(
-                    specified_url,
+                    url,
                     location,
                     &self.context,
                     &self.shared_lock,
                     media,
                 );
 
                 self.state = State::Imports;
                 CssRule::Import(import_rule)
--- a/servo/components/style/values/computed/counters.rs
+++ b/servo/components/style/values/computed/counters.rs
@@ -13,17 +13,17 @@ use style_traits::{ParseError, StylePars
 use values::CustomIdent;
 #[cfg(feature = "gecko")]
 use values::generics::CounterStyleOrNone;
 use values::generics::counters::CounterIncrement as GenericCounterIncrement;
 use values::generics::counters::CounterReset as GenericCounterReset;
 #[cfg(feature = "gecko")]
 use values::specified::Attr;
 #[cfg(feature = "gecko")]
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
 pub use values::specified::{Content, ContentItem};
 
 /// A computed value for the `counter-increment` property.
 pub type CounterIncrement = GenericCounterIncrement<i32>;
 
 /// A computed value for the `counter-increment` property.
 pub type CounterReset = GenericCounterReset<i32>;
 
@@ -74,18 +74,17 @@ impl Parse for Content {
             if input.try(|input| input.expect_ident_matching("-moz-alt-content")).is_ok() {
                 return Ok(Content::MozAltContent);
             }
         }
 
         let mut content = vec![];
         loop {
             #[cfg(feature = "gecko")] {
-                if let Ok(mut url) = input.try(|i| SpecifiedUrl::parse(_context, i)) {
-                    url.build_image_value();
+                if let Ok(url) = input.try(|i| SpecifiedImageUrl::parse(_context, i)) {
                     content.push(ContentItem::Url(url));
                     continue;
                 }
             }
             // FIXME: remove clone() when lifetimes are non-lexical
             match input.next().map(|t| t.clone()) {
                 Ok(Token::QuotedString(ref value)) => {
                     content.push(ContentItem::String(value.as_ref().to_owned().into_boxed_str()));
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -7,33 +7,34 @@
 //!
 //! [image]: https://drafts.csswg.org/css-images/#image-values
 
 use cssparser::RGBA;
 use std::f32::consts::PI;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ToCss};
 use values::{Either, None_};
-use values::computed::{Angle, ComputedUrl, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
+use values::computed::{Angle, ComputedImageUrl, Context};
+use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
 #[cfg(feature = "gecko")]
 use values::computed::Percentage;
 use values::computed::position::Position;
 use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingShape as GenericEndingShape};
 use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
 use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
 use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect};
 use values::specified::image::LineDirection as SpecifiedLineDirection;
 use values::specified::position::{X, Y};
 
 /// A computed image layer.
 pub type ImageLayer = Either<None_, Image>;
 
 /// Computed values for an image according to CSS-IMAGES.
 /// <https://drafts.csswg.org/css-images/#image-values>
-pub type Image = GenericImage<Gradient, MozImageRect, ComputedUrl>;
+pub type Image = GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
 
 /// Computed values for a CSS gradient.
 /// <https://drafts.csswg.org/css-images/#gradients>
 pub type Gradient = GenericGradient<
     LineDirection,
     Length,
     LengthOrPercentage,
     Position,
@@ -71,17 +72,17 @@ pub type EndingShape = GenericEndingShap
 
 /// A computed gradient item.
 pub type GradientItem = GenericGradientItem<RGBA, LengthOrPercentage>;
 
 /// A computed color stop.
 pub type ColorStop = GenericColorStop<RGBA, LengthOrPercentage>;
 
 /// Computed values for `-moz-image-rect(...)`.
-pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, ComputedUrl>;
+pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, ComputedImageUrl>;
 
 impl GenericLineDirection for LineDirection {
     fn points_downwards(&self, compat_mode: CompatMode) -> bool {
         match *self {
             LineDirection::Angle(angle) => angle.radians() == PI,
             LineDirection::Vertical(Y::Bottom)
                 if compat_mode == CompatMode::Modern => true,
             LineDirection::Vertical(Y::Top)
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -10,24 +10,20 @@ use Prefix;
 use context::QuirksMode;
 use euclid::Size2D;
 use font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
 use media_queries::Device;
 #[cfg(feature = "gecko")]
 use properties;
 use properties::{ComputedValues, LonghandId, StyleBuilder};
 use rule_cache::RuleCacheConditions;
-#[cfg(feature = "servo")]
-use servo_url::ServoUrl;
 use std::cell::RefCell;
 use std::cmp;
 use std::f32;
 use std::fmt::{self, Write};
-#[cfg(feature = "servo")]
-use std::sync::Arc;
 use style_traits::{CssWriter, ToCss};
 use style_traits::cursor::CursorKind;
 use super::{CSSFloat, CSSInteger};
 use super::animated::ToAnimatedValue;
 use super::generics::{GreaterThanOrEqualToOne, NonNegative};
 use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
 use super::generics::grid::{TrackSize as GenericTrackSize, TrackList as GenericTrackList};
 use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
@@ -79,16 +75,17 @@ pub use self::svg::{SVGPaintOrder, SVGSt
 pub use self::svg::MozContextProperties;
 pub use self::table::XSpan;
 pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize};
 pub use self::text::{TextAlign, TextOverflow, WordSpacing};
 pub use self::time::Time;
 pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation};
 pub use self::transform::{TransformOrigin, TransformStyle, Translate};
 pub use self::ui::MozForceBrokenImageIcon;
+pub use self::url::{ComputedUrl, ComputedImageUrl};
 
 #[cfg(feature = "gecko")]
 pub mod align;
 pub mod angle;
 pub mod background;
 pub mod basic_shape;
 pub mod border;
 #[path = "box.rs"]
@@ -112,16 +109,24 @@ pub mod position;
 pub mod rect;
 pub mod svg;
 pub mod table;
 pub mod text;
 pub mod time;
 pub mod transform;
 pub mod ui;
 
+/// Common handling for the computed value CSS url() values.
+pub mod url {
+#[cfg(feature = "servo")]
+pub use ::servo::url::{ComputedUrl, ComputedImageUrl};
+#[cfg(feature = "gecko")]
+pub use ::gecko::url::{ComputedUrl, ComputedImageUrl};
+}
+
 /// A `Context` is all the data a specified value could ever need to compute
 /// itself and be transformed to a computed value.
 pub struct Context<'a> {
     /// Whether the current element is the root element.
     pub is_root_element: bool,
 
     /// Values accessed through this need to be in the properties "computed
     /// early": color, text-decoration, font-size, display, position, float,
@@ -631,52 +636,13 @@ impl ClipRectOrAuto {
     pub fn is_auto(&self) -> bool {
         match *self {
             Either::Second(_) => true,
             _ => false
         }
     }
 }
 
-/// The computed value of a CSS `url()`, resolved relative to the stylesheet URL.
-#[cfg(feature = "servo")]
-#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
-pub enum ComputedUrl {
-    /// The `url()` was invalid or it wasn't specified by the user.
-    Invalid(#[ignore_malloc_size_of = "Arc"] Arc<String>),
-    /// The resolved `url()` relative to the stylesheet URL.
-    Valid(ServoUrl),
-}
-
-/// TODO: Properly build ComputedUrl for gecko
-#[cfg(feature = "gecko")]
-pub type ComputedUrl = specified::url::SpecifiedUrl;
-
-#[cfg(feature = "servo")]
-impl ComputedUrl {
-    /// Returns the resolved url if it was valid.
-    pub fn url(&self) -> Option<&ServoUrl> {
-        match *self {
-            ComputedUrl::Valid(ref url) => Some(url),
-            _ => None,
-        }
-    }
-}
-
-#[cfg(feature = "servo")]
-impl ToCss for ComputedUrl {
-    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
-    where
-        W: Write,
-    {
-        let string = match *self {
-            ComputedUrl::Valid(ref url) => url.as_str(),
-            ComputedUrl::Invalid(ref invalid_string) => invalid_string,
-        };
-
-        dest.write_str("url(")?;
-        string.to_css(dest)?;
-        dest.write_str(")")
-    }
-}
-
 /// <url> | <none>
 pub type UrlOrNone = Either<ComputedUrl, None_>;
+
+/// <url> | <none> for image
+pub type ImageUrlOrNone = Either<ComputedImageUrl, None_>;
--- a/servo/components/style/values/computed/pointing.rs
+++ b/servo/components/style/values/computed/pointing.rs
@@ -13,17 +13,17 @@ use selectors::parser::SelectorParseErro
 use std::fmt::{self, Write};
 #[cfg(feature = "gecko")]
 use style_traits::{CssWriter, ToCss};
 use style_traits::ParseError;
 use style_traits::cursor::CursorKind;
 use values::computed::color::Color;
 use values::generics::pointing::CaretColor as GenericCaretColor;
 #[cfg(feature = "gecko")]
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
 
 /// The computed value for the `cursor` property.
 ///
 /// https://drafts.csswg.org/css-ui/#cursor
 pub use values::specified::pointing::Cursor;
 #[cfg(feature = "gecko")]
 pub use values::specified::pointing::CursorImage;
 
@@ -60,20 +60,17 @@ impl Parse for Cursor {
     #[cfg(feature = "gecko")]
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>
     ) -> Result<Self, ParseError<'i>> {
         let mut images = vec![];
         loop {
             match input.try(|input| CursorImage::parse_image(context, input)) {
-                Ok(mut image) => {
-                    image.url.build_image_value();
-                    images.push(image)
-                }
+                Ok(image) => images.push(image),
                 Err(_) => break,
             }
             input.expect_comma()?;
         }
         Ok(Self {
             images: images.into_boxed_slice(),
             keyword: CursorKind::parse(context, input)?,
         })
@@ -109,17 +106,17 @@ impl Parse for CursorKind {
 
 #[cfg(feature = "gecko")]
 impl CursorImage {
     fn parse_image<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>
     ) -> Result<Self, ParseError<'i>> {
         Ok(Self {
-            url: SpecifiedUrl::parse(context, input)?,
+            url: SpecifiedImageUrl::parse(context, input)?,
             // FIXME(emilio): Should use Number::parse to handle calc() correctly.
             hotspot: match input.try(|input| input.expect_number()) {
                 Ok(number) => Some((number, input.expect_number()?)),
                 Err(_) => None,
             },
         })
     }
 }
--- a/servo/components/style/values/mod.rs
+++ b/servo/components/style/values/mod.rs
@@ -12,16 +12,21 @@ use Atom;
 pub use cssparser::{RGBA, Token, Parser, serialize_identifier, CowRcStr, SourceLocation};
 use parser::{Parse, ParserContext};
 use selectors::parser::SelectorParseErrorKind;
 use std::fmt::{self, Debug, Write};
 use std::hash;
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 
+#[cfg(feature = "servo")]
+pub use servo::url::CssUrl;
+#[cfg(feature = "gecko")]
+pub use gecko::url::CssUrl;
+
 pub mod animated;
 pub mod computed;
 pub mod distance;
 pub mod generics;
 pub mod specified;
 
 /// A CSS float value.
 pub type CSSFloat = f32;
--- a/servo/components/style/values/specified/counters.rs
+++ b/servo/components/style/values/specified/counters.rs
@@ -13,17 +13,17 @@ use values::CustomIdent;
 #[cfg(feature = "gecko")]
 use values::generics::CounterStyleOrNone;
 use values::generics::counters::CounterIncrement as GenericCounterIncrement;
 use values::generics::counters::CounterReset as GenericCounterReset;
 #[cfg(feature = "gecko")]
 use values::specified::Attr;
 use values::specified::Integer;
 #[cfg(feature = "gecko")]
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
 
 /// A specified value for the `counter-increment` property.
 pub type CounterIncrement = GenericCounterIncrement<Integer>;
 
 impl Parse for CounterIncrement {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>
@@ -114,10 +114,10 @@ pub enum ContentItem {
     NoOpenQuote,
     /// `no-close-quote`.
     NoCloseQuote,
     /// `attr([namespace? `|`]? ident)`
     #[cfg(feature = "gecko")]
     Attr(Attr),
     /// `url(url)`
     #[cfg(feature = "gecko")]
-    Url(SpecifiedUrl),
+    Url(SpecifiedImageUrl),
 }
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -26,24 +26,24 @@ use values::generics::image::{EndingShap
 use values::generics::image::{GradientItem as GenericGradientItem, GradientKind as GenericGradientKind};
 use values::generics::image::{Image as GenericImage, LineDirection as GenericsLineDirection};
 use values::generics::image::{MozImageRect as GenericMozImageRect, ShapeExtent};
 use values::generics::image::PaintWorklet;
 use values::generics::position::Position as GenericPosition;
 use values::specified::{Angle, Color, Length, LengthOrPercentage};
 use values::specified::{Number, NumberOrPercentage, Percentage, RGBAColor};
 use values::specified::position::{LegacyPosition, Position, PositionComponent, Side, X, Y};
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
 
 /// A specified image layer.
 pub type ImageLayer = Either<None_, Image>;
 
 /// Specified values for an image according to CSS-IMAGES.
 /// <https://drafts.csswg.org/css-images/#image-values>
-pub type Image = GenericImage<Gradient, MozImageRect, SpecifiedUrl>;
+pub type Image = GenericImage<Gradient, MozImageRect, SpecifiedImageUrl>;
 
 /// Specified values for a CSS gradient.
 /// <https://drafts.csswg.org/css-images/#gradients>
 #[cfg(not(feature = "gecko"))]
 pub type Gradient = GenericGradient<
     LineDirection,
     Length,
     LengthOrPercentage,
@@ -119,54 +119,46 @@ pub type EndingShape = GenericEndingShap
 /// A specified gradient item.
 pub type GradientItem = GenericGradientItem<RGBAColor, LengthOrPercentage>;
 
 /// A computed color stop.
 pub type ColorStop = GenericColorStop<RGBAColor, LengthOrPercentage>;
 
 /// Specified values for `moz-image-rect`
 /// -moz-image-rect(<uri>, top, right, bottom, left);
-pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, SpecifiedUrl>;
+pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, SpecifiedImageUrl>;
 
 impl Parse for Image {
-    #[cfg_attr(not(feature = "gecko"), allow(unused_mut))]
     fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Image, ParseError<'i>> {
-        if let Ok(mut url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
-            #[cfg(feature = "gecko")]
-            {
-                url.build_image_value();
-            }
+        if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) {
             return Ok(GenericImage::Url(url));
         }
         if let Ok(gradient) = input.try(|i| Gradient::parse(context, i)) {
             return Ok(GenericImage::Gradient(Box::new(gradient)));
         }
         #[cfg(feature = "servo")]
         {
             if let Ok(paint_worklet) = input.try(|i| PaintWorklet::parse(context, i)) {
                 return Ok(GenericImage::PaintWorklet(paint_worklet));
             }
         }
-        if let Ok(mut image_rect) = input.try(|input| MozImageRect::parse(context, input)) {
-            #[cfg(feature = "gecko")]
-            {
-                image_rect.url.build_image_value();
-            }
+        if let Ok(image_rect) = input.try(|input| MozImageRect::parse(context, input)) {
             return Ok(GenericImage::Rect(Box::new(image_rect)));
         }
         Ok(GenericImage::Element(Image::parse_element(input)?))
     }
 }
 
 impl Image {
     /// Creates an already specified image value from an already resolved URL
     /// for insertion in the cascade.
     #[cfg(feature = "servo")]
     pub fn for_cascade(url: ServoUrl) -> Self {
-        GenericImage::Url(SpecifiedUrl::for_cascade(url))
+        use values::CssUrl;
+        GenericImage::Url(CssUrl::for_cascade(url))
     }
 
     /// Parses a `-moz-element(# <element-id>)`.
     fn parse_element<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Atom, ParseError<'i>> {
         input.try(|i| i.expect_function_matching("-moz-element"))?;
         let location = input.current_source_location();
         input.parse_nested_block(|i| {
             match *i.next()? {
@@ -939,28 +931,21 @@ impl Parse for PaintWorklet {
     }
 }
 
 impl Parse for MozImageRect {
     fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
         input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
         input.parse_nested_block(|i| {
             let string = i.expect_url_or_string()?;
-            let url = SpecifiedUrl::parse_from_string(string.as_ref().to_owned(), context)?;
+            let url = SpecifiedImageUrl::parse_from_string(string.as_ref().to_owned(), context)?;
             i.expect_comma()?;
             let top = NumberOrPercentage::parse_non_negative(context, i)?;
             i.expect_comma()?;
             let right = NumberOrPercentage::parse_non_negative(context, i)?;
             i.expect_comma()?;
             let bottom = NumberOrPercentage::parse_non_negative(context, i)?;
             i.expect_comma()?;
             let left = NumberOrPercentage::parse_non_negative(context, i)?;
-
-            Ok(MozImageRect {
-                url: url,
-                top: top,
-                right: right,
-                bottom: bottom,
-                left: left,
-            })
+            Ok(MozImageRect { url, top, right, bottom, left })
         })
     }
 }
--- a/servo/components/style/values/specified/list.rs
+++ b/servo/components/style/values/specified/list.rs
@@ -8,17 +8,17 @@ use cssparser::{Parser, Token};
 use parser::{Parse, ParserContext};
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use values::{Either, None_};
 #[cfg(feature = "gecko")]
 use values::CustomIdent;
 #[cfg(feature = "gecko")]
 use values::generics::CounterStyleOrNone;
-use values::specified::UrlOrNone;
+use values::specified::ImageUrlOrNone;
 
 /// Specified and computed `list-style-type` property.
 #[cfg(feature = "gecko")]
 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
 pub enum ListStyleType {
     /// <counter-style> | none
     CounterStyle(CounterStyleOrNone),
     /// <string>
@@ -70,44 +70,36 @@ impl Parse for ListStyleType {
         }
 
         Ok(ListStyleType::String(input.expect_string()?.as_ref().to_owned()))
     }
 }
 
 /// Specified and computed `list-style-image` property.
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
-pub struct ListStyleImage(pub UrlOrNone);
+pub struct ListStyleImage(pub ImageUrlOrNone);
 
 // FIXME(nox): This is wrong, there are different types for specified
 // and computed URLs in Servo.
 trivial_to_computed_value!(ListStyleImage);
 
 impl ListStyleImage {
     /// Initial specified value for `list-style-image`.
     #[inline]
     pub fn none() -> ListStyleImage {
         ListStyleImage(Either::Second(None_))
     }
 }
 
 impl Parse for ListStyleImage {
-    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-                         -> Result<ListStyleImage, ParseError<'i>> {
-        #[allow(unused_mut)]
-        let mut value = input.try(|input| UrlOrNone::parse(context, input))?;
-
-        #[cfg(feature = "gecko")]
-        {
-            if let Either::First(ref mut url) = value {
-                url.build_image_value();
-            }
-        }
-
-        return Ok(ListStyleImage(value));
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<ListStyleImage, ParseError<'i>> {
+        ImageUrlOrNone::parse(context, input).map(ListStyleImage)
     }
 }
 
 /// Specified and computed `quote` property.
 ///
 /// FIXME(emilio): It's a shame that this allocates all the time it's computed,
 /// probably should just be refcounted.
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -6,17 +6,17 @@
 //!
 //! TODO(emilio): Enhance docs.
 
 use Prefix;
 use context::QuirksMode;
 use cssparser::{Parser, Token, serialize_identifier};
 use num_traits::One;
 use parser::{ParserContext, Parse};
-use self::url::SpecifiedUrl;
+use self::url::{SpecifiedImageUrl, SpecifiedUrl};
 use std::f32;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use style_traits::values::specified::AllowedNumericType;
 use super::{Auto, CSSFloat, CSSInteger, Either, None_};
 use super::computed::{Context, ToComputedValue};
 use super::generics::{GreaterThanOrEqualToOne, NonNegative};
 use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
@@ -111,33 +111,20 @@ pub mod svg;
 pub mod table;
 pub mod text;
 pub mod time;
 pub mod transform;
 pub mod ui;
 
 /// Common handling for the specified value CSS url() values.
 pub mod url {
-use cssparser::Parser;
-use parser::{Parse, ParserContext};
-use style_traits::ParseError;
-
 #[cfg(feature = "servo")]
-pub use ::servo::url::*;
+pub use ::servo::url::{SpecifiedUrl, SpecifiedImageUrl};
 #[cfg(feature = "gecko")]
-pub use ::gecko::url::*;
-
-impl Parse for SpecifiedUrl {
-    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-        let url = input.expect_url()?;
-        Self::parse_from_string(url.as_ref().to_owned(), context)
-    }
-}
-
-impl Eq for SpecifiedUrl {}
+pub use ::gecko::url::{SpecifiedUrl, SpecifiedImageUrl};
 }
 
 /// Parse a `<number>` value, with a given clamping mode.
 fn parse_number_with_clamping_mode<'i, 't>(
     context: &ParserContext,
     input: &mut Parser<'i, 't>,
     clamping_mode: AllowedNumericType,
 ) -> Result<Number, ParseError<'i>> {
@@ -529,16 +516,19 @@ impl Parse for PositiveInteger {
     fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
         Integer::parse_positive(context, input).map(GreaterThanOrEqualToOne::<Integer>)
     }
 }
 
 #[allow(missing_docs)]
 pub type UrlOrNone = Either<SpecifiedUrl, None_>;
 
+/// The specified value of a `<url>` for image or `none`.
+pub type ImageUrlOrNone = Either<SpecifiedImageUrl, None_>;
+
 /// The specified value of a grid `<track-breadth>`
 pub type TrackBreadth = GenericTrackBreadth<LengthOrPercentage>;
 
 /// The specified value of a grid `<track-size>`
 pub type TrackSize = GenericTrackSize<LengthOrPercentage>;
 
 /// The specified value of a grid `<track-list>`
 /// (could also be `<auto-track-list>` or `<explicit-track-list>`)
--- a/servo/components/style/values/specified/pointing.rs
+++ b/servo/components/style/values/specified/pointing.rs
@@ -8,17 +8,17 @@
 
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
 use style_traits::ParseError;
 use style_traits::cursor::CursorKind;
 use values::generics::pointing::CaretColor as GenericCaretColor;
 use values::specified::color::Color;
 #[cfg(feature = "gecko")]
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
 
 /// The specified value for the `cursor` property.
 ///
 /// https://drafts.csswg.org/css-ui/#cursor
 #[cfg(feature = "servo")]
 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
 pub struct Cursor(pub CursorKind);
 
@@ -34,17 +34,17 @@ pub struct Cursor {
     pub keyword: CursorKind,
 }
 
 /// The specified value for the `image cursors`.
 #[cfg(feature = "gecko")]
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
 pub struct CursorImage {
     /// The url to parse images from.
-    pub url: SpecifiedUrl,
+    pub url: SpecifiedImageUrl,
     /// The <x> and <y> coordinates.
     pub hotspot: Option<(f32, f32)>,
 }
 
 /// A specified value for the `caret-color` property.
 pub type CaretColor = GenericCaretColor<Color>;
 
 impl Parse for CaretColor {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3539,29 +3539,28 @@ pub extern "C" fn Servo_DeclarationBlock
     declarations: RawServoDeclarationBlockBorrowed,
     value: *const nsAString,
     raw_extra_data: *mut URLExtraData,
 ) {
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
     use style::values::Either;
     use style::values::generics::image::Image;
-    use style::values::specified::url::SpecifiedUrl;
+    use style::values::specified::url::SpecifiedImageUrl;
 
     let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
     let string = unsafe { (*value).to_string() };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
     );
-    if let Ok(mut url) = SpecifiedUrl::parse_from_string(string.into(), &context) {
-        url.build_image_value();
+    if let Ok(url) = SpecifiedImageUrl::parse_from_string(string.into(), &context) {
         let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
             vec![Either::Second(Image::Url(url))]
         ));
         write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
             decls.push(decl, Importance::Normal, DeclarationSource::CssOm);
         })
     }
 }
--- a/servo/ports/geckolib/stylesheet_loader.rs
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -8,33 +8,33 @@ use style::gecko::data::GeckoStyleSheet;
 use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
 use style::gecko_bindings::structs::{Loader, ServoStyleSheet, SheetLoadData, LoaderReusableStyleSheets};
 use style::gecko_bindings::sugar::ownership::FFIArcHelpers;
 use style::media_queries::MediaList;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, SharedRwLock};
 use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader};
 use style::stylesheets::import_rule::ImportSheet;
-use style::values::specified::url::SpecifiedUrl;
+use style::values::CssUrl;
 
 pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet, *mut SheetLoadData, *mut LoaderReusableStyleSheets);
 
 impl StylesheetLoader {
     pub fn new(loader: *mut Loader,
                parent: *mut ServoStyleSheet,
                parent_load_data: *mut SheetLoadData,
                reusable_sheets: *mut LoaderReusableStyleSheets) -> Self {
         StylesheetLoader(loader, parent, parent_load_data, reusable_sheets)
     }
 }
 
 impl StyleStylesheetLoader for StylesheetLoader {
     fn request_stylesheet(
         &self,
-        url: SpecifiedUrl,
+        url: CssUrl,
         source_location: SourceLocation,
         _context: &ParserContext,
         lock: &SharedRwLock,
         media: Arc<Locked<MediaList>>,
     ) -> Arc<Locked<ImportRule>> {
         // After we get this raw pointer ImportRule will be moved into a lock and Arc
         // and so the Arc<Url> pointer inside will also move,
         // but the Url it points to or the allocating backing the String inside that Url won’t,
--- a/servo/ports/geckolib/tests/size_of.rs
+++ b/servo/ports/geckolib/tests/size_of.rs
@@ -37,15 +37,15 @@ size_of_test!(test_size_of_property_decl
 
 size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24);
 size_of_test!(test_size_of_rule_node, RuleNode, 80);
 
 // This is huge, but we allocate it on the stack and then never move it,
 // we only pass `&mut SourcePropertyDeclaration` references around.
 size_of_test!(test_size_of_parsed_declaration, style::properties::SourcePropertyDeclaration, 608);
 
-size_of_test!(test_size_of_computed_image, computed::image::Image, 40);
-size_of_test!(test_size_of_specified_image, specified::image::Image, 40);
+size_of_test!(test_size_of_computed_image, computed::image::Image, 32);
+size_of_test!(test_size_of_specified_image, specified::image::Image, 32);
 
 // FIXME(bz): These can shrink if we move the None_ value inside the
 // enum instead of paying an extra word for the Either discriminant.
-size_of_test!(test_size_of_computed_image_layer, computed::image::ImageLayer, 40);
-size_of_test!(test_size_of_specified_image_layer, specified::image::ImageLayer, 40);
+size_of_test!(test_size_of_computed_image_layer, computed::image::ImageLayer, 32);
+size_of_test!(test_size_of_specified_image_layer, specified::image::ImageLayer, 32);
--- a/taskcluster/docker/firefox-snap/runme.sh
+++ b/taskcluster/docker/firefox-snap/runme.sh
@@ -42,16 +42,23 @@ cp -v "$SCRIPT_DIRECTORY/firefox.desktop
 locales=$(python3 "$SCRIPT_DIRECTORY/extract_locales_from_l10n_json.py" "${WORKSPACE}/l10n_changesets.json")
 
 mkdir -p "$DISTRIBUTION_DIR/extensions"
 for locale in $locales; do
     $CURL -o "$SOURCE_DEST/distribution/extensions/langpack-${locale}@firefox.mozilla.org.xpi" \
         "$CANDIDATES_DIR/${VERSION}-candidates/build${BUILD_NUMBER}/linux-x86_64/xpi/${locale}.xpi"
 done
 
+# Extract gtk30.mo from Ubuntu language packs
+apt download language-pack-gnome-*-base
+for i in *.deb; do
+    # shellcheck disable=SC2086
+    dpkg-deb --fsys-tarfile $i | tar xv -C "$SOURCE_DEST" --wildcards "./usr/share/locale-langpack/*/LC_MESSAGES/gtk30.mo" || true
+done
+
 # Generate snapcraft manifest
 sed -e "s/@VERSION@/${VERSION}/g" -e "s/@BUILD_NUMBER@/${BUILD_NUMBER}/g" snapcraft.yaml.in > "${WORKSPACE}/snapcraft.yaml"
 cp -v "$SCRIPT_DIRECTORY/mimeapps.list" "$WORKSPACE"
 cd "${WORKSPACE}"
 snapcraft
 
 mv -- *.snap "$TARGET_FULL_PATH"
 
--- a/taskcluster/docker/firefox-snap/snapcraft.yaml.in
+++ b/taskcluster/docker/firefox-snap/snapcraft.yaml.in
@@ -43,18 +43,20 @@ parts:
       - libxt6
       - libdbus-glib-1-2
       - libasound2
       - libpulse0
       - libgl1-mesa-dri
       - libgl1-mesa-glx
       - libmirclient9
       - desktop-file-utils
+      - ffmpeg
       - xdg-utils
-      - ffmpeg
+      - libc-bin
+      - locales-all
     after: [desktop-gtk3]
 
   xdg-open:
     after: [firefox]
     plugin: nil
     source: .
     install: |
       set -eux
--- a/taskcluster/taskgraph/transforms/task.py
+++ b/taskcluster/taskgraph/transforms/task.py
@@ -619,41 +619,41 @@ TC_TREEHERDER_SCHEMA_URL = 'https://gith
 
 UNKNOWN_GROUP_NAME = "Treeherder group {} (from {}) has no name; " \
                      "add it to taskcluster/ci/config.yml"
 
 V2_ROUTE_TEMPLATES = [
     "index.{trust-domain}.v2.{project}.latest.{product}.{job-name}",
     "index.{trust-domain}.v2.{project}.pushdate.{build_date_long}.{product}.{job-name}",
     "index.{trust-domain}.v2.{project}.pushlog-id.{pushlog_id}.{product}.{job-name}",
-    "index.{trust-domain}.v2.{project}.revision.{head_rev}.{product}.{job-name}",
+    "index.{trust-domain}.v2.{project}.revision.{branch_rev}.{product}.{job-name}",
 ]
 
 # {central, inbound, autoland} write to a "trunk" index prefix. This facilitates
 # walking of tasks with similar configurations.
 V2_TRUNK_ROUTE_TEMPLATES = [
-    "index.{trust-domain}.v2.trunk.revision.{head_rev}.{product}.{job-name}",
+    "index.{trust-domain}.v2.trunk.revision.{branch_rev}.{product}.{job-name}",
 ]
 
 V2_NIGHTLY_TEMPLATES = [
     "index.{trust-domain}.v2.{project}.nightly.latest.{product}.{job-name}",
-    "index.{trust-domain}.v2.{project}.nightly.{build_date}.revision.{head_rev}.{product}.{job-name}",  # noqa - too long
+    "index.{trust-domain}.v2.{project}.nightly.{build_date}.revision.{branch_rev}.{product}.{job-name}",  # noqa - too long
     "index.{trust-domain}.v2.{project}.nightly.{build_date}.latest.{product}.{job-name}",
-    "index.{trust-domain}.v2.{project}.nightly.revision.{head_rev}.{product}.{job-name}",
+    "index.{trust-domain}.v2.{project}.nightly.revision.{branch_rev}.{product}.{job-name}",
 ]
 
 V2_NIGHTLY_L10N_TEMPLATES = [
     "index.{trust-domain}.v2.{project}.nightly.latest.{product}-l10n.{job-name}.{locale}",
-    "index.{trust-domain}.v2.{project}.nightly.{build_date}.revision.{head_rev}.{product}-l10n.{job-name}.{locale}",  # noqa - too long
+    "index.{trust-domain}.v2.{project}.nightly.{build_date}.revision.{branch_rev}.{product}-l10n.{job-name}.{locale}",  # noqa - too long
     "index.{trust-domain}.v2.{project}.nightly.{build_date}.latest.{product}-l10n.{job-name}.{locale}",  # noqa - too long
-    "index.{trust-domain}.v2.{project}.nightly.revision.{head_rev}.{product}-l10n.{job-name}.{locale}",  # noqa - too long
+    "index.{trust-domain}.v2.{project}.nightly.revision.{branch_rev}.{product}-l10n.{job-name}.{locale}",  # noqa - too long
 ]
 
 V2_L10N_TEMPLATES = [
-    "index.{trust-domain}.v2.{project}.revision.{head_rev}.{product}-l10n.{job-name}.{locale}",
+    "index.{trust-domain}.v2.{project}.revision.{branch_rev}.{product}-l10n.{job-name}.{locale}",
     "index.{trust-domain}.v2.{project}.pushdate.{build_date_long}.{product}-l10n.{job-name}.{locale}",  # noqa - too long
     "index.{trust-domain}.v2.{project}.latest.{product}-l10n.{job-name}.{locale}",
 ]
 
 # the roots of the treeherder routes
 TREEHERDER_ROUTE_ROOT = 'tc-treeherder'
 
 # Which repository repository revision to use when reporting results to treeherder.
@@ -662,16 +662,26 @@ BRANCH_REV_PARAM = {
     'comm-esr45': 'comm_head_rev',
     'comm-esr52': 'comm_head_rev',
     'comm-beta': 'comm_head_rev',
     'comm-central': 'comm_head_rev',
     'comm-aurora': 'comm_head_rev',
     'try-comm-central': 'comm_head_rev',
 }
 
+
+def get_branch_rev(config):
+    return config.params[
+        BRANCH_REV_PARAM.get(
+            config.params['project'],
+            DEFAULT_BRANCH_REV_PARAM
+        )
+    ]
+
+
 COALESCE_KEY = '{project}.{job-identifier}'
 SUPERSEDER_URL = 'https://coalesce.mozilla-releng.net/v1/list/{age}/{size}/{key}'
 
 DEFAULT_BRANCH_PRIORITY = 'low'
 BRANCH_PRIORITIES = {
     'mozilla-release': 'highest',
     'comm-esr45': 'highest',
     'comm-esr52': 'highest',
@@ -1327,16 +1337,17 @@ def add_generic_index_routes(config, tas
     verify_index(config, index)
 
     subs = config.params.copy()
     subs['job-name'] = index['job-name']
     subs['build_date_long'] = time.strftime("%Y.%m.%d.%Y%m%d%H%M%S",
                                             time.gmtime(config.params['build_date']))
     subs['product'] = index['product']
     subs['trust-domain'] = config.graph_config['trust-domain']
+    subs['branch_rev'] = get_branch_rev(config)
 
     project = config.params.get('project')
 
     for tpl in V2_ROUTE_TEMPLATES:
         routes.append(tpl.format(**subs))
 
     # Additionally alias all tasks for "trunk" repos into a common
     # namespace.
@@ -1357,16 +1368,17 @@ def add_nightly_index_routes(config, tas
     subs = config.params.copy()
     subs['job-name'] = index['job-name']
     subs['build_date_long'] = time.strftime("%Y.%m.%d.%Y%m%d%H%M%S",
                                             time.gmtime(config.params['build_date']))
     subs['build_date'] = time.strftime("%Y.%m.%d",
                                        time.gmtime(config.params['build_date']))
     subs['product'] = index['product']
     subs['trust-domain'] = config.graph_config['trust-domain']
+    subs['branch_rev'] = get_branch_rev(config)
 
     for tpl in V2_NIGHTLY_TEMPLATES:
         routes.append(tpl.format(**subs))
 
     # Also add routes for en-US
     task = add_l10n_index_routes(config, task, force_locale="en-US")
 
     return task
@@ -1379,16 +1391,17 @@ def add_release_index_routes(config, tas
     release_config = get_release_config(config)
 
     subs = config.params.copy()
     subs['build_number'] = str(release_config['build_number'])
     subs['revision'] = subs['head_rev']
     subs['underscore_version'] = release_config['version'].replace('.', '_')
     subs['product'] = index['product']
     subs['trust-domain'] = config.graph_config['trust-domain']
+    subs['branch_rev'] = get_branch_rev(config)
     subs['branch'] = subs['project']
     if 'channel' in index:
         resolve_keyed_by(
             index, 'channel', item_name=task['label'], project=config.params['project']
         )
         subs['channel'] = index['channel']
 
     for rt in task.get('routes', []):
@@ -1414,16 +1427,17 @@ def add_l10n_index_routes(config, task, 
     verify_index(config, index)
 
     subs = config.params.copy()
     subs['job-name'] = index['job-name']
     subs['build_date_long'] = time.strftime("%Y.%m.%d.%Y%m%d%H%M%S",
                                             time.gmtime(config.params['build_date']))
     subs['product'] = index['product']
     subs['trust-domain'] = config.graph_config['trust-domain']
+    subs['branch_rev'] = get_branch_rev(config)
 
     locales = task['attributes'].get('chunk_locales',
                                      task['attributes'].get('all_locales'))
     # Some tasks has only one locale set
     if task['attributes'].get('locale'):
         locales = [task['attributes']['locale']]
 
     if force_locale:
@@ -1453,16 +1467,17 @@ def add_nightly_l10n_index_routes(config
     verify_index(config, index)
 
     subs = config.params.copy()
     subs['job-name'] = index['job-name']
     subs['build_date_long'] = time.strftime("%Y.%m.%d.%Y%m%d%H%M%S",
                                             time.gmtime(config.params['build_date']))
     subs['product'] = index['product']
     subs['trust-domain'] = config.graph_config['trust-domain']
+    subs['branch_rev'] = get_branch_rev(config)
 
     locales = task['attributes'].get('chunk_locales',
                                      task['attributes'].get('all_locales'))
     # Some tasks has only one locale set
     if task['attributes'].get('locale'):
         locales = [task['attributes']['locale']]
 
     if force_locale:
@@ -1546,25 +1561,22 @@ def build_task(config, tasks):
                 raise RuntimeError("Treeherder group and symbol names must not be longer than "
                                    "25 characters: {} (see {})".format(
                                        task_th['symbol'],
                                        TC_TREEHERDER_SCHEMA_URL,
                                        ))
             treeherder['jobKind'] = task_th['kind']
             treeherder['tier'] = task_th['tier']
 
-            treeherder_rev = config.params[
-                BRANCH_REV_PARAM.get(
-                    config.params['project'],
-                    DEFAULT_BRANCH_REV_PARAM)]
+            branch_rev = get_branch_rev(config)
 
             routes.append(
                 '{}.v2.{}.{}.{}'.format(TREEHERDER_ROUTE_ROOT,
                                         config.params['project'],
-                                        treeherder_rev,
+                                        branch_rev,
                                         config.params['pushlog_id'])
             )
 
         if 'expires-after' not in task:
             task['expires-after'] = '28 days' if config.params['project'] == 'try' else '1 year'
 
         if 'deadline-after' not in task:
             task['deadline-after'] = '1 day'
@@ -1605,17 +1617,17 @@ def build_task(config, tasks):
         }
 
         if task.get('requires', None):
             task_def['requires'] = task['requires']
 
         if task_th:
             # link back to treeherder in description
             th_push_link = 'https://treeherder.mozilla.org/#/jobs?repo={}&revision={}'.format(
-                config.params['project'], treeherder_rev)
+                config.params['project'], branch_rev)
             task_def['metadata']['description'] += ' ([Treeherder push]({}))'.format(
                 th_push_link)
 
         # add the payload and adjust anything else as required (e.g., scopes)
         payload_builders[task['worker']['implementation']](config, task, task_def)
 
         attributes = task.get('attributes', {})
         attributes['run_on_projects'] = task.get('run-on-projects', ['all'])
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/actions/key.py.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[key.py]
-  disabled:
-    if (os == "linux") and (bits == 32): https://bugzilla.mozilla.org/show_bug.cgi?id=1377805
--- a/third_party/rust/futures-cpupool/.cargo-checksum.json
+++ b/third_party/rust/futures-cpupool/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"07c97c2816b3cc41857a0cbbb5109f2a7ef2bd81131a3f4f3621f438a1eb7561","README.md":"09c5f4bacff34b3f7e1969f5b9590c062a8aabac7c2442944eab1d2fc1301373","src/lib.rs":"a368e87ed6f93552ba12391cd765d0b0b34b9fe42617a2c1f6a5ce81a0c5de11","tests/smoke.rs":"3e237fc14d19775026f6cff45d73de6bb6b4db6699ce8ab4972ed85165200ec2"},"package":"a283c84501e92cade5ea673a2a7ca44f71f209ccdd302a3e0896f50083d2c5ff"}
\ No newline at end of file
+{"files":{"Cargo.toml":"d65d12c309bb5af442353ceb79339c2d426b1ed643f5eddee14ad22637225ca2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"69036b033e4bb951821964dbc3d9b1efe6913a6e36d9c1f206de4035a1a85cc4","README.md":"09c5f4bacff34b3f7e1969f5b9590c062a8aabac7c2442944eab1d2fc1301373","src/lib.rs":"2bffe7435a2c13028978955882338fbb9df3644f725a7e9d27b5f1495e3e9f90","tests/smoke.rs":"4c07aad02b0dd17f4723f3be1abbe320629b9e0756c885b44cbc1268141668f1"},"package":"ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"}
\ No newline at end of file
--- a/third_party/rust/futures-cpupool/Cargo.toml
+++ b/third_party/rust/futures-cpupool/Cargo.toml
@@ -1,25 +1,32 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
 [package]
 name = "futures-cpupool"
-version = "0.1.5"
+version = "0.1.8"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = "MIT/Apache-2.0"
-repository = "https://github.com/alexcrichton/futures-rs"
+description = "An implementation of thread pools which hand out futures to the results of the\ncomputation on the threads themselves.\n"
 homepage = "https://github.com/alexcrichton/futures-rs"
 documentation = "https://docs.rs/futures-cpupool"
-description = """
-An implementation of thread pools which hand out futures to the results of the
-computation on the threads themselves.
-"""
+license = "MIT/Apache-2.0"
+repository = "https://github.com/alexcrichton/futures-rs"
+[dependencies.futures]
+version = "0.1"
+features = ["use_std"]
+default-features = false
 
-[dependencies]
-num_cpus = "1.0"
-
-[dependencies.futures]
-path = ".."
-version = "0.1"
-default-features = false
-features = ["use_std"]
+[dependencies.num_cpus]
+version = "1.0"
 
 [features]
 default = ["with-deprecated"]
 with-deprecated = ["futures/with-deprecated"]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures-cpupool/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures-cpupool/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2016 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
--- a/third_party/rust/futures-cpupool/src/lib.rs
+++ b/third_party/rust/futures-cpupool/src/lib.rs
@@ -8,18 +8,18 @@
 //!
 //! ```rust
 //! extern crate futures;
 //! extern crate futures_cpupool;
 //!
 //! use futures::Future;
 //! use futures_cpupool::CpuPool;
 //!
-//! # fn long_running_future(a: u32) -> futures::future::BoxFuture<u32, ()> {
-//! #     futures::future::result(Ok(a)).boxed()
+//! # fn long_running_future(a: u32) -> Box<futures::future::Future<Item = u32, Error = ()> + Send> {
+//! #     Box::new(futures::future::result(Ok(a)))
 //! # }
 //! # fn main() {
 //!
 //! // Create a worker thread pool with four threads
 //! let pool = CpuPool::new(4);
 //!
 //! // Execute some work on the thread pool, optionally closing over data.
 //! let a = pool.spawn(long_running_future(2));
@@ -30,30 +30,32 @@
 //! let c = a.join(b).map(|(a, b)| a + b).wait().unwrap();
 //!
 //! // Print out the result
 //! println!("{:?}", c);
 //! # }
 //! ```
 
 #![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
 
 extern crate futures;
 extern crate num_cpus;
 
 use std::panic::{self, AssertUnwindSafe};
 use std::sync::{Arc, Mutex};
 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
 use std::sync::mpsc;
 use std::thread;
+use std::fmt;
 
 use futures::{IntoFuture, Future, Poll, Async};
-use futures::future::lazy;
+use futures::future::{lazy, Executor, ExecuteError};
 use futures::sync::oneshot::{channel, Sender, Receiver};
-use futures::executor::{self, Run, Executor};
+use futures::executor::{self, Run, Executor as OldExecutor};
 
 /// A thread pool intended to run CPU intensive work.
 ///
 /// This thread pool will hand out futures representing the completed work
 /// that happens on the thread pool itself, and the futures can then be later
 /// composed with other work as part of an overall computation.
 ///
 /// The worker threads associated with a thread pool are kept alive so long as
@@ -73,49 +75,62 @@ pub struct CpuPool {
 }
 
 /// Thread pool configuration object
 ///
 /// Builder starts with a number of workers equal to the number
 /// of CPUs on the host. But you can change it until you call `create()`.
 pub struct Builder {
     pool_size: usize,
+    stack_size: usize,
     name_prefix: Option<String>,
     after_start: Option<Arc<Fn() + Send + Sync>>,
     before_stop: Option<Arc<Fn() + Send + Sync>>,
 }
 
 struct MySender<F, T> {
     fut: F,
     tx: Option<Sender<T>>,
     keep_running_flag: Arc<AtomicBool>,
 }
 
-fn _assert() {
-    fn _assert_send<T: Send>() {}
-    fn _assert_sync<T: Sync>() {}
-    _assert_send::<CpuPool>();
-    _assert_sync::<CpuPool>();
-}
+trait AssertSendSync: Send + Sync {}
+impl AssertSendSync for CpuPool {}
 
 struct Inner {
     tx: Mutex<mpsc::Sender<Message>>,
     rx: Mutex<mpsc::Receiver<Message>>,
     cnt: AtomicUsize,
     size: usize,
-    after_start: Option<Arc<Fn() + Send + Sync>>,
-    before_stop: Option<Arc<Fn() + Send + Sync>>,
+}
+
+impl fmt::Debug for CpuPool {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("CpuPool")
+            .field("size", &self.inner.size)
+            .finish()
+    }
+}
+
+impl fmt::Debug for Builder {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Builder")
+            .field("pool_size", &self.pool_size)
+            .field("name_prefix", &self.name_prefix)
+            .finish()
+    }
 }
 
 /// The type of future returned from the `CpuPool::spawn` function, which
 /// proxies the futures running on the thread pool.
 ///
 /// This future will resolve in the same way as the underlying future, and it
 /// will propagate panics.
 #[must_use]
+#[derive(Debug)]
 pub struct CpuFuture<T, E> {
     inner: Receiver<thread::Result<Result<T, E>>>,
     keep_running_flag: Arc<AtomicBool>,
 }
 
 enum Message {
     Run(Run),
     Close,
@@ -124,33 +139,43 @@ enum Message {
 impl CpuPool {
     /// Creates a new thread pool with `size` worker threads associated with it.
     ///
     /// The returned handle can use `execute` to run work on this thread pool,
     /// and clones can be made of it to get multiple references to the same
     /// thread pool.
     ///
     /// This is a shortcut for:
+    ///
     /// ```rust
+    /// # use futures_cpupool::{Builder, CpuPool};
+    /// #
+    /// # fn new(size: usize) -> CpuPool {
     /// Builder::new().pool_size(size).create()
+    /// # }
     /// ```
     ///
     /// # Panics
     ///
     /// Panics if `size == 0`.
     pub fn new(size: usize) -> CpuPool {
         Builder::new().pool_size(size).create()
     }
 
     /// Creates a new thread pool with a number of workers equal to the number
     /// of CPUs on the host.
     ///
     /// This is a shortcut for:
+    ///
     /// ```rust
+    /// # use futures_cpupool::{Builder, CpuPool};
+    /// #
+    /// # fn new_num_cpus() -> CpuPool {
     /// Builder::new().create()
+    /// # }
     /// ```
     pub fn new_num_cpus() -> CpuPool {
         Builder::new().create()
     }
 
     /// Spawns a future to run on this thread pool, returning a future
     /// representing the produced value.
     ///
@@ -173,17 +198,17 @@ impl CpuPool {
     /// the middle of working, it will be interrupted when possible.
     pub fn spawn<F>(&self, f: F) -> CpuFuture<F::Item, F::Error>
         where F: Future + Send + 'static,
               F::Item: Send + 'static,
               F::Error: Send + 'static,
     {
         let (tx, rx) = channel();
         let keep_running_flag = Arc::new(AtomicBool::new(false));
-        // AssertUnwindSafe is used here becuase `Send + 'static` is basically
+        // AssertUnwindSafe is used here because `Send + 'static` is basically
         // an alias for an implementation of the `UnwindSafe` trait but we can't
         // express that in the standard library right now.
         let sender = MySender {
             fut: AssertUnwindSafe(f).catch_unwind(),
             tx: Some(tx),
             keep_running_flag: keep_running_flag.clone(),
         };
         executor::spawn(sender).execute(self.inner.clone());
@@ -205,31 +230,40 @@ impl CpuPool {
               R::Future: Send + 'static,
               R::Item: Send + 'static,
               R::Error: Send + 'static,
     {
         self.spawn(lazy(f))
     }
 }
 
+impl<F> Executor<F> for CpuPool
+    where F: Future<Item = (), Error = ()> + Send + 'static,
+{
+    fn execute(&self, future: F) -> Result<(), ExecuteError<F>> {
+        executor::spawn(future).execute(self.inner.clone());
+        Ok(())
+    }
+}
+
 impl Inner {
     fn send(&self, msg: Message) {
         self.tx.lock().unwrap().send(msg).unwrap();
     }
 
-    fn work(&self) {
-        self.after_start.as_ref().map(|fun| fun());
+    fn work(&self, after_start: Option<Arc<Fn() + Send + Sync>>, before_stop: Option<Arc<Fn() + Send + Sync>>) {
+        after_start.map(|fun| fun());
         loop {
             let msg = self.rx.lock().unwrap().recv().unwrap();
             match msg {
                 Message::Run(r) => r.run(),
                 Message::Close => break,
             }
         }
-        self.before_stop.as_ref().map(|fun| fun());
+        before_stop.map(|fun| fun());
     }
 }
 
 impl Clone for CpuPool {
     fn clone(&self) -> CpuPool {
         self.inner.cnt.fetch_add(1, Ordering::Relaxed);
         CpuPool { inner: self.inner.clone() }
     }
@@ -240,17 +274,17 @@ impl Drop for CpuPool {
         if self.inner.cnt.fetch_sub(1, Ordering::Relaxed) == 1 {
             for _ in 0..self.inner.size {
                 self.inner.send(Message::Close);
             }
         }
     }
 }
 
-impl Executor for Inner {
+impl OldExecutor for Inner {
     fn execute(&self, run: Run) {
         self.send(Message::Run(run))
     }
 }
 
 impl<T, E> CpuFuture<T, E> {
     /// Drop this future without canceling the underlying future.
     ///
@@ -262,17 +296,17 @@ impl<T, E> CpuFuture<T, E> {
     }
 }
 
 impl<T: Send + 'static, E: Send + 'static> Future for CpuFuture<T, E> {
     type Item = T;
     type Error = E;
 
     fn poll(&mut self) -> Poll<T, E> {
-        match self.inner.poll().expect("shouldn't be canceled") {
+        match self.inner.poll().expect("cannot poll CpuFuture twice") {
             Async::Ready(Ok(Ok(e))) => Ok(e.into()),
             Async::Ready(Ok(Err(e))) => Err(e),
             Async::Ready(Err(e)) => panic::resume_unwind(e),
             Async::NotReady => Ok(Async::NotReady),
         }
     }
 }
 
@@ -302,53 +336,64 @@ impl<F: Future> Future for MySender<F, R
 }
 
 impl Builder {
     /// Create a builder a number of workers equal to the number
     /// of CPUs on the host.
     pub fn new() -> Builder {
         Builder {
             pool_size: num_cpus::get(),
+            stack_size: 0,
             name_prefix: None,
             after_start: None,
             before_stop: None,
         }
     }
 
     /// Set size of a future CpuPool
     ///
     /// The size of a thread pool is the number of worker threads spawned
     pub fn pool_size(&mut self, size: usize) -> &mut Self {
         self.pool_size = size;
         self
     }
 
+    /// Set stack size of threads in the pool.
+    pub fn stack_size(&mut self, stack_size: usize) -> &mut Self {
+        self.stack_size = stack_size;
+        self
+    }
+
     /// Set thread name prefix of a future CpuPool
     ///
     /// Thread name prefix is used for generating thread names. For example, if prefix is
     /// `my-pool-`, then threads in the pool will get names like `my-pool-1` etc.
     pub fn name_prefix<S: Into<String>>(&mut self, name_prefix: S) -> &mut Self {
         self.name_prefix = Some(name_prefix.into());
         self
     }
 
     /// Execute function `f` right after each thread is started but before
-    /// running any jobs on it
+    /// running any jobs on it.
     ///
-    /// This is initially intended for bookkeeping and monitoring uses
+    /// This is initially intended for bookkeeping and monitoring uses.
+    /// The `f` will be deconstructed after the `builder` is deconstructed
+    /// and all threads in the pool has executed it.
     pub fn after_start<F>(&mut self, f: F) -> &mut Self
         where F: Fn() + Send + Sync + 'static
     {
         self.after_start = Some(Arc::new(f));
         self
     }
 
-    /// Execute function `f` before each worker thread stops
+    /// Execute function `f` before each worker thread stops.
     ///
-    /// This is initially intended for bookkeeping and monitoring uses
+    /// This is initially intended for bookkeeping and monitoring uses.
+    /// The `f` will be deconstructed after the `builder` is deconstructed
+    /// and all threads in the pool has executed it.
     pub fn before_stop<F>(&mut self, f: F) -> &mut Self
         where F: Fn() + Send + Sync + 'static
     {
         self.before_stop = Some(Arc::new(f));
         self
     }
 
     /// Create CpuPool with configured parameters
@@ -359,26 +404,47 @@ impl Builder {
     pub fn create(&mut self) -> CpuPool {
         let (tx, rx) = mpsc::channel();
         let pool = CpuPool {
             inner: Arc::new(Inner {
                 tx: Mutex::new(tx),
                 rx: Mutex::new(rx),
                 cnt: AtomicUsize::new(1),
                 size: self.pool_size,
-                after_start: self.after_start.clone(),
-                before_stop: self.before_stop.clone(),
             }),
         };
         assert!(self.pool_size > 0);
 
         for counter in 0..self.pool_size {
             let inner = pool.inner.clone();
+            let after_start = self.after_start.clone();
+            let before_stop = self.before_stop.clone();
             let mut thread_builder = thread::Builder::new();
             if let Some(ref name_prefix) = self.name_prefix {
                 thread_builder = thread_builder.name(format!("{}{}", name_prefix, counter));
             }
-            thread_builder.spawn(move || inner.work()).unwrap();
+            if self.stack_size > 0 {
+                thread_builder = thread_builder.stack_size(self.stack_size);
+            }
+            thread_builder.spawn(move || inner.work(after_start, before_stop)).unwrap();
         }
-
         return pool
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::mpsc;
+
+    #[test]
+    fn test_drop_after_start() {
+        let (tx, rx) = mpsc::sync_channel(2);
+        let _cpu_pool = Builder::new()
+            .pool_size(2)
+            .after_start(move || tx.send(1).unwrap()).create();
+
+        // After Builder is deconstructed, the tx should be droped
+        // so that we can use rx as an iterator.
+        let count = rx.into_iter().count();
+        assert_eq!(count, 2);
+    }
+}
--- a/third_party/rust/futures-cpupool/tests/smoke.rs
+++ b/third_party/rust/futures-cpupool/tests/smoke.rs
@@ -1,20 +1,20 @@
 extern crate futures;
 extern crate futures_cpupool;
 
 use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
 use std::thread;
 use std::time::Duration;
 
-use futures::future::{Future, BoxFuture};
+use futures::future::Future;
 use futures_cpupool::{CpuPool, Builder};
 
-fn done<T: Send + 'static>(t: T) -> BoxFuture<T, ()> {
-    futures::future::ok(t).boxed()
+fn done<T: Send + 'static>(t: T) -> Box<Future<Item = T, Error = ()> + Send> {
+    Box::new(futures::future::ok(t))
 }
 
 #[test]
 fn join() {
     let pool = CpuPool::new(2);
     let a = pool.spawn(done(1));
     let b = pool.spawn(done(2));
     let res = a.join(b).map(|(a, b)| a + b).wait();
--- a/third_party/rust/futures/.cargo-checksum.json
+++ b/third_party/rust/futures/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".travis.yml":"5686f4b7cbca0c317c323326387c6336c96d85ed4ce286d2f0805c04727b509c","Cargo.toml":"631f50135a7e844abc26e9c16b5a216438fe4e58fe582b8e8078507096bba5f4","FAQ.md":"bbc623c1561f55766155ba71a48ef9c63056dfd6c55a71ccc4315f5e37499053","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"69036b033e4bb951821964dbc3d9b1efe6913a6e36d9c1f206de4035a1a85cc4","README.md":"c1c4d9ac68761886c4161f76efc164b8034a3230ac764df18ec191fd6d8de901","appveyor.yml":"a330fd0b75d14f1e800053470462918c16c7590f5e8df2dcb8a178ad09451fd7","src/executor.rs":"d83fbd82ef0d85f8e53bdc4abe4e61e9f68f61bc92fec3bcf19ab88d37e91a21","src/future/and_then.rs":"15653d392d331a1fc4619129f737acc28525c88d1675b7fcea6ed27c5b1bf302","src/future/catch_unwind.rs":"f9c38a9b94283f3f615e8c74417a3865ba4b1beb3fae4541bd4d8db63450f352","src/future/chain.rs":"d37330af6d5a094bca999864800fe897311da33da36fc47e66ec3944b01a4841","src/future/either.rs":"9ce99b5cc19410cb67eeb8d40d55130e34fcb522446ed2a369c486ed51de72de","src/future/empty.rs":"b549a1ca0f21bc6d1a26d9063a9a60deb9235ff7eff5db915050115fed91a9c7","src/future/flatten.rs":"f03a3689d2d3e65a3edb9fbe0d440459d97a767bcc377afb4c490e6d8c5e73b5","src/future/flatten_stream.rs":"cf914425c3606b61c046df5c43d64266d6f2328693e4122441f9bbcf7cb0a4e1","src/future/from_err.rs":"a1f42d95f7b52e80c2e5a03b44cbce0efbe5fc486dfe33d799b74ab9ba9057ab","src/future/fuse.rs":"41098c6693e1416679e1628776d7925cbd55446cd6b957080cd48e9bbf34ff65","src/future/into_stream.rs":"0fa6bc4d70e8b4d75cf45fba53b39f033b87574103fffea4090b78f049bf43d0","src/future/join.rs":"01a0e611ea7d51ac58381364ef2602ce3ef18ca32efafa7830b4e32bf646385b","src/future/join_all.rs":"6f36cfad1bbbf72356fc87e7d4eeccef0964dc3f8aa8687f5c87554f1b292a2e","src/future/lazy.rs":"1a2025bae3675fb682cefbf8a88bbb7a7519cfdee42dd6b3049a4d2b7ab8b5b1","src/future/loop_fn.rs":"5bd952247ae4e9d31dff77386bbd3700f596da136ea53e9e9944266af3f08688","src/future/map.rs":"91e148d9adaea929b85ede63c71fb07ef9b5611db906a13eedad2cf551745b47","src/future/map_err.rs":"2c8e87fa8ff56061722db6c69aaba588e6df6835a4e2fe84826f0bd4fed2e007","src/future/mod.rs":"d0fb5b3acfd96d275519042e5e1d2c3c9eb0bb9f23c8a501401ab999dbafb8c9","src/future/option.rs":"93270226cadcfa349250023e2070e687cf595831f427904ca744f7bc50342ded","src/future/or_else.rs":"444567101c4c437b184aa2e2eec0cf4363af442c0afc58d6508d3d2ac86489a9","src/future/poll_fn.rs":"817bfb75e7c43ca96a53e8cc9f48606c92c3c6742b07a732ce79a8f9b7bf8808","src/future/result.rs":"3e1f6cbd813bd2098ad85afc895f1f51396bfff111025cca58d7533acf7e5bc7","src/future/select.rs":"73efd98004d5d8c46607bf770ff07a810bcdbe05cce0e8e4f41f5e659fd44203","src/future/select2.rs":"ac80e0e2db9eb9f5a331a4c25db6c9e0e42294c4e977da2f2181a2a5822a5a34","src/future/select_all.rs":"c47a84f7dad551c2a95c2d2724577f962567aafd7959584a41d68934f6b5ba59","src/future/select_ok.rs":"04f99f4ca85bcece456c8f94edfdee197f6e2e497d51f0f1484553c03d37c11f","src/future/shared.rs":"ddf1897cafb0331c28e8d7b15e7cb7a5067e1a58b1f15ab023e0319c78f32c06","src/future/then.rs":"c49b388ab3c78979ad9ae40f6e859ee98e9351bdb11e3c3f1ad4ceca77651a56","src/lib.rs":"e3c6e1b2989764a97b8b1677e5e2ba80a4c0304ecb73cdae166e6ba2c869c9a7","src/lock.rs":"fe4c8185f9774a134d4ce27af4a9c8b25f30f7dcc6990473210d66b6b8936ce4","src/poll.rs":"05ff3ccb136b3e0e4da497d7b9b48f1dff61a0105546f6d504a3f144c5007124","src/sink/buffer.rs":"aeae8c4440d6fddf4635c9d9d298ba40b02278893703cc87235c8221fee8ec19","src/sink/flush.rs":"a2ee8c2b030dd42830ade7f76ff5505da5fbd59922b1946727a449b37ddb0dce","src/sink/from_err.rs":"0e682d8438180a0c592851e62a122d003251e1709393812a26ca45d38a59157e","src/sink/map_err.rs":"164e136d92dc7993e33cd671f5c459ee5a327eda4a7011e4b2c899ac7396e1b6","src/sink/mod.rs":"4dd651dd60dfed65105532098bb80c9d41b76cc499a737937281f7e7a81f2169","src/sink/send.rs":"8de1091909fea8d59256fa4575f3a6ade8b316eeef56e60e07144db73ca837f4","src/sink/send_all.rs":"5f8521f46e58748f8e2a8040af75566f52242cb4eeffcbade6b900c58c9ccf0d","src/sink/wait.rs":"e3f6827ded4d689242a0d315033415145a9c3385e675d5cbfac7d1cc801aac64","src/sink/with.rs":"a3a183cebbadb9ff57e8a2d7ccf84f560a6f32c2586beb3960b32033be183de6","src/stack.rs":"76d9922de0286bc7cb4da2ae31f672af38ad658ff1763e17c55e1b94d31b7f85","src/stream/and_then.rs":"fe33b6ddac5048452ba97fe78a50bcf6d6e10d92c641ca9fb14e4373ab7b925e","src/stream/buffer_unordered.rs":"32f3c1b6221da11952649425354c1efbf67e1ae1793d69f0a89c52183651873a","src/stream/buffered.rs":"a28639ec87a0b922cef842a950d803fbc01c403ae14193d792bb9296bda1eed6","src/stream/catch_unwind.rs":"957b935645f1744a4741962772c15e94370153f33e0db356309bf98ebb599c37","src/stream/chain.rs":"0b6b06cf5aaf0c2f665c61c65766d6113e24f690ebd9ad3a89abfa521e2ce9b2","src/stream/channel.rs":"f728402228fea0be01ec5cf1d02e49e52666c0c9ea986708d18e24f30376f6de","src/stream/chunks.rs":"f716e2cee2660fac9fe309c943b3eb00c3a5134fc7453ba309301f8067902daa","src/stream/collect.rs":"e770850c7ed2d458b521c12af4ee76adf2303919849d2f95fa93fdf574c86d37","src/stream/concat.rs":"140265d64a3ebe2945165920483c912fda6d395c2e5d7f882bd08f57ebcce474","src/stream/empty.rs":"e8e2820fd3b2329a6987a11c3b3f28849f49427d1a745f2bdc7a4982476514e7","src/stream/filter.rs":"0f4c2f436225b88172dd5035ac7f1dbf786c09993475c92cd6acd69805f85719","src/stream/filter_map.rs":"57970fabf3017cb0e4b36326234d813e43b19abc768547a7b067a1ef10e8e760","src/stream/flatten.rs":"8ce863e6c5fd92e847416a8d1259a32ef262ac34e19b46b610688b08fa36b3f3","src/stream/fold.rs":"46e575e4b882ae904e79cb046472a942839fe4197d1b8fd0b09987024d074034","src/stream/for_each.rs":"9d260db96b8583d1c983b2b29b791647aa39046590ff256669a796e989ceb71a","src/stream/forward.rs":"ec34bd69c000c72662850b4165c227c97b5ac34b825ef38085cd945174466392","src/stream/from_err.rs":"5912cfb747c286eb30e484ad67cb12ddc780be14fcc6fcd6b25ac5b10ca06b4c","src/stream/fuse.rs":"f0343df89167cc7e3c2354c81396b32f2359cd27ce5eae48c6f2a6f4182e188d","src/stream/future.rs":"e9e3100be0090306efa14ea81cb3680f79770648b72c8616e2fcf61a3bef8f94","src/stream/futures_unordered.rs":"c963c13a6431a032fc5d7744b5572988ae1c60ec8b6934b6aeb49426d2472476","src/stream/iter.rs":"4492d00d2463e0e04e448b11c9947170a875685d5243a96306495cc14b4d2c14","src/stream/map.rs":"9e2d5c0d68cc6cee83fc1e640450ac0c22f458796bc1e5602d3377ad7b024361","src/stream/map_err.rs":"78cc76fcf3098242e42dee9fa72dc8a55a58b449d5440e11782168923d5ea90c","src/stream/merge.rs":"9b8f31aa4e7623c39e2361db98b3e552bc39ae8933d968ba5150cefe2654bb76","src/stream/mod.rs":"dfd83151e1226a663dc81319dfb1f5bcd8ceb76ce5c4cd62de1f2e32cb799e2d","src/stream/once.rs":"65cd915f645bfcfc560d4e38dcbf47e330b050662456c75f71405b84928deada","src/stream/or_else.rs":"c11ea499d85d6204ad083058eeca9dbf29873c49ee21bf01f9fe53e9ec3bba52","src/stream/peek.rs":"25d78baa0b3e30d2d1c72d1f3b1aa2a28811522d345dceefec587beb18b70fe2","src/stream/repeat.rs":"c047f76b2d6bfb6a217ad81939cc57a6f63b105df1cccb2776db39f97a64961f","src/stream/select.rs":"cb057a133e03833f3387de7045d1d4dc8427d1070696fe9d527591e2dba51e24","src/stream/skip.rs":"3aff9f823cd8211002d36812d6709f22142afffb8bf4b24d33b3cd815b6cb797","src/stream/skip_while.rs":"ff68f87ea4b09f55f8bc3bc03b204849dac2776098c6fcc7bee60612dfc7b2b0","src/stream/split.rs":"5c08f444803ecec385070d92bceab0afff0af957047bcc78e1faac2acf2e59c5","src/stream/take.rs":"2d0a1485a85935db1dc3b57a9d5eb6a1b57d677aeba5eeb31b783ceb3f0223c2","src/stream/take_while.rs":"c542541ccabc362592515f3b463fa8a0c4fec57bf0b98663892a8357ed77c4f1","src/stream/then.rs":"c7c66e27180cf2d98694de27504283a32444a0d0d6919ab25b3621fa6169408d","src/stream/unfold.rs":"7786706eb8f7a79f72e3e560a108adcbd17a0f5bee9d36ef4ca1340b203b18c5","src/stream/wait.rs":"1ad58c82e1861b2a5285911486e6358fb665f8c2f6023037be5dac6019745f6b","src/stream/zip.rs":"05d98559a82ffd77c388e6b664ce54ce4dbccfae680bc47466f1b05a91ad1b21","src/sync/bilock.rs":"c8bf12cd6747daf63a19891d2c018b7a84b5af8c065362580c8a68b641698c07","src/sync/mod.rs":"56df9c0b8a4bfc0887299e1cd1467629fdb6b9889099978b143b54e4f6db1447","src/sync/mpsc/mod.rs":"59a264b783b189cd9acae432ee7614bb3803446f942e9bfdcaf911451d662762","src/sync/mpsc/queue.rs":"ca3c3da09c1b126658f0b5fea1014b2d605be56d19b6d127813c0230cb18f4a8","src/sync/oneshot.rs":"86d800b56cd4e4427651dad7b11ad4680003c3fcc3a928c996fbe223f1db5227","src/task.rs":"05c85355317b8558f821a708b211bdff020fbfdf320bda0c6e2ea80c4b5b6c08","src/task_impl/data.rs":"1345ab12d94a87c41ca2c98d12a4deca671a506854d4b79bc4fd52fe67e31f5d","src/task_impl/mod.rs":"01c735d065e209105cf37098854ee8a2a2287cad69e43ae5edcfdd1a27021687","src/task_impl/task_rc.rs":"685630c9d5b199496a182e6edbb9ae66863c653ca9775af690980148fb6b1378","src/task_impl/unpark_mutex.rs":"e8b27d129191dd1e79b7869b850f77a1f334006d36dfb0bbfa9bb3e13e009934","src/unsync/mod.rs":"e5da32f78212646f0161fec2e7193cda830f541bc9ae37361fbcf82e99cc1d86","src/unsync/mpsc.rs":"a7afe694c58010d5fc7f39f82c3dfe47e167484ac80b12b34fcfd7bae974fd64","src/unsync/oneshot.rs":"58263830fb7238c52ac2f57fbe260664bb5f87229129bb09c98ea4d13056b14f","tests/all.rs":"891051771df3d8daee66380968e41a5a44063d4a3e7c9f2eeda9e81b02144435","tests/bilock.rs":"734bf0fc2f9b6f5047249f570f550dfc8abf958cec4ef757c79327ab2c9817d6","tests/buffer_unordered.rs":"37df5c5e8f7a1198532d2d71268c874c880ed6ea3ea2d34ff6a41e46207e37b2","tests/channel.rs":"3fdff94031fc9d3cedc22bcc0b867242862f2b8d7857496fa3d3f744c2a47e82","tests/eager_drop.rs":"7a232c3d43906843ad179a06cb5e807a9907695ec51a6a3418d1390f0b988b15","tests/eventual.rs":"9102353f670d7d7c579b1bceb35a401aa382ab6f18da91d26fd1f2553f1c516e","tests/fuse.rs":"efe6e4808b2725832642c8a6ebabb09d4319725e4826b4753b5c8f99a5f09522","tests/future_flatten_stream.rs":"2daa00b8916d4c018d8274e5215f5434a072710494707f20b4a0b6f055d530f2","tests/futures_unordered.rs":"849fa8dcd106fcb4a4e5ee79c57c6580bd2b67e5fa5e6732ab4398b309a9d31b","tests/mpsc-close.rs":"3387e2afb4cf6b98e64bc376944a77447653f790a65d98f30e6000e9197c856b","tests/mpsc.rs":"514ee7bb3349647779f945ab3399b32c36680d7b5c06ac6287f76f0192c0e50a","tests/oneshot.rs":"82f20c57d42ddce3dee180da396dd4a8c84023f711124e3facb3dc4c7c481e90","tests/recurse.rs":"5702590b294493df85b20c239bf82f54a5384789d1439a2f929810525b585f79","tests/select_all.rs":"c7a998215df56ba7336b457798979c9cc38bfb5c30e40a1b4a43d5e58e85d4a1","tests/select_ok.rs":"2ea75dd4dd29d49b659bdc9f2df55e8928b41b55d7b39d80d987ac3273a04245","tests/shared.rs":"898f9dd106eadca3b8ec21675cb0026463c941feb04e5f247e57edf5e5e0d2b5","tests/sink.rs":"df7c44529ba2a04309a4817d2e5aea6788088c375daa382398524117d044a707","tests/split.rs":"635372fa052c4f43b196fabbd1587e0b85c15385a9ab63fe660e18d87e535da6","tests/stream.rs":"f7c5a8481093aeaaf22ba066f8c0311a1bcbe329e6575a8a009b3033442c3d4f","tests/stream_catch_unwind.rs":"6b3b5ab2315682d17df0ebd47b9cfd0f407b02e89970bdf777be9f6c981c1451","tests/support/local_executor.rs":"6c9bba7f628805e36cf47060ad057415d9fa3e6f1cd4a8cec8789022fd022e95","tests/support/mod.rs":"6be1623f036df50846952d0e073e7a7c9c133712643c550a364f9db3bf13e364","tests/unfold.rs":"75b784c8e4bada8e04a615b274d384eb7c8e8b2bd52b4e84b9e1e5bc61f21df7","tests/unsync-oneshot.rs":"b77013799ecd72a9769760c11c6f021756dd3909a085e485b784579a356e5f62","tests/unsync.rs":"100a5a69b5c6af23918e07c6e19a06cc91ed1c51fef2d634144e4b724492057a"},"package":"55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"}
\ No newline at end of file
+{"files":{".travis.yml":"09f003273cb5a49fd05defc653b5dfc2ce8587ba84c42a6db3909f51eb5f68ab","CHANGELOG.md":"a343d7c2350fa2a9f95e8b49ca8f9e69838437e1819145ceee421477b696a81c","Cargo.toml":"6a3dd737c32ae8ec4a25cc04db19d2a7f95a3988e69cd29c9ad6f04762a2a6fe","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"69036b033e4bb951821964dbc3d9b1efe6913a6e36d9c1f206de4035a1a85cc4","README.md":"9217a715c9730fb2a3814641cb0b0c25a4636c0a9517352f41aa972f3666c22f","appveyor.yml":"7b8de5d694cb575649354d7fc3eff0781e2c5c412df4bc8a90b36b6fdb55bfab","benches/bilock.rs":"60b9e0814b8396e0320d299273c6f91c2ccc09a2bb59eec92df74a1f0919e54f","benches/futures_unordered.rs":"fa2d3b5e6cdfe1e941d78c119a696fb583341fa0a0895ec2692e6d374ceb9a0e","benches/poll.rs":"ca369079c4db366a180be22f406eaf8e94e2e771c02568eb35d89e63093006cf","benches/sync_mpsc.rs":"f7f15346ef258d1defbacc8201cf912e5fe928cb39977d4e15a801a5f95e73c7","benches/thread_notify.rs":"1992b1e2b352fbc15a611d1318ac1bf6f19318d769086d55c80e6863f1b0e106","src/executor.rs":"14cbfd6fd5bd0cc55d78a51c754effa478d21cac1792c8d4daf228f2087b7246","src/future/and_then.rs":"15653d392d331a1fc4619129f737acc28525c88d1675b7fcea6ed27c5b1bf302","src/future/catch_unwind.rs":"dfef6b6a66c09574338046cf23b0c6aacd8200872d512b831d6dc12038f05298","src/future/chain.rs":"4d712e989e079f4164d5d9fe3bb522d521094b0d8083ee639350570444e5bb93","src/future/either.rs":"d8d3a4686dfe0068cc35ee452268ff2406e1e6adfddd3f0841988bfa6489ca5d","src/future/empty.rs":"b549a1ca0f21bc6d1a26d9063a9a60deb9235ff7eff5db915050115fed91a9c7","src/future/flatten.rs":"7eb15429fcc749326371fe571e1f7d294d7b83f7557e6e1971e2206180253d65","src/future/flatten_stream.rs":"cf914425c3606b61c046df5c43d64266d6f2328693e4122441f9bbcf7cb0a4e1","src/future/from_err.rs":"a1f42d95f7b52e80c2e5a03b44cbce0efbe5fc486dfe33d799b74ab9ba9057ab","src/future/fuse.rs":"41098c6693e1416679e1628776d7925cbd55446cd6b957080cd48e9bbf34ff65","src/future/inspect.rs":"89c362d8402dddd784bcc54e62ca27657ca8108e1ae8de5a7237e08650e10636","src/future/into_stream.rs":"0fa6bc4d70e8b4d75cf45fba53b39f033b87574103fffea4090b78f049bf43d0","src/future/join.rs":"b1dcefb03b1cb4e609ad2e79ba9a6cfab24235d7a4fff7fb9daf2c8fbf0f3d70","src/future/join_all.rs":"30fc27cbc1248046937b441a165a911e9ed1cd887ad6f3aeeb573b59c43e9cbf","src/future/lazy.rs":"1a2025bae3675fb682cefbf8a88bbb7a7519cfdee42dd6b3049a4d2b7ab8b5b1","src/future/loop_fn.rs":"5bd952247ae4e9d31dff77386bbd3700f596da136ea53e9e9944266af3f08688","src/future/map.rs":"91e148d9adaea929b85ede63c71fb07ef9b5611db906a13eedad2cf551745b47","src/future/map_err.rs":"2c8e87fa8ff56061722db6c69aaba588e6df6835a4e2fe84826f0bd4fed2e007","src/future/mod.rs":"c0745575c1b1cf1d63ff9af810206731f4a5f6cfcfc47338272c4f69f8f64694","src/future/option.rs":"93270226cadcfa349250023e2070e687cf595831f427904ca744f7bc50342ded","src/future/or_else.rs":"444567101c4c437b184aa2e2eec0cf4363af442c0afc58d6508d3d2ac86489a9","src/future/poll_fn.rs":"817bfb75e7c43ca96a53e8cc9f48606c92c3c6742b07a732ce79a8f9b7bf8808","src/future/result.rs":"cc62c2377defb7b53aa859bf05c41c52a9cf8583378b7072bb2b45232d5fc9c5","src/future/select.rs":"73efd98004d5d8c46607bf770ff07a810bcdbe05cce0e8e4f41f5e659fd44203","src/future/select2.rs":"cfbbf3a9794109c56a3703456fae6111826bc25f98f2f36b234d483eeeeab482","src/future/select_all.rs":"b009e57ac241a3aba78db0bb751432cb99c1e91b8bae1b3baf225921f0daa441","src/future/select_ok.rs":"4884896914d8903edbfa12b5e255d35d5b2c91a9182ce6f774978db636617905","src/future/shared.rs":"95d22f444e04378f32dbaf139a207451e01bcd12f2e8cf1d4428aa1383b57f0f","src/future/then.rs":"c49b388ab3c78979ad9ae40f6e859ee98e9351bdb11e3c3f1ad4ceca77651a56","src/lib.rs":"6084082d252dab422505eac3da3925d1a001af803cd7b1bc0c57fc8c0d79797e","src/lock.rs":"fe4c8185f9774a134d4ce27af4a9c8b25f30f7dcc6990473210d66b6b8936ce4","src/poll.rs":"df74c3a8169d7895f3c46dd6de99edd77bd024b85e26b1d0644d2b8e5ef515b9","src/resultstream.rs":"365bc127c0410badb58ea2beb2abae546968ba3ac91abe2140e93e0c3620228f","src/sink/buffer.rs":"0e0f7d60781b4b2970b1b4508bbf245a20aa22080ce2808161dd48121b03a33d","src/sink/fanout.rs":"1fbcabdb1d22a43919417790082dc27ac65e2a100263504b6664a0b5e0657ae1","src/sink/flush.rs":"6c9a3bb9705c740e601ca6101cf6e6a87f2568661cff39a3576ef55986e3cb60","src/sink/from_err.rs":"cef45aff1c0c7638a507a770b1e6fc8a5b4bf4417ae4b35faa839f579e3ae81d","src/sink/map_err.rs":"7dfd27d87f5877ddae1c30821635dfc3f88f1c243fed234007c9e50fa693ebed","src/sink/mod.rs":"4b4d80d008bfa8d0abc83cd640dc9c107423c7920795678c079c544c037ab632","src/sink/send.rs":"019f3f8ab450edc0adb864e4b819f5b0d4cfe9dc33a53093c2aa18e1eb6270dc","src/sink/send_all.rs":"b05047459faceecf0dfd5e6280014c31f5a2a1058974785db8ede497c10a1e79","src/sink/wait.rs":"9c70fdd54c642e4ecf7d9b0ff1fbb2df9c89349dfd60b5482748cd93c6dc301e","src/sink/with.rs":"1d4ec61bd702196ad8a044dc40bb6967b3dd0c1ee14c32b1481967e71aa61405","src/sink/with_flat_map.rs":"7b0f367d98a99d297c3ce097e9858ad7b0dfdafbb66516cba0767b62beb01af3","src/stream/and_then.rs":"9f0f6ee06343ab03eebcb71257963e76d8e7208e4015b402cc8a58f793e37d79","src/stream/buffer_unordered.rs":"057c3dec32baf451ef02f44ef849086637e4d2cbb2d65907cc15ed9398fe131b","src/stream/buffered.rs":"4ced19e37e47182d5f9c7f852a7906c35b71ac4a5b2774a9101859defbecb190","src/stream/catch_unwind.rs":"957b935645f1744a4741962772c15e94370153f33e0db356309bf98ebb599c37","src/stream/chain.rs":"0b6b06cf5aaf0c2f665c61c65766d6113e24f690ebd9ad3a89abfa521e2ce9b2","src/stream/channel.rs":"f728402228fea0be01ec5cf1d02e49e52666c0c9ea986708d18e24f30376f6de","src/stream/chunks.rs":"6c68b006670f2ea227231ba9a7986c46b4f798a871a3de62dd00acfb84c3435b","src/stream/collect.rs":"e770850c7ed2d458b521c12af4ee76adf2303919849d2f95fa93fdf574c86d37","src/stream/concat.rs":"39549687b589562ce713a999e2887b6f20ec8f87291d82ee8b1a48dd7dfe9c8e","src/stream/empty.rs":"e8e2820fd3b2329a6987a11c3b3f28849f49427d1a745f2bdc7a4982476514e7","src/stream/filter.rs":"4abaf6c7bd3ecbccf7deac7920cc6bdc1b17875bedf7c6acd7e702254b3b83ba","src/stream/filter_map.rs":"573079f98efc38bbc68746084702b952ccb035bd8238c3c30fa103979865ed0e","src/stream/flatten.rs":"f2edce326745373c9c524bb574ce18584be95c7fd1a0ef875256b39891219b18","src/stream/fold.rs":"7f397373ed66560ff1eb0cffc5dafaf1569d3c8155fe418cc2bf6fc33faec230","src/stream/for_each.rs":"bd7f96bf551a829e37a54fd529e0b68a8868480797df039c75e1f226639cf096","src/stream/forward.rs":"5dd07a3d85130554f6c0c950fd635e4594f43a0284440f6f1af2a240511c5621","src/stream/from_err.rs":"bde1791790030c480aa88c6f7b235703d5b400249c841c8b045ea2203728b96c","src/stream/fuse.rs":"5d544151de7e5a3ce8a47bdeabe5cc9beaf0937b1eeed67e8d76842f54dea65d","src/stream/future.rs":"e9e3100be0090306efa14ea81cb3680f79770648b72c8616e2fcf61a3bef8f94","src/stream/futures_ordered.rs":"3e41623352600e116c327fe37005da04b0dcf1d5db379cab147738a1383732d8","src/stream/futures_unordered.rs":"3a445ebf5815ecbafaef6dab011cc3edf012564082717a615b70425e78142e1e","src/stream/inspect.rs":"4a1e7d7bbb0842a7021c5145bb1b64dbc213cfdccff51fe8399e3120c123eab5","src/stream/inspect_err.rs":"b4f2bc6a139df8f8eb403aafbca91c05b3093d3a6e13cef034a639fbe3ebe01e","src/stream/iter.rs":"cfff6b28759ccf390e8367f9f63209133c16e7fa53c7ae71167f318ba3ec624b","src/stream/iter_ok.rs":"5165cb02972776515734e0f343e626fbb448b65b38cdeacffbd86116f3c3cd37","src/stream/iter_result.rs":"9db38b1066d9adc1ece496432127049d36fb4b9895660c2af2b7ac28510c9084","src/stream/map.rs":"ba16b1469e519377939cf3bd073b258ac41e6349aab1c59393e3b30178a56496","src/stream/map_err.rs":"5ce9a279fde1f4f0887435856e1efa4fdeda749d43f4bab658b0abd216bc0a6f","src/stream/merge.rs":"63bb60ca386e280985cee8e16ae8b07f02d57aa8a0fa877ae01fb8b4678366d0","src/stream/mod.rs":"474de35e551c67950b7713de203a834e2284092a8271b51da4d3b96beeb9197c","src/stream/once.rs":"277c960dc4bfa09fcc6112efa4e38a9fe937dc31fff440405e60bfd843f3c1ab","src/stream/or_else.rs":"c11ea499d85d6204ad083058eeca9dbf29873c49ee21bf01f9fe53e9ec3bba52","src/stream/peek.rs":"25d78baa0b3e30d2d1c72d1f3b1aa2a28811522d345dceefec587beb18b70fe2","src/stream/poll_fn.rs":"1dffbe60bd50c19efb71de2f768eecf70fa280b0d9c9cb889d16bb43b1619c8b","src/stream/repeat.rs":"807f2be5c9c1e7d54954f73ee38a373e71177aca43be8866712798f29ab541c2","src/stream/select.rs":"027873d9142e896272f7471cccaaccb133bf9f696a3f7510f3fb1aa4253a7c09","src/stream/skip.rs":"d7c839ca15f830709ebedd9526bb9ebd64ee22cb944e44213ce850a1383b71fa","src/stream/skip_while.rs":"aeb9bd64530bfaa631f4ca9500861c62fbf32849b09383eb26904bedd8b8b269","src/stream/split.rs":"c9b391fcbf3d1762bde442fd3549bd4739d2f9f486e88063650d42fea33c6af3","src/stream/take.rs":"9872429dd89cb34755b514abde9b6a876da076aea0449fcadfcc48e982507f21","src/stream/take_while.rs":"36bc2a33850ba2b58fb0da3866c96c8f4dfbd81133e615fda031518e71d425b5","src/stream/then.rs":"c7c66e27180cf2d98694de27504283a32444a0d0d6919ab25b3621fa6169408d","src/stream/unfold.rs":"5e69718714cc38c5ca6d0a6f5243ab28e392bdc97d96e8ab9059d9f0e772120c","src/stream/wait.rs":"936a15df4499d188f210cb0133bc8ad25e33e5b674a96105b4da549f32e92b40","src/stream/zip.rs":"33f1401683a29ce194927533c40bdbbc0783c552cf0b666f268fa7109e593853","src/sync/bilock.rs":"def09b26f9d66f2be0a8885ad6cf7106c3a073493bad591fc4a068212f0d739f","src/sync/mod.rs":"27ad26777f600f7054215fccdff07f4303182af2a6e0998d4229d62b090b7aac","src/sync/mpsc/mod.rs":"edb206061ead2428a418e4f7227df09a7f5339796af094100b176eaa6a7f5a64","src/sync/mpsc/queue.rs":"b39889f1b2000a3de995a50f46243f97a98d3cce7c6de4b95c4d8ffeb42af918","src/sync/oneshot.rs":"ff409b2518d2c41998fcbf88e67d8b0869cd5828784f088c5e3b025b034db37f","src/task.rs":"914955224ba1613835027e6d6436b83ce41caf217428c2c576e8783cacc7ba96","src/task_impl/atomic_task.rs":"79298f2f90aaf2efb63c574346ff1d7a955865a94a5de4321e22a6565c58b15e","src/task_impl/core.rs":"3ababa3970da5668f2b678724a4b5e1aa5f2b65a2355276b7d14ba3dfdd52686","src/task_impl/mod.rs":"89bf59d2cf41a91bcc972ca5c66e72f6ac02b10c70cca501a86238173abee2b2","src/task_impl/std/data.rs":"9b6210811c095c4d0ec0f59a566bb8f5bc4b6ba544c72a4565dc47f3b7fbfab9","src/task_impl/std/mod.rs":"7232659b0ff0e8c40abb4fd1c04c216f667837151fc31b2269d703b540aeb25a","src/task_impl/std/task_rc.rs":"a6e46e79fecb1497d603c016f4f1b14523346f74af800c9c27c069229d62dc25","src/task_impl/std/unpark_mutex.rs":"7a53b7209ff00880bce9d912c249b077870625ca87fe9ab7b0f441d3af430302","src/unsync/mod.rs":"e5da32f78212646f0161fec2e7193cda830f541bc9ae37361fbcf82e99cc1d86","src/unsync/mpsc.rs":"ee5fc8723258b25e802c186c2827554a6dd7cfdbfaa50fd9ea50d5b15edf826d","src/unsync/oneshot.rs":"89661388a87d4ac83befc31df9ad11e6a8c6104e2dde7be9e3585d7549cfe8c4","tests/all.rs":"99c6ad1d1e16ad2e0bc3027e1f5cb1a8f89404f71d77d3fc85badb67278f8179","tests/bilock.rs":"68462100c0c1e4e72f220d96ce1e6b25648f4c10a390be8a3bbfa99bbd795f31","tests/buffer_unordered.rs":"50ceb305da08fa095ee40a8f145fa9d95db59372cca949d77f011bbabc072152","tests/channel.rs":"63d6ab1b7fd51680562f9d626a5fab9d4b81226272b5e0f9ca7faa88eae5073a","tests/eager_drop.rs":"e0a615c39f1fb9baae543212e72a165f68e7576f6b8c6db1809149d819bd546b","tests/eventual.rs":"73cbd3836a598175439b5dc5597f7e464dfbc6d77379aaae1172c6c7f85220e5","tests/fuse.rs":"0b7ee173564cf236591d0cbf78fa076af82aad9816eb176ae58d549ecd2fadf9","tests/future_flatten_stream.rs":"133b91a9e2170849ed7dbcb4024675873a781bf2dd190cfcaa9c41418c3ccb97","tests/futures_ordered.rs":"7835bf9bedb9322a93070b5d87886b7a333dc469aee74f7eb86a1a7914b4602c","tests/futures_unordered.rs":"048153d9c4ec3433efbb97edfe01a458762e76160624362c658432f6f2357524","tests/inspect.rs":"d7706a175be9ed6ecc09d7a45e1559160e00da85fa8a9a7caec4c53918999842","tests/mpsc-close.rs":"824cdb5c574459c8a374e6b890140a22edd91f6edef901184b4507f69accf2d5","tests/mpsc.rs":"d129624af8c156566faba996bca36f5c86f902496b78fa99c8e9c0040693b53c","tests/oneshot.rs":"a8773b3a65e79944045118f36bfd81fceb826d4e2846b46f86db37a02d7ae1f4","tests/ready_queue.rs":"3d50c4e71e3954c5b8e2672255b6af33abaebc16172c038e64c3323d633693c0","tests/recurse.rs":"4922e1ad975dca9d6b63d155515cc24181ad6a915adcbb743f7c8a58c0148a77","tests/select_all.rs":"3666e95ea94da17abb1899101e51b294af576bc446119fbc8aea5bb2991f439a","tests/select_ok.rs":"7a740e5b2d70c7776202ed1495b016f6e63ae1de06ca0f12ab21fcb3117450a9","tests/shared.rs":"4abb7c9a7f6207e40bc7408ee405df4e5a3e778054ceb113b4a177a886a64d11","tests/sink.rs":"a2c5d8f89cb6d757f548f799ba84f2ba758fbdfe9cc951f1dcdbcc2bec50e648","tests/split.rs":"24dd293f049a37bfaabb02ae558c81e9fef9298a2ce43ecb544450b045c15f5c","tests/stream.rs":"3ca52f06a4503a853acce77997e4e744903c2084a83e0abf1e704e4f73833805","tests/stream_catch_unwind.rs":"6cee77f455a671d038aac24cf2f79636f1c0a5d8900957a2fed0ee3ed99832b8","tests/support/local_executor.rs":"10ca7f0bc1d9fd45350a807cfd76015fe24bf68d9a711e16ea0ec6be22af9ddd","tests/support/mod.rs":"1961189f57851a468e518327da0b7893eee990e477b82a278e0015f25b5e5a1c","tests/unfold.rs":"27ff8c3c83b333094bbffe6aebadf3730f0e35d1367b7b602a3df4e233d934d8","tests/unsync-oneshot.rs":"e676b37a64e1d6c0816d55cf443d86249ec2ff8180f1fc0d009de51e6842dac8","tests/unsync.rs":"facc6a6ef2403e26777dcc075e679a84f55ff1fd09bd259f3ff4b026adca1cf0"},"package":"0bab5b5e94f5c31fc764ba5dd9ad16568aae5d4825538c01d6bca680c9bf94a7"}
\ No newline at end of file
--- a/third_party/rust/futures/.travis.yml
+++ b/third_party/rust/futures/.travis.yml
@@ -1,37 +1,35 @@
 language: rust
 
 matrix:
   include:
+    - os: osx
+    - rust: stable
+    - rust: beta
+    - rust: nightly
+      env: BENCH=1
+      before_script:
+        - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
+      after_success:
+        - travis-cargo doc-upload
     - os: linux
-      rust: 1.10.0
+      rust: 1.15.0
       script: cargo test
-rust:
-  - stable
-  - beta
-  - nightly
 sudo: false
-before_script:
-  - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
 script:
-  - export CARGO_TARGET_DIR=`pwd`/target
   - cargo build
   - cargo build --no-default-features
   - cargo test
   - cargo test --no-default-features --features use_std
   - cargo test --manifest-path futures-cpupool/Cargo.toml
   - cargo test --manifest-path futures-cpupool/Cargo.toml --no-default-features
 
   - cargo doc --no-deps
   - cargo doc --no-deps --manifest-path futures-cpupool/Cargo.toml
-after_success:
-  - travis-cargo --only nightly doc-upload
+  - if [ "$BENCH" = "1" ]; then cargo bench; fi
 env:
   global:
     - secure: "iwVcMVIF7ZSY82fK5UyyUvVvJxMSYrbZawh1+4Oi8pvOdYq1gptcDoOC8jxWwCwrNF1b+/85n+jlEUngEqqSmV5PjAbWPjoc+u4Zn7CRi1AlxoUlvHPiQm4vM4Mkkd6GsqoIZttCeedU9m/w0nQ18uUtK8uD6vr2FVdcMnUnkYQAxuGOowGLrwidukzfBXMCu/JrwKMIbt61knAFiI/KJknu0h1mRrhpeF/sQ3tJFzRRcQeFJkbfwDzltMpPo1hq5D3HI4ONjYi/qO2pwUhDk4umfp9cLW9MS8rQvptxJTQmWemHi+f2/U4ld6a0URL6kEuMkt/EbH0A74eFtlicfRs44dX9MlWoqbLypnC3ymqmHcpwcwNA3HmZyg800MTuU+BPK41HIPdO9tPpxjHEiqvNDknH7qs+YBnis0eH7DHJgEjXq651PjW7pm+rnHPwsj+OzKE1YBNxBQZZDkS3VnZJz+O4tVsOzc3IOz0e+lf7VVuI17C9haj117nKp3umC4MVBA0S8RfreFgqpyDeY2zwcqOr0YOlEGGRl0vyWP8Qcxx12kQ7+doLolt6Kxda4uO0hKRmIF6+qki1T+L7v8BOGOtCncz4f7IX48eQ7+Wu0OtglRn45qAa3CxjUuW6xX3KSNH66PCXV0Jtp8Ga2SSevX2wtbbFu9f+9R+PQY4="
 
 notifications:
   email:
     on_success: never
-os:
-  - linux
-  - osx
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/CHANGELOG.md
@@ -0,0 +1,289 @@
+# 0.1.17 - 2017-10-31
+
+* Add a `close` method on `sink::Wait`
+* Undeprecate `stream::iter` as `stream::iter_result`
+* Improve performance of wait-related methods
+* Tweak buffered sinks with a 0 capacity to forward directly to the underlying
+  sink.
+* Add `FromIterator` implementation for `FuturesOrdered` and `FuturesUnordered`.
+
+# 0.1.16 - 2017-09-15
+
+* A `prelude` module has been added to glob import from and pick up a whole
+  bunch of useful types
+* `sync::mpsc::Sender::poll_ready` has been added as an API
+* `sync::mpsc::Sender::try_send` has been added as an API
+
+# 0.1.15 - 2017-08-24
+
+* Improve performance of `BiLock` methods
+* Implement `Clone` for `FutureResult`
+* Forward `Stream` trait through `SinkMapErr`
+* Add `stream::futures_ordered` next to `futures_unordered`
+* Reimplement `Stream::buffered` on top of `stream::futures_ordered` (much more
+  efficient at scale).
+* Add a `with_notify` function for abstractions which previously required
+  `UnparkEvent`.
+* Add `get_ref`/`get_mut`/`into_inner` functions for stream take/skip methods
+* Add a `Clone` implementation for `SharedItem` and `SharedError`
+* Add a `mpsc::spawn` function to spawn a `Stream` into an `Executor`
+* Add a `reunite` function for `BiLock` and the split stream/sink types to
+  rejoin two halves and reclaim the original item.
+* Add `stream::poll_fn` to behave similarly to `future::poll_fn`
+* Add `Sink::with_flat_map` like `Iterator::flat_map`
+* Bump the minimum Rust version to 1.13.0
+* Expose `AtomicTask` in the public API for managing synchronization around task
+  notifications.
+* Unify the `Canceled` type of the `sync` and `unsync` modules.
+* Deprecate the `boxed` methods. These methods have caused more confusion than
+  they've solved historically, so it's recommended to use a local extension
+  trait or a local helper instead of the trait-based methods.
+* Deprecate the `Stream::merge` method as it's less ergonomic than `select`.
+* Add `oneshot::Sender::is_canceled` to test if a oneshot is canceled off a
+  task.
+* Deprecates `UnboundedSender::send` in favor of a method named `unbounded_send`
+  to avoid a conflict with `Sink::send`.
+* Deprecate the `stream::iter` function in favor of an `stream::iter_ok` adaptor
+  to avoid the need to deal with `Result` manually.
+* Add an `inspect` function to the `Future` and `Stream` traits along the lines
+  of `Iterator::inspect`
+
+# 0.1.14 - 2017-05-30
+
+This is a relatively large release of the `futures` crate, although much of it
+is from reworking internals rather than new APIs. The banner feature of this
+release is that the `futures::{task, executor}` modules are now available in
+`no_std` contexts! A large refactoring of the task system was performed in
+PR #436 to accommodate custom memory allocation schemes and otherwise remove
+all dependencies on `std` for the task module. More details about this change
+can be found on the PR itself.
+
+Other API additions in this release are:
+
+* A `FuturesUnordered::push` method was added and the `FuturesUnordered` type
+  itself was completely rewritten to efficiently track a large number of
+  futures.
+* A `Task::will_notify_current` method was added with a slightly different
+  implementation than `Task::is_current` but with stronger guarantees and
+  documentation wording about its purpose.
+* Many combinators now have `get_ref`, `get_mut`, and `into_inner` methods for
+  accessing internal futures and state.
+* A `Stream::concat2` method was added which should be considered the "fixed"
+  version of `concat`, this one doesn't panic on empty streams.
+* An `Executor` trait has been added to represent abstracting over the concept
+  of spawning a new task. Crates which only need the ability to spawn a future
+  can now be generic over `Executor` rather than requiring a
+  `tokio_core::reactor::Handle`.
+
+As with all 0.1.x releases this PR is intended to be 100% backwards compatible.
+All code that previously compiled should continue to do so with these changes.
+As with other changes, though, there are also some updates to be aware of:
+
+* The `task::park` function has been renamed to `task::current`.
+* The `Task::unpark` function has been renamed to `Task::notify`, and in general
+  terminology around "unpark" has shifted to terminology around "notify"
+* The `Unpark` trait has been deprecated in favor of the `Notify` trait
+  mentioned above.
+* The `UnparkEvent` structure has been deprecated. It currently should perform
+  the same as it used to, but it's planned that in a future 0.1.x release the
+  performance will regress for crates that have not transitioned away. The
+  primary primitive to replace this is the addition of a `push` function on the
+  `FuturesUnordered` type. If this does not help implement your use case though,
+  please let us know!
+* The `Task::is_current` method is now deprecated, and you likely want to use
+  `Task::will_notify_current` instead, but let us know if this doesn't suffice!
+
+# 0.1.13 - 2017-04-05
+
+* Add forwarding sink/stream impls for `stream::FromErr` and `sink::SinkFromErr`
+* Add `PartialEq` and `Eq` to `mpsc::SendError`
+* Reimplement `Shared` with `spawn` instead of `UnparkEvent`
+
+# 0.1.12 - 2017-04-03
+
+* Add `Stream::from_err` and `Sink::from_err`
+* Allow `SendError` to be `Clone` when possible
+
+# 0.1.11 - 2017-03-13
+
+The major highlight of this release is the addition of a new "default" method on
+the `Sink` trait, `Sink::close`. This method is used to indicate to a sink that
+no new values will ever need to get pushed into it. This can be used to
+implement graceful shutdown of protocols and otherwise simply indicates to a
+sink that it can start freeing up resources.
+
+Currently this method is **not** a default method to preserve backwards
+compatibility, but it's intended to become a default method in the 0.2 series of
+the `futures` crate. It's highly recommended to audit implementations of `Sink`
+to implement the `close` method as is fit.
+
+Other changes in this release are:
+
+* A new select combinator, `Future::select2` was added for a heterogeneous
+  select.
+* A `Shared::peek` method was added to check to see if it's done.
+* `Sink::map_err` was implemented
+* The `log` dependency was removed
+* Implementations of the `Debug` trait are now generally available.
+* The `stream::IterStream` type was renamed to `stream::Iter` (with a reexport
+  for the old name).
+* Add a `Sink::wait` method which returns an adapter to use an arbitrary `Sink`
+  synchronously.
+* A `Stream::concat` method was added to concatenate a sequence of lists.
+* The `oneshot::Sender::complete` method was renamed to `send` and now returns a
+  `Result` indicating successful transmission of a message or not. Note that the
+  `complete` method still exists, it's just deprecated.
+
+# 0.1.10 - 2017-01-30
+
+* Add a new `unsync` module which mirrors `sync` to the extent that it can but
+  is intended to not perform cross-thread synchronization (only usable within
+  one thread).
+* Tweak `Shared` to work when handles may not get poll'd again.
+
+# 0.1.9 - 2017-01-18
+
+* Fix `Send/Sync` of a few types
+* Add `future::tail_fn` for more easily writing loops
+* Export SharedItem/SharedError
+* Remove an unused type parameter in `from_err`
+
+# 0.1.8 - 2017-01-11
+
+* Fix some race conditions in the `Shared` implementation
+* Add `Stream::take_while`
+* Fix an unwrap in `stream::futures_unordered`
+* Generalize `Stream::for_each`
+* Add `Stream::chain`
+* Add `stream::repeat`
+* Relax `&mut self` to `&self` in `UnboundedSender::send`
+
+# 0.1.7 - 2016-12-18
+
+* Add a `Future::shared` method for creating a future that can be shared
+  amongst threads by cloning the future itself. All derivative futures
+  will resolve to the same value once the original future has been
+  resolved.
+* Add a `FutureFrom` trait for future-based conversion
+* Fix a wakeup bug in `Receiver::close`
+* Add `future::poll_fn` for quickly adapting a `Poll`-based function to
+  a future.
+* Add an `Either` enum with two branches to easily create one future
+  type based on two different futures created on two branches of control
+  flow.
+* Remove the `'static` bound on `Unpark`
+* Optimize `send_all` and `forward` to send as many items as possible
+  before calling `poll_complete`.
+* Unify the return types of the `ok`, `err`, and `result` future to
+  assist returning different varieties in different branches of a function.
+* Add `CpuFuture::forget` to allow the computation to continue running
+  after a drop.
+* Add a `stream::futures_unordered` combinator to turn a list of futures
+  into a stream representing their order of completion.
+
+# 0.1.6 - 2016-11-22
+
+* Fix `Clone` bound on the type parameter on `UnboundedSender`
+
+# 0.1.5 - 2016-11-22
+
+* Fix `#![no_std]` support
+
+# 0.1.4 - 2016-11-22
+
+This is quite a large release relative to the previous point releases! As
+with all 0.1 releases, this release should be fully compatible with the 0.1.3
+release. If any incompatibilities are discovered please file an issue!
+
+The largest changes in 0.1.4 are the addition of a `Sink` trait coupled with a
+reorganization of this crate. Note that all old locations for types/traits
+still exist, they're just deprecated and tagged with `#[doc(hidden)]`.
+
+The new `Sink` trait is used to represent types which can periodically over
+time accept items, but may take some time to fully process the item before
+another can be accepted. Essentially, a sink is the opposite of a stream. This
+trait will then be used in the tokio-core crate to implement simple framing by
+modeling I/O streams as both a stream and a sink of frames.
+
+The organization of this crate is to now have three primary submodules,
+`future`, `stream`, and `sink`. The traits as well as all combinator types are
+defined in these submodules. The traits and types like `Async` and `Poll` are
+then reexported at the top of the crate for convenient usage. It should be a
+relatively rare occasion that the modules themselves are reached into.
+
+Finally, the 0.1.4 release comes with a new module, `sync`, in the futures
+crate.  This is intended to be the home of a suite of futures-aware
+synchronization primitives. Currently this is inhabited with a `oneshot` module
+(the old `oneshot` function), a `mpsc` module for a new multi-producer
+single-consumer channel, and a `BiLock` type which represents sharing ownership
+of one value between two consumers. This module may expand over time with more
+types like a mutex, rwlock, spsc channel, etc.
+
+Notable deprecations in the 0.1.4 release that will be deleted in an eventual
+0.2 release:
+
+* The `TaskRc` type is now deprecated in favor of `BiLock` or otherwise `Arc`
+  sharing.
+* All future combinators should be accessed through the `future` module, not
+  the top-level of the crate.
+* The `Oneshot` and `Complete` types are now replaced with the `sync::oneshot`
+  module.
+* Some old names like `collect` are deprecated in favor of more appropriately
+  named versions like `join_all`
+* The `finished` constructor is now `ok`.
+* The `failed` constructor is now `err`.
+* The `done` constructor is now `result`.
+
+As always, please report bugs to https://github.com/alexcrichton/futures-rs and
+we always love feedback! If you've got situations we don't cover, combinators
+you'd like to see, or slow code, please let us know!
+
+Full changelog:
+
+* Improve scalability of `buffer_unordered` combinator
+* Fix a memory ordering bug in oneshot
+* Add a new trait, `Sink`
+* Reorganize the crate into three primary modules
+* Add a new `sync` module for synchronization primitives
+* Add a `BiLock` sync primitive for two-way sharing
+* Deprecate `TaskRc`
+* Rename `collect` to `join_all`
+* Use a small vec in `Events` for improved clone performance
+* Add `Stream::select` for selecting items from two streams like `merge` but
+  requiring the same types.
+* Add `stream::unfold` constructor
+* Add a `sync::mpsc` module with a futures-aware multi-producer single-consumer
+  queue. Both bounded (with backpressure) and unbounded (no backpressure)
+  variants are provided.
+* Renamed `failed`, `finished`, and `done` combinators to `err`, `ok`, and
+  `result`.
+* Add `Stream::forward` to send all items to a sink, like `Sink::send_all`
+* Add `Stream::split` for streams which are both sinks and streams to have
+  separate ownership of the stream/sink halves
+* Improve `join_all` with concurrency
+
+# 0.1.3 - 2016-10-24
+
+* Rewrite `oneshot` for efficiency and removing allocations on send/recv
+* Errors are passed through in `Stream::take` and `Stream::skip`
+* Add a `select_ok` combinator to pick the first of a list that succeeds
+* Remove the unnecessary `SelectAllNext` typedef
+* Add `Stream::chunks` for receiving chunks of data
+* Rewrite `stream::channel` for efficiency, correctness, and removing
+  allocations
+* Remove `Send + 'static` bounds on the `stream::Empty` type
+
+# 0.1.2 - 2016-10-04
+
+* Fixed a bug in drop of `FutureSender`
+* Expose the channel `SendError` type
+* Add `Future::into_stream` to convert to a single-element stream
+* Add `Future::flatten_to_stream` to convert a future of a stream to a stream
+* impl Debug for SendError
+* Add stream::once for a one element stream
+* Accept IntoIterator in stream::iter
+* Add `Stream::catch_unwind`
+
+# 0.1.1 - 2016-09-09
+
+Initial release!
--- a/third_party/rust/futures/Cargo.toml
+++ b/third_party/rust/futures/Cargo.toml
@@ -1,29 +1,36 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
 [package]
 name = "futures"
-version = "0.1.13"
+version = "0.1.18"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = "MIT/Apache-2.0"
-readme = "README.md"
-keywords = ["futures", "async", "future"]
-repository = "https://github.com/alexcrichton/futures-rs"
+description = "An implementation of futures and streams featuring zero allocations,\ncomposability, and iterator-like interfaces.\n"
 homepage = "https://github.com/alexcrichton/futures-rs"
 documentation = "https://docs.rs/futures"
-description = """
-An implementation of futures and streams featuring zero allocations,
-composability, and iterator-like interfaces.
-"""
+readme = "README.md"
+keywords = ["futures", "async", "future"]
 categories = ["asynchronous"]
-
-[badges]
-travis-ci = { repository = "alexcrichton/futures-rs" }
-appveyor = { repository = "alexcrichton/futures-rs" }
+license = "MIT/Apache-2.0"
+repository = "https://github.com/alexcrichton/futures-rs"
 
 [dependencies]
 
 [features]
+default = ["use_std", "with-deprecated"]
 use_std = []
 with-deprecated = []
-default = ["use_std", "with-deprecated"]
+[badges.appveyor]
+repository = "alexcrichton/futures-rs"
 
-[workspace]
-members = ["futures-cpupool"]
+[badges.travis-ci]
+repository = "alexcrichton/futures-rs"
deleted file mode 100644
--- a/third_party/rust/futures/FAQ.md
+++ /dev/null
@@ -1,99 +0,0 @@
-# FAQ
-
-A collection of some commonly asked questions, with responses! If you find any
-of these unsatisfactory feel free to ping me (@alexcrichton) on github,
-acrichto on IRC, or just by email!
-
-### Why both `Item` and `Error` associated types?
-
-An alternative design of the `Future` trait would be to only have one associated
-type, `Item`, and then most futures would resolve to `Result<T, E>`. The
-intention of futures, the fundamental support for async I/O, typically means
-that errors will be encoded in almost all futures anyway though. By encoding an
-error type in the future as well we're able to provide convenient combinators
-like `and_then` which automatically propagate errors, as well as combinators
-like `join` which can act differently depending on whether a future resolves to
-an error or not.
-
-### Do futures work with multiple event loops?
-
-Yes! Futures are designed to source events from any location, including multiple
-event loops. All of the basic combinators will work on any number of event loops
-across any number of threads.
-
-### What if I have CPU intensive work?
-
-The documentation of the `Future::poll` function says that's it's supposed to
-"return quickly", what if I have work that doesn't return quickly! In this case
-it's intended that this work will run on a dedicated pool of threads intended
-for this sort of work, and a future to the returned value is used to represent
-its completion.
-
-A proof-of-concept method of doing this is the `futures-cpupool` crate in this
-repository, where you can execute work on a thread pool and receive a future to
-the value generated. This future is then composable with `and_then`, for
-example, to mesh in with the rest of a future's computation.
-
-### How do I call `poll`?
-
-In general it's not recommended to call `poll` unless you're implementing
-another `poll` function. If you need to poll a future, however, you can use
-`task::spawn` followed by the `poll_future` method on `Spawn<T>`.
-
-### How do I return a future?
-
-Returning a future is like returning an iterator in Rust today. It's not the
-easiest thing to do and you frequently need to resort to `Box` with a trait
-object. Thankfully though [`impl Trait`] is just around the corner and will
-allow returning these types unboxed in the future.
-
-[`impl Trait`]: https://github.com/rust-lang/rust/issues/34511
-
-For now though the cost of boxing shouldn't actually be that high. A future
-computation can be constructed *without boxing* and only the final step actually
-places a `Box` around the entire future. In that sense you're only paying the
-allocation at the very end, not for any of the intermediate futures.
-
-More information can be found [in the tutorial][return-future].
-
-[return-future]: https://github.com/alexcrichton/futures-rs/blob/master/TUTORIAL.md#returning-futures
-
-### Does it work on Windows?
-
-Yes! This library builds on top of mio, which works on Windows.
-
-### What version of Rust should I use?
-
-Rust 1.10 or later.
-
-### Is it on crates.io?
-
-Not yet! A few names are reserved, but crates cannot have dependencies from a
-git repository. Right now we depend on the master branch of `mio`, and crates
-will be published once that's on crates.io as well!
-
-### Does this implement tail call optimization?
-
-One aspect of many existing futures libraries is whether or not a tail call
-optimization is implemented. The exact meaning of this varies from framework to
-framework, but it typically boils down to whether common patterns can be
-implemented in such a way that prevents blowing the stack if the system is
-overloaded for a moment or leaking memory for the entire lifetime of a
-future/server.
-
-For the prior case, blowing the stack, this typically arises as loops are often
-implemented through recursion with futures. This recursion can end up proceeding
-too quickly if the "loop" makes lots of turns very quickly. At this time neither
-the `Future` nor `Stream` traits handle tail call optimizations in this case,
-but rather combinators are patterns are provided to avoid recursion. For example
-a `Stream` implements `fold`, `for_each`, etc. These combinators can often be
-used to implement an asynchronous loop to avoid recursion, and they all execute
-in constant stack space. Note that we're very interested in exploring more
-generalized loop combinators, so PRs are always welcome!
-
-For the latter case, leaking memory, this can happen where a future accidentally
-"remembers" all of its previous states when it'll never use them again. This
-also can arise through recursion or otherwise manufacturing of futures of
-infinite length. Like above, however, these also tend to show up in situations
-that would otherwise be expressed with a loop, so the same solutions should
-apply there regardless.
--- a/third_party/rust/futures/README.md
+++ b/third_party/rust/futures/README.md
@@ -11,17 +11,17 @@ This library is an implementation of **z
 [Tutorial](https://tokio.rs/docs/getting-started/futures/)
 
 ## Usage
 
 First, add this to your `Cargo.toml`:
 
 ```toml
 [dependencies]
-futures = "0.1.9"
+futures = "0.1.17"
 ```
 
 Next, add this to your crate:
 
 ```rust
 extern crate futures;
 
 use futures::Future;
@@ -34,18 +34,27 @@ the Tokio stack and also futures.
 ### Feature `use_std`
 
 `futures-rs` works without the standard library, such as in bare metal environments.
 However, it has a significantly reduced API surface. To use `futures-rs` in
 a `#[no_std]` environment, use:
 
 ```toml
 [dependencies]
-futures = { version = "0.1", default-features = false }
+futures = { version = "0.1.17", default-features = false }
 ```
 
 # License
 
-`futures-rs` is primarily distributed under the terms of both the MIT license and
-the Apache License (Version 2.0), with portions covered by various BSD-like
-licenses.
+This project is licensed under either of
+
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
+   http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or
+   http://opensource.org/licenses/MIT)
 
-See LICENSE-APACHE, and LICENSE-MIT for details.
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Futures by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
--- a/third_party/rust/futures/appveyor.yml
+++ b/third_party/rust/futures/appveyor.yml
@@ -1,9 +1,29 @@
 environment:
+
+  # At the time this was added AppVeyor was having troubles with checking
+  # revocation of SSL certificates of sites like static.rust-lang.org and what
+  # we think is crates.io. The libcurl HTTP client by default checks for
+  # revocation on Windows and according to a mailing list [1] this can be
+  # disabled.
+  #
+  # The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL
+  # revocation checking on Windows in libcurl. Note, though, that rustup, which
+  # we're using to download Rust here, also uses libcurl as the default backend.
+  # Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation
+  # checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to
+  # use the Hyper instead of libcurl backend. Both Hyper and libcurl use
+  # schannel on Windows but it appears that Hyper configures it slightly
+  # differently such that revocation checking isn't turned on by default.
+  #
+  # [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html
+  RUSTUP_USE_HYPER: 1
+  CARGO_HTTP_CHECK_REVOKE: false
+
   matrix:
   - TARGET: x86_64-pc-windows-msvc
 install:
   - set PATH=C:\Program Files\Git\mingw64\bin;%PATH%
   - curl -sSf -o rustup-init.exe https://win.rustup.rs/
   - rustup-init.exe -y --default-host %TARGET%
   - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
   - rustc -V
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/benches/bilock.rs
@@ -0,0 +1,121 @@
+#![feature(test)]
+
+extern crate futures;
+extern crate test;
+
+use futures::{Async, Poll};
+use futures::executor;
+use futures::executor::{Notify, NotifyHandle};
+use futures::sync::BiLock;
+use futures::sync::BiLockAcquire;
+use futures::sync::BiLockAcquired;
+use futures::future::Future;
+use futures::stream::Stream;
+
+
+use test::Bencher;
+
+fn notify_noop() -> NotifyHandle {
+    struct Noop;
+
+    impl Notify for Noop {
+        fn notify(&self, _id: usize) {}
+    }
+
+    const NOOP : &'static Noop = &Noop;
+
+    NotifyHandle::from(NOOP)
+}
+
+
+/// Pseudo-stream which simply calls `lock.poll()` on `poll`
+struct LockStream {
+    lock: BiLockAcquire<u32>,
+}
+
+impl LockStream {
+    fn new(lock: BiLock<u32>) -> LockStream {
+        LockStream {
+            lock: lock.lock()
+        }
+    }
+
+    /// Release a lock after it was acquired in `poll`,
+    /// so `poll` could be called again.
+    fn release_lock(&mut self, guard: BiLockAcquired<u32>) {
+        self.lock = guard.unlock().lock()
+    }
+}
+
+impl Stream for LockStream {
+    type Item = BiLockAcquired<u32>;
+    type Error = ();
+
+    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
+        self.lock.poll().map(|a| match a {
+            Async::Ready(a) => Async::Ready(Some(a)),
+            Async::NotReady => Async::NotReady,
+        })
+    }
+}
+
+
+#[bench]
+fn contended(b: &mut Bencher) {
+    b.iter(|| {
+        let (x, y) = BiLock::new(1);
+
+        let mut x = executor::spawn(LockStream::new(x));
+        let mut y = executor::spawn(LockStream::new(y));
+
+        for _ in 0..1000 {
+            let x_guard = match x.poll_stream_notify(&notify_noop(), 11) {
+                Ok(Async::Ready(Some(guard))) => guard,
+                _ => panic!(),
+            };
+
+            // Try poll second lock while first lock still holds the lock
+            match y.poll_stream_notify(&notify_noop(), 11) {
+                Ok(Async::NotReady) => (),
+                _ => panic!(),
+            };
+
+            x.get_mut().release_lock(x_guard);
+
+            let y_guard = match y.poll_stream_notify(&notify_noop(), 11) {
+                Ok(Async::Ready(Some(guard))) => guard,
+                _ => panic!(),
+            };
+
+            y.get_mut().release_lock(y_guard);
+        }
+        (x, y)
+    });
+}
+
+#[bench]
+fn lock_unlock(b: &mut Bencher) {
+    b.iter(|| {
+        let (x, y) = BiLock::new(1);
+
+        let mut x = executor::spawn(LockStream::new(x));
+        let mut y = executor::spawn(LockStream::new(y));
+
+        for _ in 0..1000 {
+            let x_guard = match x.poll_stream_notify(&notify_noop(), 11) {
+                Ok(Async::Ready(Some(guard))) => guard,
+                _ => panic!(),
+            };
+
+            x.get_mut().release_lock(x_guard);
+
+            let y_guard = match y.poll_stream_notify(&notify_noop(), 11) {
+                Ok(Async::Ready(Some(guard))) => guard,
+                _ => panic!(),
+            };
+
+            y.get_mut().release_lock(y_guard);
+        }
+        (x, y)
+    })
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/benches/futures_unordered.rs
@@ -0,0 +1,43 @@
+#![feature(test)]
+
+extern crate futures;
+extern crate test;
+
+use futures::*;
+use futures::stream::FuturesUnordered;
+use futures::sync::oneshot;
+
+use test::Bencher;
+
+use std::collections::VecDeque;
+use std::thread;
+
+#[bench]
+fn oneshots(b: &mut Bencher) {
+    const NUM: usize = 10_000;
+
+    b.iter(|| {
+        let mut txs = VecDeque::with_capacity(NUM);
+        let mut rxs = FuturesUnordered::new();
+
+        for _ in 0..NUM {
+            let (tx, rx) = oneshot::channel();
+            txs.push_back(tx);
+            rxs.push(rx);
+        }
+
+        thread::spawn(move || {
+            while let Some(tx) = txs.pop_front() {
+                let _ = tx.send("hello");
+            }
+        });
+
+        future::lazy(move || {
+            loop {
+                if let Ok(Async::Ready(None)) = rxs.poll() {
+                    return Ok::<(), ()>(());
+                }
+            }
+        }).wait().unwrap();
+    });
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/benches/poll.rs
@@ -0,0 +1,72 @@
+#![feature(test)]
+
+extern crate futures;
+extern crate test;
+
+use futures::*;
+use futures::executor::{Notify, NotifyHandle};
+use futures::task::Task;
+
+use test::Bencher;
+
+fn notify_noop() -> NotifyHandle {
+    struct Noop;
+
+    impl Notify for Noop {
+        fn notify(&self, _id: usize) {}
+    }
+
+    const NOOP : &'static Noop = &Noop;
+
+    NotifyHandle::from(NOOP)
+}
+
+#[bench]
+fn task_init(b: &mut Bencher) {
+    const NUM: u32 = 100_000;
+
+    struct MyFuture {
+        num: u32,
+        task: Option<Task>,
+    };
+
+    impl Future for MyFuture {
+        type Item = ();
+        type Error = ();
+
+        fn poll(&mut self) -> Poll<(), ()> {
+            if self.num == NUM {
+                Ok(Async::Ready(()))
+            } else {
+                self.num += 1;
+
+                if let Some(ref t) = self.task {
+                    if t.will_notify_current() {
+                        t.notify();
+                        return Ok(Async::NotReady);
+                    }
+                }
+
+                let t = task::current();
+                t.notify();
+                self.task = Some(t);
+
+                Ok(Async::NotReady)
+            }
+        }
+    }
+
+    let notify = notify_noop();
+
+    let mut fut = executor::spawn(MyFuture {
+        num: 0,
+        task: None,
+    });
+
+    b.iter(|| {
+        fut.get_mut().num = 0;
+
+        while let Ok(Async::NotReady) = fut.poll_future_notify(&notify, 0) {
+        }
+    });
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/benches/sync_mpsc.rs
@@ -0,0 +1,168 @@
+#![feature(test)]
+
+extern crate futures;
+extern crate test;
+
+use futures::{Async, Poll, AsyncSink};
+use futures::executor;
+use futures::executor::{Notify, NotifyHandle};
+
+use futures::sink::Sink;
+use futures::stream::Stream;
+
+use futures::sync::mpsc::unbounded;
+use futures::sync::mpsc::channel;
+use futures::sync::mpsc::Sender;
+use futures::sync::mpsc::UnboundedSender;
+
+
+use test::Bencher;
+
+fn notify_noop() -> NotifyHandle {
+    struct Noop;
+
+    impl Notify for Noop {
+        fn notify(&self, _id: usize) {}
+    }
+
+    const NOOP : &'static Noop = &Noop;
+
+    NotifyHandle::from(NOOP)
+}
+
+/// Single producer, single consumer
+#[bench]
+fn unbounded_1_tx(b: &mut Bencher) {
+    b.iter(|| {
+        let (tx, rx) = unbounded();
+
+        let mut rx = executor::spawn(rx);
+
+        // 1000 iterations to avoid measuring overhead of initialization
+        // Result should be divided by 1000
+        for i in 0..1000 {
+
+            // Poll, not ready, park
+            assert_eq!(Ok(Async::NotReady), rx.poll_stream_notify(&notify_noop(), 1));
+
+            UnboundedSender::unbounded_send(&tx, i).unwrap();
+
+            // Now poll ready
+            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll_stream_notify(&notify_noop(), 1));
+        }
+    })
+}
+
+/// 100 producers, single consumer
+#[bench]
+fn unbounded_100_tx(b: &mut Bencher) {
+    b.iter(|| {
+        let (tx, rx) = unbounded();
+
+        let mut rx = executor::spawn(rx);
+
+        let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect();
+
+        // 1000 send/recv operations total, result should be divided by 1000
+        for _ in 0..10 {
+            for i in 0..tx.len() {
+                assert_eq!(Ok(Async::NotReady), rx.poll_stream_notify(&notify_noop(), 1));
+
+                UnboundedSender::unbounded_send(&tx[i], i).unwrap();
+
+                assert_eq!(Ok(Async::Ready(Some(i))), rx.poll_stream_notify(&notify_noop(), 1));
+            }
+        }
+    })
+}
+
+#[bench]
+fn unbounded_uncontended(b: &mut Bencher) {
+    b.iter(|| {
+        let (tx, mut rx) = unbounded();
+
+        for i in 0..1000 {
+            UnboundedSender::unbounded_send(&tx, i).expect("send");
+            // No need to create a task, because poll is not going to park.
+            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll());
+        }
+    })
+}
+
+
+/// A Stream that continuously sends incrementing number of the queue
+struct TestSender {
+    tx: Sender<u32>,
+    last: u32, // Last number sent
+}
+
+// Could be a Future, it doesn't matter
+impl Stream for TestSender {
+    type Item = u32;
+    type Error = ();
+
+    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
+        match self.tx.start_send(self.last + 1) {
+            Err(_) => panic!(),
+            Ok(AsyncSink::Ready) => {
+                self.last += 1;
+                assert_eq!(Ok(Async::Ready(())), self.tx.poll_complete());
+                Ok(Async::Ready(Some(self.last)))
+            }
+            Ok(AsyncSink::NotReady(_)) => {
+                Ok(Async::NotReady)
+            }
+        }
+    }
+}
+
+
+/// Single producers, single consumer
+#[bench]
+fn bounded_1_tx(b: &mut Bencher) {
+    b.iter(|| {
+        let (tx, rx) = channel(0);
+
+        let mut tx = executor::spawn(TestSender {
+            tx: tx,
+            last: 0,
+        });
+
+        let mut rx = executor::spawn(rx);
+
+        for i in 0..1000 {
+            assert_eq!(Ok(Async::Ready(Some(i + 1))), tx.poll_stream_notify(&notify_noop(), 1));
+            assert_eq!(Ok(Async::NotReady), tx.poll_stream_notify(&notify_noop(), 1));
+            assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll_stream_notify(&notify_noop(), 1));
+        }
+    })
+}
+
+/// 100 producers, single consumer
+#[bench]
+fn bounded_100_tx(b: &mut Bencher) {
+    b.iter(|| {
+        // Each sender can send one item after specified capacity
+        let (tx, rx) = channel(0);
+
+        let mut tx: Vec<_> = (0..100).map(|_| {
+            executor::spawn(TestSender {
+                tx: tx.clone(),
+                last: 0
+            })
+        }).collect();
+
+        let mut rx = executor::spawn(rx);
+
+        for i in 0..10 {
+            for j in 0..tx.len() {
+                // Send an item
+                assert_eq!(Ok(Async::Ready(Some(i + 1))), tx[j].poll_stream_notify(&notify_noop(), 1));
+                // Then block
+                assert_eq!(Ok(Async::NotReady), tx[j].poll_stream_notify(&notify_noop(), 1));
+                // Recv the item
+                assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll_stream_notify(&notify_noop(), 1));
+            }
+        }
+    })
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/benches/thread_notify.rs
@@ -0,0 +1,114 @@
+#![feature(test)]
+
+extern crate futures;
+extern crate test;
+
+use futures::{Future, Poll, Async};
+use futures::task::{self, Task};
+
+use test::Bencher;
+
+#[bench]
+fn thread_yield_single_thread_one_wait(b: &mut Bencher) {
+    const NUM: usize = 10_000;
+
+    struct Yield {
+        rem: usize,
+    }
+
+    impl Future for Yield {
+        type Item = ();
+        type Error = ();
+
+        fn poll(&mut self) -> Poll<(), ()> {
+            if self.rem == 0 {
+                Ok(Async::Ready(()))
+            } else {
+                self.rem -= 1;
+                task::current().notify();
+                Ok(Async::NotReady)
+            }
+        }
+    }
+
+    b.iter(|| {
+        let y = Yield { rem: NUM };
+        y.wait().unwrap();
+    });
+}
+
+#[bench]
+fn thread_yield_single_thread_many_wait(b: &mut Bencher) {
+    const NUM: usize = 10_000;
+
+    struct Yield {
+        rem: usize,
+    }
+
+    impl Future for Yield {
+        type Item = ();
+        type Error = ();
+
+        fn poll(&mut self) -> Poll<(), ()> {
+            if self.rem == 0 {
+                Ok(Async::Ready(()))
+            } else {
+                self.rem -= 1;
+                task::current().notify();
+                Ok(Async::NotReady)
+            }
+        }
+    }
+
+    b.iter(|| {
+        for _ in 0..NUM {
+            let y = Yield { rem: 1 };
+            y.wait().unwrap();
+        }
+    });
+}
+
+#[bench]
+fn thread_yield_multi_thread(b: &mut Bencher) {
+    use std::sync::mpsc;
+    use std::thread;
+
+    const NUM: usize = 1_000;
+
+    let (tx, rx) = mpsc::sync_channel::<Task>(10_000);
+
+    struct Yield {
+        rem: usize,
+        tx: mpsc::SyncSender<Task>,
+    }
+
+    impl Future for Yield {
+        type Item = ();
+        type Error = ();
+
+        fn poll(&mut self) -> Poll<(), ()> {
+            if self.rem == 0 {
+                Ok(Async::Ready(()))
+            } else {
+                self.rem -= 1;
+                self.tx.send(task::current()).unwrap();
+                Ok(Async::NotReady)
+            }
+        }
+    }
+
+    thread::spawn(move || {
+        while let Ok(task) = rx.recv() {
+            task.notify();
+        }
+    });
+
+    b.iter(move || {
+        let y = Yield {
+            rem: NUM,
+            tx: tx.clone(),
+        };
+
+        y.wait().unwrap();
+    });
+}
--- a/third_party/rust/futures/src/executor.rs
+++ b/third_party/rust/futures/src/executor.rs
@@ -1,10 +1,16 @@
 //! Executors
 //!
 //! This module contains tools for managing the raw execution of futures,
 //! which is needed when building *executors* (places where futures can run).
 //!
 //! More information about executors can be [found online at tokio.rs][online].
 //!
-//! [online]: https://tokio.rs/docs/going-deeper/tasks/
+//! [online]: https://tokio.rs/docs/going-deeper-futures/tasks/
 
-pub use task_impl::{Spawn, spawn, Unpark, Executor, Run};
+#[allow(deprecated)]
+#[cfg(feature = "use_std")]
+pub use task_impl::{Unpark, Executor, Run};
+
+pub use task_impl::{Spawn, spawn, Notify, with_notify};
+
+pub use task_impl::{UnsafeNotify, NotifyHandle};
--- a/third_party/rust/futures/src/future/catch_unwind.rs
+++ b/third_party/rust/futures/src/future/catch_unwind.rs
@@ -24,17 +24,17 @@ pub fn new<F>(future: F) -> CatchUnwind<
 impl<F> Future for CatchUnwind<F>
     where F: Future + UnwindSafe,
 {
     type Item = Result<F::Item, F::Error>;
     type Error = Box<Any + Send>;
 
     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
         let mut future = self.future.take().expect("cannot poll twice");
-        let (res, future) = try!(catch_unwind(|| (future.poll(), future)));
+        let (res, future) = catch_unwind(|| (future.poll(), future))?;
         match res {
             Ok(Async::NotReady) => {
                 self.future = Some(future);
                 Ok(Async::NotReady)
             }
             Ok(Async::Ready(t)) => Ok(Async::Ready(Ok(t))),
             Err(e) => Ok(Async::Ready(Err(e))),
         }
--- a/third_party/rust/futures/src/future/chain.rs
+++ b/third_party/rust/futures/src/future/chain.rs
@@ -31,17 +31,17 @@ impl<A, B, C> Chain<A, B, C>
             }
             Chain::Second(ref mut b) => return b.poll(),
             Chain::Done => panic!("cannot poll a chained future twice"),
         };
         let data = match mem::replace(self, Chain::Done) {
             Chain::First(_, c) => c,
             _ => panic!(),
         };
-        match try!(f(a_result, data)) {
+        match f(a_result, data)? {
             Ok(e) => Ok(Async::Ready(e)),
             Err(mut b) => {
                 let ret = b.poll();
                 *self = Chain::Second(b);
                 ret
             }
         }
     }
--- a/third_party/rust/futures/src/future/either.rs
+++ b/third_party/rust/futures/src/future/either.rs
@@ -6,26 +6,26 @@ use {Future, Poll};
 pub enum Either<A, B> {
     /// First branch of the type
     A(A),
     /// Second branch of the type
     B(B),
 }
 
 impl<T, A, B> Either<(T, A), (T, B)> {
-    /// Splits out the homogenous type from an either of tuples.
+    /// Splits out the homogeneous type from an either of tuples.
     ///
     /// This method is typically useful when combined with the `Future::select2`
     /// combinator.
     pub fn split(self) -> (T, Either<A, B>) {
         match self {
             Either::A((a, b)) => (a, Either::A(b)),
             Either::B((a, b)) => (a, Either::B(b)),
         }
-	}
+    }
 }
 
 impl<A, B> Future for Either<A, B>
     where A: Future,
           B: Future<Item = A::Item, Error = A::Error>
 {
     type Item = A::Item;
     type Error = A::Error;
--- a/third_party/rust/futures/src/future/flatten.rs
+++ b/third_party/rust/futures/src/future/flatten.rs
@@ -37,13 +37,13 @@ impl<A> Future for Flatten<A>
           A::Item: IntoFuture,
           <<A as Future>::Item as IntoFuture>::Error: From<<A as Future>::Error>
 {
     type Item = <<A as Future>::Item as IntoFuture>::Item;
     type Error = <<A as Future>::Item as IntoFuture>::Error;
 
     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
         self.state.poll(|a, ()| {
-            let future = try!(a).into_future();
+            let future = a?.into_future();
             Ok(Err(future))
         })
     }
 }
new file mode 100644
--- /dev/null
+++ b/third_party/rust/futures/src/future/inspect.rs
@@ -0,0 +1,40 @@
+use {Future, Poll, Async};
+
+/// Do something with the item of a future, passing it on.
+///
+/// This is created by the `Future::inspect` method.
+#[derive(Debug)]
+#[must_use = "futures do nothing unless polled"]
+pub struct Inspect<A, F> where A: Future {
+    future: A,
+    f: Option<F>,
+}
+
+pub fn new<A, F>(future: A, f: F) -> Inspect<A, F>
+    where A: Future,
+          F: FnOnce(&A::Item),
+{
+    Inspect {
+        future: future,
+        f: Some(f),
+    }
+}
+
+impl<A, F> Future for Inspect<A, F>
+    where A: Future,
+          F: FnOnce(&A::Item),
+{
+    type Item = A::Item;
+    type Error = A::Error;
+
+    fn poll(&mut self) -> Poll<A::Item, A::Error> {
+        match self.future.poll() {
+            Ok(Async::NotReady) => Ok(Async::NotReady),
+            Ok(Async::Ready(e)) => {
+                (self.f.take().expect("cannot poll Inspect twice"))(&e);
+                Ok(Async::Ready(e))
+            },
+            Err(e) => Err(e),
+        }
+    }
+}
--- a/third_party/rust/futures/src/future/join.rs
+++ b/third_party/rust/futures/src/future/join.rs
@@ -145,17 +145,17 @@ enum MaybeDone<A: Future> {
     NotYet(A),
     Done(A::Item),
     Gone,
 }
 
 impl<A: Future> MaybeDone<A> {
     fn poll(&mut self) -> Result<bool, A::Error> {
         let res = match *self {
-            MaybeDone::NotYet(ref mut a) => try!(a.poll()),
+            MaybeDone::NotYet(ref mut a) => a.poll()?,
             MaybeDone::Done(_) => return Ok(true),
             MaybeDone::Gone => panic!("cannot poll Join twice"),
         };
         match res {
             Async::Ready(res) => {
                 *self = MaybeDone::Done(res);
                 Ok(true)
             }
--- a/third_party/rust/futures/src/future/join_all.rs
+++ b/third_party/rust/futures/src/future/join_all.rs
@@ -1,9 +1,9 @@
-//! Definition of the JoinAll combinator, waiting for all of a list of futures
+//! Definition of the `JoinAll` combinator, waiting for all of a list of futures
 //! to finish.
 
 use std::prelude::v1::*;
 
 use std::fmt;
 use std::mem;
 
 use {Future, IntoFuture, Poll, Async};
@@ -38,39 +38,40 @@ impl<I> fmt::Debug for JoinAll<I>
             .finish()
     }
 }
 
 /// Creates a future which represents a collection of the results of the futures
 /// given.
 ///
 /// The returned future will drive execution for all of its underlying futures,
-/// collecting the results into a destination `Vec<T>`. If any future returns
-/// an error then all other futures will be canceled and an error will be
-/// returned immediately. If all futures complete successfully, however, then
-/// the returned future will succeed with a `Vec` of all the successful results.
+/// collecting the results into a destination `Vec<T>` in the same order as they
+/// were provided. If any future returns an error then all other futures will be
+/// canceled and an error will be returned immediately. If all futures complete
+/// successfully, however, then the returned future will succeed with a `Vec` of
+/// all the successful results.
 ///
 /// # Examples
 ///
 /// ```
 /// use futures::future::*;
 ///
 /// let f = join_all(vec![
 ///     ok::<u32, u32>(1),
 ///     ok::<u32, u32>(2),
 ///     ok::<u32, u32>(3),
 /// ]);
 /// let f = f.map(|x| {
 ///     assert_eq!(x, [1, 2, 3]);
 /// });
 ///
 /// let f = join_all(vec![
-///     ok::<u32, u32>(1).boxed(),
-///     err::<u32, u32>(2).boxed(),
-///     ok::<u32, u32>(3).boxed(),
+///     Box::new(ok::<u32, u32>(1)),
+///     Box::new(err::<u32, u32>(2)),
+///     Box::new(ok::<u32, u32>(3)),
 /// ]);
 /// let f = f.then(|x| {
 ///     assert_eq!(x, Err(2));
 ///     x
 /// });
 /// ```
 pub fn join_all<I>(i: I) -> JoinAll<I>
     where I: IntoIterator,
@@ -89,28 +90,28 @@ impl<I> Future for JoinAll<I>
     type Item = Vec<<I::Item as IntoFuture>::Item>;
     type Error = <I::Item as IntoFuture>::Error;
 
 
     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
         let mut all_done = true;
 
         for idx in 0 .. self.elems.len() {
-            let done_val = match &mut self.elems[idx] {
-                &mut ElemState::Pending(ref mut t) => {
+            let done_val = match self.elems[idx] {
+                ElemState::Pending(ref mut t) => {
                     match t.poll() {
                         Ok(Async::Ready(v)) => Ok(v),
                         Ok(Async::NotReady) => {
                             all_done = false;
                             continue
                         }
                         Err(e) => Err(e),
                     }
                 }
-                &mut ElemState::Done(ref mut _v) => continue,
+                ElemState::Done(ref mut _v) => continue,
             };
 
             match done_val {
                 Ok(v) => self.elems[idx] = ElemState::Done(v),
                 Err(e) => {
                     // On completion drop all our associated resources
                     // ASAP.
                     self.elems = Vec::new();
--- a/third_party/rust/futures/src/future/mod.rs
+++ b/third_party/rust/futures/src/future/mod.rs
@@ -1,13 +1,14 @@
 //! Futures
 //!
 //! This module contains the `Future` trait and a number of adaptors for this
 //! trait. See the crate docs, and the docs for `Future`, for full detail.
 
+use core::fmt;
 use core::result;
 
 // Primitive futures
 mod empty;
 mod lazy;
 mod poll_fn;
 #[path = "result.rs"]
 mod result_;
@@ -50,16 +51,17 @@ mod join;
 mod map;
 mod map_err;
 mod from_err;
 mod or_else;
 mod select;
 mod select2;
 mod then;
 mod either;
+mod inspect;
 
 // impl details
 mod chain;
 
 pub use self::and_then::AndThen;
 pub use self::flatten::Flatten;
 pub use self::flatten_stream::FlattenStream;
 pub use self::fuse::Fuse;
@@ -68,16 +70,17 @@ pub use self::join::{Join, Join3, Join4,
 pub use self::map::Map;
 pub use self::map_err::MapErr;
 pub use self::from_err::FromErr;
 pub use self::or_else::OrElse;
 pub use self::select::{Select, SelectNext};
 pub use self::select2::Select2;
 pub use self::then::Then;
 pub use self::either::Either;
+pub use self::inspect::Inspect;
 
 if_std! {
     mod catch_unwind;
     mod join_all;
     mod select_all;
     mod select_ok;
     mod shared;
     pub use self::catch_unwind::CatchUnwind;
@@ -91,16 +94,20 @@ if_std! {
     #[cfg(feature = "with-deprecated")]
     pub use self::join_all::join_all as collect;
     #[doc(hidden)]
     #[deprecated(since = "0.1.4", note = "use JoinAll instead")]
     #[cfg(feature = "with-deprecated")]
     pub use self::join_all::JoinAll as Collect;
 
     /// A type alias for `Box<Future + Send>`
+    #[doc(hidden)]
+    #[deprecated(note = "removed without replacement, recommended to use a \
+                         local extension trait or function if needed, more \
+                         details in https://github.com/alexcrichton/futures-rs/issues/228")]
     pub type BoxFuture<T, E> = ::std::boxed::Box<Future<Item = T, Error = E> + Send>;
 
     impl<F: ?Sized + Future> Future for ::std::boxed::Box<F> {
         type Item = F::Item;
         type Error = F::Error;
 
         fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
             (**self).poll()
@@ -143,17 +150,17 @@ use {Poll, stream};
 ///
 /// The `poll` method is not intended to be called in general, but rather is
 /// typically called in the context of a "task" which drives a future to
 /// completion. For more information on this see the `task` module.
 ///
 /// More information about the details of `poll` and the nitty-gritty of tasks
 /// can be [found online at tokio.rs][poll-dox].
 ///
-/// [poll-dox]: https://tokio.rs/docs/going-deeper/futures-model/
+/// [poll-dox]: https://tokio.rs/docs/going-deeper-futures/futures-model/
 ///
 /// # Combinators
 ///
 /// Like iterators, futures provide a large number of combinators to work with
 /// futures to express computations in a much more natural method than
 /// scheduling a number of callbacks. For example the `map` method can change
 /// a `Future<Item=T>` to a `Future<Item=U>` or an `and_then` combinator could
 /// create a future after the first one is done and only be resolved when the
@@ -161,45 +168,45 @@ use {Poll, stream};
 ///
 /// Combinators act very similarly to the methods on the `Iterator` trait itself
 /// or those on `Option` and `Result`. Like with iterators, the combinators are
 /// zero-cost and don't impose any extra layers of indirection you wouldn't
 /// otherwise have to write down.
 ///
 /// More information about combinators can be found [on tokio.rs].
 ///
-/// [on tokio.rs]: https://tokio.rs/docs/going-deeper/futures-mechanics/
+/// [on tokio.rs]: https://tokio.rs/docs/going-deeper-futures/futures-mechanics/
 pub trait Future {
     /// The type of value that this future will resolved with if it is
     /// successful.
     type Item;
 
     /// The type of error that this future will resolve with if it fails in a
     /// normal fashion.
     type Error;
 
     /// Query this future to see if its value has become available, registering
     /// interest if it is not.
     ///
     /// This function will check the internal state of the future and assess
-    /// whether the value is ready to be produced. Implementors of this function
+    /// whether the value is ready to be produced. Implementers of this function
     /// should ensure that a call to this **never blocks** as event loops may
     /// not work properly otherwise.
     ///
     /// When a future is not ready yet, the `Async::NotReady` value will be
     /// returned. In this situation the future will *also* register interest of
     /// the current task in the value being produced. This is done by calling
     /// `task::park` to retrieve a handle to the current `Task`. When the future
     /// is then ready to make progress (e.g. it should be `poll`ed again) the
     /// `unpark` method is called on the `Task`.
     ///
     /// More information about the details of `poll` and the nitty-gritty of
     /// tasks can be [found online at tokio.rs][poll-dox].
     ///
-    /// [poll-dox]: https://tokio.rs/docs/going-deeper/futures-model/
+    /// [poll-dox]: https://tokio.rs/docs/going-deeper-futures/futures-model/
     ///
     /// # Runtime characteristics
     ///
     /// This function, `poll`, is the primary method for 'making progress'
     /// within a tree of futures. For example this method will be called
     /// repeatedly as the internal state machine makes its various transitions.
     /// Executors are responsible for ensuring that this function is called in
     /// the right location (e.g. always on an I/O thread or not). Unless it is
@@ -229,16 +236,24 @@ pub trait Future {
     /// error to continue polling the future.
     ///
     /// If `NotReady` is returned, then the future will internally register
     /// interest in the value being produced for the current task (through
     /// `task::park`). In other words, the current task will receive a
     /// notification (through the `unpark` method) once the value is ready to be
     /// produced or the future can make progress.
     ///
+    /// Note that if `NotReady` is returned it only means that *this* task will
+    /// receive a notification. Historical calls to `poll` with different tasks
+    /// will not receive notifications. In other words, implementers of the
+    /// `Future` trait need not store a queue of tasks to notify, but only the
+    /// last task that called this method. Alternatively callers of this method
+    /// can only rely on the most recent task which call `poll` being notified
+    /// when a future is ready.
+    ///
     /// # Panics
     ///
     /// Once a future has completed (returned `Ready` or `Err` from `poll`),
     /// then any future calls to `poll` may panic, block forever, or otherwise
     /// cause wrong behavior. The `Future` trait itself provides no guarantees
     /// about the behavior of `poll` after a future has completed.
     ///
     /// Callers who may call `poll` too many times may want to consider using
@@ -294,21 +309,27 @@ pub trait Future {
     /// `Send` bound, then the `Box::new` function can be used instead.
     ///
     /// This method is only available when the `use_std` feature of this
     /// library is activated, and it is activated by default.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future::{BoxFuture, result};
     ///
     /// let a: BoxFuture<i32, i32> = result(Ok(1)).boxed();
     /// ```
     #[cfg(feature = "use_std")]
+    #[doc(hidden)]
+    #[deprecated(note = "removed without replacement, recommended to use a \
+                         local extension trait or function if needed, more \
+                         details in https://github.com/alexcrichton/futures-rs/issues/228")]
+    #[allow(deprecated)]
     fn boxed(self) -> BoxFuture<Self::Item, Self::Error>
         where Self: Sized + Send + 'static
     {
         ::std::boxed::Box::new(self)
     }
 
     /// Map this future's result to a different type, returning a new future of
     /// the resulting type.
@@ -323,20 +344,33 @@ pub trait Future {
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it, similar to the existing `map` methods in the
     /// standard library.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// let future = future::ok::<u32, u32>(1);
+    /// let new_future = future.map(|x| x + 3);
+    /// assert_eq!(new_future.wait(), Ok(4));
+    /// ```
     ///
-    /// let future_of_1 = ok::<u32, u32>(1);
-    /// let future_of_4 = future_of_1.map(|x| x + 3);
+    /// Calling `map` on an errored `Future` has no effect:
+    ///
+    /// ```
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// let future = future::err::<u32, u32>(1);
+    /// let new_future = future.map(|x| x + 3);
+    /// assert_eq!(new_future.wait(), Err(1));
     /// ```
     fn map<F, U>(self, f: F) -> Map<Self, F>
         where F: FnOnce(Self::Item) -> U,
               Self: Sized,
     {
         assert_future::<U, Self::Error, _>(map::new(self, f))
     }
 
@@ -354,18 +388,29 @@ pub trait Future {
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
     /// use futures::future::*;
     ///
-    /// let future_of_err_1 = err::<u32, u32>(1);
-    /// let future_of_err_4 = future_of_err_1.map_err(|x| x + 3);
+    /// let future = err::<u32, u32>(1);
+    /// let new_future = future.map_err(|x| x + 3);
+    /// assert_eq!(new_future.wait(), Err(4));
+    /// ```
+    ///
+    /// Calling `map_err` on a successful `Future` has no effect:
+    ///
+    /// ```
+    /// use futures::future::*;
+    ///
+    /// let future = ok::<u32, u32>(1);
+    /// let new_future = future.map_err(|x| x + 3);
+    /// assert_eq!(new_future.wait(), Ok(1));
     /// ```
     fn map_err<F, E>(self, f: F) -> MapErr<Self, F>
         where F: FnOnce(Self::Error) -> E,
               Self: Sized,
     {
         assert_future::<Self::Item, E, _>(map_err::new(self, f))
     }
 
@@ -381,20 +426,21 @@ pub trait Future {
     /// combinators like `select` and `join`.
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let future_of_err_1 = err::<u32, u32>(1);
-    /// let future_of_err_4 = future_of_err_1.from_err::<u32>();
+    /// let future_with_err_u8 = future::err::<(), u8>(1);
+    /// let future_with_err_u32 = future_with_err_u8.from_err::<u32>();
     /// ```
     fn from_err<E:From<Self::Error>>(self) -> FromErr<Self, E>
         where Self: Sized,
     {
         assert_future::<Self::Item, E, _>(from_err::new(self))
     }
 
     /// Chain on a computation for when a future finished, passing the result of
@@ -414,28 +460,29 @@ pub trait Future {
     /// run.
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let future_of_1 = ok::<u32, u32>(1);
+    /// let future_of_1 = future::ok::<u32, u32>(1);
     /// let future_of_4 = future_of_1.then(|x| {
     ///     x.map(|y| y + 3)
     /// });
     ///
-    /// let future_of_err_1 = err::<u32, u32>(1);
+    /// let future_of_err_1 = future::err::<u32, u32>(1);
     /// let future_of_4 = future_of_err_1.then(|x| {
     ///     match x {
     ///         Ok(_) => panic!("expected an error"),
-    ///         Err(y) => ok::<u32, u32>(y + 3),
+    ///         Err(y) => future::ok::<u32, u32>(y + 3),
     ///     }
     /// });
     /// ```
     fn then<F, B>(self, f: F) -> Then<Self, B, F>
         where F: FnOnce(result::Result<Self::Item, Self::Error>) -> B,
               B: IntoFuture,
               Self: Sized,
     {
@@ -457,24 +504,25 @@ pub trait Future {
     /// provided closure `f` is never called.
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future::{self, FutureResult};
     ///
-    /// let future_of_1 = ok::<u32, u32>(1);
+    /// let future_of_1 = future::ok::<u32, u32>(1);
     /// let future_of_4 = future_of_1.and_then(|x| {
     ///     Ok(x + 3)
     /// });
     ///
-    /// let future_of_err_1 = err::<u32, u32>(1);
+    /// let future_of_err_1 = future::err::<u32, u32>(1);
     /// future_of_err_1.and_then(|_| -> FutureResult<u32, u32> {
     ///     panic!("should not be called in case of an error");
     /// });
     /// ```
     fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
         where F: FnOnce(Self::Item) -> B,
               B: IntoFuture<Error = Self::Error>,
               Self: Sized,
@@ -497,24 +545,25 @@ pub trait Future {
     /// provided closure `f` is never called.
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future::{self, FutureResult};
     ///
-    /// let future_of_err_1 = err::<u32, u32>(1);
+    /// let future_of_err_1 = future::err::<u32, u32>(1);
     /// let future_of_4 = future_of_err_1.or_else(|x| -> Result<u32, u32> {
     ///     Ok(x + 3)
     /// });
     ///
-    /// let future_of_1 = ok::<u32, u32>(1);
+    /// let future_of_1 = future::ok::<u32, u32>(1);
     /// future_of_1.or_else(|_| -> FutureResult<u32, u32> {
     ///     panic!("should not be called in case of success");
     /// });
     /// ```
     fn or_else<F, B>(self, f: F) -> OrElse<Self, B, F>
         where F: FnOnce(Self::Error) -> B,
               B: IntoFuture<Item = Self::Item>,
               Self: Sized,
@@ -529,30 +578,52 @@ pub trait Future {
     /// both the value resolved and a future representing the completion of the
     /// other work. Both futures must have the same item and error type.
     ///
     /// Note that this function consumes the receiving futures and returns a
     /// wrapped version of them.
     ///
     /// # Examples
     ///
-    /// ```
-    /// use futures::future::*;
+    /// ```no_run
+    /// use futures::prelude::*;
+    /// use futures::future;
+    /// use std::thread;
+    /// use std::time;
     ///
-    /// // A poor-man's join implemented on top of select
+    /// let future1 = future::lazy(|| {
+    ///     thread::sleep(time::Duration::from_secs(5));
+    ///     future::ok::<char, ()>('a')
+    /// });
+    ///
+    /// let future2 = future::lazy(|| {
+    ///     thread::sleep(time::Duration::from_secs(3));
+    ///     future::ok::<char, ()>('b')
+    /// });
     ///
-    /// fn join<A>(a: A, b: A) -> BoxFuture<(u32, u32), u32>
-    ///     where A: Future<Item = u32, Error = u32> + Send + 'static,
+    /// let (value, last_future) = future1.select(future2).wait().ok().unwrap();
+    /// assert_eq!(value, 'a');
+    /// assert_eq!(last_future.wait().unwrap(), 'b');
+    /// ```
+    ///
+    /// A poor-man's `join` implemented on top of `select`:
+    ///
+    /// ```
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// fn join<A>(a: A, b: A) -> Box<Future<Item=(u32, u32), Error=u32>>
+    ///     where A: Future<Item = u32, Error = u32> + 'static,
     /// {
-    ///     a.select(b).then(|res| {
+    ///     Box::new(a.select(b).then(|res| -> Box<Future<Item=_, Error=_>> {
     ///         match res {
-    ///             Ok((a, b)) => b.map(move |b| (a, b)).boxed(),
-    ///             Err((a, _)) => err(a).boxed(),
+    ///             Ok((a, b)) => Box::new(b.map(move |b| (a, b))),
+    ///             Err((a, _)) => Box::new(future::err(a)),
     ///         }
-    ///     }).boxed()
+    ///     }))
     /// }
     /// ```
     fn select<B>(self, other: B) -> Select<Self, B::Future>
         where B: IntoFuture<Item=Self::Item, Error=Self::Error>,
               Self: Sized,
     {
         let f = select::new(self, other.into_future());
         assert_future::<(Self::Item, SelectNext<Self, B::Future>),
@@ -571,33 +642,34 @@ pub trait Future {
     ///
     /// Also note that if both this and the second future have the same
     /// success/error type you can use the `Either::split` method to
     /// conveniently extract out the value at the end.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future::{self, Either};
     ///
     /// // A poor-man's join implemented on top of select2
     ///
-    /// fn join<A, B, E>(a: A, b: B) -> BoxFuture<(A::Item, B::Item), E>
-    ///     where A: Future<Error = E> + Send + 'static,
-    ///           B: Future<Error = E> + Send + 'static,
-    ///           A::Item: Send, B::Item: Send, E: Send + 'static,
+    /// fn join<A, B, E>(a: A, b: B) -> Box<Future<Item=(A::Item, B::Item), Error=E>>
+    ///     where A: Future<Error = E> + 'static,
+    ///           B: Future<Error = E> + 'static,
+    ///           E: 'static,
     /// {
-    ///     a.select2(b).then(|res| {
+    ///     Box::new(a.select2(b).then(|res| -> Box<Future<Item=_, Error=_>> {
     ///         match res {
-    ///             Ok(Either::A((x, b))) => b.map(move |y| (x, y)).boxed(),
-    ///             Ok(Either::B((y, a))) => a.map(move |x| (x, y)).boxed(),
-    ///             Err(Either::A((e, _))) => err(e).boxed(),
-    ///             Err(Either::B((e, _))) => err(e).boxed(),
+    ///             Ok(Either::A((x, b))) => Box::new(b.map(move |y| (x, y))),
+    ///             Ok(Either::B((y, a))) => Box::new(a.map(move |x| (x, y))),
+    ///             Err(Either::A((e, _))) => Box::new(future::err(e)),
+    ///             Err(Either::B((e, _))) => Box::new(future::err(e)),
     ///         }
-    ///     }).boxed()
+    ///     }))
     /// }
     /// ```
     fn select2<B>(self, other: B) -> Select2<Self, B::Future>
         where B: IntoFuture, Self: Sized
     {
         select2::new(self, other.into_future())
     }
 
@@ -612,26 +684,38 @@ pub trait Future {
     /// returned.
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let a = ok::<u32, u32>(1);
-    /// let b = ok::<u32, u32>(2);
+    /// let a = future::ok::<u32, u32>(1);
+    /// let b = future::ok::<u32, u32>(2);
     /// let pair = a.join(b);
     ///
-    /// pair.map(|(a, b)| {
-    ///     assert_eq!(a, 1);
-    ///     assert_eq!(b, 2);
-    /// });
+    /// assert_eq!(pair.wait(), Ok((1, 2)));
+    /// ```
+    ///
+    /// If one or both of the joined `Future`s is errored, the resulting
+    /// `Future` will be errored:
+    ///
+    /// ```
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// let a = future::ok::<u32, u32>(1);
+    /// let b = future::err::<u32, u32>(2);
+    /// let pair = a.join(b);
+    ///
+    /// assert_eq!(pair.wait(), Err(2));
     /// ```
     fn join<B>(self, other: B) -> Join<Self, B::Future>
         where B: IntoFuture<Error=Self::Error>,
               Self: Sized,
     {
         let f = join::new(self, other.into_future());
         assert_future::<(Self::Item, B::Item), Self::Error, _>(f)
     }
@@ -672,56 +756,70 @@ pub trait Future {
     /// Convert this future into a single element stream.
     ///
     /// The returned stream contains single success if this future resolves to
     /// success or single error if this future resolves into error.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::{Stream, Async};
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let future = ok::<_, bool>(17);
+    /// let future = future::ok::<_, bool>(17);
     /// let mut stream = future.into_stream();
     /// assert_eq!(Ok(Async::Ready(Some(17))), stream.poll());
     /// assert_eq!(Ok(Async::Ready(None)), stream.poll());
     ///
-    /// let future = err::<bool, _>(19);
+    /// let future = future::err::<bool, _>(19);
     /// let mut stream = future.into_stream();
     /// assert_eq!(Err(19), stream.poll());
     /// assert_eq!(Ok(Async::Ready(None)), stream.poll());
     /// ```
     fn into_stream(self) -> IntoStream<Self>
         where Self: Sized
     {
         into_stream::new(self)
     }
 
     /// Flatten the execution of this future when the successful result of this
     /// future is itself another future.
     ///
     /// This can be useful when combining futures together to flatten the
-    /// computation out the the final result. This method can only be called
+    /// computation out the final result. This method can only be called
     /// when the successful result of this future itself implements the
     /// `IntoFuture` trait and the error can be created from this future's error
     /// type.
     ///
     /// This method is roughly equivalent to `self.and_then(|x| x)`.
     ///
     /// Note that this function consumes the receiving future and returns a
     /// wrapped version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// let nested_future = future::ok::<_, u32>(future::ok::<u32, u32>(1));
+    /// let future = nested_future.flatten();
+    /// assert_eq!(future.wait(), Ok(1));
+    /// ```
     ///
-    /// let future_of_a_future = ok::<_, u32>(ok::<u32, u32>(1));
-    /// let future_of_1 = future_of_a_future.flatten();
+    /// Calling `flatten` on an errored `Future`, or if the inner `Future` is
+    /// errored, will result in an errored `Future`:
+    ///
+    /// ```
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// let nested_future = future::ok::<_, u32>(future::err::<u32, u32>(1));
+    /// let future = nested_future.flatten();
+    /// assert_eq!(future.wait(), Err(1));
     /// ```
     fn flatten(self) -> Flatten<Self>
         where Self::Item: IntoFuture,
         <<Self as Future>::Item as IntoFuture>::Error:
             From<<Self as Future>::Error>,
         Self: Sized
     {
         let f = flatten::new(self);
@@ -738,27 +836,28 @@ pub trait Future {
     /// call site.
     ///
     /// Note that this function consumes this future and returns a wrapped
     /// version of it.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::stream::{self, Stream};
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
+    /// use futures::stream;
     ///
-    /// let stream_items = vec![Ok(17), Err(true), Ok(19)];
-    /// let future_of_a_stream = ok::<_, bool>(stream::iter(stream_items));
+    /// let stream_items = vec![17, 18, 19];
+    /// let future_of_a_stream = future::ok::<_, bool>(stream::iter_ok(stream_items));
     ///
     /// let stream = future_of_a_stream.flatten_stream();
     ///
     /// let mut iter = stream.wait();
     /// assert_eq!(Ok(17), iter.next().unwrap());
-    /// assert_eq!(Err(true), iter.next().unwrap());
+    /// assert_eq!(Ok(18), iter.next().unwrap());
     /// assert_eq!(Ok(19), iter.next().unwrap());
     /// assert_eq!(None, iter.next());
     /// ```
     fn flatten_stream(self) -> FlattenStream<Self>
         where <Self as Future>::Item: stream::Stream<Error=Self::Error>,
               Self: Sized
     {
         flatten_stream::new(self)
@@ -778,37 +877,60 @@ pub trait Future {
     /// resolve).  This, unlike the trait's `poll` method, is guaranteed.
     ///
     /// This combinator will drop this future as soon as it's been completed to
     /// ensure resources are reclaimed as soon as possible.
     ///
     /// # Examples
     ///
     /// ```rust
-    /// use futures::Async;
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let mut future = ok::<i32, u32>(2);
+    /// let mut future = future::ok::<i32, u32>(2);
     /// assert_eq!(future.poll(), Ok(Async::Ready(2)));
     ///
     /// // Normally, a call such as this would panic:
     /// //future.poll();
     ///
     /// // This, however, is guaranteed to not panic
-    /// let mut future = ok::<i32, u32>(2).fuse();
+    /// let mut future = future::ok::<i32, u32>(2).fuse();
     /// assert_eq!(future.poll(), Ok(Async::Ready(2)));
     /// assert_eq!(future.poll(), Ok(Async::NotReady));
     /// ```
     fn fuse(self) -> Fuse<Self>
         where Self: Sized
     {
         let f = fuse::new(self);
         assert_future::<Self::Item, Self::Error, _>(f)
     }
 
+    /// Do something with the item of a future, passing it on.
+    ///
+    /// When using futures, you'll often chain several of them together.
+    /// While working on such code, you might want to check out what's happening at
+    /// various parts in the pipeline. To do that, insert a call to inspect().
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use futures::prelude::*;
+    /// use futures::future;
+    ///
+    /// let future = future::ok::<u32, u32>(1);
+    /// let new_future = future.inspect(|&x| println!("about to resolve: {}", x));
+    /// assert_eq!(new_future.wait(), Ok(1));
+    /// ```
+    fn inspect<F>(self, f: F) -> Inspect<Self, F>
+        where F: FnOnce(&Self::Item) -> (),
+              Self: Sized,
+    {
+        assert_future::<Self::Item, Self::Error, _>(inspect::new(self, f))
+    }
+
     /// Catches unwinding panics while polling the future.
     ///
     /// In general, panics within a future can propagate all the way out to the
     /// task level. This combinator makes it possible to halt unwinding within
     /// the future itself. It's most commonly used within task executors. It's
     /// not recommended to use this for error handling.
     ///
     /// Note that this method requires the `UnwindSafe` bound from the standard
@@ -818,66 +940,69 @@ pub trait Future {
     /// implemented for `AssertUnwindSafe<F>` where `F` implements `Future`.
     ///
     /// This method is only available when the `use_std` feature of this
     /// library is activated, and it is activated by default.
     ///
     /// # Examples
     ///
     /// ```rust
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future::{self, FutureResult};
     ///
-    /// let mut future = ok::<i32, u32>(2);
+    /// let mut future = future::ok::<i32, u32>(2);
     /// assert!(future.catch_unwind().wait().is_ok());
     ///
-    /// let mut future = lazy(|| -> FutureResult<i32, u32> {
+    /// let mut future = future::lazy(|| -> FutureResult<i32, u32> {
     ///     panic!();
-    ///     ok::<i32, u32>(2)
+    ///     future::ok::<i32, u32>(2)
     /// });
     /// assert!(future.catch_unwind().wait().is_err());
     /// ```
     #[cfg(feature = "use_std")]
     fn catch_unwind(self) -> CatchUnwind<Self>
         where Self: Sized + ::std::panic::UnwindSafe
     {
         catch_unwind::new(self)
     }
 
     /// Create a cloneable handle to this future where all handles will resolve
     /// to the same result.
     ///
-    /// The shared() method provides a mean to convert any future into a
+    /// The shared() method provides a method to convert any future into a
     /// cloneable future. It enables a future to be polled by multiple threads.
     ///
     /// The returned `Shared` future resolves successfully with
     /// `SharedItem<Self::Item>` or erroneously with `SharedError<Self::Error>`.
     /// Both `SharedItem` and `SharedError` implements `Deref` to allow shared
     /// access to the underlying result. Ownership of `Self::Item` and
     /// `Self::Error` cannot currently be reclaimed.
     ///
     /// This method is only available when the `use_std` feature of this
     /// library is activated, and it is activated by default.
     ///
     /// # Examples
     ///
     /// ```
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let future = ok::<_, bool>(6);
+    /// let future = future::ok::<_, bool>(6);
     /// let shared1 = future.shared();
     /// let shared2 = shared1.clone();
     /// assert_eq!(6, *shared1.wait().unwrap());
     /// assert_eq!(6, *shared2.wait().unwrap());
     /// ```
     ///
     /// ```
     /// use std::thread;
-    /// use futures::future::*;
+    /// use futures::prelude::*;
+    /// use futures::future;
     ///
-    /// let future = ok::<_, bool>(6);
+    /// let future = future::ok::<_, bool>(6);
     /// let shared1 = future.shared();
     /// let shared2 = shared1.clone();
     /// let join_handle = thread::spawn(move || {
     ///     assert_eq!(6, *shared2.wait().unwrap());
     /// });
     /// assert_eq!(6, *shared1.wait().unwrap());
     /// join_handle.join().unwrap();
     /// ```
@@ -952,8 +1077,94 @@ pub trait FutureFrom<T>: Sized {
     type Future: Future<Item=Self, Error=Self::Error>;
 
     /// Possible errors during conversion.
     type Error;
 
     /// Consume the given value, beginning the conversion.
     fn future_from(T) -> Self::Future;
 }
+
+/// A trait for types which can spawn fresh futures.
+///
+/// This trait is typically implemented for "executors", or those types which
+/// can execute futures to completion. Futures passed to `Spawn::spawn`
+/// typically get turned into a *task* and are then driven to completion.
+///
+/// On spawn, the executor takes ownership of the future and becomes responsible
+/// to call `Future::poll()` whenever a readiness notification is raised.
+pub trait Executor<F: Future<Item = (), Error = ()>> {
+    /// Spawns a future to run on this `Executor`, typically in the
+    /// "background".
+    ///
+    /// This function will return immediately, and schedule the future `future`
+    /// to run on `self`. The details of scheduling and execution are left to
+    /// the implementations of `Executor`, but this is typically a primary point
+    /// for injecting concurrency in a futures-based system. Futures spawned
+    /// through this `execute` function tend to run concurrently while they're
+    /// waiting on events.
+    ///
+    /// # Errors
+    ///
+    /// Implementers of this trait are allowed to reject accepting this future
+    /// as well. This can happen for various reason such as:
+    ///
+    /// * The executor is shut down
+    /// * The executor has run out of capacity to execute futures
+    ///
+    /// The decision is left to the caller how to work with this form of error.
+    /// The error returned transfers ownership of the future back to the caller.
+    fn execute(&self, future: F) -> Result<(), ExecuteError<F>>;
+}
+
+/// Errors returned from the `Spawn::spawn` function.
+pub struct ExecuteError<F> {
+    future: F,
+    kind: ExecuteErrorKind,
+}
+
+/// Kinds of errors that can be returned from the `Execute::spawn` function.
+///
+/// Executors which may not always be able to accept a future may return one of
+/// these errors, indicating why it was unable to spawn a future.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum ExecuteErrorKind {
+    /// This executor has shut down and will no longer accept new futures to
+    /// spawn.
+    Shutdown,
+
+    /// This executor has no more capacity to run more futures. Other futures
+    /// need to finish before this executor can accept another.
+    NoCapacity,
+
+    #[doc(hidden)]
+    __Nonexhaustive,
+}
+
+impl<F> ExecuteError<F> {
+    /// Create a new `ExecuteError`
+    pub fn new(kind: ExecuteErrorKind, future: F) -> ExecuteError<F> {
+        ExecuteError {
+            future: future,
+            kind: kind,
+        }
+    }
+
+    /// Returns the associated reason for the error
+    pub fn kind(&self) -> ExecuteErrorKind {
+        self.kind
+    }
+
+    /// Consumes self and returns the original future that was spawned.
+    pub fn into_future(self) -> F {
+        self.future
+    }
+}
+
+impl<F> fmt::Debug for ExecuteError<F> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self.kind {
+            ExecuteErrorKind::Shutdown => "executor has shut down".fmt(f),
+            ExecuteErrorKind::NoCapacity => "executor has no more capacity".fmt(f),
+            ExecuteErrorKind::__Nonexhaustive => panic!(),
+        }
+    }
+}
--- a/third_party/rust/futures/src/future/result.rs
+++ b/third_party/rust/futures/src/future/result.rs
@@ -2,26 +2,26 @@
 
 use core::result;
 
 use {Future, Poll, Async};
 
 /// A future representing a value that is immediately ready.
 ///
 /// Created by the `result` function.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 #[must_use = "futures do nothing unless polled"]
 // TODO: rename this to `Result` on the next major version
 pub struct FutureResult<T, E> {
     inner: Option<result::Result<T, E>>,
 }
 
 /// Creates a new "leaf future" which will resolve with the given result.
 ///
-/// The returned future represents a computation which is finshed immediately.
+/// The returned future represents a computation which is finished immediately.
 /// This can be useful with the `finished` and `failed` base future types to
 /// convert an immediate value to a future to interoperate elsewhere.
 ///
 /// # Examples
 ///
 /// ```
 /// use futures::future::*;
 ///
@@ -68,8 +68,14 @@ pub fn err<T, E>(e: E) -> FutureResult<T
 impl<T, E> Future for FutureResult<T, E> {
     type Item = T;
     type Error = E;
 
     fn poll(&mut self) -> Poll<T, E> {
         self.inner.take().expect("cannot poll Result twice").map(Async::Ready)
     }
 }
+
+impl<T, E> From<Result<T, E>> for FutureResult<T, E> {
+    fn from(r: Result<T, E>) -> Self {
+        result(r)
+    }
+}
--- a/third_party/rust/futures/src/future/select2.rs
+++ b/third_party/rust/futures/src/future/select2.rs
@@ -1,15 +1,17 @@
 use {Future, Poll, Async};
 use future::Either;
 
-/// Future for the `merge` combinator, waiting for one of two differently-typed
+/// Future for the `select2` combinator, waiting for one of two differently-typed
 /// futures to complete.
 ///
-/// This is created by the `Future::merge` method.
+/// This is created by the [`Future::select2`] method.
+///
+/// [`Future::select2`]: trait.Future.html#method.select2
 #[must_use = "futures do nothing unless polled"]
 #[derive(Debug)]
 pub struct Select2<A, B> {
     inner: Option<(A, B)>,
 }
 
 pub fn new<A, B>(a: A, b: B) -> Select2<A, B> {
     Select2 { inner: Some((a, b)) }
@@ -18,20 +20,20 @@ pub fn new<A, B>(a: A, b: B) -> Select2<
 impl<A, B> Future for Select2<A, B> where A: Future, B: Future {
     type Item = Either<(A::Item, B), (B::Item, A)>;
     type Error = Either<(A::Error, B), (B::Error, A)>;
 
     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
         let (mut a, mut b) = self.inner.take().expect("cannot poll Select2 twice");
         match a.poll() {
             Err(e) => Err(Either::A((e, b))),
-            Ok(Async::Ready(x)) => Ok(Async::Ready((Either::A((x, b))))),
+            Ok(Async::Ready(x)) => Ok(Async::Ready(Either::A((x, b)))),
             Ok(Async::NotReady) => match b.poll() {
                 Err(e) => Err(Either::B((e, a))),
-                Ok(Async::Ready(x)) => Ok(Async::Ready((Either::B((x, a))))),
+                Ok(Async::Ready(x)) => Ok(Async::Ready(Either::B((x, a)))),
                 Ok(Async::NotReady) => {
                     self.inner = Some((a, b));
                     Ok(Async::NotReady)
                 }
             }
         }
     }
 }
--- a/third_party/rust/futures/src/future/select_all.rs
+++ b/third_party/rust/futures/src/future/select_all.rs
@@ -1,9 +1,9 @@
-//! Definition of the SelectAll, finding the first future in a list that
+//! Definition of the `SelectAll`, finding the first future in a list that
 //! finishes.
 
 use std::mem;
 use std::prelude::v1::*;
 
 use {Future, IntoFuture, Poll, Async};
 
 /// Future for the `select_all` combinator, waiting for one of any of a list of
--- a/third_party/rust/futures/src/future/select_ok.rs
+++ b/third_party/rust/futures/src/future/select_ok.rs
@@ -2,17 +2,17 @@
 //! in a list.
 
 use std::mem;
 use std::prelude::v1::*;
 
 use {Future, IntoFuture, Poll, Async};
 
 /// Future for the `select_ok` combinator, waiting for one of any of a list of
-/// futures to succesfully complete. unlike `select_all`, this future ignores all
+/// futures to successfully complete. Unlike `select_all`, this future ignores all
 /// but the last error, if there are any.
 ///
 /// This is created by the `select_ok` function.
 #[derive(Debug)]
 #[must_use = "futures do nothing unless polled"]
 pub struct SelectOk<A> where A: Future {
     inner: Vec<A>,
 }
--- a/third_party/rust/futures/src/future/shared.rs
+++ b/third_party/rust/futures/src/future/shared.rs
@@ -9,28 +9,28 @@
 //! let future = ok::<_, bool>(6);
 //! let shared1 = future.shared();
 //! let shared2 = shared1.clone();
 //! assert_eq!(6, *shared1.wait().unwrap());
 //! assert_eq!(6, *shared2.wait().unwrap());
 //! ```
 
 use {Future, Poll, Async};
-use executor::{self, Spawn, Unpark};
 use task::{self, Task};
+use executor::{self, Notify, Spawn};
 
-use std::{fmt, mem, ops};
+use std::{error, fmt, mem, ops};
 use std::cell::UnsafeCell;
 use std::sync::{Arc, Mutex};
 use std::sync::atomic::AtomicUsize;
 use std::sync::atomic::Ordering::SeqCst;
 use std::collections: