merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 30 May 2016 15:29:19 +0200
changeset 338480 3435dd7ad71fe9003bdeee18fd38d815e033beef
parent 338326 cad514ad49c199e823a92e8c8d27e16c22c3cac7 (current diff)
parent 338479 e0d0d87fb7d3e2d60a0bd552fadcad7640c58a35 (diff)
child 338509 7dcc890c12a81ad6ce5ae9ff5a29eccf9137112b
child 338579 392b592c2fe40d176119896cf87daa81dd38fc85
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.0a1
first release with
nightly linux32
3435dd7ad71f / 49.0a1 / 20160530071207 / files
nightly linux64
3435dd7ad71f / 49.0a1 / 20160530071207 / files
nightly mac
3435dd7ad71f / 49.0a1 / 20160530071207 / files
nightly win32
3435dd7ad71f / 49.0a1 / 20160530071207 / files
nightly win64
3435dd7ad71f / 49.0a1 / 20160530071207 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/media/FlushableTaskQueue.cpp
dom/media/FlushableTaskQueue.h
ipc/chromium/src/base/buffer.cc
ipc/chromium/src/base/buffer.h
js/src/jit-test/tests/basic/save-frame-chain.js
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_utility.h
mfbt/Endian.h
modules/libpref/init/all.js
testing/web-platform/meta/mixed-content/blockable/http-csp/cross-origin-http/link-css-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/http-csp/cross-origin-http/link-css-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/http-csp/cross-origin-http/link-css-tag/top-level/swap-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/http-csp/same-host-http/link-css-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/http-csp/same-host-http/link-css-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/http-csp/same-host-http/link-css-tag/top-level/swap-scheme-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/meta-csp/cross-origin-http/link-css-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/meta-csp/same-host-http/link-css-tag/top-level/no-redirect/opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
--- a/accessible/tests/browser/.eslintrc
+++ b/accessible/tests/browser/.eslintrc
@@ -9,16 +9,17 @@
 
     // Defined in accessible/tests/mochitest/ common.js, name.js, states.js
     "prettyName": true,
     "statesToString": true,
     "eventTypeToString": true,
     "testName": true,
     "testDescr": true,
     "testStates": true,
+    "testRelation": true,
     "testAccessibleTree": true,
     "isAccessible": true,
     "getAccessibleDOMNodeID": true,
 
     // Defined for all accessibility browser tests.
     "addAccessibleTask": true,
     "BrowserTestUtils": true,
     "ContentTask": true,
--- a/accessible/tests/browser/browser.ini
+++ b/accessible/tests/browser/browser.ini
@@ -12,16 +12,18 @@ support-files =
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/letters.gif
   !/accessible/tests/mochitest/moz.png
 
 # Caching tests
 [browser_caching_description.js]
 [browser_caching_name.js]
 skip-if = e10s
+[browser_caching_relations.js]
+[browser_caching_states.js]
 
 # Events tests
 [browser_events_caretmove.js]
 [browser_events_hide.js]
 [browser_events_show.js]
 [browser_events_statechange.js]
 [browser_events_textchange.js]
 
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_caching_relations.js
@@ -0,0 +1,86 @@
+/* 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/. */
+
+'use strict';
+
+/* global RELATION_LABELLED_BY, RELATION_LABEL_FOR, RELATION_DESCRIBED_BY,
+          RELATION_DESCRIPTION_FOR, RELATION_CONTROLLER_FOR,
+          RELATION_CONTROLLED_BY, RELATION_FLOWS_TO, RELATION_FLOWS_FROM */
+
+loadScripts({ name: 'relations.js', dir: MOCHITESTS_DIR });
+
+/**
+ * A test specification that has the following format:
+ * [
+ *   attr                 relevant aria attribute
+ *   hostRelation         corresponding host relation type
+ *   dependantRelation    corresponding dependant relation type
+ * ]
+ */
+const attrRelationsSpec = [
+  ['aria-labelledby', RELATION_LABELLED_BY, RELATION_LABEL_FOR],
+  ['aria-describedby', RELATION_DESCRIBED_BY, RELATION_DESCRIPTION_FOR],
+  ['aria-controls', RELATION_CONTROLLER_FOR, RELATION_CONTROLLED_BY],
+  ['aria-flowto', RELATION_FLOWS_TO, RELATION_FLOWS_FROM]
+];
+
+function* testRelated(browser, accDoc, attr, hostRelation, dependantRelation) {
+  let host = findAccessibleChildByID(accDoc, 'host');
+  let dependant1 = findAccessibleChildByID(accDoc, 'dependant1');
+  let dependant2 = findAccessibleChildByID(accDoc, 'dependant2');
+
+  /**
+   * Test data has the format of:
+   * {
+   *   desc      {String}   description for better logging
+   *   attrs     {?Array}   an optional list of attributes to update
+   *   expected  {Array}    expected relation values for dependant1, dependant2
+   *                        and host respectively.
+   * }
+   */
+  const tests = [{
+    desc: 'No attribute',
+    expected: [ null, null, null ]
+  }, {
+    desc: 'Set attribute',
+    attrs: [{ key: attr, value: 'dependant1' }],
+    expected: [ host, null, dependant1 ]
+  }, {
+    desc: 'Change attribute',
+    attrs: [{ key: attr, value: 'dependant2' }],
+    expected: [ null, host, dependant2 ]
+  }, {
+    desc: 'Remove attribute',
+    attrs: [{ key: attr }],
+    expected: [ null, null, null ]
+  }];
+
+  for (let { desc, attrs, expected } of tests) {
+    info(desc);
+
+    if (attrs) {
+      for (let { key, value } of attrs) {
+        yield invokeSetAttribute(browser, 'host', key, value);
+      }
+    }
+
+    testRelation(dependant1, dependantRelation, expected[0]);
+    testRelation(dependant2, dependantRelation, expected[1]);
+    testRelation(host, hostRelation, expected[2]);
+  }
+}
+
+/**
+ * Test caching of relations between accessible objects.
+ */
+addAccessibleTask(`
+  <div id="dependant1">label</div>
+  <div id="dependant2">label2</div>
+  <div role="checkbox" id="host"></div>`,
+  function* (browser, accDoc) {
+    for (let spec of attrRelationsSpec) {
+      yield testRelated(browser, accDoc, ...spec);
+    }
+  }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_caching_states.js
@@ -0,0 +1,120 @@
+/* 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/. */
+
+'use strict';
+
+/* global EVENT_STATE_CHANGE, STATE_CHECKED, STATE_BUSY, STATE_REQUIRED,
+          STATE_INVALID, EXT_STATE_ENABLED */
+
+loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR },
+            { name: 'states.js', dir: MOCHITESTS_DIR });
+
+/**
+ * Test data has the format of:
+ * {
+ *   desc      {String}   description for better logging
+ *   expected  {Array}    expected states for a given accessible that have the
+ *                        following format:
+ *                          [
+ *                            expected state,
+ *                            expected extra state,
+ *                            absent state,
+ *                            absent extra state
+ *                          ]
+ *   attrs     {?Array}   an optional list of attributes to update
+ * }
+ */
+
+// State caching tests for attribute changes
+const attributeTests = [{
+  desc: 'Checkbox with @checked attribute set to true should have checked ' +
+        'state',
+  attrs: [{
+    attr: 'checked',
+    value: 'true'
+  }],
+  expected: [STATE_CHECKED, 0]
+}, {
+  desc: 'Checkbox with no @checked attribute should not have checked state',
+  attrs: [{
+    attr: 'checked'
+  }],
+  expected: [0, 0, STATE_CHECKED]
+}];
+
+// State caching tests for ARIA changes
+const ariaTests = [{
+  desc: 'File input has busy state when @aria-busy attribute is set to true',
+  attrs: [{
+    attr: 'aria-busy',
+    value: 'true'
+  }],
+  expected: [STATE_BUSY, 0, STATE_REQUIRED | STATE_INVALID]
+}, {
+  desc: 'File input has required state when @aria-required attribute is set ' +
+        'to true',
+  attrs: [{
+    attr: 'aria-required',
+    value: 'true'
+  }],
+  expected: [STATE_REQUIRED, 0, STATE_INVALID]
+}, {
+  desc: 'File input has invalid state when @aria-invalid attribute is set to ' +
+        'true',
+  attrs: [{
+    attr: 'aria-invalid',
+    value: 'true'
+  }],
+  expected: [STATE_INVALID, 0]
+}];
+
+// Extra state caching tests
+const extraStateTests = [{
+  desc: 'Input has no extra enabled state when aria and native disabled ' +
+        'attributes are set at once',
+  attrs: [{
+    attr: 'aria-disabled',
+    value: 'true'
+  }, {
+    attr: 'disabled',
+    value: 'true'
+  }],
+  expected: [0, 0, 0, EXT_STATE_ENABLED]
+}, {
+  desc: 'Input has an extra enabled state when aria and native disabled ' +
+        'attributes are unset at once',
+  attrs: [{
+    attr: 'aria-disabled'
+  }, {
+    attr: 'disabled'
+  }],
+  expected: [0, EXT_STATE_ENABLED]
+}];
+
+function* runStateTests(browser, accDoc, id, tests) {
+  let acc = findAccessibleChildByID(accDoc, id);
+  for (let { desc, attrs, expected } of tests) {
+    info(desc);
+    let onUpdate = waitForEvent(EVENT_STATE_CHANGE, id);
+    for (let { attr, value } of attrs) {
+      yield invokeSetAttribute(browser, id, attr, value);
+    }
+    yield onUpdate;
+    testStates(acc, ...expected);
+  }
+}
+
+/**
+ * Test caching of accessible object states
+ */
+addAccessibleTask(`
+  <input id="checkbox" type="checkbox">
+  <input id="file" type="file">
+  <input id="text">`,
+  function* (browser, accDoc) {
+    yield runStateTests(browser, accDoc, 'checkbox', attributeTests);
+    yield runStateTests(browser, accDoc, 'file', ariaTests);
+    yield runStateTests(browser, accDoc, 'text', extraStateTests);
+  }
+);
--- a/accessible/xpcom/nsAccessibleRelation.cpp
+++ b/accessible/xpcom/nsAccessibleRelation.cpp
@@ -19,16 +19,28 @@ nsAccessibleRelation::nsAccessibleRelati
   mType(aType)
 {
   mTargets = do_CreateInstance(NS_ARRAY_CONTRACTID);
   Accessible* targetAcc = nullptr;
   while ((targetAcc = aRel->Next()))
     mTargets->AppendElement(static_cast<nsIAccessible*>(ToXPC(targetAcc)), false);
 }
 
+nsAccessibleRelation::nsAccessibleRelation(uint32_t aType,
+                                           const nsTArray<ProxyAccessible*>* aTargets) :
+  mType(aType)
+{
+  mTargets = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  for (uint32_t idx = 0; idx < aTargets->Length(); ++idx) {
+    mTargets->AppendElement(
+      static_cast<nsIAccessible*>(ToXPC(aTargets->ElementAt(idx))),
+      false);
+  }
+}
+
 nsAccessibleRelation::~nsAccessibleRelation()
 {
 }
 
 // nsISupports
 NS_IMPL_ISUPPORTS(nsAccessibleRelation, nsIAccessibleRelation)
 
 // nsIAccessibleRelation
--- a/accessible/xpcom/nsAccessibleRelation.h
+++ b/accessible/xpcom/nsAccessibleRelation.h
@@ -4,42 +4,47 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsAccessibleRelation_H_
 #define _nsAccessibleRelation_H_
 
 #include "nsIAccessibleRelation.h"
 
 #include "nsCOMPtr.h"
+#include "nsTArray.h"
 #include "nsIMutableArray.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/a11y/ProxyAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class Relation;
 
 /**
  * Class represents an accessible relation.
  */
 class nsAccessibleRelation final : public nsIAccessibleRelation
 {
 public:
   nsAccessibleRelation(uint32_t aType, Relation* aRel);
 
+  nsAccessibleRelation(uint32_t aType,
+                       const nsTArray<ProxyAccessible*>* aTargets);
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIACCESSIBLERELATION
 
 private:
   nsAccessibleRelation();
   ~nsAccessibleRelation();
 
   nsAccessibleRelation(const nsAccessibleRelation&);
   nsAccessibleRelation& operator = (const nsAccessibleRelation&);
-  
+
   uint32_t mType;
   nsCOMPtr<nsIMutableArray> mTargets;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/xpcom/xpcAccessible.cpp
+++ b/accessible/xpcom/xpcAccessible.cpp
@@ -464,22 +464,31 @@ NS_IMETHODIMP
 xpcAccessible::GetRelationByType(uint32_t aType,
                                  nsIAccessibleRelation** aRelation)
 {
   NS_ENSURE_ARG_POINTER(aRelation);
   *aRelation = nullptr;
 
   NS_ENSURE_ARG(aType <= static_cast<uint32_t>(RelationType::LAST));
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  Relation rel = Intl()->RelationByType(static_cast<RelationType>(aType));
-  NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &rel));
-  return *aRelation ? NS_OK : NS_ERROR_FAILURE;
+  if (IntlGeneric().IsAccessible()) {
+    Relation rel = Intl()->RelationByType(static_cast<RelationType>(aType));
+    NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &rel));
+    return NS_OK;
+  }
+
+  ProxyAccessible* proxy = IntlGeneric().AsProxy();
+  nsTArray<ProxyAccessible*> targets =
+    proxy->RelationByType(static_cast<RelationType>(aType));
+  NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &targets));
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetRelations(nsIArray** aRelations)
 {
   NS_ENSURE_ARG_POINTER(aRelations);
   *aRelations = nullptr;
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2681,17 +2681,17 @@ var gMenuButtonUpdateBadge = {
 };
 
 // Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
 const TLS_ERROR_REPORT_TELEMETRY_AUTO_CHECKED   = 2;
 const TLS_ERROR_REPORT_TELEMETRY_AUTO_UNCHECKED = 3;
 const TLS_ERROR_REPORT_TELEMETRY_MANUAL_SEND    = 4;
 const TLS_ERROR_REPORT_TELEMETRY_AUTO_SEND      = 5;
 
-const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.min", "security.tls.version.max", "security.ssl3."];
+const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.", "security.ssl3."];
 
 const PREF_SSL_IMPACT = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => {
   return prefs.concat(Services.prefs.getChildList(root));
 }, []);
 
 /**
  * Handle command events bubbling up from error page content
  * or from about:newtab or from remote error pages that invoke
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -228,17 +228,17 @@ const SEC_ERROR_EXPIRED_CERTIFICATE     
 const SEC_ERROR_UNKNOWN_ISSUER                     = SEC_ERROR_BASE + 13;
 const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE         = SEC_ERROR_BASE + 30;
 const SEC_ERROR_OCSP_FUTURE_RESPONSE               = SEC_ERROR_BASE + 131;
 const SEC_ERROR_OCSP_OLD_RESPONSE                  = SEC_ERROR_BASE + 132;
 const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 5;
 
 const PREF_BLOCKLIST_CLOCK_SKEW_SECONDS = "services.blocklist.clock_skew_seconds";
 
-const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.min", "security.tls.version.max", "security.ssl3."];
+const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.", "security.ssl3."];
 
 const PREF_SSL_IMPACT = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => {
   return prefs.concat(Services.prefs.getChildList(root));
 }, []);
 
 
 var AboutNetAndCertErrorListener = {
   init: function(chromeGlobal) {
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -5,16 +5,17 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 
 const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}");
 const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1";
 
 function LOG(str) {
   let prefB = Cc["@mozilla.org/preferences-service;1"].
               getService(Ci.nsIPrefBranch);
 
@@ -884,26 +885,24 @@ FeedWriter.prototype = {
     let chan = docShell.currentDocumentChannel;
 
     // We probably need to call InheritFromDocShellToDoc for this, but right now
     // we can't call it from JS.
     let attrs = docShell.getOriginAttributes();
     let ssm = Services.scriptSecurityManager;
     let nullPrincipal = ssm.createNullPrincipal(attrs);
 
-    let resolvedURI = Cc["@mozilla.org/network/io-service;1"].
-                      getService(Ci.nsIIOService).
-                      newChannel2("about:feeds",
-                                  null,
-                                  null,
-                                  null, // aLoadingNode
-                                  nullPrincipal,
-                                  null, // aTriggeringPrincipal
-                                  Ci.nsILoadInfo.SEC_NORMAL,
-                                  Ci.nsIContentPolicy.TYPE_OTHER).URI;
+    // this channel is not going to be openend, use a nullPrincipal
+    // and the most restrctive securityFlag.
+    let resolvedURI = NetUtil.newChannel({
+      uri: "about:feeds",
+      loadingPrincipal: nullPrincipal,
+      securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
+      contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
+    }).URI;
 
     if (resolvedURI.equals(chan.URI))
       return chan.originalURI;
 
     return null;
   },
 
   _window: null,
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -11,19 +11,19 @@
 "size": 11189216,
 "digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "rustc 1.8.0 (db2939409 2016-04-11)",
-"size": 123218320,
-"digest": "7afcd7b39c4d5277db6b28951602aff4c698102ba45d3d811b353ca7446074beceebf03a2a529e323af19d73db4acbe96ec2bdad44def2e218ed36f55e82cab2",
+"version": "gecko rust 1.9.0 (commit e4e8b666850a763fdf1c3c2c142856ab51e32779)",
+"size": 96854912,
+"digest": "d613d5528e83bb73917372948c05a766912a9dd0ec4e8a5fab69161a515c1545d52e9ed3394716df96a9dcdf1c086b6f970413e97c2df78a11e5f9151573921a",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -11,19 +11,19 @@
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "rustc 1.8.0 (db2939409 2016-04-11)",
-"size": 123218320,
-"digest": "7afcd7b39c4d5277db6b28951602aff4c698102ba45d3d811b353ca7446074beceebf03a2a529e323af19d73db4acbe96ec2bdad44def2e218ed36f55e82cab2",
+"version": "gecko rust 1.9.0 (commit e4e8b666850a763fdf1c3c2c142856ab51e32779)",
+"size": 96854912,
+"digest": "d613d5528e83bb73917372948c05a766912a9dd0ec4e8a5fab69161a515c1545d52e9ed3394716df96a9dcdf1c086b6f970413e97c2df78a11e5f9151573921a",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/caps/nsIScriptSecurityManager.idl
+++ b/caps/nsIScriptSecurityManager.idl
@@ -121,21 +121,16 @@ interface nsIScriptSecurityManager : nsI
      * hence will check whether fixed-up versions of the URI are allowed to
      * load as well); if any of the versions of this URI is not allowed, this
      * function will return error code NS_ERROR_DOM_BAD_URI.
      */
     void checkLoadURIStrWithPrincipal(in nsIPrincipal aPrincipal,
                                       in AUTF8String uri,
                                       in unsigned long flags);
 
-    /**
-     * Return true if scripts may be executed in the scope of the given global.
-     */
-    [noscript,notxpcom] boolean scriptAllowed(in JSObjectPtr aGlobal);
-
     ///////////////// Principals ///////////////////////
 
     /**
      * Return the all-powerful system principal.
      */
     nsIPrincipal getSystemPrincipal();
 
     /**
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -222,30 +222,16 @@ public:
 private:
     nsIClassInfo *mClassInfo; // WEAK
     uint32_t mFlags;
     char *mName;
     bool mDidGetFlags;
     bool mMustFreeName;
 };
 
-JSContext *
-nsScriptSecurityManager::GetCurrentJSContext()
-{
-    // Get JSContext from stack.
-    return nsXPConnect::XPConnect()->GetCurrentJSContext();
-}
-
-JSContext *
-nsScriptSecurityManager::GetSafeJSContext()
-{
-    // Get JSContext from stack.
-    return nsXPConnect::XPConnect()->GetSafeJSContext();
-}
-
 /* static */
 bool
 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
                                              nsIURI* aTargetURI)
 {
     return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
 }
 
@@ -1107,26 +1093,16 @@ nsScriptSecurityManager::CheckLoadURIStr
             return rv;
         }
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return rv;
 }
 
-bool
-nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal)
-{
-    MOZ_ASSERT(aGlobal);
-    MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsWindowProxy(aGlobal));
-
-    // Check the bits on the compartment private.
-    return xpc::Scriptability::Get(aGlobal).Allowed();
-}
-
 ///////////////// Principals ///////////////////////
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
 {
     NS_ADDREF(*result = mSystemPrincipal);
 
     return NS_OK;
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -53,20 +53,16 @@ public:
     GetScriptSecurityManager();
 
     // Invoked exactly once, by XPConnect.
     static void InitStatics();
 
     static nsSystemPrincipal*
     SystemPrincipalSingletonConstructor();
 
-    JSContext* GetCurrentJSContext();
-
-    JSContext* GetSafeJSContext();
-
     /**
      * Utility method for comparing two URIs.  For security purposes, two URIs
      * are equivalent if their schemes, hosts, and ports (if any) match.  This
      * method returns true if aSubjectURI and aObjectURI have the same origin,
      * false otherwise.
      */
     static bool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
     static uint32_t SecurityHashURI(nsIURI* aURI);
--- a/chrome/RegistryMessageUtils.h
+++ b/chrome/RegistryMessageUtils.h
@@ -73,17 +73,17 @@ struct ParamTraits<SerializedURI>
   typedef SerializedURI paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.spec);
     WriteParam(aMsg, aParam.charset);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     nsCString spec, charset;
     if (ReadParam(aMsg, aIter, &spec) &&
         ReadParam(aMsg, aIter, &charset)) {
       aResult->spec = spec;
       aResult->charset = charset;
       return true;
     }
@@ -100,17 +100,17 @@ struct ParamTraits<ChromePackage>
   {
     WriteParam(aMsg, aParam.package);
     WriteParam(aMsg, aParam.contentBaseURI);
     WriteParam(aMsg, aParam.localeBaseURI);
     WriteParam(aMsg, aParam.skinBaseURI);
     WriteParam(aMsg, aParam.flags);
   }
   
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     nsCString package;
     SerializedURI contentBaseURI, localeBaseURI, skinBaseURI;
     uint32_t flags;
     
     if (ReadParam(aMsg, aIter, &package) &&
         ReadParam(aMsg, aIter, &contentBaseURI) &&
         ReadParam(aMsg, aIter, &localeBaseURI) &&
@@ -142,17 +142,17 @@ struct ParamTraits<SubstitutionMapping>
   
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.scheme);
     WriteParam(aMsg, aParam.path);
     WriteParam(aMsg, aParam.resolvedURI);
   }
   
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     nsCString scheme, path;
     SerializedURI resolvedURI;
     
     if (ReadParam(aMsg, aIter, &scheme) &&
         ReadParam(aMsg, aIter, &path) &&
         ReadParam(aMsg, aIter, &resolvedURI)) {
       aResult->scheme = scheme;
@@ -178,17 +178,17 @@ struct ParamTraits<OverrideMapping>
   typedef OverrideMapping paramType;
   
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.originalURI);
     WriteParam(aMsg, aParam.overrideURI);
   }
   
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     SerializedURI originalURI;
     SerializedURI overrideURI;
     
     if (ReadParam(aMsg, aIter, &originalURI) &&
         ReadParam(aMsg, aIter, &overrideURI)) {
       aResult->originalURI = originalURI;
       aResult->overrideURI = overrideURI;
--- a/devtools/client/responsivedesign/responsivedesign.jsm
+++ b/devtools/client/responsivedesign/responsivedesign.jsm
@@ -182,16 +182,22 @@ function ResponsiveUI(aWindow, aTab)
   this.bound_stopResizing = this.stopResizing.bind(this);
   this.bound_onDrag = this.onDrag.bind(this);
   this.bound_changeUA = this.changeUA.bind(this);
   this.bound_onContentResize = this.onContentResize.bind(this);
 
   this.mm.addMessageListener("ResponsiveMode:OnContentResize",
                              this.bound_onContentResize);
 
+  // We must be ready to handle window or tab close now that we have saved
+  // ourselves in ActiveTabs.  Otherwise we risk leaking the window.
+  this.mainWindow.addEventListener("unload", this);
+  this.tab.addEventListener("TabClose", this);
+  this.tabContainer.addEventListener("TabSelect", this);
+
   ActiveTabs.set(this.tab, this);
 
   this.inited = this.init();
 }
 
 ResponsiveUI.prototype = {
   _transitionsEnabled: true,
   get transitionsEnabled() {
@@ -221,20 +227,16 @@ ResponsiveUI.prototype = {
       // Tests expect events on resize to yield on various size changes
       notifyOnResize: DevToolsUtils.testing,
     });
     yield started;
 
     // Load Presets
     this.loadPresets();
 
-    // Events
-    this.tab.addEventListener("TabClose", this);
-    this.tabContainer.addEventListener("TabSelect", this);
-
     // Setup the UI
     this.container.setAttribute("responsivemode", "true");
     this.stack.setAttribute("responsivemode", "true");
     this.buildUI();
     this.checkMenus();
 
     // Rotate the responsive mode if needed
     try {
@@ -338,35 +340,38 @@ ResponsiveUI.prototype = {
     debug(`CURRENT SIZE: ${this.stack.getAttribute("style")}`);
     let style = "max-width: none;" +
                 "min-width: 0;" +
                 "max-height: none;" +
                 "min-height: 0;";
     debug("RESET STACK SIZE");
     this.stack.setAttribute("style", style);
 
-    // Wait for resize message before stopping in the child when testing
-    if (DevToolsUtils.testing) {
+    // Wait for resize message before stopping in the child when testing,
+    // but only if we should expect to still get a message.
+    if (DevToolsUtils.testing && this.tab.linkedBrowser.messageManager) {
       yield this.waitForMessage("ResponsiveMode:OnContentResize");
     }
 
     if (this.isResizing)
       this.stopResizing();
 
     // Remove listeners.
     this.menulist.removeEventListener("select", this.bound_presetSelected, true);
     this.menulist.removeEventListener("change", this.bound_handleManualInput, true);
+    this.mainWindow.removeEventListener("unload", this);
     this.tab.removeEventListener("TabClose", this);
     this.tabContainer.removeEventListener("TabSelect", this);
     this.rotatebutton.removeEventListener("command", this.bound_rotate, true);
     this.screenshotbutton.removeEventListener("command", this.bound_screenshot, true);
     this.closebutton.removeEventListener("command", this.bound_close, true);
     this.addbutton.removeEventListener("command", this.bound_addPreset, true);
     this.removebutton.removeEventListener("command", this.bound_removePreset, true);
     this.touchbutton.removeEventListener("command", this.bound_touch, true);
+    this.userAgentInput.removeEventListener("blur", this.bound_changeUA, true);
 
     // Removed elements.
     this.container.removeChild(this.toolbar);
     if (this.bottomToolbar) {
       this.bottomToolbar.remove();
       delete this.bottomToolbar;
     }
     this.stack.removeChild(this.resizer);
@@ -386,19 +391,21 @@ ResponsiveUI.prototype = {
 
     yield new Promise((resolve, reject) => {
       this.client.close(resolve);
       this.client = this.tabClient = null;
     });
 
     this._telemetry.toolClosed("responsive");
 
-    let stopped = this.waitForMessage("ResponsiveMode:Stop:Done");
-    this.tab.linkedBrowser.messageManager.sendAsyncMessage("ResponsiveMode:Stop");
-    yield stopped;
+    if (this.tab.linkedBrowser.messageManager) {
+      let stopped = this.waitForMessage("ResponsiveMode:Stop:Done");
+      this.tab.linkedBrowser.messageManager.sendAsyncMessage("ResponsiveMode:Stop");
+      yield stopped;
+    }
 
     this.inited = null;
     ResponsiveUIManager.emit("off", { tab: this.tab });
   }),
 
   waitForMessage(message) {
     return new Promise(resolve => {
       let listener = () => {
@@ -421,16 +428,17 @@ ResponsiveUI.prototype = {
   },
 
   /**
    * Handle events
    */
   handleEvent: function (aEvent) {
     switch (aEvent.type) {
       case "TabClose":
+      case "unload":
         this.close();
         break;
       case "TabSelect":
         if (this.tab.selected) {
           this.checkMenus();
         } else if (!this.mainWindow.gBrowser.selectedTab.responsiveUI) {
           this.unCheckMenus();
         }
@@ -444,17 +452,20 @@ ResponsiveUI.prototype = {
   checkMenus: function RUI_checkMenus() {
     this.chromeDoc.getElementById("menu_responsiveUI").setAttribute("checked", "true");
   },
 
   /**
    * Uncheck the menu items.
    */
   unCheckMenus: function RUI_unCheckMenus() {
-    this.chromeDoc.getElementById("menu_responsiveUI").setAttribute("checked", "false");
+    let el = this.chromeDoc.getElementById("menu_responsiveUI");
+    if (el) {
+      el.setAttribute("checked", "false");
+    }
   },
 
   /**
    * Build the toolbar and the resizers.
    *
    * <vbox class="browserContainer"> From tabbrowser.xml
    *  <toolbar class="devtools-responsiveui-toolbar">
    *    <menulist class="devtools-responsiveui-menulist"/> // presets
--- a/devtools/client/responsivedesign/test/browser.ini
+++ b/devtools/client/responsivedesign/test/browser.ini
@@ -12,8 +12,9 @@ support-files =
 skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
 [browser_responsiveruleview.js]
 skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
 [browser_responsiveui.js]
 [browser_responsiveui_touch.js]
 [browser_responsiveuiaddcustompreset.js]
 [browser_responsive_devicewidth.js]
 [browser_responsiveui_customuseragent.js]
+[browser_responsiveui_window_close.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsivedesign/test/browser_responsiveui_window_close.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(function* () {
+  let newWindowPromise = BrowserTestUtils.waitForNewWindow();
+  window.open("about:blank", "_blank");
+  let newWindow = yield newWindowPromise;
+
+  newWindow.focus();
+  yield once(newWindow.gBrowser, "load", true);
+
+  let tab = newWindow.gBrowser.selectedTab;
+  yield ResponsiveUIManager.runIfNeeded(newWindow, tab);
+
+  // Close the window on a tab with an active responsive design UI and
+  // wait for the UI to gracefully shutdown.  This has leaked the window
+  // in the past.
+  ok(ResponsiveUIManager.isActiveForTab(tab),
+     "ResponsiveUI should be active for tab when the window is closed");
+  let offPromise = once(ResponsiveUIManager, "off");
+  yield BrowserTestUtils.closeWindow(newWindow);
+  yield offPromise;
+});
--- a/devtools/shared/gcli/commands/cookie.js
+++ b/devtools/shared/gcli/commands/cookie.js
@@ -36,23 +36,29 @@ XPCOMUtils.defineLazyGetter(this, "cooki
 function sanitizeHost(host) {
   if (host == null || host == "") {
     throw new Error(l10n.lookup("cookieListOutNonePage"));
   }
   return host.split(":")[0];
 }
 
 /**
- * The cookie 'expires' value needs converting into something more readable
+ * The cookie 'expires' value needs converting into something more readable.
+ *
+ * And the unit of expires is sec, the unit that in argument of Date() needs 
+ * millisecond.
  */
 function translateExpires(expires) {
   if (expires == 0) {
     return l10n.lookup("cookieListOutSession");
   }
-  return new Date(expires).toLocaleString();
+
+  let expires_msec = expires * 1000;
+
+  return (new Date(expires_msec)).toLocaleString();
 }
 
 /**
  * Check if a given cookie matches a given host
  */
 function isCookieAtHost(cookie, host) {
   if (cookie.host == null) {
     return host == null;
--- a/docshell/base/SerializedLoadContext.h
+++ b/docshell/base/SerializedLoadContext.h
@@ -71,17 +71,17 @@ struct ParamTraits<SerializedLoadContext
     WriteParam(aMsg, aParam.mIsNotNull);
     WriteParam(aMsg, aParam.mIsContent);
     WriteParam(aMsg, aParam.mIsPrivateBitValid);
     WriteParam(aMsg, aParam.mUsePrivateBrowsing);
     WriteParam(aMsg, aParam.mUseRemoteTabs);
     WriteParam(aMsg, suffix);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     nsAutoCString suffix;
     if (!ReadParam(aMsg, aIter, &aResult->mIsNotNull) ||
         !ReadParam(aMsg, aIter, &aResult->mIsContent) ||
         !ReadParam(aMsg, aIter, &aResult->mIsPrivateBitValid) ||
         !ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing) ||
         !ReadParam(aMsg, aIter, &aResult->mUseRemoteTabs) ||
         !ReadParam(aMsg, aIter, &suffix)) {
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -3,16 +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/. */
 
 #include "Animation.h"
 #include "AnimationUtils.h"
 #include "mozilla/dom/AnimationBinding.h"
 #include "mozilla/dom/AnimationPlaybackEvent.h"
+#include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/AsyncEventDispatcher.h" // For AsyncEventDispatcher
 #include "mozilla/Maybe.h" // For Maybe
 #include "nsAnimationManager.h" // For CSSAnimation
 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
 #include "nsIDocument.h" // For nsIDocument
 #include "nsIPresShell.h" // For nsIPresShell
@@ -82,29 +83,42 @@ namespace {
 // ---------------------------------------------------------------------------
 //
 // Animation interface:
 //
 // ---------------------------------------------------------------------------
 /* static */ already_AddRefed<Animation>
 Animation::Constructor(const GlobalObject& aGlobal,
                        KeyframeEffectReadOnly* aEffect,
-                       AnimationTimeline* aTimeline,
+                       const Optional<AnimationTimeline*>& aTimeline,
                        ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<Animation> animation = new Animation(global);
 
   if (!aEffect) {
     // Bug 1049975: We do not support null effect yet.
     aRv.Throw(NS_ERROR_DOM_ANIM_NO_EFFECT_ERR);
     return nullptr;
   }
 
-  animation->SetTimeline(aTimeline);
+  AnimationTimeline* timeline;
+  if (aTimeline.WasPassed()) {
+    timeline = aTimeline.Value();
+  } else {
+    nsIDocument* document =
+      AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
+    if (!document) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    timeline = document->Timeline();
+  }
+
+  animation->SetTimeline(timeline);
   animation->SetEffect(aEffect);
 
   return animation.forget();
 }
 
 void
 Animation::SetId(const nsAString& aId)
 {
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -88,17 +88,17 @@ public:
     AutoRewind,
     Continue
   };
 
   // Animation interface methods
   static already_AddRefed<Animation>
   Constructor(const GlobalObject& aGlobal,
               KeyframeEffectReadOnly* aEffect,
-              AnimationTimeline* aTimeline,
+              const Optional<AnimationTimeline*>& aTimeline,
               ErrorResult& aRv);
   void GetId(nsAString& aResult) const { aResult = mId; }
   void SetId(const nsAString& aId);
   KeyframeEffectReadOnly* GetEffect() const { return mEffect; }
   void SetEffect(KeyframeEffectReadOnly* aEffect);
   AnimationTimeline* GetTimeline() const { return mTimeline; }
   void SetTimeline(AnimationTimeline* aTimeline);
   Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -1843,17 +1843,17 @@ ParamTraits<Metadata>::Write(Message* aM
     WriteParam(aMsg, entry.mFastHash);
     WriteParam(aMsg, entry.mNumChars);
     WriteParam(aMsg, entry.mFullHash);
     WriteParam(aMsg, entry.mModuleIndex);
   }
 }
 
 bool
-ParamTraits<Metadata>::Read(const Message* aMsg, void** aIter,
+ParamTraits<Metadata>::Read(const Message* aMsg, PickleIterator* aIter,
                             paramType* aResult)
 {
   for (unsigned i = 0; i < Metadata::kNumEntries; i++) {
     Metadata::Entry& entry = aResult->mEntries[i];
     if (!ReadParam(aMsg, aIter, &entry.mFastHash) ||
         !ReadParam(aMsg, aIter, &entry.mNumChars) ||
         !ReadParam(aMsg, aIter, &entry.mFullHash) ||
         !ReadParam(aMsg, aIter, &entry.mModuleIndex))
@@ -1882,17 +1882,17 @@ ParamTraits<WriteParams>::Write(Message*
   WriteParam(aMsg, aParam.mSize);
   WriteParam(aMsg, aParam.mFastHash);
   WriteParam(aMsg, aParam.mNumChars);
   WriteParam(aMsg, aParam.mFullHash);
   WriteParam(aMsg, aParam.mInstalled);
 }
 
 bool
-ParamTraits<WriteParams>::Read(const Message* aMsg, void** aIter,
+ParamTraits<WriteParams>::Read(const Message* aMsg, PickleIterator* aIter,
                                paramType* aResult)
 {
   return ReadParam(aMsg, aIter, &aResult->mSize) &&
          ReadParam(aMsg, aIter, &aResult->mFastHash) &&
          ReadParam(aMsg, aIter, &aResult->mNumChars) &&
          ReadParam(aMsg, aIter, &aResult->mFullHash) &&
          ReadParam(aMsg, aIter, &aResult->mInstalled);
 }
--- a/dom/asmjscache/AsmJSCache.h
+++ b/dom/asmjscache/AsmJSCache.h
@@ -164,26 +164,26 @@ struct ParamTraits<mozilla::dom::asmjsca
                                   mozilla::dom::asmjscache::NUM_OPEN_MODES>
 { };
 
 template <>
 struct ParamTraits<mozilla::dom::asmjscache::Metadata>
 {
   typedef mozilla::dom::asmjscache::Metadata paramType;
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
   static void Log(const paramType& aParam, std::wstring* aLog);
 };
 
 template <>
 struct ParamTraits<mozilla::dom::asmjscache::WriteParams>
 {
   typedef mozilla::dom::asmjscache::WriteParams paramType;
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
   static void Log(const paramType& aParam, std::wstring* aLog);
 };
 
 template <>
 struct ParamTraits<JS::AsmJSCacheResult> :
   public ContiguousEnumSerializer<JS::AsmJSCacheResult,
                                   JS::AsmJSCache_MIN,
                                   JS::AsmJSCache_LIMIT>
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3329,19 +3329,20 @@ Element::Animate(const Nullable<ElementO
   }
 
   RefPtr<KeyframeEffect> effect =
     KeyframeEffect::Constructor(global, aTarget, keyframes, aOptions, aError);
   if (aError.Failed()) {
     return nullptr;
   }
 
+  AnimationTimeline* timeline = referenceElement->OwnerDoc()->Timeline();
   RefPtr<Animation> animation =
     Animation::Constructor(global, effect,
-                           referenceElement->OwnerDoc()->Timeline(), aError);
+                           Optional<AnimationTimeline*>(timeline), aError);
   if (aError.Failed()) {
     return nullptr;
   }
 
   if (aOptions.IsKeyframeAnimationOptions()) {
     animation->SetId(aOptions.GetAsKeyframeAnimationOptions().mId);
   }
 
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -776,19 +776,17 @@ danger::AutoCxPusher::AutoCxPusher(JSCon
 
   // Hold a strong ref to the nsIScriptContext, if any. This ensures that we
   // only destroy the mContext of an nsJSContext when it is not on the cx stack
   // (and therefore not in use). See nsJSContext::DestroyJSContext().
   if (cx)
     mScx = GetScriptContextFromJSContext(cx);
 
   XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
-  if (!stack->Push(cx)) {
-    MOZ_CRASH();
-  }
+  stack->Push(cx);
   mStackDepthAfterPush = stack->Count();
 
 #ifdef DEBUG
   mPushedContext = cx;
   mCompartmentDepthOnEntry = cx ? js::GetEnterCompartmentDepth(cx) : 0;
 #endif
 
   // Enter a request and a compartment for the duration that the cx is on the
--- a/dom/base/contentAreaDropListener.js
+++ b/dom/base/contentAreaDropListener.js
@@ -115,16 +115,18 @@ ContentAreaDropListener.prototype =
     let sourceDocument = sourceNode.ownerDocument;
     let eventDocument = aEvent.originalTarget.ownerDocument;
     if (sourceDocument == eventDocument)
       return false;
 
     // also check for nodes in other child or sibling frames by checking
     // if both have the same top window.
     if (sourceDocument && eventDocument) {
+      if (sourceDocument.defaultView == null)
+        return true;
       let sourceRoot = sourceDocument.defaultView.top;
       if (sourceRoot && sourceRoot == eventDocument.defaultView.top)
         return false;
     }
 
     return true;
   },
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7419,17 +7419,18 @@ nsContentUtils::TransferableToIPCTransfe
             RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
               surface->GetDataSurface();
             if (!dataSurface) {
               continue;
             }
             size_t length;
             int32_t stride;
             mozilla::UniquePtr<char[]> surfaceData =
-              nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
+              nsContentUtils::GetSurfaceData(WrapNotNull(dataSurface), &length,
+                                             &stride);
 
             IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
             item->flavor() = flavorStr;
             // Turn item->data() into an nsCString prior to accessing it.
             item->data() = EmptyCString();
             item->data().get_nsCString().Adopt(surfaceData.release(), length);
 
             IPCDataTransferImage& imageDetails = item->imageDetails();
@@ -7523,18 +7524,19 @@ nsContentUtils::TransferableToIPCTransfe
           }
         }
       }
     }
   }
 }
 
 mozilla::UniquePtr<char[]>
-nsContentUtils::GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
-                               size_t* aLength, int32_t* aStride)
+nsContentUtils::GetSurfaceData(
+  NotNull<mozilla::gfx::DataSourceSurface*> aSurface,
+  size_t* aLength, int32_t* aStride)
 {
   mozilla::gfx::DataSourceSurface::MappedSurface map;
   if (NS_WARN_IF(!aSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map))) {
     return nullptr;
   }
   mozilla::gfx::IntSize size = aSurface->GetSize();
   mozilla::CheckedInt32 requiredBytes =
     mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -27,16 +27,17 @@
 #include "nsMathUtils.h"
 #include "nsTArrayForwardDeclare.h"
 #include "Units.h"
 #include "mozilla/dom/AutocompleteInfoBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "mozilla/Logging.h"
+#include "mozilla/NotNull.h"
 #include "nsIContentPolicy.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
 class imgICache;
@@ -2427,18 +2428,19 @@ public:
                                             bool aInSyncMessage,
                                             mozilla::dom::nsIContentChild* aChild,
                                             mozilla::dom::nsIContentParent* aParent);
 
   /*
    * Get the pixel data from the given source surface and return it as a buffer.
    * The length and stride will be assigned from the surface.
    */
-  static mozilla::UniquePtr<char[]> GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
-                                                   size_t* aLength, int32_t* aStride);
+  static mozilla::UniquePtr<char[]> GetSurfaceData(
+    mozilla::NotNull<mozilla::gfx::DataSourceSurface*> aSurface,
+    size_t* aLength, int32_t* aStride);
 
   // Helpers shared by the implementations of nsContentUtils methods and
   // nsIDOMWindowUtils methods.
   static mozilla::Modifiers GetWidgetModifiers(int32_t aModifiers);
   static nsIWidget* GetWidget(nsIPresShell* aPresShell, nsPoint* aOffset);
   static int16_t GetButtonsFlagForButton(int32_t aButton);
   static mozilla::LayoutDeviceIntPoint ToWidgetPoint(const mozilla::CSSPoint& aPoint,
                                                      const nsPoint& aOffset,
--- a/dom/base/nsDOMJSUtils.h
+++ b/dom/base/nsDOMJSUtils.h
@@ -25,18 +25,16 @@ GetScriptContextFromJSContext(JSContext 
     do_QueryInterface(static_cast<nsISupports *>
                                  (::JS_GetContextPrivate(cx)));
 
   // This will return a pointer to something that's about to be
   // released, but that's ok here.
   return scx;
 }
 
-JSObject* GetDefaultScopeFromJSContext(JSContext *cx);
-
 // A factory function for turning a JS::Value argv into an nsIArray
 // but also supports an effecient way of extracting the original argv.
 // The resulting object will take a copy of the array, and ensure each
 // element is rooted.
 // Optionally, aArgv may be nullptr, in which case the array is allocated and
 // rooted, but all items remain nullptr.  This presumably means the caller
 // will then QI us for nsIJSArgArray, and set our array elements.
 nsresult NS_CreateJSArgv(JSContext *aContext, uint32_t aArgc,
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -133,16 +133,17 @@
 #include "nsIDateTimeFormat.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "nsDOMCID.h"
 
 #include "jsapi.h"
 #include "nsIXPConnect.h"
+#include "xpcpublic.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsICategoryManager.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIDocumentLoader.h"
 #include "nsIContentViewer.h"
 #include "nsIXMLContentSink.h"
@@ -8467,28 +8468,25 @@ bool
 nsDocument::IsScriptEnabled()
 {
   // If this document is sandboxed without 'allow-scripts'
   // script is not enabled
   if (mSandboxFlags & SANDBOXED_SCRIPTS) {
     return false;
   }
 
-  nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
-  NS_ENSURE_TRUE(sm, false);
-
   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow());
   if (!globalObject && mMasterDocument) {
     globalObject = do_QueryInterface(mMasterDocument->GetInnerWindow());
   }
   if (!globalObject || !globalObject->GetGlobalJSObject()) {
     return false;
   }
 
-  return sm->ScriptAllowed(globalObject->GetGlobalJSObject());
+  return xpc::Scriptability::Get(globalObject->GetGlobalJSObject()).Allowed();
 }
 
 nsRadioGroupStruct*
 nsDocument::GetRadioGroupInternal(const nsAString& aName) const
 {
 #ifdef DEBUG
   if (IsHTMLDocument()) {
     nsAutoString lcName;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8106,33 +8106,31 @@ nsGlobalWindow::Open(const nsAString& aU
                    NS_ERROR_NOT_INITIALIZED);
   return OpenInternal(aUrl, aName, aOptions,
                       false,          // aDialog
                       false,          // aContentModal
                       true,           // aCalledNoScript
                       false,          // aDoJSFixups
                       true,           // aNavigate
                       nullptr, nullptr,  // No args
-                      nullptr,           // aJSCallerContext
                       _retval);
 }
 
 nsresult
 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
                        const nsAString& aOptions, nsPIDOMWindowOuter **_retval)
 {
   MOZ_ASSERT(IsOuterWindow());
   return OpenInternal(aUrl, aName, aOptions,
                       false,          // aDialog
                       false,          // aContentModal
                       false,          // aCalledNoScript
                       true,           // aDoJSFixups
                       true,           // aNavigate
                       nullptr, nullptr,  // No args
-                      nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
                       _retval);
 }
 
 // like Open, but attaches to the new window any extra parameters past
 // [features] as a JS property named "arguments"
 nsresult
 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
                            const nsAString& aOptions,
@@ -8142,17 +8140,16 @@ nsGlobalWindow::OpenDialog(const nsAStri
   MOZ_ASSERT(IsOuterWindow());
   return OpenInternal(aUrl, aName, aOptions,
                       true,                    // aDialog
                       false,                   // aContentModal
                       true,                    // aCalledNoScript
                       false,                   // aDoJSFixups
                       true,                    // aNavigate
                       nullptr, aExtraArgument,    // Arguments
-                      nullptr,                    // aJSCallerContext
                       _retval);
 }
 
 // Like Open, but passes aNavigate=false.
 /* virtual */ nsresult
 nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl,
                                const nsAString& aName,
                                const nsAString& aOptions,
@@ -8161,17 +8158,16 @@ nsGlobalWindow::OpenNoNavigate(const nsA
   MOZ_ASSERT(IsOuterWindow());
   return OpenInternal(aUrl, aName, aOptions,
                       false,          // aDialog
                       false,          // aContentModal
                       true,           // aCalledNoScript
                       false,          // aDoJSFixups
                       false,          // aNavigate
                       nullptr, nullptr,  // No args
-                      nullptr,           // aJSCallerContext
                       _retval);
 
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindow::OpenDialogOuter(JSContext* aCx, const nsAString& aUrl,
                                 const nsAString& aName, const nsAString& aOptions,
                                 const Sequence<JS::Value>& aExtraArgument,
@@ -8190,17 +8186,16 @@ nsGlobalWindow::OpenDialogOuter(JSContex
   nsCOMPtr<nsPIDOMWindowOuter> dialog;
   aError = OpenInternal(aUrl, aName, aOptions,
                         true,             // aDialog
                         false,            // aContentModal
                         false,            // aCalledNoScript
                         false,            // aDoJSFixups
                         true,                // aNavigate
                         argvArray, nullptr,  // Arguments
-                        aCx,                 // aJSCallerContext
                         getter_AddRefs(dialog));
   return dialog.forget();
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindow::OpenDialog(JSContext* aCx, const nsAString& aUrl,
                            const nsAString& aName, const nsAString& aOptions,
                            const Sequence<JS::Value>& aExtraArgument,
@@ -8628,23 +8623,24 @@ nsGlobalWindow::FinalClose()
   // This stuff is non-sensical but incredibly fragile. The reasons for the
   // behavior here don't make sense today and may not have ever made sense,
   // but various bits of frontend code break when you change them. If you need
   // to fix up this behavior, feel free to. It's a righteous task, but involves
   // wrestling with various download manager tests, frontend code, and possible
   // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
   // testing ground.
   //
-  // In particular, if |win|'s JSContext is at the top of the stack, we must
+  // In particular, if some inner of |win| is the entry global, we must
   // complete _two_ round-trips to the event loop before the call to
   // ReallyCloseWindow. This allows setTimeout handlers that are set after
   // FinalClose() is called to run before the window is torn down.
-  bool indirect = GetContextInternal() && // Occasionally null. See bug 877390.
-                  (nsContentUtils::GetCurrentJSContext() ==
-                   GetContextInternal()->GetNativeContext());
+  nsCOMPtr<nsPIDOMWindowInner> entryWindow =
+    do_QueryInterface(GetEntryGlobal());
+  bool indirect =
+    entryWindow && entryWindow->GetOuterWindow() == this->AsOuter();
   if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
     ReallyCloseWindow();
   } else {
     mHavePendingClose = true;
   }
 }
 
 
@@ -9270,17 +9266,16 @@ nsGlobalWindow::ShowModalDialogOuter(con
   nsContentUtils::SetMicroTaskLevel(0);
   aError = OpenInternal(aUrl, EmptyString(), options,
                         false,          // aDialog
                         true,           // aContentModal
                         true,           // aCalledNoScript
                         true,           // aDoJSFixups
                         true,           // aNavigate
                         nullptr, argHolder, // args
-                        nullptr,            // aJSCallerContext
                         getter_AddRefs(dlgWin));
   nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);
   LeaveModalState();
   if (aError.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin);
@@ -11739,32 +11734,29 @@ public:
 
 nsresult
 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
                              const nsAString& aOptions, bool aDialog,
                              bool aContentModal, bool aCalledNoScript,
                              bool aDoJSFixups, bool aNavigate,
                              nsIArray *argv,
                              nsISupports *aExtraArgument,
-                             JSContext *aJSCallerContext,
                              nsPIDOMWindowOuter **aReturn)
 {
   MOZ_ASSERT(IsOuterWindow());
 
 #ifdef DEBUG
   uint32_t argc = 0;
   if (argv)
       argv->GetLength(&argc);
 #endif
   NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
                   "Can't pass in arguments both ways");
   NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
                   "Can't pass JS args when called via the noscript methods");
-  NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
-                  "Shouldn't have caller context when called noscript");
 
   mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
 
   // Calls to window.open from script should navigate.
   MOZ_ASSERT(aCalledNoScript || aNavigate);
 
   *aReturn = nullptr;
 
@@ -11815,23 +11807,28 @@ nsGlobalWindow::OpenInternal(const nsASt
 
   if (NS_FAILED(rv))
     return rv;
 
   PopupControlState abuseLevel = gPopupControlState;
   if (checkForPopup) {
     abuseLevel = RevisePopupAbuseLevel(abuseLevel);
     if (abuseLevel >= openAbused) {
-      if (aJSCallerContext) {
+      if (!aCalledNoScript) {
         // If script in some other window is doing a window.open on us and
         // it's being blocked, then it's OK to close us afterwards, probably.
         // But if we're doing a window.open on ourselves and block the popup,
         // prevent this window from closing until after this script terminates
         // so that whatever popup blocker UI the app has will be visible.
-        if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
+        nsCOMPtr<nsPIDOMWindowInner> entryWindow =
+          do_QueryInterface(GetEntryGlobal());
+        // Note that entryWindow can be null here if some JS component was the
+        // place where script was entered for this JS execution.
+        if (entryWindow &&
+            entryWindow->GetOuterWindow() == this->AsOuter()) {
           mBlockScriptedClosingFlag = true;
           closeUnblocker.emplace(this);
         }
       }
 
       FireAbuseEvents(aUrl, aName, aOptions);
       return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
     }
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1426,34 +1426,30 @@ private:
    *        three args, if present, will be aUrl, aName, and aOptions.  So this
    *        param only matters if there are more than 3 arguments.
    *
    * @param argc The number of arguments in argv.
    *
    * @param aExtraArgument Another way to pass arguments in.  This is mutually
    *        exclusive with the argv/argc approach.
    *
-   * @param aJSCallerContext The calling script's context. This must be null
-   *        when aCalledNoScript is true.
-   *
    * @param aReturn [out] The window that was opened, if any.
    *
    * Outer windows only.
    */
   nsresult OpenInternal(const nsAString& aUrl,
                         const nsAString& aName,
                         const nsAString& aOptions,
                         bool aDialog,
                         bool aContentModal,
                         bool aCalledNoScript,
                         bool aDoJSFixups,
                         bool aNavigate,
                         nsIArray *argv,
                         nsISupports *aExtraArgument,
-                        JSContext *aJSCallerContext,
                         nsPIDOMWindowOuter **aReturn);
 
 public:
   // Timeout Functions
   // Language agnostic timeout function (all args passed).
   // |interval| is in milliseconds.
   nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
                                 int32_t interval,
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -169,18 +169,17 @@ nsJSUtils::EvaluateString(JSContext* aCx
   // cases.  So we need to be explicitly told whether the caller cares about the
   // return value.  Callers can do this by calling the other overload of
   // EvaluateString() which calls this function with
   // aCompileOptions.noScriptRval set to true.
   aRetValue.setUndefined();
 
   nsresult rv = NS_OK;
 
-  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-  NS_ENSURE_TRUE(ssm->ScriptAllowed(aEvaluationGlobal), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
 
   bool ok = true;
   // Scope the JSAutoCompartment so that we can later wrap the return value
   // into the caller's cx.
   {
     JSAutoCompartment ac(aCx, aEvaluationGlobal);
 
     // Now make sure to wrap the scope chain into the right compartment.
@@ -289,18 +288,17 @@ nsJSUtils::CompileModule(JSContext* aCx,
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(aSrcBuf.get());
   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) ==
              aEvaluationGlobal);
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(nsContentUtils::IsInMicroTask());
 
-  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-  NS_ENSURE_TRUE(ssm->ScriptAllowed(aEvaluationGlobal), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
 
   if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -311,19 +309,17 @@ nsJSUtils::ModuleDeclarationInstantiatio
     js::ProfileEntry::Category::JS);
 
   MOZ_ASSERT(JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting(),
              "Caller must own error reporting");
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(nsContentUtils::IsInMicroTask());
 
-  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-  JSObject* global = JS_GetGlobalForObject(aCx, aModule);
-  NS_ENSURE_TRUE(ssm->ScriptAllowed(global), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
 
   if (!JS::ModuleDeclarationInstantiation(aCx, aModule)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -334,19 +330,17 @@ nsJSUtils::ModuleEvaluation(JSContext* a
     js::ProfileEntry::Category::JS);
 
   MOZ_ASSERT(JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting(),
              "Caller must own error reporting");
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(nsContentUtils::IsInMicroTask());
 
-  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-  JSObject* global = JS_GetGlobalForObject(aCx, aModule);
-  NS_ENSURE_TRUE(ssm->ScriptAllowed(global), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
 
   if (!JS::ModuleEvaluation(aCx, aModule)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -376,25 +370,16 @@ nsJSUtils::ResetTimeZone()
 {
   JS::ResetTimeZone();
 }
 
 //
 // nsDOMJSUtils.h
 //
 
-JSObject* GetDefaultScopeFromJSContext(JSContext *cx)
-{
-  // DOM JSContexts don't store their default compartment object on
-  // the cx, so in those cases we need to fetch it via the scx
-  // instead.
-  nsIScriptContext *scx = GetScriptContextFromJSContext(cx);
-  return  scx ? scx->GetWindowProxy() : nullptr;
-}
-
 bool nsAutoJSString::init(const JS::Value &v)
 {
   JSContext* cx = nsContentUtils::RootingCxForThread();
   if (!init(nsContentUtils::RootingCxForThread(), v)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1997,17 +1997,17 @@ nsScriptLoader::EvaluateScript(nsScriptL
       // execution currentScript of the master should refer to this
       // script. So let's update the mCurrentScript of the ScriptLoader
       // of the master document too.
       masterScriptUpdater.emplace(master->ScriptLoader(),
                                   aRequest->mElement);
     }
 
     if (aRequest->IsModuleRequest()) {
-      rv = EnsureModuleResolveHook(context->GetNativeContext());
+      rv = EnsureModuleResolveHook(aes.cx());
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsModuleLoadRequest* request = aRequest->AsModuleRequest();
       MOZ_ASSERT(request->mModuleScript);
       MOZ_ASSERT(!request->mOffThreadToken);
       JS::Rooted<JSObject*> module(aes.cx(),
                                    request->mModuleScript->ModuleRecord());
       MOZ_ASSERT(module);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -168,17 +168,17 @@ ErrorResult::SerializeMessage(IPC::Messa
   using namespace IPC;
   MOZ_ASSERT(mUnionState == HasMessage);
   MOZ_ASSERT(mMessage);
   WriteParam(aMsg, mMessage->mArgs);
   WriteParam(aMsg, mMessage->mErrorNumber);
 }
 
 bool
-ErrorResult::DeserializeMessage(const IPC::Message* aMsg, void** aIter)
+ErrorResult::DeserializeMessage(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   using namespace IPC;
   nsAutoPtr<Message> readMessage(new Message());
   if (!ReadParam(aMsg, aIter, &readMessage->mArgs) ||
       !ReadParam(aMsg, aIter, &readMessage->mErrorNumber)) {
     return false;
   }
   if (!readMessage->HasCorrectNumberOfArguments()) {
@@ -290,17 +290,17 @@ ErrorResult::SerializeDOMExceptionInfo(I
   using namespace IPC;
   MOZ_ASSERT(mDOMExceptionInfo);
   MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
   WriteParam(aMsg, mDOMExceptionInfo->mMessage);
   WriteParam(aMsg, mDOMExceptionInfo->mRv);
 }
 
 bool
-ErrorResult::DeserializeDOMExceptionInfo(const IPC::Message* aMsg, void** aIter)
+ErrorResult::DeserializeDOMExceptionInfo(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   using namespace IPC;
   nsCString message;
   nsresult rv;
   if (!ReadParam(aMsg, aIter, &message) ||
       !ReadParam(aMsg, aIter, &rv)) {
     return false;
   }
@@ -2177,17 +2177,17 @@ InterfaceHasInstance(JSContext* cx, JS::
   if (domClass &&
       domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
     *bp = true;
     return true;
   }
 
   if (jsipc::IsWrappedCPOW(instance)) {
     bool boolp = false;
-    if (!jsipc::DOMInstanceOf(cx, js::CheckedUnwrap(instance), clasp->mPrototypeID,
+    if (!jsipc::DOMInstanceOf(cx, js::UncheckedUnwrap(instance), clasp->mPrototypeID,
                               clasp->mDepth, &boolp)) {
       return false;
     }
     *bp = boolp;
     return true;
   }
 
   JS::Rooted<JS::Value> protov(cx);
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -7,17 +7,16 @@
 #include "mozilla/dom/CallbackObject.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "jsfriendapi.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIXPConnect.h"
 #include "nsIScriptContext.h"
 #include "nsPIDOMWindow.h"
 #include "nsJSUtils.h"
-#include "nsIScriptSecurityManager.h"
 #include "xpcprivate.h"
 #include "WorkerPrivate.h"
 #include "nsGlobalWindow.h"
 #include "WorkerScope.h"
 #include "jsapi.h"
 #include "nsJSPrincipals.h"
 
 namespace mozilla {
@@ -172,18 +171,17 @@ CallbackObject::CallSetup::CallSetup(Cal
   }
 
   // JS-implemented WebIDL is always OK to run, since it runs with Chrome
   // privileges anyway.
   if (mIsMainThread && !aIsJSImplementedWebIDL) {
     // Check that it's ok to run this callback at all.
     // Make sure to use realCallback to get the global of the callback object,
     // not the wrapper.
-    bool allowed = nsContentUtils::GetSecurityManager()->
-      ScriptAllowed(js::GetGlobalForObjectCrossCompartment(realCallback));
+    bool allowed = xpc::Scriptability::Get(realCallback).Allowed();
 
     if (!allowed) {
       aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
         NS_LITERAL_CSTRING("Refusing to execute function from global in which "
                            "script is disabled."));
       return;
     }
   }
--- a/dom/bindings/ErrorIPCUtils.h
+++ b/dom/bindings/ErrorIPCUtils.h
@@ -45,17 +45,17 @@ struct ParamTraits<mozilla::ErrorResult>
     WriteParam(aMsg, aParam.IsDOMException());
     if (aParam.IsErrorWithMessage()) {
       aParam.SerializeMessage(aMsg);
     } else if (aParam.IsDOMException()) {
       aParam.SerializeDOMExceptionInfo(aMsg);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     paramType readValue;
     if (!ReadParam(aMsg, aIter, &readValue.mResult)) {
       return false;
     }
     bool hasMessage = false;
     if (!ReadParam(aMsg, aIter, &hasMessage)) {
       return false;
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -31,16 +31,17 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/Move.h"
 #include "nsTArray.h"
 
 namespace IPC {
 class Message;
 template <typename> struct ParamTraits;
 } // namespace IPC
+class PickleIterator;
 
 namespace mozilla {
 
 namespace dom {
 
 enum ErrNum {
 #define MSG_DEF(_name, _argc, _exn, _str) \
   _name,
@@ -302,20 +303,20 @@ private:
     HasDOMExceptionInfo,
     HasJSException,
     HasNothing
   };
 #endif // DEBUG
 
   friend struct IPC::ParamTraits<ErrorResult>;
   void SerializeMessage(IPC::Message* aMsg) const;
-  bool DeserializeMessage(const IPC::Message* aMsg, void** aIter);
+  bool DeserializeMessage(const IPC::Message* aMsg, PickleIterator* aIter);
 
   void SerializeDOMExceptionInfo(IPC::Message* aMsg) const;
-  bool DeserializeDOMExceptionInfo(const IPC::Message* aMsg, void** aIter);
+  bool DeserializeDOMExceptionInfo(const IPC::Message* aMsg, PickleIterator* aIter);
 
   // Helper method that creates a new Message for this ErrorResult,
   // and returns the arguments array from that Message.
   nsTArray<nsString>& CreateErrorMessageHelper(const dom::ErrNum errorNumber, nsresult errorType);
 
   template<dom::ErrNum errorNumber, typename... Ts>
   void ThrowErrorWithMessage(nsresult errorType, Ts&&... messageArgs)
   {
--- a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
@@ -10,17 +10,17 @@
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuidHelper.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/BluetoothMapParametersBinding.h"
 #include "mozilla/dom/ipc/BlobParent.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/dom/File.h"
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIInputStream.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
--- a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
@@ -8,17 +8,17 @@
 #include "BluetoothPbapManager.h"
 
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuidHelper.h"
 
 #include "mozilla/dom/BluetoothPbapParametersBinding.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIInputStream.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
--- a/dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothSocketMessageWatcher.h"
 #include <errno.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include "BluetoothInterface.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "nsClassHashtable.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // SocketMessageWatcherWrapper
 //
 
--- a/dom/bluetooth/common/BluetoothCommon.h
+++ b/dom/bluetooth/common/BluetoothCommon.h
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_BluetoothCommon_h
 #define mozilla_dom_bluetooth_BluetoothCommon_h
 
 #include <algorithm>
 #include "mozilla/Compiler.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/Observer.h"
 #include "mozilla/UniquePtr.h"
 #include "nsPrintfCString.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 extern bool gBluetoothDebugFlag;
 
--- a/dom/bluetooth/common/ObexBase.h
+++ b/dom/bluetooth/common/ObexBase.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_dom_bluetooth_ObexBase_h
 #define mozilla_dom_bluetooth_ObexBase_h
 
 #include "BluetoothCommon.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/UniquePtr.h"
 #include "nsTArray.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 const char FINAL_BIT = 0x80;
 
 /**
--- a/dom/bluetooth/ipc/BluetoothMessageUtils.h
+++ b/dom/bluetooth/ipc/BluetoothMessageUtils.h
@@ -19,17 +19,17 @@ struct ParamTraits<mozilla::dom::bluetoo
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(aParam.mAddr); ++i) {
       WriteParam(aMsg, aParam.mAddr[i]);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(aResult->mAddr); ++i) {
       if (!ReadParam(aMsg, aIter, aResult->mAddr + i)) {
         return false;
       }
     }
     return true;
   }
@@ -56,17 +56,17 @@ struct ParamTraits<mozilla::dom::bluetoo
     }
 
     WriteParam(aMsg, length);
     for (uint8_t i = 0; i < length; ++i) {
       WriteParam(aMsg, aParam.mPinCode[i]);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &aResult->mLength)) {
       return false;
     }
 
     auto maxLength = MOZ_ARRAY_LENGTH(aResult->mPinCode);
 
     if (aResult->mLength > maxLength) {
@@ -92,17 +92,17 @@ struct ParamTraits<mozilla::dom::bluetoo
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mLength);
     for (size_t i = 0; i < aParam.mLength; ++i) {
       WriteParam(aMsg, aParam.mName[i]);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &aResult->mLength)) {
       return false;
     }
     if (aResult->mLength > MOZ_ARRAY_LENGTH(aResult->mName)) {
       return false;
     }
     for (uint8_t i = 0; i < aResult->mLength; ++i) {
@@ -153,17 +153,17 @@ struct ParamTraits<mozilla::dom::bluetoo
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     for (uint8_t i = 0; i < 16; i++) {
       WriteParam(aMsg, aParam.mUuid[i]);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     for (uint8_t i = 0; i < 16; i++) {
       if (!ReadParam(aMsg, aIter, &(aResult->mUuid[i]))) {
         return false;
       }
     }
 
     return true;
@@ -176,17 +176,17 @@ struct ParamTraits<mozilla::dom::bluetoo
   typedef mozilla::dom::bluetooth::BluetoothGattId paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mUuid);
     WriteParam(aMsg, aParam.mInstanceId);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mUuid)) ||
         !ReadParam(aMsg, aIter, &(aResult->mInstanceId))) {
       return false;
     }
 
     return true;
   }
@@ -198,17 +198,17 @@ struct ParamTraits<mozilla::dom::bluetoo
   typedef mozilla::dom::bluetooth::BluetoothGattServiceId paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mId);
     WriteParam(aMsg, aParam.mIsPrimary);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIsPrimary))) {
       return false;
     }
 
     return true;
   }
@@ -221,17 +221,17 @@ struct ParamTraits<mozilla::dom::bluetoo
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mId);
     WriteParam(aMsg, aParam.mProperties);
     WriteParam(aMsg, aParam.mWriteType);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mProperties)) ||
         !ReadParam(aMsg, aIter, &(aResult->mWriteType))) {
       return false;
     }
 
     return true;
@@ -243,17 +243,17 @@ struct ParamTraits<mozilla::dom::bluetoo
 {
   typedef mozilla::dom::bluetooth::BluetoothAttributeHandle paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mHandle);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mHandle))) {
       return false;
     }
 
     return true;
   }
 };
@@ -274,17 +274,17 @@ struct ParamTraits<mozilla::dom::bluetoo
     WriteParam(aMsg, aParam.mOffset);
     WriteParam(aMsg, length);
     WriteParam(aMsg, aParam.mAuthReq);
     for (uint16_t i = 0; i < length; i++) {
       WriteParam(aMsg, aParam.mValue[i]);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mHandle)) ||
         !ReadParam(aMsg, aIter, &(aResult->mOffset)) ||
         !ReadParam(aMsg, aIter, &(aResult->mLength)) ||
         !ReadParam(aMsg, aIter, &(aResult->mAuthReq))) {
       return false;
     }
 
@@ -307,17 +307,17 @@ struct ParamTraits<mozilla::dom::bluetoo
 {
   typedef mozilla::dom::bluetooth::ControlPlayStatus paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<uint8_t>(aParam));
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     uint8_t value;
     if (!ReadParam(aMsg, aIter, &value)) {
       return false;
     }
 
     mozilla::dom::bluetooth::ControlPlayStatus result =
       static_cast<mozilla::dom::bluetooth::ControlPlayStatus>(value);
@@ -347,17 +347,17 @@ struct ParamTraits<mozilla::dom::bluetoo
     WriteParam(aMsg, aParam.mAppearance);
     WriteParam(aMsg, aParam.mIncludeDevName);
     WriteParam(aMsg, aParam.mIncludeTxPower);
     WriteParam(aMsg, aParam.mManufacturerData);
     WriteParam(aMsg, aParam.mServiceData);
     WriteParam(aMsg, aParam.mServiceUuids);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mAppearance)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIncludeDevName)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIncludeTxPower)) ||
         !ReadParam(aMsg, aIter, &(aResult->mManufacturerData)) ||
         !ReadParam(aMsg, aIter, &(aResult->mServiceData)) ||
         !ReadParam(aMsg, aIter, &(aResult->mServiceUuids))) {
       return false;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -77,17 +77,17 @@
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/PatternHelpers.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/ipc/PDocumentRendererParent.h"
 #include "mozilla/layers/PersistentBufferProvider.h"
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -45,17 +45,17 @@
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 
 namespace mozilla {
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
--- a/dom/canvas/WebGLContextTextures.cpp
+++ b/dom/canvas/WebGLContextTextures.cpp
@@ -42,17 +42,17 @@
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 namespace mozilla {
 
 static bool
 IsValidTexTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexTarget,
                  TexTarget* const out)
 {
     uint8_t targetDims;
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -1164,17 +1164,17 @@ Event::Serialize(IPC::Message* aMsg, boo
   IPC::WriteParam(aMsg, Bubbles());
   IPC::WriteParam(aMsg, Cancelable());
   IPC::WriteParam(aMsg, IsTrusted());
 
   // No timestamp serialization for now!
 }
 
 NS_IMETHODIMP_(bool)
-Event::Deserialize(const IPC::Message* aMsg, void** aIter)
+Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   nsString type;
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
 
   bool bubbles = false;
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
 
   bool cancelable = false;
--- a/dom/events/NotifyPaintEvent.cpp
+++ b/dom/events/NotifyPaintEvent.cpp
@@ -135,17 +135,17 @@ NotifyPaintEvent::Serialize(IPC::Message
   IPC::WriteParam(aMsg, length);
   for (uint32_t i = 0; i < length; ++i) {
     IPC::WriteParam(aMsg, mInvalidateRequests[i].mRect);
     IPC::WriteParam(aMsg, mInvalidateRequests[i].mFlags);
   }
 }
 
 NS_IMETHODIMP_(bool)
-NotifyPaintEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+NotifyPaintEvent::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   NS_ENSURE_TRUE(Event::Deserialize(aMsg, aIter), false);
 
   uint32_t length = 0;
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &length), false);
   mInvalidateRequests.SetCapacity(length);
   for (uint32_t i = 0; i < length; ++i) {
     nsInvalidateRequestList::Request req;
--- a/dom/events/NotifyPaintEvent.h
+++ b/dom/events/NotifyPaintEvent.h
@@ -38,17 +38,17 @@ public:
 
   // Forward to base class
   NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData() override
   {
     return Event::DuplicatePrivateData();
   }
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) override;
-  NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter) override;
+  NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, PickleIterator* aIter) override;
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return NotifyPaintEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   already_AddRefed<DOMRectList> ClientRects();
 
--- a/dom/events/ScrollAreaEvent.cpp
+++ b/dom/events/ScrollAreaEvent.cpp
@@ -55,17 +55,17 @@ ScrollAreaEvent::Serialize(IPC::Message*
 
   IPC::WriteParam(aMsg, X());
   IPC::WriteParam(aMsg, Y());
   IPC::WriteParam(aMsg, Width());
   IPC::WriteParam(aMsg, Height());
 }
 
 NS_IMETHODIMP_(bool)
-ScrollAreaEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+ScrollAreaEvent::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   NS_ENSURE_TRUE(Event::Deserialize(aMsg, aIter), false);
 
   float x, y, width, height;
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &x), false);
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &y), false);
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &width), false);
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &height), false);
--- a/dom/events/ScrollAreaEvent.h
+++ b/dom/events/ScrollAreaEvent.h
@@ -28,17 +28,17 @@ public:
   NS_FORWARD_NSIDOMUIEVENT(UIEvent::)
 
   NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData() override
   {
     return Event::DuplicatePrivateData();
   }
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) override;
-  NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter) override;
+  NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, PickleIterator* aIter) override;
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return ScrollAreaEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   float X() const
   {
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -393,17 +393,17 @@ UIEvent::Serialize(IPC::Message* aMsg, b
   Event::Serialize(aMsg, false);
 
   int32_t detail = 0;
   GetDetail(&detail);
   IPC::WriteParam(aMsg, detail);
 }
 
 NS_IMETHODIMP_(bool)
-UIEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+UIEvent::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   NS_ENSURE_TRUE(Event::Deserialize(aMsg, aIter), false);
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &mDetail), false);
   return true;
 }
 
 // XXX Following struct and array are used only in
 //     UIEvent::ComputeModifierState(), but if we define them in it,
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -33,17 +33,17 @@ public:
 
   // nsIDOMUIEvent Interface
   NS_DECL_NSIDOMUIEVENT
 
   // Forward to Event
   NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData() override;
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) override;
-  NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter) override;
+  NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, PickleIterator* aIter) override;
 
 
   static already_AddRefed<UIEvent> Constructor(const GlobalObject& aGlobal,
                                                const nsAString& aType,
                                                const UIEventInit& aParam,
                                                ErrorResult& aRv);
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
@@ -134,17 +134,17 @@ protected:
   }                                                         \
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg,           \
                               bool aSerializeInterfaceType) \
     override                                                \
   {                                                         \
     UIEvent::Serialize(aMsg, aSerializeInterfaceType);      \
   }                                                         \
   NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg,   \
-                                void** aIter) override      \
+                                PickleIterator* aIter) override \
   {                                                         \
     return UIEvent::Deserialize(aMsg, aIter);               \
   }
 
 already_AddRefed<mozilla::dom::UIEvent>
 NS_NewDOMUIEvent(mozilla::dom::EventTarget* aOwner,
                  nsPresContext* aPresContext,
                  mozilla::WidgetGUIEvent* aEvent);
--- a/dom/geolocation/nsGeoPositionIPCSerialiser.h
+++ b/dom/geolocation/nsGeoPositionIPCSerialiser.h
@@ -48,17 +48,17 @@ struct ParamTraits<nsIDOMGeoPositionCoor
     aParam->GetHeading(&coordData);
     WriteParam(aMsg, coordData);
 
     aParam->GetSpeed(&coordData);
     WriteParam(aMsg, coordData);
   }
 
   // Function to de-serialize a geoposition
-  static bool Read(const Message* aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if it is the null pointer we have transfered
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) return false;
 
     if (isNull) {
       *aResult = 0;
       return true;
@@ -114,17 +114,17 @@ struct ParamTraits<nsIDOMGeoPosition*>
     WriteParam(aMsg, timeStamp);
 
     nsCOMPtr<nsIDOMGeoPositionCoords> coords;
     aParam->GetCoords(getter_AddRefs(coords));
     WriteParam(aMsg, coords.get());
   }
 
   // Function to de-serialize a geoposition
-  static bool Read(const Message* aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if it is the null pointer we have transfered
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) return false;
 
     if (isNull) {
       *aResult = 0;
       return true;
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -16,17 +16,17 @@
 #include "IndexedDatabaseManager.h"
 #include "js/StructuredClone.h"
 #include "js/Value.h"
 #include "jsapi.h"
 #include "KeyPath.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/AutoRestore.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/storage.h"
 #include "mozilla/unused.h"
 #include "mozilla/UniquePtrExtensions.h"
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -18,17 +18,17 @@
 #include "IDBTransaction.h"
 #include "IndexedDatabase.h"
 #include "IndexedDatabaseInlines.h"
 #include "IndexedDatabaseManager.h"
 #include "js/Class.h"
 #include "js/Date.h"
 #include "js/StructuredClone.h"
 #include "KeyPath.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Move.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -7,17 +7,17 @@
 
 #include "Key.h"
 
 #include <algorithm>
 #include "IndexedDatabaseManager.h"
 #include "js/Date.h"
 #include "js/Value.h"
 #include "jsfriendapi.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageValueArray.h"
 #include "nsAlgorithm.h"
 #include "nsJSUtils.h"
 #include "ReportInternalError.h"
 #include "xpcpublic.h"
 
--- a/dom/indexedDB/SerializationHelpers.h
+++ b/dom/indexedDB/SerializationHelpers.h
@@ -21,17 +21,17 @@ struct ParamTraits<mozilla::dom::indexed
 {
   typedef mozilla::dom::indexedDB::Key paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mBuffer);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mBuffer);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     LogParam(aParam.mBuffer, aLog);
   }
@@ -50,17 +50,17 @@ struct ParamTraits<mozilla::dom::indexed
   typedef mozilla::dom::indexedDB::KeyPath paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mStrings);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mType) &&
            ReadParam(aMsg, aIter, &aResult->mStrings);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     LogParam(aParam.mStrings, aLog);
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -6,28 +6,30 @@
 #include "domstubs.idl"
 
 interface nsIDOMEventTarget;
 
 [ptr] native WidgetEvent(mozilla::WidgetEvent);
 [ptr] native DOMEventPtr(mozilla::dom::Event);
 [ptr] native IPCMessagePtr(IPC::Message);
 [ptr] native ConstIPCMessagePtr(const IPC::Message);
+[ptr] native PickleIterator(PickleIterator);
 [ptr] native EventTargetPtr(mozilla::dom::EventTarget);
 %{C++
 #ifdef ERROR
 #undef ERROR
 #endif
 
 #include "mozilla/EventForwards.h"
 class nsPresContext;
 class nsInvalidateRequestList;
 namespace IPC {
 class Message;
 }
+class PickleIterator;
 namespace mozilla {
 namespace dom {
 class Event;
 class EventTarget;
 } // namespace dom
 } // namespace mozilla
 %}
 
@@ -206,13 +208,13 @@ interface nsIDOMEvent : nsISupports
 
   [noscript] void duplicatePrivateData();
   [noscript] void setTarget(in nsIDOMEventTarget aTarget);
   [notxpcom] boolean IsDispatchStopped();
   [notxpcom] WidgetEvent WidgetEventPtr();
   [noscript,notxpcom] void SetTrusted(in boolean aTrusted);
   [notxpcom] void Serialize(in IPCMessagePtr aMsg,
                             in boolean aSerializeInterfaceType);
-  [notxpcom] boolean Deserialize(in ConstIPCMessagePtr aMsg, out voidPtr aIter);
+  [notxpcom] boolean Deserialize(in ConstIPCMessagePtr aMsg, in PickleIterator aIter);
   [noscript,notxpcom] void SetOwner(in EventTargetPtr aOwner);
   [notxpcom] DOMEventPtr InternalDOMEvent();
   [noscript] void stopCrossProcessForwarding();
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -638,16 +638,18 @@ ContentChild::Init(MessageLoop* aIOLoop,
   // to use, and when starting under XWayland, it may choose to start with
   // the wayland backend instead of the x11 backend.
   // The DISPLAY environment variable is normally set by the parent process.
   char* display_name = PR_GetEnv("DISPLAY");
   if (display_name) {
     int argc = 3;
     char option_name[] = "--display";
     char* argv[] = {
+      // argv0 is unused because g_set_prgname() was called in
+      // XRE_InitChildProcess().
       nullptr,
       option_name,
       display_name,
       nullptr
     };
     char** argvp = argv;
     gtk_init(&argc, &argvp);
   } else {
--- a/dom/ipc/IdType.h
+++ b/dom/ipc/IdType.h
@@ -57,17 +57,17 @@ struct ParamTraits<mozilla::dom::IdType<
 {
   typedef mozilla::dom::IdType<T> paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mId);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mId);
   }
 };
 
 } // namespace IPC
 
 #endif // mozilla_dom_IdType_h
--- a/dom/ipc/PermissionMessageUtils.cpp
+++ b/dom/ipc/PermissionMessageUtils.cpp
@@ -32,17 +32,17 @@ ParamTraits<Principal>::Write(Message* a
     NS_RUNTIMEABORT("Unable to serialize principal.");
     return;
   }
 
   WriteParam(aMsg, principalString);
 }
 
 bool
-ParamTraits<Principal>::Read(const Message* aMsg, void** aIter, paramType* aResult)
+ParamTraits<Principal>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
 {
   bool isNull;
   if (!ReadParam(aMsg, aIter, &isNull)) {
     return false;
   }
 
   if (isNull) {
     aResult->mPrincipal = nullptr;
--- a/dom/ipc/PermissionMessageUtils.h
+++ b/dom/ipc/PermissionMessageUtils.h
@@ -34,15 +34,15 @@ private:
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 template <>
 struct ParamTraits<Principal>
 {
   typedef Principal paramType;
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
 };
 
 } // namespace IPC
 
 #endif // mozilla_dom_permission_message_utils_h__
 
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -93,48 +93,43 @@ StructuredCloneData::Write(JSContext* aC
 }
 
 void
 StructuredCloneData::WriteIPCParams(IPC::Message* aMsg) const
 {
   WriteParam(aMsg, DataLength());
 
   if (DataLength()) {
-    // Structured clone data must be 64-bit aligned.
-    aMsg->WriteBytes(Data(), DataLength(), sizeof(uint64_t));
+    aMsg->WriteBytes(Data(), DataLength());
   }
 }
 
 bool
 StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
-                                   void** aIter)
+                                   PickleIterator* aIter)
 {
   MOZ_ASSERT(!Data());
 
   size_t dataLength = 0;
   if (!ReadParam(aMsg, aIter, &dataLength)) {
     return false;
   }
 
   if (!dataLength) {
     return true;
   }
 
-  uint64_t* dataBuffer = nullptr;
-  const char** buffer =
-    const_cast<const char**>(reinterpret_cast<char**>(&dataBuffer));
-  // Structured clone data must be 64-bit aligned.
-  if (!aMsg->ReadBytes(aIter, buffer, dataLength, sizeof(uint64_t))) {
+  mSharedData = SharedJSAllocatedData::AllocateForExternalData(dataLength);
+  NS_ENSURE_TRUE(mSharedData, false);
+
+  if (!aMsg->ReadBytesInto(aIter, mSharedData->Data(), dataLength)) {
+    mSharedData = nullptr;
     return false;
   }
 
-  mSharedData = SharedJSAllocatedData::CreateFromExternalData(dataBuffer,
-                                                              dataLength);
-  NS_ENSURE_TRUE(mSharedData, false);
-
   return true;
 }
 
 bool
 StructuredCloneData::CopyExternalData(const void* aData,
                                       size_t aDataLength)
 {
   MOZ_ASSERT(!Data());
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -10,44 +10,53 @@
 #include <algorithm>
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "nsISupportsImpl.h"
 
 namespace IPC {
 class Message;
 }
+class PickleIterator;
 
 namespace mozilla {
 namespace dom {
 namespace ipc {
 
 class SharedJSAllocatedData final
 {
 public:
   SharedJSAllocatedData(uint64_t* aData, size_t aDataLength)
   : mData(aData), mDataLength(aDataLength)
   {
     MOZ_ASSERT(mData);
   }
 
   static already_AddRefed<SharedJSAllocatedData>
-  CreateFromExternalData(const void* aData, size_t aDataLength)
+  AllocateForExternalData(size_t aDataLength)
   {
     uint64_t* data = Allocate64bitSafely(aDataLength);
     if (!data) {
       return nullptr;
     }
 
-    memcpy(data, aData, aDataLength);
     RefPtr<SharedJSAllocatedData> sharedData =
       new SharedJSAllocatedData(data, aDataLength);
     return sharedData.forget();
   }
 
+  static already_AddRefed<SharedJSAllocatedData>
+  CreateFromExternalData(const void* aData, size_t aDataLength)
+  {
+    RefPtr<SharedJSAllocatedData> sharedData =
+      AllocateForExternalData(aDataLength);
+    memcpy(sharedData->Data(), aData, aDataLength);
+    return sharedData.forget();
+  }
+
   NS_INLINE_DECL_REFCOUNTING(SharedJSAllocatedData)
 
   uint64_t* Data() const { return mData; }
   size_t DataLength() const { return mDataLength; }
 
 private:
   ~SharedJSAllocatedData()
   {
@@ -132,17 +141,17 @@ public:
 
   SharedJSAllocatedData* SharedData() const
   {
     return mSharedData;
   }
 
   // For IPC serialization
   void WriteIPCParams(IPC::Message* aMessage) const;
-  bool ReadIPCParams(const IPC::Message* aMessage, void** aIter);
+  bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
 
 private:
   uint64_t* MOZ_NON_OWNING_REF mExternalData;
   size_t mExternalDataLength;
 
   RefPtr<SharedJSAllocatedData> mSharedData;
 };
 
--- a/dom/ipc/TabMessageUtils.cpp
+++ b/dom/ipc/TabMessageUtils.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/TabMessageUtils.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
 
 bool
-ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
+ReadRemoteEvent(const IPC::Message* aMsg, PickleIterator* aIter,
                 RemoteDOMEvent* aResult)
 {
   aResult->mEvent = nullptr;
   nsString type;
   NS_ENSURE_TRUE(ReadParam(aMsg, aIter, &type), false);
 
   aResult->mEvent = EventDispatcher::CreateEvent(nullptr, nullptr, nullptr,
                                                  type);
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -19,17 +19,17 @@
 namespace mozilla {
 namespace dom {
 struct RemoteDOMEvent
 {
   // Make sure to set the owner after deserializing.
   nsCOMPtr<nsIDOMEvent> mEvent;
 };
 
-bool ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
+bool ReadRemoteEvent(const IPC::Message* aMsg, PickleIterator* aIter,
                      mozilla::dom::RemoteDOMEvent* aResult);
 
 #ifdef MOZ_CRASHREPORTER
 typedef CrashReporter::ThreadId NativeThreadId;
 #else
 // unused in this case
 typedef int32_t NativeThreadId;
 #endif
@@ -44,17 +44,17 @@ struct ParamTraits<mozilla::dom::RemoteD
 {
   typedef mozilla::dom::RemoteDOMEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     aParam.mEvent->Serialize(aMsg, true);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return mozilla::dom::ReadRemoteEvent(aMsg, aIter, aResult);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
   }
 };
@@ -70,17 +70,17 @@ struct ParamTraits<mozilla::dom::AudioCh
   }
 
   static void Write(Message* aMsg, const paramType& aValue)
   {
     MOZ_ASSERT(IsLegalValue(aValue));
     WriteParam(aMsg, (uint32_t)aValue);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     uint32_t value;
     if(!ReadParam(aMsg, aIter, &value) ||
        !IsLegalValue(paramType(value))) {
       return false;
     }
     *aResult = paramType(value);
     return true;
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -376,17 +376,17 @@ nsMathMLElement::ParseNumericValue(const
   int32_t stringLength = str.Length();
   if (!stringLength) {
     if (!(aFlags & PARSE_SUPPRESS_WARNINGS)) {
       ReportLengthParseError(aString, aDocument);
     }
     return false;
   }
 
-  if (ParseNamedSpaceValue(aString, aCSSValue, aFlags)) {
+  if (ParseNamedSpaceValue(str, aCSSValue, aFlags)) {
     return true;
   }
 
   nsAutoString number, unit;
 
   // see if the negative sign is there
   int32_t i = 0;
   char16_t c = str[0];
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -136,17 +136,17 @@ Benchmark::Init()
 
   MediaPrefs::GetSingleton();
 }
 
 BenchmarkPlayback::BenchmarkPlayback(Benchmark* aMainThreadState,
                                      MediaDataDemuxer* aDemuxer)
   : QueueObject(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK)))
   , mMainThreadState(aMainThreadState)
-  , mDecoderTaskQueue(new FlushableTaskQueue(GetMediaThreadPool(
+  , mDecoderTaskQueue(new TaskQueue(GetMediaThreadPool(
                         MediaThreadType::PLATFORM_DECODER)))
   , mDemuxer(aDemuxer)
   , mSampleIndex(0)
   , mFrameCount(0)
   , mFinished(false)
 {
   MOZ_ASSERT(static_cast<Benchmark*>(mMainThreadState)->OnThread());
 }
--- a/dom/media/Benchmark.h
+++ b/dom/media/Benchmark.h
@@ -12,17 +12,17 @@
 #include "PlatformDecoderModule.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TaskQueue.h"
 #include "mozilla/TimeStamp.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 
-class FlushableTaskQueue;
+class TaskQueue;
 class Benchmark;
 
 class BenchmarkPlayback : public QueueObject, private MediaDataDecoderCallback
 {
   friend class Benchmark;
   explicit BenchmarkPlayback(Benchmark* aMainThreadState, MediaDataDemuxer* aDemuxer);
   void DemuxSamples();
   void DemuxNextSample();
@@ -34,17 +34,17 @@ class BenchmarkPlayback : public QueueOb
   void Output(MediaData* aData) override;
   void Error() override;
   void InputExhausted() override;
   void DrainComplete() override;
   bool OnReaderTaskQueue() override;
 
   Atomic<Benchmark*> mMainThreadState;
 
-  RefPtr<FlushableTaskQueue> mDecoderTaskQueue;
+  RefPtr<TaskQueue> mDecoderTaskQueue;
   RefPtr<MediaDataDecoder> mDecoder;
 
   // Object only accessed on Thread()
   RefPtr<MediaDataDemuxer> mDemuxer;
   RefPtr<MediaTrackDemuxer> mTrackDemuxer;
   nsTArray<RefPtr<MediaRawData>> mSamples;
   size_t mSampleIndex;
   TimeStamp mDecodeStartTime;
--- a/dom/media/FileBlockCache.cpp
+++ b/dom/media/FileBlockCache.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "mozilla/SharedThreadPool.h"
 #include "FileBlockCache.h"
 #include "VideoUtils.h"
 #include "prio.h"
 #include <algorithm>
 
 namespace mozilla {
 
 nsresult FileBlockCache::Open(PRFileDesc* aFD)
deleted file mode 100644
--- a/dom/media/FlushableTaskQueue.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- 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/. */
-
-#include "FlushableTaskQueue.h"
-
-namespace mozilla {
-
-void
-FlushableTaskQueue::Flush()
-{
-  MonitorAutoLock mon(mQueueMonitor);
-  AutoSetFlushing autoFlush(this);
-  FlushLocked();
-  AwaitIdleLocked();
-}
-
-nsresult
-FlushableTaskQueue::FlushAndDispatch(already_AddRefed<nsIRunnable> aRunnable)
-{
-  nsCOMPtr<nsIRunnable> r = aRunnable;
-  {
-    MonitorAutoLock mon(mQueueMonitor);
-    AutoSetFlushing autoFlush(this);
-    FlushLocked();
-    nsresult rv = DispatchLocked(/* passed by ref */r, IgnoreFlushing, AssertDispatchSuccess);
-    NS_ENSURE_SUCCESS(rv, rv);
-    AwaitIdleLocked();
-  }
-  // If the ownership of |r| is not transferred in DispatchLocked() due to
-  // dispatch failure, it will be deleted here outside the lock. We do so
-  // since the destructor of the runnable might access TaskQueue and result
-  // in deadlocks.
-  return NS_OK;
-}
-
-void
-FlushableTaskQueue::FlushLocked()
-{
-  // Make sure there are no tasks for this queue waiting in the caller's tail
-  // dispatcher.
-  MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
-                !AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
-
-  mQueueMonitor.AssertCurrentThreadOwns();
-  MOZ_ASSERT(mIsFlushing);
-
-  // Clear the tasks. If this strikes you as awful, stop using a
-  // FlushableTaskQueue.
-  while (!mTasks.empty()) {
-    mTasks.pop();
-  }
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/FlushableTaskQueue.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- 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 FlushableTaskQueue_h_
-#define FlushableTaskQueue_h_
-
-#include "mozilla/TaskQueue.h"
-
-//
-// WARNING: THIS CLASS IS DEPRECATED AND GOING AWAY. DO NOT USE IT!
-//
-
-namespace mozilla {
-
-class FlushableTaskQueue : public TaskQueue
-{
-public:
-  explicit FlushableTaskQueue(already_AddRefed<SharedThreadPool> aPool) : TaskQueue(Move(aPool)) {}
-  nsresult FlushAndDispatch(already_AddRefed<nsIRunnable> aRunnable);
-  void Flush();
-
-  bool IsDispatchReliable() override { return false; }
-
-private:
-
-  class MOZ_STACK_CLASS AutoSetFlushing
-  {
-  public:
-    explicit AutoSetFlushing(FlushableTaskQueue* aTaskQueue) : mTaskQueue(aTaskQueue)
-    {
-      mTaskQueue->mQueueMonitor.AssertCurrentThreadOwns();
-      mTaskQueue->mIsFlushing = true;
-    }
-    ~AutoSetFlushing()
-    {
-      mTaskQueue->mQueueMonitor.AssertCurrentThreadOwns();
-      mTaskQueue->mIsFlushing = false;
-    }
-
-  private:
-    FlushableTaskQueue* mTaskQueue;
-  };
-
-  void FlushLocked();
-
-};
-
-}  // namespace mozilla
-
-#endif // FlushableTaskQueue_h_
--- a/dom/media/MP3Demuxer.cpp
+++ b/dom/media/MP3Demuxer.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MP3Demuxer.h"
 
 #include <inttypes.h>
 #include <algorithm>
 
 #include "mozilla/Assertions.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "VideoUtils.h"
 #include "TimeUnits.h"
 #include "prenv.h"
 
 #ifdef PR_LOGGING
 mozilla::LazyLogModule gMP3DemuxerLog("MP3Demuxer");
 #define MP3LOG(msg, ...) \
   MOZ_LOG(gMP3DemuxerLog, LogLevel::Debug, ("MP3Demuxer " msg, ##__VA_ARGS__))
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -167,19 +167,19 @@ MediaFormatReader::InitLayersBackendType
 nsresult
 MediaFormatReader::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
 
   InitLayersBackendType();
 
   mAudio.mTaskQueue =
-    new FlushableTaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
+    new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
   mVideo.mTaskQueue =
-    new FlushableTaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
+    new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
 
   return NS_OK;
 }
 
 #ifdef MOZ_EME
 class DispatchKeyNeededEvent : public Runnable {
 public:
   DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
@@ -1099,16 +1099,21 @@ MediaFormatReader::Update(TrackType aTra
   bool needOutput = false;
   auto& decoder = GetDecoderData(aTrack);
   decoder.mUpdateScheduled = false;
 
   if (!mInitDone) {
     return;
   }
 
+  if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
+    LOGV("Skipping in progress, nothing more to do");
+    return;
+  }
+
   if (UpdateReceivedNewData(aTrack)) {
     LOGV("Nothing more to do");
     return;
   }
 
   if (decoder.mSeekRequest.Exists()) {
     LOGV("Seeking hasn't completed, nothing more to do");
     return;
@@ -1413,38 +1418,68 @@ MediaFormatReader::Reset(TrackType aTrac
 
   decoder.ResetState();
   decoder.Flush();
 
   LOG("Reset(%s) END", TrackTypeToStr(aTrack));
 }
 
 void
+MediaFormatReader::DropDecodedSamples(TrackType aTrack)
+{
+  MOZ_ASSERT(OnTaskQueue());
+  auto& decoder = GetDecoderData(aTrack);
+  size_t lengthDecodedQueue = decoder.mOutput.Length();
+  if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) {
+    TimeUnit time =
+      TimeUnit::FromMicroseconds(decoder.mOutput.LastElement()->mTime);
+    if (time >= decoder.mTimeThreshold.ref().Time()) {
+      // We would have reached our internal seek target.
+      decoder.mTimeThreshold.reset();
+    }
+  }
+  decoder.mOutput.Clear();
+  decoder.mSizeOfQueue -= lengthDecodedQueue;
+  if (aTrack == TrackInfo::kVideoTrack && mDecoder) {
+    mDecoder->NotifyDecodedFrames(0, 0, lengthDecodedQueue);
+  }
+}
+
+void
 MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mVideo.HasPromise());
   LOG("Skipping up to %lld", aTimeThreshold.ToMicroseconds());
 
+  // We've reached SkipVideoDemuxToNextKeyFrame when our decoding is late.
+  // As such we can drop all already decoded samples and discard all pending
+  // samples.
+  // TODO: Ideally we should set mOutputRequested to false so that all pending
+  // frames are dropped too. However, we can't do such thing as the code assumes
+  // that the decoder just got flushed. Once bug 1257107 land, we could set the
+  // decoder threshold to the value of currentTime.
+  DropDecodedSamples(TrackInfo::kVideoTrack);
+
   mSkipRequest.Begin(mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
                           ->Then(OwnerThread(), __func__, this,
                                  &MediaFormatReader::OnVideoSkipCompleted,
                                  &MediaFormatReader::OnVideoSkipFailed));
   return;
 }
 
 void
 MediaFormatReader::VideoSkipReset(uint32_t aSkipped)
 {
   MOZ_ASSERT(OnTaskQueue());
-  // I think it's still possible for an output to have been sent from the decoder
-  // and is currently sitting in our event queue waiting to be processed. The following
-  // flush won't clear it, and when we return to the event loop it'll be added to our
-  // output queue and be used.
-  // This code will count that as dropped, which was the intent, but not quite true.
+
+  // Some frames may have been output by the decoder since we initiated the
+  // videoskip process and we know they would be late.
+  DropDecodedSamples(TrackInfo::kVideoTrack);
+  // Report the pending frames as dropped.
   if (mDecoder) {
     mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames());
   }
 
   // Cancel any pending demux request and pending demuxed samples.
   mVideo.mDemuxRequest.DisconnectIfExists();
   Reset(TrackType::kVideoTrack);
 
@@ -1473,16 +1508,19 @@ MediaFormatReader::OnVideoSkipFailed(Med
   MOZ_ASSERT(OnTaskQueue());
   LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
   mSkipRequest.Complete();
 
   MOZ_ASSERT(mVideo.HasPromise());
   switch (aFailure.mFailure) {
     case DemuxerFailureReason::END_OF_STREAM: MOZ_FALLTHROUGH;
     case DemuxerFailureReason::WAITING_FOR_DATA:
+      // Some frames may have been output by the decoder since we initiated the
+      // videoskip process and we know they would be late.
+      DropDecodedSamples(TrackInfo::kVideoTrack);
       // We can't complete the skip operation, will just service a video frame
       // normally.
       NotifyDecodingRequested(TrackInfo::kVideoTrack);
       break;
     case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
     case DemuxerFailureReason::SHUTDOWN:
       if (mVideo.HasPromise()) {
         mVideo.RejectPromise(CANCELED, __func__);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -174,16 +174,17 @@ private:
 
   // DecoderCallback proxies the MediaDataDecoderCallback calls to these
   // functions.
   void Output(TrackType aType, MediaData* aSample);
   void InputExhausted(TrackType aTrack);
   void Error(TrackType aTrack);
   void Reset(TrackType aTrack);
   void DrainComplete(TrackType aTrack);
+  void DropDecodedSamples(TrackType aTrack);
 
   bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
 
   size_t SizeOfQueue(TrackType aTrack);
 
   RefPtr<PDMFactory> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
@@ -249,17 +250,17 @@ private:
     {}
 
     MediaFormatReader* mOwner;
     // Disambiguate Audio vs Video.
     MediaData::Type mType;
     RefPtr<MediaTrackDemuxer> mTrackDemuxer;
     // TaskQueue on which decoder can choose to decode.
     // Only non-null up until the decoder is created.
-    RefPtr<FlushableTaskQueue> mTaskQueue;
+    RefPtr<TaskQueue> mTaskQueue;
     // Callback that receives output and error notifications from the decoder.
     nsAutoPtr<DecoderCallback> mCallback;
 
     // Monitor protecting mDescription and mDecoder.
     Monitor mMonitor;
     // The platform decoder.
     RefPtr<MediaDataDecoder> mDecoder;
     const char* mDescription;
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -307,24 +307,16 @@ GenerateRandomPathName(nsCString& aOutSa
 already_AddRefed<TaskQueue>
 CreateMediaDecodeTaskQueue()
 {
   RefPtr<TaskQueue> queue = new TaskQueue(
     GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
   return queue.forget();
 }
 
-already_AddRefed<FlushableTaskQueue>
-CreateFlushableMediaDecodeTaskQueue()
-{
-  RefPtr<FlushableTaskQueue> queue = new FlushableTaskQueue(
-    GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
-  return queue.forget();
-}
-
 void
 SimpleTimer::Cancel() {
   if (mTimer) {
 #ifdef DEBUG
     nsCOMPtr<nsIEventTarget> target;
     mTimer->GetTarget(getter_AddRefs(target));
     nsCOMPtr<nsIThread> thread(do_QueryInterface(target));
     MOZ_ASSERT(NS_GetCurrentThread() == thread);
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -2,17 +2,16 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 VideoUtils_h
 #define VideoUtils_h
 
-#include "FlushableTaskQueue.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 
 #include "nsIThread.h"
 #include "nsSize.h"
@@ -263,19 +262,16 @@ GenerateRandomName(nsCString& aOutSalt, 
 // This version returns a string suitable for use as a file or URL
 // path. This is based on code from nsExternalAppHandler::SetUpTempFile.
 nsresult
 GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
 
 already_AddRefed<TaskQueue>
 CreateMediaDecodeTaskQueue();
 
-already_AddRefed<FlushableTaskQueue>
-CreateFlushableMediaDecodeTaskQueue();
-
 // Iteratively invokes aWork until aCondition returns true, or aWork returns false.
 // Use this rather than a while loop to avoid bogarting the task queue.
 template<class Work, class Condition>
 RefPtr<GenericPromise> InvokeUntil(Work aWork, Condition aCondition) {
   RefPtr<GenericPromise::Private> p = new GenericPromise::Private(__func__);
 
   if (aCondition()) {
     p->Resolve(true, __func__);
--- a/dom/media/encoder/fmp4_muxer/ISOControl.h
+++ b/dom/media/encoder/fmp4_muxer/ISOControl.h
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ISOCOMPOSITOR_H_
 #define ISOCOMPOSITOR_H_
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "nsTArray.h"
 #include "ISOTrackMetadata.h"
 #include "EncodedFrameContainer.h"
 
 namespace mozilla {
 
 class Box;
 class ISOControl;
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -213,17 +213,17 @@ static const uint8_t sTestH264ExtraData[
   0xc0, 0x1e, 0xbb, 0x40, 0x50, 0x17, 0xfc, 0xb8, 0x08, 0x80,
   0x00, 0x00, 0x32, 0x00, 0x00, 0x0b, 0xb5, 0x07, 0x8b, 0x17,
   0x50, 0x01, 0x00, 0x04, 0x68, 0xce, 0x32, 0xc8
 };
 
 static already_AddRefed<MediaDataDecoder>
 CreateTestH264Decoder(layers::LayersBackend aBackend,
                       VideoInfo& aConfig,
-                      FlushableTaskQueue* aTaskQueue)
+                      TaskQueue* aTaskQueue)
 {
   aConfig.mMimeType = "video/avc";
   aConfig.mId = 1;
   aConfig.mDuration = 40000;
   aConfig.mMediaTime = 0;
   aConfig.mImage = aConfig.mDisplay = nsIntSize(640, 360);
   aConfig.mExtraData = new MediaByteBuffer();
   aConfig.mExtraData->AppendElements(sTestH264ExtraData,
@@ -246,18 +246,18 @@ MP4Decoder::IsVideoAccelerated(layers::L
   ErrorResult rv;
   RefPtr<dom::Promise> promise;
   promise = dom::Promise::Create(aParent, rv);
   if (rv.Failed()) {
     rv.SuppressException();
     return nullptr;
   }
 
-  RefPtr<FlushableTaskQueue> taskQueue =
-    new FlushableTaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
+  RefPtr<TaskQueue> taskQueue =
+    new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
   VideoInfo config;
   RefPtr<MediaDataDecoder> decoder(CreateTestH264Decoder(aBackend, config, taskQueue));
   if (!decoder) {
     taskQueue->BeginShutdown();
     taskQueue->AwaitShutdownAndIdle();
     promise->MaybeResolve(NS_LITERAL_STRING("No; Failed to create H264 decoder"));
     return promise.forget();
   }
--- a/dom/media/gmp/GMPDiskStorage.cpp
+++ b/dom/media/gmp/GMPDiskStorage.cpp
@@ -5,17 +5,17 @@
 
 #include "plhash.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "GMPParent.h"
 #include "gmp-storage.h"
 #include "mozilla/unused.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "nsClassHashtable.h"
 #include "prio.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsContentCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsISimpleEnumerator.h"
 
 namespace mozilla {
--- a/dom/media/gmp/GMPMessageUtils.h
+++ b/dom/media/gmp/GMPMessageUtils.h
@@ -127,17 +127,17 @@ struct ParamTraits<GMPSimulcastStream>
     WriteParam(aMsg, aParam.mHeight);
     WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
     WriteParam(aMsg, aParam.mMaxBitrate);
     WriteParam(aMsg, aParam.mTargetBitrate);
     WriteParam(aMsg, aParam.mMinBitrate);
     WriteParam(aMsg, aParam.mQPMax);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (ReadParam(aMsg, aIter, &(aResult->mWidth)) &&
         ReadParam(aMsg, aIter, &(aResult->mHeight)) &&
         ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
         ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) &&
         ReadParam(aMsg, aIter, &(aResult->mTargetBitrate)) &&
         ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) &&
         ReadParam(aMsg, aIter, &(aResult->mQPMax))) {
@@ -176,17 +176,17 @@ struct ParamTraits<GMPVideoCodec>
     WriteParam(aMsg, aParam.mQPMax);
     WriteParam(aMsg, aParam.mNumberOfSimulcastStreams);
     for (uint32_t i = 0; i < aParam.mNumberOfSimulcastStreams; i++) {
       WriteParam(aMsg, aParam.mSimulcastStream[i]);
     }
     WriteParam(aMsg, aParam.mMode);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // NOTE: make sure this matches any versions supported
     if (!ReadParam(aMsg, aIter, &(aResult->mGMPApiVersion)) ||
       aResult->mGMPApiVersion != kGMPVersion33) {
         return false;
     }
     if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
       return false;
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -2,17 +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 "ContainerParser.h"
 
 #include "WebMBufferedParser.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/ErrorResult.h"
 #include "mp4_demuxer/MoofParser.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Maybe.h"
 #include "MediaData.h"
 #ifdef MOZ_FMP4
 #include "MP4Stream.h"
 #include "mp4_demuxer/AtomType.h"
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -98,17 +98,16 @@ EXPORTS += [
     'Benchmark.h',
     'BufferMediaResource.h',
     'CubebUtils.h',
     'DecoderDoctorDiagnostics.h',
     'DecoderTraits.h',
     'DOMMediaStream.h',
     'EncodedBufferCache.h',
     'FileBlockCache.h',
-    'FlushableTaskQueue.h',
     'FrameStatistics.h',
     'Intervals.h',
     'Latency.h',
     'MediaCache.h',
     'MediaCallbackID.h',
     'MediaData.h',
     'MediaDataDemuxer.h',
     'MediaDecoder.h',
@@ -210,17 +209,16 @@ UNIFIED_SOURCES += [
     'AudioTrackList.cpp',
     'Benchmark.cpp',
     'CanvasCaptureMediaStream.cpp',
     'CubebUtils.cpp',
     'DecoderDoctorDiagnostics.cpp',
     'DOMMediaStream.cpp',
     'EncodedBufferCache.cpp',
     'FileBlockCache.cpp',
-    'FlushableTaskQueue.cpp',
     'GetUserMediaRequest.cpp',
     'GraphDriver.cpp',
     'Latency.cpp',
     'MediaCache.cpp',
     'MediaCallbackID.cpp',
     'MediaData.cpp',
     'MediaDecoder.cpp',
     'MediaDecoderReader.cpp',
--- a/dom/media/ogg/OggCodecState.cpp
+++ b/dom/media/ogg/OggCodecState.cpp
@@ -2,17 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <string.h>
 
 #include "mozilla/DebugOnly.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include <stdint.h>
 
 #include "nsDebug.h"
 #include "MediaDecoderReader.h"
 #include "OggCodecState.h"
 #include "OggDecoder.h"
 #include "nsISupportsImpl.h"
 #include "VideoUtils.h"
--- a/dom/media/ogg/OpusParser.cpp
+++ b/dom/media/ogg/OpusParser.cpp
@@ -2,17 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <string.h>
 
 #include "mozilla/DebugOnly.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include <stdint.h>
 
 #include "OpusParser.h"
 
 #include "nsDebug.h"
 #include "MediaDecoderReader.h"
 #include "VideoUtils.h"
 #include <algorithm>
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -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/. */
 
 #include "OpusDecoder.h"
 #include "TimeUnits.h"
 #include "VorbisUtils.h"
 #include "VorbisDecoder.h" // For VorbisLayout
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/SyncRunnable.h"
 
 #include <stdint.h>
 #include <inttypes.h>  // For PRId64
 
 #define OPUS_DEBUG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
     ("OpusDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "GMPVideoDecoder.h"
 #include "GMPVideoHost.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "prsystem.h"
 #include "MediaData.h"
 #include "GMPDecoderModule.h"
 
 namespace mozilla {
 
 #if defined(DEBUG)
 extern bool IsOnGMPThread();
--- a/dom/media/wave/WaveDemuxer.cpp
+++ b/dom/media/wave/WaveDemuxer.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WaveDemuxer.h"
 
 #include <inttypes.h>
 #include <algorithm>
 
 #include "mozilla/Assertions.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "VideoUtils.h"
 #include "TimeUnits.h"
 #include "prenv.h"
 
 using mozilla::media::TimeUnit;
 using mozilla::media::TimeIntervals;
 using mp4_demuxer::ByteReader;
 
--- a/dom/media/wave/WaveReader.cpp
+++ b/dom/media/wave/WaveReader.cpp
@@ -8,17 +8,17 @@
 #include "WaveReader.h"
 #include "MediaDecoderStateMachine.h"
 #include "VideoUtils.h"
 #include "nsISeekableStream.h"
 
 #include <stdint.h>
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/UniquePtr.h"
 #include <algorithm>
 
 using namespace mozilla::media;
 
 namespace mozilla {
 
 // Un-comment to enable logging of seek bisections.
--- a/dom/media/webm/EbmlComposer.cpp
+++ b/dom/media/webm/EbmlComposer.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EbmlComposer.h"
 #include "mozilla/UniquePtr.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "libmkv/EbmlIDs.h"
 #include "libmkv/EbmlWriter.h"
 #include "libmkv/WebMElement.h"
 #include "prtime.h"
 
 namespace mozilla {
 
 // Timecode scale in nanoseconds
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -7,17 +7,17 @@
 #include "nsError.h"
 #include "MediaDecoderStateMachine.h"
 #include "AbstractMediaDecoder.h"
 #include "MediaResource.h"
 #include "WebMDemuxer.h"
 #include "WebMBufferedParser.h"
 #include "gfx2DGlue.h"
 #include "mozilla/Atomics.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/SharedThreadPool.h"
 #include "MediaDataDemuxer.h"
 #include "nsAutoRef.h"
 #include "NesteggPacketHolder.h"
 #include "XiphExtradata.h"
 #include "prprf.h"           // leaving it for PR_vsnprintf()
 #include "mozilla/Snprintf.h"
 
--- a/dom/media/webrtc/WebrtcGlobal.h
+++ b/dom/media/webrtc/WebrtcGlobal.h
@@ -26,17 +26,17 @@ struct ParamTraits<mozilla::dom::Optiona
       WriteParam(aMsg, true);
       WriteParam(aMsg, aParam.Value());
       return;
     }
 
     WriteParam(aMsg, false);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool was_passed = false;
 
     if (!ReadParam(aMsg, aIter, &was_passed)) {
       return false;
     }
 
     aResult->Reset(); //XXX Optional_base seems to reach this point with isSome true.
@@ -56,17 +56,17 @@ struct ParamTraits<mozilla::dom::Sequenc
 {
   typedef mozilla::dom::Sequence<T> paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<const FallibleTArray<T>&>(aParam));
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, dynamic_cast<FallibleTArray<T>*>(aResult));
   }
 };
 
 template<>
 struct ParamTraits<mozilla::dom::RTCStatsType> :
   public ContiguousEnumSerializer<
@@ -109,17 +109,17 @@ struct ParamTraits<mozilla::dom::RTCStat
     WriteParam(aMsg, aParam.mMediaStreamTrackStats);
     WriteParam(aMsg, aParam.mOutboundRTPStreamStats);
     WriteParam(aMsg, aParam.mPcid);
     WriteParam(aMsg, aParam.mRemoteSdp);
     WriteParam(aMsg, aParam.mTimestamp);
     WriteParam(aMsg, aParam.mTransportStats);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mClosed)) ||
         !ReadParam(aMsg, aIter, &(aResult->mCodecStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceCandidatePairStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceCandidateStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceComponentStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mInboundRTPStreamStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mLocalSdp)) ||
@@ -142,17 +142,17 @@ typedef mozilla::dom::RTCStats RTCStats;
 static void WriteRTCStats(Message* aMsg, const RTCStats& aParam)
 {
   // RTCStats base class
   WriteParam(aMsg, aParam.mId);
   WriteParam(aMsg, aParam.mTimestamp);
   WriteParam(aMsg, aParam.mType);
 }
 
-static bool ReadRTCStats(const Message* aMsg, void** aIter, RTCStats* aResult)
+static bool ReadRTCStats(const Message* aMsg, PickleIterator* aIter, RTCStats* aResult)
 {
   // RTCStats base class
   if (!ReadParam(aMsg, aIter, &(aResult->mId)) ||
       !ReadParam(aMsg, aIter, &(aResult->mTimestamp)) ||
       !ReadParam(aMsg, aIter, &(aResult->mType))) {
     return false;
   }
 
@@ -169,17 +169,17 @@ struct ParamTraits<mozilla::dom::RTCCode
     WriteParam(aMsg, aParam.mChannels);
     WriteParam(aMsg, aParam.mClockRate);
     WriteParam(aMsg, aParam.mCodec);
     WriteParam(aMsg, aParam.mParameters);
     WriteParam(aMsg, aParam.mPayloadType);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mChannels)) ||
         !ReadParam(aMsg, aIter, &(aResult->mClockRate)) ||
         !ReadParam(aMsg, aIter, &(aResult->mCodec)) ||
         !ReadParam(aMsg, aIter, &(aResult->mParameters)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPayloadType)) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
@@ -202,17 +202,17 @@ struct ParamTraits<mozilla::dom::RTCIceC
     WriteParam(aMsg, aParam.mNominated);
     WriteParam(aMsg, aParam.mReadable);
     WriteParam(aMsg, aParam.mRemoteCandidateId);
     WriteParam(aMsg, aParam.mSelected);
     WriteParam(aMsg, aParam.mState);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mComponentId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mLocalCandidateId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPriority)) ||
         !ReadParam(aMsg, aIter, &(aResult->mNominated)) ||
         !ReadParam(aMsg, aIter, &(aResult->mReadable)) ||
         !ReadParam(aMsg, aIter, &(aResult->mRemoteCandidateId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mSelected)) ||
@@ -237,17 +237,17 @@ struct ParamTraits<mozilla::dom::RTCIceC
     WriteParam(aMsg, aParam.mComponentId);
     WriteParam(aMsg, aParam.mIpAddress);
     WriteParam(aMsg, aParam.mMozLocalTransport);
     WriteParam(aMsg, aParam.mPortNumber);
     WriteParam(aMsg, aParam.mTransport);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mCandidateId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mCandidateType)) ||
         !ReadParam(aMsg, aIter, &(aResult->mComponentId)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIpAddress)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMozLocalTransport)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPortNumber)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTransport)) ||
@@ -269,17 +269,17 @@ struct ParamTraits<mozilla::dom::RTCIceC
     WriteParam(aMsg, aParam.mActiveConnection);
     WriteParam(aMsg, aParam.mBytesReceived);
     WriteParam(aMsg, aParam.mBytesSent);
     WriteParam(aMsg, aParam.mComponent);
     WriteParam(aMsg, aParam.mTransportId);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mActiveConnection)) ||
         !ReadParam(aMsg, aIter, &(aResult->mBytesReceived)) ||
         !ReadParam(aMsg, aIter, &(aResult->mBytesSent)) ||
         !ReadParam(aMsg, aIter, &(aResult->mComponent)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTransportId)) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
@@ -302,17 +302,17 @@ static void WriteRTCRTPStreamStats(
     WriteParam(aMsg, aParam.mMediaTrackId);
     WriteParam(aMsg, aParam.mMediaType);
     WriteParam(aMsg, aParam.mRemoteId);
     WriteParam(aMsg, aParam.mSsrc);
     WriteParam(aMsg, aParam.mTransportId);
 }
 
 static bool ReadRTCRTPStreamStats(
-              const Message* aMsg, void** aIter,
+              const Message* aMsg, PickleIterator* aIter,
               mozilla::dom::RTCRTPStreamStats* aResult)
 {
   if (!ReadParam(aMsg, aIter, &(aResult->mBitrateMean)) ||
       !ReadParam(aMsg, aIter, &(aResult->mBitrateStdDev)) ||
       !ReadParam(aMsg, aIter, &(aResult->mCodecId)) ||
       !ReadParam(aMsg, aIter, &(aResult->mFramerateMean)) ||
       !ReadParam(aMsg, aIter, &(aResult->mFramerateStdDev)) ||
       !ReadParam(aMsg, aIter, &(aResult->mIsRemote)) ||
@@ -341,17 +341,17 @@ struct ParamTraits<mozilla::dom::RTCInbo
     WriteParam(aMsg, aParam.mMozJitterBufferDelay);
     WriteParam(aMsg, aParam.mMozRtt);
     WriteParam(aMsg, aParam.mPacketsLost);
     WriteParam(aMsg, aParam.mPacketsReceived);
     WriteRTCRTPStreamStats(aMsg, aParam);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mBytesReceived)) ||
         !ReadParam(aMsg, aIter, &(aResult->mDiscardedPackets)) ||
         !ReadParam(aMsg, aIter, &(aResult->mJitter)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMozAvSyncDelay)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMozJitterBufferDelay)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMozRtt)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPacketsLost)) ||
@@ -375,17 +375,17 @@ struct ParamTraits<mozilla::dom::RTCOutb
     WriteParam(aMsg, aParam.mBytesSent);
     WriteParam(aMsg, aParam.mDroppedFrames);
     WriteParam(aMsg, aParam.mPacketsSent);
     WriteParam(aMsg, aParam.mTargetBitrate);
     WriteRTCRTPStreamStats(aMsg, aParam);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mBytesSent)) ||
         !ReadParam(aMsg, aIter, &(aResult->mDroppedFrames)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPacketsSent)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTargetBitrate)) ||
         !ReadRTCRTPStreamStats(aMsg, aIter, aResult) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
@@ -402,17 +402,17 @@ struct ParamTraits<mozilla::dom::RTCMedi
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mStreamIdentifier);
     WriteParam(aMsg, aParam.mTrackIds);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mStreamIdentifier)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTrackIds)) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
     }
 
     return true;
@@ -426,17 +426,17 @@ struct ParamTraits<mozilla::dom::RTCTran
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mBytesReceived);
     WriteParam(aMsg, aParam.mBytesSent);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mBytesReceived)) ||
         !ReadParam(aMsg, aIter, &(aResult->mBytesSent)) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
     }
 
     return true;
@@ -462,17 +462,17 @@ struct ParamTraits<mozilla::dom::RTCMedi
     WriteParam(aMsg, aParam.mFramesReceived);
     WriteParam(aMsg, aParam.mFramesSent);
     WriteParam(aMsg, aParam.mRemoteSource);
     WriteParam(aMsg, aParam.mSsrcIds);
     WriteParam(aMsg, aParam.mTrackIdentifier);
     WriteRTCStats(aMsg, aParam);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mAudioLevel)) ||
         !ReadParam(aMsg, aIter, &(aResult->mEchoReturnLoss)) ||
         !ReadParam(aMsg, aIter, &(aResult->mEchoReturnLossEnhancement)) ||
         !ReadParam(aMsg, aIter, &(aResult->mFrameHeight)) ||
         !ReadParam(aMsg, aIter, &(aResult->mFrameWidth)) ||
         !ReadParam(aMsg, aIter, &(aResult->mFramesCorrupted)) ||
         !ReadParam(aMsg, aIter, &(aResult->mFramesDecoded)) ||
--- a/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h
+++ b/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h
@@ -92,17 +92,17 @@ struct ParamTraits<nsIMobileCallForwardi
     aParam->GetTimeSeconds(&pShort);
     WriteParam(aMsg, pShort);
 
     aParam->GetServiceClass(&pShort);
     WriteParam(aMsg, pShort);
   }
 
   // Function to de-serialize a MobileCallForwardingOptions.
-  static bool Read(const Message *aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message *aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if is the null pointer we have transfered.
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) {
       return false;
     }
 
     if (isNull) {
@@ -171,17 +171,17 @@ struct ParamTraits<nsIMobileNetworkInfo*
     aParam->GetState(pString);
     WriteParam(aMsg, pString);
 
     // We release the ref here given that ipdl won't handle reference counting.
     aParam->Release();
   }
 
   // Function to de-serialize a MobileNetworkInfo.
-  static bool Read(const Message *aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message *aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if is the null pointer we have transfered.
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) {
       return false;
     }
 
     if (isNull) {
@@ -258,17 +258,17 @@ struct ParamTraits<nsIMobileCellInfo*>
     aParam->GetCdmaNetworkId(&pLong);
     WriteParam(aMsg, pLong);
 
     // We release the ref here given that ipdl won't handle reference counting.
     aParam->Release();
   }
 
   // Function to de-serialize a MobileCellInfo.
-  static bool Read(const Message *aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message *aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if is the null pointer we have transfered.
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) {
       return false;
     }
 
     if (isNull) {
@@ -373,17 +373,17 @@ struct ParamTraits<nsIMobileConnectionIn
       WriteParam(aMsg, pInt32);
     }
 
     // We release the ref here given that ipdl won't handle reference counting.
     aParam->Release();
   }
 
   // Function to de-serialize a MobileConectionInfo.
-  static bool Read(const Message* aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if is the null pointer we have transfered.
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) {
       return false;
     }
 
     if (isNull) {
@@ -536,17 +536,17 @@ struct ParamTraits<MozCallForwardingOpti
       WriteParam(aMsg, isNull);
       if (!isNull) {
         WriteParam(aMsg, aParam.mServiceClass.Value().Value());
       }
     }
   }
 
   // Function to de-serialize a MozCallForwardingOptions.
-  static bool Read(const Message *aMsg, void **aIter, paramType* aResult)
+  static bool Read(const Message *aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool wasPassed = false;
     bool isNull = false;
 
     // Read mActive
     if (!ReadParam(aMsg, aIter, &wasPassed)) {
       return false;
     }
--- a/dom/nfc/gonk/NfcService.cpp
+++ b/dom/nfc/gonk/NfcService.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "NfcService.h"
 #include <binder/Parcel.h>
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/NfcOptionsBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/RootedDictionary.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/ListenSocket.h"
 #include "mozilla/ipc/ListenSocketConsumer.h"
 #include "mozilla/ipc/NfcConnector.h"
 #include "mozilla/ipc/StreamSocket.h"
 #include "mozilla/ipc/StreamSocketConsumer.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/UniquePtr.h"
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -467,28 +467,16 @@ GetGlobalObject(NPP npp)
 
   nsCOMPtr<nsIDocument> doc;
   owner->GetDocument(getter_AddRefs(doc));
   NS_ENSURE_TRUE(doc, nullptr);
 
   return doc->GetScopeObject();
 }
 
-JSContext *
-GetJSContext(NPP npp)
-{
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetGlobalObject(npp));
-  NS_ENSURE_TRUE(sgo, nullptr);
-
-  nsIScriptContext *scx = sgo->GetContext();
-  NS_ENSURE_TRUE(scx, nullptr);
-
-  return scx->GetNativeContext();
-}
-
 } // namespace parent
 } // namespace plugins
 } // namespace mozilla
 
 static NPP
 LookupNPP(NPObject *npobj);
 
 
@@ -605,17 +593,17 @@ JSValToNPVariant(NPP npp, JSContext *cx,
   // legitimate cases where a security wrapper ends up here (for example,
   // Location objects, which are _always_ behind security wrappers).
   JS::Rooted<JSObject*> obj(cx, val.toObjectOrNull());
   obj = js::CheckedUnwrap(obj);
   if (!obj) {
     obj = val.toObjectOrNull();
   }
 
-  NPObject *npobj = nsJSObjWrapper::GetNewOrUsed(npp, cx, obj);
+  NPObject* npobj = nsJSObjWrapper::GetNewOrUsed(npp, obj);
   if (!npobj) {
     return false;
   }
 
   // Pass over ownership of npobj to *variant
   OBJECT_TO_NPVARIANT(npobj, *variant);
 
   return true;
@@ -1098,17 +1086,17 @@ nsJSObjWrapper::NP_Construct(NPObject *n
 {
   return doInvoke(npobj, NPIdentifier_VOID, args, argCount, true, result);
 }
 
 // Look up or create an NPObject that wraps the JSObject obj.
 
 // static
 NPObject *
-nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle<JSObject*> obj)
+nsJSObjWrapper::GetNewOrUsed(NPP npp, JS::Handle<JSObject*> obj)
 {
   if (!npp) {
     NS_ERROR("Null NPP passed to nsJSObjWrapper::GetNewOrUsed()!");
 
     return nullptr;
   }
 
   // If we're running out-of-process and initializing asynchronously, and if
@@ -1117,26 +1105,16 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
   nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(npp->ndata);
   if (inst->GetPlugin()->GetLibrary()->IsOOP()) {
     PluginAsyncSurrogate* surrogate = PluginAsyncSurrogate::Cast(npp);
     if (surrogate && surrogate->IsDestroyPending()) {
       return nullptr;
     }
   }
 
-  if (!cx) {
-    cx = GetJSContext(npp);
-
-    if (!cx) {
-      NS_ERROR("Unable to find a JSContext in nsJSObjWrapper::GetNewOrUsed()!");
-
-      return nullptr;
-    }
-  }
-
   // No need to enter the right compartment here as we only get the
   // class and private from the JSObject, neither of which cares about
   // compartments.
 
   if (nsNPObjWrapper::IsWrapper(obj)) {
     // obj is one of our own, its private data is the NPObject we're
     // looking for.
 
--- a/dom/plugins/base/nsJSNPRuntime.h
+++ b/dom/plugins/base/nsJSNPRuntime.h
@@ -53,18 +53,17 @@ public:
 
 class nsJSObjWrapper : public NPObject
 {
 public:
   JS::Heap<JSObject *> mJSObj;
   const NPP mNpp;
   bool mDestroyPending;
 
-  static NPObject *GetNewOrUsed(NPP npp, JSContext *cx,
-                                JS::Handle<JSObject*> obj);
+  static NPObject* GetNewOrUsed(NPP npp, JS::Handle<JSObject*> obj);
   static bool HasOwnProperty(NPObject* npobj, NPIdentifier npid);
 
   void trace(JSTracer* trc) {
       JS::TraceEdge(trc, &mJSObj, "nsJSObjWrapper");
   }
 
 protected:
   explicit nsJSObjWrapper(NPP npp);
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1057,19 +1057,19 @@ NPObject*
 
   // The window want to return here is the outer window, *not* the inner (since
   // we don't know what the plugin will do with it).
   nsIDocument* doc = GetDocumentFromNPP(npp);
   NS_ENSURE_TRUE(doc, nullptr);
   nsCOMPtr<nsPIDOMWindowOuter> outer = doc->GetWindow();
   NS_ENSURE_TRUE(outer, nullptr);
 
-  AutoJSContext cx;
-  JS::Rooted<JSObject*> global(cx, nsGlobalWindow::Cast(outer)->GetGlobalJSObject());
-  return nsJSObjWrapper::GetNewOrUsed(npp, cx, global);
+  JS::Rooted<JSObject*> global(nsContentUtils::RootingCx(),
+                               nsGlobalWindow::Cast(outer)->GetGlobalJSObject());
+  return nsJSObjWrapper::GetNewOrUsed(npp, global);
 }
 
 NPObject*
 _getpluginelement(NPP npp)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getpluginelement called from the wrong thread\n"));
     return nullptr;
@@ -1099,17 +1099,17 @@ NPObject*
   nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
   NS_ENSURE_TRUE(xpc, nullptr);
 
   JS::RootedObject obj(cx);
   xpc->WrapNative(cx, ::JS::CurrentGlobalOrNull(cx), element,
                   NS_GET_IID(nsIDOMElement), obj.address());
   NS_ENSURE_TRUE(obj, nullptr);
 
-  return nsJSObjWrapper::GetNewOrUsed(npp, cx, obj);
+  return nsJSObjWrapper::GetNewOrUsed(npp, obj);
 }
 
 NPIdentifier
 _getstringidentifier(const NPUTF8* name)
 {
   if (!name) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier: passed null name"));
     return nullptr;
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1542,45 +1542,16 @@ nsNPAPIPluginInstance::GetMIMEType(const
   if (!mMIMEType)
     *result = "";
   else
     *result = mMIMEType;
 
   return NS_OK;
 }
 
-nsresult
-nsNPAPIPluginInstance::GetJSContext(JSContext* *outContext)
-{
-  if (!mOwner)
-    return NS_ERROR_FAILURE;
-
-  RefPtr<nsPluginInstanceOwner> deathGrip(mOwner);
-
-  *outContext = nullptr;
-  nsCOMPtr<nsIDocument> document;
-
-  nsresult rv = mOwner->GetDocument(getter_AddRefs(document));
-
-  if (NS_SUCCEEDED(rv) && document) {
-    nsCOMPtr<nsIScriptGlobalObject> global =
-      do_QueryInterface(document->GetWindow());
-
-    if (global) {
-      nsIScriptContext *context = global->GetContext();
-
-      if (context) {
-        *outContext = context->GetNativeContext();
-      }
-    }
-  }
-
-  return rv;
-}
-
 nsPluginInstanceOwner*
 nsNPAPIPluginInstance::GetOwner()
 {
   return mOwner;
 }
 
 void
 nsNPAPIPluginInstance::SetOwner(nsPluginInstanceOwner *aOwner)
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -116,17 +116,16 @@ public:
   nsresult IsTransparent(bool* isTransparent);
   nsresult GetFormValue(nsAString& aValue);
   nsresult PushPopupsEnabledState(bool aEnabled);
   nsresult PopPopupsEnabledState();
   nsresult GetPluginAPIVersion(uint16_t* version);
   nsresult InvalidateRect(NPRect *invalidRect);
   nsresult InvalidateRegion(NPRegion invalidRegion);
   nsresult GetMIMEType(const char* *result);
-  nsresult GetJSContext(JSContext* *outContext);
 #if defined(XP_WIN)
   nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer **aContainer);
   nsresult UpdateScrollState(bool aIsScrolling);
 #endif
   nsresult HandledWindowedPluginKeyEvent(
              const mozilla::NativeEventData& aKeyEventData,
              bool aIsConsumed);
   nsPluginInstanceOwner* GetOwner();
--- a/dom/plugins/ipc/NPEventAndroid.h
+++ b/dom/plugins/ipc/NPEventAndroid.h
@@ -32,26 +32,19 @@ struct ParamTraits<mozilla::plugins::NPR
 {
     typedef mozilla::plugins::NPRemoteEvent paramType;
 
     static void Write(Message* aMsg, const paramType& aParam)
     {
         aMsg->WriteBytes(&aParam, sizeof(paramType));
     }
 
-    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     {
-        const char* bytes = 0;
-
-        if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
-            return false;
-        }
-
-        memcpy(aResult, bytes, sizeof(paramType));
-        return true;
+        return aMsg->ReadBytesInto(aIter, aResult, sizeof(paramType));
     }
 
     static void Log(const paramType& aParam, std::wstring* aLog)
     {
         // TODO
         aLog->append(L"(AndroidEvent)");
     }
 };
--- a/dom/plugins/ipc/NPEventOSX.h
+++ b/dom/plugins/ipc/NPEventOSX.h
@@ -77,17 +77,17 @@ struct ParamTraits<mozilla::plugins::NPR
                 break;
             default:
                 NS_NOTREACHED("Attempted to serialize unknown event type.");
                 return;
         }
         aMsg->WriteDouble(aParam.contentsScaleFactor);
     }
 
-    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     {
         int type = 0;
         if (!aMsg->ReadInt(aIter, &type)) {
             return false;
         }
         aResult->event.type = static_cast<NPCocoaEventType>(type);
 
         if (!aMsg->ReadUInt32(aIter, &aResult->event.version)) {
--- a/dom/plugins/ipc/NPEventUnix.h
+++ b/dom/plugins/ipc/NPEventUnix.h
@@ -50,26 +50,22 @@ struct ParamTraits<mozilla::plugins::NPR
 {
     typedef mozilla::plugins::NPRemoteEvent paramType;
 
     static void Write(Message* aMsg, const paramType& aParam)
     {
         aMsg->WriteBytes(&aParam, sizeof(paramType));
     }
 
-    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     {
-        const char* bytes = 0;
-
-        if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
+        if (!aMsg->ReadBytesInto(aIter, aResult, sizeof(paramType))) {
             return false;
         }
 
-        memcpy(aResult, bytes, sizeof(paramType));
-
 #ifdef MOZ_X11
         SetXDisplay(aResult->event);
 #endif
         return true;
     }
 
     static void Log(const paramType& aParam, std::wstring* aLog)
     {
--- a/dom/plugins/ipc/NPEventWindows.h
+++ b/dom/plugins/ipc/NPEventWindows.h
@@ -125,24 +125,21 @@ struct ParamTraits<mozilla::plugins::NPR
                 // entirely.
                 paramCopy.event.event = WM_NULL;
                 break;
         }
 
         aMsg->WriteBytes(&paramCopy, sizeof(paramType));
     }
 
-    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     {
-        const char* bytes = 0;
-
-        if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
+        if (!aMsg->ReadBytesInto(aIter, aResult, sizeof(paramType))) {
             return false;
         }
-        memcpy(aResult, bytes, sizeof(paramType));
 
         if (aResult->event.event == WM_PAINT) {
             // restore the lParam to point at the RECT
             aResult->event.lParam = reinterpret_cast<LPARAM>(&aResult->lParamData.rect);
         } else if (aResult->event.event == WM_WINDOWPOSCHANGED) {
             // restore the lParam to point at the WINDOWPOS
             aResult->event.lParam = reinterpret_cast<LPARAM>(&aResult->lParamData.windowpos);
         }
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -275,17 +275,17 @@ struct ParamTraits<NPRect>
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.top);
     WriteParam(aMsg, aParam.left);
     WriteParam(aMsg, aParam.bottom);
     WriteParam(aMsg, aParam.right);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     uint16_t top, left, bottom, right;
     if (ReadParam(aMsg, aIter, &top) &&
         ReadParam(aMsg, aIter, &left) &&
         ReadParam(aMsg, aIter, &bottom) &&
         ReadParam(aMsg, aIter, &right)) {
       aResult->top = top;
       aResult->left = left;
@@ -308,17 +308,17 @@ struct ParamTraits<NPWindowType>
 {
   typedef NPWindowType paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     aMsg->WriteInt16(int16_t(aParam));
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     int16_t result;
     if (aMsg->ReadInt16(aIter, &result)) {
       *aResult = paramType(result);
       return true;
     }
     return false;
   }
@@ -347,17 +347,17 @@ struct ParamTraits<mozilla::plugins::NPR
     aMsg->WriteULong(aParam.visualID);
     aMsg->WriteULong(aParam.colormap);
 #endif
 #if defined(XP_MACOSX)
     aMsg->WriteDouble(aParam.contentsScaleFactor);
 #endif
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     uint64_t window;
     int32_t x, y;
     uint32_t width, height;
     NPRect clipRect;
     NPWindowType type;
     if (!(aMsg->ReadUInt64(aIter, &window) &&
           ReadParam(aMsg, aIter, &x) &&
@@ -438,41 +438,45 @@ struct ParamTraits<NPNSString*>
     } else {
       UniChar *buffer = (UniChar*)moz_xmalloc(length * sizeof(UniChar));
       ::CFStringGetCharacters(cfString, ::CFRangeMake(0, length), buffer);
       aMsg->WriteBytes(buffer, length * sizeof(UniChar));
       free(buffer);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool haveString = false;
     if (!aMsg->ReadBool(aIter, &haveString)) {
       return false;
     }
     if (!haveString) {
       *aResult = nullptr;
       return true;
     }
 
     long length;
     if (!ReadParam(aMsg, aIter, &length)) {
       return false;
     }
 
-    UniChar* buffer = nullptr;
+    // Avoid integer multiplication overflow.
+    if (length > INT_MAX / static_cast<long>(sizeof(UniChar))) {
+      return false;
+    }
+
+    auto chars = mozilla::MakeUnique<UniChar[]>(length);
     if (length != 0) {
-      if (!aMsg->ReadBytes(aIter, (const char**)&buffer, length * sizeof(UniChar)) ||
-          !buffer) {
+      if (!aMsg->ReadBytesInto(aIter, chars.get(), length * sizeof(UniChar))) {
         return false;
       }
     }
 
-    *aResult = (NPNSString*)::CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8*)buffer,
+    *aResult = (NPNSString*)::CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8*)chars.get(),
                                                       length * sizeof(UniChar),
                                                       kCFStringEncodingUTF16, false);
     if (!*aResult) {
       return false;
     }
 
     return true;
   }
@@ -502,17 +506,17 @@ struct ParamTraits<NSCursorInfo>
     }
 
     uint8_t* buffer = (uint8_t*)moz_xmalloc(dataLength);
     memcpy(buffer, aParam.GetCustomImageData(), dataLength);
     aMsg->WriteBytes(buffer, dataLength);
     free(buffer);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     NSCursorInfo::Type type;
     if (!aMsg->ReadInt(aIter, (int*)&type)) {
       return false;
     }
 
     nscoord hotSpotX, hotSpotY;
     if (!ReadParam(aMsg, aIter, &hotSpotX) ||
@@ -520,26 +524,26 @@ struct ParamTraits<NSCursorInfo>
       return false;
     }
 
     uint32_t dataLength;
     if (!ReadParam(aMsg, aIter, &dataLength)) {
       return false;
     }
 
-    uint8_t* data = nullptr;
+    auto data = mozilla::MakeUnique<uint8_t[]>(dataLength);
     if (dataLength != 0) {
-      if (!aMsg->ReadBytes(aIter, (const char**)&data, dataLength) || !data) {
+      if (!aMsg->ReadBytesInto(aIter, data.get(), dataLength)) {
         return false;
       }
     }
 
     aResult->SetType(type);
     aResult->SetHotSpot(nsPoint(hotSpotX, hotSpotY));
-    aResult->SetCustomImageData(data, dataLength);
+    aResult->SetCustomImageData(data.get(), dataLength);
 
     return true;
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     const char* typeName = aParam.GetTypeName();
     nsPoint hotSpot = aParam.GetHotSpot();
@@ -561,17 +565,17 @@ struct ParamTraits<NSCursorInfo>
 #else
 template<>
 struct ParamTraits<NSCursorInfo>
 {
   typedef NSCursorInfo paramType;
   static void Write(Message* aMsg, const paramType& aParam) {
     NS_RUNTIMEABORT("NSCursorInfo isn't meaningful on this platform");
   }
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult) {
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
     NS_RUNTIMEABORT("NSCursorInfo isn't meaningful on this platform");
     return false;
   }
 };
 #endif // #ifdef XP_MACOSX
 
 template <>
 struct ParamTraits<mozilla::plugins::IPCByteRange>
@@ -579,17 +583,17 @@ struct ParamTraits<mozilla::plugins::IPC
   typedef mozilla::plugins::IPCByteRange paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.offset);
     WriteParam(aMsg, aParam.length);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     paramType p;
     if (ReadParam(aMsg, aIter, &p.offset) &&
         ReadParam(aMsg, aIter, &p.length)) {
       *aResult = p;
       return true;
     }
     return false;
@@ -601,17 +605,17 @@ struct ParamTraits<NPNVariable>
 {
   typedef NPNVariable paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, int(aParam));
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     int intval;
     if (ReadParam(aMsg, aIter, &intval)) {
       *aResult = paramType(intval);
       return true;
     }
     return false;
   }
@@ -622,17 +626,17 @@ struct ParamTraits<NPNURLVariable>
 {
   typedef NPNURLVariable paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, int(aParam));
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     int intval;
     if (ReadParam(aMsg, aIter, &intval)) {
       switch (intval) {
       case NPNURLVCookie:
       case NPNURLVProxy:
         *aResult = paramType(intval);
         return true;
@@ -648,17 +652,17 @@ struct ParamTraits<NPCoordinateSpace>
 {
   typedef NPCoordinateSpace paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, int32_t(aParam));
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     int32_t intval;
     if (ReadParam(aMsg, aIter, &intval)) {
       switch (intval) {
       case NPCoordinateSpacePlugin:
       case NPCoordinateSpaceWindow:
       case NPCoordinateSpaceFlippedWindow:
       case NPCoordinateSpaceScreen:
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -80,50 +80,35 @@ static bool IsImageLoadInEditorAppType(n
 static nsresult
 DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
 {
   // Bug 1228117: determine the correct security policy for DTD loads
   if (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DTD) {
     return NS_OK;
   }
 
-  nsresult rv = NS_OK;
+  if (IsImageLoadInEditorAppType(aLoadInfo)) {
+    return NS_OK;
+  }
 
-  nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadInfo->LoadingPrincipal();
   uint32_t flags = nsIScriptSecurityManager::STANDARD;
   if (aLoadInfo->GetAllowChrome()) {
     flags |= nsIScriptSecurityManager::ALLOW_CHROME;
   }
   if (aLoadInfo->GetDisallowScript()) {
     flags |= nsIScriptSecurityManager::DISALLOW_SCRIPT;
   }
 
-  bool isImageInEditorType = IsImageLoadInEditorAppType(aLoadInfo);
-
-  // We don't have a loadingPrincipal for TYPE_DOCUMENT
-  if (aLoadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT &&
-      !isImageInEditorType) {
-    rv = nsContentUtils::GetSecurityManager()->
-      CheckLoadURIWithPrincipal(loadingPrincipal,
-                                aURI,
-                                flags);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // If the loadingPrincipal and the triggeringPrincipal are different, then make
-  // sure the triggeringPrincipal is allowed to access that URI.
-  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
-  if (loadingPrincipal != triggeringPrincipal && !isImageInEditorType) {
-    rv = nsContentUtils::GetSecurityManager()->
-           CheckLoadURIWithPrincipal(triggeringPrincipal,
+  // Only call CheckLoadURIWithPrincipal() using the TriggeringPrincipal and not
+  // the LoadingPrincipal when SEC_ALLOW_CROSS_ORIGIN_* security flags are set,
+  // to allow, e.g. user stylesheets to load chrome:// URIs.
+  return nsContentUtils::GetSecurityManager()->
+           CheckLoadURIWithPrincipal(aLoadInfo->TriggeringPrincipal(),
                                      aURI,
                                      flags);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return NS_OK;
 }
 
 static bool
 URIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
 {
   bool hasFlags;
   nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags);
   NS_ENSURE_SUCCESS(rv, false);
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -92,18 +92,18 @@ GetStrokeDashData(SVGContentUtils::AutoS
     for (size_t i = 0; i < dashArrayLength; i++) {
       if (dashSrc[i] < 0.0) {
         return eContinuousStroke; // invalid
       }
       dashPattern[i] = Float(dashSrc[i]);
       (i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashSrc[i];
     }
   } else {
-    const nsStyleCoord *dasharray = aStyleSVG->mStrokeDasharray;
-    dashArrayLength = aStyleSVG->mStrokeDasharrayLength;
+    const nsTArray<nsStyleCoord>& dasharray = aStyleSVG->mStrokeDasharray;
+    dashArrayLength = aStyleSVG->mStrokeDasharray.Length();
     if (dashArrayLength <= 0) {
       return eContinuousStroke;
     }
     if (aElement->IsSVGElement(nsGkAtoms::path)) {
       pathScale = static_cast<SVGPathElement*>(aElement)->
         GetPathLengthScale(SVGPathElement::eForStroking);
       if (pathScale <= 0) {
         return eContinuousStroke;
--- a/dom/telephony/ipc/TelephonyIPCSerializer.h
+++ b/dom/telephony/ipc/TelephonyIPCSerializer.h
@@ -78,17 +78,17 @@ struct ParamTraits<nsITelephonyCallInfo*
 
     WriteParam(aMsg, isOutgoing);
     WriteParam(aMsg, isEmergency);
     WriteParam(aMsg, isConference);
     WriteParam(aMsg, isSwitchable);
     WriteParam(aMsg, isMergeable);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     // Check if is the null pointer we have transfered.
     bool isNull;
     if (!ReadParam(aMsg, aIter, &isNull)) {
       return false;
     }
 
     if (isNull) {
--- a/dom/tests/mochitest/fetch/fetch_test_framework.js
+++ b/dom/tests/mochitest/fetch/fetch_test_framework.js
@@ -1,9 +1,16 @@
 function testScript(script) {
+
+  // The framework runs the entire test in many different configurations.
+  // On slow platforms and builds this can make the tests likely to
+  // timeout while they are still running.  Lengthen the timeout to
+  // accomodate this.
+  SimpleTest.requestLongerTimeout(2);
+
   // reroute.html should have set this variable if a service worker is present!
   if (!("isSWPresent" in window)) {
     window.isSWPresent = false;
   }
 
   function setupPrefs() {
     return new Promise(function(resolve, reject) {
       SpecialPowers.pushPrefEnv({
--- a/dom/tests/mochitest/fetch/nested_worker_wrapper.js
+++ b/dom/tests/mochitest/fetch/nested_worker_wrapper.js
@@ -1,12 +1,15 @@
+// Hold the nested worker alive until this parent worker closes.
+var worker;
+
 addEventListener('message', function nestedWorkerWrapperOnMessage(evt) {
   removeEventListener('message', nestedWorkerWrapperOnMessage);
 
-  var worker = new Worker('worker_wrapper.js');
+  worker = new Worker('worker_wrapper.js');
 
   worker.addEventListener('message', function(evt) {
     self.postMessage({
       context: 'NestedWorker',
       type: evt.data.type,
       status: evt.data.status,
       msg: evt.data.msg,
     });
--- a/dom/tests/mochitest/fetch/test_fetch_cors.html
+++ b/dom/tests/mochitest/fetch/test_fetch_cors.html
@@ -11,17 +11,13 @@
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test"></pre>
 <script type="text/javascript" src="utils.js"> </script>
 <script type="text/javascript" src="fetch_test_framework.js"> </script>
 <script class="testbody" type="text/javascript">
-
-// XXXcatalinb: this test takes a really long time to run on android debug.
-SimpleTest.requestLongerTimeout(2);
-
 testScript("test_fetch_cors.js");
 </script>
 </body>
 </html>
 
--- a/dom/webidl/Animation.webidl
+++ b/dom/webidl/Animation.webidl
@@ -9,17 +9,17 @@
  * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
 
 [Func="nsDocument::IsElementAnimateEnabled",
  Constructor (optional KeyframeEffectReadOnly? effect = null,
-              optional AnimationTimeline? timeline = null)]
+              optional AnimationTimeline? timeline)]
 interface Animation : EventTarget {
   attribute DOMString id;
   // Bug 1049975: Make 'effect' writeable
   [Func="nsDocument::IsWebAnimationsEnabled", Pure]
   readonly attribute AnimationEffectReadOnly? effect;
   [Func="nsDocument::IsWebAnimationsEnabled"]
   readonly attribute AnimationTimeline? timeline;
   [BinaryName="startTimeAsDouble"]
--- a/dom/wifi/WifiCertService.cpp
+++ b/dom/wifi/WifiCertService.cpp
@@ -2,17 +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 "WifiCertService.h"
 
 #include "mozilla/ClearOnShutdown.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "cert.h"
 #include "certdb.h"
 #include "CryptoTask.h"
 #include "nsIDOMBlob.h"
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3577,33 +3577,16 @@ WorkerPrivateParent<Derived>::SetPrincip
   mLoadInfo.mPrincipalInfo = new PrincipalInfo();
   mLoadInfo.mPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(aLoadGroup);
 
   MOZ_ALWAYS_SUCCEEDS(
     PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo));
 }
 
 template <class Derived>
-JSContext*
-WorkerPrivateParent<Derived>::ParentJSContext() const
-{
-  AssertIsOnParentThread();
-
-  if (mParent) {
-    return mParent->GetJSContext();
-  }
-
-  AssertIsOnMainThread();
-
-  return mLoadInfo.mScriptContext ?
-         mLoadInfo.mScriptContext->GetNativeContext() :
-         nsContentUtils::GetSafeJSContext();
-}
-
-template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
 {
   AssertIsOnMainThread();
 
   // The load group should have been overriden at init time.
   mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
 }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -434,19 +434,16 @@ public:
 
   Status
   ParentStatus() const
   {
     mMutex.AssertCurrentThreadOwns();
     return mParentStatus;
   }
 
-  JSContext*
-  ParentJSContext() const;
-
   nsIScriptContext*
   GetScriptContext() const
   {
     AssertIsOnMainThread();
     return mLoadInfo.mScriptContext;
   }
 
   const nsString&
--- a/dom/xbl/builtin/android/platformHTMLBindings.xml
+++ b/dom/xbl/builtin/android/platformHTMLBindings.xml
@@ -22,18 +22,16 @@
       <handler event="keypress" keycode="VK_LEFT" modifiers="shift,alt" command="cmd_selectBeginLine"/>
       <handler event="keypress" keycode="VK_RIGHT" modifiers="shift,alt" command="cmd_selectEndLine"/>
 
       <handler event="keypress" keycode="VK_HOME" command="cmd_beginLine"/>
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift" command="cmd_selectBeginLine" />
       <handler event="keypress" keycode="VK_END" modifiers="shift" command="cmd_selectEndLine" />
 
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift" command="cmd_deleteCharForward"/>
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift,alt" command="cmd_deleteToEndOfLine"/>
       <handler event="keypress" keycode="VK_BACK" modifiers="alt" command="cmd_deleteToBeginningOfLine"/>
       <handler event="keypress" keycode="VK_DELETE" modifiers="alt" command="cmd_deleteToEndOfLine"/>
     </handlers>
   </binding>
 
   <binding id="textAreas" bindToUntrustedContent="true">
     <handlers>
 #include ../textareas-base.inc
@@ -66,18 +64,16 @@
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift" command="cmd_selectBeginLine" />
       <handler event="keypress" keycode="VK_END" modifiers="shift" command="cmd_selectEndLine" />
       <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
       <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" />
       <handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" />
 
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift" command="cmd_deleteCharForward"/>
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift,alt" command="cmd_deleteToEndOfLine"/>
       <handler event="keypress" keycode="VK_BACK" modifiers="alt" command="cmd_deleteToBeginningOfLine"/>
       <handler event="keypress" keycode="VK_DELETE" modifiers="alt" command="cmd_deleteToEndOfLine"/>
     </handlers>
   </binding>
 
   <binding id="browser">
     <handlers>
 #include ../browser-base.inc
@@ -112,18 +108,16 @@
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift" command="cmd_selectBeginLine" />
       <handler event="keypress" keycode="VK_END" modifiers="shift" command="cmd_selectEndLine" />
       <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
       <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" />
       <handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" />
 
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift" command="cmd_deleteCharForward"/>
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift,alt" command="cmd_deleteToEndOfLine"/>
       <handler event="keypress" keycode="VK_BACK" modifiers="alt" command="cmd_deleteToBeginningOfLine"/>
       <handler event="keypress" keycode="VK_DELETE" modifiers="alt" command="cmd_deleteToEndOfLine"/>
     </handlers>
   </binding>
 
   <binding id="editor">
     <handlers>
 #include ../editor-base.inc
@@ -156,15 +150,13 @@
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift" command="cmd_selectBeginLine" />
       <handler event="keypress" keycode="VK_END" modifiers="shift" command="cmd_selectEndLine" />
       <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
       <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" />
       <handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" />
 
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift" command="cmd_deleteCharForward"/>
-      <handler event="keypress" keycode="VK_BACK" modifiers="shift,alt" command="cmd_deleteToEndOfLine"/>
       <handler event="keypress" keycode="VK_BACK" modifiers="alt" command="cmd_deleteToBeginningOfLine"/>
       <handler event="keypress" keycode="VK_DELETE" modifiers="alt" command="cmd_deleteToEndOfLine"/>
     </handlers>
   </binding>
 </bindings>
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -311,18 +311,17 @@ nsXBLProtoImplAnonymousMethod::Execute(n
   JS::Rooted<JSObject*> method(cx, JS::CloneFunctionObject(cx, jsMethodObject,
                                                            scopeChain));
   if (!method)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Now call the method
 
   // Check whether script is enabled.
-  bool scriptAllowed = nsContentUtils::GetSecurityManager()->
-                         ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
+  bool scriptAllowed = xpc::Scriptability::Get(method).Allowed();
 
   if (scriptAllowed) {
     JS::Rooted<JS::Value> retval(cx);
     JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
     // No need to check the return here as AutoEntryScript has taken ownership
     // of error reporting.
     ::JS::Call(cx, scopeChain[0], methodVal, JS::HandleValueArray::empty(), &retval);
   }
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -88,16 +88,17 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/Preferences.h"
 #include "nsTextNode.h"
 #include "nsJSUtils.h"
 #include "mozilla/dom/URL.h"
 #include "nsIContentPolicy.h"
 #include "mozAutoDocUpdate.h"
+#include "xpcpublic.h"
 #include "mozilla/StyleSheetHandle.h"
 #include "mozilla/StyleSheetHandleInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 //
@@ -3506,17 +3507,17 @@ XULDocument::ExecuteScript(nsXULPrototyp
     // Execute the precompiled script with the given version
     nsAutoMicroTask mt;
 
     // We're about to run script via JS::CloneAndExecuteScript, so we need an
     // AutoEntryScript. This is Gecko specific and not in any spec.
     AutoEntryScript aes(mScriptGlobalObject, "precompiled XUL <script> element");
     JSContext* cx = aes.cx();
     JS::Rooted<JSObject*> baseGlobal(cx, JS::CurrentGlobalOrNull(cx));
-    NS_ENSURE_TRUE(nsContentUtils::GetSecurityManager()->ScriptAllowed(baseGlobal), NS_OK);
+    NS_ENSURE_TRUE(xpc::Scriptability::Get(baseGlobal).Allowed(), NS_OK);
 
     JSAddonId* addonId = mCurrentPrototype ? MapURIToAddonID(mCurrentPrototype->GetURI()) : nullptr;
     JS::Rooted<JSObject*> global(cx, xpc::GetAddonScope(cx, baseGlobal, addonId));
     NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
     JS::ExposeObjectToActiveJS(global);
     xpc_UnmarkGrayScript(scriptObject);
     JSAutoCompartment ac(cx, global);
--- a/dom/xul/templates/tests/chrome/test_bug330010.xul
+++ b/dom/xul/templates/tests/chrome/test_bug330010.xul
@@ -13,28 +13,31 @@ SimpleTest.waitForExplicitFinish();
 function boom()
 {
   const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
                          getService(Components.interfaces.nsIRDFService);
   var src = window.location.href.replace(/test_bug330010.xul/, "file_bug330010.rdf");
 
   var ds = RDF.GetDataSourceBlocking(src);
 
+  var s = document.getElementById("s");
+  s.setAttribute("datasources", "file_bug330010.rdf");
+
   var x = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox");
-  var generatedShape = document.getElementById("s").childNodes[3];
+  var generatedShape = s.childNodes[3];
   generatedShape.appendChild(x);
   document.documentElement.removeChild(document.getElementById("s"));
   ok(true, "Didn't crash");
   SimpleTest.finish();
 }
 
 ]]>
 </script>
 
-  <html:div datasources="file_bug330010.rdf" ref="urn:root" flex="1" id="s">
+  <html:div datasources="rdf:null" ref="urn:root" flex="1" id="s">
     <template>
       <rule>
         <conditions>
           <content uri="?root"/>
           <triple subject="?root"
                   predicate="urn:croczilla:xulsvg1:shapes"
                   object="?shapes"/>
           <member container="?shapes" child="?shape" id="m"/>
--- a/gfx/2d/BasePoint.h
+++ b/gfx/2d/BasePoint.h
@@ -17,17 +17,22 @@ namespace gfx {
 
 /**
  * Do not use this class directly. Subclass it, pass that subclass as the
  * Sub parameter, and only use that subclass. This allows methods to safely
  * cast 'this' to 'Sub*'.
  */
 template <class T, class Sub, class Coord = T>
 struct BasePoint {
-  T x, y;
+  union {
+    struct {
+      T x, y;
+    };
+    T components[2];
+  };
 
   // Constructors
   MOZ_CONSTEXPR BasePoint() : x(0), y(0) {}
   MOZ_CONSTEXPR BasePoint(Coord aX, Coord aY) : x(aX), y(aY) {}
 
   void MoveTo(T aX, T aY) { x = aX; y = aY; }
   void MoveBy(T aDx, T aDy) { x += aDx; y += aDy; }
 
--- a/gfx/2d/BasePoint3D.h
+++ b/gfx/2d/BasePoint3D.h
@@ -13,17 +13,22 @@ namespace gfx {
 
 /**
  * Do not use this class directly. Subclass it, pass that subclass as the
  * Sub parameter, and only use that subclass. This allows methods to safely
  * cast 'this' to 'Sub*'.
  */
 template <class T, class Sub>
 struct BasePoint3D {
-  T x, y, z;
+  union {
+    struct {
+      T x, y, z;
+    };
+    T components[3];
+  };
 
   // Constructors
   BasePoint3D() : x(0), y(0), z(0) {}
   BasePoint3D(T aX, T aY, T aZ) : x(aX), y(aY), z(aZ) {}
 
   void MoveTo(T aX, T aY, T aZ) { x = aX; y = aY; z = aZ; }
   void MoveBy(T aDx, T aDy, T aDz) { x += aDx; y += aDy; z += aDz; }
 
--- a/gfx/2d/BasePoint4D.h
+++ b/gfx/2d/BasePoint4D.h
@@ -13,17 +13,22 @@ namespace gfx {
 
 /**
  * Do not use this class directly. Subclass it, pass that subclass as the
  * Sub parameter, and only use that subclass. This allows methods to safely
  * cast 'this' to 'Sub*'.
  */
 template <class T, class Sub>
 struct BasePoint4D {
-  T x, y, z, w;
+  union {
+    struct {
+      T x, y, z, w;
+    };
+    T components[4];
+  };
 
   // Constructors
   BasePoint4D() : x(0), y(0), z(0), w(0) {}
   BasePoint4D(T aX, T aY, T aZ, T aW) : x(aX), y(aY), z(aZ), w(aW) {}
 
   void MoveTo(T aX, T aY, T aZ, T aW) { x = aX; y = aY; z = aZ; w = aW; }
   void MoveBy(T aDx, T aDy, T aDz, T aDw) { x += aDx; y += aDy; z += aDz; w += aDw; }
 
--- a/gfx/2d/BaseSize.h
+++ b/gfx/2d/BaseSize.h
@@ -13,17 +13,22 @@ namespace gfx {
 
 /**
  * Do not use this class directly. Subclass it, pass that subclass as the
  * Sub parameter, and only use that subclass. This allows methods to safely
  * cast 'this' to 'Sub*'.
  */
 template <class T, class Sub>
 struct BaseSize {
-  T width, height;
+  union {
+    struct {
+      T width, height;
+    };
+    T components[2];
+  };
 
   // Constructors
   MOZ_CONSTEXPR BaseSize() : width(0), height(0) {}
   MOZ_CONSTEXPR BaseSize(T aWidth, T aHeight) : width(aWidth), height(aHeight) {}
 
   void SizeTo(T aWidth, T aHeight) { width = aWidth; height = aHeight; }
 
   bool IsEmpty() const {
--- a/gfx/2d/BigEndianInts.h
+++ b/gfx/2d/BigEndianInts.h
@@ -2,17 +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/. */
 
 #ifndef mozilla_BigEndianInts_h
 #define mozilla_BigEndianInts_h
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 namespace mozilla {
 
 #pragma pack(push, 1)
 
 struct BigEndianUint16
 {
 #ifdef __SUNPRO_CC
@@ -72,9 +72,9 @@ struct BigEndianUint32
 private:
   uint32_t  value;
 };
 
 #pragma pack(pop)
 
 } // mozilla
 
-#endif // mozilla_BigEndianInts_h
\ No newline at end of file
+#endif // mozilla_BigEndianInts_h
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -32,19 +32,24 @@ public:
     , _21(0), _22(1.0f)
     , _31(0), _32(0)
   {}
   Matrix(Float a11, Float a12, Float a21, Float a22, Float a31, Float a32)
     : _11(a11), _12(a12)
     , _21(a21), _22(a22)
     , _31(a31), _32(a32)
   {}
-  Float _11, _12;
-  Float _21, _22;
-  Float _31, _32;
+  union {
+    struct {
+      Float _11, _12;
+      Float _21, _22;
+      Float _31, _32;
+    };
+    Float components[6];
+  };
 
   MOZ_ALWAYS_INLINE Matrix Copy() const
   {
     return Matrix(*this);
   }
 
   friend std::ostream& operator<<(std::ostream& aStream, const Matrix& aMatrix);
 
@@ -456,20 +461,25 @@ public:
     , _41(a41), _42(a42), _43(a43), _44(a44)
   {}
 
   Matrix4x4Typed(const Matrix4x4Typed& aOther)
   {
     memcpy(this, &aOther, sizeof(*this));
   }
 
-  Float _11, _12, _13, _14;
-  Float _21, _22, _23, _24;
-  Float _31, _32, _33, _34;
-  Float _41, _42, _43, _44;
+  union {
+    struct {
+      Float _11, _12, _13, _14;
+      Float _21, _22, _23, _24;
+      Float _31, _32, _33, _34;
+      Float _41, _42, _43, _44;
+    };
+    Float components[16];
+  };
 
   friend std::ostream& operator<<(std::ostream& aStream, const Matrix4x4Typed& aMatrix)
   {
     const Float *f = &aMatrix._11;
     aStream << "[ " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ;" << std::endl; f += 4;
     aStream << "  " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ;" << std::endl; f += 4;
     aStream << "  " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ;" << std::endl; f += 4;
     aStream << "  " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ]" << std::endl;
@@ -1613,19 +1623,24 @@ public:
   }
 
   Matrix5x4& operator*=(const Matrix5x4 &aMatrix)
   {
     *this = *this * aMatrix;
     return *this;
   }
 
-  Float _11, _12, _13, _14;
-  Float _21, _22, _23, _24;
-  Float _31, _32, _33, _34;
-  Float _41, _42, _43, _44;
-  Float _51, _52, _53, _54;
+  union {
+    struct {
+      Float _11, _12, _13, _14;
+      Float _21, _22, _23, _24;
+      Float _31, _32, _33, _34;
+      Float _41, _42, _43, _44;
+      Float _51, _52, _53, _54;
+    };
+    Float components[20];
+  };
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_MATRIX_H_ */
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_TYPES_H_
 #define MOZILLA_GFX_TYPES_H_
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 #include <stddef.h>
 #include <stdint.h>
 
 namespace mozilla {
 namespace gfx {
 
 typedef float Float;
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -49,16 +49,18 @@ EXPORTS.mozilla.gfx += [
     'SourceSurfaceCairo.h',
     'SourceSurfaceRawData.h',
     'StackArray.h',
     'Tools.h',
     'Types.h',
     'UserData.h',
 ]
 
+EXPORTS.mozilla.gfx += ['ssse3-scaler.h']
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
     EXPORTS.mozilla.gfx += [
         'MacIOSurface.h',
     ]
     UNIFIED_SOURCES += [
         'DrawTargetCG.cpp',
         'PathCG.cpp',
         'ScaledFontMac.cpp',
@@ -106,27 +108,29 @@ if CONFIG['MOZ_ENABLE_SKIA']:
     ]
 
 # Are we targeting x86 or x64?  If so, build SSE2 files.
 if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += [
         'BlurSSE2.cpp',
         'FilterProcessingSSE2.cpp',
         'ImageScalingSSE2.cpp',
+        'ssse3-scaler.c',
     ]
     if CONFIG['MOZ_ENABLE_SKIA']:
         SOURCES += [
             'convolverSSE2.cpp',
         ]
     DEFINES['USE_SSE2'] = True
     # The file uses SSE2 intrinsics, so it needs special compile flags on some
     # compilers.
     SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+    SOURCES['ssse3-scaler.c'].flags += CONFIG['SSSE3_FLAGS']
     if CONFIG['MOZ_ENABLE_SKIA']:
         SOURCES['convolverSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
 elif CONFIG['CPU_ARCH'].startswith('mips'):
     SOURCES += [
         'BlurLS3.cpp',
     ]
     if CONFIG['MOZ_ENABLE_SKIA']:
         SOURCES += [
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ssse3-scaler.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright © 2013 Soren Sandmann Pedersen
+ * Copyright © 2013 Red Hat, Inc.
+ * Copyright © 2016 Mozilla Foundation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ * Author: Soren Sandmann (soren.sandmann@gmail.com)
+ *         Jeff Muizelaar (jmuizelaar@mozilla.com)
+ */
+
+/* This has been adapted from the ssse3 code from pixman. It's currently
+ * a mess as I want to try it out in practice before finalizing the details.
+ */
+
+#include <stdlib.h>
+#include <mmintrin.h>
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <tmmintrin.h>
+#include <stdint.h>
+#include <assert.h>
+
+typedef int32_t                 pixman_fixed_16_16_t;
+typedef pixman_fixed_16_16_t    pixman_fixed_t;
+#define pixman_fixed_1                  (pixman_int_to_fixed(1))
+#define pixman_fixed_to_int(f)          ((int) ((f) >> 16))
+#define pixman_int_to_fixed(i)          ((pixman_fixed_t) ((i) << 16))
+#define pixman_double_to_fixed(d)       ((pixman_fixed_t) ((d) * 65536.0))
+typedef struct pixman_vector pixman_vector_t;
+
+typedef int pixman_bool_t;
+typedef int64_t                 pixman_fixed_32_32_t;
+typedef pixman_fixed_32_32_t    pixman_fixed_48_16_t;
+typedef struct { pixman_fixed_48_16_t v[3]; } pixman_vector_48_16_t;
+
+struct pixman_vector
+{
+    pixman_fixed_t      vector[3];
+};
+typedef struct pixman_transform pixman_transform_t;
+
+struct pixman_transform
+{
+    pixman_fixed_t      matrix[3][3];
+};
+
+#ifdef _MSC_VER
+#define force_inline __forceinline
+#else
+#define force_inline __inline__ __attribute__((always_inline))
+#endif
+
+#define BILINEAR_INTERPOLATION_BITS 6
+
+static force_inline int
+pixman_fixed_to_bilinear_weight (pixman_fixed_t x)
+{
+    return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) &
+                               ((1 << BILINEAR_INTERPOLATION_BITS) - 1);
+}
+
+static void
+pixman_transform_point_31_16_3d (const pixman_transform_t    *t,
+                                 const pixman_vector_48_16_t *v,
+                                 pixman_vector_48_16_t       *result)
+{
+    int i;
+    int64_t tmp[3][2];
+
+    /* input vector values must have no more than 31 bits (including sign)
+     * in the integer part */
+    assert (v->v[0] <   ((pixman_fixed_48_16_t)1 << (30 + 16)));
+    assert (v->v[0] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
+    assert (v->v[1] <   ((pixman_fixed_48_16_t)1 << (30 + 16)));
+    assert (v->v[1] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
+    assert (v->v[2] <   ((pixman_fixed_48_16_t)1 << (30 + 16)));
+    assert (v->v[2] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
+
+    for (i = 0; i < 3; i++)
+    {
+        tmp[i][0] = (int64_t)t->matrix[i][0] * (v->v[0] >> 16);
+        tmp[i][1] = (int64_t)t->matrix[i][0] * (v->v[0] & 0xFFFF);
+        tmp[i][0] += (int64_t)t->matrix[i][1] * (v->v[1] >> 16);
+        tmp[i][1] += (int64_t)t->matrix[i][1] * (v->v[1] & 0xFFFF);
+        tmp[i][0] += (int64_t)t->matrix[i][2] * (v->v[2] >> 16);
+        tmp[i][1] += (int64_t)t->matrix[i][2] * (v->v[2] & 0xFFFF);
+    }
+
+    result->v[0] = tmp[0][0] + ((tmp[0][1] + 0x8000) >> 16);
+    result->v[1] = tmp[1][0] + ((tmp[1][1] + 0x8000) >> 16);
+    result->v[2] = tmp[2][0] + ((tmp[2][1] + 0x8000) >> 16);
+}
+
+static pixman_bool_t
+pixman_transform_point_3d (const struct pixman_transform *transform,
+                           struct pixman_vector *         vector)
+{
+    pixman_vector_48_16_t tmp;
+    tmp.v[0] = vector->vector[0];
+    tmp.v[1] = vector->vector[1];
+    tmp.v[2] = vector->vector[2];
+
+    pixman_transform_point_31_16_3d (transform, &tmp, &tmp);
+
+    vector->vector[0] = tmp.v[0];
+    vector->vector[1] = tmp.v[1];
+    vector->vector[2] = tmp.v[2];
+
+    return vector->vector[0] == tmp.v[0] &&
+           vector->vector[1] == tmp.v[1] &&
+           vector->vector[2] == tmp.v[2];
+}
+
+
+struct bits_image_t
+{
+    uint32_t *                 bits;
+    int                        rowstride;
+    pixman_transform_t *transform;
+};
+
+typedef struct bits_image_t bits_image_t;
+typedef struct {
+    int unused;
+} pixman_iter_info_t;
+
+typedef struct pixman_iter_t pixman_iter_t;
+typedef void      (* pixman_iter_fini_t)         (pixman_iter_t *iter);
+
+struct pixman_iter_t
+{
+    int x, y;
+    pixman_iter_fini_t          fini;
+    bits_image_t *image;
+    uint32_t *                  buffer;
+    int width;
+    int height;
+    void *                      data;
+};
+
+typedef struct
+{
+    int		y;
+    uint64_t *	buffer;
+} line_t;
+
+typedef struct
+{
+    line_t		lines[2];
+    pixman_fixed_t	y;
+    pixman_fixed_t	x;
+    uint64_t		data[1];
+} bilinear_info_t;
+
+static void
+ssse3_fetch_horizontal (bits_image_t *image, line_t *line,
+			int y, pixman_fixed_t x, pixman_fixed_t ux, int n)
+{
+    uint32_t *bits = image->bits + y * image->rowstride;
+    __m128i vx = _mm_set_epi16 (
+	- (x + 1), x, - (x + 1), x,
+	- (x + ux + 1), x + ux,  - (x + ux + 1), x + ux);
+    __m128i vux = _mm_set_epi16 (
+	- 2 * ux, 2 * ux, - 2 * ux, 2 * ux,
+	- 2 * ux, 2 * ux, - 2 * ux, 2 * ux);
+    __m128i vaddc = _mm_set_epi16 (1, 0, 1, 0, 1, 0, 1, 0);
+    __m128i *b = (__m128i *)line->buffer;
+    __m128i vrl0, vrl1;
+
+    while ((n -= 2) >= 0)
+    {
+        __m128i vw, vr, s;
+#ifdef HACKY_PADDING
+        if (pixman_fixed_to_int(x + ux) >= image->rowstride) {
+            vrl1 = _mm_setzero_si128();
+            printf("overread 2loop\n");
+         } else {
+                 if (pixman_fixed_to_int(x + ux) < 0)
+                         printf("underflow\n");
+        vrl1 = _mm_loadl_epi64(
+            (__m128i *)(bits + (pixman_fixed_to_int(x + ux) < 0 ? 0 : pixman_fixed_to_int(x + ux))));
+        }
+#else
+        vrl1 = _mm_loadl_epi64(
+            (__m128i *)(bits + pixman_fixed_to_int(x + ux)));
+#endif
+	/* vrl1: R1, L1 */
+
+    final_pixel:
+#ifdef HACKY_PADDING
+	vrl0 = _mm_loadl_epi64 (
+	    (__m128i *)(bits + (pixman_fixed_to_int (x) < 0 ? 0 : pixman_fixed_to_int (x))));
+#else
+        vrl0 = _mm_loadl_epi64 (
+	    (__m128i *)(bits + pixman_fixed_to_int (x)));
+#endif
+        /* vrl0: R0, L0 */
+
+	/* The weights are based on vx which is a vector of 
+	 *
+	 *    - (x + 1), x, - (x + 1), x,
+	 *          - (x + ux + 1), x + ux, - (x + ux + 1), x + ux
+	 *
+	 * so the 16 bit weights end up like this:
+	 *
+	 *    iw0, w0, iw0, w0, iw1, w1, iw1, w1
+	 *
+	 * and after shifting and packing, we get these bytes:
+	 *
+	 *    iw0, w0, iw0, w0, iw1, w1, iw1, w1,
+	 *        iw0, w0, iw0, w0, iw1, w1, iw1, w1,
+	 *
+	 * which means the first and the second input pixel 
+	 * have to be interleaved like this:
+	 *
+	 *    la0, ra0, lr0, rr0, la1, ra1, lr1, rr1,
+	 *        lg0, rg0, lb0, rb0, lg1, rg1, lb1, rb1
+	 *
+	 * before maddubsw can be used.
+	 */
+
+	vw = _mm_add_epi16 (
+	    vaddc, _mm_srli_epi16 (vx, 16 - BILINEAR_INTERPOLATION_BITS));
+	/* vw: iw0, w0, iw0, w0, iw1, w1, iw1, w1
+	 */
+
+	vw = _mm_packus_epi16 (vw, vw);
+	/* vw: iw0, w0, iw0, w0, iw1, w1, iw1, w1,
+	 *         iw0, w0, iw0, w0, iw1, w1, iw1, w1
+	 */
+	vx = _mm_add_epi16 (vx, vux);
+
+	x += 2 * ux;
+
+	vr = _mm_unpacklo_epi16 (vrl1, vrl0);
+	/* vr: rar0, rar1, rgb0, rgb1, lar0, lar1, lgb0, lgb1 */
+
+	s = _mm_shuffle_epi32 (vr, _MM_SHUFFLE (1, 0, 3, 2));
+	/* s:  lar0, lar1, lgb0, lgb1, rar0, rar1, rgb0, rgb1 */
+
+	vr = _mm_unpackhi_epi8 (vr, s);
+	/* vr: la0, ra0, lr0, rr0, la1, ra1, lr1, rr1,
+	 *         lg0, rg0, lb0, rb0, lg1, rg1, lb1, rb1
+	 */
+
+	vr = _mm_maddubs_epi16 (vr, vw);
+
+	/* When the weight is 0, the inverse weight is
+	 * 128 which can't be represented in a signed byte.
+	 * As a result maddubsw computes the following:
+	 *
+	 *     r = l * -128 + r * 0
+	 *
+	 * rather than the desired
+	 *
+	 *     r = l * 128 + r * 0
+	 *
+	 * We fix this by taking the absolute value of the
+	 * result.
+	 */
+        // we can drop this if we use lower precision
+
+	vr = _mm_shuffle_epi32 (vr, _MM_SHUFFLE (2, 0, 3, 1));
+	/* vr: A0, R0, A1, R1, G0, B0, G1, B1 */
+	_mm_store_si128 (b++, vr);
+    }
+
+    if (n == -1)
+    {
+	vrl1 = _mm_setzero_si128();
+	goto final_pixel;
+    }
+
+    line->y = y;
+}
+
+// scale a line of destination pixels
+static uint32_t *
+ssse3_fetch_bilinear_cover (pixman_iter_t *iter, const uint32_t *mask)
+{
+    pixman_fixed_t fx, ux;
+    bilinear_info_t *info = iter->data;
+    line_t *line0, *line1;
+    int y0, y1;
+    int32_t dist_y;
+    __m128i vw, uvw;
+    int i;
+
+    fx = info->x;
+    ux = iter->image->transform->matrix[0][0];
+
+    y0 = pixman_fixed_to_int (info->y);
+    if (y0 < 0)
+        *(volatile char*)0 = 9;
+    y1 = y0 + 1;
+
+    // clamping in y direction
+    if (y1 >= iter->height) {
+        y1 = iter->height - 1;
+    }
+
+    line0 = &info->lines[y0 & 0x01];
+    line1 = &info->lines[y1 & 0x01];
+
+    if (line0->y != y0)
+    {
+	ssse3_fetch_horizontal (
+	    iter->image, line0, y0, fx, ux, iter->width);
+    }
+
+    if (line1->y != y1)
+    {
+	ssse3_fetch_horizontal (
+	    iter->image, line1, y1, fx, ux, iter->width);
+    }
+
+#ifdef PIXMAN_STYLE_INTERPOLATION
+    dist_y = pixman_fixed_to_bilinear_weight (info->y);
+    dist_y <<= (16 - BILINEAR_INTERPOLATION_BITS);
+
+    vw = _mm_set_epi16 (
+	dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y);
+
+#else
+    // setup the weights for the top (vw) and bottom (uvw) lines
+    dist_y = pixman_fixed_to_bilinear_weight (info->y);
+    // we use 15 instead of 16 because we need an extra bit to handle when the weights are 0 and 1
+    dist_y <<= (15 - BILINEAR_INTERPOLATION_BITS);
+
+    vw = _mm_set_epi16 (
+	dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y);
+
+
+    dist_y = (1 << BILINEAR_INTERPOLATION_BITS) - pixman_fixed_to_bilinear_weight (info->y);
+    dist_y <<= (15 - BILINEAR_INTERPOLATION_BITS);
+    uvw = _mm_set_epi16 (
+	dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y);
+#endif
+
+    for (i = 0; i + 3 < iter->width; i += 4)
+    {
+	__m128i top0 = _mm_load_si128 ((__m128i *)(line0->buffer + i));
+	__m128i bot0 = _mm_load_si128 ((__m128i *)(line1->buffer + i));
+	__m128i top1 = _mm_load_si128 ((__m128i *)(line0->buffer + i + 2));
+	__m128i bot1 = _mm_load_si128 ((__m128i *)(line1->buffer + i + 2));
+#ifdef PIXMAN_STYLE_INTERPOLATION
+	__m128i r0, r1, tmp, p;
+
+        r0 = _mm_mulhi_epu16 (
+	    _mm_sub_epi16 (bot0, top0), vw);
+	tmp = _mm_cmplt_epi16 (bot0, top0);
+	tmp = _mm_and_si128 (tmp, vw);
+	r0 = _mm_sub_epi16 (r0, tmp);
+	r0 = _mm_add_epi16 (r0, top0);
+	r0 = _mm_srli_epi16 (r0, BILINEAR_INTERPOLATION_BITS);
+	/* r0:  A0 R0 A1 R1 G0 B0 G1 B1 */
+        //r0 = _mm_shuffle_epi32 (r0, _MM_SHUFFLE (2, 0, 3, 1));
+	/* r0:  A1 R1 G1 B1 A0 R0 G0 B0 */
+
+        // tmp = bot1 < top1 ? vw : 0;
+        // r1 = (bot1 - top1)*vw + top1 - tmp
+        // r1 = bot1*vw - vw*top1 + top1 - tmp
+        // r1 = bot1*vw + top1 - vw*top1 - tmp
+        // r1 = bot1*vw + top1*(1 - vw) - tmp
+	r1 = _mm_mulhi_epu16 (
+	    _mm_sub_epi16 (bot1, top1), vw);
+	tmp = _mm_cmplt_epi16 (bot1, top1);
+	tmp = _mm_and_si128 (tmp, vw);
+	r1 = _mm_sub_epi16 (r1, tmp);
+	r1 = _mm_add_epi16 (r1, top1);
+	r1 = _mm_srli_epi16 (r1, BILINEAR_INTERPOLATION_BITS);
+	//r1 = _mm_shuffle_epi32 (r1, _MM_SHUFFLE (2, 0, 3, 1));
+	/* r1: A3 R3 G3 B3 A2 R2 G2 B2 */
+#else
+	__m128i r0, r1, p;
+        top0 = _mm_mulhi_epu16 (top0, uvw);
+        bot0 = _mm_mulhi_epu16 (bot0, vw);
+        r0 = _mm_add_epi16(top0, bot0);
+        r0 = _mm_srli_epi16(r0, BILINEAR_INTERPOLATION_BITS-1);
+
+        top1 = _mm_mulhi_epu16 (top1, uvw);
+        bot1 = _mm_mulhi_epu16 (bot1, vw);
+        r1 = _mm_add_epi16(top1, bot1);
+        r1 = _mm_srli_epi16(r1, BILINEAR_INTERPOLATION_BITS-1);
+#endif
+
+	p = _mm_packus_epi16 (r0, r1);
+	_mm_storeu_si128 ((__m128i *)(iter->buffer + i), p);
+    }
+
+    while (i < iter->width)
+    {
+	__m128i top0 = _mm_load_si128 ((__m128i *)(line0->buffer + i));
+	__m128i bot0 = _mm_load_si128 ((__m128i *)(line1->buffer + i));
+
+#ifdef PIXMAN_STYLE_INTERPOLATION
+	__m128i r0, tmp, p;
+	r0 = _mm_mulhi_epu16 (
+	    _mm_sub_epi16 (bot0, top0), vw);
+	tmp = _mm_cmplt_epi16 (bot0, top0);
+	tmp = _mm_and_si128 (tmp, vw);
+	r0 = _mm_sub_epi16 (r0, tmp);
+	r0 = _mm_add_epi16 (r0, top0);
+	r0 = _mm_srli_epi16 (r0, BILINEAR_INTERPOLATION_BITS);
+	/* r0:  A0 R0 A1 R1 G0 B0 G1 B1 */
+	r0 = _mm_shuffle_epi32 (r0, _MM_SHUFFLE (2, 0, 3, 1));
+	/* r0:  A1 R1 G1 B1 A0 R0 G0 B0 */
+#else
+	__m128i r0, p;
+        top0 = _mm_mulhi_epu16 (top0, uvw);
+        bot0 = _mm_mulhi_epu16 (bot0, vw);
+        r0 = _mm_add_epi16(top0, bot0);
+        r0 = _mm_srli_epi16(r0, BILINEAR_INTERPOLATION_BITS-1);
+#endif
+
+	p = _mm_packus_epi16 (r0, r0);
+
+	if (iter->width - i == 1)
+	{
+	    *(uint32_t *)(iter->buffer + i) = _mm_cvtsi128_si32 (p);
+	    i++;
+	}
+	else
+	{
+	    _mm_storel_epi64 ((__m128i *)(iter->buffer + i), p);
+	    i += 2;
+	}
+    }
+
+    info->y += iter->image->transform->matrix[1][1];
+
+    return iter->buffer;
+}
+
+static void
+ssse3_bilinear_cover_iter_fini (pixman_iter_t *iter)
+{
+    free (iter->data);
+}
+
+static void
+ssse3_bilinear_cover_iter_init (pixman_iter_t *iter)
+{
+    int width = iter->width;
+    bilinear_info_t *info;
+    pixman_vector_t v;
+
+    /* Reference point is the center of the pixel */
+    v.vector[0] = pixman_int_to_fixed (iter->x) + pixman_fixed_1 / 2;
+    v.vector[1] = pixman_int_to_fixed (iter->y) + pixman_fixed_1 / 2;
+    v.vector[2] = pixman_fixed_1;
+
+    if (!pixman_transform_point_3d (iter->image->transform, &v))
+	goto fail;
+
+    info = malloc (sizeof (*info) + (2 * width - 1) * sizeof (uint64_t) + 64);
+    if (!info)
+	goto fail;
+
+    info->x = v.vector[0] - pixman_fixed_1 / 2;
+    info->y = v.vector[1] - pixman_fixed_1 / 2;
+
+#define ALIGN(addr)							\
+    ((void *)((((uintptr_t)(addr)) + 15) & (~15)))
+
+    /* It is safe to set the y coordinates to -1 initially
+     * because COVER_CLIP_BILINEAR ensures that we will only
+     * be asked to fetch lines in the [0, height) interval
+     */
+    info->lines[0].y = -1;
+    info->lines[0].buffer = ALIGN (&(info->data[0]));
+    info->lines[1].y = -1;
+    info->lines[1].buffer = ALIGN (info->lines[0].buffer + width);
+
+    iter->fini = ssse3_bilinear_cover_iter_fini;
+
+    iter->data = info;
+    return;
+
+fail:
+    /* Something went wrong, either a bad matrix or OOM; in such cases,
+     * we don't guarantee any particular rendering.
+     */
+    iter->fini = NULL;
+}
+
+/* scale the src from src_width/height to dest_width/height drawn
+ * into the rectangle x,y width,height
+ * src_stride and dst_stride are 4 byte units */
+void ssse3_scale_data(uint32_t *src, int src_width, int src_height, int src_stride,
+                      uint32_t *dest, int dest_width, int dest_height,
+                      int dest_stride,
+                      int x, int y,
+                      int width, int height)
+{
+    //XXX: assert(src_width > 1)
+    pixman_transform_t transform = {
+        { { pixman_fixed_1, 0, 0 },
+            { 0, pixman_fixed_1, 0 },
+            { 0, 0, pixman_fixed_1 } }
+    };
+    double width_scale = ((double)src_width)/dest_width;
+    double height_scale = ((double)src_height)/dest_height;
+#define AVOID_PADDING
+#ifdef AVOID_PADDING
+    // scale up by enough that we don't read outside of the bounds of the source surface
+    // currently this is required to avoid reading out of bounds.
+    if (width_scale < 1) {
+        width_scale = (double)(src_width-1)/dest_width;
+        transform.matrix[0][2] = pixman_fixed_1/2;
+    }
+    if (height_scale < 1) {
+        height_scale = (double)(src_height-1)/dest_height;
+        transform.matrix[1][2] = pixman_fixed_1/2;
+    }
+#endif
+    transform.matrix[0][0] = pixman_double_to_fixed(width_scale);
+    transform.matrix[1][1] = pixman_double_to_fixed(height_scale);
+    transform.matrix[2][2] = pixman_fixed_1;
+
+    bits_image_t image;
+    image.bits = src;
+    image.transform = &transform;
+    image.rowstride = src_stride;
+
+    pixman_iter_t iter;
+    iter.image = &image;
+    iter.x = x;
+    iter.y = y;
+    iter.width = width;
+    iter.height = src_height;
+    iter.buffer = dest;
+
+    ssse3_bilinear_cover_iter_init(&iter);
+    for (int iy = 0; iy < height; iy++) {
+        ssse3_fetch_bilinear_cover(&iter, NULL);
+        iter.buffer += dest_stride;
+    }
+    ssse3_bilinear_cover_iter_fini(&iter);
+
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ssse3-scaler.h
@@ -0,0 +1,22 @@
+#/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_2D_SSSE3_SCALER_H_
+#define MOZILLA_GFX_2D_SSSE3_SCALER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void ssse3_scale_data(uint32_t *src, int src_width, int src_height,
+                int src_stride,
+                uint32_t *dest, int dest_width, int dest_height,
+                int dest_rowstride,
+                int x, int y,
+                int width, int height);
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MOZILLA_GFX_2D_SSS3_SCALER_H_
--- a/gfx/ipc/D3DMessageUtils.cpp
+++ b/gfx/ipc/D3DMessageUtils.cpp
@@ -48,24 +48,22 @@ ParamTraits<DxgiAdapterDesc>::Write(Mess
   WriteParam(aMsg, aParam.AdapterLuid.LowPart);
   WriteParam(aMsg, aParam.AdapterLuid.HighPart);
 #else
   MOZ_ASSERT_UNREACHABLE("DxgiAdapterDesc is Windows-only");
 #endif
 }
 
 bool
-ParamTraits<DxgiAdapterDesc>::Read(const Message* aMsg, void** aIter, paramType* aResult)
+ParamTraits<DxgiAdapterDesc>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
 {
 #if defined(XP_WIN)
-  const char* description = nullptr;
-  if (!aMsg->ReadBytes(aIter, &description, sizeof(aResult->Description))) {
+  if (!aMsg->ReadBytesInto(aIter, aResult->Description, sizeof(aResult->Description))) {
     return false;
   }
-  memcpy(aResult->Description, description, sizeof(aResult->Description));
 
   if (ReadParam(aMsg, aIter, &aResult->VendorId) &&
       ReadParam(aMsg, aIter, &aResult->DeviceId) &&
       ReadParam(aMsg, aIter, &aResult->SubSysId) &&
       ReadParam(aMsg, aIter, &aResult->Revision) &&
       ReadParam(aMsg, aIter, &aResult->DedicatedVideoMemory) &&
       ReadParam(aMsg, aIter, &aResult->DedicatedSystemMemory) &&
       ReadParam(aMsg, aIter, &aResult->SharedSystemMemory) &&
--- a/gfx/ipc/D3DMessageUtils.h
+++ b/gfx/ipc/D3DMessageUtils.h
@@ -35,14 +35,14 @@ struct DxgiAdapterDesc
 
 namespace IPC {
 
 template <>
 struct ParamTraits<DxgiAdapterDesc>
 {
   typedef DxgiAdapterDesc paramType;
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
 };
 
 } // namespace IPC
 
 #endif // _include_gfx_ipc_D3DMessageUtils_h__
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -49,17 +49,17 @@ struct ParamTraits<mozilla::gfx::Matrix>
     WriteParam(aMsg, aParam._11);
     WriteParam(aMsg, aParam._12);
     WriteParam(aMsg, aParam._21);
     WriteParam(aMsg, aParam._22);
     WriteParam(aMsg, aParam._31);
     WriteParam(aMsg, aParam._32);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (ReadParam(aMsg, aIter, &aResult->_11) &&
         ReadParam(aMsg, aIter, &aResult->_12) &&
         ReadParam(aMsg, aIter, &aResult->_21) &&
         ReadParam(aMsg, aIter, &aResult->_22) &&
         ReadParam(aMsg, aIter, &aResult->_31) &&
         ReadParam(aMsg, aIter, &aResult->_32))
       return true;
@@ -84,17 +84,17 @@ struct ParamTraits<mozilla::gfx::Matrix4
 #define Wr(_f)  WriteParam(msg, param. _f)
     Wr(_11); Wr(_12); Wr(_13); Wr(_14);
     Wr(_21); Wr(_22); Wr(_23); Wr(_24);
     Wr(_31); Wr(_32); Wr(_33); Wr(_34);
     Wr(_41); Wr(_42); Wr(_43); Wr(_44);
 #undef Wr
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
 #define Rd(_f)  ReadParam(msg, iter, &result-> _f)
     return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
             Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
             Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
             Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44));
 #undef Rd
   }
@@ -111,17 +111,17 @@ struct ParamTraits<mozilla::gfx::Matrix5
     Wr(_11); Wr(_12); Wr(_13); Wr(_14);
     Wr(_21); Wr(_22); Wr(_23); Wr(_24);
     Wr(_31); Wr(_32); Wr(_33); Wr(_34);
     Wr(_41); Wr(_42); Wr(_43); Wr(_44);
     Wr(_51); Wr(_52); Wr(_53); Wr(_54);
 #undef Wr
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
 #define Rd(_f)  ReadParam(msg, iter, &result-> _f)
     return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
             Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
             Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
             Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44) &&
             Rd(_51) && Rd(_52) && Rd(_53) && Rd(_54));
 #undef Rd
@@ -134,17 +134,17 @@ struct ParamTraits<gfxPoint>
   typedef gfxPoint paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.x);
     WriteParam(aMsg, aParam.y);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->x) &&
             ReadParam(aMsg, aIter, &aResult->y));
  }
 };
 
 template<>
 struct ParamTraits<gfxSize>
@@ -152,17 +152,17 @@ struct ParamTraits<gfxSize>
   typedef gfxSize paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.width);
     WriteParam(aMsg, aParam.height);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (ReadParam(aMsg, aIter, &aResult->width) &&
         ReadParam(aMsg, aIter, &aResult->height))
       return true;
 
     return false;
   }
 };
@@ -175,17 +175,17 @@ struct ParamTraits<gfxRect>
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.x);
     WriteParam(aMsg, aParam.y);
     WriteParam(aMsg, aParam.width);
     WriteParam(aMsg, aParam.height);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->x) &&
            ReadParam(aMsg, aIter, &aResult->y) &&
            ReadParam(aMsg, aIter, &aResult->width) &&
            ReadParam(aMsg, aIter, &aResult->height);
   }
 };
 
@@ -292,17 +292,17 @@ struct ParamTraits<mozilla::gfx::Color>
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.r);
     WriteParam(msg, param.g);
     WriteParam(msg, param.b);
     WriteParam(msg, param.a);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->r) &&
             ReadParam(msg, iter, &result->g) &&
             ReadParam(msg, iter, &result->b) &&
             ReadParam(msg, iter, &result->a));
   }
 };
 
@@ -312,17 +312,17 @@ struct ParamTraits<nsPoint>
   typedef nsPoint paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y));
   }
 };
 
 template<>
 struct ParamTraits<nsIntPoint>
@@ -330,17 +330,17 @@ struct ParamTraits<nsIntPoint>
   typedef nsIntPoint paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y));
   }
 };
 
 template<typename T>
 struct ParamTraits<mozilla::gfx::IntSizeTyped<T> >
@@ -348,17 +348,17 @@ struct ParamTraits<mozilla::gfx::IntSize
   typedef mozilla::gfx::IntSizeTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
 template<typename Region, typename Rect, typename Iter>
 struct RegionParamTraits
@@ -373,17 +373,17 @@ struct RegionParamTraits
       MOZ_RELEASE_ASSERT(!r.IsEmpty());
       WriteParam(msg, r);
     }
     // empty rects are sentinel values because nsRegions will never
     // contain them
     WriteParam(msg, Rect());
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     RegionBuilder<Region> builder;
     Rect rect;
     while (ReadParam(msg, iter, &rect)) {
       if (rect.IsEmpty()) {
         *result = builder.ToRegion();
         return true;
       }
@@ -407,83 +407,83 @@ struct ParamTraits<mozilla::gfx::IntSize
   typedef mozilla::gfx::IntSize paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
 template<class T>
 struct ParamTraits< mozilla::gfx::CoordTyped<T> >
 {
   typedef mozilla::gfx::CoordTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.value);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->value));
   }
 };
 
 template<class T>
 struct ParamTraits< mozilla::gfx::IntCoordTyped<T> >
 {
   typedef mozilla::gfx::IntCoordTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.value);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->value));
   }
 };
 
 template<class T, class U>
 struct ParamTraits< mozilla::gfx::ScaleFactor<T, U> >
 {
   typedef mozilla::gfx::ScaleFactor<T, U> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.scale);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->scale));
   }
 };
 
 template<class T, class U>
 struct ParamTraits< mozilla::gfx::ScaleFactors2D<T, U> >
 {
   typedef mozilla::gfx::ScaleFactors2D<T, U> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.xScale);
     WriteParam(msg, param.yScale);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->xScale) &&
             ReadParam(msg, iter, &result->yScale));
   }
 };
 
 template<class T>
 struct ParamTraits< mozilla::gfx::PointTyped<T> >
@@ -491,17 +491,17 @@ struct ParamTraits< mozilla::gfx::PointT
   typedef mozilla::gfx::PointTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y));
   }
 };
 
 template<class F, class T>
 struct ParamTraits< mozilla::gfx::Point3DTyped<F, T> >
@@ -510,17 +510,17 @@ struct ParamTraits< mozilla::gfx::Point3
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
     WriteParam(msg, param.z);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y) &&
             ReadParam(msg, iter, &result->z));
   }
 };
 
 template<class T>
@@ -529,17 +529,17 @@ struct ParamTraits< mozilla::gfx::IntPoi
   typedef mozilla::gfx::IntPointTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y));
   }
 };
 
 template<class T>
 struct ParamTraits< mozilla::gfx::SizeTyped<T> >
@@ -547,17 +547,17 @@ struct ParamTraits< mozilla::gfx::SizeTy
   typedef mozilla::gfx::SizeTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
 template<class T>
 struct ParamTraits< mozilla::gfx::RectTyped<T> >
@@ -567,17 +567,17 @@ struct ParamTraits< mozilla::gfx::RectTy
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y) &&
             ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
@@ -589,17 +589,17 @@ struct ParamTraits< mozilla::gfx::IntRec
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y) &&
             ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
@@ -611,17 +611,17 @@ struct ParamTraits<mozilla::gfx::Margin>
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.top);
     WriteParam(msg, param.right);
     WriteParam(msg, param.bottom);
     WriteParam(msg, param.left);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->top) &&
             ReadParam(msg, iter, &result->right) &&
             ReadParam(msg, iter, &result->bottom) &&
             ReadParam(msg, iter, &result->left));
   }
 };
 
@@ -633,17 +633,17 @@ struct ParamTraits< mozilla::gfx::Margin
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.top);
     WriteParam(msg, param.right);
     WriteParam(msg, param.bottom);
     WriteParam(msg, param.left);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->top) &&
             ReadParam(msg, iter, &result->right) &&
             ReadParam(msg, iter, &result->bottom) &&
             ReadParam(msg, iter, &result->left));
   }
 };
 
@@ -655,17 +655,17 @@ struct ParamTraits<nsRect>
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
-  static bool Read(const Message* msg, void** iter, paramType* result)
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y) &&
             ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
@@ -685,17 +685,17 @@ struct ParamTraits<mozilla::layers::Fram
 // Helper class for reading bitfields.
 // If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
 template <typename ParamType>
 struct BitfieldHelper
 {
   // We need this helper because we can't get the address of a bitfield to
   // pass directly to ReadParam. So instead we read it into a temporary bool
   // and set the bitfield using a setter function
-  static bool ReadBoolForBitfield(const Message* aMsg, void** aIter,
+  static bool ReadBoolForBitfield(const Message* aMsg, PickleIterator* aIter,
         ParamType* aResult, void (ParamType::*aSetter)(bool))
   {
     bool value;
     if (ReadParam(aMsg, aIter, &value)) {
       (aResult->*aSetter)(value);
       return true;
     }
     return false;
@@ -730,17 +730,17 @@ struct ParamTraits<mozilla::layers::Fram
     WriteParam(aMsg, aParam.mPaintRequestTime);
     WriteParam(aMsg, aParam.mScrollUpdateType);
     WriteParam(aMsg, aParam.mIsRootContent);
     WriteParam(aMsg, aParam.mDoSmoothScroll);
     WriteParam(aMsg, aParam.mUseDisplayPortMargins);
     WriteParam(aMsg, aParam.mIsScrollInfoLayer);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mScrollId) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellResolution) &&
             ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
             ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
             ReadParam(aMsg, aIter, &aResult->mCriticalDisplayPort) &&
             ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
             ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
@@ -773,17 +773,17 @@ struct ParamTraits<mozilla::layers::Scro
     WriteParam(aMsg, aParam.mScrollSnapTypeX);
     WriteParam(aMsg, aParam.mScrollSnapTypeY);
     WriteParam(aMsg, aParam.mScrollSnapIntervalX);
     WriteParam(aMsg, aParam.mScrollSnapIntervalY);
     WriteParam(aMsg, aParam.mScrollSnapDestination);
     WriteParam(aMsg, aParam.mScrollSnapCoordinates);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeX) &&
             ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeY) &&
             ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalX) &&
             ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalY) &&
             ReadParam(aMsg, aIter, &aResult->mScrollSnapDestination) &&
             ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates));
   }
@@ -795,17 +795,17 @@ struct ParamTraits<mozilla::layers::Laye
   typedef mozilla::layers::LayerClip paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mClipRect);
     WriteParam(aMsg, aParam.mMaskLayerIndex);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mClipRect) &&
             ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex));
   }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::ScrollMetadata>
@@ -825,27 +825,27 @@ struct ParamTraits<mozilla::layers::Scro
     WriteParam(aMsg, aParam.mScrollClip);
     WriteParam(aMsg, aParam.mHasScrollgrab);
     WriteParam(aMsg, aParam.mAllowVerticalScrollWithWheel);
     WriteParam(aMsg, aParam.mIsLayersIdRoot);
     WriteParam(aMsg, aParam.mUsesContainerScrolling);
     WriteParam(aMsg, aParam.mForceDisableApz);
   }
 
-  static bool ReadContentDescription(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool ReadContentDescription(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     nsCString str;
     if (!ReadParam(aMsg, aIter, &str)) {
       return false;
     }
     aResult->SetContentDescription(str);
     return true;
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mMetrics) &&
             ReadParam(aMsg, aIter, &aResult->mSnapInfo) &&
             ReadParam(aMsg, aIter, &aResult->mScrollParentId) &&
             ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
             ReadContentDescription(aMsg, aIter, aResult) &&
             ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) &&
             ReadParam(aMsg, aIter, &aResult->mPageScrollAmount) &&
@@ -867,17 +867,17 @@ struct ParamTraits<mozilla::layers::Text
   {
     WriteParam(aMsg, aParam.mParentBackend);
     WriteParam(aMsg, aParam.mMaxTextureSize);
     WriteParam(aMsg, aParam.mSupportsTextureBlitting);
     WriteParam(aMsg, aParam.mSupportsPartialUploads);
     WriteParam(aMsg, aParam.mSyncHandle);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool result = ReadParam(aMsg, aIter, &aResult->mParentBackend) &&
                   ReadParam(aMsg, aIter, &aResult->mMaxTextureSize) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
                   ReadParam(aMsg, aIter, &aResult->mSyncHandle);
     return result;
   }
@@ -889,17 +889,17 @@ struct ParamTraits<mozilla::layers::Text
   typedef mozilla::layers::TextureInfo paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mCompositableType);
     WriteParam(aMsg, aParam.mTextureFlags);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mCompositableType) &&
            ReadParam(aMsg, aIter, &aResult->mTextureFlags);
   }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::CompositableType>
@@ -932,17 +932,17 @@ struct ParamTraits<mozilla::layers::Scro
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mLayersId);
     WriteParam(aMsg, aParam.mPresShellId);
     WriteParam(aMsg, aParam.mScrollId);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mLayersId) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mScrollId));
   }
 };
 
 
@@ -954,17 +954,17 @@ struct ParamTraits<mozilla::layers::Zoom
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mAllowZoom);
     WriteParam(aMsg, aParam.mAllowDoubleTapZoom);
     WriteParam(aMsg, aParam.mMinZoom);
     WriteParam(aMsg, aParam.mMaxZoom);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mAllowZoom) &&
             ReadParam(aMsg, aIter, &aResult->mAllowDoubleTapZoom) &&
             ReadParam(aMsg, aIter, &aResult->mMinZoom) &&
             ReadParam(aMsg, aIter, &aResult->mMaxZoom));
   }
 };
 
@@ -977,17 +977,17 @@ struct ParamTraits<mozilla::layers::Even
   {
     WriteParam(aMsg, aParam.mHitRegion);
     WriteParam(aMsg, aParam.mDispatchToContentHitRegion);
     WriteParam(aMsg, aParam.mNoActionRegion);
     WriteParam(aMsg, aParam.mHorizontalPanRegion);
     WriteParam(aMsg, aParam.mVerticalPanRegion);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mHitRegion) &&
             ReadParam(aMsg, aIter, &aResult->mDispatchToContentHitRegion) &&
             ReadParam(aMsg, aIter, &aResult->mNoActionRegion) &&
             ReadParam(aMsg, aIter, &aResult->mHorizontalPanRegion) &&
             ReadParam(aMsg, aIter, &aResult->mVerticalPanRegion));
   }
 };
@@ -1032,17 +1032,17 @@ struct ParamTraits<mozilla::gfx::Attribu
 #undef CASE_TYPE
 
         default:
           MOZ_CRASH("GFX: unhandled attribute type");
       }
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     uint32_t count;
     if (!ReadParam(aMsg, aIter, &count)) {
       return false;
     }
     for (uint32_t i = 0; i < count; i++) {
       mozilla::gfx::AttributeType type;
       if (!ReadParam(aMsg, aIter, &type)) {
@@ -1111,17 +1111,17 @@ struct ParamTraits<mozilla::gfx::FilterP
     WriteParam(aMsg, aParam.NumberOfInputs());
     for (size_t i = 0; i < aParam.NumberOfInputs(); i++) {
       WriteParam(aMsg, aParam.InputPrimitiveIndex(i));
       WriteParam(aMsg, aParam.InputColorSpace(i));
     }
     WriteParam(aMsg, aParam.Attributes());
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     mozilla::gfx::PrimitiveType type;
     mozilla::gfx::IntRect primitiveSubregion;
     mozilla::gfx::IntRect filterSpaceBounds;
     bool isTainted = false;
     mozilla::gfx::ColorSpace outputColorSpace;
     size_t numberOfInputs = 0;
     if (!ReadParam(aMsg, aIter, &type) ||
@@ -1159,17 +1159,17 @@ struct ParamTraits<mozilla::gfx::FilterD
 {
   typedef mozilla::gfx::FilterDescription paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mPrimitives);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mPrimitives));
   }
 };
 
 typedef mozilla::layers::GeckoContentController::APZStateChange APZStateChange;
 
 template <>
@@ -1205,17 +1205,17 @@ struct ParamTraits<mozilla::layers::Asyn
     WriteParam(aMsg, aParam.mViewId);
     WriteParam(aMsg, aParam.mPresShellId);
     WriteParam(aMsg, aParam.mDragStartSequenceNumber);
     WriteParam(aMsg, aParam.mScrollbarDragOffset);
     WriteParam(aMsg, aParam.mScrollTrack);
     WriteParam(aMsg, aParam.mDirection);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mViewId) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mDragStartSequenceNumber) &&
             ReadParam(aMsg, aIter, &aResult->mScrollbarDragOffset) &&
             ReadParam(aMsg, aIter, &aResult->mScrollTrack) &&
             ReadParam(aMsg, aIter, &aResult->mDirection));
   }
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -61,19 +61,21 @@ enum class TextureFlags : uint32_t {
   // during the transaction, because the producer may want to write
   // to it again.
   IMMEDIATE_UPLOAD   = 1 << 10,
   // The texture is part of a component-alpha pair
   COMPONENT_ALPHA    = 1 << 11,
   // The texture is being allocated for a compositor that no longer exists.
   // This flag is only used in the parent process.
   INVALID_COMPOSITOR = 1 << 12,
+  // The texture was created by converting from YCBCR to RGB
+  RGB_FROM_YCBCR = 1 << 13,
 
   // OR union of all valid bits
-  ALL_BITS           = (1 << 13) - 1,
+  ALL_BITS           = (1 << 14) - 1,
   // the default flags
   DEFAULT = NO_FLAGS
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TextureFlags)
 
 static inline bool
 TextureRequiresLocking(TextureFlags aFlags)
 {
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
 #include "LayerScope.h"
 
 #include "nsAppRunner.h"
 #include "Composer2D.h"
 #include "Effects.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 
 #include "TexturePoolOGL.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerManagerComposite.h"
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3144,17 +3144,17 @@ AsyncPanZoomController::ReportCheckerboa
     }
     mCheckerboardEvent = nullptr;
   }
 }
 
 bool AsyncPanZoomController::IsCurrentlyCheckerboarding() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
-  if (!gfxPrefs::APZAllowCheckerboarding()) {
+  if (!gfxPrefs::APZAllowCheckerboarding() || mScrollMetadata.IsApzForceDisabled()) {
     return false;
   }
 
   CSSPoint currentScrollOffset = mFrameMetrics.GetScrollOffset() + mTestAsyncScrollOffset;
   CSSRect painted = mLastContentPaintMetrics.GetDisplayPort() + mLastContentPaintMetrics.GetScrollOffset();
   painted.Inflate(CSSMargin::FromAppUnits(nsMargin(1, 1, 1, 1)));   // fuzz for rounding error
   CSSRect visible = CSSRect(currentScrollOffset, mFrameMetrics.CalculateCompositedSizeInCssPixels());
   if (painted.Contains(visible)) {
--- a/gfx/layers/apz/testutil/APZTestData.h
+++ b/gfx/layers/apz/testutil/APZTestData.h
@@ -138,17 +138,17 @@ struct ParamTraits<mozilla::layers::APZT
   typedef mozilla::layers::APZTestData paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mPaints);
     WriteParam(aMsg, aParam.mRepaintRequests);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mPaints) &&
             ReadParam(aMsg, aIter, &aResult->mRepaintRequests));
   }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::APZTestData::ScrollFrameData>
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -7,16 +7,18 @@
 #include "BasicLayersImpl.h"            // for FillRectWithMask
 #include "TextureHostBasic.h"
 #include "mozilla/layers/Effects.h"
 #include "nsIWidget.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "mozilla/gfx/Tools.h"
+#include "mozilla/gfx/ssse3-scaler.h"
+#include "mozilla/SSE.h"
 #include "gfxUtils.h"
 #include "YCbCrUtils.h"
 #include <algorithm>
 #include "ImageContainer.h"
 #include "gfxPrefs.h"
 
 namespace mozilla {
 using namespace mozilla::gfx;
@@ -194,17 +196,20 @@ BasicCompositor::CreateRenderTargetForWi
   }
 
   return rt.forget();
 }
 
 already_AddRefed<DataTextureSource>
 BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
 {
-  RefPtr<DataTextureSource> result = new DataTextureSourceBasic(nullptr);
+  RefPtr<DataTextureSourceBasic> result = new DataTextureSourceBasic(nullptr);
+  if (aFlags & TextureFlags::RGB_FROM_YCBCR) {
+      result->mFromYCBCR = true;
+  }
   return result.forget();
 }
 
 already_AddRefed<DataTextureSource>
 BasicCompositor::CreateDataTextureSourceAround(DataSourceSurface* aSurface)
 {
   RefPtr<DataTextureSource> result = new DataTextureSourceBasic(aSurface);
   return result.forget();
@@ -270,16 +275,79 @@ SetupMask(const EffectChain& aEffectChai
       gfxWarning() << "Invalid sourceMask effect";
     }
     MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
     aMaskTransform = effectMask->mMaskTransform.As2D();
     aMaskTransform.PostTranslate(-aOffset.x, -aOffset.y);
   }
 }
 
+static bool
+AttemptVideoScale(TextureSourceBasic* aSource, const SourceSurface* aSourceMask,
+                       gfx::Float aOpacity, CompositionOp aBlendMode,
+                       const TexturedEffect* aTexturedEffect,
+                       const Matrix& aNewTransform, const gfx::Rect& aRect,
+                       const gfx::IntRect& aClipRect,
+                       DrawTarget* aDest, const DrawTarget* aBuffer)
+{
+  if (!mozilla::supports_ssse3())
+      return false;
+  if (aNewTransform.IsTranslation()) // unscaled painting should take the regular path
+      return false;
+  if (aNewTransform.HasNonAxisAlignedTransform() || aNewTransform.HasNegativeScaling())
+      return false;
+  if (aSourceMask || aOpacity != 1.0f)
+      return false;
+  if (aBlendMode != CompositionOp::OP_OVER && aBlendMode != CompositionOp::OP_SOURCE)
+      return false;
+
+  IntRect dstRect;
+  // the compiler should know a lot about aNewTransform at this point
+  // maybe it can do some sophisticated optimization of the following
+  if (!aNewTransform.TransformBounds(aRect).ToIntRect(&dstRect))
+      return false;
+
+  if (!(aTexturedEffect->mTextureCoords == Rect(0.0f, 0.0f, 1.0f, 1.0f)))
+      return false;
+  if (aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16)
+      return false;
+
+  uint8_t* dstData;
+  IntSize dstSize;
+  int32_t dstStride;
+  SurfaceFormat dstFormat;
+  if (aDest->LockBits(&dstData, &dstSize, &dstStride, &dstFormat)) {
+    // If we're not painting to aBuffer the clip will
+    // be applied later
+    IntRect fillRect = dstRect;
+    if (aDest == aBuffer) {
+      // we need to clip fillRect because LockBits ignores the clip on the aDest
+      fillRect = fillRect.Intersect(aClipRect);
+    }
+
+    fillRect = fillRect.Intersect(IntRect(IntPoint(0, 0), aDest->GetSize()));
+    IntPoint offset = fillRect.TopLeft() - dstRect.TopLeft();
+
+    RefPtr<DataSourceSurface> srcSource = aSource->GetSurface(aDest)->GetDataSurface();
+    DataSourceSurface::ScopedMap mapSrc(srcSource, DataSourceSurface::READ);
+
+    ssse3_scale_data((uint32_t*)mapSrc.GetData(), srcSource->GetSize().width, srcSource->GetSize().height,
+                     mapSrc.GetStride()/4,
+                     ((uint32_t*)dstData) + fillRect.x + (dstStride / 4) * fillRect.y, dstRect.width, dstRect.height,
+                     dstStride / 4,
+                     offset.x, offset.y,
+                     fillRect.width, fillRect.height);
+
+    aDest->ReleaseBits(dstData);
+    return true;
+  } else {
+    return false;
+  }
+}
+
 void
 BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                           const gfx::IntRect& aClipRect,
                           const EffectChain &aEffectChain,
                           gfx::Float aOpacity,
                           const gfx::Matrix4x4& aTransform,
                           const gfx::Rect& aVisibleRect)
 {
@@ -358,22 +426,31 @@ BasicCompositor::DrawQuad(const gfx::Rec
       break;
     }
     case EffectTypes::RGB: {
       TexturedEffect* texturedEffect =
           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
       TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();
 
       if (source && texturedEffect->mPremultiplied) {
+        // we have a fast path for video here
+        if (source->mFromYCBCR &&
+            AttemptVideoScale(source, sourceMask, aOpacity, blendMode,
+                              texturedEffect,
+                              newTransform, aRect, aClipRect - offset,
+                              dest, buffer)) {
+          // we succeeded in scaling
+        } else {
           DrawSurfaceWithTextureCoords(dest, aRect,
                                        source->GetSurface(dest),
                                        texturedEffect->mTextureCoords,
                                        texturedEffect->mFilter,
                                        DrawOptions(aOpacity, blendMode),
                                        sourceMask, &maskTransform);
+        }
       } else if (source) {
         SourceSurface* srcSurf = source->GetSurface(dest);
         if (srcSurf) {
           RefPtr<DataSourceSurface> srcData = srcSurf->GetDataSurface();
 
           // Yes, we re-create the premultiplied data every time.
           // This might be better with a cache, eventually.
           RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData);
--- a/gfx/layers/basic/TextureHostBasic.h
+++ b/gfx/layers/basic/TextureHostBasic.h
@@ -16,16 +16,18 @@ namespace mozilla {
 namespace layers {
 
 /**
  * A texture source interface that can be used by the software Compositor.
  */
 class TextureSourceBasic
 {
 public:
+  TextureSourceBasic() : mFromYCBCR(false) {}
   virtual ~TextureSourceBasic() {}
   virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) = 0;
+  bool mFromYCBCR; // we to track sources from YCBCR so we can use a less accurate fast path for video
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_TEXTUREHOSTBASIC_H_
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -1038,23 +1038,27 @@ TextureClient::RemoveFromCompositable(Co
 void
 TextureClient::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) {
   mRemoveFromCompositableWaiter = aWaiter;
 }
 
 already_AddRefed<gfx::DataSourceSurface>
 TextureClient::GetAsSurface()
 {
-  Lock(OpenMode::OPEN_READ);
+  if (!Lock(OpenMode::OPEN_READ)) {
+    return nullptr;
+  }
   RefPtr<gfx::DataSourceSurface> data;
-  RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget();
-  if (dt) {
-    RefPtr<gfx::SourceSurface> surf = dt->Snapshot();
-    if (surf) {
-      data = surf->GetDataSurface();
+  {  // scope so that the DrawTarget is destroyed before Unlock()
+    RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget();
+    if (dt) {
+      RefPtr<gfx::SourceSurface> surf = dt->Snapshot();
+      if (surf) {
+        data = surf->GetDataSurface();
+      }
     }
   }
   Unlock();
   return data.forget();
 }
 
 void
 TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
--- a/gfx/layers/composite/FrameUniformityData.h
+++ b/gfx/layers/composite/FrameUniformityData.h
@@ -57,17 +57,17 @@ struct ParamTraits<mozilla::layers::Fram
 {
   typedef mozilla::layers::FrameUniformityData paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mUniformities);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ParamTraitsStd<std::map<uintptr_t,float>>::Read(aMsg, aIter, &aResult->mUniformities);
   }
 };
 
 } // namespace IPC
 
 #endif // mozilla_layers_FrameUniformityData_h_
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -671,17 +671,17 @@ BufferTextureHost::Upload(nsIntRegion *a
 
     if (!mCompositor->SupportsEffect(EffectTypes::YCBCR)) {
       RefPtr<gfx::DataSourceSurface> surf =
         ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(buf, mDescriptor.get_YCbCrDescriptor());
       if (NS_WARN_IF(!surf)) {
         return false;
       }
       if (!mFirstSource) {
-        mFirstSource = mCompositor->CreateDataTextureSource(mFlags);
+        mFirstSource = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR);
         mFirstSource->SetOwner(this);
       }
       mFirstSource->Update(surf, aRegion);
       return true;
     }
 
     RefPtr<DataTextureSource> srcY;
     RefPtr<DataTextureSource> srcU;
--- a/gfx/layers/d3d11/CompositorD3D11.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11.hlsl
@@ -316,17 +316,17 @@ float4 ComputeBlendSourceColor(const VS_
     if (iBlendConfig.x == PS_LAYER_RGB) {
       return RGBShader(tmp);
     } else if (iBlendConfig.x == PS_LAYER_RGBA) {
       return RGBAShader(tmp);
     } else if (iBlendConfig.x == PS_LAYER_YCBCR) {
       return YCbCrShader(tmp);
     }
     return SolidColorShader(tmp);
-  } else if (iBlendConfig.y == PS_MASK_2D) {
+  } else if (iBlendConfig.y == PS_MASK) {
     VS_MASK_OUTPUT tmp;
     tmp.vPosition = aVertex.vPosition;
     tmp.vTexCoords = aVertex.vTexCoords;
     tmp.vMaskCoords = aVertex.vMaskCoords;
 
     if (iBlendConfig.x == PS_LAYER_RGB) {
       return RGBShaderMask(tmp);
     } else if (iBlendConfig.x == PS_LAYER_RGBA) {
--- a/gfx/layers/ipc/FenceUtils.cpp
+++ b/gfx/layers/ipc/FenceUtils.cpp
@@ -28,17 +28,17 @@ ParamTraits<FenceHandle>::Write(Message*
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   RefPtr<FenceHandle::FdObj> fence = handle.GetAndResetFdObj();
   aMsg->WriteFileDescriptor(base::FileDescriptor(fence->GetAndResetFd(), true));
 #endif
 }
 
 bool
 ParamTraits<FenceHandle>::Read(const Message* aMsg,
-                               void** aIter, paramType* aResult)
+                               PickleIterator* aIter, paramType* aResult)
 {
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   base::FileDescriptor fd;
   if (aMsg->ReadFileDescriptor(aIter, &fd)) {
     aResult->Merge(FenceHandle(new FenceHandle::FdObj(fd.fd)));
   }
 #endif
   return true;
--- a/gfx/layers/ipc/FenceUtils.h
+++ b/gfx/layers/ipc/FenceUtils.h
@@ -71,14 +71,14 @@ private:
 
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::layers::FenceHandle> {
   typedef mozilla::layers::FenceHandle paramType;
 
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
 };
 
 } // namespace IPC
 
 #endif // IPC_FencerUtils_h
--- a/gfx/layers/ipc/GonkNativeHandleUtils.cpp
+++ b/gfx/layers/ipc/GonkNativeHandleUtils.cpp
@@ -27,17 +27,17 @@ ParamTraits<GonkNativeHandle>::Write(Mes
 
   for (size_t i = 0; i < static_cast<size_t>(nativeHandle->numFds); ++i) {
     aMsg->WriteFileDescriptor(base::FileDescriptor(nativeHandle->data[i], true));
   }
 }
 
 bool
 ParamTraits<GonkNativeHandle>::Read(const Message* aMsg,
-                               void** aIter, paramType* aResult)
+                               PickleIterator* aIter, paramType* aResult)
 {
   size_t nbytes;
   const char* data;
   if (!aMsg->ReadSize(aIter, &nbytes) ||
       !aMsg->ReadBytes(aIter, &data, nbytes)) {
     return false;
   }
 
--- a/gfx/layers/ipc/GonkNativeHandleUtils.h
+++ b/gfx/layers/ipc/GonkNativeHandleUtils.h
@@ -15,22 +15,22 @@
 namespace IPC {
 
 #ifdef MOZ_WIDGET_GONK
 template <>
 struct ParamTraits<mozilla::layers::GonkNativeHandle> {
   typedef mozilla::layers::GonkNativeHandle paramType;
 
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
 };
 #else
 template <>
 struct ParamTraits<mozilla::layers::GonkNativeHandle> {
   typedef mozilla::layers::GonkNativeHandle paramType;
   static void Write(Message*, const paramType&) {}
-  static bool Read(const Message*, void**, paramType*) { return false; }
+  static bool Read(const Message*, PickleIterator*, paramType*) { return false; }
 };
 #endif
 
 } // namespace IPC
 
 #endif // IPC_GonkNativeHandleUtils_h
--- a/gfx/layers/ipc/ShadowLayerUtils.h
+++ b/gfx/layers/ipc/ShadowLayerUtils.h
@@ -45,33 +45,33 @@ struct GrallocBufferRef {
 
 namespace IPC {
 
 #if !defined(MOZ_HAVE_SURFACEDESCRIPTORX11)
 template <>
 struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
   typedef mozilla::layers::SurfaceDescriptorX11 paramType;
   static void Write(Message*, const paramType&) {}
-  static bool Read(const Message*, void**, paramType*) { return false; }
+  static bool Read(const Message*, PickleIterator*, paramType*) { return false; }
 };
 #endif  // !defined(MOZ_HAVE_XSURFACEDESCRIPTORX11)
 
 #if !defined(MOZ_HAVE_SURFACEDESCRIPTORGRALLOC)
 template <>
 struct ParamTraits<mozilla::layers::MagicGrallocBufferHandle> {
   typedef mozilla::layers::MagicGrallocBufferHandle paramType;
   static void Write(Message*, const paramType&) {}
-  static bool Read(const Message*, void**, paramType*) { return false; }
+  static bool Read(const Message*, PickleIterator*, paramType*) { return false; }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::GrallocBufferRef> {
   typedef mozilla::layers::GrallocBufferRef paramType;
   static void Write(Message*, const paramType&) {}
-  static bool Read(const Message*, void**, paramType*) { return false; }
+  static bool Read(const Message*, PickleIterator*, paramType*) { return false; }
 };
 #endif  // !defined(MOZ_HAVE_XSURFACEDESCRIPTORGRALLOC)
 
 template <>
 struct ParamTraits<mozilla::ScreenRotation>
   : public ContiguousEnumSerializer<
              mozilla::ScreenRotation,
              mozilla::ROTATION_0,
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -44,17 +44,17 @@ void
 ParamTraits<GrallocBufferRef>::Write(Message* aMsg,
                                      const paramType& aParam)
 {
   aMsg->WriteInt(aParam.mOwner);
   aMsg->WriteInt64(aParam.mKey);
 }
 
 bool
-ParamTraits<GrallocBufferRef>::Read(const Message* aMsg, void** aIter,
+ParamTraits<GrallocBufferRef>::Read(const Message* aMsg, PickleIterator* aIter,
                                     paramType* aParam)
 {
   int owner;
   int64_t index;
   if (!aMsg->ReadInt(aIter, &owner) ||
       !aMsg->ReadInt64(aIter, &index)) {
     printf_stderr("ParamTraits<GrallocBufferRef>::Read() failed to read a message\n");
     return false;
@@ -104,17 +104,17 @@ ParamTraits<MagicGrallocBufferHandle>::W
     // synchonously and the parent-side buffer can only be dropped if
     // there's a crash.
     aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
   }
 }
 
 bool
 ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg,
-                                            void** aIter, paramType* aResult)
+                                            PickleIterator* aIter, paramType* aResult)
 {
   MOZ_ASSERT(!aResult->mGraphicBuffer.get());
   MOZ_ASSERT(aResult->mRef.mOwner == 0);
   MOZ_ASSERT(aResult->mRef.mKey == -1);
 
   size_t nbytes;
   const char* data;
   int owner;
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.h
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.h
@@ -74,22 +74,22 @@ android::sp<android::GraphicBuffer> GetG
 
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::layers::MagicGrallocBufferHandle> {
   typedef mozilla::layers::MagicGrallocBufferHandle paramType;
 
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
 };
 
 template<>
 struct ParamTraits<mozilla::layers::GrallocBufferRef> {
   typedef mozilla::layers::GrallocBufferRef paramType;
   static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
 };
 
 
 } // namespace IPC
 
 #endif  // mozilla_layers_ShadowLayerUtilsGralloc_h
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.h
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.h
@@ -66,17 +66,17 @@ struct ParamTraits<mozilla::layers::Surf
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mId);
     WriteParam(aMsg, aParam.mSize);
     WriteParam(aMsg, aParam.mFormat);
     WriteParam(aMsg, aParam.mGLXPixmap);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult) {
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
     return (ReadParam(aMsg, aIter, &aResult->mId) &&
             ReadParam(aMsg, aIter, &aResult->mSize) &&
             ReadParam(aMsg, aIter, &aResult->mFormat) &&
             ReadParam(aMsg, aIter, &aResult->mGLXPixmap)
             );
   }
 };
 
--- a/gfx/thebes/gfxColor.h
+++ b/gfx/thebes/gfxColor.h
@@ -2,17 +2,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 GFX_COLOR_H
 #define GFX_COLOR_H
 
 #include "mozilla/Attributes.h" // for MOZ_ALWAYS_INLINE
-#include "mozilla/Endian.h" // for mozilla::NativeEndian::swapToBigEndian
+#include "mozilla/EndianUtils.h" // for mozilla::NativeEndian::swapToBigEndian
 
 /**
  * GFX_BLOCK_RGB_TO_FRGB(from,to)
  *   sizeof(*from) == sizeof(char)
  *   sizeof(*to)   == sizeof(uint32_t)
  *
  * Copy 4 pixels at a time, reading blocks of 12 bytes (RGB x4)
  *   and writing blocks of 16 bytes (FRGB x4)
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -5,17 +5,17 @@
 
 #ifndef GFX_FONT_UTILS_H
 #define GFX_FONT_UTILS_H
 
 #include "gfxPlatform.h"
 #include "nsComponentManagerUtils.h"
 #include "nsTArray.h"
 #include "mozilla/Likely.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/UniquePtr.h"
 
 #include "zlib.h"
 #include <algorithm>
 
 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
 #ifdef __MINGW32__
@@ -1004,10 +1004,9 @@ protected:
                    ((mEncoding == rhs.mEncoding) && (mLanguage < rhs.mLanguage));
         }
     };
     static const MacFontNameCharsetMapping gMacFontNameCharsets[];
     static const char* gISOFontNameCharsets[];
     static const char* gMSFontNameCharsets[];
 };
 
-
 #endif /* GFX_FONT_UTILS_H */
--- a/gfx/vr/ipc/VRMessageUtils.h
+++ b/gfx/vr/ipc/VRMessageUtils.h
@@ -32,17 +32,17 @@ struct ParamTraits<mozilla::gfx::VRDevic
   typedef mozilla::gfx::VRDeviceUpdate paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mDeviceInfo);
     WriteParam(aMsg, aParam.mSensorState);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mDeviceInfo)) ||
         !ReadParam(aMsg, aIter, &(aResult->mSensorState))) {
       return false;
     }
     return true;
   }
 };
@@ -53,17 +53,17 @@ struct ParamTraits<mozilla::gfx::VRSenso
   typedef mozilla::gfx::VRSensorUpdate paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mDeviceID);
     WriteParam(aMsg, aParam.mSensorState);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mDeviceID)) ||
         !ReadParam(aMsg, aIter, &(aResult->mSensorState))) {
       return false;
     }
     return true;
   }
 };
@@ -87,17 +87,17 @@ struct ParamTraits<mozilla::gfx::VRDevic
       WriteParam(aMsg, aParam.mMaximumEyeFOV[i]);
       WriteParam(aMsg, aParam.mRecommendedEyeFOV[i]);
       WriteParam(aMsg, aParam.mEyeFOV[i]);
       WriteParam(aMsg, aParam.mEyeTranslation[i]);
       WriteParam(aMsg, aParam.mEyeProjectionMatrix[i]);
     }
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mType)) ||
         !ReadParam(aMsg, aIter, &(aResult->mDeviceID)) ||
         !ReadParam(aMsg, aIter, &(aResult->mDeviceName)) ||
         !ReadParam(aMsg, aIter, &(aResult->mSupportedSensorBits)) ||
         !ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
         !ReadParam(aMsg, aIter, &(aResult->mScreenRect)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIsFakeScreen)) ||
@@ -145,17 +145,17 @@ struct ParamTraits<mozilla::gfx::VRHMDSe
     WriteParam(aMsg, aParam.linearVelocity[0]);
     WriteParam(aMsg, aParam.linearVelocity[1]);
     WriteParam(aMsg, aParam.linearVelocity[2]);
     WriteParam(aMsg, aParam.linearAcceleration[0]);
     WriteParam(aMsg, aParam.linearAcceleration[1]);
     WriteParam(aMsg, aParam.linearAcceleration[2]);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->timestamp)) ||
         !ReadParam(aMsg, aIter, &(aResult->inputFrameID)) ||
         !ReadParam(aMsg, aIter, &(aResult->flags)) ||
         !ReadParam(aMsg, aIter, &(aResult->orientation[0])) ||
         !ReadParam(aMsg, aIter, &(aResult->orientation[1])) ||
         !ReadParam(aMsg, aIter, &(aResult->orientation[2])) ||
         !ReadParam(aMsg, aIter, &(aResult->orientation[3])) ||
@@ -188,17 +188,17 @@ struct ParamTraits<mozilla::gfx::VRField
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.upDegrees);
     WriteParam(aMsg, aParam.rightDegrees);
     WriteParam(aMsg, aParam.downDegrees);
     WriteParam(aMsg, aParam.leftDegrees);
   }
 
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->upDegrees)) ||
         !ReadParam(aMsg, aIter, &(aResult->rightDegrees)) ||
         !ReadParam(aMsg, aIter, &(aResult->downDegrees)) ||
         !ReadParam(aMsg, aIter, &(aResult->leftDegrees))) {
       return false;
     }
 
--- a/image/DecoderFactory.cpp
+++ b/image/DecoderFactory.cpp
@@ -199,16 +199,17 @@ DecoderFactory::CreateMetadataDecoder(De
   }
 
   return decoder.forget();
 }
 
 /* static */ already_AddRefed<Decoder>
 DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
                                        SourceBuffer* aSourceBuffer,
+                                       const Maybe<IntSize>& aTargetSize,
                                        SurfaceFlags aSurfaceFlags)
 {
   if (aType == DecoderType::UNKNOWN) {
     return nullptr;
   }
 
   RefPtr<Decoder> decoder =
     GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
@@ -227,16 +228,22 @@ DecoderFactory::CreateAnonymousDecoder(D
   // Decoder::GetCurrentFrame(). That means that anonymous decoders should
   // always be first-frame-only decoders, because nobody ever wants the *last*
   // frame.
   decoderFlags |= DecoderFlags::FIRST_FRAME_ONLY;
 
   decoder->SetDecoderFlags(decoderFlags);
   decoder->SetSurfaceFlags(aSurfaceFlags);
 
+  // Set a target size for downscale-during-decode if applicable.
+  if (aTargetSize) {
+    DebugOnly<nsresult> rv = decoder->SetTargetSize(*aTargetSize);
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
+  }
+
   decoder->Init();
   if (NS_FAILED(decoder->GetDecoderError())) {
     return nullptr;
   }
 
   return decoder.forget();
 }
 
--- a/image/DecoderFactory.h
+++ b/image/DecoderFactory.h
@@ -115,22 +115,27 @@ public:
 
   /**
    * Creates and initializes an anonymous decoder (one which isn't associated
    * with an Image object). Only the first frame of the image will be decoded.
    *
    * @param aType Which type of decoder to create - JPEG, PNG, etc.
    * @param aSourceBuffer The SourceBuffer which the decoder will read its data
    *                      from.
+   * @param aTargetSize If not Nothing(), the target size which the image should
+   *                    be scaled to during decoding. It's an error to specify
+   *                    a target size for a decoder type which doesn't support
+   *                    downscale-during-decode.
    * @param aSurfaceFlags Flags specifying the type of output this decoder
    *                      should produce.
    */
   static already_AddRefed<Decoder>
   CreateAnonymousDecoder(DecoderType aType,
                          SourceBuffer* aSourceBuffer,
+                         const Maybe<gfx::IntSize>& aTargetSize,
                          SurfaceFlags aSurfaceFlags);
 
   /**
    * Creates and initializes an anonymous metadata decoder (one which isn't
    * associated with an Image object). This decoder will only decode the image's
    * header, extracting metadata like the size of the image. No actual image
    * data will be decoded and no surfaces will be allocated.
    *
--- a/image/ImageOps.cpp
+++ b/image/ImageOps.cpp
@@ -115,16 +115,17 @@ ImageOps::DecodeToSurface(nsIInputStream
   sourceBuffer->Complete(NS_OK);
 
   // Create a decoder.
   DecoderType decoderType =
     DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
   RefPtr<Decoder> decoder =
     DecoderFactory::CreateAnonymousDecoder(decoderType,
                                            sourceBuffer,
+                                           Nothing(),
                                            ToSurfaceFlags(aFlags));
   if (!decoder) {
     return nullptr;
   }
 
   // Run the decoder synchronously.
   decoder->Decode();
   if (!decoder->GetDecodeDone() || decoder->HasError()) {
--- a/image/decoders/EXIF.cpp
+++ b/image/decoders/EXIF.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EXIF.h"
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 namespace mozilla {
 namespace image {
 
 // Section references in this file refer to the EXIF v2.3 standard, also known
 // as CIPA DC-008-Translation-2010.
 
 // See Section 4.6.4, Table 4.
--- a/image/decoders/icon/gtk/nsIconChannel.cpp
+++ b/image/decoders/icon/gtk/nsIconChannel.cpp
@@ -2,17 +2,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/. */
 
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "mozilla/DebugOnly.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include <algorithm>
 
 #ifdef MOZ_ENABLE_GIO
 #include <gio/gio.h>
 #endif
 
 #include <gtk/gtk.h>
 
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsContentUtils.h"
 #include "nsIconChannel.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "nsIIconURI.h"
 #include "nsIServiceManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsXPIDLString.h"
 #include "nsMimeTypes.h"
 #include "nsMemory.h"
 #include "nsIStringStream.h"
--- a/image/decoders/icon/qt/nsIconChannel.cpp
+++ b/image/decoders/icon/qt/nsIconChannel.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <QIcon>
 
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 #include "nsMimeTypes.h"
 #include "nsIMIMEService.h"
 
 #include "nsIStringBundle.h"
 
 #include "nsNetUtil.h"
 #include "nsNullPrincipal.h"
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -81,17 +81,17 @@
 //   support.
 // - We treat OS2-BMPv2 files as if they are WinBMPv3 (i.e. ignore the extra 24
 //   bytes in the info header), which in practice is good enough.
 
 #include <stdlib.h>
 
 #include "ImageLogging.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/Likely.h"
 #include "nsBMPDecoder.h"
 
 #include "nsIInputStream.h"
 #include "RasterImage.h"
 #include <algorithm>
 
 using namespace mozilla::gfx;
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* This is a Cross-Platform ICO Decoder, which should work everywhere, including
  * Big-Endian machines like the PowerPC. */
 
 #include <stdlib.h>
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/Move.h"
 #include "nsICODecoder.h"
 
 #include "RasterImage.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -14,17 +14,17 @@
 
 #include "nspr.h"
 #include "nsCRT.h"
 #include "gfxColor.h"
 
 #include "jerror.h"
 
 #include "gfxPlatform.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/Telemetry.h"
 
 extern "C" {
 #include "iccjpeg.h"
 }
 
 #if MOZ_BIG_ENDIAN
 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
--- a/image/encoders/bmp/nsBMPEncoder.cpp
+++ b/image/encoders/bmp/nsBMPEncoder.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCRT.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "nsBMPEncoder.h"
 #include "prprf.h"
 #include "nsString.h"
 #include "nsStreamUtils.h"
 #include "nsTArray.h"
 
 using namespace mozilla;
--- a/image/encoders/ico/nsICOEncoder.cpp
+++ b/image/encoders/ico/nsICOEncoder.cpp
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCRT.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "nsBMPEncoder.h"
 #include "nsPNGEncoder.h"
 #include "nsICOEncoder.h"
 #include "prprf.h"
 #include "nsString.h"
 #include "nsStreamUtils.h"
 #include "nsTArray.h"
 
--- a/image/test/gtest/Common.cpp
+++ b/image/test/gtest/Common.cpp
@@ -156,17 +156,17 @@ RectIsSolidColor(SourceSurface* aSurface
 
 already_AddRefed<Decoder>
 CreateTrivialDecoder()
 {
   gfxPrefs::GetSingleton();
   DecoderType decoderType = DecoderFactory::GetDecoderType("image/gif");
   RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer();
   RefPtr<Decoder> decoder =
-    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer,
+    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
                                            DefaultSurfaceFlags());
   return decoder.forget();
 }
 
 void AssertCorrectPipelineFinalState(SurfaceFilter* aFilter,
                                      const gfx::IntRect& aInputSpaceRect,
                                      const gfx::IntRect& aOutputSpaceRect)
 {
@@ -505,10 +505,60 @@ ImageTestCase NoFrameDelayGIFTestCase()
 {
   // This is an invalid (or at least, questionably valid) GIF that's animated
   // even though it specifies a frame delay of zero. It's animated, but it's not
   // marked TEST_CASE_IS_ANIMATED because the metadata decoder can't detect that
   // it's animated.
   return ImageTestCase("no-frame-delay.gif", "image/gif", IntSize(100, 100));
 }
 
+ImageTestCase DownscaledPNGTestCase()
+{
+  // This testcase (and all the other "downscaled") testcases) consists of 25
+  // lines of green, followed by 25 lines of red, followed by 25 lines of green,
+  // followed by 25 more lines of red. It's intended that tests downscale it
+  // from 100x100 to 20x20, so we specify a 20x20 output size.
+  return ImageTestCase("downscaled.png", "image/png", IntSize(100, 100),
+                       IntSize(20, 20));
+}
+
+ImageTestCase DownscaledGIFTestCase()
+{
+  return ImageTestCase("downscaled.gif", "image/gif", IntSize(100, 100),
+                       IntSize(20, 20));
+}
+
+ImageTestCase DownscaledJPGTestCase()
+{
+  return ImageTestCase("downscaled.jpg", "image/jpeg", IntSize(100, 100),
+                       IntSize(20, 20));
+}
+
+ImageTestCase DownscaledBMPTestCase()
+{
+  return ImageTestCase("downscaled.bmp", "image/bmp", IntSize(100, 100),
+                       IntSize(20, 20));
+}
+
+ImageTestCase DownscaledICOTestCase()
+{
+  return ImageTestCase("downscaled.ico", "image/x-icon", IntSize(100, 100),
+                       IntSize(20, 20), TEST_CASE_IS_TRANSPARENT);
+}
+
+ImageTestCase DownscaledIconTestCase()
+{
+  return ImageTestCase("downscaled.icon", "image/icon", IntSize(100, 100),
+                       IntSize(20, 20), TEST_CASE_IS_TRANSPARENT);
+}
+
+ImageTestCase DownscaledTransparentICOWithANDMaskTestCase()
+{
+  // This test case is an ICO with AND mask transparency. We want to ensure that
+  // we can downscale it without crashing or triggering ASAN failures, but its
+  // content isn't simple to verify, so for now we don't check the output.
+  return ImageTestCase("transparent-ico-with-and-mask.ico", "image/x-icon",
+                       IntSize(32, 32), IntSize(20, 20),
+                       TEST_CASE_IS_TRANSPARENT | TEST_CASE_IGNORE_OUTPUT);
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/test/gtest/Common.h
+++ b/image/test/gtest/Common.h
@@ -28,33 +28,48 @@ namespace image {
 
 enum TestCaseFlags
 {
   TEST_CASE_DEFAULT_FLAGS   = 0,
   TEST_CASE_IS_FUZZY        = 1 << 0,
   TEST_CASE_HAS_ERROR       = 1 << 1,
   TEST_CASE_IS_TRANSPARENT  = 1 << 2,
   TEST_CASE_IS_ANIMATED     = 1 << 3,
+  TEST_CASE_IGNORE_OUTPUT   = 1 << 4,
 };
 
 struct ImageTestCase
 {
   ImageTestCase(const char* aPath,
                 const char* aMimeType,
                 gfx::IntSize aSize,
                 uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
     : mPath(aPath)
     , mMimeType(aMimeType)
     , mSize(aSize)
+    , mOutputSize(aSize)
+    , mFlags(aFlags)
+  { }
+
+  ImageTestCase(const char* aPath,
+                const char* aMimeType,
+                gfx::IntSize aSize,
+                gfx::IntSize aOutputSize,
+                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
+    : mPath(aPath)
+    , mMimeType(aMimeType)
+    , mSize(aSize)
+    , mOutputSize(aOutputSize)
     , mFlags(aFlags)
   { }
 
   const char* mPath;
   const char* mMimeType;
   gfx::IntSize mSize;
+  gfx::IntSize mOutputSize;
   uint32_t mFlags;
 };
 
 struct BGRAColor
 {
   BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha)
     : mBlue(aBlue)
     , mGreen(aGreen)
@@ -307,12 +322,20 @@ ImageTestCase TransparentPNGTestCase();
 ImageTestCase TransparentGIFTestCase();
 ImageTestCase FirstFramePaddingGIFTestCase();
 ImageTestCase NoFrameDelayGIFTestCase();
 
 ImageTestCase TransparentBMPWhenBMPAlphaEnabledTestCase();
 ImageTestCase RLE4BMPTestCase();
 ImageTestCase RLE8BMPTestCase();
 
+ImageTestCase DownscaledPNGTestCase();
+ImageTestCase DownscaledGIFTestCase();
+ImageTestCase DownscaledJPGTestCase();
+ImageTestCase DownscaledBMPTestCase();
+ImageTestCase DownscaledICOTestCase();
+ImageTestCase DownscaledIconTestCase();
+ImageTestCase DownscaledTransparentICOWithANDMaskTestCase();
+
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_test_gtest_Common_h
--- a/image/test/gtest/TestDecoders.cpp
+++ b/image/test/gtest/TestDecoders.cpp
@@ -33,31 +33,31 @@ TEST(ImageDecoders, ImageModuleAvailable
   // We can run into problems if XPCOM modules get initialized in the wrong
   // order. It's important that this test run first, both as a sanity check and
   // to ensure we get the module initialization order we want.
   nsCOMPtr<imgITools> imgTools =
     do_CreateInstance("@mozilla.org/image/tools;1");
   EXPECT_TRUE(imgTools != nullptr);
 }
 
-static void
-CheckDecoderResults(const ImageTestCase& aTestCase, Decoder* aDecoder)
+static already_AddRefed<SourceSurface>
+CheckDecoderState(const ImageTestCase& aTestCase, Decoder* aDecoder)
 {
   EXPECT_TRUE(aDecoder->GetDecodeDone());
   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
             aDecoder->HasError());
   EXPECT_TRUE(!aDecoder->WasAborted());
 
   // Verify that the decoder made the expected progress.
   Progress progress = aDecoder->TakeProgress();
   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
             bool(progress & FLAG_HAS_ERROR));
 
   if (aTestCase.mFlags & TEST_CASE_HAS_ERROR) {
-    return;  // That's all we can check for bad images.
+    return nullptr;  // That's all we can check for bad images.
   }
 
   EXPECT_TRUE(bool(progress & FLAG_SIZE_AVAILABLE));
   EXPECT_TRUE(bool(progress & FLAG_DECODE_COMPLETE));
   EXPECT_TRUE(bool(progress & FLAG_FRAME_COMPLETE));
   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT),
             bool(progress & FLAG_HAS_TRANSPARENCY));
   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED),
@@ -72,23 +72,42 @@ CheckDecoderResults(const ImageTestCase&
   // because CreateAnonymousDecoder() forces a first-frame-only decode.
   RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
   RefPtr<SourceSurface> surface = currentFrame->GetSurface();
 
   // Verify that the resulting surfaces matches our expectations.
   EXPECT_EQ(SurfaceType::DATA, surface->GetType());
   EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
               surface->GetFormat() == SurfaceFormat::B8G8R8A8);
-  EXPECT_EQ(aTestCase.mSize, surface->GetSize());
+  EXPECT_EQ(aTestCase.mOutputSize, surface->GetSize());
+
+  return surface.forget();
+}
+
+static void
+CheckDecoderResults(const ImageTestCase& aTestCase, Decoder* aDecoder)
+{
+  RefPtr<SourceSurface> surface = CheckDecoderState(aTestCase, aDecoder);
+  if (!surface) {
+    return;
+  }
+
+  if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
+    return;
+  }
+
+  // Check the output.
   EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green(),
                            aTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
 }
 
-static void
-CheckDecoderSingleChunk(const ImageTestCase& aTestCase)
+template <typename Func>
+void WithSingleChunkDecode(const ImageTestCase& aTestCase,
+                           const Maybe<IntSize>& aOutputSize,
+                           Func aResultChecker)
 {
   nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
   ASSERT_TRUE(inputStream != nullptr);
 
   // Figure out how much data we have.
   uint64_t length;
   nsresult rv = inputStream->Available(&length);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
@@ -99,24 +118,33 @@ CheckDecoderSingleChunk(const ImageTestC
   rv = sourceBuffer->AppendFromInputStream(inputStream, length);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
   sourceBuffer->Complete(NS_OK);
 
   // Create a decoder.
   DecoderType decoderType =
     DecoderFactory::GetDecoderType(aTestCase.mMimeType);
   RefPtr<Decoder> decoder =
-    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer,
+    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, aOutputSize,
                                            DefaultSurfaceFlags());
   ASSERT_TRUE(decoder != nullptr);
 
   // Run the full decoder synchronously.
   decoder->Decode();
-  
-  CheckDecoderResults(aTestCase, decoder);
+
+  // Call the lambda to verify the expected results.
+  aResultChecker(decoder);
+}
+
+static void
+CheckDecoderSingleChunk(const ImageTestCase& aTestCase)
+{
+  WithSingleChunkDecode(aTestCase, Nothing(), [&](Decoder* aDecoder) {
+    CheckDecoderResults(aTestCase, aDecoder);
+  });
 }
 
 class NoResume : public IResumable
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(NoResume, override)
   virtual void Resume() override { }
 
@@ -136,17 +164,17 @@ CheckDecoderMultiChunk(const ImageTestCa
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 
   // Create a SourceBuffer and a decoder.
   RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer();
   sourceBuffer->ExpectLength(length);
   DecoderType decoderType =
     DecoderFactory::GetDecoderType(aTestCase.mMimeType);
   RefPtr<Decoder> decoder =
-    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer,
+    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
                                            DefaultSurfaceFlags());
   ASSERT_TRUE(decoder != nullptr);
 
   // Decode synchronously, using a |NoResume| IResumable so the Decoder doesn't
   // attempt to schedule itself on a nonexistent DecodePool when we write more
   // data into the SourceBuffer.
   RefPtr<NoResume> noResume = new NoResume();
   for (uint64_t read = 0; read < length ; ++read) {
@@ -162,76 +190,141 @@ CheckDecoderMultiChunk(const ImageTestCa
   }
 
   sourceBuffer->Complete(NS_OK);
   decoder->Decode(noResume);
   
   CheckDecoderResults(aTestCase, decoder);
 }
 
+static void
+CheckDownscaleDuringDecode(const ImageTestCase& aTestCase)
+{
+  // This function expects that |aTestCase| consists of 25 lines of green,
+  // followed by 25 lines of red, followed by 25 lines of green, followed by 25
+  // more lines of red. We'll downscale it from 100x100 to 20x20.
+  IntSize outputSize(20, 20);
+
+  WithSingleChunkDecode(aTestCase, Some(outputSize), [&](Decoder* aDecoder) {
+    RefPtr<SourceSurface> surface = CheckDecoderState(aTestCase, aDecoder);
+
+    // There are no downscale-during-decode tests that have TEST_CASE_HAS_ERROR
+    // set, so we expect to always get a surface here.
+    EXPECT_TRUE(surface != nullptr);
+
+    if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
+      return;
+    }
+
+    // Check that the downscaled image is correct. Note that we skip rows near
+    // the transitions between colors, since the downscaler does not produce a
+    // sharp boundary at these points. Even some of the rows we test need a
+    // small amount of fuzz; this is just the nature of Lanczos downscaling.
+    EXPECT_TRUE(RowsAreSolidColor(surface, 0, 4, BGRAColor::Green(), /* aFuzz = */ 4));
+    EXPECT_TRUE(RowsAreSolidColor(surface, 6, 3, BGRAColor::Red(), /* aFuzz = */ 4));
+    EXPECT_TRUE(RowsAreSolidColor(surface, 11, 3, BGRAColor::Green(), /* aFuzz = */ 4));
+    EXPECT_TRUE(RowsAreSolidColor(surface, 16, 4, BGRAColor::Red(), /* aFuzz = */ 3));
+  });
+}
+
 TEST(ImageDecoders, PNGSingleChunk)
 {
   CheckDecoderSingleChunk(GreenPNGTestCase());
 }
 
 TEST(ImageDecoders, PNGMultiChunk)
 {
   CheckDecoderMultiChunk(GreenPNGTestCase());
 }
 
+TEST(ImageDecoders, PNGDownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledPNGTestCase());
+}
+
 TEST(ImageDecoders, GIFSingleChunk)
 {
   CheckDecoderSingleChunk(GreenGIFTestCase());
 }
 
 TEST(ImageDecoders, GIFMultiChunk)
 {
   CheckDecoderMultiChunk(GreenGIFTestCase());
 }
 
+TEST(ImageDecoders, GIFDownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledGIFTestCase());
+}
+
 TEST(ImageDecoders, JPGSingleChunk)
 {
   CheckDecoderSingleChunk(GreenJPGTestCase());
 }
 
 TEST(ImageDecoders, JPGMultiChunk)
 {
   CheckDecoderMultiChunk(GreenJPGTestCase());
 }
 
+TEST(ImageDecoders, JPGDownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledJPGTestCase());
+}
+
 TEST(ImageDecoders, BMPSingleChunk)
 {
   CheckDecoderSingleChunk(GreenBMPTestCase());
 }
 
 TEST(ImageDecoders, BMPMultiChunk)
 {
   CheckDecoderMultiChunk(GreenBMPTestCase());
 }
 
+TEST(ImageDecoders, BMPDownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledBMPTestCase());
+}
+
 TEST(ImageDecoders, ICOSingleChunk)
 {
   CheckDecoderSingleChunk(GreenICOTestCase());
 }
 
 TEST(ImageDecoders, ICOMultiChunk)
 {
   CheckDecoderMultiChunk(GreenICOTestCase());
 }
 
+TEST(ImageDecoders, ICODownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledICOTestCase());
+}
+
+TEST(ImageDecoders, ICOWithANDMaskDownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledTransparentICOWithANDMaskTestCase());
+}
+
 TEST(ImageDecoders, IconSingleChunk)
 {
   CheckDecoderSingleChunk(GreenIconTestCase());
 }
 
 TEST(ImageDecoders, IconMultiChunk)
 {
   CheckDecoderMultiChunk(GreenIconTestCase());
 }
 
+TEST(ImageDecoders, IconDownscaleDuringDecode)
+{
+  CheckDownscaleDuringDecode(DownscaledIconTestCase());
+}
+
 TEST(ImageDecoders, AnimatedGIFSingleChunk)
 {
   CheckDecoderSingleChunk(GreenFirstFrameAnimatedGIFTestCase());
 }
 
 TEST(ImageDecoders, AnimatedGIFMultiChunk)
 {
   CheckDecoderMultiChunk(GreenFirstFrameAnimatedGIFTestCase());
--- a/image/test/gtest/TestMetadata.cpp
+++ b/image/test/gtest/TestMetadata.cpp
@@ -105,17 +105,17 @@ CheckMetadata(const ImageTestCase& aTest
                           : bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT);
   EXPECT_EQ(expectTransparency, bool(metadataProgress & FLAG_HAS_TRANSPARENCY));
 
   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED),
             bool(metadataProgress & FLAG_IS_ANIMATED));
 
   // Create a full decoder, so we can compare the result.
   decoder =
-    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer,
+    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
                                            DefaultSurfaceFlags());
   ASSERT_TRUE(decoder != nullptr);
 
   if (aBMPWithinICO == BMPWithinICO::YES) {
     static_cast<nsBMPDecoder*>(decoder.get())->SetIsWithinICO();
   }
 
   // Run the full decoder synchronously.
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9e6a29e62ba6cae31498a7cc039d4ef1deaeb44b
GIT binary patch
literal 30138
zc%1Fdp$<V|7zW^D%!YVolT0uZ&8dPZk|GO&of|MsP!vVhT!x8m!bQk3X9r_$;GFQh
zd*1N<|Mq|XXmVZ!X?981Nf+-Hf<}7YOYXzktKU36(qS~7E;pBZcYbQtTiaV<7)9YG
zjyuCRE*}qv%Ak5JwrBhP?+c~iKMw!^000000RCmY9{>OV0000WkFx&(00000002P#
PWW65%0000003e5+*4hEW
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ff9a20bcdb44edf3ea04eea3654fcffe3a51f3ba
GIT binary patch
literal 223
zc$@*>03iQINk%w1VPpVg0Pz3-{{R30{{SXM$tFd~A^8LV00000EC2ui0Av7U00088
zjE||y?GK}zwAzca-n{z{hT=$;=82~2%C_zc$MQ_q_KoNI&iDQg3<`(DqVb4KDkp%Z
z^9hYgr_`$Tip^@b+^+Wv4vWX+viXcotJmzd`wfrF=k&V$j?e4&{J#GW7$`VMSZH{N
zn5ekO*y#8O8L72IS!sERnW?$S+3EQS8Y((UT55WVnyR|W+UojxA}KpdTWfoZo2$Fa
Z+w1!a94tIcTx@)doUFXe-0W5W06UaCazg+B
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ee112af0a9a77a74f5931f8e5bda019e6cac9d39
GIT binary patch
literal 41662
zc%1Fpp$&jA6h+a;5@;l2Figinp%{g&N(mN4NC@P-n^W;;XwtPxNqdK^OVTG9n|8{U
z^L}iabFo?h0000000000;PWI&k|arzBuSDaNs=T<`a^I3#{&QW00000004j|NRlK;
Vk|arzBuSDaNs{!3%*@PgYzG+X+W-In
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..19785f5dcb84a0a3f1fd541f0de8ef9f3e8b4076
GIT binary patch
literal 40003
zc%1FpK?wjr2mnFfm(%_gyb^*a!!j*4GfI*qNs=T<k|arzBuSE_14RJ<000000002M
jev%|fk|arzBuSDaNs=U8X!^$k0000000000fClda<TTed
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5a4b3cd03608e26d06ca58a46c0fb4ca82903e54
GIT binary patch
literal 6035
zc%1E4dr(tX8vpV#JajMuYP*l5LF=QEKmZjgUIiqAs1UVitz|;qizI0hN_5eyuvE*~
zL3gpJoi0_D)!putX>Fy|P9uocb?c&HtF$}i;Zm`+-2_rM#N?j+E>h{(y5p{YHs76l
z&+mNadz|lg?m2VFRnh|!bF*`@fy3dzQhb2)hD(eNhc!(uH``@ut)*Be(^yL7PPJ8@
zC`*vT0?KJsYf5wuNwLmgGN()bb;2c;n6&BA!j$C+%dMF@qiN}8n{L(S6{|IyOEjrk
zDYa0tz?tSOwU+7}YKgOSquHM3OqY%XPeaVA<x<IriK8T4x^{WKB-3KkNm67fvIHr5
z+qC*LRaW+>FZR-<qmwKzFPD`k$t*U5JTWyjRi2=bD-`i)5pUmQcBq~4W_#Rs5wdi4
zjm>0rm@H-q+gBG`${guZsT{}UqbXQ;cdiR1Aqh!HLK2dYgyg3uW49fh8Lv3yc$Xnx
z!<>Ah#bL1<EmldAECJ?c<Sge;2UaFt{>84YT6l|pV_W#Xo4$;#q>pRN$;>RuSFOy>
z$y<UKEdcJ?jha$BKLMcB?69en8IrZ@o|XuEKme0q9Pr>twZ?8;oS&Zu_mx|p0EcZm
z<JnmExBF3v)Z$GDfD?vzk;ZCsAjZ2NtSEO_S-cN%jK-+eBK`~FIX0Xi;;XE__zu3w
zV#5gLvN2<9t5unZV-QOW-^0b<!y2Ql6mc@*X{8&>G^6ujD;cjduUW<F@%=g2K?O?4
z014#463B$PkO-;xoeS}x02%h+KK_ak{}o_CUk!e(unBBn0s|Pq0dr7WhS7D{>QS%5
zXCqpmuxoHHw|0G!;!cL~xd4J|gbd9F5WWHs+(F3gLxcny0eHyE$+|IrOC7-cZ&1H`
zOgHUSfT${fV;_v^ikkphb^}cP+^V*zM^rp~xq3ao;9-CX>j0uJ07R_6!`tXMG+qH%
z{cC`{^8ot~06dQNQO}UikSESV3LE5MV{phx5QTvjv^<UoxFQZu#3Ah<MivEk48Hph
zIb0rJFisd29ubKK?@R<PhsWdcc>)2SkE2^~9QY!^q{k8$kBcr)3#HG+D7No87#5fD
zW^1hKqI+6Wv8^&ZV)B%!k32g4@fkB`%}!34J8yn!T4vUgY~|9N+*PaBJXMH<YqUDO
z!D#xG-BI>@xpULzs^3(<uw&<oHNX8`-QJh$_w7G$sPPX?e>{BTPk(;v=-clcYkBv*
z<87zfPoMel>|f7a>b(5%Cs(d^ecIc1?VtT$TpzgcrDt%+`|YiN`-c5&T^!)uE&WI9
zLJ~M!KA*=IvUPE|<*b2-FL*3*+@!??LiKaeQpNVLn2bFK-)s$!OH#RGi)|MpCQnQ5
zo$g^v8>#HU3ak9TD!W_QSY4mOcpe8Ak0$~O{B5rO3Ia9O*SOmvU?x07Lp3z`o*^)m
z9(X;FOQ7wm)8fF}&0ac~-P7QY^Q|W!3LGY|KPtH2)mLA1bRM&}%NtAJjMB{`(B!7u
zuKP|ASW?ti$V_>5CV~DY@t5=X1TKo(x_!0%RN$=Gv#h!66#}_8{SgGN#rZe{F8Qcl
zdq7R#P_yR=0+G!z^x&o1Z+})v57hQr0?NS#MjPd8x^nY8CV75~fcESO0D&77V)uJY
z0!A<N?IlosrG^?dDg7_CQeLIIg^3$pNkAbCsJ^<T#~ddXR=Rv=8KAu%ME$VH#(PWT
zF|*2UC($=HG%PL(XlbDQMZ$oL-bH!WFw^PYvc6j8=>n$Fx-uvV#1q)btRnEyb^<ZS
zksI$D9j`Sr3Tm4;D6e9sP-n#c*#suJ+{Zmi0`W*p!Mih<oy=qc?er`HUo67)+pzVc
zZhxWSLLq@i#3!Se`c|Z(;aXHMmVU9wx53#+;N?2{$UmY9WYLjyA5}+SNJ5{Mx%8Ic
z6GsP-xm~qALITTrkc<w`4yMM{-W-s<UqIk*xzuHII1)@%yFB7^^zd%#r?-B;EGbga
zWdewSe9oc=YPNn(pOP?t@Aj^w2EX=n5J>(wfb@$Fw|Dqw(L)n<(?drHoQq;)YlFwc
z-UIaTH$_<;%pT-qeAVqI>5B`H`j!u=Kxe@{UQ}Oy?PthX4$k%W{oXueW1`r7mO9!J
zjP3}WsIU__pCa}=T7e^n>Io!t;lid>g%X7l-8Yf&(%xYc6I=bi{NULHPE}N3?t_-z
zW+ps<Q#=0>jr*<r1RiY@=HrYaZ4Hb~?9ZW3ze)g)jN1Cn*9lBE;Ng~sjuSk1(p0-%
zaQSAihuhp_`W{zdU|l!v#DU>0X)cf6iF8~(BX)O-aRaaSl@O?;W9T7`GO(-#51I>|
jHMF}0kHqVeP`*&Uhs|ebPr2Pips@A9w!?pGXwvl`>V<X;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b71b4652d5288450d91a28c1d8da4a51f16cfb85
GIT binary patch
literal 1015
zc%17D@N?(olHy`uVBq!ia0vp^DIm<j1SJ1AFflVQFiK~JM3hAM`dB6B=jtV<<R_)-
zRpb^hfPjsCML}Y6c4~=2Qfhi;o~_dR-TRdkGE;1o!cBb*d<&dYGcrA@ic*8C{6dne
zvXd=Sl<e)eY$~jP2IQueBq~(o=HwMyRoE(l&9wruLBje<3ScEA*|tg%z5xo(`9-M;
zrh2A&21<5Z3N}S4X;wilZcxoYo~=?wNlAf~zJ7Umxn8-kUVc%!zM-Y1rM`iYzLAkG
zP=#)BWnM{Qg>GK4GRO#s87`^C$wiq3C7Jno3Lt)BQhsTPt&);H$P#_1EkNh$!`%zy
zz<r#W2lQqU&_7aMt6u?wsV&plIiNVm-ATdI)!EF@(#%ZPNY9XgL1SX+#Qok*fg;E4
zGxuvKYqYnqwP$qnZ0cCFv}c2p${L5&uJi49x5&NM6zt_)%ggt7!P1Ut&u%TMSKw&M
z>RMnb#TBI#_dIKX%e>QjzZdWSKBxG-t+>p@o@raNek<;tW_*}&zq(NDCli}scj>Pd
zlHHlp3=Pf2m#nJ27rgkH_4-qxci+cn`>E*iW=XXkH$8lY)1SNDtf=jgZQ}N6eX1?z
zTdRF{F8Hwc(qq-S&^cP0oS&A==6>jzxP60q=)sR%*Dj@nRe0>so_#WV|Mx)sLe=YH
z&!_6`749}*{8KR_vCFefG9lzx;+`KbCX0qXsy+Hc;I+`|lNlR2Pikpidh$ZlRR88=
zqt}bnm!=+Z_W678{;jBA3)Yu3WsALv%lW;SU5f8v_3>@{`*MH(W|<Q-{k4;2-ChRe
z{6+7lZC$6Faks5|^(Ha<*3+>sDvXlS)@WERwJwppcYc8?*W2wEw#2Nu{oYQUf5QgW
zgVHzb8}dHp$NpseRg`YJZsjIDVCv*7@Q5sCVBi)8VMc~ob0mO*A3R+gLn`LHy?v1L
zfB_GSqxRqLbG9s~oq52AHErkoi*vqj_;RQ2!2AwTQecn$HQUo%M@WLlRA0|aWlbUp
e>P0e>YK>jb3zmaY3+7gU@~fw-pUXO@geCygWQ7<2
--- a/image/test/gtest/moz.build
+++ b/image/test/gtest/moz.build
@@ -26,28 +26,35 @@ if CONFIG['MOZ_ENABLE_SKIA']:
 
 SOURCES += [
     # Can't be unified because it manipulates the preprocessor environment.
     'TestDownscalingFilterNoSkia.cpp',
 ]
 
 TEST_HARNESS_FILES.gtest += [
     'corrupt.jpg',
+    'downscaled.bmp',
+    'downscaled.gif',
+    'downscaled.ico',
+    'downscaled.icon',
+    'downscaled.jpg',
+    'downscaled.png',
     'first-frame-green.gif',
     'first-frame-green.png',
     'first-frame-padding.gif',
     'green.bmp',
     'green.gif',
     'green.ico',
     'green.icon',
     'green.jpg',
     'green.png',
     'no-frame-delay.gif',
     'rle4.bmp',
     'rle8.bmp',
+    'transparent-ico-with-and-mask.ico',
     'transparent-if-within-ico.bmp',
     'transparent.gif',
     'transparent.png',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ab0dc4bce1ebb02377bca48dae36775579e2414d
GIT binary patch
literal 3262
zc$~GCUuYx89mjt&qtvs$wi;a^-c<_GI4NlMQm}M=@m@;Lx)f?Tfmlu-PQE}ZT?;*_
zg-90)mRo3~+(S;HrPienx4uGSxq(<F5G#4HoKP%>Laoa~tu&C+T_3axrD&CeXpUH`
ztDrA=IS4HM4Znf;J$&agzxmA{05ooa0E~MTUi&)0LjVvQ`#1z=;eYY_8oBGipP#`0
zc@TFV#veUO{_!~a`)T~w?~&an$(v7kUjGsK^96kUBK|{~y!-<G?XU65OZfQ``S~mO
z$2ai#P5jI@`Qh96`|se{_wdY368tBA<PKIp#^3CdiO(=1%J2a?n4~=)?WpwjBeZpj
zHp8?rtJKfZohYp?(v7%c{)DcjXfZ?cD|F>Wnkmxs8cklO@mFbVTX|}SM(T>OPeX?j
z;)wEFRP9jKqZ6M_c!<vd@8@JZVisfVDRwmNI}~hx##^8Dy*0<S7krzGUh_OFCw#>e
z%V*fiiZAmbyY#XzvBu7?`xYzSXq82F*zB$^w9iD7@gt^w#JnA*{F@Q%AA(;Z%_gd)
zXl<Xr<<}0mwlB23kXAdRZlBXOquP2*D?jHiCAECYpL^b)$!V#AmMCfQvbK0bTc~J}
zEx%FILVKz>(D<QWYiaDZO8=!2JnaCNi1$&T>*4LmK+DIQDsN2ly5KuuzCFt;=lJ@3
zU~P$);=GUy<WfAF4Wx2BSqQ|7JXYrOCZF5nXR170<D$;_K|s4XeX_;rhnyh&7zv4m
zjf91QZ4zvq5Y3aKp^067swRTfkf<2KoYTwEU@;~Nagj^t*;Fu<70H~4=k-`o%$M~!
zQy3e1xGF?VACryO&zgeX3=#+rAtX`AMxic*Zr#7mzLHf!dUb}^!c)5;)(B0!H$$-D
zfFY4#gVBZAwo84}&^L|g>Y1rG4OTalcMT7Yj39CsA~u|}AmWz491&(Dun|#Tk9cbl
z<*f*T=n$e37J4w>fv8*lQdE?q0dqlpb-}x}pu92ffu$kDB#PM(>*CmLm->Z8QH=5O
zqH4xiWl{M{%!4i*qvZj_dpK@E+--hxagkr<#kjf__nL9#PjP}S4pCB~qz%a~B;4jF
zn-IAqFI?2FCdUV!zLF#)eT>orNcA9XLCUTErIg5|c`l{q)9h-B{ys&}<zvVW@Z~;a
zEtGYupUCQ|48NS!avAngmR`wVwE6|C4j^Yku8UUP>M!T?M2@F(S~ka4SLtt72);6e
z!T<_36f7vXt)Hd5zFe426x2%v@8!JmtAdA=94HN-*oTq@CAa(wMG-3o&X?3g(VH$R
zzqpF=H3zOqShJyQ!J6CpjFeB!m-$k8d~vg6nf|nl(TyRP12AncEim2k&t4aECXcRb
zi|Z_IPFyev+8m;a#FbA_#e#}k{ZK_WHh83>%~x2gqCC4n$o3Gb5>;*3vY_gAfAuX9
zu5x2rJG;&1x9HPVf@(vkNmT1Y%|bP|{Jb`PVEF0U__6dwYV-#+g7%JKPeQ#1bqnfl
z^|gAC?*&9%o2fISPM_E%=wJv35;bhtx1ixRKfZ=O)!@9L1sg2fP)_d?^1cI2iJCoV
zcA@E(fAUbAY;vus2AW>cRKC;n;17n-lF+i@$U-f*_5Z+;psfIF`KQL;ke2e;5k_~0
z&>q0;9<(iJyX8l1-E%82+17k*=5Nz)-SR+p2$qCS53DY9-137JL>BjS)Jco^I?96<
zA$<qz0q*yq*8#f?b_?50)H?us59}ReZ$ZC;Y!lhnkX=M}0qj-iXTiP%b^`1;*fG?L
zB0B=M0d^SKI_ga$+fRDzL{Irfk09xQlpuQ`yD(^j`~b<DARBPE4zdQa3bFzN6J#05
z639G~IgnY9DY%;ixeRg%22qgb(7-_QG#cnga*!&LJ~E)50U@J%*f~a{Pq6bbcJ7eT
zhuC=^kN$?8ckt+K<h+5M*N}6AIDf>W-x22uc2?2o1>*b?J3qst=dklE9zBhnC$aMc
j8Ge^Ik7MWC#CaGyCy6sjhF`m1A}8+Md-wn4U!Lc`Uedvd
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/downscaling/downscale-moz-icon-1-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html class="reftest-wait">
+<head>
+  <meta charset="utf-8" />
+  <title>Reference for downscaling moz-icon images (bug 1261964)</title>
+  <script>
+    function beginTest() {
+      var canvas = document.getElementById("canvas");
+      var ctx = canvas.getContext("2d");
+      var image = new Image();
+
+      image.onload = function() {
+        // When image loads: draw it to canvas, scale down the canvas, and
+        // then let the reftest snapshot happen.
+        ctx.drawImage(image, 0, 0);
+        canvas.setAttribute("class", "downscale");
+        document.documentElement.removeAttribute("class");
+      }
+
+      // Kick off the image load:
+      image.src = "moz-icon://bogus-unrecognized-icon?size=100";
+    }
+  </script>
+  <style>
+    body { margin: 0; }
+    .downscale {
+      transform-origin: 0 0;
+      transform: scale(0.9);
+    }
+  </style>
+</head>
+<body onload="beginTest()">
+  <canvas id="canvas" height="100px" width="100px"></canvas>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/downscaling/downscale-moz-icon-1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+<head>
+  <meta charset="utf-8" />
+  <title>Testcase for downscaling moz-icon images (bug 1261964)</title>
+  <style>
+    body { margin: 0; }
+    .downscale {
+      transform-origin: 0 0;
+      transform: scale(0.9);
+    }
+  </style>
+</head>
+<body>
+  <img class="downscale" src="moz-icon://bogus-unrecognized-icon?size=100">
+</body>
+</html>
--- a/image/test/reftest/downscaling/reftest.list
+++ b/image/test/reftest/downscaling/reftest.list
@@ -82,16 +82,18 @@ fuzzy(20,999) != downscale-2d.html?203,5
 fuzzy(20,999) != downscale-2e.html?203,52,bottom about:blank
 
 fuzzy(20,999) != downscale-2a.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
 fuzzy(20,999) fails-if(OSX>=1008&&!skiaContent) != downscale-2e.html?205,53,bottom about:blank
 
+fuzzy(52,3386) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
+
 == downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
 == downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
 
 # Non-transparent and transparent ICO images
 == downscale-16px.html?ff-0RGB.ico downscale-16px.html?ff-0RGB.png
 fuzzy(1,1) == downscale-16px.html?ff-ARGB.ico downscale-16px.html?ff-ARGB.png
 
 # Upside-down (negative height) BMP
@@ -163,16 +165,18 @@ fuzzy(20,999) != downscale-2f.html?203,5
 
 fuzzy(20,999) != downscale-2a.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2e.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2f.html?205,53,bottom about:blank
 
+fuzzy(71,4439) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
+
 == downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
 == downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
 
 # Non-transparent and transparent ICO images
 fuzzy(1,3) == downscale-16px.html?ff-0RGB.ico downscale-16px.html?ff-0RGB.png
 fuzzy(3,32) == downscale-16px.html?ff-ARGB.ico downscale-16px.html?ff-ARGB.png
 
 # Upside-down (negative height) BMP
--- a/intl/uconv/ucvlatin/nsUTF16ToUnicode.cpp
+++ b/intl/uconv/ucvlatin/nsUTF16ToUnicode.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsUTF16ToUnicode.h"
 #include "nsCharTraits.h"
 #include "mozilla/CheckedInt.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 enum {
   STATE_NORMAL = 0,
   STATE_HALF_CODE_POINT = 1,
   STATE_FIRST_CALL = 2,
   STATE_SECOND_BYTE = STATE_FIRST_CALL | STATE_HALF_CODE_POINT,
   STATE_ODD_SURROGATE_PAIR = 4
 };
--- a/intl/uconv/ucvlatin/nsUnicodeToUTF16.h
+++ b/intl/uconv/ucvlatin/nsUnicodeToUTF16.h
@@ -2,17 +2,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 nsUnicodeToUTF16_h_
 #define nsUnicodeToUTF16_h_
 
 #include "nsUCSupport.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 class nsUnicodeToUTF16BE: public nsBasicEncoder
 {
 public:
   nsUnicodeToUTF16BE() { mBOM = 0;}
 
   //--------------------------------------------------------------------
   // Interface nsIUnicodeEncoder [declaration]
--- a/ipc/chromium/moz.build
+++ b/ipc/chromium/moz.build
@@ -4,17 +4,16 @@
 # 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/.
 
 libevent_path_prefix = 'src/third_party'
 include(libevent_path_prefix + '/libeventcommon.mozbuild')
 
 UNIFIED_SOURCES += [
     'src/base/at_exit.cc',
-    'src/base/buffer.cc',
     'src/base/command_line.cc',
     'src/base/file_path.cc',
     'src/base/file_util.cc',
     'src/base/histogram.cc',
     'src/base/lock.cc',
     'src/base/logging.cc',
     'src/base/message_loop.cc',
     'src/base/message_pump_default.cc',
deleted file mode 100644
--- a/ipc/chromium/src/base/buffer.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- 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/. */
-
-#include "buffer.h"
-#include "nsDebug.h"
-
-Buffer::Buffer()
- : mBuffer(nullptr),
-   mSize(0),
-   mReserved(0)
-{
-}
-
-Buffer::~Buffer()
-{
-  if (mBuffer) {
-    free(mBuffer);
-  }
-}
-
-bool
-Buffer::empty() const
-{
-  return mSize == 0;
-}
-
-size_t
-Buffer::size() const
-{
-  return mSize;
-}
-
-const char*
-Buffer::data() const
-{
-  return mBuffer;
-}
-
-void
-Buffer::clear()
-{
-  free(mBuffer);
-  mBuffer = nullptr;
-  mSize = 0;
-  mReserved = 0;
-}
-
-void
-Buffer::try_realloc(size_t newlength)
-{
-  char* buffer = (char*)realloc(mBuffer, newlength);
-  if (buffer || !newlength) {
-    mBuffer = buffer;
-    mReserved = newlength;
-    return;
-  }
-
-  // If we're growing the buffer, crash. If we're shrinking, then we continue to
-  // use the old (larger) buffer.
-  if (newlength > mReserved) {
-    NS_ABORT_OOM(newlength);
-  }
-}
-
-void
-Buffer::append(const char* bytes, size_t length)
-{
-  if (mSize + length > mReserved) {
-    try_realloc(mSize + length);
-  }
-
-  memcpy(mBuffer + mSize, bytes, length);
-  mSize += length;
-}
-
-void
-Buffer::assign(const char* bytes, size_t length)
-{
-  if (bytes >= mBuffer && bytes < mBuffer + mReserved) {
-    MOZ_RELEASE_ASSERT(bytes + length <= mBuffer + mSize);
-    memmove(mBuffer, bytes, length);
-    mSize = length;
-    try_realloc(length);
-  } else {
-    try_realloc(length);
-    mSize = length;
-    memcpy(mBuffer, bytes, length);
-  }
-}
-
-void
-Buffer::erase(size_t start, size_t count)
-{
-  mSize -= count;
-  memmove(mBuffer + start, mBuffer + start + count, mSize - start);
-  try_realloc(mSize);
-}
-
-void
-Buffer::reserve(size_t size)
-{
-  if (mReserved < size) {
-    try_realloc(size);
-  }
-}
-
-char*
-Buffer::trade_bytes(size_t count)
-{
-  MOZ_RELEASE_ASSERT(count);
-
-  char* result = mBuffer;
-  mSize = mReserved = mSize - count;
-  mBuffer = mReserved ? (char*)malloc(mReserved) : nullptr;
-  MOZ_RELEASE_ASSERT(!mReserved || mBuffer);
-  if (mSize) {
-    memcpy(mBuffer, result + count, mSize);
-  }
-
-  // Try to resize the buffer down, but ignore failure. This can cause extra
-  // copies, but so be it.
-  char* resized = (char*)realloc(result, count);
-  if (resized) {
-    return resized;
-  }
-  return result;
-}
deleted file mode 100644
--- a/ipc/chromium/src/base/buffer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- 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 CHROME_BASE_BUFFER_H_
-#define CHROME_BASE_BUFFER_H_
-
-// Buffer is a simple std::string-like class for buffering up IPC messages. Its
-// main distinguishing characteristic is the trade_bytes function.
-class Buffer {
-public:
-  Buffer();
-  ~Buffer();
-
-  bool empty() const;
-  const char* data() const;
-  size_t size() const;
-
-  void clear();
-  void append(const char* bytes, size_t length);
-  void assign(const char* bytes, size_t length);
-  void erase(size_t start, size_t count);
-
-  void reserve(size_t size);
-
-  // This function should be used by a caller who wants to extract the first
-  // |count| bytes from the buffer. Rather than copying the bytes out, this
-  // function returns the entire buffer. The bytes in range [count, size()) are
-  // copied out to a new buffer which becomes the current buffer. The
-  // presumption is that |count| is very large and approximately equal to size()
-  // so not much needs to be copied.
-  char* trade_bytes(size_t count);
-
-private:
-  void try_realloc(size_t newlength);
-
-  char* mBuffer;
-  size_t mSize;
-  size_t mReserved;
-};
-
-#endif // CHROME_BASE_BUFFER_H_
--- a/ipc/chromium/src/base/histogram.cc
+++ b/ipc/chromium/src/base/histogram.cc
@@ -235,109 +235,16 @@ void Histogram::WriteAscii(bool graph_it
       WriteAsciiBucketGraph(current_size, max_size, output);
     WriteAsciiBucketContext(past, current, remaining, i, output);
     output->append(newline);
     past += current;
   }
   DCHECK_EQ(sample_count, past);
 }
 
-// static
-std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
-                                              const SampleSet& snapshot) {
-  DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
-
-  Pickle pickle;
-  pickle.WriteString(histogram.histogram_name());
-  pickle.WriteInt(histogram.declared_min());
-  pickle.WriteInt(histogram.declared_max());
-  pickle.WriteSize(histogram.bucket_count());
-  pickle.WriteUInt32(histogram.range_checksum());
-  pickle.WriteInt(histogram.histogram_type());
-  pickle.WriteInt(histogram.flags());
-
-  snapshot.Serialize(&pickle);
-  return std::string(static_cast<const char*>(pickle.data()), pickle.size());
-}
-
-// static
-bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
-  if (histogram_info.empty()) {
-      return false;
-  }
-
-  Pickle pickle(histogram_info.data(),
-                static_cast<int>(histogram_info.size()));
-  std::string histogram_name;
-  int declared_min;
-  int declared_max;
-  size_t bucket_count;
-  uint32_t range_checksum;
-  int histogram_type;
-  int pickle_flags;
-  SampleSet sample;
-
-  void* iter = NULL;
-  if (!pickle.ReadString(&iter, &histogram_name) ||
-      !pickle.ReadInt(&iter, &declared_min) ||
-      !pickle.ReadInt(&iter, &declared_max) ||
-      !pickle.ReadSize(&iter, &bucket_count) ||
-      !pickle.ReadUInt32(&iter, &range_checksum) ||
-      !pickle.ReadInt(&iter, &histogram_type) ||
-      !pickle.ReadInt(&iter, &pickle_flags) ||
-      !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
-    CHROMIUM_LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
-    return false;
-  }
-  DCHECK(pickle_flags & kIPCSerializationSourceFlag);
-  // Since these fields may have come from an untrusted renderer, do additional
-  // checks above and beyond those in Histogram::Initialize()
-  if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
-      INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
-    CHROMIUM_LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
-    return false;
-  }
-
-  Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
-
-  DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
-
-  Histogram* render_histogram(NULL);
-
-  if (histogram_type == HISTOGRAM) {
-    render_histogram = Histogram::FactoryGet(
-        histogram_name, declared_min, declared_max, bucket_count, flags);
-  } else if (histogram_type == LINEAR_HISTOGRAM) {
-    render_histogram = LinearHistogram::FactoryGet(
-        histogram_name, declared_min, declared_max, bucket_count, flags);
-  } else if (histogram_type == BOOLEAN_HISTOGRAM) {
-    render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
-  } else {
-    CHROMIUM_LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
-                        << histogram_type;
-    return false;
-  }
-
-  DCHECK_EQ(render_histogram->declared_min(), declared_min);
-  DCHECK_EQ(render_histogram->declared_max(), declared_max);
-  DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
-  DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
-  DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
-
-  if (render_histogram->flags() & kIPCSerializationSourceFlag) {
-    DVLOG(1) << "Single process mode, histogram observed and not copied: "
-             << histogram_name;
-  } else {
-    DCHECK_EQ(flags & render_histogram->flags(), flags);
-    render_histogram->AddSampleSet(sample);
-  }
-
-  return true;
-}
-
 //------------------------------------------------------------------------------
 // Methods for the validating a sample and a related histogram.
 //------------------------------------------------------------------------------
 
 Histogram::Inconsistencies Histogram::FindCorruption(
     const SampleSet& snapshot,
     const OffTheBooksMutexAutoLock& snapshotLockEvidence) const {
   int inconsistencies = NO_INCONSISTENCIES;
@@ -768,58 +675,16 @@ void Histogram::SampleSet::Add(const Sam
   OffTheBooksMutexAutoLock locker(mutex_);
   DCHECK_EQ(counts_.size(), other.counts_.size());
   sum_ += other.sum_;
   redundant_count_ += other.redundant_count_;
   for (size_t index = 0; index < counts_.size(); ++index)
     counts_[index] += other.counts_[index];
 }
 
-bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
-  OffTheBooksMutexAutoLock locker(mutex_);
-  pickle->WriteInt64(sum_);
-  pickle->WriteInt64(redundant_count_);
-  pickle->WriteSize(counts_.size());
-
-  for (size_t index = 0; index < counts_.size(); ++index) {
-    pickle->WriteInt(counts_[index]);
-  }
-
-  return true;
-}
-
-bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
-  OffTheBooksMutexAutoLock locker(mutex_);
-  DCHECK_EQ(counts_.size(), 0u);
-  DCHECK_EQ(sum_, 0);
-  DCHECK_EQ(redundant_count_, 0);
-
-  size_t counts_size;
-
-  if (!pickle.ReadInt64(iter, &sum_) ||
-      !pickle.ReadInt64(iter, &redundant_count_) ||
-      !pickle.ReadSize(iter, &counts_size)) {
-    return false;
-  }
-
-  if (counts_size == 0)
-    return false;
-
-  int count = 0;
-  for (size_t index = 0; index < counts_size; ++index) {
-    int i;
-    if (!pickle.ReadInt(iter, &i))
-      return false;
-    counts_.push_back(i);
-    count += i;
-  }
-
-  return true;
-}
-
 //------------------------------------------------------------------------------
 // LinearHistogram: This histogram uses a traditional set of evenly spaced
 // buckets.
 //------------------------------------------------------------------------------
 
 LinearHistogram::~LinearHistogram() {
 }
 
--- a/ipc/chromium/src/base/histogram.h
+++ b/ipc/chromium/src/base/histogram.h
@@ -49,18 +49,16 @@
 
 #include <map>
 #include <string>
 #include <vector>
 
 #include "base/time.h"
 #include "base/lock.h"
 
-class Pickle;
-
 namespace base {
 
 using mozilla::OffTheBooksMutex;
 using mozilla::OffTheBooksMutexAutoLock;
 
 //------------------------------------------------------------------------------
 // Provide easy general purpose histogram in a macro, just like stats counters.
 // The first four macros use 50 buckets.
@@ -296,23 +294,16 @@ class Histogram {
     LINEAR,
     CUSTOM
   };
 
   enum Flags {
     kNoFlags = 0,
     kUmaTargetedHistogramFlag = 0x1,  // Histogram should be UMA uploaded.
 
-    // Indicate that the histogram was pickled to be sent across an IPC Channel.
-    // If we observe this flag on a histogram being aggregated into after IPC,
-    // then we are running in a single process mode, and the aggregation should
-    // not take place (as we would be aggregating back into the source
-    // histogram!).
-    kIPCSerializationSourceFlag = 0x10,
-
     kHexRangePrintingFlag = 0x8000  // Fancy bucket-naming supported.
   };
 
   enum Inconsistencies {
     NO_INCONSISTENCIES = 0x0,
     RANGE_CHECKSUM_ERROR = 0x1,
     BUCKET_ORDER_ERROR = 0x2,
     COUNT_HIGH_ERROR = 0x4,
@@ -355,19 +346,16 @@ class Histogram {
     void Resize(const Histogram& histogram);
 
     // Accessor for histogram to make routine additions.
     void Accumulate(Sample value, Count count, size_t index);
 
     // Arithmetic manipulation of corresponding elements of the set.
     void Add(const SampleSet& other);
 
-    bool Serialize(Pickle* pickle) const;
-    bool Deserialize(void** iter, const Pickle& pickle);
-
     size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
     //---------------- THREAD UNSAFE METHODS ----------------//
     //
     // The caller must hold |this.mutex_|, and must supply evidence by passing
     // a const reference to the relevant OffTheBooksMutexAutoLock used.
 
     Count counts(const OffTheBooksMutexAutoLock& ev, size_t i) const {
@@ -468,31 +456,16 @@ class Histogram {
 
   // Support generic flagging of Histograms.
   // 0x1 Currently used to mark this histogram to be recorded by UMA..
   // 0x8000 means print ranges in hex.
   void SetFlags(Flags flags) { flags_ = static_cast<Flags> (flags_ | flags); }
   void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); }
   int flags() const { return flags_; }
 
-  // Convenience methods for serializing/deserializing the histograms.
-  // Histograms from Renderer process are serialized and sent to the browser.
-  // Browser process reconstructs the histogram from the pickled version
-  // accumulates the browser-side shadow copy of histograms (that mirror
-  // histograms created in the renderer).
-
-  // Serialize the given snapshot of a Histogram into a String. Uses
-  // Pickle class to flatten the object.
-  static std::string SerializeHistogramInfo(const Histogram& histogram,
-                                            const SampleSet& snapshot);
-  // The following method accepts a list of pickled histograms and
-  // builds a histogram and updates shadow copy of histogram data in the
-  // browser process.
-  static bool DeserializeHistogramInfo(const std::string& histogram_info);
-
   // Check to see if bucket ranges, counts and tallies in the snapshot are
   // consistent with the bucket ranges and checksums in our histogram.  This can
   // produce a false-alarm if a race occurred in the reading of the data during
   // a SnapShot process, but should otherwise be false at all times (unless we
   // have memory over-writes, or DRAM failures).
   virtual Inconsistencies FindCorruption(const SampleSet& snapshot,
                                          const OffTheBooksMutexAutoLock&
                                                snapshotLockEvidence) const;
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -2,39 +2,40 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/pickle.h"
 
 #include "mozilla/Alignment.h"
-#include "mozilla/Endian.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/TypeTraits.h"
 
 #include <stdlib.h>
 
 #include <limits>
 #include <string>
 #include <algorithm>
 
 #include "nsDebug.h"
 
+#if !defined(RELEASE_BUILD) || defined(DEBUG)
+#define SENTINEL_CHECKING
+#endif
+
 //------------------------------------------------------------------------------
 
 static_assert(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
               "Insufficient alignment");
 
-// static
-const int Pickle::kPayloadUnit = 64;
+static const uint32_t kHeaderSegmentCapacity = 64;
 
-const uint32_t kFastGrowthCap = 128 * 1024;
-
-// We mark a read only pickle with a special capacity_.
-static const uint32_t kCapacityReadOnly = (uint32_t) -1;
+static const uint32_t kDefaultSegmentCapacity = 4096;
 
 static const char kBytePaddingMarker = char(0xbf);
 
 namespace {
 
 // We want to copy data to our payload as efficiently as possible.
 // memcpy fits the bill for copying, but not all compilers or
 // architectures support inlining memcpy from void*, which has unknown
@@ -43,525 +44,479 @@ namespace {
 // therefore use that knowledge to construct a copier that will copy
 // efficiently (via standard C++ assignment mechanisms) if the datatype
 // needs that alignment or less, and memcpy otherwise.  (The compiler
 // may still inline memcpy, of course.)
 
 template<typename T, size_t size, bool hasSufficientAlignment>
 struct Copier
 {
-  static void Copy(T* dest, void** iter) {
-    memcpy(dest, *iter, sizeof(T));
+  static void Copy(T* dest, const char* iter) {
+    memcpy(dest, iter, sizeof(T));
   }
 };
 
 // Copying 64-bit quantities happens often enough and can easily be made
 // worthwhile on 32-bit platforms, so handle it specially.  Only do it
 // if 64-bit types aren't sufficiently aligned; the alignment
 // requirements for them vary between 32-bit platforms.
 #ifndef HAVE_64BIT_BUILD
 template<typename T>
 struct Copier<T, sizeof(uint64_t), false>
 {
-  static void Copy(T* dest, void** iter) {
+  static void Copy(T* dest, const char* iter) {
 #if MOZ_LITTLE_ENDIAN
     static const int loIndex = 0, hiIndex = 1;
 #else
     static const int loIndex = 1, hiIndex = 0;
 #endif
     static_assert(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
                   "Pointers have different alignments");
-    uint32_t* src = *reinterpret_cast<uint32_t**>(iter);
+    const uint32_t* src = reinterpret_cast<const uint32_t*>(iter);
     uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
     uint32dest[loIndex] = src[loIndex];
     uint32dest[hiIndex] = src[hiIndex];
   }
 };
 #endif
 
 template<typename T, size_t size>
 struct Copier<T, size, true>
 {
-  static void Copy(T* dest, void** iter) {
-    // The reinterpret_cast is only safe if two conditions hold:
-    // (1) If the alignment of T* is the same as void*;
-    // (2) The alignment of the data in *iter is at least as
-    //     big as MOZ_ALIGNOF(T).
-    // Check the first condition, as the second condition is already
-    // known to be true, or we wouldn't be here.
-    static_assert(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*),
-                  "Pointers have different alignments");
-    *dest = *(*reinterpret_cast<T**>(iter));
+  static void Copy(T* dest, const char* iter) {
+    *dest = *reinterpret_cast<const T*>(iter);
   }
 };
 
-template<typename T>
-void CopyFromIter(T* dest, void** iter) {
-  static_assert(mozilla::IsPod<T>::value, "Copied type must be a POD type");
-  Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter);
-}
-
 } // anonymous namespace
 
-// Payload is sizeof(Pickle::memberAlignmentType) aligned.
+PickleIterator::PickleIterator(const Pickle& pickle)
+   : iter_(pickle.buffers_.Iter()) {
+  iter_.Advance(pickle.buffers_, pickle.header_size_);
+}
 
-Pickle::Pickle()
-    : header_(NULL),
-      header_size_(sizeof(Header)),
-      capacity_(0),
-      variable_buffer_offset_(0) {
-  Resize(kPayloadUnit);
-  header_->payload_size = 0;
+template<typename T>
+void
+PickleIterator::CopyInto(T* dest) {
+  static_assert(mozilla::IsPod<T>::value, "Copied type must be a POD type");
+  Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter_.Data());
 }
 
-Pickle::Pickle(int header_size)
-    : header_(NULL),
-      header_size_(AlignInt(header_size)),
-      capacity_(0),
-      variable_buffer_offset_(0) {
+bool Pickle::IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const {
+  // Make sure we don't get into trouble where AlignInt(len) == 0.
+  MOZ_RELEASE_ASSERT(len < 64);
+
+  return iter.iter_.HasRoomFor(AlignInt(len));
+}
+
+void Pickle::UpdateIter(PickleIterator* iter, uint32_t bytes) const {
+  // Make sure we don't get into trouble where AlignInt(bytes) == 0.
+  MOZ_RELEASE_ASSERT(bytes < 64);
+
+  iter->iter_.Advance(buffers_, AlignInt(bytes));
+}
+
+// Payload is sizeof(Pickle::memberAlignmentType) aligned.
+
+Pickle::Pickle(uint32_t header_size)
+    : buffers_(AlignInt(header_size), kHeaderSegmentCapacity, kDefaultSegmentCapacity),
+      header_(nullptr),
+      header_size_(AlignInt(header_size)) {
   DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
-  DCHECK(header_size <= kPayloadUnit);
-  Resize(kPayloadUnit);
-  if (!header_) {
-    NS_ABORT_OOM(kPayloadUnit);
-  }
+  DCHECK(header_size_ <= kHeaderSegmentCapacity);
+  header_ = reinterpret_cast<Header*>(buffers_.Start());
   header_->payload_size = 0;
 }
 
-Pickle::Pickle(const char* data, int data_len, Ownership ownership)
-    : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
-      header_size_(0),
-      capacity_(ownership == BORROWS ? kCapacityReadOnly : data_len),
-      variable_buffer_offset_(0) {
-  if (data_len >= static_cast<int>(sizeof(Header)))
-    header_size_ = data_len - header_->payload_size;
-
-  if (header_size_ > static_cast<unsigned int>(data_len))
-    header_size_ = 0;
-
-  if (header_size_ != AlignInt(header_size_))
-    header_size_ = 0;
+Pickle::Pickle(uint32_t header_size, const char* data, uint32_t length)
+    : buffers_(length, AlignCapacity(length), kDefaultSegmentCapacity),
+      header_(nullptr),
+      header_size_(AlignInt(header_size)) {
+  DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
+  DCHECK(header_size <= kHeaderSegmentCapacity);
+  MOZ_RELEASE_ASSERT(header_size <= length);
 
-  // If there is anything wrong with the data, we're not going to use it.
-  if (!header_size_)
-    header_ = nullptr;
-}
-
-Pickle::Pickle(const Pickle& other)
-    : header_(NULL),
-      header_size_(other.header_size_),
-      capacity_(0),
-      variable_buffer_offset_(other.variable_buffer_offset_) {
-  uint32_t payload_size = header_size_ + other.header_->payload_size;
-  Resize(payload_size);
-  memcpy(header_, other.header_, payload_size);
+  header_ = reinterpret_cast<Header*>(buffers_.Start());
+  memcpy(header_, data, length);
 }
 
 Pickle::Pickle(Pickle&& other)
-  : header_(other.header_),
-    header_size_(other.header_size_),
-    capacity_(other.capacity_),
-    variable_buffer_offset_(other.variable_buffer_offset_) {
-  other.header_ = NULL;
-  other.capacity_ = 0;
-  other.variable_buffer_offset_ = 0;
+   : buffers_(mozilla::Move(other.buffers_)),
+     header_(other.header_),
+     header_size_(other.header_size_) {
+  other.header_ = nullptr;
 }
 
 Pickle::~Pickle() {
-  if (capacity_ != kCapacityReadOnly)
-    free(header_);
 }
 
-Pickle& Pickle::operator=(const Pickle& other) {
-  if (header_size_ != other.header_size_ && capacity_ != kCapacityReadOnly) {
-    free(header_);
-    header_ = NULL;
-    header_size_ = other.header_size_;
-  }
-  Resize(other.header_size_ + other.header_->payload_size);
-  memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
-  variable_buffer_offset_ = other.variable_buffer_offset_;
+Pickle& Pickle::operator=(Pickle&& other) {
+  BufferList tmp = mozilla::Move(other.buffers_);
+  other.buffers_ = mozilla::Move(buffers_);
+  buffers_ = mozilla::Move(tmp);
+
+  //std::swap(buffers_, other.buffers_);
+  std::swap(header_, other.header_);
+  std::swap(header_size_, other.header_size_);
   return *this;
 }
 
-Pickle& Pickle::operator=(Pickle&& other) {
-  std::swap(header_, other.header_);
-  std::swap(header_size_, other.header_size_);
-  std::swap(capacity_, other.capacity_);
-  std::swap(variable_buffer_offset_, other.variable_buffer_offset_);
-  return *this;
-}
-
-bool Pickle::ReadBool(void** iter, bool* result) const {
+bool Pickle::ReadBool(PickleIterator* iter, bool* result) const {
   DCHECK(iter);
 
   int tmp;
   if (!ReadInt(iter, &tmp))
     return false;
   DCHECK(0 == tmp || 1 == tmp);
   *result = tmp ? true : false;
   return true;
 }
 
-bool Pickle::ReadInt16(void** iter, int16_t* result) const {
+bool Pickle::ReadInt16(PickleIterator* iter, int16_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadUInt16(void** iter, uint16_t* result) const {
+bool Pickle::ReadUInt16(PickleIterator* iter, uint16_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadInt(void** iter, int* result) const {
+bool Pickle::ReadInt(PickleIterator* iter, int* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
-bool Pickle::ReadLong(void** iter, long* result) const {
+bool Pickle::ReadLong(PickleIterator* iter, long* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
-  int64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  int64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
+  DCHECK(big_result <= LONG_MAX && big_result >= LONG_MIN);
+  *result = static_cast<long>(big_result);
 
-  CopyFromIter(&bigResult, iter);
-  DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
-  *result = static_cast<long>(bigResult);
-
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
-bool Pickle::ReadULong(void** iter, unsigned long* result) const {
+bool Pickle::ReadULong(PickleIterator* iter, unsigned long* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
-  uint64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  uint64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
+  DCHECK(big_result <= ULONG_MAX);
+  *result = static_cast<unsigned long>(big_result);
 
-  CopyFromIter(&bigResult, iter);
-  DCHECK(bigResult <= ULONG_MAX);
-  *result = static_cast<unsigned long>(bigResult);
-
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
-bool Pickle::ReadLength(void** iter, int* result) const {
+bool Pickle::ReadLength(PickleIterator* iter, int* result) const {
   if (!ReadInt(iter, result))
     return false;
   return ((*result) >= 0);
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
-bool Pickle::ReadSize(void** iter, size_t* result) const {
+bool Pickle::ReadSize(PickleIterator* iter, size_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
-  uint64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  uint64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
+  DCHECK(big_result <= std::numeric_limits<size_t>::max());
+  *result = static_cast<size_t>(big_result);
 
-  CopyFromIter(&bigResult, iter);
-  DCHECK(bigResult <= std::numeric_limits<size_t>::max());
-  *result = static_cast<size_t>(bigResult);
-
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
-bool Pickle::ReadInt32(void** iter, int32_t* result) const {
+bool Pickle::ReadInt32(PickleIterator* iter, int32_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadUInt32(void** iter, uint32_t* result) const {
+bool Pickle::ReadUInt32(PickleIterator* iter, uint32_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadInt64(void** iter, int64_t* result) const {
+bool Pickle::ReadInt64(PickleIterator* iter, int64_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadUInt64(void** iter, uint64_t* result) const {
+bool Pickle::ReadUInt64(PickleIterator* iter, uint64_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadDouble(void** iter, double* result) const {
+bool Pickle::ReadDouble(PickleIterator* iter, double* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
-bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
+bool Pickle::ReadIntPtr(PickleIterator* iter, intptr_t* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
-  int64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  int64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
 
-  CopyFromIter(&bigResult, iter);
-  DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
-  *result = static_cast<intptr_t>(bigResult);
+  DCHECK(big_result <= std::numeric_limits<intptr_t>::max() && big_result >= std::numeric_limits<intptr_t>::min());
+  *result = static_cast<intptr_t>(big_result);
 
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
-bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const {
+bool Pickle::ReadUnsignedChar(PickleIterator* iter, unsigned char* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  CopyFromIter(result, iter);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
-bool Pickle::ReadString(void** iter, std::string* result) const {
+bool Pickle::ReadString(PickleIterator* iter, std::string* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   int len;
   if (!ReadLength(iter, &len))
     return false;
-  if (!IteratorHasRoomFor(*iter, len))
-    return false;
 
-  char* chars = reinterpret_cast<char*>(*iter);
-  result->assign(chars, len);
+  auto chars = mozilla::MakeUnique<char[]>(len);
+  if (!ReadBytesInto(iter, chars.get(), len)) {
+    return false;
+  }
+  result->assign(chars.get(), len);
 
-  UpdateIter(iter, len);
   return true;
 }
 
-bool Pickle::ReadWString(void** iter, std::wstring* result) const {
+bool Pickle::ReadWString(PickleIterator* iter, std::wstring* result) const {
   DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
 
   int len;
   if (!ReadLength(iter, &len))
     return false;
   // Avoid integer multiplication overflow.
   if (len > INT_MAX / static_cast<int>(sizeof(wchar_t)))
     return false;
-  if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
-    return false;
 
-  wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
-  result->assign(chars, len);
+  auto chars = mozilla::MakeUnique<wchar_t[]>(len);
+  if (!ReadBytesInto(iter, chars.get(), len * sizeof(wchar_t))) {
+    return false;
+  }
+  result->assign(chars.get(), len);
 
-  UpdateIter(iter, len * sizeof(wchar_t));
   return true;
 }
 
-bool Pickle::ReadBytes(void** iter, const char** data, int length,
-                       uint32_t alignment) const {
+bool Pickle::FlattenBytes(PickleIterator* iter, const char** data, uint32_t length,
+                          uint32_t alignment) {
   DCHECK(iter);
   DCHECK(data);
   DCHECK(alignment == 4 || alignment == 8);
   DCHECK(intptr_t(header_) % alignment == 0);
 
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
+  if (AlignInt(length) < length) {
+    return false;
+  }
+
+  uint32_t padding_len = intptr_t(iter->iter_.Data()) % alignment;
+  if (!iter->iter_.AdvanceAcrossSegments(buffers_, padding_len)) {
+    return false;
+  }
+
+  if (!buffers_.FlattenBytes(iter->iter_, data, length)) {
+    return false;
+  }
 
-  uint32_t paddingLen = intptr_t(*iter) % alignment;
-  if (paddingLen) {
-#ifdef DEBUG
-    {
-      const char* padding = static_cast<const char*>(*iter);
-      for (uint32_t i = 0; i < paddingLen; i++) {
-        DCHECK(*(padding + i) == kBytePaddingMarker);
-      }
-    }
-#endif
-    length += paddingLen;
+  header_ = reinterpret_cast<Header*>(buffers_.Start());
+
+  return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
+}
+
+bool Pickle::ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const {
+  if (AlignInt(length) < length) {
+    return false;
+  }
+
+  if (!buffers_.ReadBytes(iter->iter_, reinterpret_cast<char*>(data), length)) {
+    return false;
   }
 
-  if (!IteratorHasRoomFor(*iter, length))
-    return false;
-
-  *data = static_cast<const char*>(*iter) + paddingLen;
-  DCHECK(intptr_t(*data) % alignment == 0);
-
-  UpdateIter(iter, length);
-  return true;
+  return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
 }
 
-bool Pickle::ReadData(void** iter, const char** data, int* length) const {
-  DCHECK(iter);
-  DCHECK(data);
-  DCHECK(length);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
-
-  if (!ReadLength(iter, length))
+bool Pickle::ReadSentinel(PickleIterator* iter, uint32_t sentinel) const {
+#ifdef SENTINEL_CHECKING
+  uint32_t found;
+  if (!ReadUInt32(iter, &found)) {
     return false;
-
-  return ReadBytes(iter, data, *length);
+  }
+  return found == sentinel;
+#else
+  return true;
+#endif
 }
 
-char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
+bool Pickle::WriteSentinel(uint32_t sentinel) {
+#ifdef SENTINEL_CHECKING
+  return WriteUInt32(sentinel);
+#else
+  return true;
+#endif
+}
+
+void Pickle::EndRead(PickleIterator& iter) const {
+  DCHECK(iter.iter_.Done());
+}
+
+void Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
   DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!";
 
   // write at an alignment-aligned offset from the beginning of the header
   uint32_t offset = AlignInt(header_->payload_size);
-  uint32_t padding = (header_size_ + offset) %  alignment;
+  uint32_t padding = (header_size_ + offset) % alignment;
   uint32_t new_size = offset + padding + AlignInt(length);
-  uint32_t needed_size = header_size_ + new_size;
-
-  if (needed_size > capacity_) {
-    double growth_rate = capacity_ < kFastGrowthCap ? 2.0 : 1.4;
-    Resize(std::max(static_cast<uint32_t>(capacity_ * growth_rate), needed_size));
-  }
+  MOZ_RELEASE_ASSERT(new_size >= header_->payload_size);
 
   DCHECK(intptr_t(header_) % alignment == 0);
 
 #ifdef ARCH_CPU_64_BITS
   DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
 #endif
 
-  char* buffer = payload() + offset;
-
   if (padding) {
-    memset(buffer, kBytePaddingMarker, padding);
-    buffer += padding;
+    MOZ_RELEASE_ASSERT(padding <= 8);
+    static const char padding_data[8] = {
+      kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
+      kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
+    };
+    buffers_.WriteBytes(padding_data, padding);
   }
 
-  DCHECK(intptr_t(buffer) % alignment == 0);
+  DCHECK((header_size_ + header_->payload_size + padding) % alignment == 0);
 
   header_->payload_size = new_size;
-
-#ifdef MOZ_VALGRIND
-  // pad the trailing end as well, so that valgrind
-  // doesn't complain when we write the buffer
-  padding = AlignInt(length) - length;
-  if (padding) {
-    memset(buffer + length, kBytePaddingMarker, padding);
-  }
-#endif
-
-  return buffer;
 }
 
-void Pickle::EndWrite(char* dest, int length) {
+void Pickle::EndWrite(uint32_t length) {
   // Zero-pad to keep tools like purify from complaining about uninitialized
   // memory.
-  if (length % sizeof(memberAlignmentType))
-    memset(dest + length, 0,
-           sizeof(memberAlignmentType) - (length % sizeof(memberAlignmentType)));
+  uint32_t padding = AlignInt(length) - length;
+  if (padding) {
+    MOZ_RELEASE_ASSERT(padding <= 4);
+    static const char padding_data[4] = {
+      kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
+    };
+    buffers_.WriteBytes(padding_data, padding);
+  }
 }
 
-bool Pickle::WriteBytes(const void* data, int data_len, uint32_t alignment) {
-  DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
+bool Pickle::WriteBytes(const void* data, uint32_t data_len, uint32_t alignment) {
   DCHECK(alignment == 4 || alignment == 8);
   DCHECK(intptr_t(header_) % alignment == 0);
 
-  char* dest = BeginWrite(data_len, alignment);
-  if (!dest)
-    return false;
+  BeginWrite(data_len, alignment);
 
-  memcpy(dest, data, data_len);
+  buffers_.WriteBytes(reinterpret_cast<const char*>(data), data_len);
 
-  EndWrite(dest, data_len);
+  EndWrite(data_len);
   return true;
 }
 
 bool Pickle::WriteString(const std::string& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(), static_cast<int>(value.size()));
@@ -570,97 +525,48 @@ bool Pickle::WriteString(const std::stri
 bool Pickle::WriteWString(const std::wstring& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(),
                     static_cast<int>(value.size() * sizeof(wchar_t)));
 }
 
-bool Pickle::WriteData(const char* data, int length) {
+bool Pickle::WriteData(const char* data, uint32_t length) {
   return WriteInt(length) && WriteBytes(data, length);
 }
 
-char* Pickle::BeginWriteData(int length) {
-  DCHECK_EQ(variable_buffer_offset_, 0U) <<
-    "There can only be one variable buffer in a Pickle";
-
-  if (!WriteInt(length))
-    return NULL;
-
-  char *data_ptr = BeginWrite(length, sizeof(memberAlignmentType));
-  if (!data_ptr)
-    return NULL;
-
-  variable_buffer_offset_ =
-      data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
-
-  // EndWrite doesn't necessarily have to be called after the write operation,
-  // so we call it here to pad out what the caller will eventually write.
-  EndWrite(data_ptr, length);
-  return data_ptr;
+void Pickle::InputBytes(const char* data, uint32_t length) {
+  buffers_.WriteBytes(data, length);
 }
 
-void Pickle::TrimWriteData(int new_length) {
-  DCHECK(variable_buffer_offset_ != 0);
-
-  // Fetch the the variable buffer size
-  int* cur_length = reinterpret_cast<int*>(
-      reinterpret_cast<char*>(header_) + variable_buffer_offset_);
-
-  if (new_length < 0 || new_length > *cur_length) {
-    NOTREACHED() << "Invalid length in TrimWriteData.";
-    return;
-  }
-
-  // Update the payload size and variable buffer size
-  header_->payload_size -= (*cur_length - new_length);
-  *cur_length = new_length;
-}
-
-void Pickle::Resize(uint32_t new_capacity) {
-  new_capacity = ConstantAligner<kPayloadUnit>::align(new_capacity);
-
-  void* p = moz_xrealloc(header_, new_capacity);
-
-  header_ = reinterpret_cast<Header*>(p);
-  capacity_ = new_capacity;
+int32_t* Pickle::GetInt32PtrForTest(uint32_t offset) {
+  size_t pos = buffers_.Size() - offset;
+  BufferList::IterImpl iter(buffers_);
+  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(buffers_, pos));
+  return reinterpret_cast<int32_t*>(iter.Data());
 }
 
 // static
-const char* Pickle::FindNext(uint32_t header_size,
+uint32_t Pickle::MessageSize(uint32_t header_size,
                              const char* start,
                              const char* end) {
   DCHECK(header_size == AlignInt(header_size));
-  DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
-
-  if (end < start)
-    return nullptr;
-  size_t length = static_cast<size_t>(end - start);
-  if (length < sizeof(Header))
-    return nullptr;
-
-  const Header* hdr = reinterpret_cast<const Header*>(start);
-  if (length < header_size || length - header_size < hdr->payload_size)
-    return nullptr;
-
-  return start + header_size + hdr->payload_size;
-}
-
-// static
-uint32_t Pickle::GetLength(uint32_t header_size,
-                           const char* start,
-                           const char* end) {
-  DCHECK(header_size == AlignInt(header_size));
-  DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
+  DCHECK(header_size <= static_cast<memberAlignmentType>(kHeaderSegmentCapacity));
 
   if (end < start)
     return 0;
   size_t length = static_cast<size_t>(end - start);
   if (length < sizeof(Header))
     return 0;
 
   const Header* hdr = reinterpret_cast<const Header*>(start);
   if (length < header_size)
     return 0;
 
-  return header_size + hdr->payload_size;
+  mozilla::CheckedInt<uint32_t> sum(header_size);
+  sum += hdr->payload_size;
+
+  if (!sum.isValid())
+    return 0;
+
+  return sum.value();
 }
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -9,16 +9,33 @@
 
 #include <string>
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/string16.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/BufferList.h"
+#include "mozilla/mozalloc.h"
+
+class Pickle;
+
+class PickleIterator {
+public:
+  explicit PickleIterator(const Pickle& pickle);
+
+private:
+  friend class Pickle;
+
+  mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_;
+
+  template<typename T>
+  void CopyInto(T* dest);
+};
 
 // This class provides facilities for basic binary value packing and unpacking.
 //
 // The Pickle class supports appending primitive values (ints, strings, etc.)
 // to a pickle instance.  The Pickle instance grows its internal memory buffer
 // dynamically to hold the sequence of primitive values.   The internal memory
 // buffer is exposed as the "data" of the Pickle.  This "data" can be passed
 // to a Pickle object to initialize it for reading.
@@ -29,89 +46,77 @@
 //
 // The Pickle's data has a header which contains the size of the Pickle's
 // payload.  It can optionally support additional space in the header.  That
 // space is controlled by the header_size parameter passed to the Pickle
 // constructor.
 //
 class Pickle {
  public:
-  enum Ownership {
-    BORROWS,
-    OWNS,
-  };
-
   ~Pickle();
 
-  // Initialize a Pickle object using the default header size.
-  Pickle();
+  Pickle() = delete;
 
   // Initialize a Pickle object with the specified header size in bytes, which
   // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
   // will be rounded up to ensure that the header size is 32bit-aligned.
-  explicit Pickle(int header_size);
+  explicit Pickle(uint32_t header_size);
 
-  // Initializes a Pickle from a const block of data. If ownership == BORROWS,
-  // the data is not copied; instead the data is merely referenced by this
-  // Pickle. Only const methods should be used on the Pickle when initialized
-  // this way. The header padding size is deduced from the data length.  If
-  // ownership == OWNS, then again no copying takes place. However, the buffer
-  // is writable and will be freed when this Pickle is destroyed.
-  Pickle(const char* data, int data_len, Ownership ownership = BORROWS);
+  Pickle(uint32_t header_size, const char* data, uint32_t length);
 
-  // Initializes a Pickle as a deep copy of another Pickle.
-  Pickle(const Pickle& other);
+  Pickle(const Pickle& other) = delete;
 
   Pickle(Pickle&& other);
 
   // Performs a deep copy.
-  Pickle& operator=(const Pickle& other);
+  Pickle& operator=(const Pickle& other) = delete;
 
   Pickle& operator=(Pickle&& other);
 
   // Returns the size of the Pickle's data.
-  int size() const { return static_cast<int>(header_size_ +
-                                             header_->payload_size); }
+  uint32_t size() const { return header_size_ + header_->payload_size; }
+
+  typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
 
-  // Return the full size of the memory allocated for this Pickle's data.
-  uint32_t capacity() const {
-    return capacity_;
-  }
+  const BufferList& Buffers() const { return buffers_; }
 
-  // Returns the data for this Pickle.
-  const void* data() const { return header_; }
+  uint32_t CurrentSize() const { return buffers_.Size(); }
 
   // Methods for reading the payload of the Pickle.  To read from the start of
   // the Pickle, initialize *iter to NULL.  If successful, these methods return
   // true.  Otherwise, false is returned to indicate that the result could not
   // be extracted.
-  MOZ_MUST_USE bool ReadBool(void** iter, bool* result) const;
-  MOZ_MUST_USE bool ReadInt16(void** iter, int16_t* result) const;
-  MOZ_MUST_USE bool ReadUInt16(void** iter, uint16_t* result) const;
-  MOZ_MUST_USE bool ReadShort(void** iter, short* result) const;
-  MOZ_MUST_USE bool ReadInt(void** iter, int* result) const;
-  MOZ_MUST_USE bool ReadLong(void** iter, long* result) const;
-  MOZ_MUST_USE bool ReadULong(void** iter, unsigned long* result) const;
-  MOZ_MUST_USE bool ReadSize(void** iter, size_t* result) const;
-  MOZ_MUST_USE bool ReadInt32(void** iter, int32_t* result) const;
-  MOZ_MUST_USE bool ReadUInt32(void** iter, uint32_t* result) const;
-  MOZ_MUST_USE bool ReadInt64(void** iter, int64_t* result) const;
-  MOZ_MUST_USE bool ReadUInt64(void** iter, uint64_t* result) const;
-  MOZ_MUST_USE bool ReadDouble(void** iter, double* result) const;
-  MOZ_MUST_USE bool ReadIntPtr(void** iter, intptr_t* result) const;
-  MOZ_MUST_USE bool ReadUnsignedChar(void** iter, unsigned char* result) const;
-  MOZ_MUST_USE bool ReadString(void** iter, std::string* result) const;
-  MOZ_MUST_USE bool ReadWString(void** iter, std::wstring* result) const;
-  MOZ_MUST_USE bool ReadData(void** iter, const char** data, int* length) const;
-  MOZ_MUST_USE bool ReadBytes(void** iter, const char** data, int length,
-                              uint32_t alignment = sizeof(memberAlignmentType)) const;
+  MOZ_MUST_USE bool ReadBool(PickleIterator* iter, bool* result) const;
+  MOZ_MUST_USE bool ReadInt16(PickleIterator* iter, int16_t* result) const;
+  MOZ_MUST_USE bool ReadUInt16(PickleIterator* iter, uint16_t* result) const;
+  MOZ_MUST_USE bool ReadShort(PickleIterator* iter, short* result) const;
+  MOZ_MUST_USE bool ReadInt(PickleIterator* iter, int* result) const;
+  MOZ_MUST_USE bool ReadLong(PickleIterator* iter, long* result) const;
+  MOZ_MUST_USE bool ReadULong(PickleIterator* iter, unsigned long* result) const;
+  MOZ_MUST_USE bool ReadSize(PickleIterator* iter, size_t* result) const;
+  MOZ_MUST_USE bool ReadInt32(PickleIterator* iter, int32_t* result) const;
+  MOZ_MUST_USE bool ReadUInt32(PickleIterator* iter, uint32_t* result) const;
+  MOZ_MUST_USE bool ReadInt64(PickleIterator* iter, int64_t* result) const;
+  MOZ_MUST_USE bool ReadUInt64(PickleIterator* iter, uint64_t* result) const;
+  MOZ_MUST_USE bool ReadDouble(PickleIterator* iter, double* result) const;
+  MOZ_MUST_USE bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const;
+  MOZ_MUST_USE bool ReadUnsignedChar(PickleIterator* iter, unsigned char* result) const;
+  MOZ_MUST_USE bool ReadString(PickleIterator* iter, std::string* result) const;
+  MOZ_MUST_USE bool ReadWString(PickleIterator* iter, std::wstring* result) const;
+  MOZ_MUST_USE bool ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const;
+  MOZ_MUST_USE bool FlattenBytes(PickleIterator* iter, const char** data, uint32_t length,
+                                 uint32_t alignment = sizeof(memberAlignmentType));
 
   // Safer version of ReadInt() checks for the result not being negative.
   // Use it for reading the object sizes.
-  MOZ_MUST_USE bool ReadLength(void** iter, int* result) const;
+  MOZ_MUST_USE bool ReadLength(PickleIterator* iter, int* result) const;
+
+  MOZ_MUST_USE bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const;
+
+  void EndRead(PickleIterator& iter) const;
 
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
   // to the Pickle.
   bool WriteBool(bool value) {
     return WriteInt(value ? 1 : 0);
   }
@@ -159,44 +164,25 @@ class Pickle {
     // differ between architectures.
     return WriteInt64(int64_t(value));
   }
   bool WriteUnsignedChar(unsigned char value) {
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteString(const std::string& value);
   bool WriteWString(const std::wstring& value);
-  bool WriteData(const char* data, int length);
-  bool WriteBytes(const void* data, int data_len,
+  bool WriteData(const char* data, uint32_t length);
+  bool WriteBytes(const void* data, uint32_t data_len,
                   uint32_t alignment = sizeof(memberAlignmentType));
 
-  // Same as WriteData, but allows the caller to write directly into the
-  // Pickle. This saves a copy in cases where the data is not already
-  // available in a buffer. The caller should take care to not write more
-  // than the length it declares it will. Use ReadData to get the data.
-  // Returns NULL on failure.
-  //
-  // The returned pointer will only be valid until the next write operation
-  // on this Pickle.
-  char* BeginWriteData(int length);
+  bool WriteSentinel(uint32_t sentinel);
 
-  // For Pickles which contain variable length buffers (e.g. those created
-  // with BeginWriteData), the Pickle can
-  // be 'trimmed' if the amount of data required is less than originally
-  // requested.  For example, you may have created a buffer with 10K of data,
-  // but decided to only fill 10 bytes of that data.  Use this function
-  // to trim the buffer so that we don't send 9990 bytes of unused data.
-  // You cannot increase the size of the variable buffer; only shrink it.
-  // This function assumes that the length of the variable buffer has
-  // not been changed.
-  void TrimWriteData(int length);
+  int32_t* GetInt32PtrForTest(uint32_t offset);
 
-  void EndRead(void* iter) const {
-    DCHECK(iter == end_of_payload());
-  }
+  void InputBytes(const char* data, uint32_t length);
 
   // Payload follows after allocation of Header (header size is customizable).
   struct Header {
     uint32_t payload_size;  // Specifies the size of the payload.
   };
 
   // Returns the header, cast to a user-specified type T.  The type T must be a
   // subclass of Header and its size must correspond to the header_size passed
@@ -207,103 +193,72 @@ class Pickle {
     return static_cast<T*>(header_);
   }
   template <class T>
   const T* headerT() const {
     DCHECK(sizeof(T) == header_size_);
     return static_cast<const T*>(header_);
   }
 
-  // Returns true if the given iterator could point to data with the given
-  // length. If there is no room for the given data before the end of the
-  // payload, returns false.
-  bool IteratorHasRoomFor(const void* iter, int len) const {
-    if ((len < 0) || (iter < header_) || iter > end_of_payload())
-      return false;
-    const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
-    // Watch out for overflow in pointer calculation, which wraps.
-    return (iter <= end_of_region) && (end_of_region <= end_of_payload());
-  }
-
   typedef uint32_t memberAlignmentType;
 
  protected:
   uint32_t payload_size() const { return header_->payload_size; }
 
-  char* payload() {
-    return reinterpret_cast<char*>(header_) + header_size_;
-  }
-  const char* payload() const {
-    return reinterpret_cast<const char*>(header_) + header_size_;
-  }
-
-  // Returns the address of the byte immediately following the currently valid
-  // header + payload.
-  char* end_of_payload() {
-    // We must have a valid header_.
-    return payload() + payload_size();
-  }
-  const char* end_of_payload() const {
-    // This object may be invalid.
-    return header_ ? payload() + payload_size() : nullptr;
-  }
-
   // Resizes the buffer for use when writing the specified amount of data. The
   // location that the data should be written at is returned, or NULL if there
   // was an error. Call EndWrite with the returned offset and the given length
   // to pad out for the next write.
-  char* BeginWrite(uint32_t length, uint32_t alignment);
+  void BeginWrite(uint32_t length, uint32_t alignment);
 
   // Completes the write operation by padding the data with NULL bytes until it
   // is padded. Should be paired with BeginWrite, but it does not necessarily
   // have to be called after the data is written.
-  void EndWrite(char* dest, int length);
-
-  // Resize the capacity, note that the input value should include the size of
-  // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
-  // A realloc() failure will cause a Resize failure... and caller should check
-  // the return result for true (i.e., successful resizing).
-  void Resize(uint32_t new_capacity);
+  void EndWrite(uint32_t length);
 
   // Round 'bytes' up to the next multiple of 'alignment'.  'alignment' must be
   // a power of 2.
   template<uint32_t alignment> struct ConstantAligner {
     static uint32_t align(int bytes) {
       static_assert((alignment & (alignment - 1)) == 0,
                     "alignment must be a power of two");
       return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1);
     }
   };
 
   static uint32_t AlignInt(int bytes) {
     return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes);
   }
 
+  static uint32_t AlignCapacity(int bytes) {
+    return ConstantAligner<kSegmentAlignment>::align(bytes);
+  }
+
+  // Returns true if the given iterator could point to data with the given
+  // length. If there is no room for the given data before the end of the
+  // payload, returns false.
+  bool IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const;
+
   // Moves the iterator by the given number of bytes, making sure it is aligned.
   // Pointer (iterator) is NOT aligned, but the change in the pointer
   // is guaranteed to be a multiple of sizeof(memberAlignmentType).
-  static void UpdateIter(void** iter, int bytes) {
-    *iter = static_cast<char*>(*iter) + AlignInt(bytes);
-  }
+  void UpdateIter(PickleIterator* iter, uint32_t bytes) const;
 
-  // Find the end of the pickled data that starts at range_start.  Returns NULL
-  // if the entire Pickle is not found in the given data range.
-  static const char* FindNext(uint32_t header_size,
+  // Figure out how big the message starting at range_start is. Returns 0 if
+  // there's no enough data to determine (i.e., if [range_start, range_end) does
+  // not contain enough of the message header to know the size).
+  static uint32_t MessageSize(uint32_t header_size,
                               const char* range_start,
                               const char* range_end);
 
-  // If the given range contains at least header_size bytes, return the length
-  // of the pickled data including the header.
-  static uint32_t GetLength(uint32_t header_size,
-                            const char* range_start,
-                            const char* range_end);
-
-  // The allocation granularity of the payload.
-  static const int kPayloadUnit;
+  // Segments capacities are aligned to 8 bytes to ensure that all reads/writes
+  // at 8-byte aligned offsets will be on 8-byte aligned pointers.
+  static const uint32_t kSegmentAlignment = 8;
 
  private:
+  friend class PickleIterator;
+
+  BufferList buffers_;
   Header* header_;
   uint32_t header_size_;
-  uint32_t capacity_;
-  uint32_t variable_buffer_offset_;
 };
 
 #endif  // BASE_PICKLE_H__
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -30,16 +30,19 @@
 #include "base/string_util.h"
 #include "base/singleton.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/file_descriptor_set_posix.h"
 #include "chrome/common/ipc_message_utils.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/UniquePtr.h"
 
+// Work around possible OS limitations.
+static const size_t kMaxIOVecSize = 256;
+
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracerImpl.h"
 using namespace mozilla::tasktracer;
 #endif
 
 namespace IPC {
 
 // IPC channels on Windows use named pipes (CreateNamedPipe()) with
@@ -180,17 +183,18 @@ Channel::ChannelImpl::ChannelImpl(int fd
   EnqueueHelloMessage();
 }
 
 void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
   DCHECK(kControlBufferSlopBytes >= CMSG_SPACE(0));
 
   mode_ = mode;
   is_blocked_on_write_ = false;
-  message_send_bytes_written_ = 0;
+  partial_write_iter_.reset();
+  input_buf_offset_ = 0;
   server_listen_pipe_ = -1;
   pipe_ = -1;
   client_pipe_ = -1;
   listener_ = listener;
   waiting_connect_ = true;
   processing_incoming_ = false;
   closed_ = false;
 #if defined(OS_MACOSX)
@@ -258,21 +262,16 @@ bool Channel::ChannelImpl::EnqueueHelloM
     Close();
     return false;
   }
 
   OutputQueuePush(msg.release());
   return true;
 }
 
-void Channel::ChannelImpl::ClearAndShrinkInputOverflowBuf()
-{
-  input_overflow_buf_.clear();
-}
-
 bool Channel::ChannelImpl::Connect() {
   if (pipe_ == -1) {
     return false;
   }
 
   MessageLoopForIO::current()->WatchFileDescriptor(
       pipe_,
       true,
@@ -282,49 +281,50 @@ bool Channel::ChannelImpl::Connect() {
   waiting_connect_ = false;
 
   if (!waiting_connect_)
     return ProcessOutgoingMessages();
   return true;
 }
 
 bool Channel::ChannelImpl::ProcessIncomingMessages() {
-  ssize_t bytes_read = 0;
-
   struct msghdr msg = {0};
-  struct iovec iov = {input_buf_, Channel::kReadBufferSize};
+  struct iovec iov;
 
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_control = input_cmsg_buf_;
 
   for (;;) {
     msg.msg_controllen = sizeof(input_cmsg_buf_);
 
-    if (bytes_read == 0) {
-      if (pipe_ == -1)
-        return false;
+    if (pipe_ == -1)
+      return false;
 
-      // Read from pipe.
-      // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
-      // is waiting on the pipe.
-      bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+    // In some cases the beginning of a message will be stored in input_buf_. We
+    // don't want to overwrite that, so we store the new data after it.
+    iov.iov_base = input_buf_ + input_buf_offset_;
+    iov.iov_len = Channel::kReadBufferSize - input_buf_offset_;
 
-      if (bytes_read < 0) {
-        if (errno == EAGAIN) {
-          return true;
-        } else {
-          CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
-          return false;
-        }
-      } else if (bytes_read == 0) {
-        // The pipe has closed...
-        Close();
+    // Read from pipe.
+    // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
+    // is waiting on the pipe.
+    ssize_t bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+
+    if (bytes_read < 0) {
+      if (errno == EAGAIN) {
+        return true;
+      } else {
+        CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
         return false;
       }
+    } else if (bytes_read == 0) {
+      // The pipe has closed...
+      Close();
+      return false;
     }
     DCHECK(bytes_read);
 
     if (client_pipe_ != -1) {
       Singleton<PipeMap>()->Remove(pipe_name_);
       HANDLE_EINTR(close(client_pipe_));
       client_pipe_ = -1;
     }
@@ -368,54 +368,18 @@ bool Channel::ChannelImpl::ProcessIncomi
             return false;
           }
           break;
         }
       }
     }
 
     // Process messages from input buffer.
-    const char *p;
-    const char *overflowp;
-    const char *end;
-    if (input_overflow_buf_.empty()) {
-      overflowp = NULL;
-      p = input_buf_;
-      end = p + bytes_read;
-    } else {
-      if (input_overflow_buf_.size() >
-         static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
-        ClearAndShrinkInputOverflowBuf();
-        CHROMIUM_LOG(ERROR) << "IPC message is too big";
-        return false;
-      }
-
-      input_overflow_buf_.append(input_buf_, bytes_read);
-      overflowp = p = input_overflow_buf_.data();
-      end = p + input_overflow_buf_.size();
-
-      // If we've received the entire header, then we know the message
-      // length. In that case, reserve enough space to hold the entire
-      // message. This is more efficient than repeatedly enlarging the buffer as
-      // more data comes in.
-      uint32_t length = Message::GetLength(p, end);
-      if (length) {
-        if (length > kMaximumMessageSize) {
-          ClearAndShrinkInputOverflowBuf();
-          CHROMIUM_LOG(ERROR) << "IPC message is too big";
-          return false;
-        }
-
-        input_overflow_buf_.reserve(length + kReadBufferSize);
-
-        // Recompute these pointers in case the buffer moved.
-        overflowp = p = input_overflow_buf_.data();
-        end = p + input_overflow_buf_.size();
-      }
-    }
+    const char *p = input_buf_;
+    const char *end = input_buf_ + input_buf_offset_ + bytes_read;
 
     // A pointer to an array of |num_fds| file descriptors which includes any
     // fds that have spilled over from a previous read.
     const int* fds;
     unsigned num_fds;
     unsigned fds_i = 0;  // the index of the first unused descriptor
 
     if (input_overflow_fds_.empty()) {
@@ -425,141 +389,164 @@ bool Channel::ChannelImpl::ProcessIncomi
       const size_t prev_size = input_overflow_fds_.size();
       input_overflow_fds_.resize(prev_size + num_wire_fds);
       memcpy(&input_overflow_fds_[prev_size], wire_fds,
              num_wire_fds * sizeof(int));
       fds = &input_overflow_fds_[0];
       num_fds = input_overflow_fds_.size();
     }
 
+    // The data for the message we're currently reading consists of any data
+    // stored in incoming_message_ followed by data in input_buf_ (followed by
+    // other messages).
+
     while (p < end) {
-      const char* message_tail = Message::FindNext(p, end);
-      if (message_tail) {
-        int len = static_cast<int>(message_tail - p);
-        char* buf;
+      // Try to figure out how big the message is. Size is 0 if we haven't read
+      // enough of the header to know the size.
+      uint32_t message_length = 0;
+      if (incoming_message_.isSome()) {
+        message_length = incoming_message_.ref().size();
+      } else {
+        message_length = Message::MessageSize(p, end);
+      }
+
+      if (!message_length) {
+        // We haven't seen the full message header.
+        MOZ_ASSERT(incoming_message_.isNothing());
+
+        // Move everything we have to the start of the buffer. We'll finish
+        // reading this message when we get more data. For now we leave it in
+        // input_buf_.
+        memmove(input_buf_, p, end - p);
+        input_buf_offset_ = end - p;
+
+        break;
+      }
+
+      input_buf_offset_ = 0;
+
+      bool partial;
+      if (incoming_message_.isSome()) {
+        // We already have some data for this message stored in
+        // incoming_message_. We want to append the new data there.
+        Message& m = incoming_message_.ref();
 
-        // The Message |m| allocated below needs to own its data. We can either
-        // copy the data out of the buffer or else steal the buffer and move the
-        // remaining data elsewhere. If len is large enough, we steal. Otherwise
-        // we copy.
-        if (len > kMaxCopySize) {
-          // Since len > kMaxCopySize > kReadBufferSize, we know that we must be
-          // using the overflow buffer. And since we always shift everything to
-          // the left at the end of a read, we must be at the start of the
-          // overflow buffer.
-          MOZ_RELEASE_ASSERT(p == overflowp);
-          buf = input_overflow_buf_.trade_bytes(len);
+        // How much data from this message remains to be added to
+        // incoming_message_?
+        MOZ_ASSERT(message_length > m.CurrentSize());
+        uint32_t remaining = message_length - m.CurrentSize();
+
+        // How much data from this message is stored in input_buf_?
+        uint32_t in_buf = std::min(remaining, uint32_t(end - p));
+
+        m.InputBytes(p, in_buf);
+        p += in_buf;
+
+        // Are we done reading this message?
+        partial = in_buf != remaining;
+      } else {
+        // How much data from this message is stored in input_buf_?
+        uint32_t in_buf = std::min(message_length, uint32_t(end - p));
 
-          // At this point the remaining data is at the front of
-          // input_overflow_buf_. p will get fixed up at the end of the
-          // loop. Set it to null here to make sure no one uses it.
-          p = nullptr;
-          overflowp = message_tail = input_overflow_buf_.data();
-          end = overflowp + input_overflow_buf_.size();
-        } else {
-          buf = (char*)moz_xmalloc(len);
-          memcpy(buf, p, len);
+        incoming_message_.emplace(p, in_buf);
+        p += in_buf;
+
+        // Are we done reading this message?
+        partial = in_buf != message_length;
+      }
+
+      if (partial) {
+        break;
+      }
+
+      Message& m = incoming_message_.ref();
+
+      if (m.header()->num_fds) {
+        // the message has file descriptors
+        const char* error = NULL;
+        if (m.header()->num_fds > num_fds - fds_i) {
+          // the message has been completely received, but we didn't get
+          // enough file descriptors.
+          error = "Message needs unreceived descriptors";
         }
-        Message m(buf, len, Message::OWNS);
-        if (m.header()->num_fds) {
-          // the message has file descriptors
-          const char* error = NULL;
-          if (m.header()->num_fds > num_fds - fds_i) {
-            // the message has been completely received, but we didn't get
-            // enough file descriptors.
-            error = "Message needs unreceived descriptors";
-          }
+
+        if (m.header()->num_fds >
+            FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
+          // There are too many descriptors in this message
+          error = "Message requires an excessive number of descriptors";
+        }
 
-          if (m.header()->num_fds >
-              FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
-            // There are too many descriptors in this message
-            error = "Message requires an excessive number of descriptors";
-          }
-
-          if (error) {
-            CHROMIUM_LOG(WARNING) << error
-                                  << " channel:" << this
-                                  << " message-type:" << m.type()
-                                  << " header()->num_fds:" << m.header()->num_fds
-                                  << " num_fds:" << num_fds
-                                  << " fds_i:" << fds_i;
-            // close the existing file descriptors so that we don't leak them
-            for (unsigned i = fds_i; i < num_fds; ++i)
-              HANDLE_EINTR(close(fds[i]));
-            input_overflow_fds_.clear();
-            // abort the connection
-            return false;
-          }