Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 27 Feb 2014 15:43:29 +0100
changeset 171438 fb009d10f3e6d0f47cdc5f4e88b1d359765f118c
parent 171437 3b92bea7b2e78893609424e264f42b25f6d7069d (current diff)
parent 171323 4cfb6c61b13789061152cd9b04950b0430ddf81d (diff)
child 171439 c10115ce8c0dd25e2b98dd09b87f82f58b584364
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge mozilla-central to fx-team
dom/events/nsDOMDataTransfer.cpp
dom/events/nsDOMDataTransfer.h
toolkit/crashreporter/google-breakpad/src/common/mac/Makefile.in
xpcom/base/nsTraceRefcntImpl.cpp
xpcom/base/nsTraceRefcntImpl.h
xpcom/glue/nsTraceRefcnt.h
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -12,17 +12,17 @@
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 #include "OuterDocAccessible.h"
 
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISelectionPrivate.h"
-#include "nsTraceRefcntImpl.h"
+#include "nsTraceRefcnt.h"
 #include "nsIWebProgress.h"
 #include "prenv.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIURI.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
@@ -795,17 +795,17 @@ logging::DOMEvent(const char* aDescr, ns
   logging::MsgEnd();
 }
 
 void
 logging::Stack()
 {
   if (IsEnabled(eStack)) {
     printf("  stack: \n");
-    nsTraceRefcntImpl::WalkTheStack(stdout);
+    nsTraceRefcnt::WalkTheStack(stdout);
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // namespace logging:: initialization
 
 bool
 logging::IsEnabled(uint32_t aModules)
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -428,16 +428,25 @@ this.Logger = {
     if (aEvent.eventType == Events.STATE_CHANGE) {
       let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
       let stateStrings = event.isExtraState ?
         Utils.AccRetrieval.getStringStates(0, event.state) :
         Utils.AccRetrieval.getStringStates(event.state, 0);
       str += ' (' + stateStrings.item(0) + ')';
     }
 
+    if (aEvent.eventType == Events.VIRTUALCURSOR_CHANGED) {
+      let event = aEvent.QueryInterface(
+        Ci.nsIAccessibleVirtualCursorChangeEvent);
+      let pivot = aEvent.accessible.QueryInterface(
+        Ci.nsIAccessibleDocument).virtualCursor;
+      str += ' (' + this.accessibleToString(event.oldAccessible) + ' -> ' +
+	this.accessibleToString(pivot.position) + ')';
+    }
+
     return str;
   },
 
   statesToString: function statesToString(aAccessible) {
     return Utils.getState(aAccessible).toString();
   },
 
   dumpTree: function dumpTree(aLogLevel, aRootAccessible) {
--- a/accessible/src/jsat/content-script.js
+++ b/accessible/src/jsat/content-script.js
@@ -395,16 +395,18 @@ addMessageListener(
     addMessageListener('AccessFu:MoveCaret', moveCaret);
     addMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
     addMessageListener('AccessFu:ClearCursor', clearCursor);
 
     if (!eventManager) {
       eventManager = new EventManager(this);
     }
     eventManager.start();
+
+    sendAsyncMessage('AccessFu:ContentStarted');
   });
 
 addMessageListener(
   'AccessFu:Stop',
   function(m) {
     Logger.debug('AccessFu:Stop');
 
     removeMessageListener('AccessFu:MoveToPoint', moveToPoint);
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   jsatcommon.js
   output.js
   doc_traversal.html
+  doc_content_integration.html
 
 [test_alive.html]
+[test_content_integration.html]
 [test_explicit_names.html]
 [test_landmarks.html]
 [test_live_regions.html]
 [test_output.html]
 [test_tables.html]
 [test_traversal.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/doc_content_integration.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Traversal Rule test document</title>
+  <meta charset="utf-8" />
+  <script>
+    var frameContents = '<html>' +
+      '<head><title>such app</title></head>' +
+      '<body>' +
+      '<h1>wow</h1>' +
+      '<label><input type="checkbox">many option</label>' +
+      '</body>' +
+      '</html>';
+
+  </script>
+  <style>
+    #windows > iframe {
+      width: 320px;
+      height: 480px;
+    }
+  </style>
+
+</head>
+<body>
+  <div>Phone status bar</div>
+  <div id="windows"></div>
+  <button>Home</button>
+</body>
+</html>
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -150,8 +150,122 @@ var AccessFuTest = {
       }
     };
 
     // Invoke the whole thing.
     SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
     SpecialPowers.setIntPref("accessibility.accessfu.notify_output", 1);
   }
 };
+
+function AccessFuContentTest(aFuncResultPairs) {
+  this.queue = aFuncResultPairs;
+}
+
+AccessFuContentTest.prototype = {
+  currentPair: null,
+
+  start: function(aFinishedCallback) {
+    this.finishedCallback = aFinishedCallback;
+    var self = this;
+
+    // Get top content message manager, and set it up.
+    this.mms = [Utils.getMessageManager(currentBrowser())];
+    this.setupMessageManager(this.mms[0], function () {
+      // Get child message managers and set them up
+      var frames = currentTabDocument().querySelectorAll('iframe');
+      var toSetup = 0;
+      for (var i = 0; i < frames.length; i++ ) {
+        var mm = Utils.getMessageManager(frames[i]);
+        if (mm) {
+          toSetup++;
+          self.mms.push(mm);
+          self.setupMessageManager(mm, function () {
+            if (--toSetup === 0) {
+              // All message managers are loaded and ready to go.
+              self.pump();
+            }
+          });
+        }
+      }
+    });
+  },
+
+  setupMessageManager:  function (aMessageManager, aCallback) {
+    function contentScript() {
+      addMessageListener('AccessFuTest:Focus', function (aMessage) {
+        var elem = content.document.querySelector(aMessage.json.selector);
+        if (elem) {
+          if (aMessage.json.blur) {
+            elem.blur();
+          } else {
+            elem.focus();
+          }
+        }
+      });
+    }
+
+    aMessageManager.addMessageListener('AccessFu:Present', this);
+    aMessageManager.addMessageListener('AccessFu:Ready', function (aMessage) {
+      aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback);
+      aMessageManager.sendAsyncMessage('AccessFu:Start', { buildApp: 'browser' });
+    });
+
+    aMessageManager.loadFrameScript(
+      'chrome://global/content/accessibility/content-script.js', false);
+    aMessageManager.loadFrameScript(
+      'data:,(' + contentScript.toString() + ')();', false);
+  },
+
+  pump: function() {
+    this.currentPair = this.queue.shift();
+
+    if (this.currentPair) {
+      if (this.currentPair[0] instanceof Function) {
+        this.currentPair[0](this.mms[0]);
+      } else {
+        this.mms[0].sendAsyncMessage(this.currentPair[0].name,
+                                     this.currentPair[0].json);
+      }
+    } else if (this.finishedCallback) {
+      for (var mm of this.mms) {
+	mm.sendAsyncMessage('AccessFu:Stop');
+      }
+      this.finishedCallback();
+    }
+  },
+
+  receiveMessage: function(aMessage) {
+    if (!this.currentPair) {
+      return;
+    }
+
+    var expected = this.currentPair[1];
+
+    if (expected) {
+      if (expected.speak !== undefined) {
+        var speech = this.extractUtterance(aMessage.json);
+        if (!speech) {
+          // Probably a visual highlight adjustment after a scroll.
+          return;
+        }
+        var checkFunc = SimpleTest[expected.speak_checkFunc] || is;
+        checkFunc(speech, expected.speak);
+      }
+    }
+
+    this.pump();
+  },
+
+  extractUtterance: function(aData) {
+    for (var output of aData) {
+      if (output && output.type === 'Speech') {
+        for (var action of output.details.actions) {
+          if (action && action.method == 'speak') {
+            return action.data;
+          }
+        }
+      }
+    }
+
+    return null;
+  }
+};
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Tests AccessFu content integration</title>
+  <meta charset="utf-8" />
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js">
+  </script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/chrome-harness.js">
+  </script>
+
+  <script type="application/javascript" src="../common.js"></script>
+  <script type="application/javascript" src="../browser.js"></script>
+  <script type="application/javascript" src="../events.js"></script>
+  <script type="application/javascript" src="../role.js"></script>
+  <script type="application/javascript" src="../states.js"></script>
+  <script type="application/javascript" src="../layout.js"></script>
+  <script type="application/javascript" src="jsatcommon.js"></script>
+
+  <script type="application/javascript">
+    function doTest() {
+      var doc = currentTabDocument();
+      var iframe = doc.createElement("iframe");
+      iframe.mozbrowser = true;
+      iframe.addEventListener("mozbrowserloadend", function () {
+        var simpleMoveNext = { name: 'AccessFu:MoveCursor',
+                               json: { action: 'moveNext',
+                                       rule: 'Simple',
+                                       inputType: 'gesture',
+                                       origin: 'top' }
+                             };
+
+        var simpleMovePrevious = { name: 'AccessFu:MoveCursor',
+                                   json: { action: 'movePrevious',
+                                           rule: 'Simple',
+                                           inputType: 'gesture',
+                                           origin: 'top' }
+                                 };
+
+        var activateCurrent = { name: 'AccessFu:Activate',
+                                json: { origin: 'top' } };
+
+        var simpleMoveLast = { name: 'AccessFu:MoveCursor',
+                               json: { action: 'moveLast',
+                                       rule: 'Simple',
+                                       inputType: 'gesture',
+                                       origin: 'top' }
+                             };
+
+        var simpleMoveFirst = { name: 'AccessFu:MoveCursor',
+                                json: { action: 'moveFirst',
+                                        rule: 'Simple',
+                                        inputType: 'gesture',
+                                        origin: 'top' }
+                              };
+
+        var clearCursor = { name: 'AccessFu:ClearCursor',
+                            json: { origin: 'top' }
+                          };
+
+        function focusFunc(aSelector, aBlur) {
+         return function (mm) {
+          mm.sendAsyncMessage(
+            'AccessFuTest:Focus', { selector: aSelector, blur: aBlur });
+          };
+        }
+
+        var contentTest = new AccessFuContentTest(
+          [
+            // Simple traversal forward
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+           [simpleMoveNext,
+            { speak: 'wow heading level 1 such app' }],
+           [simpleMoveNext,
+            { speak: 'many option not checked check button' }],
+            // check checkbox
+           [activateCurrent,
+            { speak: 'checked' }],
+            [null,
+             { speak: 'checked', speak_checkFunc: 'todo_isnot' }],
+            // uncheck checkbox
+           [simpleMoveNext,
+            { speak: 'Home button' }],
+
+            // Simple traversal backward
+           [simpleMovePrevious,
+            { speak: 'many option checked check button such app' }],
+           [activateCurrent,
+            { speak: 'unchecked' }],
+           [null,
+            { speak: 'unchecked', speak_checkFunc: 'todo_isnot' }],
+           [simpleMovePrevious,
+            { speak: 'wow heading level 1' }],
+           [simpleMovePrevious,
+            { speak: 'Phone status bar' }],
+
+            // Moving to the absolute last item from an embedded document fails.
+            // Bug 972035.
+            [simpleMoveNext,
+            { speak: 'wow heading level 1 such app' }],
+            // Move from an inner frame to the last element in the parent doc
+            [simpleMoveLast,
+             { speak: 'Home button', speak_checkFunc: 'todo_is' }],
+
+            [clearCursor, null], // Reset cursors
+
+            // Moving to the absolute first item from an embedded document fails.
+            // Bug 972035.
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+            [simpleMoveNext,
+             { speak: 'wow heading level 1 such app' }],
+            [simpleMoveNext,
+             { speak: 'many option not checked check button' }],
+            [simpleMoveFirst,
+             { speak: 'Phone status bar', speak_checkFunc: 'todo_is' }],
+
+            // Reset cursors
+            [clearCursor, null],
+
+            // Move cursor with focus in outside document
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+            [ focusFunc('button', false), { speak: 'Home button' }],
+
+            // Blur button and reset cursor
+            [focusFunc('button', true), null],
+            [clearCursor, null],
+
+            // Set focus on element outside of embedded frame while cursor is in frame
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+            [simpleMoveNext,
+             { speak: 'wow heading level 1 such app' }],
+            [focusFunc('button', false), { speak: 'Home button' }]
+
+            // XXX: Set focus on iframe itself.
+            // XXX: Set focus on element in iframe when cursor is outside of it.
+            // XXX: Set focus on element in iframe when cursor is in iframe.
+        ]);
+
+        contentTest.start(function () {
+          closeBrowserWindow();
+          SimpleTest.finish();
+        });
+
+      });
+      iframe.src = 'data:text/html;charset=utf-8,' + doc.defaultView.frameContents;
+      doc.querySelector('#windows').appendChild(iframe);
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(
+      function () {
+        openBrowserWindow(
+          function () {
+            SpecialPowers.pushPrefEnv({
+              "set": [
+                // TODO: remove this as part of bug 820712
+                ["network.disable.ipc.security", true],
+
+
+                ["dom.ipc.browser_frames.oop_by_default", true],
+                ["dom.mozBrowserFramesEnabled", true],
+                ["browser.pagethumbnails.capturing_disabled", true]
+              ]
+            }, doTest) },
+          getRootDirectory(window.location.href) + "doc_content_integration.html");
+        });
+  </script>
+</head>
+<body id="body">
+
+  <a target="_blank"
+     title="Add tests for OOP message handling and general integration"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=972047">Mozilla Bug 933808</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+</body>
+</html>
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -21,17 +21,16 @@ LIBS += \
   $(MOZ_ZLIB_LIBS) \
   $(NULL)
 ifeq ($(ANDROID_VERSION),$(findstring $(ANDROID_VERSION),17 18 19))
 LIBS += \
   -lgui \
   -lsuspend \
   $(NULL)
 endif
-OS_LDFLAGS += -Wl,--export-dynamic
 endif
 
 STL_FLAGS=
 
 LIBS += $(JEMALLOC_LIBS)
 
 LIBS += \
   $(XPCOM_STANDALONE_GLUE_LDOPTS) \
--- a/b2g/app/moz.build
+++ b/b2g/app/moz.build
@@ -34,8 +34,10 @@ LOCAL_INCLUDES += [
     '/xpcom/base',
     '/xpcom/build',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     LOCAL_INCLUDES += [
         '/widget/gonk/libdisplay',
     ]
+
+    LDFLAGS += ['-Wl,--export-dynamic']
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "remote": "", 
         "branch": "", 
         "revision": ""
     }, 
-    "revision": "2761bef239957844e6126ef252b82b5f63b304e7", 
+    "revision": "cba6294f97cb705143dc4581410518901aa4aa59", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22d48b62df7901ad45044f66e15e7d8943884a06"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a9fdec737cdfd41206a332970fea833ec4ca13a"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -21,16 +21,17 @@ MOZ_SAFE_BROWSING=
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_METRICS=1
 MOZ_CAPTIVEDETECT=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_DISABLE_CRYPTOLEGACY=1
 MOZ_APP_STATIC_INI=1
 NSS_NO_LIBPKIX=1
+MOZ_NO_EV_CERTS=1
 MOZ_DISABLE_EXPORT_JS=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
 MOZ_RAW=1
 MOZ_AUDIO_CHANNEL_MANAGER=1
 fi
 
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -62,32 +62,16 @@ RCINCLUDE = splash.rc
 # here.
 EXTRA_DEPS += firefox.exe.manifest
 endif
 
 PROGRAMS_DEST = $(DIST)/bin
 
 include $(topsrcdir)/config/rules.mk
 
-ifeq ($(OS_ARCH),WINNT) #{
-#
-# Control the default heap size.
-# This is the heap returned by GetProcessHeap().
-# As we use the CRT heap, the default size is too large and wastes VM.
-#
-# The default heap size is 1MB on Win32.
-# The heap will grow if need be.
-#
-# Set it to 256k.  See bug 127069.
-#
-ifndef GNU_CC #{
-LDFLAGS += /HEAP:0x40000
-endif #}
-endif #}
-
 ifneq (,$(filter-out WINNT,$(OS_ARCH)))
 
 ifdef COMPILE_ENVIRONMENT
 libs:: 
 	cp -p $(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
 
 GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, firefox.js)
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -35,8 +35,19 @@ LOCAL_INCLUDES += [
 
 if CONFIG['_MSC_VER']:
     # Always enter a Windows program through wmain, whether or not we're
     # a console application.
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DEFINES['MOZ_PHOENIX'] = True
+
+# Control the default heap size.
+# This is the heap returned by GetProcessHeap().
+# As we use the CRT heap, the default size is too large and wastes VM.
+#
+# The default heap size is 1MB on Win32.
+# The heap will grow if need be.
+#
+# Set it to 256k.  See bug 127069.
+if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
+    LDFLAGS += ['/HEAP:0x40000']
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -487,34 +487,18 @@ function sendDragEvent(aEventType, aTarg
 
 /**
  * Creates a custom drag event.
  * @param aEventType The drag event's type.
  * @param aData The event's drag data (optional).
  * @return The drag event.
  */
 function createDragEvent(aEventType, aData) {
-  let dataTransfer = {
-    mozUserCancelled: false,
-    setData: function () null,
-    setDragImage: function () null,
-    getData: function () aData,
-
-    types: {
-      contains: function (aType) aType == "text/x-moz-url"
-    },
-
-    mozGetDataAt: function (aType, aIndex) {
-      if (aIndex || aType != "text/x-moz-url")
-        return null;
-
-      return aData;
-    }
-  };
-
+  let dataTransfer = new getContentWindow().DataTransfer("dragstart", false);
+  dataTransfer.mozSetDataAt("text/x-moz-url", aData, 0);
   let event = getContentDocument().createEvent("DragEvents");
   event.initDragEvent(aEventType, true, true, getContentWindow(), 0, 0, 0, 0, 0,
                       false, false, false, false, 0, null, dataTransfer);
 
   return event;
 }
 
 /**
--- a/browser/components/customizableui/src/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/src/CustomizableWidgets.jsm
@@ -673,45 +673,40 @@ const CustomizableWidgets = [{
       containerElem.addEventListener("command", this.onCommand, false);
 
       let list = this.charsetInfo[aSection];
 
       for (let item of list) {
         let elem = aDocument.createElementNS(kNSXUL, "toolbarbutton");
         elem.setAttribute("label", item.label);
         elem.setAttribute("type", "checkbox");
-        elem.section = aSection == "detectors" ? "detectors" : "charsets";
-        elem.value = item.id;
+        elem.section = aSection;
+        elem.value = item.value;
         elem.setAttribute("class", "subviewbutton");
         containerElem.appendChild(elem);
       }
     },
     updateCurrentCharset: function(aDocument) {
       let content = aDocument.defaultView.content;
       let currentCharset = content && content.document && content.document.characterSet;
-      if (currentCharset) {
-        currentCharset = aDocument.defaultView.FoldCharset(currentCharset);
-      }
-      currentCharset = currentCharset ? ("charset." + currentCharset) : "";
+      currentCharset = CharsetMenu.foldCharset(currentCharset);
 
       let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
       let charsetContainer = aDocument.getElementById("PanelUI-characterEncodingView-charsets");
       let elements = [...(pinnedContainer.childNodes), ...(charsetContainer.childNodes)];
 
       this._updateElements(elements, currentCharset);
     },
     updateCurrentDetector: function(aDocument) {
       let detectorContainer = aDocument.getElementById("PanelUI-characterEncodingView-autodetect");
-      let detectorEnum = CharsetManager.GetCharsetDetectorList();
       let currentDetector;
       try {
         currentDetector = Services.prefs.getComplexValue(
           "intl.charset.detector", Ci.nsIPrefLocalizedString).data;
       } catch (e) {}
-      currentDetector = "chardet." + (currentDetector || "off");
 
       this._updateElements(detectorContainer.childNodes, currentDetector);
     },
     _updateElements: function(aElements, aCurrentItem) {
       if (!aElements.length) {
         return;
       }
       let disabled = this.maybeDisableMenu(aElements[0].ownerDocument);
@@ -757,23 +752,18 @@ const CustomizableWidgets = [{
 
       let window = node.ownerDocument.defaultView;
       let section = node.section;
       let value = node.value;
 
       // The behavior as implemented here is directly based off of the
       // `MultiplexHandler()` method in browser.js.
       if (section != "detectors") {
-        let charset = value.substring(value.indexOf('charset.') + 'charset.'.length);
-        window.BrowserSetForcedCharacterSet(charset);
+        window.BrowserSetForcedCharacterSet(value);
       } else {
-        value = value.replace(/^chardet\./, "");
-        if (value == "off") {
-          value = "";
-        }
         // Set the detector pref.
         try {
           let str = Cc["@mozilla.org/supports-string;1"]
                       .createInstance(Ci.nsISupportsString);
           str.data = value;
           Services.prefs.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str);
         } catch (e) {
           Cu.reportError("Failed to set the intl.charset.detector preference.");
--- a/config/config.mk
+++ b/config/config.mk
@@ -476,17 +476,17 @@ INCLUDES = \
   $(NSPR_CFLAGS) $(NSS_CFLAGS) \
   $(OS_INCLUDES) \
   $(NULL)
 
 include $(topsrcdir)/config/static-checking-config.mk
 
 CFLAGS		= $(OS_CPPFLAGS) $(OS_CFLAGS)
 CXXFLAGS	= $(OS_CPPFLAGS) $(OS_CXXFLAGS)
-LDFLAGS		= $(OS_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
+LDFLAGS		= $(OS_LDFLAGS) $(MOZBUILD_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
 
 # Allow each module to override the *default* optimization settings
 # by setting MODULE_OPTIMIZE_FLAGS if the developer has not given
 # arguments to --enable-optimize
 ifdef MOZ_OPTIMIZE
 ifeq (1,$(MOZ_OPTIMIZE))
 ifdef MODULE_OPTIMIZE_FLAGS
 CFLAGS		+= $(MODULE_OPTIMIZE_FLAGS)
@@ -582,20 +582,20 @@ HOST_CMMFLAGS += -fobjc-exceptions
 OS_COMPILE_CMFLAGS += -fobjc-exceptions
 OS_COMPILE_CMMFLAGS += -fobjc-exceptions
 ifeq ($(MOZ_WIDGET_TOOLKIT),uikit)
 OS_COMPILE_CMFLAGS += -fobjc-abi-version=2 -fobjc-legacy-dispatch
 OS_COMPILE_CMMFLAGS += -fobjc-abi-version=2 -fobjc-legacy-dispatch
 endif
 endif
 
-COMPILE_CFLAGS	= $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CFLAGS) $(CFLAGS) $(EXTRA_COMPILE_FLAGS)
-COMPILE_CXXFLAGS = $(STL_FLAGS) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CXXFLAGS) $(CXXFLAGS) $(EXTRA_COMPILE_FLAGS)
-COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(EXTRA_COMPILE_FLAGS)
-COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CFLAGS	= $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CXXFLAGS = $(STL_FLAGS) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CXXFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS) $(EXTRA_COMPILE_FLAGS)
 ASFLAGS += $(EXTRA_ASSEMBLER_FLAGS)
 
 ifndef CROSS_COMPILE
 HOST_CFLAGS += $(RTL_FLAGS)
 endif
 
 #
 # Name of the binary code directories
--- a/configure.in
+++ b/configure.in
@@ -1294,26 +1294,16 @@ if test "$GNU_CC"; then
     CFLAGS="$CFLAGS -std=gnu99"
     if test "${OS_ARCH}" != Darwin; then
         CFLAGS="$CFLAGS -fgnu89-inline"
     fi
     # FIXME: Let us build with strict aliasing. bug 414641.
     CFLAGS="$CFLAGS -fno-strict-aliasing"
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
-    DSO_LDOPTS='-shared'
-    if test "$GCC_USE_GNU_LD"; then
-        # Some tools like ASan use a runtime library that is only
-        # linked against executables, so we must allow undefined
-        # symbols for shared objects in some cases.
-        if test -z "$MOZ_NO_WLZDEFS"; then
-            # Don't allow undefined symbols in libraries
-            DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs"
-        fi
-    fi
     WARNINGS_AS_ERRORS='-Werror'
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     ASFLAGS="$ASFLAGS -fPIC"
     AC_MSG_CHECKING([for --noexecstack option to as])
     _SAVE_CFLAGS=$CFLAGS
     CFLAGS="$CFLAGS -Wa,--noexecstack"
     AC_TRY_COMPILE(,,AC_MSG_RESULT([yes])
@@ -1338,16 +1328,24 @@ if test "$GNU_CC"; then
     AC_MSG_CHECKING([for --build-id option to ld])
     _SAVE_LDFLAGS=$LDFLAGS
     LDFLAGS="$LDFLAGS -Wl,--build-id"
     AC_TRY_LINK(,,AC_MSG_RESULT([yes])
                   [NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,--build-id"],
                   AC_MSG_RESULT([no])
                   LDFLAGS=$_SAVE_LDFLAGS)
 
+    AC_MSG_CHECKING([for --ignore-unresolved-symbol option to ld])
+    HAVE_LINKER_SUPPORT_IGNORE_UNRESOLVED=
+    _SAVE_LDFLAGS=$LDFLAGS
+    LDFLAGS="$LDFLAGS -Wl,--ignore-unresolved-symbol,environ"
+    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
+                  [HAVE_LINKER_SUPPORT_IGNORE_UNRESOLVED=1],
+                  AC_MSG_RESULT([no]))
+    LDFLAGS=$_SAVE_LDFLAGS
 
     # Check for -mssse3 on $CC
     AC_MSG_CHECKING([if toolchain supports -mssse3 option])
     HAVE_TOOLCHAIN_SUPPORT_MSSSE3=
     _SAVE_CFLAGS=$CFLAGS
     CFLAGS="$CFLAGS -mssse3"
     AC_TRY_COMPILE([asm ("pmaddubsw %xmm2,%xmm3");],,AC_MSG_RESULT([yes])
                      [HAVE_TOOLCHAIN_SUPPORT_MSSSE3=1],
@@ -1373,16 +1371,38 @@ if test "$GNU_CC"; then
       AC_MSG_RESULT("$result")
       if test "$result" = "yes"; then
           HAVE_X86_AVX2=1
           AC_DEFINE(HAVE_X86_AVX2)
           AC_SUBST(HAVE_X86_AVX2)
       fi
     esac
 
+    DSO_LDOPTS='-shared'
+    if test "$GCC_USE_GNU_LD"; then
+        # Some tools like ASan use a runtime library that is only
+        # linked against executables, so we must allow undefined
+        # symbols for shared objects in some cases.
+        if test -z "$MOZ_NO_WLZDEFS"; then
+            # Don't allow undefined symbols in libraries
+            DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs"
+
+            # BSDs need `environ' exposed for posix_spawn (bug 753046)
+            case "$OS_TARGET" in
+            DragonFly|FreeBSD|NetBSD|OpenBSD)
+                if test -n "$HAVE_LINKER_SUPPORT_IGNORE_UNRESOLVED"; then
+                    DSO_LDOPTS="$DSO_LDOPTS -Wl,--ignore-unresolved-symbol,environ"
+                else
+                    DSO_LDOPTS="$DSO_LDOPTS -Wl,--warn-unresolved-symbols"
+                fi
+                ;;
+            esac
+        fi
+    fi
+
     # Turn on GNU-specific warnings:
     # -Wall - turn on a lot of warnings
     # -Wpointer-arith - good to have
     # -Wdeclaration-after-statement - MSVC doesn't like these
     # -Werror=return-type - catches missing returns, zero false positives
     # -Werror=int-to-pointer-cast - catches cast to pointer from integer of different size
     # -Wtype-limits - catches overflow bugs, few false positives
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
@@ -6266,16 +6286,24 @@ dnl ====================================
 dnl = Disable DOMCrypto
 dnl ========================================================
 if test -n "$MOZ_DISABLE_CRYPTOLEGACY"; then
     AC_DEFINE(MOZ_DISABLE_CRYPTOLEGACY)
 fi
 AC_SUBST(MOZ_DISABLE_CRYPTOLEGACY)
 
 dnl ========================================================
+dnl = Disable EV certificate verification
+dnl ========================================================
+if test -n "$MOZ_NO_EV_CERTS"; then
+    AC_DEFINE(MOZ_NO_EV_CERTS)
+fi
+AC_SUBST(MOZ_NO_EV_CERTS)
+
+dnl ========================================================
 dnl = Disable libpkix
 dnl ========================================================
 if test -n "$NSS_NO_LIBPKIX"; then
     AC_DEFINE(NSS_NO_LIBPKIX)
 fi
 AC_SUBST(NSS_NO_LIBPKIX)
 
 dnl ========================================================
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1638,30 +1638,41 @@ public:
   // mAnimationController isn't yet initialized.
   virtual nsSMILAnimationController* GetAnimationController() = 0;
 
   // Makes the images on this document capable of having their animation
   // active or suspended. An Image will animate as long as at least one of its
   // owning Documents needs it to animate; otherwise it can suspend.
   virtual void SetImagesNeedAnimating(bool aAnimating) = 0;
 
+  enum SuppressionType {
+    eAnimationsOnly = 0x1,
+
+    // Note that suppressing events also suppresses animation frames, so
+    // there's no need to split out events in its own bitmask.
+    eEvents = 0x3,
+  };
+
   /**
    * Prevents user initiated events from being dispatched to the document and
    * subdocuments.
    */
-  virtual void SuppressEventHandling(uint32_t aIncrease = 1) = 0;
+  virtual void SuppressEventHandling(SuppressionType aWhat,
+                                     uint32_t aIncrease = 1) = 0;
 
   /**
    * Unsuppress event handling.
    * @param aFireEvents If true, delayed events (focus/blur) will be fired
    *                    asynchronously.
    */
-  virtual void UnsuppressEventHandlingAndFireEvents(bool aFireEvents) = 0;
+  virtual void UnsuppressEventHandlingAndFireEvents(SuppressionType aWhat,
+                                                    bool aFireEvents) = 0;
 
   uint32_t EventHandlingSuppressed() const { return mEventsSuppressed; }
+  uint32_t AnimationsPaused() const { return mAnimationsPaused; }
 
   bool IsEventHandlingEnabled() {
     return !EventHandlingSuppressed() && mScriptGlobalObject;
   }
 
   /**
    * Increment the number of external scripts being evaluated.
    */
@@ -2482,16 +2493,18 @@ protected:
 
   // If we're an external resource document, this will be non-null and will
   // point to our "display document": the one that all resource lookups should
   // go to.
   nsCOMPtr<nsIDocument> mDisplayDocument;
 
   uint32_t mEventsSuppressed;
 
+  uint32_t mAnimationsPaused;
+
   /**
    * The number number of external scripts (ones with the src attribute) that
    * have this document as their owner and that are being evaluated right now.
    */
   uint32_t mExternalScriptsBeingEvaluated;
 
   /**
    * The current frame request callback handle
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -44,43 +44,43 @@
 #include "nsIPrincipal.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsEscape.h"
 #include "nsContentUtils.h"
 #include "nsIMIMEService.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
-#include "nsDOMDataTransfer.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "nsIMIMEInfo.h"
 #include "nsRange.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLAreaElement.h"
 
-using mozilla::dom::HTMLAreaElement;
+using namespace mozilla::dom;
 
 class MOZ_STACK_CLASS DragDataProducer
 {
 public:
   DragDataProducer(nsPIDOMWindow* aWindow,
                    nsIContent* aTarget,
                    nsIContent* aSelectionTargetNode,
                    bool aIsAltKeyPressed);
-  nsresult Produce(nsDOMDataTransfer* aDataTransfer,
+  nsresult Produce(DataTransfer* aDataTransfer,
                    bool* aCanDrag,
                    nsISelection** aSelection,
                    nsIContent** aDragNode);
 
 private:
-  void AddString(nsDOMDataTransfer* aDataTransfer,
+  void AddString(DataTransfer* aDataTransfer,
                  const nsAString& aFlavor,
                  const nsAString& aData,
                  nsIPrincipal* aPrincipal);
   nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
-                                    nsDOMDataTransfer* aDataTransfer);
+                                    DataTransfer* aDataTransfer);
   static nsresult GetDraggableSelectionData(nsISelection* inSelection,
                                             nsIContent* inRealTargetNode,
                                             nsIContent **outImageOrLinkNode,
                                             bool* outDragSelectedText);
   static already_AddRefed<nsIContent> FindParentLinkNode(nsIContent* inNode);
   static void GetAnchorURL(nsIContent* inNode, nsAString& outURL);
   static void GetNodeString(nsIContent* inNode, nsAString & outNodeString);
   static void CreateLinkText(const nsAString& inURL, const nsAString & inText,
@@ -107,17 +107,17 @@ private:
 };
 
 
 nsresult
 nsContentAreaDragDrop::GetDragData(nsPIDOMWindow* aWindow,
                                    nsIContent* aTarget,
                                    nsIContent* aSelectionTargetNode,
                                    bool aIsAltKeyPressed,
-                                   nsDOMDataTransfer* aDataTransfer,
+                                   DataTransfer* aDataTransfer,
                                    bool* aCanDrag,
                                    nsISelection** aSelection,
                                    nsIContent** aDragNode)
 {
   NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
 
   *aCanDrag = true;
 
@@ -349,17 +349,17 @@ DragDataProducer::GetNodeString(nsIConte
   nsRefPtr<nsRange> range = doc->CreateRange(rv);
   if (range) {
     range->SelectNode(*node, rv);
     range->ToString(outNodeString);
   }
 }
 
 nsresult
-DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
+DragDataProducer::Produce(DataTransfer* aDataTransfer,
                           bool* aCanDrag,
                           nsISelection** aSelection,
                           nsIContent** aDragNode)
 {
   NS_PRECONDITION(aCanDrag && aSelection && aDataTransfer && aDragNode,
                   "null pointer passed to Produce");
   NS_ASSERTION(mWindow, "window not set");
   NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
@@ -698,31 +698,31 @@ DragDataProducer::Produce(nsDOMDataTrans
          dragNode ? dragNode : mSelectionTargetNode.get(), aDataTransfer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_IF_ADDREF(*aDragNode = dragNode);
   return NS_OK;
 }
 
 void
-DragDataProducer::AddString(nsDOMDataTransfer* aDataTransfer,
+DragDataProducer::AddString(DataTransfer* aDataTransfer,
                             const nsAString& aFlavor,
                             const nsAString& aData,
                             nsIPrincipal* aPrincipal)
 {
   nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
   if (variant) {
     variant->SetAsAString(aData);
     aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal);
   }
 }
 
 nsresult
 DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode,
-                                           nsDOMDataTransfer* aDataTransfer)
+                                           DataTransfer* aDataTransfer)
 {
   NS_ASSERTION(aDragNode, "adding strings for null node");
 
   // set all of the data to have the principal of the node where the data came from
   nsIPrincipal* principal = aDragNode->NodePrincipal();
 
   // add a special flavor if we're an anchor to indicate that we have
   // a URL in the drag data
--- a/content/base/src/nsContentAreaDragDrop.h
+++ b/content/base/src/nsContentAreaDragDrop.h
@@ -16,17 +16,22 @@ class nsIDOMNode;
 class nsPIDOMWindow;
 class nsIDOMDragEvent;
 class nsISelection;
 class nsITransferable;
 class nsIContent;
 class nsIURI;
 class nsIFile;
 class nsISimpleEnumerator;
-class nsDOMDataTransfer;
+
+namespace mozilla {
+namespace dom {
+class DataTransfer;
+}
+}
 
 //
 // class nsContentAreaDragDrop, used to generate the dragdata
 //
 class nsContentAreaDragDrop
 {
 public:
 
@@ -47,17 +52,17 @@ public:
    *                    selection is being dragged.
    * aDragNode - [out] the link, image or area being dragged, or null if the
    *             drag occurred on another element.
    */
   static nsresult GetDragData(nsPIDOMWindow* aWindow,
                               nsIContent* aTarget,
                               nsIContent* aSelectionTargetNode,
                               bool aIsAltKeyPressed,
-                              nsDOMDataTransfer* aDataTransfer,
+                              mozilla::dom::DataTransfer* aDataTransfer,
                               bool* aCanDrag,
                               nsISelection** aSelection,
                               nsIContent** aDragNode);
 };
 
 // this is used to save images to disk lazily when the image data is asked for
 // during the drop instead of when it is added to the drag data transfer. This
 // ensures that the image data is only created when an image drop is allowed.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -62,17 +62,17 @@
 #include "nsCPrefetchService.h"
 #include "nsCRT.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDataHashtable.h"
 #include "nsDocShellCID.h"
 #include "nsDocument.h"
 #include "nsDOMCID.h"
-#include "nsDOMDataTransfer.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "nsDOMJSUtils.h"
 #include "nsDOMMutationObserver.h"
 #include "nsDOMTouchEvent.h"
 #include "nsError.h"
 #include "nsEventDispatcher.h"
 #include "nsEventListenerManager.h"
 #include "nsEventStateManager.h"
 #include "nsFocusManager.h"
@@ -4969,39 +4969,43 @@ nsContentUtils::SetDataTransferInEvent(W
   // drag events, get the object from the drag session.
   NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE &&
                aDragEvent->message != NS_DRAGDROP_START,
                "draggesture event created without a dataTransfer");
 
   nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
   NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
 
-  nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
-  dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
-  if (!initialDataTransfer) {
+  nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
+  nsCOMPtr<DataTransfer> initialDataTransfer;
+  dragSession->GetDataTransfer(getter_AddRefs(dataTransfer));
+  if (dataTransfer) {
+    initialDataTransfer = do_QueryInterface(dataTransfer);
+    if (!initialDataTransfer) {
+      return NS_ERROR_FAILURE;
+    }
+  } else {
     // A dataTransfer won't exist when a drag was started by some other
     // means, for instance calling the drag service directly, or a drag
     // from another application. In either case, a new dataTransfer should
     // be created that reflects the data.
-    initialDataTransfer = new nsDOMDataTransfer(aDragEvent->message, true, -1);
-
-    NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
+    initialDataTransfer = new DataTransfer(aDragEvent->target, aDragEvent->message, true, -1);
 
     // now set it in the drag session so we don't need to create it again
     dragSession->SetDataTransfer(initialDataTransfer);
   }
 
   bool isCrossDomainSubFrameDrop = false;
   if (aDragEvent->message == NS_DRAGDROP_DROP ||
       aDragEvent->message == NS_DRAGDROP_DRAGDROP) {
     isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent);
   }
 
   // each event should use a clone of the original dataTransfer.
-  initialDataTransfer->Clone(aDragEvent->message, aDragEvent->userCancelled,
+  initialDataTransfer->Clone(aDragEvent->target, aDragEvent->message, aDragEvent->userCancelled,
                              isCrossDomainSubFrameDrop,
                              getter_AddRefs(aDragEvent->dataTransfer));
   NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
 
   // for the dragenter and dragover events, initialize the drop effect
   // from the drop action, which platform specific widget code sets before
   // the event is fired based on the keyboard state.
   if (aDragEvent->message == NS_DRAGDROP_ENTER ||
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -15,17 +15,17 @@
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
 #include "nsRange.h"
 #include "imgIContainer.h"
 #include "nsIPresShell.h"
 #include "nsFocusManager.h"
 #include "nsEventDispatcher.h"
-#include "nsDOMDataTransfer.h"
+#include "mozilla/dom/DataTransfer.h"
 
 #include "nsIDocShell.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIClipboardDragDropHookList.h"
 #include "nsIClipboardHelper.h"
 #include "nsISelectionController.h"
 
@@ -48,16 +48,17 @@
 
 #include "mozilla/ContentEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Selection.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
 static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
 static NS_DEFINE_CID(kHTMLConverterCID,        NS_HTMLFORMATCONVERTER_CID);
 
 // copy string data onto the transferable
@@ -638,19 +639,20 @@ nsCopySupport::FireClipboardEvent(int32_
     return false;
 
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(piWindow);
   const bool chromeShell =
     docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome;
 
   // next, fire the cut, copy or paste event
   bool doDefault = true;
-  nsRefPtr<nsDOMDataTransfer> clipboardData;
+  nsRefPtr<DataTransfer> clipboardData;
   if (chromeShell || Preferences::GetBool("dom.event.clipboardevents.enabled", true)) {
-    clipboardData = new nsDOMDataTransfer(aType, aType == NS_PASTE, aClipboardType);
+    clipboardData =
+      new DataTransfer(piWindow, aType, aType == NS_PASTE, aClipboardType);
 
     nsEventStatus status = nsEventStatus_eIgnore;
     InternalClipboardEvent evt(true, aType);
     evt.clipboardData = clipboardData;
     nsEventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt, nullptr,
                                 &status);
     // If the event was cancelled, don't do the clipboard operation
     doDefault = (status != nsEventStatus_eConsumeNoDefault);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9140,32 +9140,51 @@ nsIDocument::GetReadyState(nsAString& aR
   case READYSTATE_COMPLETE :
     aReadyState.Assign(NS_LITERAL_STRING("complete"));
     break;
   default:
     aReadyState.Assign(NS_LITERAL_STRING("uninitialized"));
   }
 }
 
+namespace {
+
+struct SuppressArgs
+{
+  nsIDocument::SuppressionType mWhat;
+  uint32_t mIncrease;
+};
+
+}
+
 static bool
 SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
 {
-  aDocument->SuppressEventHandling(*static_cast<uint32_t*>(aData));
+  SuppressArgs* args = static_cast<SuppressArgs*>(aData);
+  aDocument->SuppressEventHandling(args->mWhat, args->mIncrease);
   return true;
 }
 
 void
-nsDocument::SuppressEventHandling(uint32_t aIncrease)
-{
-  if (mEventsSuppressed == 0 && aIncrease != 0 && mPresShell &&
-      mScriptGlobalObject) {
+nsDocument::SuppressEventHandling(nsIDocument::SuppressionType aWhat,
+                                  uint32_t aIncrease)
+{
+  if (mEventsSuppressed == 0 && mAnimationsPaused == 0 &&
+      aIncrease != 0 && mPresShell && mScriptGlobalObject) {
     RevokeAnimationFrameNotifications();
   }
-  mEventsSuppressed += aIncrease;
-  EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
+
+  if (aWhat == eAnimationsOnly) {
+    mAnimationsPaused += aIncrease;
+  } else {
+    mEventsSuppressed += aIncrease;
+  }
+
+  SuppressArgs args = { aWhat, aIncrease };
+  EnumerateSubDocuments(SuppressEventHandlingInDocument, &args);
 }
 
 static void
 FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
                          bool aFireEvents)
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm)
@@ -9309,40 +9328,69 @@ public:
     FireOrClearDelayedEvents(mDocuments, true);
     return NS_OK;
   }
 
 private:
   nsTArray<nsCOMPtr<nsIDocument> > mDocuments;
 };
 
+namespace {
+
+struct UnsuppressArgs
+{
+  UnsuppressArgs(nsIDocument::SuppressionType aWhat)
+    : mWhat(aWhat)
+  {
+  }
+
+  nsIDocument::SuppressionType mWhat;
+  nsTArray<nsCOMPtr<nsIDocument>> mDocs;
+};
+
+}
+
 static bool
-GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
-{
-  uint32_t suppression = aDocument->EventHandlingSuppressed();
-  if (suppression > 0) {
+GetAndUnsuppressSubDocuments(nsIDocument* aDocument,
+                             void* aData)
+{
+  UnsuppressArgs* args = static_cast<UnsuppressArgs*>(aData);
+  if (args->mWhat != nsIDocument::eAnimationsOnly &&
+      aDocument->EventHandlingSuppressed() > 0) {
     static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
-  }
-  nsTArray<nsCOMPtr<nsIDocument> >* docs =
-    static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
-  docs->AppendElement(aDocument);
-  aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, docs);
+  } else if (args->mWhat == nsIDocument::eAnimationsOnly &&
+             aDocument->AnimationsPaused()) {
+    static_cast<nsDocument*>(aDocument)->ResumeAnimations();
+  }
+
+  if (args->mWhat != nsIDocument::eAnimationsOnly) {
+    // No need to remember documents if we only care about animation frames.
+    args->mDocs.AppendElement(aDocument);
+  }
+
+  aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, aData);
   return true;
 }
 
 void
-nsDocument::UnsuppressEventHandlingAndFireEvents(bool aFireEvents)
-{
-  nsTArray<nsCOMPtr<nsIDocument> > documents;
-  GetAndUnsuppressSubDocuments(this, &documents);
+nsDocument::UnsuppressEventHandlingAndFireEvents(nsIDocument::SuppressionType aWhat,
+                                                 bool aFireEvents)
+{
+  UnsuppressArgs args(aWhat);
+  GetAndUnsuppressSubDocuments(this, &args);
+
+  if (aWhat == nsIDocument::eAnimationsOnly) {
+    // No need to fire events if we only care about animations here.
+    return;
+  }
 
   if (aFireEvents) {
-    NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(documents));
+    NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(args.mDocs));
   } else {
-    FireOrClearDelayedEvents(documents, false);
+    FireOrClearDelayedEvents(args.mDocs, false);
   }
 }
 
 nsISupports*
 nsDocument::GetCurrentContentSink()
 {
   return mParser ? mParser->GetContentSink() : nullptr;
 }
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -975,25 +975,34 @@ public:
   nsTArray<nsCString> mHostObjectURIs;
 
   // Returns our (lazily-initialized) animation controller.
   // If HasAnimationController is true, this is guaranteed to return non-null.
   nsSMILAnimationController* GetAnimationController() MOZ_OVERRIDE;
 
   void SetImagesNeedAnimating(bool aAnimating) MOZ_OVERRIDE;
 
-  virtual void SuppressEventHandling(uint32_t aIncrease) MOZ_OVERRIDE;
+  virtual void SuppressEventHandling(SuppressionType aWhat,
+                                     uint32_t aIncrease) MOZ_OVERRIDE;
+
+  virtual void UnsuppressEventHandlingAndFireEvents(SuppressionType aWhat,
+                                                    bool aFireEvents) MOZ_OVERRIDE;
 
-  virtual void UnsuppressEventHandlingAndFireEvents(bool aFireEvents) MOZ_OVERRIDE;
-  
   void DecreaseEventSuppression() {
+    MOZ_ASSERT(mEventsSuppressed);
     --mEventsSuppressed;
     MaybeRescheduleAnimationFrameNotifications();
   }
 
+  void ResumeAnimations() {
+    MOZ_ASSERT(mAnimationsPaused);
+    --mAnimationsPaused;
+    MaybeRescheduleAnimationFrameNotifications();
+  }
+
   virtual nsIDocument* GetTemplateContentsOwner() MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
                                                                    nsIDocument)
 
   void DoNotifyPossibleTitleChange();
 
   nsExternalResourceMap& ExternalResourceMap()
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1816,16 +1816,17 @@ GK_ATOM(columnSetFrame, "ColumnSetFrame"
 GK_ATOM(comboboxControlFrame, "ComboboxControlFrame")
 GK_ATOM(comboboxDisplayFrame, "ComboboxDisplayFrame")
 GK_ATOM(deckFrame, "DeckFrame")
 GK_ATOM(fieldSetFrame, "FieldSetFrame")
 GK_ATOM(flexContainerFrame, "FlexContainerFrame")
 GK_ATOM(formControlFrame, "FormControlFrame") // radio or checkbox
 GK_ATOM(frameSetFrame, "FrameSetFrame")
 GK_ATOM(gfxButtonControlFrame, "gfxButtonControlFrame")
+GK_ATOM(gridContainerFrame, "GridContainerFrame")
 GK_ATOM(HTMLButtonControlFrame, "HTMLButtonControlFrame")
 GK_ATOM(HTMLCanvasFrame, "HTMLCanvasFrame")
 GK_ATOM(subDocumentFrame, "subDocumentFrame")
 GK_ATOM(imageBoxFrame, "ImageBoxFrame")
 GK_ATOM(imageFrame, "ImageFrame")
 GK_ATOM(imageControlFrame, "ImageControlFrame")
 GK_ATOM(inlineFrame, "InlineFrame")
 GK_ATOM(leafBoxFrame, "LeafBoxFrame")
--- a/content/base/src/nsTextFragment.h
+++ b/content/base/src/nsTextFragment.h
@@ -11,17 +11,17 @@
 #ifndef nsTextFragment_h___
 #define nsTextFragment_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "nsString.h"
 #include "nsReadableUtils.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 class nsString;
 class nsCString;
 
 // XXX should this normalize the code to keep a \u0000 at the end?
 
 // XXX nsTextFragmentPool?
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2867,17 +2867,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
     if (GetOwner()) {
       nsCOMPtr<nsIDOMWindow> topWindow;
       if (NS_SUCCEEDED(GetOwner()->GetTop(getter_AddRefs(topWindow)))) {
         nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
         if (suspendedWindow &&
             (suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
           suspendedDoc = suspendedWindow->GetExtantDoc();
           if (suspendedDoc) {
-            suspendedDoc->SuppressEventHandling();
+            suspendedDoc->SuppressEventHandling(nsIDocument::eEvents);
           }
           suspendedWindow->SuspendTimeouts(1, false);
           resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
         }
       }
     }
 
     ChangeState(XML_HTTP_REQUEST_SENT);
@@ -2891,17 +2891,18 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
         if (!NS_ProcessNextEvent(thread)) {
           rv = NS_ERROR_UNEXPECTED;
           break;
         }
       }
     }
 
     if (suspendedDoc) {
-      suspendedDoc->UnsuppressEventHandlingAndFireEvents(true);
+      suspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
+                                                         true);
     }
 
     if (resumeTimeoutRunnable) {
       NS_DispatchToCurrentThread(resumeTimeoutRunnable);
     }
   } else {
     // Now that we've successfully opened the channel, we can change state.  Note
     // that this needs to come after the AsyncOpen() and rv check, because this
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -10,17 +10,17 @@
 #include "nsIDOMCanvasRenderingContext2D.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TypedArray.h"
 #include <stdint.h>
 
 #include "nsCycleCollectionParticipant.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "js/GCAPI.h"
 
 namespace mozilla {
 namespace dom {
 
 class ImageData MOZ_FINAL : public nsISupports
 {
 public:
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3337,16 +3337,22 @@ WebGLContext::CompressedTexImage2D(GLenu
         return;
     }
 
     uint32_t byteLength = view.Length();
     if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
         return;
     }
 
+    if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0,
+                                  width, height, width, height, func))
+    {
+        return;
+    }
+
     MakeContextCurrent();
     gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     MOZ_ASSERT(tex);
     tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
                       WebGLImageDataStatus::InitializedImageData);
 
     ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
@@ -3371,29 +3377,29 @@ WebGLContext::CompressedTexSubImage2D(GL
     {
         return;
     }
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     MOZ_ASSERT(tex);
     WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
 
+    uint32_t byteLength = view.Length();
+    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
+        return;
+
     if (!ValidateCompTexImageSize(target, level, format,
                                   xoffset, yoffset,
                                   width, height,
                                   levelInfo.Width(), levelInfo.Height(),
                                   func))
     {
         return;
     }
 
-    uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
-        return;
-
     if (levelInfo.HasUninitializedImageData())
         tex->DoDeferredImageInitialization(target, level);
 
     MakeContextCurrent();
     gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
 }
 
 JS::Value
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -771,36 +771,64 @@ WebGLContext::ValidateCompTexImageSize(G
         if (yoffset % blockHeight != 0) {
             ErrorInvalidOperation("%s: yoffset must be multiple of %d",
                                   InfoFrom(func), blockHeight);
             return false;
         }
 
         /* The size must be a multiple of blockWidth and blockHeight,
          * or must be using offset+size that exactly hits the edge.
-         * Important for small mipmap levels. (s3tc extension appears
-         * to have changed and old code that checks 1x1, 2x2 doesn't
-         * appear necessary anymore)
+         * Important for small mipmap levels.
+         */
+        /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+         * "When level equals zero width and height must be a multiple of 4. When
+         *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
+         *  If they are not an INVALID_OPERATION error is generated."
          */
-        if ((width % blockWidth != 0) &&
-            (xoffset + width != (GLint) levelWidth))
-        {
-            ErrorInvalidOperation("%s: width must be multiple of %d or "
-                                  "xoffset + width must be %d",
-                                  InfoFrom(func), blockWidth, levelWidth);
-            return false;
+        if (level == 0) {
+            if (width % blockWidth != 0) {
+                ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
+                                      InfoFrom(func), blockWidth);
+                return false;
+            }
+
+            if (height % blockHeight != 0) {
+                ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
+                                      InfoFrom(func), blockHeight);
+                return false;
+            }
+        }
+        else if (level > 0) {
+            if (width % blockWidth != 0 && width > 2) {
+                ErrorInvalidOperation("%s: width of level %d must be multiple"
+                                      " of %d or 0, 1, 2",
+                                      InfoFrom(func), level, blockWidth);
+                return false;
+            }
+
+            if (height % blockHeight != 0 && height > 2) {
+                ErrorInvalidOperation("%s: height of level %d must be multiple"
+                                      " of %d or 0, 1, 2",
+                                      InfoFrom(func), level, blockHeight);
+                return false;
+            }
         }
 
-        if ((height % blockHeight != 0) &&
-            (yoffset + height != (GLint) levelHeight))
-        {
-            ErrorInvalidOperation("%s: height must be multiple of %d or "
-                                  "yoffset + height must be %d",
-                                  InfoFrom(func), blockHeight, levelHeight);
-            return false;
+        if (IsSubFunc(func)) {
+            if ((xoffset % blockWidth) != 0) {
+                ErrorInvalidOperation("%s: xoffset must be multiple of %d",
+                                      InfoFrom(func), blockWidth);
+                return false;
+            }
+
+            if (yoffset % blockHeight != 0) {
+                ErrorInvalidOperation("%s: yoffset must be multiple of %d",
+                                      InfoFrom(func), blockHeight);
+                return false;
+            }
         }
     }
 
     switch (format) {
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
@@ -1148,20 +1176,36 @@ WebGLContext::ValidateTexImageFormatAndT
         validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
                       type == LOCAL_GL_UNSIGNED_INT);
         break;
 
     case LOCAL_GL_DEPTH_STENCIL:
         validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
         break;
 
+    case LOCAL_GL_ATC_RGB:
+    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
+    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
+        break;
+
     default:
         // Only valid formats should be passed to the switch stmt.
-        MOZ_ASSERT("Invalid format");
-        return false;
+        MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
+        validCombo = false;
+        // Fall through to return an InvalidOperations. This will alert us to the
+        // unexpected case that needs fixing in builds without asserts.
     }
 
     if (!validCombo)
         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
                               InfoFrom(func), NameFrom(format), NameFrom(type));
 
     return validCombo;
 }
--- a/content/media/AudioNodeStream.cpp
+++ b/content/media/AudioNodeStream.cpp
@@ -510,32 +510,42 @@ AudioNodeStream::FinishOutput()
     AudioSegment emptySegment;
     l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
                                 mSampleRate,
                                 track->GetSegment()->GetDuration(),
                                 MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);
   }
 }
 
-TrackTicks
-AudioNodeStream::TicksFromDestinationTime(MediaStream* aDestination,
-                                          double aSeconds)
+double
+AudioNodeStream::TimeFromDestinationTime(AudioNodeStream* aDestination,
+                                         double aSeconds)
 {
-  MOZ_ASSERT(aDestination->AsAudioNodeStream() &&
-             aDestination->AsAudioNodeStream()->SampleRate() == SampleRate());
+  MOZ_ASSERT(aDestination->SampleRate() == SampleRate());
 
   double destinationSeconds = std::max(0.0, aSeconds);
   StreamTime streamTime = SecondsToMediaTime(destinationSeconds);
   // MediaTime does not have the resolution of double
   double offset = destinationSeconds - MediaTimeToSeconds(streamTime);
 
   GraphTime graphTime = aDestination->StreamTimeToGraphTime(streamTime);
   StreamTime thisStreamTime = GraphTimeToStreamTimeOptimistic(graphTime);
   double thisSeconds = MediaTimeToSeconds(thisStreamTime) + offset;
   MOZ_ASSERT(thisSeconds >= 0.0);
+  return thisSeconds;
+}
+
+TrackTicks
+AudioNodeStream::TicksFromDestinationTime(MediaStream* aDestination,
+                                          double aSeconds)
+{
+  AudioNodeStream* destination = aDestination->AsAudioNodeStream();
+  MOZ_ASSERT(destination);
+
+  double thisSeconds = TimeFromDestinationTime(destination, aSeconds);
   // Round to nearest
   TrackTicks ticks = thisSeconds * SampleRate() + 0.5;
   return ticks;
 }
 
 double
 AudioNodeStream::DestinationTimeFromTicks(AudioNodeStream* aDestination,
                                           TrackTicks aPosition)
--- a/content/media/AudioNodeStream.h
+++ b/content/media/AudioNodeStream.h
@@ -124,16 +124,22 @@ public:
     return true;
   }
 
   // Any thread
   AudioNodeEngine* Engine() { return mEngine; }
   TrackRate SampleRate() const { return mSampleRate; }
 
   /**
+   * Convert a time in seconds on the destination stream to seconds
+   * on this stream.
+   */
+  double TimeFromDestinationTime(AudioNodeStream* aDestination,
+                                 double aSeconds);
+  /**
    * Convert a time in seconds on the destination stream to TrackTicks
    * on this stream.
    */
   TrackTicks TicksFromDestinationTime(MediaStream* aDestination,
                                       double aSeconds);
   /**
    * Get the destination stream time in seconds corresponding to a position on
    * this stream.
--- a/content/media/mediasource/SourceBufferResource.cpp
+++ b/content/media/mediasource/SourceBufferResource.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceBufferResource.h"
 
 #include <string.h>
 #include <algorithm>
 
 #include "nsISeekableStream.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "prenv.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaSourceLog;
 #define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
 #else
 #define LOG(type, msg)
--- a/content/media/mediasource/test/mochitest.ini
+++ b/content/media/mediasource/test/mochitest.ini
@@ -1,4 +1,4 @@
 [DEFAULT]
-support-files = seek.webm
+support-files = seek.webm seek.webm^headers^
 
 [test_MediaSource.html]
new file mode 100644
--- /dev/null
+++ b/content/media/mediasource/test/seek.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/ogg/OggCodecState.cpp
+++ b/content/media/ogg/OggCodecState.cpp
@@ -9,17 +9,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Endian.h"
 #include <stdint.h>
 
 #include "nsDebug.h"
 #include "MediaDecoderReader.h"
 #include "OggCodecState.h"
 #include "OggDecoder.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "VideoUtils.h"
 #include <algorithm>
 
 // On Android JellyBean, the hardware.h header redefines version_major and
 // version_minor, which breaks our build.  See:
 // https://bugzilla.mozilla.org/show_bug.cgi?id=912702#c6
 #ifdef MOZ_WIDGET_GONK
 #ifdef version_major
new file mode 100644
--- /dev/null
+++ b/content/media/test/320x240.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/448636.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/VID_0001.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/audio-gaps.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/audio-overhang.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/audio.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/badtags.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/beta-phrasebook.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/big-buck-bunny-unseekable.mp4^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/big.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bogus.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bogus.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug461281.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug482461-theora.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug482461.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug495129.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug495794.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug498380.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug498855-1.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug498855-2.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug498855-3.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug499519.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/test/bug500311.ogv^headers^
+++ b/content/media/test/bug500311.ogv^headers^
@@ -1,2 +1,2 @@
 X-Content-Duration: 1.96
-
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug501279.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug504613.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug504644.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug504843.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug506094.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug516323.indexed.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug516323.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug520493.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug520500.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/test/bug520908.ogv^headers^
+++ b/content/media/test/bug520908.ogv^headers^
@@ -1,2 +1,2 @@
 X-Content-Duration: 9000
-
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug523816.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug533822.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug556821.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug557094.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug580982.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug603918.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/bug604067.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/chain.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/chain.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/chain.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/chained-audio-video.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/chained-video.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/detodos.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/detodos.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/dirac.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/file_a4_tone.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/gizmo.mp4^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/huge-id3.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/id3tags.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-cmap-s0c0.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-cmap-s0c2.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-cmap-s1c2.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-cmap-short.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-m0c0.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-m0c3.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-m1c0.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-m1c9.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-m2c0.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-m2c1.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-preskip.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/make-headers.sh
@@ -0,0 +1,22 @@
+# 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/.
+
+# Script to generate ^header^ files for all media files we use.
+# This is to ensure that our media files are not cached by necko,
+# so that our detection as to whether the server supports byte range
+# requests is not interferred with by Necko's cache. See bug 977398
+# for details. Necko will fix this in bug 977314. 
+
+FILES=(`ls *.ogg *.ogv *.webm *.mp3 *.opus *.mp4 *.wav`)
+
+rm *.ogg^headers^ *.ogv^headers^ *.webm^headers^ *.mp3^headers^ *.opus^headers^ *.mp4^headers^ *.wav^headers^
+
+# Restore special headers.
+echo "X-Content-Duration: 1.96" > bug500311.ogv^headers^
+echo "X-Content-Duration: 9000" > bug520908.ogv^headers^
+
+for i in "${FILES[@]}"
+do
+  echo "Cache-Control: no-store" >> $i^headers^
+done
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -19,174 +19,283 @@
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
 support-files =
   320x240.ogv
+  320x240.ogv^headers^
   448636.ogv
+  448636.ogv^headers^
+  VID_0001.ogg
+  VID_0001.ogg^headers^
   allowed.sjs
   audio-gaps.ogg
+  audio-gaps.ogg^headers^
   audio-overhang.ogg
+  audio-overhang.ogg^headers^
   audio.wav
+  audio.wav^headers^
   badtags.ogg
+  badtags.ogg^headers^
   basic.vtt
   beta-phrasebook.ogg
+  beta-phrasebook.ogg^headers^
   big-buck-bunny-unseekable.mp4
+  big-buck-bunny-unseekable.mp4^headers^
   big.wav
+  big.wav^headers^
   bogus.duh
   bogus.ogv
+  bogus.ogv^headers^
   bogus.wav
+  bogus.wav^headers^
   bug461281.ogg
+  bug461281.ogg^headers^
   bug482461-theora.ogv
+  bug482461-theora.ogv^headers^
   bug482461.ogv
+  bug482461.ogv^headers^
   bug495129.ogv
+  bug495129.ogv^headers^
   bug495794.ogg
+  bug495794.ogg^headers^
   bug498380.ogv
+  bug498380.ogv^headers^
   bug498855-1.ogv
+  bug498855-1.ogv^headers^
   bug498855-2.ogv
+  bug498855-2.ogv^headers^
   bug498855-3.ogv
+  bug498855-3.ogv^headers^
   bug499519.ogv
+  bug499519.ogv^headers^
   bug500311.ogv
   bug500311.ogv^headers^
   bug501279.ogg
+  bug501279.ogg^headers^
   bug504613.ogv
+  bug504613.ogv^headers^
   bug504644.ogv
+  bug504644.ogv^headers^
   bug504843.ogv
+  bug504843.ogv^headers^
   bug506094.ogv
+  bug506094.ogv^headers^
   bug516323.indexed.ogv
+  bug516323.indexed.ogv^headers^
   bug516323.ogv
+  bug516323.ogv^headers^
   bug520493.ogg
+  bug520493.ogg^headers^
   bug520500.ogg
+  bug520500.ogg^headers^
   bug520908.ogv
   bug520908.ogv^headers^
   bug523816.ogv
+  bug523816.ogv^headers^
   bug533822.ogg
+  bug533822.ogg^headers^
   bug556821.ogv
+  bug556821.ogv^headers^
   bug557094.ogv
+  bug557094.ogv^headers^
   bug580982.webm
+  bug580982.webm^headers^
   bug603918.webm
+  bug603918.webm^headers^
   bug604067.webm
+  bug604067.webm^headers^
   bug883173.vtt
   can_play_type_dash.js
   can_play_type_mpeg.js
   can_play_type_ogg.js
   can_play_type_wave.js
   can_play_type_webm.js
   cancellable_request.sjs
   chain.ogg
+  chain.ogg^headers^
   chain.ogv
+  chain.ogv^headers^
   chain.opus
+  chain.opus^headers^
   chained-audio-video.ogg
+  chained-audio-video.ogg^headers^
   chained-video.ogv
+  chained-video.ogv^headers^
   contentDuration1.sjs
   contentDuration2.sjs
   contentDuration3.sjs
   contentDuration4.sjs
   contentDuration5.sjs
   contentDuration6.sjs
   contentDuration7.sjs
   contentType.sjs
   detodos.opus
+  detodos.opus^headers^
   detodos.webm
+  detodos.webm^headers^
   dirac.ogg
+  dirac.ogg^headers^
   dynamic_redirect.sjs
   dynamic_resource.sjs
   file_a4_tone.ogg
+  file_a4_tone.ogg^headers^
   file_access_controls.html
   file_audio_event_adopt_iframe.html
   fragment_noplay.js
   fragment_play.js
   gizmo.mp4
+  gizmo.mp4^headers^
   huge-id3.mp3
+  huge-id3.mp3^headers^
   id3tags.mp3
+  id3tags.mp3^headers^
   invalid-cmap-s0c0.opus
+  invalid-cmap-s0c0.opus^headers^
   invalid-cmap-s0c2.opus
+  invalid-cmap-s0c2.opus^headers^
   invalid-cmap-s1c2.opus
+  invalid-cmap-s1c2.opus^headers^
   invalid-cmap-short.opus
+  invalid-cmap-short.opus^headers^
   invalid-m0c0.opus
+  invalid-m0c0.opus^headers^
   invalid-m0c3.opus
+  invalid-m0c3.opus^headers^
   invalid-m1c0.opus
+  invalid-m1c0.opus^headers^
   invalid-m1c9.opus
+  invalid-m1c9.opus^headers^
   invalid-m2c0.opus
+  invalid-m2c0.opus^headers^
   invalid-m2c1.opus
+  invalid-m2c1.opus^headers^
   invalid-preskip.webm
+  invalid-preskip.webm^headers^
   long.vtt
   manifest.js
   multiple-bos.ogg
+  multiple-bos.ogg^headers^
   no-cues.webm
+  no-cues.webm^headers^
   noContentLength.sjs
   notags.mp3
+  notags.mp3^headers^
   owl-funnier-id3.mp3
+  owl-funnier-id3.mp3^headers^
   owl-funny-id3.mp3
+  owl-funny-id3.mp3^headers^
   owl.mp3
+  owl.mp3^headers^
   r11025_msadpcm_c1.wav
+  r11025_msadpcm_c1.wav^headers^
   r11025_s16_c1.wav
+  r11025_s16_c1.wav^headers^
   r11025_s16_c1_trailing.wav
+  r11025_s16_c1_trailing.wav^headers^
   r11025_u8_c1.wav
+  r11025_u8_c1.wav^headers^
   r11025_u8_c1_trunc.wav
+  r11025_u8_c1_trunc.wav^headers^
   r16000_u8_c1_list.wav
+  r16000_u8_c1_list.wav^headers^
   reactivate_helper.html
   redirect.sjs
   referer.sjs
   region.vtt
   seek.ogv
+  seek.ogv^headers^
   seek.webm
-  vp9.webm
-  vp9cake.webm
+  seek.webm^headers^
   seek.yuv
   seek1.js
   seek10.js
   seek11.js
   seek12.js
   seek13.js
   seek2.js
   seek3.js
   seek4.js
   seek5.js
   seek6.js
   seek7.js
   seek8.js
   seek9.js
   seekLies.sjs
+  seek_with_sound.ogg^headers^
   short-video.ogv
+  short-video.ogv^headers^
   small-shot.m4a
   small-shot.mp3
+  small-shot.mp3^headers^
   small-shot.ogg
+  small-shot.ogg^headers^
   sound.ogg
+  sound.ogg^headers^
   spacestorm-1000Hz-100ms.ogg
+  spacestorm-1000Hz-100ms.ogg^headers^
   split.webm
+  split.webm^headers^
   street.mp4
+  street.mp4^headers^
   test-1-mono.opus
+  test-1-mono.opus^headers^
   test-2-stereo.opus
+  test-2-stereo.opus^headers^
   test-3-LCR.opus
+  test-3-LCR.opus^headers^
   test-4-quad.opus
+  test-4-quad.opus^headers^
   test-5-5.0.opus
+  test-5-5.0.opus^headers^
   test-6-5.1.opus
+  test-6-5.1.opus^headers^
   test-7-6.1.opus
+  test-7-6.1.opus^headers^
   test-8-7.1.opus
+  test-8-7.1.opus^headers^
   variable-channel.ogg
+  variable-channel.ogg^headers^
   variable-channel.opus
+  variable-channel.opus^headers^
   variable-preskip.opus
+  variable-preskip.opus^headers^
   variable-samplerate.ogg
+  variable-samplerate.ogg^headers^
   variable-samplerate.opus
+  variable-samplerate.opus^headers^
   vbr-head.mp3
+  vbr-head.mp3^headers^
   vbr.mp3
-  VID_0001.ogg
+  vbr.mp3^headers^
   video-overhang.ogg
+  video-overhang.ogg^headers^
+  vp9.webm
+  vp9.webm^headers^
+  vp9cake.webm
+  vp9cake.webm^headers^
   wave_metadata.wav
+  wave_metadata.wav^headers^
   wave_metadata_bad_len.wav
+  wave_metadata_bad_len.wav^headers^
   wave_metadata_bad_no_null.wav
+  wave_metadata_bad_no_null.wav^headers^
   wave_metadata_bad_utf8.wav
+  wave_metadata_bad_utf8.wav^headers^
   wave_metadata_unknown_tag.wav
+  wave_metadata_unknown_tag.wav^headers^
   wave_metadata_utf8.wav
+  wave_metadata_utf8.wav^headers^
   wavedata_s16.wav
+  wavedata_s16.wav^headers^
   wavedata_u8.wav
+  wavedata_u8.wav^headers^
 
 [test_a4_tone.html]
 [test_access_control.html]
 [test_audio1.html]
 [test_audio2.html]
 [test_audio_event_adopt.html]
 [test_autoplay.html]
 [test_bug448534.html]
new file mode 100644
--- /dev/null
+++ b/content/media/test/multiple-bos.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/no-cues.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/notags.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/owl-funnier-id3.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/owl-funny-id3.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/owl.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/r11025_msadpcm_c1.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/r11025_s16_c1.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/r11025_s16_c1_trailing.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/r11025_u8_c1.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/r11025_u8_c1_trunc.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/r16000_u8_c1_list.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/seek.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/seek.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/seek_with_sound.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/short-video.ogv^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/small-shot.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/small-shot.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/sound.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/spacestorm-1000Hz-100ms.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/split.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/street.mp4^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-1-mono.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-2-stereo.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-3-LCR.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-4-quad.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-5-5.0.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-6-5.1.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-7-6.1.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/test-8-7.1.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/variable-channel.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/variable-channel.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/variable-preskip.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/variable-samplerate.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/variable-samplerate.opus^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/vbr-head.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/vbr.mp3^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/video-overhang.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/vp9.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/vp9cake.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wave_metadata.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wave_metadata_bad_len.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wave_metadata_bad_no_null.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wave_metadata_bad_utf8.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wave_metadata_unknown_tag.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wave_metadata_utf8.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wavedata_s16.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/content/media/test/wavedata_u8.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -51,21 +51,22 @@ NS_IMPL_RELEASE_INHERITED(AudioBufferSou
  * AudioNodeStream::SetInt32Parameter).
  */
 class AudioBufferSourceNodeEngine : public AudioNodeEngine
 {
 public:
   explicit AudioBufferSourceNodeEngine(AudioNode* aNode,
                                        AudioDestinationNode* aDestination) :
     AudioNodeEngine(aNode),
-    mStart(0), mStop(TRACK_TICKS_MAX),
+    mStart(0.0), mBeginProcessing(0),
+    mStop(TRACK_TICKS_MAX),
     mResampler(nullptr), mRemainingResamplerTail(0),
     mBufferEnd(0),
     mLoopStart(0), mLoopEnd(0),
-    mBufferSampleRate(0), mBufferPosition(0), mChannels(0), mPlaybackRate(1.0f),
+    mBufferSampleRate(0), mBufferPosition(0), mChannels(0),
     mDopplerShift(1.0f),
     mDestination(static_cast<AudioNodeStream*>(aDestination->Stream())),
     mPlaybackRateTimeline(1.0f), mLoop(false)
   {}
 
   ~AudioBufferSourceNodeEngine()
   {
     if (mResampler) {
@@ -89,30 +90,36 @@ public:
       break;
     default:
       NS_ERROR("Bad AudioBufferSourceNodeEngine TimelineParameter");
     }
   }
   virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
   {
     switch (aIndex) {
-    case AudioBufferSourceNode::START: mStart = aParam; break;
     case AudioBufferSourceNode::STOP: mStop = aParam; break;
     default:
       NS_ERROR("Bad AudioBufferSourceNodeEngine StreamTimeParameter");
     }
   }
   virtual void SetDoubleParameter(uint32_t aIndex, double aParam)
   {
     switch (aIndex) {
-      case AudioBufferSourceNode::DOPPLERSHIFT:
-        mDopplerShift = aParam;
-        break;
-      default:
-        NS_ERROR("Bad AudioBufferSourceNodeEngine double parameter.");
+    case AudioBufferSourceNode::START:
+      MOZ_ASSERT(!mStart, "Another START?");
+      mStart = mSource->TimeFromDestinationTime(mDestination, aParam) *
+        mSource->SampleRate();
+      // Round to nearest
+      mBeginProcessing = mStart + 0.5;
+      break;
+    case AudioBufferSourceNode::DOPPLERSHIFT:
+      mDopplerShift = aParam > 0 && aParam == aParam ? aParam : 1.0;
+      break;
+    default:
+      NS_ERROR("Bad AudioBufferSourceNodeEngine double parameter.");
     };
   }
   virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
   {
     switch (aIndex) {
     case AudioBufferSourceNode::SAMPLE_RATE: mBufferSampleRate = aParam; break;
     case AudioBufferSourceNode::BUFFERSTART:
       if (mBufferPosition == 0) {
@@ -127,32 +134,70 @@ public:
       NS_ERROR("Bad AudioBufferSourceNodeEngine Int32Parameter");
     }
   }
   virtual void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
   {
     mBuffer = aBuffer;
   }
 
-  SpeexResamplerState* Resampler(AudioNodeStream* aStream, uint32_t aChannels)
+  bool BegunResampling()
+  {
+    return mBeginProcessing == -TRACK_TICKS_MAX;
+  }
+
+  void UpdateResampler(int32_t aOutRate, uint32_t aChannels)
   {
-    if (aChannels != mChannels && mResampler) {
+    if (mResampler &&
+        (aChannels != mChannels ||
+         // If the resampler has begun, then it will have moved
+         // mBufferPosition to after the samples it has read, but it hasn't
+         // output its buffered samples.  Keep using the resampler, even if
+         // the rates now match, so that this latent segment is output.
+         (aOutRate == mBufferSampleRate && !BegunResampling()))) {
       speex_resampler_destroy(mResampler);
       mResampler = nullptr;
+      mBeginProcessing = mStart + 0.5;
+    }
+
+    if (aOutRate == mBufferSampleRate && !mResampler) {
+      return;
     }
 
     if (!mResampler) {
       mChannels = aChannels;
-      mResampler = speex_resampler_init(mChannels, mBufferSampleRate,
-                                        ComputeFinalOutSampleRate(aStream->SampleRate()),
+      mResampler = speex_resampler_init(mChannels, mBufferSampleRate, aOutRate,
                                         SPEEX_RESAMPLER_QUALITY_DEFAULT,
                                         nullptr);
-      speex_resampler_skip_zeros(mResampler);
+    } else {
+      uint32_t currentOutSampleRate, currentInSampleRate;
+      speex_resampler_get_rate(mResampler, &currentInSampleRate,
+                               &currentOutSampleRate);
+      if (currentOutSampleRate == static_cast<uint32_t>(aOutRate)) {
+        return;
+      }
+      speex_resampler_set_rate(mResampler, currentInSampleRate, aOutRate);
     }
-    return mResampler;
+
+    if (!BegunResampling()) {
+      // Low pass filter effects from the resampler mean that samples before
+      // the start time are influenced by resampling the buffer.  The input
+      // latency indicates half the filter width.
+      int64_t inputLatency = speex_resampler_get_input_latency(mResampler);
+      uint32_t ratioNum, ratioDen;
+      speex_resampler_get_ratio(mResampler, &ratioNum, &ratioDen);
+      // The output subsample resolution supported in aligning the resampler
+      // is ratioNum.  First round the start time to the nearest subsample.
+      int64_t subsample = mStart * ratioNum + 0.5;
+      // Now include the leading effects of the filter, and round *up* to the
+      // next whole tick, because there is no effect on samples outside the
+      // filter width.
+      mBeginProcessing =
+        (subsample - inputLatency * ratioDen + ratioNum - 1) / ratioNum;
+    }
   }
 
   // Borrow a full buffer of size WEBAUDIO_BLOCK_SIZE from the source buffer
   // at offset aSourceOffset.  This avoids copying memory.
   void BorrowFromInputBuffer(AudioChunk* aOutput,
                              uint32_t aChannels)
   {
     aOutput->mDuration = WEBAUDIO_BLOCK_SIZE;
@@ -182,84 +227,101 @@ public:
   // Resamples input data to an output buffer, according to |mBufferSampleRate| and
   // the playbackRate.
   // The number of frames consumed/produced depends on the amount of space
   // remaining in both the input and output buffer, and the playback rate (that
   // is, the ratio between the output samplerate and the input samplerate).
   void CopyFromInputBufferWithResampling(AudioNodeStream* aStream,
                                          AudioChunk* aOutput,
                                          uint32_t aChannels,
-                                         uint32_t aOffsetWithinBlock,
-                                         uint32_t& aFramesWritten,
+                                         uint32_t* aOffsetWithinBlock,
+                                         TrackTicks* aCurrentPosition,
                                          int32_t aBufferMax) {
     // TODO: adjust for mStop (see bug 913854 comment 9).
-    uint32_t availableInOutputBuffer = WEBAUDIO_BLOCK_SIZE - aOffsetWithinBlock;
-    SpeexResamplerState* resampler = Resampler(aStream, aChannels);
+    uint32_t availableInOutputBuffer =
+      WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock;
+    SpeexResamplerState* resampler = mResampler;
     MOZ_ASSERT(aChannels > 0);
 
     if (mBufferPosition < aBufferMax) {
       uint32_t availableInInputBuffer = aBufferMax - mBufferPosition;
+      uint32_t ratioNum, ratioDen;
+      speex_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
       // Limit the number of input samples copied and possibly
       // format-converted for resampling by estimating how many will be used.
-      // This may be a little small when filling the resampler with initial
-      // data, but we'll get called again and it will work out.
-      uint32_t num, den;
-      speex_resampler_get_ratio(resampler, &num, &den);
-      uint32_t inputLimit = std::min(availableInInputBuffer,
-                                     availableInOutputBuffer * num / den + 10);
+      // This may be a little small if still filling the resampler with
+      // initial data, but we'll get called again and it will work out.
+      uint32_t inputLimit = availableInOutputBuffer * ratioNum / ratioDen + 10;
+      if (!BegunResampling()) {
+        // First time the resampler is used.
+        uint32_t inputLatency = speex_resampler_get_input_latency(resampler);
+        inputLimit += inputLatency;
+        // If starting after mStart, then play from the beginning of the
+        // buffer, but correct for input latency.  If starting before mStart,
+        // then align the resampler so that the time corresponding to the
+        // first input sample is mStart.
+        uint32_t skipFracNum = inputLatency * ratioDen;
+        double leadTicks = mStart - *aCurrentPosition;
+        if (leadTicks > 0.0) {
+          // Round to nearest output subsample supported by the resampler at
+          // these rates.
+          skipFracNum -= leadTicks * ratioNum + 0.5;
+          MOZ_ASSERT(skipFracNum < INT32_MAX, "mBeginProcessing is wrong?");
+        }
+        speex_resampler_set_skip_frac_num(resampler, skipFracNum);
+
+        mBeginProcessing = -TRACK_TICKS_MAX;
+      }
+      inputLimit = std::min(inputLimit, availableInInputBuffer);
+
       for (uint32_t i = 0; true; ) {
         uint32_t inSamples = inputLimit;
         const float* inputData = mBuffer->GetData(i) + mBufferPosition;
 
         uint32_t outSamples = availableInOutputBuffer;
         float* outputData =
           static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
-          aOffsetWithinBlock;
+          *aOffsetWithinBlock;
 
         WebAudioUtils::SpeexResamplerProcess(resampler, i,
                                              inputData, &inSamples,
                                              outputData, &outSamples);
         if (++i == aChannels) {
           mBufferPosition += inSamples;
           MOZ_ASSERT(mBufferPosition <= mBufferEnd || mLoop);
-          aFramesWritten = outSamples;
+          *aOffsetWithinBlock += outSamples;
+          *aCurrentPosition += outSamples;
           if (inSamples == availableInInputBuffer && !mLoop) {
-            // If the available output space were unbounded then the input
-            // latency would always be the correct amount of extra input to
-            // provide in order to advance the output position to align with
-            // the final point in the buffer.  However, when the output space
-            // becomes full, the resampler may read all available input
-            // without writing out the corresponding output.  Add one more
-            // input sample, so that we know that enough output has been
-            // written when the last input sample has been read.  This may
-            // often write more than necessary but the extra samples will be
-            // based on (mostly) zero input.
+            // We'll feed in enough zeros to empty out the resampler's memory.
+            // This handles the output latency as well as capturing the low
+            // pass effects of the resample filter.
             mRemainingResamplerTail =
-              speex_resampler_get_input_latency(resampler) + 1;
+              2 * speex_resampler_get_input_latency(resampler) - 1;
           }
           return;
         }
       }
     } else {
       for (uint32_t i = 0; true; ) {
         uint32_t inSamples = mRemainingResamplerTail;
         uint32_t outSamples = availableInOutputBuffer;
         float* outputData =
           static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
-          aOffsetWithinBlock;
+          *aOffsetWithinBlock;
 
         // AudioDataValue* for aIn selects the function that does not try to
         // copy and format-convert input data.
         WebAudioUtils::SpeexResamplerProcess(resampler, i,
                          static_cast<AudioDataValue*>(nullptr), &inSamples,
                          outputData, &outSamples);
         if (++i == aChannels) {
           mRemainingResamplerTail -= inSamples;
           MOZ_ASSERT(mRemainingResamplerTail >= 0);
-          aFramesWritten = outSamples;
+          *aOffsetWithinBlock += outSamples;
+          *aCurrentPosition += outSamples;
           break;
         }
       }
     }
   }
 
   /**
    * Fill aOutput with as many zero frames as we can, and advance
@@ -307,88 +369,63 @@ public:
                       TrackTicks* aCurrentPosition,
                       int32_t aBufferMax)
   {
     MOZ_ASSERT(*aCurrentPosition < mStop);
     uint32_t numFrames =
       std::min(std::min<TrackTicks>(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                                     aBufferMax - mBufferPosition),
                mStop - *aCurrentPosition);
-    if (numFrames == WEBAUDIO_BLOCK_SIZE && !ShouldResample(aStream->SampleRate())) {
+    if (numFrames == WEBAUDIO_BLOCK_SIZE && !mResampler) {
       MOZ_ASSERT(mBufferPosition < aBufferMax);
       BorrowFromInputBuffer(aOutput, aChannels);
       *aOffsetWithinBlock += numFrames;
       *aCurrentPosition += numFrames;
       mBufferPosition += numFrames;
     } else {
       if (*aOffsetWithinBlock == 0) {
         AllocateAudioBlock(aChannels, aOutput);
       }
-      if (!ShouldResample(aStream->SampleRate())) {
+      if (!mResampler) {
         MOZ_ASSERT(mBufferPosition < aBufferMax);
         CopyFromInputBuffer(aOutput, aChannels, *aOffsetWithinBlock, numFrames);
         *aOffsetWithinBlock += numFrames;
         *aCurrentPosition += numFrames;
         mBufferPosition += numFrames;
       } else {
-        uint32_t framesWritten;
-        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, *aOffsetWithinBlock, framesWritten, aBufferMax);
-        *aOffsetWithinBlock += framesWritten;
-        *aCurrentPosition += framesWritten;
+        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aOffsetWithinBlock, aCurrentPosition, aBufferMax);
       }
     }
   }
 
-  uint32_t ComputeFinalOutSampleRate(TrackRate aStreamSampleRate)
+  int32_t ComputeFinalOutSampleRate(float aPlaybackRate)
   {
-    if (mPlaybackRate <= 0 || mPlaybackRate != mPlaybackRate) {
-      mPlaybackRate = 1.0f;
-    }
-    if (mDopplerShift <= 0 || mDopplerShift != mDopplerShift) {
-      mDopplerShift = 1.0f;
-    }
-    return WebAudioUtils::TruncateFloatToInt<uint32_t>(aStreamSampleRate /
-                                                       (mPlaybackRate * mDopplerShift));
-  }
-
-  bool ShouldResample(TrackRate aStreamSampleRate) const
-  {
-    // There is latency in the resampler.  If there is already a resampler,
-    // then it will have moved mBufferPosition to after the samples it has
-    // read, but it hasn't output its buffered samples.  Keep using the
-    // resampler, even if the rates now match, so that this latent segment is
-    // output.
-    return mResampler ||
-      (mPlaybackRate * mDopplerShift * mBufferSampleRate != aStreamSampleRate);
+    // Make sure the playback rate and the doppler shift are something
+    // our resampler can work with.
+    int32_t rate = WebAudioUtils::
+      TruncateFloatToInt<int32_t>(mSource->SampleRate() /
+                                  (aPlaybackRate * mDopplerShift));
+    return rate ? rate : mBufferSampleRate;
   }
 
-  void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels)
+  void UpdateSampleRateIfNeeded(uint32_t aChannels)
   {
+    float playbackRate;
+
     if (mPlaybackRateTimeline.HasSimpleValue()) {
-      mPlaybackRate = mPlaybackRateTimeline.GetValue();
+      playbackRate = mPlaybackRateTimeline.GetValue();
     } else {
-      mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition());
+      playbackRate = mPlaybackRateTimeline.GetValueAtTime(mSource->GetCurrentPosition());
+    }
+    if (playbackRate <= 0 || playbackRate != playbackRate) {
+      playbackRate = 1.0f;
     }
 
-    // Make sure the playback rate and the doppler shift are something
-    // our resampler can work with.
-    if (ComputeFinalOutSampleRate(aStream->SampleRate()) == 0) {
-      mPlaybackRate = 1.0;
-      mDopplerShift = 1.0;
-    }
-
-    if (mResampler) {
-      SpeexResamplerState* resampler = Resampler(aStream, aChannels);
-      uint32_t currentOutSampleRate, currentInSampleRate;
-      speex_resampler_get_rate(resampler, &currentInSampleRate, &currentOutSampleRate);
-      uint32_t finalSampleRate = ComputeFinalOutSampleRate(aStream->SampleRate());
-      if (currentOutSampleRate != finalSampleRate) {
-        speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate);
-      }
-    }
+    int32_t outRate = ComputeFinalOutSampleRate(playbackRate);
+    UpdateResampler(outRate, aChannels);
   }
 
   virtual void ProduceAudioBlock(AudioNodeStream* aStream,
                                  const AudioChunk& aInput,
                                  AudioChunk* aOutput,
                                  bool* aFinished)
   {
     if (!mBuffer || !mBufferEnd) {
@@ -400,28 +437,29 @@ public:
     if (!channels) {
       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
       return;
     }
 
     // WebKit treats the playbackRate as a k-rate parameter in their code,
     // despite the spec saying that it should be an a-rate parameter. We treat
     // it as k-rate. Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=21592
-    UpdateSampleRateIfNeeded(aStream, channels);
+    UpdateSampleRateIfNeeded(channels);
 
     uint32_t written = 0;
     TrackTicks streamPosition = aStream->GetCurrentPosition();
     while (written < WEBAUDIO_BLOCK_SIZE) {
       if (mStop != TRACK_TICKS_MAX &&
           streamPosition >= mStop) {
         FillWithZeroes(aOutput, channels, &written, &streamPosition, TRACK_TICKS_MAX);
         continue;
       }
-      if (streamPosition < mStart) {
-        FillWithZeroes(aOutput, channels, &written, &streamPosition, mStart);
+      if (streamPosition < mBeginProcessing) {
+        FillWithZeroes(aOutput, channels, &written, &streamPosition,
+                       mBeginProcessing);
         continue;
       }
       if (mLoop) {
         // mLoopEnd can become less than mBufferPosition when a LOOPEND engine
         // parameter is received after "loopend" is changed on the node or a
         // new buffer with lower samplerate is set.
         if (mBufferPosition >= mLoopEnd) {
           mBufferPosition = mLoopStart;
@@ -439,30 +477,34 @@ public:
     // We've finished if we've gone past mStop, or if we're past mDuration when
     // looping is disabled.
     if (streamPosition >= mStop ||
         (!mLoop && mBufferPosition >= mBufferEnd && !mRemainingResamplerTail)) {
       *aFinished = true;
     }
   }
 
-  TrackTicks mStart;
+  double mStart; // including the fractional position between ticks
+  // Low pass filter effects from the resampler mean that samples before the
+  // start time are influenced by resampling the buffer.  mBeginProcessing
+  // includes the extent of this filter.  The special value of -TRACK_TICKS_MAX
+  // indicates that the resampler has begun processing.
+  TrackTicks mBeginProcessing;
   TrackTicks mStop;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
   SpeexResamplerState* mResampler;
   // mRemainingResamplerTail, like mBufferPosition, and
   // mBufferEnd, is measured in input buffer samples.
   int mRemainingResamplerTail;
   int32_t mBufferEnd;
   int32_t mLoopStart;
   int32_t mLoopEnd;
   int32_t mBufferSampleRate;
   int32_t mBufferPosition;
   uint32_t mChannels;
-  float mPlaybackRate;
   float mDopplerShift;
   AudioNodeStream* mDestination;
   AudioNodeStream* mSource;
   AudioParamTimeline mPlaybackRateTimeline;
   bool mLoop;
 };
 
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
@@ -527,17 +569,17 @@ AudioBufferSourceNode::Start(double aWhe
   // We can't send these parameters without a buffer because we don't know the
   // buffer's sample rate or length.
   if (mBuffer) {
     SendOffsetAndDurationParametersToStream(ns);
   }
 
   // Don't set parameter unnecessarily
   if (aWhen > 0.0) {
-    ns->SetStreamTimeParameter(START, Context(), aWhen);
+    ns->SetDoubleParameter(START, mContext->DOMTimeToStreamTime(aWhen));
   }
 }
 
 void
 AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx)
 {
   AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
   MOZ_ASSERT(ns, "Why don't we have a stream here?");
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -58,18 +58,20 @@ support-files =
 [test_bug866737.html]
 [test_bug867089.html]
 [test_bug867104.html]
 [test_bug867174.html]
 [test_bug867203.html]
 [test_bug875221.html]
 [test_bug875402.html]
 [test_bug894150.html]
+[test_bug938022.html]
 [test_bug956489.html]
 [test_bug964376.html]
+[test_bug972678.html]
 [test_channelMergerNode.html]
 [test_channelMergerNodeWithVolume.html]
 [test_channelSplitterNode.html]
 [test_channelSplitterNodeWithVolume.html]
 [test_convolverNode.html]
 [test_convolverNodeChannelCount.html]
 [test_convolverNodeWithGain.html]
 [test_convolverNode_mono_mono.html]
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_bug938022.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test audio element currentTime is correct when used as media source</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  var context = new AudioContext();
+  var audio = new Audio("small-shot.ogg");
+  audio.load();
+  audio.addEventListener("loadeddata", function (e) {
+    is(this.currentTime, 0, "currentTime must be 0");
+    SimpleTest.finish();
+  });
+  audio.play();
+
+  var source = context.createMediaElementSource(audio);
+  source.connect(context.destination);
+});
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_bug972678.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test buffers do not interfere when scheduled in sequence</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var OFFSETS = [0.005, 0.01, 0.02, 0.03];
+var LENGTH = 128;
+
+var gTest = {
+  length: 128 * OFFSETS.length,
+  numberOfChannels: 1,
+
+  createGraph: function(context) {
+    var gain = context.createGain();
+
+    // create a repeating sample
+    var repeatingSample = context.createBuffer(1, 2, context.sampleRate);
+    var c = repeatingSample.getChannelData(0);
+    for (var i = 0; i < repeatingSample.length; ++i) {
+      c[i] = i % 2 == 0 ? 1 : -1;
+    }
+
+    OFFSETS.forEach(function (offset, offsetIdx) {
+      // Schedule a set of nodes to repeat the sample.
+      for (var i = 0; i < LENGTH; i += repeatingSample.length) {
+        var source = context.createBufferSource();
+        source.buffer = repeatingSample;
+        source.connect(gain);
+        source.start((offsetIdx * LENGTH + i + offset) / context.sampleRate);
+      }
+
+      buffer = context.createBuffer(1, LENGTH, context.sampleRate);
+      c = buffer.getChannelData(0);
+      for (var i = 0; i < buffer.length; ++i) {
+        c[i] = i % 2 == 0 ? -1 : 1;
+      }
+
+      var source = context.createBufferSource();
+      source.buffer = buffer;
+      source.connect(gain);
+      source.start((offsetIdx * LENGTH + offset) / context.sampleRate);
+    });
+
+    return gain;
+  },
+
+  createExpectedBuffers: function(context) {
+    return context.createBuffer(1, gTest.length, context.sampleRate);
+  },
+};
+
+runTest();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webspeech/recognition/test/hello.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/webspeech/recognition/test/mochitest.ini
+++ b/content/media/webspeech/recognition/test/mochitest.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   head.js
   hello.ogg
+  hello.ogg^headers^
   silence.ogg
+  silence.ogg^headers^
 
 [test_abort.html]
 [test_audio_capture_error.html]
 [test_call_start_from_end_handler.html]
 [test_nested_eventloop.html]
 skip-if = toolkit == 'android'
 [test_preference_enable.html]
 [test_recognition_service_error.html]
new file mode 100644
--- /dev/null
+++ b/content/media/webspeech/recognition/test/silence.ogg^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/svg/content/test/mochitest.ini
+++ b/content/svg/content/test/mochitest.ini
@@ -52,16 +52,17 @@ skip-if = true
 [test_pathAnimInterpolation.xhtml]
 [test_pathSeg.xhtml]
 [test_pointAtLength.xhtml]
 [test_pointer-events-1a.xhtml]
 [test_pointer-events-1b.xhtml]
 [test_pointer-events-2.xhtml]
 [test_pointer-events-3.xhtml]
 [test_pointer-events-4.xhtml]
+[test_pointer-events-5.xhtml]
 [test_scientific.html]
 [test_selectSubString.xhtml]
 [test_stroke-linecap-hit-testing.xhtml]
 [test_SVGLengthList-2.xhtml]
 [test_SVGLengthList.xhtml]
 [test_SVGMatrix.xhtml]
 [test_SVG_namespace_ids.html]
 [test_SVGNumberList.xhtml]
copy from content/svg/content/test/test_pointer-events-2.xhtml
copy to content/svg/content/test/test_pointer-events-5.xhtml
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7974,18 +7974,26 @@ nsDocShell::RestoreFromHistory()
     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
     uint32_t parentSuspendCount = 0;
     if (document) {
         nsCOMPtr<nsIDocShellTreeItem> parent;
         GetParent(getter_AddRefs(parent));
         nsCOMPtr<nsIDocument> d = do_GetInterface(parent);
         if (d) {
             if (d->EventHandlingSuppressed()) {
-                document->SuppressEventHandling(d->EventHandlingSuppressed());
-            }
+                document->SuppressEventHandling(nsIDocument::eEvents,
+                                                d->EventHandlingSuppressed());
+            }
+
+            // Ick, it'd be nicer to not rewalk all of the subdocs here.
+            if (d->AnimationsPaused()) {
+                document->SuppressEventHandling(nsIDocument::eAnimationsOnly,
+                                                d->AnimationsPaused());
+            }
+
             nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
             if (parentWindow) {
                 parentSuspendCount = parentWindow->TimeoutSuspendCount();
             }
         }
 
         // Use the uri from the mLSHE we had when we entered this function
         // (which need not match the document's URI if anchors are involved),
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -126,18 +126,16 @@
 #include "nsIDOMSVGLength.h"
 #include "nsIDOMSVGNumber.h"
 
 // Storage includes
 #include "nsIDOMStorage.h"
 #include "nsPIDOMStorage.h"
 
 // Drag and drop
-#include "nsIDOMDataTransfer.h"
-
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
 
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 
 #include "nsDOMTouchEvent.h"
 
@@ -436,20 +434,16 @@ static nsDOMClassInfoData sClassInfoData
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_CLASSINFO_DATA(MozMobileConnection, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  // data transfer for drag and drop
-  NS_DEFINE_CLASSINFO_DATA(DataTransfer, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
@@ -1118,20 +1112,16 @@ nsDOMClassInfo::Init()
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 #endif // MOZ_B2G_RIL
 
   DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(DataTransfer, nsIDOMDataTransfer)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataTransfer)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(EventListenerInfo, nsIEventListenerInfo)
     DOM_CLASSINFO_MAP_ENTRY(nsIEventListenerInfo)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -81,18 +81,16 @@ DOMCI_CLASS(MozMobileMessageThread)
 
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(MozMobileConnection)
 #endif
 
 // @font-face in CSS
 DOMCI_CLASS(CSSFontFaceRule)
 
-DOMCI_CLASS(DataTransfer)
-
 DOMCI_CLASS(EventListenerInfo)
 
 DOMCI_CLASS(ContentFrameMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1678,19 +1678,19 @@ nsDOMWindowUtils::SuppressEventHandling(
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   if (aSuppress) {
-    doc->SuppressEventHandling();
+    doc->SuppressEventHandling(nsIDocument::eEvents);
   } else {
-    doc->UnsuppressEventHandlingAndFireEvents(true);
+    doc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, true);
   }
 
   return NS_OK;
 }
 
 static nsresult
 getScrollXYAppUnits(nsWeakPtr mWindow, bool aFlushLayout, nsPoint& aScrollPos) {
   if (!nsContentUtils::IsCallerChrome()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1563,18 +1563,21 @@ nsGlobalWindow::FreeInnerObjects()
 
   if (mDoc) {
     // Remember the document's principal and URI.
     mDocumentPrincipal = mDoc->NodePrincipal();
     mDocumentURI = mDoc->GetDocumentURI();
     mDocBaseURI = mDoc->GetDocBaseURI();
 
     while (mDoc->EventHandlingSuppressed()) {
-      mDoc->UnsuppressEventHandlingAndFireEvents(false);
-    }
+      mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
+    }
+
+    // Note: we don't have to worry about eAnimationsOnly suppressions because
+    // they won't leak.
   }
 
   // Remove our reference to the document and the document principal.
   mFocusedNode = nullptr;
 
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
     mApplicationCache = nullptr;
@@ -8277,17 +8280,17 @@ nsGlobalWindow::EnterModalState()
     nsIPresShell::SetCapturingContent(nullptr, 0);
   }
 
   if (topWin->mModalStateDepth == 0) {
     NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
 
     mSuspendedDoc = topDoc;
     if (mSuspendedDoc) {
-      mSuspendedDoc->SuppressEventHandling();
+      mSuspendedDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
     }
   }
   topWin->mModalStateDepth++;
 }
 
 // static
 void
 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
@@ -8374,17 +8377,18 @@ nsGlobalWindow::LeaveModalState()
 
   if (topWin->mModalStateDepth == 0) {
     nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
     if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
       NS_WARNING("failed to dispatch pending timeout runnable");
 
     if (mSuspendedDoc) {
       nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
-      mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
+      mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
+                                                          currentDoc == mSuspendedDoc);
       mSuspendedDoc = nullptr;
     }
   }
 
   // Remember the time of the last dialog quit.
   nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
   if (inner)
     inner->mLastDialogQuitTime = TimeStamp::Now();
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -22,17 +22,17 @@
 #include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsCycleCollector.h"
 #include "nsIXPConnect.h"
 #include "MainThreadUtils.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
 #include "nsIVariant.h"
 
 #include "nsWrapperCacheInlines.h"
 
 class nsPIDOMWindow;
 
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1964,9 +1964,8 @@ addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
 addExternalIface('XPathResult', nativeType='nsISupports')
 addExternalIface('XPathExpression')
 addExternalIface('XPathNSResolver')
 addExternalIface('XULCommandDispatcher')
-addExternalIface('DataTransfer', notflattened=True)
--- a/dom/bindings/NonRefcountedDOMObject.h
+++ b/dom/bindings/NonRefcountedDOMObject.h
@@ -2,17 +2,17 @@
 /* vim: set ts=2 sw=2 et tw=79: */
 /* 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_NonRefcountedDOMObject_h__
 #define mozilla_dom_NonRefcountedDOMObject_h__
 
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
 // Natives for DOM classes with 'owned' as the value for nativeOwnership in
 // Bindings.conf need to inherit from this class.
 // If you're seeing objects of this class leak then natives for one of the DOM
 // classes with 'owned' as the value for nativeOwnership in Bindings.conf is
--- a/dom/bluetooth/ipc/BluetoothChild.cpp
+++ b/dom/bluetooth/ipc/BluetoothChild.cpp
@@ -5,18 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "BluetoothChild.h"
 
 #include "mozilla/Assertions.h"
 #include "nsDebug.h"
+#include "nsISupportsImpl.h"
 #include "nsThreadUtils.h"
-#include "nsTraceRefcnt.h"
 
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothServiceChildProcess.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 namespace {
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -6,18 +6,18 @@
 
 #include "base/basictypes.h"
 
 #include "BluetoothParent.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/unused.h"
 #include "nsDebug.h"
+#include "nsISupportsImpl.h"
 #include "nsThreadUtils.h"
-#include "nsTraceRefcnt.h"
 
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 
 using mozilla::unused;
 USING_BLUETOOTH_NAMESPACE
 
 /*******************************************************************************
--- a/dom/events/ClipboardEvent.cpp
+++ b/dom/events/ClipboardEvent.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 "mozilla/dom/ClipboardEvent.h"
 #include "mozilla/ContentEvents.h"
-#include "nsDOMDataTransfer.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "nsIClipboard.h"
 
 namespace mozilla {
 namespace dom {
 
 ClipboardEvent::ClipboardEvent(EventTarget* aOwner,
                                nsPresContext* aPresContext,
                                InternalClipboardEvent* aEvent)
@@ -33,70 +33,88 @@ NS_IMPL_ADDREF_INHERITED(ClipboardEvent,
 NS_IMPL_RELEASE_INHERITED(ClipboardEvent, nsDOMEvent)
 
 nsresult
 ClipboardEvent::InitClipboardEvent(const nsAString& aType,
                                    bool aCanBubble,
                                    bool aCancelable,
                                    nsIDOMDataTransfer* aClipboardData)
 {
-  nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<DataTransfer> clipboardData = do_QueryInterface(aClipboardData);
+  // Null clipboardData is OK
+
+  ErrorResult rv;
+  InitClipboardEvent(aType, aCanBubble, aCancelable, clipboardData, rv);
+
+  return rv.ErrorCode();
+}
+
+void
+ClipboardEvent::InitClipboardEvent(const nsAString& aType, bool aCanBubble,
+                                   bool aCancelable,
+                                   DataTransfer* aClipboardData,
+                                   ErrorResult& aError)
+{
+  aError = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
+  if (aError.Failed()) {
+    return;
+  }
 
   mEvent->AsClipboardEvent()->clipboardData = aClipboardData;
-
-  return NS_OK;
 }
 
 already_AddRefed<ClipboardEvent>
 ClipboardEvent::Constructor(const GlobalObject& aGlobal,
                             const nsAString& aType,
                             const ClipboardEventInit& aParam,
                             ErrorResult& aRv)
 {
   nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<ClipboardEvent> e = new ClipboardEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
 
-  nsRefPtr<nsDOMDataTransfer> clipboardData;
+  nsRefPtr<DataTransfer> clipboardData;
   if (e->mEventIsInternal) {
     InternalClipboardEvent* event = e->mEvent->AsClipboardEvent();
     if (event) {
       // Always create a clipboardData for the copy event. If this is changed to
       // support other types of events, make sure that read/write privileges are
-      // checked properly within nsDOMDataTransfer.
-      clipboardData = new nsDOMDataTransfer(NS_COPY, false, -1);
+      // checked properly within DataTransfer.
+      clipboardData = new DataTransfer(ToSupports(e), NS_COPY, false, -1);
       clipboardData->SetData(aParam.mDataType, aParam.mData);
     }
   }
 
-  aRv = e->InitClipboardEvent(aType, aParam.mBubbles, aParam.mCancelable,
-                              clipboardData);
+  e->InitClipboardEvent(aType, aParam.mBubbles, aParam.mCancelable,
+                        clipboardData, aRv);
   e->SetTrusted(trusted);
   return e.forget();
 }
 
 NS_IMETHODIMP
 ClipboardEvent::GetClipboardData(nsIDOMDataTransfer** aClipboardData)
 {
   NS_IF_ADDREF(*aClipboardData = GetClipboardData());
   return NS_OK;
 }
 
-nsIDOMDataTransfer*
+DataTransfer*
 ClipboardEvent::GetClipboardData()
 {
   InternalClipboardEvent* event = mEvent->AsClipboardEvent();
 
   if (!event->clipboardData) {
     if (mEventIsInternal) {
-      event->clipboardData = new nsDOMDataTransfer(NS_COPY, false, -1);
+      event->clipboardData =
+        new DataTransfer(ToSupports(this), NS_COPY, false, -1);
     } else {
       event->clipboardData =
-        new nsDOMDataTransfer(event->message, event->message == NS_PASTE, nsIClipboard::kGlobalClipboard);
+        new DataTransfer(ToSupports(this), event->message,
+                         event->message == NS_PASTE,
+                         nsIClipboard::kGlobalClipboard);
     }
   }
 
   return event->clipboardData;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/events/ClipboardEvent.h
+++ b/dom/events/ClipboardEvent.h
@@ -8,16 +8,17 @@
 
 #include "nsIDOMClipboardEvent.h"
 #include "nsDOMEvent.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/ClipboardEventBinding.h"
 
 namespace mozilla {
 namespace dom {
+class DataTransfer;
 
 class ClipboardEvent : public nsDOMEvent,
                        public nsIDOMClipboardEvent
 {
 public:
   ClipboardEvent(EventTarget* aOwner,
                  nsPresContext* aPresContext,
                  InternalClipboardEvent* aEvent);
@@ -36,15 +37,20 @@ public:
   }
 
   static already_AddRefed<ClipboardEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const ClipboardEventInit& aParam,
               ErrorResult& aRv);
 
-  nsIDOMDataTransfer* GetClipboardData();
+  DataTransfer* GetClipboardData();
+
+  void InitClipboardEvent(const nsAString& aType, bool aCanBubble,
+                          bool aCancelable,
+                          DataTransfer* aClipboardData,
+                          ErrorResult& aError);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ClipboardEvent_h_
rename from dom/events/nsDOMDataTransfer.cpp
rename to dom/events/DataTransfer.cpp
--- a/dom/events/nsDOMDataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -2,171 +2,219 @@
 /* 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 "mozilla/ArrayUtils.h"
 #include "mozilla/BasicEvents.h"
 
-#include "nsDOMDataTransfer.h"
+#include "DataTransfer.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIVariant.h"
 #include "nsISupportsPrimitives.h"
-#include "nsDOMClassInfoID.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsDOMLists.h"
 #include "nsError.h"
 #include "nsIDragService.h"
 #include "nsIClipboard.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsCRT.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIDocument.h"
 #include "nsIScriptGlobalObject.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
+#include "mozilla/dom/DataTransferBinding.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/BindingUtils.h"
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDataTransfer)
+namespace mozilla {
+namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMDataTransfer)
+NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
   if (tmp->mFiles) {
     tmp->mFiles->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMDataTransfer)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer)
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMDataTransfer)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMDataTransfer)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer)
 
-DOMCI_DATA(DataTransfer, nsDOMDataTransfer)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMDataTransfer)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer)
+  NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DataTransfer)
 NS_INTERFACE_MAP_END
 
 // the size of the array
-const char nsDOMDataTransfer::sEffects[8][9] = {
+const char DataTransfer::sEffects[8][9] = {
   "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
 };
 
-nsDOMDataTransfer::nsDOMDataTransfer(uint32_t aEventType, bool aIsExternal, int32_t aClipboardType)
-  : mEventType(aEventType),
+DataTransfer::DataTransfer(nsISupports* aParent, uint32_t aEventType,
+                           bool aIsExternal, int32_t aClipboardType)
+  : mParent(aParent),
+    mEventType(aEventType),
     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
     mCursorState(false),
     mReadOnly(true),
     mIsExternal(aIsExternal),
     mUserCancelled(false),
     mIsCrossDomainSubFrameDrop(false),
     mClipboardType(aClipboardType),
     mDragImageX(0),
     mDragImageY(0)
 {
+  MOZ_ASSERT(mParent);
+  SetIsDOMBinding();
   // For these events, we want to be able to add data to the data transfer, so
   // clear the readonly state. Otherwise, the data is already present. For
   // external usage, cache the data from the native clipboard or drag.
   if (aEventType == NS_CUT ||
       aEventType == NS_COPY ||
       aEventType == NS_DRAGDROP_START ||
       aEventType == NS_DRAGDROP_GESTURE) {
     mReadOnly = false;
-} else if (mIsExternal) {
+  } else if (mIsExternal) {
     if (aEventType == NS_PASTE) {
       CacheExternalClipboardFormats();
     } else if (aEventType >= NS_DRAGDROP_EVENT_START && aEventType <= NS_DRAGDROP_LEAVE_SYNTH) {
       CacheExternalDragFormats();
     }
   }
 }
 
-nsDOMDataTransfer::nsDOMDataTransfer(uint32_t aEventType,
-                                     const uint32_t aEffectAllowed,
-                                     bool aCursorState,
-                                     bool aIsExternal,
-                                     bool aUserCancelled,
-                                     bool aIsCrossDomainSubFrameDrop,
-                                     int32_t aClipboardType,
-                                     nsTArray<nsTArray<TransferItem> >& aItems,
-                                     nsIDOMElement* aDragImage,
-                                     uint32_t aDragImageX,
-                                     uint32_t aDragImageY)
-  : mEventType(aEventType),
+DataTransfer::DataTransfer(nsISupports* aParent,
+                           uint32_t aEventType,
+                           const uint32_t aEffectAllowed,
+                           bool aCursorState,
+                           bool aIsExternal,
+                           bool aUserCancelled,
+                           bool aIsCrossDomainSubFrameDrop,
+                           int32_t aClipboardType,
+                           nsTArray<nsTArray<TransferItem> >& aItems,
+                           Element* aDragImage,
+                           uint32_t aDragImageX,
+                           uint32_t aDragImageY)
+  : mParent(aParent),
+    mEventType(aEventType),
     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     mEffectAllowed(aEffectAllowed),
     mCursorState(aCursorState),
     mReadOnly(true),
     mIsExternal(aIsExternal),
     mUserCancelled(aUserCancelled),
     mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop),
     mClipboardType(aClipboardType),
     mItems(aItems),
     mDragImage(aDragImage),
     mDragImageX(aDragImageX),
     mDragImageY(aDragImageY)
 {
+  MOZ_ASSERT(mParent);
+  SetIsDOMBinding();
   // The items are copied from aItems into mItems. There is no need to copy
   // the actual data in the items as the data transfer will be read only. The
   // draggesture and dragstart events are the only times when items are
   // modifiable, but those events should have been using the first constructor
   // above.
   NS_ASSERTION(aEventType != NS_DRAGDROP_GESTURE &&
                aEventType != NS_DRAGDROP_START,
-               "invalid event type for nsDOMDataTransfer constructor");
+               "invalid event type for DataTransfer constructor");
+}
+
+DataTransfer::~DataTransfer()
+{
+  if (mFiles) {
+    mFiles->Disconnect();
+  }
+}
+
+// static
+already_AddRefed<DataTransfer>
+DataTransfer::Constructor(const GlobalObject& aGlobal,
+                          const nsAString& aEventType, bool aIsExternal,
+                          ErrorResult& aRv)
+{
+  nsAutoCString onEventType("on");
+  AppendUTF16toUTF8(aEventType, onEventType);
+  nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(onEventType);
+  if (!eventTypeAtom) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
+
+  uint32_t eventType = nsContentUtils::GetEventId(eventTypeAtom);
+  nsRefPtr<DataTransfer> transfer = new DataTransfer(aGlobal.GetAsSupports(),
+                                                     eventType, aIsExternal,
+                                                     -1);
+  return transfer.forget();
+}
+
+JSObject*
+DataTransfer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return DataTransferBinding::Wrap(aCx, aScope, this);
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetDropEffect(nsAString& aDropEffect)
+DataTransfer::GetDropEffect(nsAString& aDropEffect)
 {
-  aDropEffect.AssignASCII(sEffects[mDropEffect]);
+  nsString dropEffect;
+  GetDropEffect(dropEffect);
+  aDropEffect = dropEffect;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::SetDropEffect(const nsAString& aDropEffect)
+DataTransfer::SetDropEffect(const nsAString& aDropEffect)
 {
   // the drop effect can only be 'none', 'copy', 'move' or 'link'.
   for (uint32_t e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) {
     if (aDropEffect.EqualsASCII(sEffects[e])) {
       // don't allow copyMove
       if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
                 nsIDragService::DRAGDROP_ACTION_MOVE))
         mDropEffect = e;
       break;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
+DataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
 {
-  if (mEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
-    aEffectAllowed.AssignLiteral("uninitialized");
-  else
-    aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]);
+  nsString effectAllowed;
+  GetEffectAllowed(effectAllowed);
+  aEffectAllowed = effectAllowed;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
+DataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
 {
   if (aEffectAllowed.EqualsLiteral("uninitialized")) {
     mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
     return NS_OK;
   }
 
   static_assert(nsIDragService::DRAGDROP_ACTION_NONE == 0,
                 "DRAGDROP_ACTION_NONE constant is wrong");
@@ -183,145 +231,157 @@ nsDOMDataTransfer::SetEffectAllowed(cons
       break;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetDropEffectInt(uint32_t* aDropEffect)
+DataTransfer::GetDropEffectInt(uint32_t* aDropEffect)
 {
   *aDropEffect = mDropEffect;
   return  NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::SetDropEffectInt(uint32_t aDropEffect)
+DataTransfer::SetDropEffectInt(uint32_t aDropEffect)
 {
   mDropEffect = aDropEffect;
   return  NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed)
+DataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed)
 {
   *aEffectAllowed = mEffectAllowed;
   return  NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed)
+DataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed)
 {
   mEffectAllowed = aEffectAllowed;
   return  NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetMozUserCancelled(bool* aUserCancelled)
+DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
 {
-  *aUserCancelled = mUserCancelled;
+  *aUserCancelled = MozUserCancelled();
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMDataTransfer::GetFiles(nsIDOMFileList** aFileList)
+nsDOMFileList*
+DataTransfer::GetFiles(ErrorResult& aRv)
 {
-  *aFileList = nullptr;
-
   if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
       mEventType != NS_PASTE) {
-    return NS_OK;
+    return nullptr;
   }
 
   if (!mFiles) {
     mFiles = new nsDOMFileList(static_cast<nsIDOMDataTransfer*>(this));
 
     uint32_t count = mItems.Length();
 
     for (uint32_t i = 0; i < count; i++) {
       nsCOMPtr<nsIVariant> variant;
-      nsresult rv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant));
-      NS_ENSURE_SUCCESS(rv, rv);
+      aRv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant));
+      if (aRv.Failed()) {
+        return nullptr;
+      }
 
       if (!variant)
         continue;
 
       nsCOMPtr<nsISupports> supports;
-      rv = variant->GetAsISupports(getter_AddRefs(supports));
+      nsresult rv = variant->GetAsISupports(getter_AddRefs(supports));
 
       if (NS_FAILED(rv))
         continue;
 
       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
       if (!file)
         continue;
 
       nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
 
-      if (!mFiles->Append(domFile))
-        return NS_ERROR_FAILURE;
+      if (!mFiles->Append(domFile)) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+      }
     }
   }
 
-  *aFileList = mFiles;
-  NS_ADDREF(*aFileList);
-  return NS_OK;
+  return mFiles;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetTypes(nsIDOMDOMStringList** aTypes)
+DataTransfer::GetFiles(nsIDOMFileList** aFileList)
 {
-  *aTypes = nullptr;
+  ErrorResult rv;
+  *aFileList = GetFiles(rv);
+  return rv.ErrorCode();
+}
 
+already_AddRefed<nsIDOMDOMStringList>
+DataTransfer::Types()
+{
   nsRefPtr<nsDOMStringList> types = new nsDOMStringList();
-
   if (mItems.Length()) {
     const nsTArray<TransferItem>& item = mItems[0];
     for (uint32_t i = 0; i < item.Length(); i++)
       types->Add(item[i].mFormat);
 
     bool filePresent, filePromisePresent;
     types->Contains(NS_LITERAL_STRING(kFileMime), &filePresent);
     types->Contains(NS_LITERAL_STRING("application/x-moz-file-promise"), &filePromisePresent);
     if (filePresent || filePromisePresent)
       types->Add(NS_LITERAL_STRING("Files"));
   }
 
-  *aTypes = types;
-  NS_ADDREF(*aTypes);
+  return types.forget();
+}
+
+NS_IMETHODIMP
+DataTransfer::GetTypes(nsIDOMDOMStringList** aTypes)
+{
+  *aTypes = Types().get();
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMDataTransfer::GetData(const nsAString& aFormat, nsAString& aData)
+void
+DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
+                      ErrorResult& aRv)
 {
   // return an empty string if data for the format was not found
   aData.Truncate();
 
   nsCOMPtr<nsIVariant> data;
   nsresult rv = MozGetDataAt(aFormat, 0, getter_AddRefs(data));
-  if (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) {
-    return NS_OK;
+  if (NS_FAILED(rv)) {
+    if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) {
+      aRv.Throw(rv);
+    }
+    return;
   }
 
-  NS_ENSURE_SUCCESS(rv, rv);
-
   if (data) {
     nsAutoString stringdata;
     data->GetAsAString(stringdata);
 
     // for the URL type, parse out the first URI from the list. The URIs are
     // separated by newlines
     nsAutoString lowercaseFormat;
-    rv = nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
-    if (NS_FAILED(rv)) {
-      return rv;
+    aRv = nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
+    if (aRv.Failed()) {
+      return;
     }
 
     if (lowercaseFormat.EqualsLiteral("url")) {
       int32_t lastidx = 0, idx;
       int32_t length = stringdata.Length();
       while (lastidx < length) {
         idx = stringdata.FindChar('\n', lastidx);
         // lines beginning with # are comments
@@ -330,122 +390,174 @@ nsDOMDataTransfer::GetData(const nsAStri
             break;
         }
         else {
           if (idx == -1)
             aData.Assign(Substring(stringdata, lastidx));
           else
             aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
           aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData, true);
-          return NS_OK;
+          return;
         }
         lastidx = idx + 1;
       }
     }
     else {
       aData = stringdata;
     }
   }
+}
 
+NS_IMETHODIMP
+DataTransfer::GetData(const nsAString& aFormat, nsAString& aData)
+{
+  ErrorResult rv;
+  GetData(aFormat, aData, rv);
+  return rv.ErrorCode();
+}
+
+void
+DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData,
+                      ErrorResult& aRv)
+{
+  nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
+  if (!variant) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  variant->SetAsAString(aData);
+
+  aRv = MozSetDataAt(aFormat, variant, 0);
+}
+
+NS_IMETHODIMP
+DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData)
+{
+  ErrorResult rv;
+  SetData(aFormat, aData, rv);
+  return rv.ErrorCode();
+}
+
+void
+DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv)
+{
+  if (mReadOnly) {
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+
+  if (mItems.Length() == 0) {
+    return;
+  }
+
+  if (aFormat.WasPassed()) {
+    MozClearDataAtHelper(aFormat.Value(), 0, aRv);
+  } else {
+    MozClearDataAtHelper(EmptyString(), 0, aRv);
+  }
+}
+
+NS_IMETHODIMP
+DataTransfer::ClearData(const nsAString& aFormat)
+{
+  Optional<nsAString> format;
+  format = &aFormat;
+  ErrorResult rv;
+  ClearData(format, rv);
+  return rv.ErrorCode();
+}
+
+NS_IMETHODIMP
+DataTransfer::GetMozItemCount(uint32_t* aCount)
+{
+  *aCount = MozItemCount();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::SetData(const nsAString& aFormat, const nsAString& aData)
+DataTransfer::GetMozCursor(nsAString& aCursorState)
 {
-  nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
-  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
-
-  variant->SetAsAString(aData);
-
-  return MozSetDataAt(aFormat, variant, 0);
-}
-
-NS_IMETHODIMP
-nsDOMDataTransfer::ClearData(const nsAString& aFormat)
-{
-  nsresult rv = MozClearDataAt(aFormat, 0);
-  return (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) ? NS_OK : rv;
-}
-
-NS_IMETHODIMP
-nsDOMDataTransfer::GetMozItemCount(uint32_t* aCount)
-{
-  *aCount = mItems.Length();
+  nsString cursor;
+  GetMozCursor(cursor);
+  aCursorState = cursor;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::GetMozCursor(nsAString& aCursorState)
-{
-  if (mCursorState) {
-    aCursorState.AssignLiteral("default");
-  } else {
-    aCursorState.AssignLiteral("auto");
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMDataTransfer::SetMozCursor(const nsAString& aCursorState)
+DataTransfer::SetMozCursor(const nsAString& aCursorState)
 {
   // Lock the cursor to an arrow during the drag.
   mCursorState = aCursorState.EqualsLiteral("default");
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMDataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
+already_AddRefed<nsINode>
+DataTransfer::GetMozSourceNode()
 {
-  *aSourceNode = nullptr;
-
   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
-  if (!dragSession)
-    return NS_OK;
+  if (!dragSession) {
+    return nullptr;
+  }
 
   nsCOMPtr<nsIDOMNode> sourceNode;
   dragSession->GetSourceNode(getter_AddRefs(sourceNode));
-  if (sourceNode && !nsContentUtils::CanCallerAccess(sourceNode))
-    return NS_OK;
+  nsCOMPtr<nsINode> node = do_QueryInterface(sourceNode);
+  if (node && !nsContentUtils::CanCallerAccess(node)) {
+    return nullptr;
+  }
 
-  sourceNode.swap(*aSourceNode);
-  return NS_OK;
+  return node.forget();
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::MozTypesAt(uint32_t aIndex, nsIDOMDOMStringList** aTypes)
+DataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
 {
-  *aTypes = nullptr;
+  nsCOMPtr<nsINode> sourceNode = GetMozSourceNode();
+  if (!sourceNode) {
+    *aSourceNode = nullptr;
+    return NS_OK;
+  }
 
+  return CallQueryInterface(sourceNode, aSourceNode);
+}
+
+already_AddRefed<nsIDOMDOMStringList>
+DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv)
+{
   // Only the first item is valid for clipboard events
   if (aIndex > 0 &&
       (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
   }
 
   nsRefPtr<nsDOMStringList> types = new nsDOMStringList();
-
   if (aIndex < mItems.Length()) {
     // note that you can retrieve the types regardless of their principal
     nsTArray<TransferItem>& item = mItems[aIndex];
     for (uint32_t i = 0; i < item.Length(); i++)
       types->Add(item[i].mFormat);
   }
 
-  *aTypes = types;
-  NS_ADDREF(*aTypes);
-
-  return NS_OK;
+  return types.forget();
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::MozGetDataAt(const nsAString& aFormat,
-                                uint32_t aIndex,
-                                nsIVariant** aData)
+DataTransfer::MozTypesAt(uint32_t aIndex, nsIDOMDOMStringList** aTypes)
+{
+  ErrorResult rv;
+  *aTypes = MozTypesAt(aIndex, rv).get();
+  return rv.ErrorCode();
+}
+
+NS_IMETHODIMP
+DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex,
+                           nsIVariant** aData)
 {
   *aData = nullptr;
 
   if (aFormat.IsEmpty())
     return NS_OK;
 
   if (aIndex >= mItems.Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
@@ -517,28 +629,51 @@ nsDOMDataTransfer::MozGetDataAt(const ns
       NS_IF_ADDREF(*aData);
       return NS_OK;
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMDataTransfer::MozSetDataAt(const nsAString& aFormat,
-                                nsIVariant* aData,
-                                uint32_t aIndex)
+JS::Value
+DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
+                           uint32_t aIndex, mozilla::ErrorResult& aRv)
 {
-  NS_ENSURE_TRUE(aData, NS_ERROR_NULL_POINTER);
+  nsCOMPtr<nsIVariant> data;
+  aRv = MozGetDataAt(aFormat, aIndex, getter_AddRefs(data));
+  if (aRv.Failed()) {
+    return JS::UndefinedValue();
+  }
+
+  if (!data) {
+    return JS::NullValue();
+  }
 
-  if (aFormat.IsEmpty())
+  JS::Rooted<JS::Value> result(aCx);
+  JS::Rooted<JSObject*> scope(aCx, GetWrapper());
+  if (!VariantToJsval(aCx, scope, data, &result)) {
+    aRv = NS_ERROR_FAILURE;
+    return JS::UndefinedValue();
+  }
+
+  return result;
+}
+
+NS_IMETHODIMP
+DataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData,
+                           uint32_t aIndex)
+{
+  if (aFormat.IsEmpty()) {
     return NS_OK;
+  }
 
-  if (mReadOnly)
+  if (mReadOnly) {
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
 
   // Specifying an index less than the current length will replace an existing
   // item. Specifying an index equal to the current length will add a new item.
   if (aIndex > mItems.Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Only the first item is valid for clipboard events
@@ -553,124 +688,183 @@ nsDOMDataTransfer::MozSetDataAt(const ns
        aFormat.EqualsLiteral("application/x-moz-file")) &&
        !nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsresult rv = NS_OK;
   nsIPrincipal* principal = GetCurrentPrincipal(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
+
   return SetDataWithPrincipal(aFormat, aData, aIndex, principal);
 }
 
-NS_IMETHODIMP
-nsDOMDataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex)
+void
+DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
+                           JS::Handle<JS::Value> aData,
+                           uint32_t aIndex, ErrorResult& aRv)
 {
-  if (mReadOnly)
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  nsCOMPtr<nsIVariant> data;
+  aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData,
+                                                    getter_AddRefs(data));
+  if (!aRv.Failed()) {
+    aRv = MozSetDataAt(aFormat, data, aIndex);
+  }
+}
+
+void
+DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
+                             ErrorResult& aRv)
+{
+  if (mReadOnly) {
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
 
   if (aIndex >= mItems.Length()) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
   }
 
   // Only the first item is valid for clipboard events
   if (aIndex > 0 &&
       (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
   }
 
+  MozClearDataAtHelper(aFormat, aIndex, aRv);
+}
+
+void
+DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
+                                   ErrorResult& aRv)
+{
+  MOZ_ASSERT(!mReadOnly);
+  MOZ_ASSERT(aIndex < mItems.Length());
+  MOZ_ASSERT(aIndex == 0 ||
+             (mEventType != NS_CUT && mEventType != NS_COPY &&
+              mEventType != NS_PASTE));
+
   nsAutoString format;
   GetRealFormat(aFormat, format);
 
   nsresult rv = NS_OK;
   nsIPrincipal* principal = GetCurrentPrincipal(&rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aRv = rv;
+    return;
+  }
 
   // if the format is empty, clear all formats
   bool clearall = format.IsEmpty();
 
   nsTArray<TransferItem>& item = mItems[aIndex];
   // count backwards so that the count and index don't have to be adjusted
   // after removing an element
   for (int32_t i = item.Length() - 1; i >= 0; i--) {
     TransferItem& formatitem = item[i];
     if (clearall || formatitem.mFormat.Equals(format)) {
       // don't allow removing data that has a stronger principal
       bool subsumes;
       if (formatitem.mPrincipal && principal &&
-          (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
-        return NS_ERROR_DOM_SECURITY_ERR;
+          (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) {
+        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+        return;
+      }
 
       item.RemoveElementAt(i);
 
       // if a format was specified, break out. Otherwise, loop around until
       // all formats have been removed
       if (!clearall)
         break;
     }
   }
 
   // if the last format for an item is removed, remove the entire item
   if (!item.Length())
      mItems.RemoveElementAt(aIndex);
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
+DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex)
 {
-  if (mReadOnly)
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  ErrorResult rv;
+  MozClearDataAt(aFormat, aIndex, rv);
+  return rv.ErrorCode();
+}
 
-  if (aImage) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(aImage);
-    NS_ENSURE_TRUE(content, NS_ERROR_INVALID_ARG);
+void
+DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY,
+                           ErrorResult& aRv)
+{
+  if (mReadOnly) {
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
-  mDragImage = aImage;
+
+  mDragImage = &aImage;
   mDragImageX = aX;
   mDragImageY = aY;
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDataTransfer::AddElement(nsIDOMElement* aElement)
+DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
+{
+  ErrorResult rv;
+  nsCOMPtr<Element> image = do_QueryInterface(aImage);
+  if (image) {
+    SetDragImage(*image, aX, aY, rv);
+  }
+  return rv.ErrorCode();
+}
+
+void
+DataTransfer::AddElement(Element& aElement, ErrorResult& aRv)
+{
+  if (mReadOnly) {
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+
+  mDragTarget = &aElement;
+}
+
+NS_IMETHODIMP
+DataTransfer::AddElement(nsIDOMElement* aElement)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
 
-  if (aElement) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
-    NS_ENSURE_TRUE(content, NS_ERROR_INVALID_ARG);
-  }
+  nsCOMPtr<Element> element = do_QueryInterface(aElement);
+  NS_ENSURE_TRUE(element, NS_ERROR_INVALID_ARG);
 
-  if (mReadOnly)
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-
-  mDragTarget = do_QueryInterface(aElement);
-
-  return NS_OK;
+  ErrorResult rv;
+  AddElement(*element, rv);
+  return rv.ErrorCode();
 }
 
 nsresult
-nsDOMDataTransfer::Clone(uint32_t aEventType, bool aUserCancelled,
-                         bool aIsCrossDomainSubFrameDrop,
-                         nsIDOMDataTransfer** aNewDataTransfer)
+DataTransfer::Clone(nsISupports* aParent, uint32_t aEventType,
+                    bool aUserCancelled, bool aIsCrossDomainSubFrameDrop,
+                    DataTransfer** aNewDataTransfer)
 {
-  nsDOMDataTransfer* newDataTransfer =
-    new nsDOMDataTransfer(aEventType, mEffectAllowed, mCursorState,
-                          mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop,
-                          mClipboardType, mItems, mDragImage, mDragImageX, mDragImageY);
+  DataTransfer* newDataTransfer =
+    new DataTransfer(aParent, aEventType, mEffectAllowed, mCursorState,
+                     mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop,
+                     mClipboardType, mItems, mDragImage, mDragImageX,
+                     mDragImageY);
 
   *aNewDataTransfer = newDataTransfer;
   NS_ADDREF(*aNewDataTransfer);
   return NS_OK;
 }
 
 already_AddRefed<nsISupportsArray>
-nsDOMDataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
+DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
 {
   MOZ_ASSERT(aDragTarget);
 
   nsCOMPtr<nsISupportsArray> transArray =
     do_CreateInstance("@mozilla.org/supports-array;1");
   if (!transArray) {
     return nullptr;
   }
@@ -695,17 +889,17 @@ nsDOMDataTransfer::GetTransferables(nsID
       transArray->AppendElement(transferable);
     }
   }
 
   return transArray.forget();
 }
 
 already_AddRefed<nsITransferable>
-nsDOMDataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
+DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
 {
   if (aIndex >= mItems.Length()) {
     return nullptr;
   }
 
   nsTArray<TransferItem>& item = mItems[aIndex];
   uint32_t count = item.Length();
   if (!count) {
@@ -762,19 +956,19 @@ nsDOMDataTransfer::GetTransferable(uint3
   if (added) {
     return transferable.forget();
   }
 
   return nullptr;
 }
 
 bool
-nsDOMDataTransfer::ConvertFromVariant(nsIVariant* aVariant,
-                                      nsISupports** aSupports,
-                                      uint32_t* aLength)
+DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
+                                 nsISupports** aSupports,
+                                 uint32_t* aLength)
 {
   *aSupports = nullptr;
   *aLength = 0;
 
   uint16_t type;
   aVariant->GetDataType(&type);
   if (type == nsIDataType::VTYPE_INTERFACE ||
       type == nsIDataType::VTYPE_INTERFACE_IS) {
@@ -826,26 +1020,26 @@ nsDOMDataTransfer::ConvertFromVariant(ns
 
   // each character is two bytes
   *aLength = str.Length() << 1;
 
   return true;
 }
 
 void
-nsDOMDataTransfer::ClearAll()
+DataTransfer::ClearAll()
 {
   mItems.Clear();
 }
 
 nsresult
-nsDOMDataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
-                                        nsIVariant* aData,
-                                        uint32_t aIndex,
-                                        nsIPrincipal* aPrincipal)
+DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
+                                   nsIVariant* aData,
+                                   uint32_t aIndex,
+                                   nsIPrincipal* aPrincipal)
 {
   nsAutoString format;
   GetRealFormat(aFormat, format);
 
   // check if the item for the format already exists. In that case,
   // just replace it.
   TransferItem* formatitem;
   if (aIndex < mItems.Length()) {
@@ -884,59 +1078,59 @@ nsDOMDataTransfer::SetDataWithPrincipal(
   formatitem->mFormat = format;
   formatitem->mPrincipal = aPrincipal;
   formatitem->mData = aData;
 
   return NS_OK;
 }
 
 nsIPrincipal*
-nsDOMDataTransfer::GetCurrentPrincipal(nsresult* rv)
+DataTransfer::GetCurrentPrincipal(nsresult* rv)
 {
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
 
   nsCOMPtr<nsIPrincipal> currentPrincipal;
   *rv = ssm->GetSubjectPrincipal(getter_AddRefs(currentPrincipal));
   NS_ENSURE_SUCCESS(*rv, nullptr);
 
   if (!currentPrincipal)
     ssm->GetSystemPrincipal(getter_AddRefs(currentPrincipal));
 
   return currentPrincipal.get();
 }
 
 void
-nsDOMDataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
+DataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
 {
   // treat text/unicode as equivalent to text/plain
   nsAutoString lowercaseFormat;
   nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat);
   if (lowercaseFormat.EqualsLiteral("text") || lowercaseFormat.EqualsLiteral("text/unicode"))
     aOutFormat.AssignLiteral("text/plain");
   else if (lowercaseFormat.EqualsLiteral("url"))
     aOutFormat.AssignLiteral("text/uri-list");
   else
     aOutFormat.Assign(lowercaseFormat);
 }
 
 void
-nsDOMDataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal)
+DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal)
 {
   if (strcmp(aFormat, kUnicodeMime) == 0) {
     SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex, aPrincipal);
   } else {
     if (strcmp(aFormat, kURLDataMime) == 0) {
       SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex, aPrincipal);
     }
     SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex, aPrincipal);
   }
 }
 
 void
-nsDOMDataTransfer::CacheExternalDragFormats()
+DataTransfer::CacheExternalDragFormats()
 {
   // Called during the constructor to cache the formats available from an
   // external drag. The data associated with each format will be set to null.
   // This data will instead only be retrieved in FillInExternalDragData when
   // asked for, as it may be time consuming for the source application to
   // generate it.
 
   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
@@ -968,17 +1162,17 @@ nsDOMDataTransfer::CacheExternalDragForm
       if (supported) {
         CacheExternalData(formats[f], c, sysPrincipal);
       }
     }
   }
 }
 
 void
-nsDOMDataTransfer::CacheExternalClipboardFormats()
+DataTransfer::CacheExternalClipboardFormats()
 {
   NS_ASSERTION(mEventType == NS_PASTE, "caching clipboard data for invalid event");
 
   // Called during the constructor for paste events to cache the formats
   // available on the clipboard. As with CacheExternalDragFormats, the
   // data will only be retrieved when needed.
 
   nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1");
@@ -1002,17 +1196,17 @@ nsDOMDataTransfer::CacheExternalClipboar
     // the data. When retrieved, GetRealData will read the data.
     if (supported) {
       CacheExternalData(formats[f], 0, sysPrincipal);
     }
   }
 }
 
 void
-nsDOMDataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
+DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
 {
   NS_PRECONDITION(mIsExternal, "Not an external data transfer");
 
   if (aItem.mData) {
     return;
   }
 
   // only drag and paste events should be calling FillInExternalData
@@ -1076,8 +1270,11 @@ nsDOMDataTransfer::FillInExternalData(Tr
       variant->SetAsAString(str);
     }
     else {
       variant->SetAsISupports(data);
     }
 
     aItem.mData = variant;
   }
+
+} // namespace dom
+} // namespace mozilla
rename from dom/events/nsDOMDataTransfer.h
rename to dom/events/DataTransfer.h
--- a/dom/events/nsDOMDataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -1,102 +1,182 @@
 /* -*- 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 nsDOMDataTransfer_h__
-#define nsDOMDataTransfer_h__
+#ifndef mozilla_dom_DataTransfer_h
+#define mozilla_dom_DataTransfer_h
 
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsIVariant.h"
 #include "nsIPrincipal.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsIDOMElement.h"
+#include "nsIDragService.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsAutoPtr.h"
 #include "nsDOMFile.h"
 #include "mozilla/Attributes.h"
 
+class nsEventStateManager;
+class nsINode;
 class nsITransferable;
 class nsISupportsArray;
 class nsILoadContext;
 
+namespace mozilla {
+namespace dom {
+
+class Element;
+template<typename T> class Optional;
+
 /**
  * TransferItem is used to hold data for a particular format. Each piece of
  * data has a principal set from the caller which added it. This allows a
  * caller that wishes to retrieve the data to only be able to access the data
  * it is allowed to, yet still allow a chrome caller to retrieve any of the
  * data.
  */
 struct TransferItem {
   nsString mFormat;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIVariant> mData;
 };
 
-class nsDOMDataTransfer MOZ_FINAL : public nsIDOMDataTransfer
+#define NS_DATATRANSFER_IID \
+{ 0x43ee0327, 0xde5d, 0x463d, \
+  { 0x9b, 0xd0, 0xf1, 0x79, 0x09, 0x69, 0xf2, 0xfb } }
+
+class DataTransfer MOZ_FINAL : public nsIDOMDataTransfer,
+                               public nsWrapperCache
 {
 public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATATRANSFER_IID)
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIDOMDATATRANSFER
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMDataTransfer, nsIDOMDataTransfer)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DataTransfer)
 
-  friend class nsEventStateManager;
+  friend class ::nsEventStateManager;
 
 protected:
 
   // hide the default constructor
-  nsDOMDataTransfer();
+  DataTransfer();
 
   // this constructor is used only by the Clone method to copy the fields as
   // needed to a new data transfer.
-  nsDOMDataTransfer(uint32_t aEventType,
-                    const uint32_t aEffectAllowed,
-                    bool aCursorState,
-                    bool aIsExternal,
-                    bool aUserCancelled,
-                    bool aIsCrossDomainSubFrameDrop,
-                    int32_t aClipboardType,
-                    nsTArray<nsTArray<TransferItem> >& aItems,
-                    nsIDOMElement* aDragImage,
-                    uint32_t aDragImageX,
-                    uint32_t aDragImageY);
+  DataTransfer(nsISupports* aParent,
+               uint32_t aEventType,
+               const uint32_t aEffectAllowed,
+               bool aCursorState,
+               bool aIsExternal,
+               bool aUserCancelled,
+               bool aIsCrossDomainSubFrameDrop,
+               int32_t aClipboardType,
+               nsTArray<nsTArray<TransferItem> >& aItems,
+               Element* aDragImage,
+               uint32_t aDragImageX,
+               uint32_t aDragImageY);
 
-  ~nsDOMDataTransfer()
-  {
-    if (mFiles) {
-      mFiles->Disconnect();
-    }
-  }
+  ~DataTransfer();
 
   static const char sEffects[8][9];
 
 public:
 
-  // Constructor for nsDOMDataTransfer.
+  // Constructor for DataTransfer.
   //
   // aEventType is an event constant (such as NS_DRAGDROP_START)
   //
   // aIsExternal must only be true when used to create a dataTransfer for a
   // paste or a drag that was started without using a data transfer. The
   // latter will occur when an external drag occurs, that is, a drag where the
   // source is another application, or a drag is started by calling the drag
   // service directly. For clipboard operations, aClipboardType indicates
   // which clipboard to use, from nsIClipboard, or -1 for non-clipboard operations,
   // or if access to the system clipboard should not be allowed.
-  nsDOMDataTransfer(uint32_t aEventType, bool aIsExternal, int32_t aClipboardType);
+  DataTransfer(nsISupports* aParent, uint32_t aEventType, bool aIsExternal,
+               int32_t aClipboardType);
+
+  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope);
+  nsISupports* GetParentObject()
+  {
+    return mParent;
+  }
+
+  void SetParentObject(nsISupports* aNewParent)
+  {
+    MOZ_ASSERT(aNewParent);
+    // Setting the parent after we've been wrapped is pointless, so
+    // make sure we aren't wrapped yet.
+    MOZ_ASSERT(!GetWrapperPreserveColor());
+    mParent = aNewParent;
+  }
+
+  static already_AddRefed<DataTransfer>
+  Constructor(const GlobalObject& aGlobal, const nsAString& aEventType,
+              bool aIsExternal, ErrorResult& aRv);
 
-  void GetDragTarget(nsIDOMElement** aDragTarget)
+  void GetDropEffect(nsString& aDropEffect)
+  {
+    aDropEffect.AssignASCII(sEffects[mDropEffect]);
+  }
+  void GetEffectAllowed(nsString& aEffectAllowed)
+  {
+    if (mEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
+      aEffectAllowed.AssignLiteral("uninitialized");
+    } else {
+      aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]);
+    }
+  }
+  void SetDragImage(Element& aElement, int32_t aX, int32_t aY,
+                    ErrorResult& aRv);
+  already_AddRefed<nsIDOMDOMStringList> Types();
+  void GetData(const nsAString& aFormat, nsAString& aData, ErrorResult& aRv);
+  void SetData(const nsAString& aFormat, const nsAString& aData,
+               ErrorResult& aRv);
+  void ClearData(const mozilla::dom::Optional<nsAString>& aFormat,
+                 mozilla::ErrorResult& aRv);
+  nsDOMFileList* GetFiles(mozilla::ErrorResult& aRv);
+  void AddElement(Element& aElement, mozilla::ErrorResult& aRv);
+  uint32_t MozItemCount()
   {
-    *aDragTarget = mDragTarget;
-    NS_IF_ADDREF(*aDragTarget);
+    return mItems.Length();
+  }
+  void GetMozCursor(nsString& aCursor)
+  {
+    if (mCursorState) {
+      aCursor.AssignLiteral("default");
+    } else {
+      aCursor.AssignLiteral("auto");
+    }
+  }
+  already_AddRefed<nsIDOMDOMStringList> MozTypesAt(uint32_t aIndex,
+                                                   mozilla::ErrorResult& aRv);
+  void MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
+                      mozilla::ErrorResult& aRv);
+  void MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
+                    JS::Handle<JS::Value> aData, uint32_t aIndex,
+                    mozilla::ErrorResult& aRv);
+  JS::Value MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
+                         uint32_t aIndex, mozilla::ErrorResult& aRv);
+  bool MozUserCancelled()
+  {
+    return mUserCancelled;
+  }
+  already_AddRefed<nsINode> GetMozSourceNode();
+
+  mozilla::dom::Element* GetDragTarget()
+  {
+    return mDragTarget;
   }
 
   // a readonly dataTransfer cannot have new data added or existing data removed.
   // Only the dropEffect and effectAllowed may be modified.
   void SetReadOnly() { mReadOnly = true; }
 
   // converts the data into an array of nsITransferable objects to be used for
   // drag and drop or clipboard operations.
@@ -118,26 +198,29 @@ public:
   // Similar to SetData except also specifies the principal to store.
   // aData may be null when called from CacheExternalDragFormats or
   // CacheExternalClipboardFormats.
   nsresult SetDataWithPrincipal(const nsAString& aFormat,
                                 nsIVariant* aData,
                                 uint32_t aIndex,
                                 nsIPrincipal* aPrincipal);
 
-protected:
-
   // returns a weak reference to the drag image
-  nsIDOMElement* GetDragImage(int32_t* aX, int32_t* aY)
+  Element* GetDragImage(int32_t* aX, int32_t* aY)
   {
     *aX = mDragImageX;
     *aY = mDragImageY;
     return mDragImage;
   }
 
+  nsresult Clone(nsISupports* aParent, uint32_t aEventType, bool aUserCancelled,
+                 bool aIsCrossDomainSubFrameDrop, DataTransfer** aResult);
+
+protected:
+
   // returns a weak reference to the current principal
   nsIPrincipal* GetCurrentPrincipal(nsresult* rv);
 
   // converts some formats used for compatibility in aInFormat into aOutFormat.
   // Text and text/unicode become text/plain, and URL becomes text/uri-list
   void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat);
 
   // caches text and uri-list data formats that exist in the drag service or
@@ -150,16 +233,21 @@ protected:
 
   // caches the formats that exist in the clipboard
   void CacheExternalClipboardFormats();
 
   // fills in the data field of aItem with the data from the drag service or
   // clipboard for a given index.
   void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
 
+  void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
+                            mozilla::ErrorResult& aRv);
+
+  nsCOMPtr<nsISupports> mParent;
+
   // the event type this data transfer is for. This will correspond to an
   // event->message value.
   uint32_t mEventType;
 
   // the drop effect and effect allowed
   uint32_t mDropEffect;
   uint32_t mEffectAllowed;
 
@@ -187,19 +275,24 @@ protected:
 
   // array of items, each containing an array of format->data pairs
   nsTArray<nsTArray<TransferItem> > mItems;
 
   // array of files, containing only the files present in the dataTransfer
   nsRefPtr<nsDOMFileList> mFiles;
 
   // the target of the drag. The drag and dragend events will fire at this.
-  nsCOMPtr<nsIDOMElement> mDragTarget;
+  nsCOMPtr<mozilla::dom::Element> mDragTarget;
 
   // the custom drag image and coordinates within the image. If mDragImage is
   // null, the default image is created from the drag target.
-  nsCOMPtr<nsIDOMElement> mDragImage;
+  nsCOMPtr<mozilla::dom::Element> mDragImage;
   uint32_t mDragImageX;
   uint32_t mDragImageY;
 };
 
-#endif // nsDOMDataTransfer_h__
+NS_DEFINE_STATIC_IID_ACCESSOR(DataTransfer, NS_DATATRANSFER_IID)
 
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_DataTransfer_h */
+
--- a/dom/events/Touch.h
+++ b/dom/events/Touch.h
@@ -3,29 +3,31 @@
  * 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_Touch_h
 #define mozilla_dom_Touch_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
+#include "mozilla/MouseEvents.h"
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "Units.h"
 
 class nsPresContext;
 
 namespace mozilla {
 namespace dom {
 
 class EventTarget;
 
 class Touch MOZ_FINAL : public nsISupports
                       , public nsWrapperCache
+                      , public WidgetPointerHelper
 {
 public:
   static bool PrefEnabled(JSContext* aCx, JSObject* aGlobal);
 
   Touch(mozilla::dom::EventTarget* aTarget,
         int32_t aIdentifier,
         int32_t aPageX,
         int32_t aPageY,
--- a/dom/events/moz.build
+++ b/dom/events/moz.build
@@ -37,36 +37,37 @@ EXPORTS.mozilla += [
 
 EXPORTS.mozilla.dom += [
     'AnimationEvent.h',
     'BeforeUnloadEvent.h',
     'ClipboardEvent.h',
     'CommandEvent.h',
     'CompositionEvent.h',
     'DataContainerEvent.h',
+    'DataTransfer.h',
     'EventTarget.h',
     'PointerEvent.h',
     'Touch.h',
     'WheelEvent.h',
 ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     EXPORTS.mozilla.dom += ['SpeechRecognitionError.h']
 
 UNIFIED_SOURCES += [
     'AnimationEvent.cpp',
     'BeforeUnloadEvent.cpp',
     'ClipboardEvent.cpp',
     'CommandEvent.cpp',
     'CompositionEvent.cpp',
     'DataContainerEvent.cpp',
+    'DataTransfer.cpp',
     'EventTarget.cpp',
     'nsAsyncDOMEvent.cpp',
     'nsContentEventHandler.cpp',
-    'nsDOMDataTransfer.cpp',
     'nsDOMDeviceMotionEvent.cpp',
     'nsDOMDragEvent.cpp',
     'nsDOMEventTargetHelper.cpp',
     'nsDOMFocusEvent.cpp',
     'nsDOMKeyboardEvent.cpp',
     'nsDOMMessageEvent.cpp',
     'nsDOMMouseEvent.cpp',
     'nsDOMMouseScrollEvent.cpp',
--- a/dom/events/nsDOMDragEvent.cpp
+++ b/dom/events/nsDOMDragEvent.cpp
@@ -1,22 +1,22 @@
 /* -*- 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 "nsDOMDragEvent.h"
 #include "nsContentUtils.h"
-#include "nsIDOMDataTransfer.h"
 #include "prtime.h"
 #include "mozilla/MouseEvents.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
-nsDOMDragEvent::nsDOMDragEvent(mozilla::dom::EventTarget* aOwner,
+nsDOMDragEvent::nsDOMDragEvent(EventTarget* aOwner,
                                nsPresContext* aPresContext,
                                WidgetDragEvent* aEvent)
   : nsDOMMouseEvent(aOwner, aPresContext, aEvent ? aEvent :
                     new WidgetDragEvent(false, 0, nullptr))
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
@@ -30,48 +30,76 @@ nsDOMDragEvent::nsDOMDragEvent(mozilla::
 
 NS_IMPL_ADDREF_INHERITED(nsDOMDragEvent, nsDOMMouseEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMDragEvent, nsDOMMouseEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMDragEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDragEvent)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
 
+void
+nsDOMDragEvent::InitDragEvent(const nsAString& aType, bool aCanBubble,
+                              bool aCancelable, nsIDOMWindow* aView,
+                              int32_t aDetail, int32_t aScreenX,
+                              int32_t aScreenY, int32_t aClientX,
+                              int32_t aClientY, bool aCtrlKey, bool aAltKey,
+                              bool aShiftKey, bool aMetaKey, uint16_t aButton,
+                              EventTarget* aRelatedTarget,
+                              DataTransfer* aDataTransfer, ErrorResult& aError)
+{
+  aError =
+    nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable,
+                                    aView, aDetail, aScreenX, aScreenY,
+                                    aClientX, aClientY, aCtrlKey, aAltKey,
+                                    aShiftKey, aMetaKey, aButton,
+                                    aRelatedTarget);
+  if (aError.Failed()) {
+    return;
+  }
+
+  if (mEventIsInternal && mEvent) {
+    mEvent->AsDragEvent()->dataTransfer = aDataTransfer;
+  }
+}
+
 NS_IMETHODIMP
 nsDOMDragEvent::InitDragEvent(const nsAString & aType,
                               bool aCanBubble, bool aCancelable,
                               nsIDOMWindow* aView, int32_t aDetail,
                               int32_t aScreenX, int32_t aScreenY,
                               int32_t aClientX, int32_t aClientY, 
                               bool aCtrlKey, bool aAltKey, bool aShiftKey,
                               bool aMetaKey, uint16_t aButton,
                               nsIDOMEventTarget *aRelatedTarget,
                               nsIDOMDataTransfer* aDataTransfer)
 {
+  nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDataTransfer);
+  NS_ENSURE_ARG(dataTransfer);
+
   nsresult rv = nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable,
                   aView, aDetail, aScreenX, aScreenY, aClientX, aClientY,
                   aCtrlKey, aAltKey, aShiftKey, aMetaKey, aButton,
                   aRelatedTarget);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mEventIsInternal && mEvent) {
-    mEvent->AsDragEvent()->dataTransfer = aDataTransfer;
+    mEvent->AsDragEvent()->dataTransfer = dataTransfer;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDragEvent::GetDataTransfer(nsIDOMDataTransfer** aDataTransfer)
 {
   NS_IF_ADDREF(*aDataTransfer = GetDataTransfer());
   return NS_OK;
 }
 
-nsIDOMDataTransfer*
+DataTransfer*
 nsDOMDragEvent::GetDataTransfer()
 {
   // the dataTransfer field of the event caches the DataTransfer associated
   // with the drag. It is initialized when an attempt is made to retrieve it
   // rather that when the event is created to avoid duplicating the data when
   // no listener ever uses it.
   if (!mEvent || mEvent->eventStructType != NS_DRAG_EVENT) {
     NS_WARNING("Tried to get dataTransfer from non-drag event!");
@@ -84,15 +112,15 @@ nsDOMDragEvent::GetDataTransfer()
     nsresult rv = nsContentUtils::SetDataTransferInEvent(dragEvent);
     NS_ENSURE_SUCCESS(rv, nullptr);
   }
 
   return dragEvent->dataTransfer;
 }
 
 nsresult NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
-                            mozilla::dom::EventTarget* aOwner,
+                            EventTarget* aOwner,
                             nsPresContext* aPresContext,
                             WidgetDragEvent* aEvent) 
 {
   nsDOMDragEvent* event = new nsDOMDragEvent(aOwner, aPresContext, aEvent);
   return CallQueryInterface(event, aInstancePtrResult);
 }
--- a/dom/events/nsDOMDragEvent.h
+++ b/dom/events/nsDOMDragEvent.h
@@ -6,16 +6,22 @@
 #ifndef nsDOMDragEvent_h__
 #define nsDOMDragEvent_h__
 
 #include "nsIDOMDragEvent.h"
 #include "nsDOMMouseEvent.h"
 #include "mozilla/dom/DragEventBinding.h"
 #include "mozilla/EventForwards.h"
 
+namespace mozilla {
+namespace dom {
+class DataTransfer;
+}
+}
+
 class nsDOMDragEvent : public nsDOMMouseEvent,
                        public nsIDOMDragEvent
 {
 public:
   nsDOMDragEvent(mozilla::dom::EventTarget* aOwner,
                  nsPresContext* aPresContext,
                  mozilla::WidgetDragEvent* aEvent);
 
@@ -26,34 +32,28 @@ public:
   NS_FORWARD_TO_NSDOMMOUSEEVENT
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
     return mozilla::dom::DragEventBinding::Wrap(aCx, aScope, this);
   }
 
-  nsIDOMDataTransfer* GetDataTransfer();
+  mozilla::dom::DataTransfer* GetDataTransfer();
 
   void InitDragEvent(const nsAString& aType,
                      bool aCanBubble, bool aCancelable,
                      nsIDOMWindow* aView, int32_t aDetail,
                      int32_t aScreenX, int32_t aScreenY,
-                     int32_t aClientX, int32_t aClientY, 
+                     int32_t aClientX, int32_t aClientY,
                      bool aCtrlKey, bool aAltKey, bool aShiftKey,
                      bool aMetaKey, uint16_t aButton,
                      mozilla::dom::EventTarget* aRelatedTarget,
-                     nsIDOMDataTransfer* aDataTransfer,
-                     mozilla::ErrorResult& aRv)
-  {
-    aRv = InitDragEvent(aType, aCanBubble, aCancelable,
-                        aView, aDetail, aScreenX, aScreenY, aClientX, aClientY,
-                        aCtrlKey, aAltKey, aShiftKey, aMetaKey, aButton,
-                        aRelatedTarget, aDataTransfer);
-  }
+                     mozilla::dom::DataTransfer* aDataTransfer,
+                     mozilla::ErrorResult& aError);
 };
 
 nsresult NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
                             mozilla::dom::EventTarget* aOwner,
                             nsPresContext* aPresContext,
                             mozilla::WidgetDragEvent* aEvent);
 
 #endif // nsDOMDragEvent_h__
--- a/dom/events/nsEventStateManager.cpp
+++ b/dom/events/nsEventStateManager.cpp
@@ -65,17 +65,17 @@
 #include "nsEventDispatcher.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsITimer.h"
 #include "nsFontMetrics.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDragService.h"
 #include "nsIDragSession.h"
-#include "nsDOMDataTransfer.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "nsContentAreaDragDrop.h"
 #ifdef MOZ_XUL
 #include "nsTreeBodyFrame.h"
 #endif
 #include "nsIController.h"
 #include "nsICommandParams.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/HTMLLabelElement.h"
@@ -1089,16 +1089,21 @@ nsEventStateManager::PreHandleEvent(nsPr
         // then fall through...
       case WidgetMouseEvent::eRightButton:
       case WidgetMouseEvent::eMiddleButton:
         SetClickCount(aPresContext, mouseEvent, aStatus);
         break;
     }
     break;
   }
+  case NS_POINTER_CANCEL:
+  {
+    GenerateMouseEnterExit(mouseEvent);
+    break;
+  }
   case NS_MOUSE_EXIT:
     // If the event is not a top-level window exit, then it's not
     // really an exit --- we may have traversed widget boundaries but
     // we're still in our toplevel window.
     if (mouseEvent->exit != WidgetMouseEvent::eTopLevel) {
       // Treat it as a synthetic move so we don't generate spurious
       // "exit" or "move" events.  Any necessary "out" or "over" events
       // will be generated by GenerateMouseEnterExit
@@ -2101,35 +2106,42 @@ nsEventStateManager::GenerateDragGesture
     if (DeprecatedAbs(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
         DeprecatedAbs(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
       if (Prefs::ClickHoldContextMenu()) {
         // stop the click-hold before we fire off the drag gesture, in case
         // it takes a long time
         KillClickHoldTimer();
       }
 
-      nsRefPtr<nsDOMDataTransfer> dataTransfer =
-        new nsDOMDataTransfer(NS_DRAGDROP_START, false, -1);
-      if (!dataTransfer)
+      nsCOMPtr<nsISupports> container = aPresContext->GetContainerWeak();
+      nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
+      if (!window)
         return;
 
+      nsRefPtr<DataTransfer> dataTransfer =
+        new DataTransfer(window, NS_DRAGDROP_START, false, -1);
+
       nsCOMPtr<nsISelection> selection;
       nsCOMPtr<nsIContent> eventContent, targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
       if (eventContent)
-        DetermineDragTarget(aPresContext, eventContent, dataTransfer,
+        DetermineDragTarget(window, eventContent, dataTransfer,
                             getter_AddRefs(selection), getter_AddRefs(targetContent));
 
       // Stop tracking the drag gesture now. This should stop us from
       // reentering GenerateDragGesture inside DOM event processing.
       StopTrackingDragGesture();
 
       if (!targetContent)
         return;
 
+      // Use our targetContent, now that we've determined it, as the
+      // parent object of the DataTransfer.
+      dataTransfer->SetParentObject(targetContent);
+
       sLastDragOverFrame = nullptr;
       nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
 
       // get the widget from the target frame
       WidgetDragEvent startEvent(aEvent->mFlags.mIsTrusted,
                                  NS_DRAGDROP_START, widget);
       FillInEventFromGestureDown(&startEvent);
 
@@ -2203,38 +2215,33 @@ nsEventStateManager::GenerateDragGesture
 
     // Now flush all pending notifications, for better responsiveness
     // while dragging.
     FlushPendingEvents(aPresContext);
   }
 } // GenerateDragGesture
 
 void
-nsEventStateManager::DetermineDragTarget(nsPresContext* aPresContext,
+nsEventStateManager::DetermineDragTarget(nsPIDOMWindow* aWindow,
                                          nsIContent* aSelectionTarget,
-                                         nsDOMDataTransfer* aDataTransfer,
+                                         DataTransfer* aDataTransfer,
                                          nsISelection** aSelection,
                                          nsIContent** aTargetNode)
 {
   *aTargetNode = nullptr;
 
-  nsCOMPtr<nsISupports> container = aPresContext->GetContainerWeak();
-  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
-  if (!window)
-    return;
-
   // GetDragData determines if a selection, link or image in the content
   // should be dragged, and places the data associated with the drag in the
   // data transfer.
   // mGestureDownContent is the node where the mousedown event for the drag
   // occurred, and aSelectionTarget is the node to use when a selection is used
   bool canDrag;
   nsCOMPtr<nsIContent> dragDataNode;
   bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
-  nsresult rv = nsContentAreaDragDrop::GetDragData(window, mGestureDownContent,
+  nsresult rv = nsContentAreaDragDrop::GetDragData(aWindow, mGestureDownContent,
                                                    aSelectionTarget, wasAlt,
                                                    aDataTransfer, &canDrag, aSelection,
                                                    getter_AddRefs(dragDataNode));
   if (NS_FAILED(rv) || !canDrag)
     return;
 
   // if GetDragData returned a node, use that as the node being dragged.
   // Otherwise, if a selection is being dragged, use the node within the
@@ -2292,17 +2299,17 @@ nsEventStateManager::DetermineDragTarget
     *aTargetNode = dragContent;
     NS_ADDREF(*aTargetNode);
   }
 }
 
 bool
 nsEventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
                                         WidgetDragEvent* aDragEvent,
-                                        nsDOMDataTransfer* aDataTransfer,
+                                        DataTransfer* aDataTransfer,
                                         nsIContent* aDragTarget,
                                         nsISelection* aSelection)
 {
   nsCOMPtr<nsIDragService> dragService =
     do_GetService("@mozilla.org/widget/dragservice;1");
   if (!dragService)
     return false;
 
@@ -2325,49 +2332,46 @@ nsEventStateManager::DoDefaultDragStart(
     aDataTransfer->GetMozItemCount(&count);
   if (!count)
     return false;
 
   // Get the target being dragged, which may not be the same as the
   // target of the mouse event. If one wasn't set in the
   // aDataTransfer during the event handler, just use the original
   // target instead.
-  nsCOMPtr<nsIDOMNode> dragTarget;
-  nsCOMPtr<nsIDOMElement> dragTargetElement;
-  aDataTransfer->GetDragTarget(getter_AddRefs(dragTargetElement));
-  dragTarget = do_QueryInterface(dragTargetElement);
+  nsCOMPtr<Element> dragTarget = aDataTransfer->GetDragTarget();
   if (!dragTarget) {
     dragTarget = do_QueryInterface(aDragTarget);
     if (!dragTarget)
       return false;
   }
-  nsCOMPtr<nsIContent> content = do_QueryInterface(dragTarget);
 
   // check which drag effect should initially be used. If the effect was not
   // set, just use all actions, otherwise Windows won't allow a drop.
   uint32_t action;
   aDataTransfer->GetEffectAllowedInt(&action);
   if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
     action = nsIDragService::DRAGDROP_ACTION_COPY |
              nsIDragService::DRAGDROP_ACTION_MOVE |
              nsIDragService::DRAGDROP_ACTION_LINK;
 
   // get any custom drag image that was set
   int32_t imageX, imageY;
-  nsIDOMElement* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
-
-  nsCOMPtr<nsISupportsArray> transArray = aDataTransfer->GetTransferables(dragTarget);
+  Element* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
+
+  nsCOMPtr<nsISupportsArray> transArray =
+    aDataTransfer->GetTransferables(dragTarget->AsDOMNode());
   if (!transArray)
     return false;
 
   // XXXndeakin don't really want to create a new drag DOM event
   // here, but we need something to pass to the InvokeDragSession
   // methods.
   nsCOMPtr<nsIDOMEvent> domEvent;
-  NS_NewDOMDragEvent(getter_AddRefs(domEvent), content,
+  NS_NewDOMDragEvent(getter_AddRefs(domEvent), dragTarget,
                      aPresContext, aDragEvent);
 
   nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent);
   // if creating a drag event failed, starting a drag session will
   // just fail.
 
   // Use InvokeDragSessionWithSelection if a selection is being dragged,
   // such that the image can be generated from the selected text. However,
@@ -2382,29 +2386,33 @@ nsEventStateManager::DoDefaultDragStart(
     // if dragging within a XUL tree and no custom drag image was
     // set, the region argument to InvokeDragSessionWithImage needs
     // to be set to the area encompassing the selected rows of the
     // tree to ensure that the drag feedback gets clipped to those
     // rows. For other content, region should be null.
     nsCOMPtr<nsIScriptableRegion> region;
 #ifdef MOZ_XUL
     if (dragTarget && !dragImage) {
-      if (content->NodeInfo()->Equals(nsGkAtoms::treechildren,
-                                      kNameSpaceID_XUL)) {
-        nsTreeBodyFrame* treeBody = do_QueryFrame(content->GetPrimaryFrame());
+      if (dragTarget->NodeInfo()->Equals(nsGkAtoms::treechildren,
+                                         kNameSpaceID_XUL)) {
+        nsTreeBodyFrame* treeBody =
+          do_QueryFrame(dragTarget->GetPrimaryFrame());
         if (treeBody) {
           treeBody->GetSelectionRegion(getter_AddRefs(region));
         }
       }
     }
 #endif
 
-    dragService->InvokeDragSessionWithImage(dragTarget, transArray,
-                                            region, action, dragImage,
-                                            imageX, imageY, domDragEvent,
+    dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(), transArray,
+                                            region, action,
+                                            dragImage ? dragImage->AsDOMNode() :
+                                                        nullptr,
+                                            imageX,
+                                            imageY, domDragEvent,
                                             aDataTransfer);
   }
 
   return true;
 }
 
 nsresult
 nsEventStateManager::GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv)
@@ -4435,16 +4443,17 @@ nsEventStateManager::GenerateMouseEnterE
         targetElement = mDocument->GetRootElement();
       }
       if (targetElement) {
         NotifyMouseOver(aMouseEvent, targetElement);
       }
     }
     break;
   case NS_POINTER_LEAVE:
+  case NS_POINTER_CANCEL:
   case NS_MOUSE_EXIT:
     {
       // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
       OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
       if (helper->mLastOverFrame &&
           nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
--- a/dom/events/nsEventStateManager.h
+++ b/dom/events/nsEventStateManager.h
@@ -19,24 +19,24 @@
 #include "Units.h"
 
 class nsFrameLoader;
 class nsIContent;
 class nsIDocument;
 class nsIDocShell;
 class nsIDocShellTreeItem;
 class imgIContainer;
-class nsDOMDataTransfer;
 class EnterLeaveDispatcher;
 class nsIMarkupDocumentViewer;
 class nsIScrollableFrame;
 class nsITimer;
 
 namespace mozilla {
 namespace dom {
+class DataTransfer;
 class TabParent;
 }
 }
 
 class OverOutElementsWrapper MOZ_FINAL : public nsISupports
 {
 public:
   OverOutElementsWrapper() : mLastOverFrame(nullptr) {}
@@ -732,35 +732,35 @@ protected:
    * This is either the node clicked when there is a selection, or, for HTML,
    * the element with a draggable property set to true.
    *
    * aSelectionTarget - target to check for selection
    * aDataTransfer - data transfer object that will contain the data to drag
    * aSelection - [out] set to the selection to be dragged
    * aTargetNode - [out] the draggable node, or null if there isn't one
    */
-  void DetermineDragTarget(nsPresContext* aPresContext,
+  void DetermineDragTarget(nsPIDOMWindow* aWindow,
                            nsIContent* aSelectionTarget,
-                           nsDOMDataTransfer* aDataTransfer,
+                           mozilla::dom::DataTransfer* aDataTransfer,
                            nsISelection** aSelection,
                            nsIContent** aTargetNode);
 
   /*
    * Perform the default handling for the dragstart/draggesture event and set up a
    * drag for aDataTransfer if it contains any data. Returns true if a drag has
    * started.
    *
    * aDragEvent - the dragstart/draggesture event
    * aDataTransfer - the data transfer that holds the data to be dragged
    * aDragTarget - the target of the drag
    * aSelection - the selection to be dragged
    */
   bool DoDefaultDragStart(nsPresContext* aPresContext,
                           mozilla::WidgetDragEvent* aDragEvent,
-                          nsDOMDataTransfer* aDataTransfer,
+                          mozilla::dom::DataTransfer* aDataTransfer,
                           nsIContent* aDragTarget,
                           nsISelection* aSelection);
 
   bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nullptr; }
   /**
    * Set the fields of aEvent to reflect the mouse position and modifier keys
    * that were set when the user first pressed the mouse button (stored by
    * BeginTrackingDragGesture). aEvent->widget must be
--- a/dom/interfaces/events/nsIDOMDataTransfer.idl
+++ b/dom/interfaces/events/nsIDOMDataTransfer.idl
@@ -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 "domstubs.idl"
 
 interface nsIVariant;
 interface nsIDOMFileList;
 
-[scriptable, uuid(7D73CFBF-EC30-4F8E-B6A4-BB31EB943580)]
+[scriptable, builtinclass, uuid(4ba241dd-a964-4077-bc30-515a657772e4)]
 interface nsIDOMDataTransfer : nsISupports
 {
   /**
    * The actual effect that will be used, and should always be one of the
    * possible values of effectAllowed.
    *
    * For dragstart, drag and dragleave events, the dropEffect is initialized
    * to none. Any value assigned to the dropEffect will be set, but the value
@@ -224,19 +224,9 @@ interface nsIDOMDataTransfer : nsISuppor
    */
   [noscript] attribute unsigned long dropEffectInt;
 
   /*
    * Integer version of effectAllowed, set to one or a combination of the
    * constants in nsIDragService.
    */
   [noscript] attribute unsigned long effectAllowedInt;
-
-  /**
-   * Creates a copy of the data transfer object, for the given event type and
-   * user cancelled flag. If isCrossDomainSubFrameDrop is set, then this is a
-   * cross-domain drop from a subframe where access to the data should be
-   * prevented.
-   */
-  [noscript] nsIDOMDataTransfer clone(in uint32_t aEventType,
-                                      in boolean aUserCancelled,
-                                      in boolean isCrossDomainSubFrameDrop);
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -93,17 +93,17 @@
 #include "ProcessPriorityManager.h"
 #include "SandboxHal.h"
 #include "StructuredCloneUtils.h"
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/NeckoMessageUtils.h"
-#include "gfxPlatform.h"
+#include "gfxPrefs.h"
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #ifdef ANDROID
 # include "gfxAndroidPlatform.h"
 #endif
@@ -1547,17 +1547,17 @@ ContentParent::InitInternal(ProcessPrior
         // PBrowsers are created, because they rely on the Compositor
         // already being around.  (Creation is async, so can't happen
         // on demand.)
         bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
         if (useOffMainThreadCompositing) {
             DebugOnly<bool> opened = PCompositor::Open(this);
             MOZ_ASSERT(opened);
 
-            if (gfxPlatform::AsyncVideoEnabled()) {
+            if (gfxPrefs::AsyncVideoEnabled()) {
                 opened = PImageBridge::Open(this);
                 MOZ_ASSERT(opened);
             }
         }
     }
 
     if (aSendRegisteredChrome) {
         nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
--- a/dom/plugins/base/nsPluginNativeWindow.h
+++ b/dom/plugins/base/nsPluginNativeWindow.h
@@ -4,20 +4,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsPluginNativeWindow_h_
 #define _nsPluginNativeWindow_h_
 
 #include "nscore.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
+#include "nsISupportsImpl.h"
 #include "nsNPAPIPluginInstance.h"
 #include "npapi.h"
 #include "nsIWidget.h"
-#include "nsTraceRefcnt.h"
 
 /**
  * base class for native plugin window implementations
  */
 class nsPluginNativeWindow : public NPWindow
 {
 public: 
   nsPluginNativeWindow() : NPWindow() {
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -11812,17 +11812,19 @@ ICCIOHelperObject.prototype = {
                      " EF id = " + options.fileId.toString(16) +
                      " command = " + options.command.toString(16);
       if (options.sw1 && options.sw2) {
         errorMsg += "(" + options.sw1.toString(16) +
                     "/" + options.sw2.toString(16) + ")";
       }
       this.context.debug(errorMsg);
     }
-    onerror(requestError);
+    if (options.onerror) {
+      options.onerror(requestError);
+    }
   },
 };
 ICCIOHelperObject.prototype[ICC_COMMAND_SEEK] = null;
 ICCIOHelperObject.prototype[ICC_COMMAND_READ_BINARY] = function ICC_COMMAND_READ_BINARY(options) {
   this.processICCIOReadBinary(options);
 };
 ICCIOHelperObject.prototype[ICC_COMMAND_READ_RECORD] = function ICC_COMMAND_READ_RECORD(options) {
   this.processICCIOReadRecord(options);
@@ -12200,17 +12202,17 @@ ICCRecordHelperObject.prototype = {
 
     this.context.ICCIOHelper.updateLinearFixedEF({
       fileId: fileId,
       recordNumber: recordNumber,
       dataWriter: dataWriter,
       callback: onsuccess,
       onerror: onerror
     });
- },
+  },
 
   /**
    * Cache EF_ANR record size.
    */
   _anrRecordSize: null,
 
   /**
    * Read USIM/RUIM Phonebook EF_ANR.
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "Telephony.h"
 #include "mozilla/dom/TelephonyBinding.h"
+#include "mozilla/dom/Promise.h"
 
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 #include "nsIPermissionManager.h"
 
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/Preferences.h"
 #include "nsCharSeparatedTokenizer.h"
@@ -56,16 +57,54 @@ public:
   void
   Disconnect()
   {
     MOZ_ASSERT(mTelephony);
     mTelephony = nullptr;
   }
 };
 
+class Telephony::Callback : public nsITelephonyCallback
+{
+  nsRefPtr<Telephony> mTelephony;
+  nsRefPtr<Promise> mPromise;
+  uint32_t mServiceId;
+  nsString mNumber;
+
+public:
+  NS_DECL_ISUPPORTS
+
+  Callback(Telephony* aTelephony, Promise* aPromise, uint32_t aServiceId,
+           const nsAString& aNumber)
+    : mTelephony(aTelephony), mPromise(aPromise), mServiceId(aServiceId),
+      mNumber(aNumber)
+  {
+    MOZ_ASSERT(mTelephony);
+  }
+
+  virtual ~Callback() {}
+
+  NS_IMETHODIMP
+  NotifyDialError(const nsAString& aError)
+  {
+    mPromise->MaybeReject(aError);
+    return NS_OK;
+  }
+
+  NS_IMETHODIMP
+  NotifyDialSuccess()
+  {
+    nsRefPtr<TelephonyCall> call =
+      mTelephony->CreateNewDialingCall(mServiceId, mNumber);
+
+    mPromise->MaybeResolve(call);
+    return NS_OK;
+  }
+};
+
 class Telephony::EnumerationAck : public nsRunnable
 {
   nsRefPtr<Telephony> mTelephony;
 
 public:
   EnumerationAck(Telephony* aTelephony)
   : mTelephony(aTelephony)
   {
@@ -75,18 +114,17 @@ public:
   NS_IMETHOD Run()
   {
     mTelephony->NotifyCallsChanged(nullptr);
     return NS_OK;
   }
 };
 
 Telephony::Telephony(nsPIDOMWindow* aOwner)
-  : nsDOMEventTargetHelper(aOwner),
-    mActiveCall(nullptr), mEnumerated(false)
+  : nsDOMEventTargetHelper(aOwner), mActiveCall(nullptr), mEnumerated(false)
 {
   if (!gTelephonyList) {
     gTelephonyList = new TelephonyList();
   }
 
   gTelephonyList->AppendElement(this);
 }
 
@@ -230,73 +268,62 @@ Telephony::HasDialingCall()
 bool
 Telephony::MatchActiveCall(TelephonyCall* aCall)
 {
   return (mActiveCall &&
           mActiveCall->CallIndex() == aCall->CallIndex() &&
           mActiveCall->ServiceId() == aCall->ServiceId());
 }
 
-already_AddRefed<TelephonyCall>
+already_AddRefed<Promise>
 Telephony::DialInternal(uint32_t aServiceId, const nsAString& aNumber,
-                        bool aIsEmergency, ErrorResult& aRv)
+                        bool aIsEmergency)
 {
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = new Promise(global);
+
   if (!IsValidNumber(aNumber) || !IsValidServiceId(aServiceId)) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return nullptr;
+    promise->MaybeReject(NS_LITERAL_STRING("InvalidAccessError"));
+    return promise.forget();
   }
 
   // We only support one outgoing call at a time.
   if (HasDialingCall()) {
-    NS_WARNING("Only permitted to dial one call at a time!");
-    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
-    return nullptr;
-  }
-
-  nsresult rv = mProvider->Dial(aServiceId, aNumber, aIsEmergency);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return nullptr;
+    promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
+    return promise.forget();
   }
 
-  nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aServiceId, aNumber);
-
-  // Notify other telephony objects that we just dialed.
-  for (uint32_t i = 0; i < gTelephonyList->Length(); i++) {
-    Telephony*& telephony = gTelephonyList->ElementAt(i);
-    if (telephony != this) {
-      nsRefPtr<Telephony> kungFuDeathGrip = telephony;
-      telephony->NoteDialedCallFromOtherInstance(aServiceId, aNumber);
-    }
+  nsCOMPtr<nsITelephonyCallback> callback =
+    new Callback(this, promise, aServiceId, aNumber);
+  nsresult rv = mProvider->Dial(aServiceId, aNumber, aIsEmergency, callback);
+  if (NS_FAILED(rv)) {
+    promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
+    return promise.forget();
   }
 
-  return call.forget();
+  return promise.forget();
 }
 
 already_AddRefed<TelephonyCall>
 Telephony::CreateNewDialingCall(uint32_t aServiceId, const nsAString& aNumber)
 {
   nsRefPtr<TelephonyCall> call =
     TelephonyCall::Create(this, aServiceId, aNumber,
                           nsITelephonyProvider::CALL_STATE_DIALING);
   NS_ASSERTION(call, "This should never fail!");
 
   NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
 
   return call.forget();
 }
 
-void
-Telephony::NoteDialedCallFromOtherInstance(uint32_t aServiceId,
-                                           const nsAString& aNumber)
-{
-  // We don't need to hang on to this call object, it is held alive by mCalls.
-  nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aServiceId, aNumber);
-}
-
 nsresult
 Telephony::NotifyCallsChanged(TelephonyCall* aCall)
 {
   return DispatchCallEvent(NS_LITERAL_STRING("callschanged"), aCall);
 }
 
 void
 Telephony::UpdateActiveCall(TelephonyCall* aCall, bool aIsActive)
@@ -377,36 +404,35 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Telephony)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(Telephony, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(Telephony, nsDOMEventTargetHelper)
 
 NS_IMPL_ISUPPORTS1(Telephony::Listener, nsITelephonyListener)
+NS_IMPL_ISUPPORTS1(Telephony::Callback, nsITelephonyCallback)
 
 // Telephony WebIDL
 
-already_AddRefed<TelephonyCall>
-Telephony::Dial(const nsAString& aNumber, const Optional<uint32_t>& aServiceId,
-                ErrorResult& aRv)
+already_AddRefed<Promise>
+Telephony::Dial(const nsAString& aNumber, const Optional<uint32_t>& aServiceId)
 {
   uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
-  nsRefPtr<TelephonyCall> call = DialInternal(serviceId, aNumber, false, aRv);
-  return call.forget();
+  nsRefPtr<Promise> promise = DialInternal(serviceId, aNumber, false);
+  return promise.forget();
 }
 
-already_AddRefed<TelephonyCall>
+already_AddRefed<Promise>
 Telephony::DialEmergency(const nsAString& aNumber,
-                         const Optional<uint32_t>& aServiceId,
-                         ErrorResult& aRv)
+                         const Optional<uint32_t>& aServiceId)
 {
   uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
-  nsRefPtr<TelephonyCall> call = DialInternal(serviceId, aNumber, true, aRv);
-  return call.forget();
+  nsRefPtr<Promise> promise = DialInternal(serviceId, aNumber, true);
+  return promise.forget();
 }
 
 void
 Telephony::StartTone(const nsAString& aDTMFChar,
                      const Optional<uint32_t>& aServiceId,
                      ErrorResult& aRv)
 {
   uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
@@ -639,17 +665,17 @@ Telephony::EnumerateCallState(uint32_t a
 }
 
 NS_IMETHODIMP
 Telephony::SupplementaryServiceNotification(uint32_t aServiceId,
                                             int32_t aCallIndex,
                                             uint16_t aNotification)
 {
   nsRefPtr<TelephonyCall> associatedCall;
-  if (!mCalls.IsEmpty() && aCallIndex != -1) {
+  if (!mCalls.IsEmpty()) {
     associatedCall = GetCall(aServiceId, aCallIndex);
   }
 
   nsresult rv;
   switch (aNotification) {
     case nsITelephonyProvider::NOTIFICATION_REMOTE_HELD:
       rv = DispatchCallEvent(NS_LITERAL_STRING("remoteheld"), associatedCall);
       break;
@@ -670,21 +696,17 @@ Telephony::NotifyError(uint32_t aService
                        int32_t aCallIndex,
                        const nsAString& aError)
 {
   if (mCalls.IsEmpty()) {
     NS_ERROR("No existing call!");
     return NS_ERROR_UNEXPECTED;
   }
 
-  nsRefPtr<TelephonyCall> callToNotify;
-
-  callToNotify = (aCallIndex == -1) ? GetOutgoingCall()
-                                    : GetCall(aServiceId, aCallIndex);
-
+  nsRefPtr<TelephonyCall> callToNotify = GetCall(aServiceId, aCallIndex);
   if (!callToNotify) {
     NS_ERROR("Don't call me with a bad call index!");
     return NS_ERROR_UNEXPECTED;
   }
 
   UpdateActiveCall(callToNotify, false);
 
   // Set the call state to 'disconnected' and remove it from the calls list.
--- a/dom/telephony/Telephony.h
+++ b/dom/telephony/Telephony.h
@@ -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/. */
 
 #ifndef mozilla_dom_telephony_telephony_h__
 #define mozilla_dom_telephony_telephony_h__
 
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/Promise.h"
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 
 #include "nsITelephonyProvider.h"
 
 // Need to include TelephonyCall.h because we have inline methods that
 // assume they see the definition of TelephonyCall.
 #include "TelephonyCall.h"
 
@@ -29,16 +30,19 @@ class Telephony MOZ_FINAL : public nsDOM
    * Class Telephony doesn't actually inherit nsITelephonyListener.
    * Instead, it owns an nsITelephonyListener derived instance mListener
    * and passes it to nsITelephonyProvider. The onreceived events are first
    * delivered to mListener and then forwarded to its owner, Telephony. See
    * also bug 775997 comment #51.
    */
   class Listener;
 
+  class Callback;
+  friend class Callback;
+
   class EnumerationAck;
   friend class EnumerationAck;
 
   nsCOMPtr<nsITelephonyProvider> mProvider;
   nsRefPtr<Listener> mListener;
 
   TelephonyCall* mActiveCall;
   nsTArray<nsRefPtr<TelephonyCall> > mCalls;
@@ -61,23 +65,21 @@ public:
     return GetOwner();
   }
 
   // WrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
-  already_AddRefed<TelephonyCall>
-  Dial(const nsAString& aNumber, const Optional<uint32_t>& aServiceId,
-       ErrorResult& aRv);
+  already_AddRefed<Promise>
+  Dial(const nsAString& aNumber, const Optional<uint32_t>& aServiceId);
 
-  already_AddRefed<TelephonyCall>
-  DialEmergency(const nsAString& aNumber, const Optional<uint32_t>& aServiceId,
-                ErrorResult& aRv);
+  already_AddRefed<Promise>
+  DialEmergency(const nsAString& aNumber, const Optional<uint32_t>& aServiceId);
 
   void
   StartTone(const nsAString& aDTMFChar, const Optional<uint32_t>& aServiceId,
             ErrorResult& aRv);
 
   void
   StopTone(const Optional<uint32_t>& aServiceId, ErrorResult& aRv);
 
@@ -165,27 +167,22 @@ private:
   ProvidedOrDefaultServiceId(const Optional<uint32_t>& aServiceId);
 
   bool
   HasDialingCall();
 
   bool
   MatchActiveCall(TelephonyCall* aCall);
 
-  already_AddRefed<TelephonyCall>
-  DialInternal(uint32_t aServiceId, const nsAString& aNumber,
-               bool isEmergency, ErrorResult& aRv);
+  already_AddRefed<Promise>
+  DialInternal(uint32_t aServiceId, const nsAString& aNumber, bool isEmergency);
 
   already_AddRefed<TelephonyCall>
   CreateNewDialingCall(uint32_t aServiceId, const nsAString& aNumber);
 
-  void
-  NoteDialedCallFromOtherInstance(uint32_t aServiceId,
-                                  const nsAString& aNumber);
-
   nsresult
   NotifyCallsChanged(TelephonyCall* aCall);
 
   nsresult
   DispatchCallEvent(const nsAString& aType, TelephonyCall* aCall);
 
   void
   EnqueueEnumerationAck();
--- a/dom/telephony/gonk/TelephonyProvider.js
+++ b/dom/telephony/gonk/TelephonyProvider.js
@@ -395,44 +395,54 @@ TelephonyProvider.prototype = {
     for (let i = 0; i < this._numClients; ++i) {
       promise = promise.then(this._enumerateCallsForClient.bind(this, i, aListener));
     }
     promise.then(function() {
       aListener.enumerateCallStateComplete();
     });
   },
 
-  dial: function(aClientId, aNumber, aIsEmergency) {
+  isDialing: false,
+  dial: function(aClientId, aNumber, aIsEmergency, aTelephonyCallback) {
     if (DEBUG) debug("Dialing " + (aIsEmergency ? "emergency " : "") + aNumber);
 
+    if (this.isDialing) {
+      if (DEBUG) debug("Already has a dialing call. Drop.");
+      aTelephonyCallback.notifyDialError("InvalidStateError");
+      return;
+    }
+
     // we don't try to be too clever here, as the phone is probably in the
     // locked state. Let's just check if it's a number without normalizing
     if (!aIsEmergency) {
       aNumber = gPhoneNumberUtils.normalize(aNumber);
     }
 
+    // Validate the number.
     if (!gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
       // Note: isPlainPhoneNumber also accepts USSD and SS numbers
       if (DEBUG) debug("Number '" + aNumber + "' is not viable. Drop.");
       let errorMsg = RIL.RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[RIL.CALL_FAIL_UNOBTAINABLE_NUMBER];
-      Services.tm.currentThread.dispatch(
-        this.notifyCallError.bind(this, aClientId, -1, errorMsg),
-        Ci.nsIThread.DISPATCH_NORMAL);
+      aTelephonyCallback.notifyDialError(errorMsg);
       return;
     }
 
+    this.isDialing = true;
     this._getClient(aClientId).sendWorkerMessage("dial", {
       number: aNumber,
       isDialEmergency: aIsEmergency
-    }, (function(clientId, response) {
-      if (!response.success) {
-        this.notifyCallError(clientId, -1, response.errorMsg);
+    }, (function(response) {
+      this.isDialing = false;
+      if (response.success) {
+        aTelephonyCallback.notifyDialSuccess();
+      } else {
+        aTelephonyCallback.notifyDialError(response.errorMsg);
       }
       return false;
-    }).bind(this, aClientId));
+    }).bind(this));
   },
 
   hangUp: function(aClientId, aCallIndex) {
     this._getClient(aClientId).sendWorkerMessage("hangUp", { callIndex: aCallIndex });
   },
 
   startTone: function(aClientId, aDtmfChar) {
     this._getClient(aClientId).sendWorkerMessage("startTone", { dtmfChar: aDtmfChar });
--- a/dom/telephony/ipc/PTelephony.ipdl
+++ b/dom/telephony/ipc/PTelephony.ipdl
@@ -7,16 +7,34 @@
 include protocol PContent;
 include protocol PTelephonyRequest;
 include TelephonyTypes;
 
 namespace mozilla {
 namespace dom {
 namespace telephony {
 
+struct EnumerateCallsRequest
+{
+  // empty.
+};
+
+struct DialRequest
+{
+  uint32_t clientId;
+  nsString number;
+  bool isEmergency;
+};
+
+union IPCTelephonyRequest
+{
+  EnumerateCallsRequest;
+  DialRequest;
+};
+
 sync protocol PTelephony {
   manager PContent;
   manages PTelephonyRequest;
 
 child:
   NotifyCallError(uint32_t aClientId, int32_t aCallIndex, nsString aError);
 
   NotifyCallStateChanged(uint32_t aClientId, IPCCallStateData aData);
@@ -32,27 +50,24 @@ child:
 
 parent:
   /**
    * Sent when the child no longer needs to use PTelephony.
    */
   __delete__();
 
   /**
-   * Sent when the child makes an asynchronous request to the parent.  It's
-   * currently only for request call enumeration.
+   * Sent when the child makes an asynchronous request to the parent.
    */
-  PTelephonyRequest();
+  PTelephonyRequest(IPCTelephonyRequest request);
 
   RegisterListener();
 
   UnregisterListener();
 
-  DialCall(uint32_t aClientId, nsString aNumber, bool aIsEmergency);
-
   HangUpCall(uint32_t aClientId, uint32_t aCallIndex);
 
   AnswerCall(uint32_t aClientId, uint32_t aCallIndex);
 
   RejectCall(uint32_t aClientId, uint32_t aCallIndex);
 
   HoldCall(uint32_t aClientId, uint32_t aCallIndex);
 
--- a/dom/telephony/ipc/PTelephonyRequest.ipdl
+++ b/dom/telephony/ipc/PTelephonyRequest.ipdl
@@ -6,25 +6,44 @@
 
 include protocol PTelephony;
 include TelephonyTypes;
 
 namespace mozilla {
 namespace dom {
 namespace telephony {
 
+struct EnumerateCallsResponse
+{
+  // empty.
+};
+
+struct DialResponse
+{
+  // empty.
+};
+
+union IPCTelephonyResponse
+{
+  EnumerateCallsResponse;
+  DialResponse;
+};
+
 protocol PTelephonyRequest
 {
   manager PTelephony;
 
 child:
   NotifyEnumerateCallState(uint32_t aClientId, IPCCallStateData aData);
 
+  NotifyDialError(nsString aError);
+
+  NotifyDialSuccess();
+
   /**
-   * Sent when the asynchronous request has completed. It's currently only for
-   * request call enumeration.
+   * Sent when the asynchronous request has completed.
    */
-  __delete__();
+  __delete__(IPCTelephonyResponse aResponse);
 };
 
 } /* namespace telephony */
 } /* namespace dom */
 } /* namespace mozilla */
--- a/dom/telephony/ipc/TelephonyChild.cpp
+++ b/dom/telephony/ipc/TelephonyChild.cpp
@@ -19,17 +19,17 @@ TelephonyChild::TelephonyChild(nsITeleph
 
 void
 TelephonyChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mListener = nullptr;
 }
 
 PTelephonyRequestChild*
-TelephonyChild::AllocPTelephonyRequestChild()
+TelephonyChild::AllocPTelephonyRequestChild(const IPCTelephonyRequest& aRequest)
 {
   MOZ_CRASH("Caller is supposed to manually construct a request!");
 }
 
 bool
 TelephonyChild::DeallocPTelephonyRequestChild(PTelephonyRequestChild* aActor)
 {
   delete aActor;
@@ -104,34 +104,43 @@ TelephonyChild::RecvNotifySupplementaryS
                                               aNotification);
   return true;
 }
 
 /*******************************************************************************
  * TelephonyRequestChild
  ******************************************************************************/
 
-TelephonyRequestChild::TelephonyRequestChild(nsITelephonyListener* aListener)
-  : mListener(aListener)
+TelephonyRequestChild::TelephonyRequestChild(nsITelephonyListener* aListener,
+                                             nsITelephonyCallback* aCallback)
+  : mListener(aListener), mCallback(aCallback)
 {
-  MOZ_ASSERT(aListener);
 }
 
 void
 TelephonyRequestChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mListener = nullptr;
+  mCallback = nullptr;
 }
 
 bool
-TelephonyRequestChild::Recv__delete__()
+TelephonyRequestChild::Recv__delete__(const IPCTelephonyResponse& aResponse)
 {
-  MOZ_ASSERT(mListener);
+  switch (aResponse.type()) {
+    case IPCTelephonyResponse::TEnumerateCallsResponse:
+      mListener->EnumerateCallStateComplete();
+      break;
+    case IPCTelephonyResponse::TDialResponse:
+      // Do nothing.
+      break;
+    default:
+      MOZ_CRASH("Unknown type!");
+  }
 
-  mListener->EnumerateCallStateComplete();
   return true;
 }
 
 bool
 TelephonyRequestChild::RecvNotifyEnumerateCallState(const uint32_t& aClientId,
                                                     const IPCCallStateData& aData)
 {
   MOZ_ASSERT(mListener);
@@ -141,8 +150,26 @@ TelephonyRequestChild::RecvNotifyEnumera
                                 aData.callState(),
                                 aData.number(),
                                 aData.isActive(),
                                 aData.isOutGoing(),
                                 aData.isEmergency(),
                                 aData.isConference());
   return true;
 }
+
+bool
+TelephonyRequestChild::RecvNotifyDialError(const nsString& aError)
+{
+  MOZ_ASSERT(mCallback);
+
+  mCallback->NotifyDialError(aError);
+  return true;
+}
+
+bool
+TelephonyRequestChild::RecvNotifyDialSuccess()
+{
+  MOZ_ASSERT(mCallback);
+
+  mCallback->NotifyDialSuccess();
+  return true;
+}
--- a/dom/telephony/ipc/TelephonyChild.h
+++ b/dom/telephony/ipc/TelephonyChild.h
@@ -20,17 +20,17 @@ public:
 
 protected:
   virtual ~TelephonyChild() {}
 
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual PTelephonyRequestChild*
-  AllocPTelephonyRequestChild() MOZ_OVERRIDE;
+  AllocPTelephonyRequestChild(const IPCTelephonyRequest& aRequest) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPTelephonyRequestChild(PTelephonyRequestChild* aActor) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyCallError(const uint32_t& aClientId, const int32_t& aCallIndex,
                       const nsString& aError) MOZ_OVERRIDE;
 
@@ -56,30 +56,38 @@ protected:
 
 private:
   nsCOMPtr<nsITelephonyListener> mListener;
 };
 
 class TelephonyRequestChild : public PTelephonyRequestChild
 {
 public:
-  TelephonyRequestChild(nsITelephonyListener* aListener);
+  TelephonyRequestChild(nsITelephonyListener* aListener,
+                        nsITelephonyCallback* aCallback);
 
 protected:
   virtual ~TelephonyRequestChild() {}
 
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
-  Recv__delete__() MOZ_OVERRIDE;
+  Recv__delete__(const IPCTelephonyResponse& aResponse) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyEnumerateCallState(const uint32_t& aClientId,
                                const IPCCallStateData& aData) MOZ_OVERRIDE;
 
+  virtual bool
+  RecvNotifyDialError(const nsString& aError) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyDialSuccess() MOZ_OVERRIDE;
+
 private:
   nsCOMPtr<nsITelephonyListener> mListener;
+  nsCOMPtr<nsITelephonyCallback> mCallback;
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif // mozilla_dom_telephony_TelephonyChild_h
--- a/dom/telephony/ipc/TelephonyIPCProvider.cpp
+++ b/dom/telephony/ipc/TelephonyIPCProvider.cpp
@@ -112,32 +112,40 @@ TelephonyIPCProvider::UnregisterListener
   mListeners.RemoveElement(aListener);
 
   if (!mListeners.Length()) {
     mPTelephonyChild->SendUnregisterListener();
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TelephonyIPCProvider::EnumerateCalls(nsITelephonyListener *aListener)
+nsresult
+TelephonyIPCProvider::SendRequest(nsITelephonyListener *aListener,
+                                  nsITelephonyCallback *aCallback,
+                                  const IPCTelephonyRequest& aRequest)
 {
   // Life time of newly allocated TelephonyRequestChild instance is managed by
   // IPDL itself.
-  TelephonyRequestChild* actor = new TelephonyRequestChild(aListener);
-  mPTelephonyChild->SendPTelephonyRequestConstructor(actor);
+  TelephonyRequestChild* actor = new TelephonyRequestChild(aListener, aCallback);
+  mPTelephonyChild->SendPTelephonyRequestConstructor(actor, aRequest);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TelephonyIPCProvider::Dial(uint32_t aClientId, const nsAString& aNumber,
-                           bool aIsEmergency)
+TelephonyIPCProvider::EnumerateCalls(nsITelephonyListener *aListener)
 {
-  mPTelephonyChild->SendDialCall(aClientId, nsString(aNumber), aIsEmergency);
-  return NS_OK;
+  return SendRequest(aListener, nullptr, EnumerateCallsRequest());
+}
+
+NS_IMETHODIMP
+TelephonyIPCProvider::Dial(uint32_t aClientId, const nsAString& aNumber,
+                           bool aIsEmergency, nsITelephonyCallback *aCallback)
+{
+  return SendRequest(nullptr, aCallback,
+                     DialRequest(aClientId, nsString(aNumber), aIsEmergency));
 }
 
 NS_IMETHODIMP
 TelephonyIPCProvider::HangUp(uint32_t aClientId, uint32_t aCallIndex)
 {
   mPTelephonyChild->SendHangUpCall(aClientId, aCallIndex);
   return NS_OK;
 }
--- a/dom/telephony/ipc/TelephonyIPCProvider.h
+++ b/dom/telephony/ipc/TelephonyIPCProvider.h
@@ -8,16 +8,17 @@
 
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 #include "mozilla/Attributes.h"
 #include "nsIObserver.h"
 #include "nsITelephonyProvider.h"
 
 BEGIN_TELEPHONY_NAMESPACE
 
+struct IPCTelephonyRequest;
 class PTelephonyChild;
 
 class TelephonyIPCProvider MOZ_FINAL : public nsITelephonyProvider
                                      , public nsITelephonyListener
                                      , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
@@ -29,13 +30,17 @@ public:
 
 protected:
   virtual ~TelephonyIPCProvider();
 
 private:
   nsTArray<nsCOMPtr<nsITelephonyListener> > mListeners;
   PTelephonyChild* mPTelephonyChild;
   uint32_t mDefaultServiceId;
+
+  nsresult SendRequest(nsITelephonyListener *aListener,
+                       nsITelephonyCallback *aCallback,
+                       const IPCTelephonyRequest& aRequest);
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif // mozilla_dom_telephony_TelephonyIPCProvider_h
--- a/dom/telephony/ipc/TelephonyParent.cpp
+++ b/dom/telephony/ipc/TelephonyParent.cpp
@@ -28,25 +28,35 @@ TelephonyParent::ActorDestroy(ActorDestr
   // an error here to avoid sending a message to the dead process.
   mActorDestroyed = true;
 
   // Try to unregister listener if we're still registered.
   RecvUnregisterListener();
 }
 
 bool
-TelephonyParent::RecvPTelephonyRequestConstructor(PTelephonyRequestParent* aActor)
+TelephonyParent::RecvPTelephonyRequestConstructor(PTelephonyRequestParent* aActor,
+                                                  const IPCTelephonyRequest& aRequest)
 {
   TelephonyRequestParent* actor = static_cast<TelephonyRequestParent*>(aActor);
 
-  return actor->DoRequest();
+  switch (aRequest.type()) {
+    case IPCTelephonyRequest::TEnumerateCallsRequest:
+      return actor->DoRequest(aRequest.get_EnumerateCallsRequest());
+    case IPCTelephonyRequest::TDialRequest:
+      return actor->DoRequest(aRequest.get_DialRequest());
+    default:
+      MOZ_CRASH("Unknown type!");
+  }
+
+  return false;
 }
 
 PTelephonyRequestParent*
-TelephonyParent::AllocPTelephonyRequestParent()
+TelephonyParent::AllocPTelephonyRequestParent(const IPCTelephonyRequest& aRequest)
 {
   TelephonyRequestParent* actor = new TelephonyRequestParent();
   // Add an extra ref for IPDL. Will be released in
   // TelephonyParent::DeallocPTelephonyRequestParent().
   NS_ADDREF(actor);
 
   return actor;
 }
@@ -87,29 +97,16 @@ TelephonyParent::RecvUnregisterListener(
     do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
   NS_ENSURE_TRUE(provider, true);
 
   mRegistered = !NS_SUCCEEDED(provider->UnregisterListener(this));
   return true;
 }
 
 bool
-TelephonyParent::RecvDialCall(const uint32_t& aClientId,
-                              const nsString& aNumber,
-                              const bool& aIsEmergency)
-{
-  nsCOMPtr<nsITelephonyProvider> provider =
-    do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, true);
-
-  provider->Dial(aClientId, aNumber, aIsEmergency);
-  return true;
-}
-
-bool
 TelephonyParent::RecvHangUpCall(const uint32_t& aClientId,
                                 const uint32_t& aCallIndex)
 {
   nsCOMPtr<nsITelephonyProvider> provider =
     do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
   NS_ENSURE_TRUE(provider, true);
 
   provider->HangUp(aClientId, aCallIndex);
@@ -367,50 +364,67 @@ TelephonyParent::SupplementaryServiceNot
   return SendNotifySupplementaryService(aClientId, aCallIndex, aNotification)
       ? NS_OK : NS_ERROR_FAILURE;
 }
 
 /*******************************************************************************
  * TelephonyRequestParent
  ******************************************************************************/
 
-NS_IMPL_ISUPPORTS1(TelephonyRequestParent, nsITelephonyListener)
+NS_IMPL_ISUPPORTS2(TelephonyRequestParent,
+                   nsITelephonyListener,
+                   nsITelephonyCallback)
 
 TelephonyRequestParent::TelephonyRequestParent()
   : mActorDestroyed(false)
 {
 }
 
 void
 TelephonyRequestParent::ActorDestroy(ActorDestroyReason why)
 {
   // The child process could die before this asynchronous notification, in which
   // case ActorDestroy() was called and mActorDestroyed is set to true. Return
   // an error here to avoid sending a message to the dead process.
   mActorDestroyed = true;
 }
 
 bool
-TelephonyRequestParent::DoRequest()
+TelephonyRequestParent::DoRequest(const EnumerateCallsRequest& aRequest)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
   nsCOMPtr<nsITelephonyProvider> provider =
     do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
   if (provider) {
     rv = provider->EnumerateCalls(this);
   }
 
   if (NS_FAILED(rv)) {
     return NS_SUCCEEDED(EnumerateCallStateComplete());
   }
 
   return true;
 }
 
+bool
+TelephonyRequestParent::DoRequest(const DialRequest& aRequest)
+{
+  nsCOMPtr<nsITelephonyProvider> provider =
+    do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
+  if (provider) {
+    provider->Dial(aRequest.clientId(), aRequest.number(),
+                   aRequest.isEmergency(), this);
+  } else {
+    return NS_SUCCEEDED(NotifyDialError(NS_LITERAL_STRING("InvalidStateError")));
+  }
+
+  return true;
+}
+
 // nsITelephonyListener
 
 NS_IMETHODIMP
 TelephonyRequestParent::CallStateChanged(uint32_t aClientId,
                                          uint32_t aCallIndex,
                                          uint16_t aCallState,
                                          const nsAString& aNumber,
                                          bool aIsActive,
@@ -427,17 +441,17 @@ TelephonyRequestParent::ConferenceCallSt
   MOZ_CRASH("Not a TelephonyParent!");
 }
 
 NS_IMETHODIMP
 TelephonyRequestParent::EnumerateCallStateComplete()
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
-  return Send__delete__(this) ? NS_OK : NS_ERROR_FAILURE;
+  return Send__delete__(this, EnumerateCallsResponse()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 TelephonyRequestParent::EnumerateCallState(uint32_t aClientId,
                                            uint32_t aCallIndex,
                                            uint16_t aCallState,
                                            const nsAString& aNumber,
                                            bool aIsActive,
@@ -477,8 +491,28 @@ TelephonyRequestParent::NotifyError(uint
 
 NS_IMETHODIMP
 TelephonyRequestParent::SupplementaryServiceNotification(uint32_t aClientId,
                                                          int32_t aCallIndex,
                                                          uint16_t aNotification)
 {
   MOZ_CRASH("Not a TelephonyParent!");
 }
+
+// nsITelephonyCallback
+
+NS_IMETHODIMP
+TelephonyRequestParent::NotifyDialError(const nsAString& aError)
+{
+  NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
+
+  return (SendNotifyDialError(nsString(aError)) &&
+          Send__delete__(this, DialResponse())) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+TelephonyRequestParent::NotifyDialSuccess()
+{
+  NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
+
+  return (SendNotifyDialSuccess() &&
+          Send__delete__(this, DialResponse())) ? NS_OK : NS_ERROR_FAILURE;
+}
--- a/dom/telephony/ipc/TelephonyParent.h
+++ b/dom/telephony/ipc/TelephonyParent.h
@@ -24,37 +24,34 @@ public:
 
 protected:
   virtual ~TelephonyParent() {}
 
   virtual void
   ActorDestroy(ActorDestroyReason why);
 
   virtual bool
-  RecvPTelephonyRequestConstructor(PTelephonyRequestParent* aActor) MOZ_OVERRIDE;
+  RecvPTelephonyRequestConstructor(PTelephonyRequestParent* aActor, const IPCTelephonyRequest& aRequest) MOZ_OVERRIDE;
 
   virtual PTelephonyRequestParent*
-  AllocPTelephonyRequestParent() MOZ_OVERRIDE;
+  AllocPTelephonyRequestParent(const IPCTelephonyRequest& aRequest) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPTelephonyRequestParent(PTelephonyRequestParent* aActor) MOZ_OVERRIDE;
 
   virtual bool
   Recv__delete__() MOZ_OVERRIDE;
 
   virtual bool
   RecvRegisterListener() MOZ_OVERRIDE;
 
   virtual bool
   RecvUnregisterListener() MOZ_OVERRIDE;
 
   virtual bool
-  RecvDialCall(const uint32_t& aClientId, const nsString& aNumber, const bool& aIsEmergency) MOZ_OVERRIDE;
-
-  virtual bool
   RecvHangUpCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
 
   virtual bool
   RecvAnswerCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
 
   virtual bool
   RecvRejectCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
 
@@ -96,32 +93,37 @@ protected:
 
 private:
   bool mActorDestroyed;
   bool mRegistered;
 };
 
 class TelephonyRequestParent : public PTelephonyRequestParent
                              , public nsITelephonyListener
+                             , public nsITelephonyCallback
 {
   friend class TelephonyParent;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITELEPHONYLISTENER
+  NS_DECL_NSITELEPHONYCALLBACK
 
 protected:
   TelephonyRequestParent();
   virtual ~TelephonyRequestParent() {}
 
   virtual void
   ActorDestroy(ActorDestroyReason why);
 
 private:
   bool mActorDestroyed;
 
   bool
-  DoRequest();
+  DoRequest(const EnumerateCallsRequest& aRequest);
+
+  bool
+  DoRequest(const DialRequest& aRequest);
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif /* mozilla_dom_telephony_TelephonyParent_h */
--- a/dom/telephony/nsITelephonyProvider.idl
+++ b/dom/telephony/nsITelephonyProvider.idl
@@ -127,28 +127,44 @@ interface nsITelephonyListener : nsISupp
    *        Error name. Possible values are addError and removeError.
    * @param message
    *        Detailed error message from RIL.
    */
   void notifyConferenceError(in AString name,
                              in AString message);
 };
 
+[scriptable, uuid(c095aa82-aacb-4e53-a787-56a89c3f638e)]
+interface nsITelephonyCallback : nsISupports
+{
+  /**
+   * Called when a dial request fails.
+   * @param error
+   *        Error from RIL.
+   */
+  void notifyDialError(in AString error);
+
+  /**
+   * Called when a dial request succeeds.
+   */
+  void notifyDialSuccess();
+};
+
 %{C++
 #define TELEPHONY_PROVIDER_CID \
   { 0x9cf8aa52, 0x7c1c, 0x4cde, { 0x97, 0x4e, 0xed, 0x2a, 0xa0, 0xe7, 0x35, 0xfa } }
 #define TELEPHONY_PROVIDER_CONTRACTID \
   "@mozilla.org/telephony/telephonyprovider;1"
 %}
 
 /**
  * XPCOM component (in the content process) that provides the telephony
  * information.
  */
-[scriptable, uuid(4ff3ecb7-b024-4752-9dd6-c3623c6e6b8a)]
+[scriptable, uuid(b16ca98f-994f-4ae1-8c2d-e7b18e08d1f3)]
 interface nsITelephonyProvider : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_ALERTING = 2;
   const unsigned short CALL_STATE_CONNECTING = 3;
   const unsigned short CALL_STATE_CONNECTED = 4;
   const unsigned short CALL_STATE_HOLDING = 5;
@@ -176,17 +192,17 @@ interface nsITelephonyProvider : nsISupp
    * returns false.
    */
   void enumerateCalls(in nsITelephonyListener listener);
 
   /**
    * Functionality for making and managing phone calls.
    */
   void dial(in unsigned long clientId, in DOMString number,
-            in boolean isEmergency);
+            in boolean isEmergency, in nsITelephonyCallback callback);
   void hangUp(in unsigned long clientId, in unsigned long callIndex);
 
   void startTone(in unsigned long clientId, in DOMString dtmfChar);
   void stopTone(in unsigned long clientId);
 
   void answerCall(in unsigned long clientId, in unsigned long callIndex);
   void rejectCall(in unsigned long clientId, in unsigned long callIndex);
   void holdCall(in unsigned long clientId, in unsigned long callIndex);
--- a/dom/telephony/test/marionette/test_audiomanager_phonestate.js
+++ b/dom/telephony/test/marionette/test_audiomanager_phonestate.js
@@ -44,28 +44,29 @@ function checkEventCallState(event, call
   is(call, event.call, "event.call");
   is(call.state, state, "call state");
 }
 
 function dial(number) {
   log("Make an outgoing call: " + number);
 
   let deferred = Promise.defer();
-  let call = telephony.dial(number);
 
-  ok(call);
-  is(call.number, number);
-  is(call.state, "dialing");
+  telephony.dial(number).then(call => {
+    ok(call);
+    is(call.number, number);
+    is(call.state, "dialing");
 
-  call.onalerting = function onalerting(event) {
-    call.onalerting = null;
-    log("Received 'onalerting' call event.");
-    checkEventCallState(event, call, "alerting");
-    deferred.resolve(call);
-  };
+    call.onalerting = function onalerting(event) {
+      call.onalerting = null;
+      log("Received 'onalerting' call event.");
+      checkEventCallState(event, call, "alerting");
+      deferred.resolve(call);
+    };
+  });
 
   return deferred.promise;
 }
 
 function answer(call) {
   log("Answering the incoming call.");
 
   let deferred = Promise.defer();
--- a/dom/telephony/test/marionette/test_conference.js
+++ b/dom/telephony/test/marionette/test_conference.js
@@ -101,28 +101,29 @@ function receivedPending(received, pendi
     nextAction();
   }
 }
 
 function dial(number) {
   log("Make an outgoing call: " + number);
 
   let deferred = Promise.defer();
-  let call = telephony.dial(number);
 
-  ok(call);
-  is(call.number, number);
-  is(call.state, "dialing");
+  telephony.dial(number).then(call => {
+    ok(call);
+    is(call.number, number);
+    is(call.state, "dialing");
 
-  call.onalerting = function onalerting(event) {
-    call.onalerting = null;
-    log("Received 'onalerting' call event.");
-    checkEventCallState(event, call, "alerting");
-    deferred.resolve(call);
-  };
+    call.onalerting = function onalerting(event) {
+      call.onalerting = null;
+      log("Received 'onalerting' call event.");
+      checkEventCallState(event, call, "alerting");
+      deferred.resolve(call);
+    };
+  });
 
   return deferred.promise;
 }
 
 // Answering an incoming call could trigger conference state change.
 function answer(call, conferenceStateChangeCallback) {
   log("Answering the incoming call.");
 
--- a/dom/telephony/test/marionette/test_crash_emulator.js
+++ b/dom/telephony/test/marionette/test_crash_emulator.js
@@ -4,22 +4,23 @@
 MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let outNumber = "5555551111";
 let outgoingCall;
 
 function dial() {
   log("Make an outgoing call.");
-  outgoingCall = telephony.dial(outNumber);
-
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'alerting' call event.");
-    answer();
-  };
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'alerting' call event.");
+      answer();
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   outgoingCall.onconnected = function onconnectedOut(event) {
     log("Received 'connected' call event for the original outgoing call.");
     // just some code to keep call active for awhile
--- a/dom/telephony/test/marionette/test_dsds_normal_call.js
+++ b/dom/telephony/test/marionette/test_dsds_normal_call.js
@@ -68,29 +68,30 @@ function checkAll(active, calls, callLis
   return checkEmulatorCallList(callList);
 }
 
 function dial(number, serviceId) {
   serviceId = typeof serviceId !== "undefined" ? serviceId : 0;
   log("Make an outgoing call: " + number + ", serviceId: " + serviceId);
 
   let deferred = Promise.defer();
-  let call = telephony.dial(number, serviceId);
 
-  ok(call);
-  is(call.number, number);
-  is(call.state, "dialing");
+  telephony.dial(number).then(call => {
+    ok(call);
+    is(call.number, number);
+    is(call.state, "dialing");
 
-  call.onalerting = function onalerting(event) {
-    call.onalerting = null;
-    log("Received 'onalerting' call event.");
-    is(call.serviceId, serviceId);
-    checkEventCallState(event, call, "alerting");
-    deferred.resolve(call);
-  };
+    call.onalerting = function onalerting(event) {
+      call.onalerting = null;
+      log("Received 'onalerting' call event.");
+      is(call.serviceId, serviceId);
+      checkEventCallState(event, call, "alerting");
+      deferred.resolve(call);
+    };
+  });
 
   return deferred.promise;
 }
 
 function remoteDial(number) {
   log("Simulating an incoming call.");
 
   let deferred = Promise.defer();
--- a/dom/telephony/test/marionette/test_emergency.js
+++ b/dom/telephony/test/marionette/test_emergency.js
@@ -6,38 +6,41 @@ MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "911";
 let outgoing;
 let calls;
 
 function dial() {
   log("Make an emergency call.");
 
-  outgoing = telephony.dialEmergency(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dialEmergency(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  //ok(telephony.calls === calls); // bug 717414
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    //ok(telephony.calls === calls); // bug 717414
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
+      is(outgoing.emergency, true);
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + "        : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + "        : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the emergency call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoing.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_emergency_badNumber.js
+++ b/dom/telephony/test/marionette/test_emergency_badNumber.js
@@ -1,46 +1,32 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "not a valid emergency number";
-let outgoing;
-let calls;
 
 function dial() {
   log("Make an outgoing call to an invalid number.");
 
-  outgoing = telephony.dialEmergency(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dialEmergency(number).then(null, cause => {
+    log("Received promise 'reject'");
 
-  is(outgoing, telephony.active);
-  //ok(telephony.calls === calls); // bug 717414
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
-
-  outgoing.onerror = function onerror(event) {
-    log("Received 'error' event.");
-    is(event.call, outgoing);
-    ok(event.call.error);
-    is(event.call.error.name, "BadNumberError");
-
+    is(telephony.active, null);
     is(telephony.calls.length, 0);
-    is(telephony.active, null);
+    is(cause, "BadNumberError");
 
     emulator.run("gsm list", function(result) {
       log("Initial call list: " + result);
       is(result[0], "OK");
       cleanUp();
     });
-  };
+  });
 }
 
 function cleanUp() {
   finish();
 }
 
 startTest(function() {
   dial();
--- a/dom/telephony/test/marionette/test_emergency_label.js
+++ b/dom/telephony/test/marionette/test_emergency_label.js
@@ -21,38 +21,40 @@ function createGoldenCallListResult0(num
   let padPattern = "          ";
   let pad = padPattern.substring(0, padPattern.length - number.length);
   return "outbound to  " + number + pad + " : " + state;
 }
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
-    is(outgoing.emergency, emergency);
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
+      is(outgoing.emergency, emergency);
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], createGoldenCallListResult0(number, "ringing"));
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], createGoldenCallListResult0(number, "ringing"));
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoing.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_incoming_already_connected.js
+++ b/dom/telephony/test/marionette/test_incoming_already_connected.js
@@ -7,37 +7,39 @@ MARIONETTE_HEAD_JS = 'head.js';
 let outNumber = "5555551111";
 let inNumber = "5555552222";
 let outgoingCall;
 let incomingCall;
 let gotOriginalConnected = false;
 
 function dial() {
   log("Make an outgoing call.");
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + outNumber + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + outNumber + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
   outgoingCall.onconnected = function onconnectedOut(event) {
     log("Received 'connected' call event for the original outgoing call.");
--- a/dom/telephony/test/marionette/test_incoming_already_held.js
+++ b/dom/telephony/test/marionette/test_incoming_already_held.js
@@ -7,37 +7,39 @@ MARIONETTE_HEAD_JS = 'head.js';
 let outNumber = "5555551111";
 let inNumber = "5555552222";
 let outgoingCall;
 let incomingCall;
 let gotOriginalConnected = false;
 
 function dial() {
   log("Make an outgoing call.");
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + outNumber + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + outNumber + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
   outgoingCall.onconnected = function onconnectedOut(event) {
     log("Received 'connected' call event for the original outgoing call.");
--- a/dom/telephony/test/marionette/test_multiple_hold.js
+++ b/dom/telephony/test/marionette/test_multiple_hold.js
@@ -91,38 +91,40 @@ function holdCall() {
   };
   incomingCall.hold();
 }
 
 // With one call on hold, make outgoing call
 function dial() {
   log("Making an outgoing call (while have one call already held).");
 
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 2);
-  is(telephony.calls[0], incomingCall);
-  is(telephony.calls[1], outgoingCall);
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 2);
+    is(telephony.calls[0], incomingCall);
+    is(telephony.calls[1], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "inbound from " + inNumber + " : held");
-      is(result[1], "outbound to  " + outNumber + " : ringing");
-      is(result[2], "OK");
-      answerOutgoing();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "inbound from " + inNumber + " : held");
+        is(result[1], "outbound to  " + outNumber + " : ringing");
+        is(result[2], "OK");
+        answerOutgoing();
+      });
+    };
+  });
 }
 
 // Have the outgoing call answered
 function answerOutgoing() {
   log("Answering the outgoing/2nd call");
 
   // We get no "connecting" event when the remote party answers the call.
   outgoingCall.onconnected = function onconnectedOut(event) {
--- a/dom/telephony/test/marionette/test_outgoing_already_held.js
+++ b/dom/telephony/test/marionette/test_outgoing_already_held.js
@@ -104,39 +104,41 @@ function holdCall(){
   };
   incomingCall.hold();
 }
 
 // With one call on hold, make outgoing call
 function dial() {
   log("Making an outgoing call (while have one call already held).");
 
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 2);
-  is(telephony.calls[0], incomingCall);
-  is(telephony.calls[1], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 2);
+    is(telephony.calls[0], incomingCall);
+    is(telephony.calls[1], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "inbound from " + inNumber + " : held");
-      is(result[1], "outbound to  " + outNumber + " : ringing");
-      is(result[2], "OK");
-      answerOutgoing();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "inbound from " + inNumber + " : held");
+        is(result[1], "outbound to  " + outNumber + " : ringing");
+        is(result[2], "OK");
+        answerOutgoing();
+      });
+    };
+  });
 }
 
 // Have the outgoing call answered
 function answerOutgoing() {
   log("Answering the outgoing/2nd call");
 
   // We get no "connecting" event when the remote party answers the call.
   outgoingCall.onconnected = function onconnectedOut(event) {
--- a/dom/telephony/test/marionette/test_outgoing_answer_hangup.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_hangup.js
@@ -6,38 +6,40 @@ MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "5555552368";
 let outgoing;
 let calls;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  //ok(telephony.calls === calls); // bug 717414
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    //ok(telephony.calls === calls); // bug 717414
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoing.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_outgoing_answer_local_hangup.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_local_hangup.js
@@ -5,38 +5,40 @@ MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let outgoingCall;
 let outNumber = "5555551111";
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'alerting' call event.");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'alerting' call event.");
 
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + outNumber + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + outNumber + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoingCall.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_outgoing_answer_radio_off.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_radio_off.js
@@ -25,29 +25,29 @@ function setRadioEnabled(enabled) {
 
   return deferred.promise;
 }
 
 function dial(number) {
   log("Make an outgoing call.");
 
   let deferred = Promise.defer();
-  let call = telephony.dial(number);
-
-  ok(call);
-  is(call.number, number);
-  is(call.state, "dialing");
+  telephony.dial(number).then(call => {
+    ok(call);
+    is(call.number, number);
+    is(call.state, "dialing");
 
-  call.onalerting = function(event) {
-    log("Received 'onalerting' call event.");
-    call.onalerting = null;
-    is(call, event.call);
-    is(call.state, "alerting");
-    deferred.resolve(call);
-  };
+    call.onalerting = function(event) {
+      log("Received 'onalerting' call event.");
+      call.onalerting = null;
+      is(call, event.call);
+      is(call.state, "alerting");
+      deferred.resolve(call);
+    };
+  });
 
   return deferred.promise;
 }
 
 function remoteAnswer(call) {
   log("Remote answering the call.");
 
   let deferred = Promise.defer();
--- a/dom/telephony/test/marionette/test_outgoing_badNumber.js
+++ b/dom/telephony/test/marionette/test_outgoing_badNumber.js
@@ -2,40 +2,46 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "****5555552368****";
 let outgoing;
 
+
 function dial() {
   log("Make an outgoing call to an invalid number.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  // Note: The number is valid from the view of phone and the call could be
+  // dialed out successfully. However, it will later receive the BadNumberError
+  // from network side.
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onerror = function onerror(event) {
-    log("Received 'error' event.");
-    is(event.call, outgoing);
-    ok(event.call.error);
-    is(event.call.error.name, "BadNumberError");
+    outgoing.onerror = function onerror(event) {
+      log("Received 'error' event.");
+      is(event.call, outgoing);
+      ok(event.call.error);
+      is(event.call.error.name, "BadNumberError");
 
-    emulator.run("gsm list", function(result) {
-      log("Initial call list: " + result);
-      is(result[0], "OK");
-      cleanUp();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Initial call list: " + result);
+        is(result[0], "OK");
+        cleanUp();
+      });
+    };
+  });
 }
 
 function cleanUp() {
   finish();
 }
 
 startTest(function() {
   dial();
--- a/dom/telephony/test/marionette/test_outgoing_busy.js
+++ b/dom/telephony/test/marionette/test_outgoing_busy.js
@@ -5,37 +5,39 @@ MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "5555552368";
 let outgoing;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + " : ringing");
-      is(result[1], "OK");
-      busy();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + " : ringing");
+        is(result[1], "OK");
+        busy();
+      });
+    };
+  });
 }
 
 function busy() {
   log("The receiver is busy.");
 
   outgoing.onerror = function onerror(event) {
     log("Received 'error' call event.");
     is(outgoing, event.call);
--- a/dom/telephony/test/marionette/test_outgoing_emergency_in_airplane_mode.js
+++ b/dom/telephony/test/marionette/test_outgoing_emergency_in_airplane_mode.js
@@ -41,37 +41,39 @@ function setRadioEnabled(enabled, callba
   request.onerror = function onerror() {
     ok(false, "setRadioEnabled should be ok");
   };
 }
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + "        : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + "        : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoing.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_outgoing_hangup_alerting.js
+++ b/dom/telephony/test/marionette/test_outgoing_hangup_alerting.js
@@ -6,35 +6,37 @@ MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "5555552368";
 let outgoing;
 let calls;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  //ok(telephony.calls === calls); // bug 717414
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    //ok(telephony.calls === calls); // bug 717414
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'alerting' call event.");
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + " : ringing");
-      is(result[1], "OK");
-      hangUp();
-    });
-  };
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'alerting' call event.");
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + " : ringing");
+        is(result[1], "OK");
+        hangUp();
+      });
+    };
+  });
 }
 
 function hangUp() {
   log("Hang up the outgoing call.");
 
   let gotDisconnecting = false;
 
   outgoing.ondisconnecting = function ondisconnecting(event) {
--- a/dom/telephony/test/marionette/test_outgoing_hangup_held.js
+++ b/dom/telephony/test/marionette/test_outgoing_hangup_held.js
@@ -6,37 +6,39 @@ MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "5555552368";
 let outgoing;
 let calls;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
-  is(outgoing, telephony.active);
-  //ok(telephony.calls === calls); // bug 717414
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
+    is(outgoing, telephony.active);
+    //ok(telephony.calls === calls); // bug 717414
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoing.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_outgoing_hold_resume.js
+++ b/dom/telephony/test/marionette/test_outgoing_hold_resume.js
@@ -6,37 +6,39 @@ MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "5555557777";
 let connectedCalls;
 let outgoingCall;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoingCall = telephony.dial(number);
-  ok(outgoingCall);
-  is(outgoingCall.number, number);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, number);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoingCall.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_outgoing_onstatechange.js
+++ b/dom/telephony/test/marionette/test_outgoing_onstatechange.js
@@ -5,41 +5,43 @@ MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let outgoingCall;
 let outNumber = "5555551111";
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
 
-  outgoingCall.onstatechange = function statechangering(event) {
-    log("Received 'onstatechange' call event.");
+    outgoingCall.onstatechange = function statechangering(event) {
+      log("Received 'onstatechange' call event.");
 
-    is(outgoingCall, event.call);
-    let expectedStates = ["dialing", "alerting"];
-    ok(expectedStates.indexOf(event.call.state) != -1);
+      is(outgoingCall, event.call);
+      let expectedStates = ["dialing", "alerting"];
+      ok(expectedStates.indexOf(event.call.state) != -1);
 
-    if (event.call.state == "alerting") {
-      emulator.run("gsm list", function(result) {
-        log("Call list is now: " + result);
-        is(result[0], "outbound to  " + outNumber + " : ringing");
-        is(result[1], "OK");
-        answer();
-      });
-    }
-  };
+      if (event.call.state == "alerting") {
+        emulator.run("gsm list", function(result) {
+          log("Call list is now: " + result);
+          is(result[0], "outbound to  " + outNumber + " : ringing");
+          is(result[1], "OK");
+          answer();
+        });
+      }
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoingCall.onstatechange = function onstatechangeanswer(event) {
--- a/dom/telephony/test/marionette/test_outgoing_radio_off.js
+++ b/dom/telephony/test/marionette/test_outgoing_radio_off.js
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let connection;
-let outgoing;
 
 function receivedPending(received, pending, nextAction) {
   let index = pending.indexOf(received);
   if (index != -1) {
     pending.splice(index, 1);
   }
   if (pending.length === 0) {
     nextAction();
@@ -45,39 +44,31 @@ function setRadioEnabled(enabled, callba
 function dial(number) {
   // Verify initial state before dial.
   ok(telephony);
   is(telephony.active, null);
   ok(telephony.calls);
   is(telephony.calls.length, 0);
 
   log("Make an outgoing call.");
-  outgoing = telephony.dial(number);
 
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(null, cause => {
+    log("Received promise 'reject'");
 
-  is(telephony.active, outgoing);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
-
-  outgoing.onerror = function onerror(event) {
-    log("Received 'error' event.");
-    is(event.call, outgoing);
-    ok(event.call.error);
-    is(event.call.error.name, "RadioNotAvailable");
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+    is(cause, "RadioNotAvailable");
 
     emulator.run("gsm list", function(result) {
       log("Initial call list: " + result);
       is(result[0], "OK");
 
       setRadioEnabled(true, cleanUp);
     });
-  };
+  });
 }
 
 function cleanUp() {
   finish();
 }
 
 startTestWithPermissions(['mobileconnection'], function() {
   connection = navigator.mozMobileConnections[0];
--- a/dom/telephony/test/marionette/test_outgoing_reject.js
+++ b/dom/telephony/test/marionette/test_outgoing_reject.js
@@ -5,37 +5,39 @@ MARIONETTE_TIMEOUT = 60000;
 MARIONETTE_HEAD_JS = 'head.js';
 
 let number = "5555552368";
 let outgoing;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoing = telephony.dial(number);
-  ok(outgoing);
-  is(outgoing.number, number);
-  is(outgoing.state, "dialing");
+  telephony.dial(number).then(call => {
+    outgoing = call;
+    ok(outgoing);
+    is(outgoing.number, number);
+    is(outgoing.state, "dialing");
 
-  is(outgoing, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoing);
+    is(outgoing, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoing);
 
-  outgoing.onalerting = function onalerting(event) {
-    log("Received 'onalerting' call event.");
-    is(outgoing, event.call);
-    is(outgoing.state, "alerting");
+    outgoing.onalerting = function onalerting(event) {
+      log("Received 'onalerting' call event.");
+      is(outgoing, event.call);
+      is(outgoing.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + number + " : ringing");
-      is(result[1], "OK");
-      reject();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + number + " : ringing");
+        is(result[1], "OK");
+        reject();
+      });
+    };
+  });
 }
 
 function reject() {
   log("Reject the outgoing call on the other end.");
   // We get no "disconnecting" event when the remote party rejects the call.
 
   outgoing.ondisconnected = function ondisconnected(event) {
     log("Received 'disconnected' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_remote_hangup_held.js
+++ b/dom/telephony/test/marionette/test_outgoing_remote_hangup_held.js
@@ -4,38 +4,40 @@
 MARIONETTE_TIMEOUT = 60000;
 
 let outNumber = "5555551111";
 let outgoingCall;
 
 function dial() {
   log("Make an outgoing call.");
 
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  is(outgoingCall, telephony.active);
-  is(telephony.calls.length, 1);
-  is(telephony.calls[0], outgoingCall);
+    is(outgoingCall, telephony.active);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'alerting' call event.");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'alerting' call event.");
 
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + outNumber + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + outNumber + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
 
   outgoingCall.onconnected = function onconnected(event) {
--- a/dom/telephony/test/marionette/test_swap_held_and_active.js
+++ b/dom/telephony/test/marionette/test_swap_held_and_active.js
@@ -9,37 +9,39 @@ let inNumber = "5555552222";
 let outgoingCall;
 let incomingCall;
 let gotOriginalConnected = false;
 let gotHeld = false;
 let gotConnected = false;
 
 function dial() {
   log("Make an outgoing call.");
-  outgoingCall = telephony.dial(outNumber);
-  ok(outgoingCall);
-  is(outgoingCall.number, outNumber);
-  is(outgoingCall.state, "dialing");
+  telephony.dial(outNumber).then(call => {
+    outgoingCall = call;
+    ok(outgoingCall);
+    is(outgoingCall.number, outNumber);
+    is(outgoingCall.state, "dialing");
 
-  outgoingCall.onalerting = function onalerting(event) {
-    log("Received 'alerting' call event.");
+    outgoingCall.onalerting = function onalerting(event) {
+      log("Received 'alerting' call event.");
 
-    is(outgoingCall, event.call);
-    is(outgoingCall.state, "alerting");
-    is(outgoingCall, telephony.active);
-    is(telephony.calls.length, 1);
-    is(telephony.calls[0], outgoingCall);
+      is(outgoingCall, event.call);
+      is(outgoingCall.state, "alerting");
+      is(outgoingCall, telephony.active);
+      is(telephony.calls.length, 1);
+      is(telephony.calls[0], outgoingCall);
 
-    emulator.run("gsm list", function(result) {
-      log("Call list is now: " + result);
-      is(result[0], "outbound to  " + outNumber + " : ringing");
-      is(result[1], "OK");
-      answer();
-    });
-  };
+      emulator.run("gsm list", function(result) {
+        log("Call list is now: " + result);
+        is(result[0], "outbound to  " + outNumber + " : ringing");
+        is(result[1], "OK");
+        answer();
+      });
+    };
+  });
 }
 
 function answer() {
   log("Answering the outgoing call.");
 
   // We get no "connecting" event when the remote party answers the call.
   outgoingCall.onconnected = function onconnectedOut(event) {
     log("Received 'connected' call event for the original outgoing call.");
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -69,16 +69,17 @@ var ecmaGlobals =
     {name: "NaN", xbl: false},
     "Number",
     "Object",
     "Proxy",
     "RangeError",
     "ReferenceError",
     "RegExp",
     "Set",
+    {name: "SharedArrayBuffer", nightly: true},
     {name: "SIMD", nightly: true},
     "StopIteration",
     "String",
     "SyntaxError",
     {name: "TypedObject", nightly: true},
     "TypeError",
     "Uint16Array",
     "Uint32Array",
--- a/dom/webidl/ClipboardEvent.webidl
+++ b/dom/webidl/ClipboardEvent.webidl
@@ -5,18 +5,16 @@
  *
  * For more information on this interface please see
  * http://dev.w3.org/2006/webapi/clipops/#x5-clipboard-event-interfaces
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface DataTransfer;
-
 [Constructor(DOMString type, optional ClipboardEventInit eventInitDict)]
 interface ClipboardEvent : Event
 {
   readonly attribute DataTransfer? clipboardData;
 };
 
 dictionary ClipboardEventInit : EventInit
 {
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DataTransfer.webidl
@@ -0,0 +1,137 @@
+/* -*- Mode: IDL; 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/.
+ *
+ * The origin of this IDL file is:
+ * http://www.whatwg.org/specs/web-apps/current-work/#the-datatransfer-interface
+ */
+
+[ChromeConstructor(DOMString eventType, boolean isExternal)]
+interface DataTransfer {
+           attribute DOMString dropEffect;
+           attribute DOMString effectAllowed;
+
+  //readonly attribute DataTransferItemList items;
+
+  [Throws]
+  void setDragImage(Element image, long x, long y);
+
+  readonly attribute DOMStringList types;
+  [Throws]
+  DOMString getData(DOMString format);
+  [Throws]
+  void setData(DOMString format, DOMString data);
+  [Throws]
+  void clearData(optional DOMString format);
+  [Throws]
+  readonly attribute FileList files;
+};
+
+// Mozilla specific stuff
+partial interface DataTransfer {
+  /*
+   * Set the drag source. Usually you would not change this, but it will
+   * affect which node the drag and dragend events are fired at. The
+   * default target is the node that was dragged.
+   *
+   * @param element drag source to use
+   * @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified
+   */
+  [Throws]
+  void addElement(Element element);
+
+  /**
+   * The number of items being dragged.
+   */
+  readonly attribute unsigned long mozItemCount;
+
+  /**
+   * Sets the drag cursor state. Primarily used to control the cursor during
+   * tab drags, but could be expanded to other uses. XXX Currently implemented
+   * on Win32 only.
+   *
+   * Possible values:
+   *  auto - use default system behavior.
+   *  default - set the cursor to an arrow during the drag operation.
+   *
+   * Values other than 'default' are indentical to setting mozCursor to
+   * 'auto'.
+   */
+  attribute DOMString mozCursor;
+
+  /**
+   * Holds a list of the format types of the data that is stored for an item
+   * at the specified index. If the index is not in the range from 0 to
+   * itemCount - 1, an empty string list is returned.
+   */
+  [Throws]
+  DOMStringList mozTypesAt(unsigned long index);
+
+  /**
+   * Remove the data associated with the given format for an item at the
+   * specified index. The index is in the range from zero to itemCount - 1.
+   *
+   * If the last format for the item is removed, the entire item is removed,
+   * reducing the itemCount by one.
+   *
+   * If format is empty, then the data associated with all formats is removed.
+   * If the format is not found, then this method has no effect.
+   *
+   * @param format the format to remove
+   * @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount
+   * @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified
+   */
+  [Throws]
+  void mozClearDataAt(DOMString format, unsigned long index);
+
+  /*
+   * A data transfer may store multiple items, each at a given zero-based
+   * index. setDataAt may only be called with an index argument less than
+   * itemCount in which case an existing item is modified, or equal to
+   * itemCount in which case a new item is added, and the itemCount is
+   * incremented by one.
+   *
+   * Data should be added in order of preference, with the most specific
+   * format added first and the least specific format added last. If data of
+   * the given format already exists, it is replaced in the same position as
+   * the old data.
+   *
+   * The data should be either a string, a primitive boolean or number type
+   * (which will be converted into a string) or an nsISupports.
+   *
+   * @param format the format to add
+   * @param data the data to add
+   * @throws NS_ERROR_NULL_POINTER if the data is null
+   * @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater than itemCount
+   * @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified
+   */
+  [Throws]
+  void mozSetDataAt(DOMString format, any data, unsigned long index);
+
+  /**
+   * Retrieve the data associated with the given format for an item at the
+   * specified index, or null if it does not exist. The index should be in the
+   * range from zero to itemCount - 1.
+   *
+   * @param format the format of the data to look up
+   * @returns the data of the given format, or null if it doesn't exist.
+   * @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount
+   */
+  [Throws]
+  any mozGetDataAt(DOMString format, unsigned long index);
+
+  /**
+   * Will be true when the user has cancelled the drag (typically by pressing
+   * Escape) and when the drag has been cancelled unexpectedly.  This will be
+   * false otherwise, including when the drop has been rejected by its target.
+   * This property is only relevant for the dragend event.
+   */
+  readonly attribute boolean mozUserCancelled;
+
+  /**
+   * The node that the mouse was pressed over to begin the drag. For external
+   * drags, or if the caller cannot access this node, this will be null.
+   */
+  readonly attribute Node? mozSourceNode;
+};
--- a/dom/webidl/DragEvent.webidl
+++ b/dom/webidl/DragEvent.webidl
@@ -1,16 +1,15 @@
 /* -*- Mode: IDL; 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/.
  */
 
 interface WindowProxy;
-interface DataTransfer;
 
 interface DragEvent : MouseEvent
 {
   readonly attribute DataTransfer? dataTransfer;
 
   [Throws]
   void initDragEvent(DOMString type,
                      boolean canBubble,
--- a/dom/webidl/Telephony.webidl
+++ b/dom/webidl/Telephony.webidl
@@ -11,21 +11,21 @@ interface Telephony : EventTarget {
    * |serviceId| to indicate the target telephony service. If not specified,
    * the implementation MUST use the default service.
    *
    * Possible values of |serviceId| are 0 ~ (number of services - 1), which is
    * simply the index of a service. Get number of services by acquiring
    * |navigator.mozMobileConnections.length|.
    */
 
-  [Throws]
-  TelephonyCall dial(DOMString number, optional unsigned long serviceId);
+  // Promise<TelephonyCall>
+  Promise dial(DOMString number, optional unsigned long serviceId);
 
-  [Throws]
-  TelephonyCall dialEmergency(DOMString number, optional unsigned long serviceId);
+  // Promise<TelephonyCall>
+  Promise dialEmergency(DOMString number, optional unsigned long serviceId);
 
   [Throws]
   void startTone(DOMString tone, optional unsigned long serviceId);
 
   [Throws]
   void stopTone(optional unsigned long serviceId);
 
   [Throws]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -61,16 +61,17 @@ WEBIDL_FILES = [
     'CSS.webidl',
     'CSSPrimitiveValue.webidl',
     'CSSStyleDeclaration.webidl',
     'CSSStyleSheet.webidl',
     'CSSValue.webidl',
     'CSSValueList.webidl',
     'DataContainerEvent.webidl',
     'DataStore.webidl',
+    'DataTransfer.webidl',
     'DedicatedWorkerGlobalScope.webidl',
     'DelayNode.webidl',
     'DesktopNotification.webidl',
     'DeviceMotionEvent.webidl',
     'DeviceStorage.webidl',
     'Document.webidl',
     'DocumentFragment.webidl',
     'DocumentType.webidl',
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -35,22 +35,22 @@
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
+#include "nsISupportsImpl.h"
 #include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
-#include "nsTraceRefcnt.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "OSFileConstants.h"
 #include "xpcpublic.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
--- a/dom/xslt/base/txCore.h
+++ b/dom/xslt/base/txCore.h
@@ -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/. */
 
 #ifndef __txCore_h__
 #define __txCore_h__
 
 #include "nscore.h"
 #include "nsDebug.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 class nsAString;
 
 class txObject
 {
 public:
     txObject()
     {
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -16,17 +16,17 @@
 #include "nsEventListenerManager.h"     // for nsEventListenerManager
 #include "nsFocusManager.h"             // for nsFocusManager
 #include "nsGkAtoms.h"                  // for nsGkAtoms, nsGkAtoms::input
 #include "nsIClipboard.h"               // for nsIClipboard, etc
 #include "nsIContent.h"                 // for nsIContent
 #include "nsIController.h"              // for nsIController
 #include "nsID.h"
 #include "nsIDOMDOMStringList.h"        // for nsIDOMDOMStringList
-#include "nsIDOMDataTransfer.h"         // for nsIDOMDataTransfer
+#include "mozilla/dom/DataTransfer.h"
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
 #include "nsIDOMDragEvent.h"            // for nsIDOMDragEvent
 #include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIDOMEvent.h"                // for nsIDOMEvent
 #include "nsIDOMEventTarget.h"          // for nsIDOMEventTarget
 #include "nsIDOMKeyEvent.h"             // for nsIDOMKeyEvent
 #include "nsIDOMMouseEvent.h"           // for nsIDOMMouseEvent
 #include "nsIDOMNode.h"                 // for nsIDOMNode
--- a/editor/libeditor/html/TypeInState.cpp
+++ b/editor/libeditor/html/TypeInState.cpp
@@ -11,19 +11,19 @@
 #include "nsAString.h"
 #include "nsDebug.h"
 #include "nsEditProperty.h"
 #include "nsEditor.h"
 #include "nsError.h"
 #include "nsIDOMNode.h"
 #include "nsISelection.h"
 #include "nsISupportsBase.h"
+#include "nsISupportsImpl.h"
 #include "nsReadableUtils.h"
 #include "nsStringFwd.h"
-#include "nsTraceRefcnt.h"
 
 class nsIAtom;
 class nsIDOMDocument;
 
 /********************************************************************
  *                     XPCOM cruft 
  *******************************************************************/
 
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -30,17 +30,17 @@
 #include "nsGkAtoms.h"
 #include "nsHTMLEditUtils.h"
 #include "nsHTMLEditor.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
 #include "nsIContentFilter.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMDOMStringList.h"
-#include "nsIDOMDataTransfer.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLAnchorElement.h"
 #include "nsIDOMHTMLEmbedElement.h"
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMHTMLIFrameElement.h"
 #include "nsIDOMHTMLImageElement.h"
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -12,17 +12,16 @@
 #include "nsEditor.h"
 #include "nsIEditActionListener.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsISupportsImpl.h"
 #include "nsSelectionState.h"
 #include "nsTArray.h"
 #include "nsTextEditRules.h"
-#include "nsTraceRefcnt.h"
 #include "nscore.h"
 
 class nsHTMLEditor;
 class nsIAtom;
 class nsIDOMCharacterData;
 class nsIDOMDocument;
 class nsIDOMElement;
 class nsIDOMNode;
--- a/editor/txmgr/src/nsTransactionItem.cpp
+++ b/editor/txmgr/src/nsTransactionItem.cpp
@@ -3,18 +3,18 @@
  * 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/mozalloc.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
+#include "nsISupportsImpl.h"
 #include "nsITransaction.h"
-#include "nsTraceRefcnt.h"
 #include "nsTransactionItem.h"
 #include "nsTransactionManager.h"
 #include "nsTransactionStack.h"
 
 nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction)
     : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0)
 {
 }
--- a/embedding/tests/winEmbed/Makefile.in
+++ b/embedding/tests/winEmbed/Makefile.in
@@ -32,27 +32,8 @@ LIBS = \
 	$(XPCOM_STANDALONE_GLUE_LDOPTS) \
 	$(NULL)
 
 STL_FLAGS=
 
 OS_LIBS		+= $(call EXPAND_LIBNAME,ole32 comdlg32 shell32 version)
 
 include $(topsrcdir)/config/rules.mk
-
-#
-# Control the default heap size.
-# This is the heap returned by GetProcessHeap().
-# As we use the CRT heap, the default size is too large and wastes VM.
-#
-# The default heap size is 1MB on Win32.
-# The heap will grow if need be.
-#
-# Set it to 256k.  See bug 127069.
-#
-ifndef GNU_CC
-LDFLAGS += /HEAP:0x40000
-endif
-
-# Get rid of console window
-ifdef GNU_CC
-LDFLAGS += -mwindows
-endif
--- a/embedding/tests/winEmbed/moz.build
+++ b/embedding/tests/winEmbed/moz.build
@@ -12,8 +12,22 @@ SOURCES += [
     'winEmbed.cpp',
 ]
 
 XPI_NAME = 'winembed'
 
 DEFINES['XPCOM_GLUE'] = True
 
 RESFILE = 'winEmbed.res'
+
+if CONFIG['GNU_CC']:
+    # Get rid of console window
+    LDFLAGS += ['-mwindows']
+else:
+    # Control the default heap size.
+    # This is the heap returned by GetProcessHeap().
+    # As we use the CRT heap, the default size is too large and wastes VM.
+    #
+    # The default heap size is 1MB on Win32.
+    # The heap will grow if need be.
+    #
+    # Set it to 256k.  See bug 127069.
+    LDFLAGS += ['/HEAP:0x40000']
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -7,17 +7,17 @@
 #include "GLContextCGL.h"
 #include "TextureImageCGL.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include <OpenGL/gl.h>
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
-#include "gfxPlatform.h"
+#include "gfxPrefs.h"
 #include "gfxFailure.h"
 #include "prenv.h"
 #include "mozilla/Preferences.h"
 #include "GeckoProfiler.h"
 #include "mozilla/gfx/MacIOSurface.h"
 
 using namespace mozilla::gfx;
 
@@ -134,17 +134,17 @@ GLContextCGL::MakeCurrentImpl(bool aForc
     if (mContext) {
         [mContext makeCurrentContext];
         // Use non-blocking swap in "ASAP mode".
         // ASAP mode means that rendering is iterated as fast as possible.
         // ASAP mode is entered when layout.frame_rate=0 (requires restart).
         // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
         // When we're iterating as fast as possible, however, we want a non-blocking
         // glSwapBuffers, which will happen when swapInt==0.
-        GLint swapInt = gfxPlatform::GetPrefLayoutFrameRate() == 0 ? 0 : 1;
+        GLint swapInt = gfxPrefs::LayoutFrameRate() == 0 ? 0 : 1;
         [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
     }
     return true;
 }
 
 bool
 GLContextCGL::IsCurrent() {
     return [NSOpenGLContext currentContext] == mContext;
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -9,17 +9,17 @@
 #include "Units.h"                      // for ScreenPoint
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/gfx/Point.h"          // for IntSize, Point
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float
 #include "mozilla/layers/CompositorTypes.h"  // for DiagnosticTypes, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"
 #include <vector>
 
 /**
  * Different elements of a web pages are rendered into separate "layers" before
  * they are flattened into the final image that is brought to the screen.
  * See Layers.h for more informations about layers and why we use retained
  * structures.
--- a/gfx/layers/CopyableCanvasLayer.h
+++ b/gfx/layers/CopyableCanvasLayer.h
@@ -14,17 +14,17 @@
 #include "gfxTypes.h"
 #include "gfxPlatform.h"                // for gfxImageFormat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class CanvasClientWebGL;
 
 /**
  * A shared CanvasLayer implementation that supports copying
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -20,17 +20,16 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr, etc
 #include "nsDataHashtable.h"            // for nsDataHashtable
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsHashKeys.h"                 // for nsPtrHashKey
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray_Impl
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 struct LayerPropertiesBase;
 LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot);
 
 static nsIntRect
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -14,17 +14,16 @@
 #include "LayerSorter.h"                // for SortLayersBy3DZOrder
 #include "LayersLogging.h"              // for AppendToString
 #include "ReadbackLayer.h"              // for ReadbackLayer
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxUtils.h"                   // for gfxUtils, etc
 #include "gfx2DGlue.h"
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/Telemetry.h"          // for Accumulate
-#include "mozilla/TelemetryHistogramEnums.h"
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -7,16 +7,17 @@
 #include <sys/types.h>                  // for int32_t
 #include <algorithm>                    // for max
 #include "BasicImplData.h"              // for BasicImplData
 #include "BasicLayersImpl.h"            // for ToData
 #include "BufferUnrotate.h"             // for BufferUnrotate
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "Layers.h"                     // for ThebesLayer, Layer, etc
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxUtils.h"                   // for gfxUtils
 #include "mozilla/ArrayUtils.h"         // for ArrayLength
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix
 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
@@ -447,17 +448,17 @@ RotatedContentBuffer::BeginPaint(ThebesL
 #if defined(MOZ_GFX_OPTIMIZE_MOBILE) || defined(MOZ_WIDGET_GONK)
       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
 #else
       if (!aLayer->GetParent() ||
           !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
           !aLayer->Manager()->IsCompositingCheap() ||
           !aLayer->AsShadowableLayer() ||
           !aLayer->AsShadowableLayer()->HasShadow() ||
-          !gfxPlatform::ComponentAlphaEnabled()) {
+          !gfxPrefs::ComponentAlphaEnabled()) {
         mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
       } else {
         result.mContentType = gfxContentType::COLOR;
       }
 #endif
     }
 
     if ((aFlags & PAINT_WILL_RESAMPLE) &&
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -10,20 +10,20 @@
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, TemporaryRef
 #include "mozilla/gfx/2D.h"             // for DrawTarget, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "LayersTypes.h"
 
 struct nsIntSize;
 
 namespace mozilla {
 namespace gfx {
 class Matrix;
 }
--- a/gfx/layers/basic/BasicColorLayer.cpp
+++ b/gfx/layers/basic/BasicColorLayer.cpp
@@ -12,17 +12,16 @@
 #include "gfx2DGlue.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class BasicColorLayer : public ColorLayer, public BasicImplData {
 public:
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -11,16 +11,17 @@
 #include "nsIWidget.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "gfxUtils.h"
 #include "YCbCrUtils.h"
 #include <algorithm>
 #include "ImageContainer.h"
+#include "gfxPrefs.h"
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"                     // for pixman_f_transform, etc
 
 namespace mozilla {
 using namespace mozilla::gfx;
 
 namespace layers {
 
@@ -613,17 +614,17 @@ BasicCompositor::BeginFrame(const nsIntR
 }
 
 void
 BasicCompositor::EndFrame()
 {
   // Pop aClipRectIn/bounds rect
   mRenderTarget->mDrawTarget->PopClip();
 
-  if (gfxPlatform::GetPlatform()->WidgetUpdateFlashing()) {
+  if (gfxPrefs::WidgetUpdateFlashing()) {
     float r = float(rand()) / RAND_MAX;
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     // We're still clipped to mInvalidRegion, so just fill the bounds.
     mRenderTarget->mDrawTarget->FillRect(ToRect(mInvalidRegion.GetBounds()),
                                          ColorPattern(Color(r, g, b, 0.2f)));
   }
 
--- a/gfx/layers/basic/BasicContainerLayer.h
+++ b/gfx/layers/basic/BasicContainerLayer.h
@@ -5,18 +5,18 @@
 
 #ifndef GFX_BASICCONTAINERLAYER_H
 #define GFX_BASICCONTAINERLAYER_H
 
 #include "BasicImplData.h"              // for BasicImplData
 #include "BasicLayers.h"                // for BasicLayerManager
 #include "Layers.h"                     // for Layer, ContainerLayer
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR
 struct nsIntRect;
 
 namespace mozilla {
 namespace layers {
 
 class BasicContainerLayer : public ContainerLayer, public BasicImplData {
 public:
   BasicContainerLayer(BasicLayerManager* aManager) :
--- a/gfx/layers/basic/BasicImageLayer.cpp
+++ b/gfx/layers/basic/BasicImageLayer.cpp
@@ -18,17 +18,16 @@
 #endif
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxPattern::Release, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "mozilla/gfx/Point.h"          // for IntSize
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class BasicImageLayer : public ImageLayer, public BasicImplData {
--- a/gfx/layers/basic/BasicImplData.h
+++ b/gfx/layers/basic/BasicImplData.h
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_BASICIMPLDATA_H
 #define GFX_BASICIMPLDATA_H
 
 #include "Layers.h"                     // for Layer (ptr only), etc
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "nsDebug.h"                    // for NS_ASSERTION
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "mozilla/gfx/Types.h"
 
 class gfxASurface;
 
 namespace mozilla {
 namespace layers {
 
 class ReadbackProcessor;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -19,16 +19,17 @@
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "gfxCachedTempSurface.h"       // for gfxCachedTempSurface
 #include "gfxColor.h"                   // for gfxRGBA
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "gfxMatrix.h"                  // for gfxMatrix
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for gfxUtils
 #include "gfx2DGlue.h"                  // for thebes --> moz2d transition
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/WidgetUtils.h"        // for ScreenRotation
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
@@ -40,17 +41,16 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion, etc
 #include "nsTArray.h"                   // for nsAutoTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"                     // for pixman_f_transform, etc
 
 class nsIWidget;
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
@@ -538,17 +538,17 @@ BasicLayerManager::AbortTransaction()
   mUsingDefaultTarget = false;
   mInTransaction = false;
 }
 
 static uint16_t sFrameCount = 0;
 void
 BasicLayerManager::RenderDebugOverlay()
 {
-  if (!gfxPlatform::DrawFrameCounter()) {
+  if (!gfxPrefs::DrawFrameCounter()) {
     return;
   }
 
   profiler_set_frame_number(sFrameCount);
 
   uint16_t frameNumber = sFrameCount;
   const uint16_t bitWidth = 3;
   for (size_t i = 0; i < 16; i++) {
@@ -659,17 +659,17 @@ BasicLayerManager::EndTransactionInterna
   // out target is the default target.
 
   return !mTransactionIncomplete;
 }
 
 void
 BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
 {
-  if (gfxPlatform::GetPlatform()->WidgetUpdateFlashing()) {
+  if (gfxPrefs::WidgetUpdateFlashing()) {
     float r = float(rand()) / RAND_MAX;
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
     aContext->Paint();
   }
 }
 
--- a/gfx/layers/basic/BasicLayersImpl.h
+++ b/gfx/layers/basic/BasicLayersImpl.h
@@ -13,17 +13,16 @@
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "ipc/AutoOpenSurface.h"        // for AutoOpenSurface
 #include "mozilla/Attributes.h"         // for MOZ_DELETE, MOZ_STACK_CLASS
 #include "mozilla/Maybe.h"              // for Maybe
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class AutoMaskData;
 class BasicContainerLayer;
 class Layer;
 
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -11,18 +11,18 @@
 #include "BasicImplData.h"              // for BasicImplData
 #include "BasicLayers.h"                // for BasicLayerManager
 #include "gfxPoint.h"                   // for gfxPoint
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/layers/ContentClient.h"  // for ContentClientBasic
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 class gfxContext;
 
 namespace mozilla {
 namespace layers {
 
 class ReadbackProcessor;
 
 class BasicThebesLayer : public ThebesLayer, public BasicImplData {
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -11,18 +11,18 @@
 #include "CopyableCanvasLayer.h"        // for CopyableCanvasLayer
 #include "Layers.h"                     // for CanvasLayer, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/LayersMessages.h"  // for CanvasLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class ShadowableLayer;
 
 class ClientCanvasLayer : public CopyableCanvasLayer,
--- a/gfx/layers/client/ClientColorLayer.cpp
+++ b/gfx/layers/client/ClientColorLayer.cpp
@@ -7,17 +7,16 @@
 #include "Layers.h"                     // for ColorLayer, etc
 #include "mozilla/layers/LayersMessages.h"  // for ColorLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class ClientColorLayer : public ColorLayer, 
                          public ClientLayer {
--- a/gfx/layers/client/ClientContainerLayer.h
+++ b/gfx/layers/client/ClientContainerLayer.h
@@ -4,22 +4,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_CLIENTCONTAINERLAYER_H
 #define GFX_CLIENTCONTAINERLAYER_H
 
 #include <stdint.h>                     // for uint32_t
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
-#include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsAutoTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class ShadowableLayer;
 
 class ClientContainerLayer : public ContainerLayer,
                              public ClientLayer
@@ -53,17 +53,17 @@ public:
       if (GetEffectiveVisibleRegion().GetNumRects() != 1 ||
           !(GetContentFlags() & Layer::CONTENT_OPAQUE))
       {
         gfx::Matrix transform;
         if (HasOpaqueAncestorLayer(this) &&
             GetEffectiveTransform().Is2D(&transform) &&
             !gfx::ThebesMatrix(transform).HasNonIntegerTranslation()) {
           SetSupportsComponentAlphaChildren(
-            gfxPlatform::ComponentAlphaEnabled());
+            gfxPrefs::ComponentAlphaEnabled());
         }
       }
     } else {
       SetSupportsComponentAlphaChildren(
         (GetContentFlags() & Layer::CONTENT_OPAQUE) ||
         (GetParent() && GetParent()->SupportsComponentAlphaChildren()));
     }
 
--- a/gfx/layers/client/ClientImageLayer.cpp
+++ b/gfx/layers/client/ClientImageLayer.cpp
@@ -13,17 +13,16 @@
 #include "mozilla/layers/ImageClient.h"  // for ImageClient, etc
 #include "mozilla/layers/LayersMessages.h"  // for ImageLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class ClientImageLayer : public ImageLayer, 
                          public ClientLayer {
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -16,17 +16,16 @@
 #include "mozilla/layers/LayersTypes.h"  // for BufferMode, LayersBackend, etc
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR
 #include "nscore.h"                     // for nsAString
 
 class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
 class ClientThebesLayer;
--- a/gfx/layers/client/ClientThebesLayer.cpp
+++ b/gfx/layers/client/ClientThebesLayer.cpp
@@ -6,16 +6,17 @@
 #include "ClientThebesLayer.h"
 #include "ClientTiledThebesLayer.h"     // for ClientTiledThebesLayer
 #include <stdint.h>                     // for uint32_t
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "client/ClientLayerManager.h"  // for ClientLayerManager, etc
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "gfxContext.h"                 // for gfxContext
 #include "gfxRect.h"                    // for gfxRect
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Matrix.h"         // for Matrix
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float, etc
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/Preferences.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
@@ -166,17 +167,17 @@ ClientLayerManager::CreateThebesLayer()
 already_AddRefed<ThebesLayer>
 ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   if (
 #ifdef MOZ_B2G
       aHint == SCROLLABLE &&
 #endif
-      gfxPlatform::GetPrefLayersEnableTiles() && AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL) {
+      gfxPrefs::LayersTilesEnabled() && AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL) {
     nsRefPtr<ClientTiledThebesLayer> layer =
       new ClientTiledThebesLayer(this);
     CREATE_SHADOW(Thebes);
     return layer.forget();
   } else
   {
     nsRefPtr<ClientThebesLayer> layer =
       new ClientThebesLayer(this);
--- a/gfx/layers/client/ClientThebesLayer.h
+++ b/gfx/layers/client/ClientThebesLayer.h
@@ -9,18 +9,18 @@
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "Layers.h"                     // for ThebesLayer, etc
 #include "RotatedBuffer.h"              // for RotatedContentBuffer, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/ContentClient.h"  // for ContentClient
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "mozilla/layers/PLayerTransaction.h" // for ThebesLayerAttributes
 
 class gfxContext;
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -3,24 +3,25 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientTiledThebesLayer.h"
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "Units.h"                      // for ScreenIntRect, CSSPoint, etc
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Rect.h"           // for Rect, RectTyped
 #include "mozilla/layers/LayersMessages.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRect.h"                     // for nsIntRect
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 
 ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager)
   : ThebesLayer(aManager,
                 static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
@@ -171,18 +172,18 @@ ClientTiledThebesLayer::RenderLayer()
   // Only paint the mask layer on the first transaction.
   if (GetMaskLayer() && !ClientManager()->IsRepeatTransaction()) {
     ToClientLayer(GetMaskLayer())->RenderLayer();
   }
 
   // Fast path for no progressive updates, no low-precision updates and no
   // critical display-port set, or no display-port set.
   const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics();
-  if ((!gfxPlatform::UseProgressiveTilePainting() &&
-       !gfxPlatform::UseLowPrecisionBuffer() &&
+  if ((!gfxPrefs::UseProgressiveTilePainting() &&
+       !gfxPrefs::UseLowPrecisionBuffer() &&
        parentMetrics.mCriticalDisplayPort.IsEmpty()) ||
        parentMetrics.mDisplayPort.IsEmpty()) {
     mValidRegion = mVisibleRegion;
 
     NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");
 
     mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion,
                                              callback, data);
@@ -207,17 +208,17 @@ ClientTiledThebesLayer::RenderLayer()
       // Make sure that tiles that fall outside of the critical displayport are
       // discarded on the first update.
       mValidRegion.And(mValidRegion, mPaintData.mLayoutCriticalDisplayPort);
     }
   }
 
   nsIntRegion lowPrecisionInvalidRegion;
   if (!mPaintData.mLayoutCriticalDisplayPort.IsEmpty()) {
-    if (gfxPlatform::UseLowPrecisionBuffer()) {
+    if (gfxPrefs::UseLowPrecisionBuffer()) {
       // Calculate the invalid region for the low precision buffer
       lowPrecisionInvalidRegion.Sub(mVisibleRegion, mLowPrecisionValidRegion);
 
       // Remove the valid region from the low precision valid region (we don't
       // validate this part of the low precision buffer).
       lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion);
     }
 
@@ -227,17 +228,17 @@ ClientTiledThebesLayer::RenderLayer()
       EndPaint(true);
       return;
     }
   }
 
   if (!invalidRegion.IsEmpty() && mPaintData.mLowPrecisionPaintCount == 0) {
     bool updatedBuffer = false;
     // Only draw progressively when the resolution is unchanged.
-    if (gfxPlatform::UseProgressiveTilePainting() &&
+    if (gfxPrefs::UseProgressiveTilePainting() &&
         !ClientManager()->HasShadowTarget() &&
         mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) {
       // Store the old valid region, then clear it before painting.
       // We clip the old valid region to the visible region, as it only gets
       // used to decide stale content (currently valid and previously visible)
       nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion();
       oldValidRegion.And(oldValidRegion, mVisibleRegion);
       if (!mPaintData.mLayoutCriticalDisplayPort.IsEmpty()) {
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -10,17 +10,17 @@
 #include <vector>                       // for vector
 #include <map>                          // for map
 #include "mozilla/Assertions.h"         // for MOZ_CRASH
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "gfxASurface.h"                // for gfxContentType
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class DeprecatedTextureClient;
 class TextureClient;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -3,16 +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 "mozilla/layers/ContentClient.h"
 #include "BasicLayers.h"                // for BasicLayerManager
 #include "gfxColor.h"                   // for gfxRGBA
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
 #include "gfxTeeSurface.h"              // for gfxTeeSurface
 #include "gfxUtils.h"                   // for gfxUtils
 #include "ipc/ShadowLayers.h"           // for ShadowLayerForwarder
 #include "mozilla/ArrayUtils.h"         // for ArrayLength
 #include "mozilla/gfx/2D.h"             // for DrawTarget, Factory
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
@@ -1095,17 +1096,17 @@ ContentClientIncremental::BeginPaintBuff
         // going to be visible. We'll move it.
         destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
       }
     } else {
       destBufferRect = neededRegion.GetBounds();
     }
 
     if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-      if (!gfxPlatform::ComponentAlphaEnabled() ||
+      if (!gfxPrefs::ComponentAlphaEnabled() ||
           !aLayer->GetParent() ||
           !aLayer->GetParent()->SupportsComponentAlphaChildren()) {
         mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
       } else {
         contentType = gfxContentType::COLOR;
       }
     }
 
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -16,17 +16,17 @@
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrImage, etc
 #include "mozilla/gfx/2D.h"
 
 #ifdef MOZ_ANDROID_OMTC
 #  include "gfxReusableImageSurfaceWrapper.h"
 #  include "gfxImageSurface.h"
 #else
 #  include "gfxReusableSharedImageSurfaceWrapper.h"
@@ -103,17 +103,17 @@ private:
     AddRef();
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
 
-  CompositableForwarder* mForwarder;
+  RefPtr<CompositableForwarder> mForwarder;
   TextureClientData* mTextureData;
   TextureClient* mTextureClient;
   bool mIPCOpen;
 
   friend class TextureClient;
 };
 
 void
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -6,16 +6,17 @@
 #include "mozilla/layers/TiledContentClient.h"
 #include <math.h>                       // for ceil, ceilf, floor
 #include "ClientTiledThebesLayer.h"     // for ClientTiledThebesLayer
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "ClientLayerManager.h"         // for ClientLayerManager
 #include "CompositorChild.h"            // for CompositorChild
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/MathAlgorithms.h"     // for Abs
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
@@ -78,17 +79,18 @@ namespace layers {
 TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
                                        ClientLayerManager* aManager)
   : CompositableClient(aManager->AsShadowForwarder())
   , mTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
   , mLowPrecisionTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
 {
   MOZ_COUNT_CTOR(TiledContentClient);
 
-  mLowPrecisionTiledBuffer.SetResolution(gfxPlatform::GetLowPrecisionResolution());
+  // The preference is int in "thousands", so adjust:
+  mLowPrecisionTiledBuffer.SetResolution(gfxPrefs::LowPrecisionResolution()/1000.f);
 }
 
 void
 TiledContentClient::LockCopyAndWrite(TiledBufferType aType)
 {
   BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
     ? &mLowPrecisionTiledBuffer
     : &mTiledBuffer;
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -16,21 +16,21 @@
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_DTOR
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_DTOR
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "gfxReusableSurfaceWrapper.h"
 
 class gfxImageSurface;
 
 namespace mozilla {
 namespace layers {
 
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -11,18 +11,17 @@
 #include "Units.h"                      // for CSSPoint, CSSRect, etc
 #include "gfxPoint.h"                   // for gfxPoint
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/EventForwards.h"      // for WidgetInputEvent, nsEventStatus
 #include "mozilla/Monitor.h"            // for Monitor
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
-#include "nsISupportsImpl.h"
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "mozilla/Vector.h"             // for mozilla::Vector
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 
 class gfx3DMatrix;
 template <class E> class nsTArray;
 
 namespace mozilla {
 class InputData;
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -12,17 +12,16 @@
 #include "mozilla/Attributes.h"         // for MOZ_DELETE, MOZ_FINAL, etc
 #include "mozilla/RefPtr.h"             // for RefCounted
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for LayerManager::AddRef, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class AsyncPanZoomController;
 class Layer;
 class LayerManagerComposite;
 class AutoResolveRefLayers;
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -11,19 +11,19 @@
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for Point
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsString.h"                   // for nsAutoCString
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 CanvasLayerComposite::CanvasLayerComposite(LayerManagerComposite* aManager)
   : CanvasLayer(aManager, nullptr)
   , LayerComposite(aManager)
--- a/gfx/layers/composite/ColorLayerComposite.h
+++ b/gfx/layers/composite/ColorLayerComposite.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_ColorLayerComposite_H
 #define GFX_ColorLayerComposite_H
 
 #include "Layers.h"                     // for ColorLayer, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 
 struct nsIntPoint;
 struct nsIntRect;
 
 namespace mozilla {
 namespace layers {
 
 class CompositableHost;
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -9,17 +9,17 @@
 #include "ContentHost.h"                // for ContentHostDoubleBuffered, etc
 #include "Effects.h"                    // for EffectMask, Effect, etc
 #include "ImageHost.h"                  // for DeprecatedImageHostBuffered, etc
 #include "TiledContentHost.h"           // for TiledContentHost
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_WARNING
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 
 namespace mozilla {
 namespace layers {
 
 class Matrix4x4;
 class Compositor;
 
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -5,37 +5,37 @@
 
 #include "ContainerLayerComposite.h"
 #include <algorithm>                    // for min
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "Units.h"                      // for LayerRect, LayerPixel, etc
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxImageSurface.h"            // for gfxImageSurface
-#include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxUtils.h"                   // for gfxUtils, etc
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
 #include "mozilla/gfx/Rect.h"           // for IntRect, Rect
 #include "mozilla/layers/Compositor.h"  // for Compositor, etc
 #include "mozilla/layers/CompositorTypes.h"  // for DIAGNOSTIC_CONTAINER
 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
 #include "mozilla/layers/TextureHost.h"  // for CompositingRenderTarget
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsAutoTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include <vector>
 
 namespace mozilla {
 namespace layers {
 
 // HasOpaqueAncestorLayer and ContainerRender are shared between RefLayer and ContainerLayer
 static bool
 HasOpaqueAncestorLayer(Layer* aLayer)
@@ -266,21 +266,21 @@ ContainerRender(ContainerT* aContainer,
       const gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform();
       gfx::Matrix transform;
       // If we have an opaque ancestor layer, then we can be sure that
       // all the pixels we draw into are either opaque already or will be
       // covered by something opaque. Otherwise copying up the background is
       // not safe.
       if (HasOpaqueAncestorLayer(aContainer) &&
           transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) {
-        surfaceCopyNeeded = gfxPlatform::ComponentAlphaEnabled();
+        surfaceCopyNeeded = gfxPrefs::ComponentAlphaEnabled();
         sourcePoint.x += transform._31;
         sourcePoint.y += transform._32;
         aContainer->mSupportsComponentAlphaChildren
-          = gfxPlatform::ComponentAlphaEnabled();
+          = gfxPrefs::ComponentAlphaEnabled();
       }
     }
 
     sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
     if (surfaceCopyNeeded) {
       surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
     } else {
       surface = compositor->CreateRenderTarget(surfaceRect, mode);
@@ -343,17 +343,17 @@ ContainerRender(ContainerT* aContainer,
         gfx::Rect aRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
         compositor->clearFBRect(&aRect);
         layerToRender->SetClearFB(false);
       }
     } else {
       layerToRender->RenderLayer(clipRect);
     }
 
-    if (gfxPlatform::GetPrefLayersScrollGraph()) {
+    if (gfxPrefs::LayersScrollGraph()) {
       DrawVelGraph(clipRect, aManager, layerToRender->GetLayer());
     }
     // invariant: our GL context should be current here, I don't think we can
     // assert it though
   }
 
   if (needsSurface) {
     // Unbind the current surface and rebind the previous one.
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -21,21 +21,21 @@
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for etc
 #include "mozilla/layers/TextureHost.h"  // for DeprecatedTextureHost
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsAutoPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
 
 namespace mozilla {
 namespace gfx {
 class Matrix4x4;
 }
 namespace layers {
 class Compositor;
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -15,20 +15,20 @@
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/layers/TextureHost.h"  // for DeprecatedTextureHost, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsString.h"                   // for nsAutoCString
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 ImageLayerComposite::ImageLayerComposite(LayerManagerComposite* aManager)
   : ImageLayer(aManager, nullptr)
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -16,17 +16,17 @@
 #include "GeckoProfiler.h"              // for profiler_set_frame_number, etc
 #include "ImageLayerComposite.h"        // for ImageLayerComposite
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "ThebesLayerComposite.h"       // for ThebesLayerComposite
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "Units.h"                      // for ScreenIntRect
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
-#include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs
 #ifdef XP_MACOSX
 #include "gfxPlatformMac.h"
 #endif
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, TemporaryRef
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
@@ -384,28 +384,28 @@ void FPSState::DrawFPS(TimeStamp aNow,
   DrawDigits(txnFps, FontWidth * 4, 0, aCompositor, effectChain);
   DrawDigits(aFillRatio, FontWidth * 8, 0, aCompositor, effectChain);
 }
 
 static uint16_t sFrameCount = 0;
 void
 LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds)
 {
-  if (gfxPlatform::GetPrefLayersDrawFPS()) {
+  if (gfxPrefs::LayersDrawFPS()) {
     if (!mFPS) {
       mFPS = new FPSState();
     }
 
     float fillRatio = mCompositor->GetFillRatio();
     mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mCompositor);
   } else {
     mFPS = nullptr;
   }
 
-  if (gfxPlatform::DrawFrameCounter()) {
+  if (gfxPrefs::DrawFrameCounter()) {
     profiler_set_frame_number(sFrameCount);
 
     uint16_t frameNumber = sFrameCount;
     const uint16_t bitWidth = 3;
     float opacity = 1.0;
     gfx::Rect clip(0,0, bitWidth*16, bitWidth);
     for (size_t i = 0; i < 16; i++) {
 
@@ -432,27 +432,27 @@ void
 LayerManagerComposite::Render()
 {
   PROFILER_LABEL("LayerManagerComposite", "Render");
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
-  if (gfxPlatform::GetPrefLayersDump()) {
+  if (gfxPrefs::LayersDump()) {
     this->Dump();
   }
 
   /** Our more efficient but less powerful alter ego, if one is available. */
   nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
 
   if (composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
     if (mFPS) {
       double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
-      if (gfxPlatform::GetPrefLayersDrawFPS()) {
+      if (gfxPrefs::LayersDrawFPS()) {
         printf_stderr("HWComposer: FPS is %g\n", fps);
       }
     }
     mCompositor->EndFrameForExternalComposition(mWorldMatrix);
     return;
   }
 
   {
@@ -650,17 +650,17 @@ GetDisplayportCoverage(const CSSRect& aD
 }
 #endif // MOZ_ANDROID_OMTC
 
 float
 LayerManagerComposite::ComputeRenderIntegrity()
 {
   // We only ever have incomplete rendering when progressive tiles are enabled.
   Layer* root = GetRoot();
-  if (!gfxPlatform::UseProgressiveTilePainting() || !root) {
+  if (!gfxPrefs::UseProgressiveTilePainting() || !root) {
     return 1.f;
   }
 
   const FrameMetrics& rootMetrics = root->AsContainerLayer()->GetFrameMetrics();
   nsIntRect screenRect(rootMetrics.mCompositionBounds.x,
                        rootMetrics.mCompositionBounds.y,
                        rootMetrics.mCompositionBounds.width,
                        rootMetrics.mCompositionBounds.height);
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -15,18 +15,18 @@
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/Point.h"          // for IntSize, IntPoint
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat, etc
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
 
 class gfxImageSurface;
 class gfxReusableSurfaceWrapper;
 struct nsIntPoint;
 struct nsIntSize;
 struct nsIntRect;
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -15,22 +15,22 @@
 #include "mozilla/gfx/Rect.h"           // for RoundedToInt, Rect
 #include "mozilla/gfx/Types.h"          // for Filter::Filter::LINEAR
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ContentHost.h"  // for ContentHost
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsMathUtils.h"                // for NS_lround
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
 #include "nsString.h"                   // for nsAutoCString
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "GeckoProfiler.h"
 
 namespace mozilla {
 namespace layers {
 
 class TiledLayerComposer;
 
 ThebesLayerComposite::ThebesLayerComposite(LayerManagerComposite *aManager)
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -9,16 +9,17 @@
 #include "CompositorD3D11Shaders.h"
 
 #include "gfxWindowsPlatform.h"
 #include "nsIWidget.h"
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/layers/ContentHost.h"
 #include "mozilla/layers/Effects.h"
 #include "nsWindowsHelpers.h"
+#include "gfxPrefs.h"
 
 #ifdef MOZ_METRO
 #include <DXGI1_2.h>
 #endif
 
 namespace mozilla {
 
 using namespace gfx;
@@ -220,17 +221,17 @@ CompositorD3D11::Initialize()
       D3D11_COLOR_WRITE_ENABLE_ALL
     };
     blendDesc.RenderTarget[0] = rtBlendNonPremul;
     hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mNonPremulBlendState));
     if (FAILED(hr)) {
       return false;
     }
 
-    if (gfxPlatform::ComponentAlphaEnabled()) {
+    if (gfxPrefs::ComponentAlphaEnabled()) {
       D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = {
         TRUE,
         D3D11_BLEND_ONE,
         D3D11_BLEND_INV_SRC1_COLOR,
         D3D11_BLEND_OP_ADD,
         D3D11_BLEND_ONE,
         D3D11_BLEND_INV_SRC_ALPHA,
         D3D11_BLEND_OP_ADD,
@@ -628,17 +629,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
                                         nullptr, byRef(views[2]));
 
       ID3D11ShaderResourceView* srViews[3] = { views[0], views[1], views[2] };
       mContext->PSSetShaderResources(0, 3, srViews);
     }
     break;
   case EFFECT_COMPONENT_ALPHA:
     {
-      MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
+      MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
       MOZ_ASSERT(mAttachments->mComponentBlendState);
       EffectComponentAlpha* effectComponentAlpha =
         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
 
       TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11();
       TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11();
 
       if (!sourceOnWhite || !sourceOnBlack) {
@@ -880,17 +881,17 @@ CompositorD3D11::CreateShaders()
   if (FAILED(hr)) { \
     return false; \
   }
 
   LOAD_PIXEL_SHADER(SolidColorShader);
   LOAD_PIXEL_SHADER(RGBShader);
   LOAD_PIXEL_SHADER(RGBAShader);
   LOAD_PIXEL_SHADER(YCbCrShader);
-  if (gfxPlatform::ComponentAlphaEnabled()) {
+  if (gfxPrefs::ComponentAlphaEnabled()) {
     LOAD_PIXEL_SHADER(ComponentAlphaShader);
   }
 
 #undef LOAD_PIXEL_SHADER
 
   hr = mDevice->CreatePixelShader(RGBAShaderMask3D,
                                   sizeof(RGBAShaderMask3D),
                                   nullptr,
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/layers/ContentHost.h"
 #include "mozilla/layers/Effects.h"
 #include "nsWindowsHelpers.h"
 #include "Nv3DVUtils.h"
 #include "gfxFailure.h"
 #include "mozilla/layers/PCompositorParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
+#include "gfxPrefs.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 CompositorD3D9::CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget)
   : Compositor(aParent)
@@ -398,17 +399,17 @@ CompositorD3D9::DrawQuad(const gfx::Rect
       device()->SetTexture(Y, sourceY->GetD3D9Texture());
       device()->SetTexture(Cb, sourceCb->GetD3D9Texture());
       device()->SetTexture(Cr, sourceCr->GetD3D9Texture());
       maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, maskType);
     }
     break;
   case EFFECT_COMPONENT_ALPHA:
     {
-      MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
+      MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
       EffectComponentAlpha* effectComponentAlpha =
         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
       TextureSourceD3D9* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D9();
       TextureSourceD3D9* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D9();
 
       Rect textureCoords = effectComponentAlpha->mTextureCoords;
       d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                            ShaderConstantRect(
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -10,17 +10,17 @@
 #include "ImageLayerD3D9.h"
 #include "ColorLayerD3D9.h"
 #include "CanvasLayerD3D9.h"
 #include "ReadbackLayerD3D9.h"
 #include "gfxWindowsPlatform.h"
 #include "nsIGfxInfo.h"
 #include "nsServiceManagerUtils.h"
 #include "gfxFailure.h"
-#include "mozilla/Preferences.h"
+#include "gfxPrefs.h"
 
 #include "gfxCrashReporterUtils.h"
 
 namespace mozilla {
 namespace layers {
 
 LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget)
   : mWidget(aWidget)
@@ -36,17 +36,17 @@ LayerManagerD3D9::~LayerManagerD3D9()
 }
 
 bool
 LayerManagerD3D9::Initialize(bool force)
 {
   ScopedGfxFeatureReporter reporter("D3D9 Layers", force);
 
   /* XXX: this preference and blacklist code should move out of the layer manager */
-  bool forceAccelerate = gfxPlatform::GetPrefLayersAccelerationForceEnabled();
+  bool forceAccelerate = gfxPrefs::LayersAccelerationForceEnabled();
 
   nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
   if (gfxInfo) {
     int32_t status;
     if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
       if (status != nsIGfxInfo::FEATURE_NO_INFO && !forceAccelerate)
       {
         NS_WARNING("Direct3D 9-accelerated layers are not supported on this system.");
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -14,17 +14,17 @@
 #include "FrameMetrics.h"               // for FrameMetrics, etc
 #include "GestureEventListener.h"       // for GestureEventListener
 #include "InputData.h"                  // for MultiTouchInput, etc
 #include "LayerTransactionParent.h"     // for LayerTransactionParent
 #include "Units.h"                      // for CSSRect, CSSPoint, etc
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
-#include "gfxPlatform.h"                // for gfxPlatform::UseProgressiveTilePainting
+#include "gfxPrefs.h"                   // for gfxPrefs::UseProgressiveTilePainting
 #include "gfxTypes.h"                   // for gfxFloat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/BasicEvents.h"        // for Modifiers, MODIFIER_*
 #include "mozilla/ClearOnShutdown.h"    // for ClearOnShutdown
 #include "mozilla/Constants.h"          // for M_PI
 #include "mozilla/EventForwards.h"      // for nsEventStatus_*
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitorAutoEnter, etc
@@ -44,24 +44,23 @@
 #include "mozilla/layers/TaskThrottler.h"  // for TaskThrottler
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/unused.h"             // for unused
 #include "nsAlgorithm.h"                // for clamped
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsIDOMWindowUtils.h"          // for nsIDOMWindowUtils
-#include "nsISupportsImpl.h"
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsMathUtils.h"                // for NS_hypot
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsStyleConsts.h"
 #include "nsStyleStruct.h"              // for nsTimingFunction
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "nsThreadUtils.h"              // for NS_IsMainThread
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "SharedMemoryBasic.h"          // for SharedMemoryBasic
 
 // #define APZC_ENABLE_RENDERTRACE
 
 #define APZC_LOG(...)
 // #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
 #define APZC_LOG_FM(fm, prefix, ...) \