merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 10 Jul 2014 14:47:01 +0200
changeset 214068 6e9f72bdd32ed5533d1f90b75b39ac6dafaf2bb8
parent 213981 41e1a83bd7f7d31fde5c9f52dc707a086f003b84 (current diff)
parent 214067 18ed7626a49b5ef1293d6b327967eadaf956ea04 (diff)
child 214081 9c138b12276d36f4455d04894f6bc3ac2db60952
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
b2g/installer/package-manifest.in
content/media/fmp4/wmf/WMFAudioOutputSource.cpp
content/media/fmp4/wmf/WMFAudioOutputSource.h
content/media/fmp4/wmf/WMFVideoOutputSource.cpp
content/media/fmp4/wmf/WMFVideoOutputSource.h
toolkit/locales/en-US/chrome/mozapps/preferences/ocsp.dtd
toolkit/mozapps/preferences/ocsp.js
toolkit/mozapps/preferences/ocsp.xul
xpcom/ds/StringBuilder.h
xpcom/ds/nsManifestLineReader.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,11 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1033481 - Use a .mozbuild file rather than a .mk in
-m/a/tests/background/junit3 -- doesn't clean the classes* directory
-when moving from in APK to in JAR building.
+Bug 1024707 - It seems like changing 3 uuids is just too much!
\ No newline at end of file
--- a/Makefile.in
+++ b/Makefile.in
@@ -162,17 +162,17 @@ export:: install-dist-sdk
 ifndef JS_STANDALONE
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 endif
 endif
 
 default all::
-	$(call BUILDSTATUS,TIERS export $(if $(COMPILE_ENVIRONMENT),$(if $(MOZ_PSEUDO_DERECURSE),compile ))libs tools $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
+	$(call BUILDSTATUS,TIERS export $(if $(COMPILE_ENVIRONMENT),compile )libs tools $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
 
 include $(topsrcdir)/config/rules.mk
 
 distclean::
 	$(RM) $(DIST_GARBAGE)
 
 ifeq ($(OS_ARCH),WINNT)
 # we want to copy PDB files on Windows
@@ -304,16 +304,14 @@ source-package install:
 
 # Every export rule depends on config/export, but the rule for config/export
 # doesn't exist when building js non-standalone.
 .PHONY: config/export
 config/export:
 
 endif
 
-ifdef MOZ_PSEUDO_DERECURSE
 # Interdependencies for parallel export.
 js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
 accessible/xpcom/export: xpcom/xpidl/export
 ifdef ENABLE_CLANG_PLUGIN
 js/src/export config/export: build/clang-plugin/export
 endif
-endif
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -454,16 +454,28 @@ pref("services.push.userAgentID", "");
 // Maximum back-off is pingInterval.
 pref("services.push.retryBaseInterval", 5000);
 // Interval at which to ping PushServer to check connection status. In
 // milliseconds. If no reply is received within requestTimeout, the connection
 // is considered closed.
 pref("services.push.pingInterval", 1800000); // 30 minutes
 // How long before a DOMRequest errors as timeout
 pref("services.push.requestTimeout", 10000);
+pref("services.push.pingInterval.default", 180000);// 3 min
+pref("services.push.pingInterval.mobile", 180000); // 3 min
+pref("services.push.pingInterval.wifi", 180000);  // 3 min
+// Adaptive ping
+pref("services.push.adaptive.enabled", true);
+pref("services.push.adaptive.lastGoodPingInterval", 180000);// 3 min
+pref("services.push.adaptive.lastGoodPingInterval.mobile", 180000);// 3 min
+pref("services.push.adaptive.lastGoodPingInterval.wifi", 180000);// 3 min
+// Valid gap between the biggest good ping and the bad ping
+pref("services.push.adaptive.gap", 60000); // 1 minute
+// We limit the ping to this maximum value
+pref("services.push.adaptive.upperLimit", 1740000); // 29 min
 // enable udp wakeup support
 pref("services.push.udp.wakeupEnabled", true);
 // This value should be the prefix to be added to the current PDP context[1]
 // domain or a full-qualified domain name.
 // If finished with a dot, it will be added as a prefix to the PDP context
 // domain. If not, will be used as the DNS query.
 // If the DNS query is unsuccessful, the push agent will send a null netid and
 // is a server decision what to do with the device. If the MCC-MNC identifies a
--- a/b2g/components/test/unit/test_fxaccounts.js
+++ b/b2g/components/test/unit/test_fxaccounts.js
@@ -6,18 +6,21 @@
 const {utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://testing-common/httpd.js");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsMgmtService",
-                                  "resource://gre/modules/FxAccountsMgmtService.jsm",
-                                  "FxAccountsMgmtService");
+  "resource://gre/modules/FxAccountsMgmtService.jsm",
+  "FxAccountsMgmtService");
+
+XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsManager",
+  "resource://gre/modules/FxAccountsManager.jsm");
 
 // At end of test, restore original state
 const ORIGINAL_AUTH_URI = Services.prefs.getCharPref("identity.fxaccounts.auth.uri");
 let { SystemAppProxy } = Cu.import("resource://gre/modules/FxAccountsMgmtService.jsm");
 const ORIGINAL_SENDCUSTOM = SystemAppProxy._sendCustomEvent;
 do_register_cleanup(function() {
   Services.prefs.setCharPref("identity.fxaccounts.auth.uri", ORIGINAL_AUTH_URI);
   SystemAppProxy._sendCustomEvent = ORIGINAL_SENDCUSTOM;
@@ -153,16 +156,32 @@ add_test(function test_invalidEmailCase_
         method: "signIn",
         email: clientEmail,
         password: "123456",
       },
     },
   });
 });
 
+add_test(function testHandleGetAssertionError_defaultCase() {
+  do_test_pending();
+
+  FxAccountsManager.getAssertion(null).then(
+    success => {
+      // getAssertion should throw with invalid audience
+      ok(false);
+    },
+    reason => {
+      equal("INVALID_AUDIENCE", reason.error);
+      do_test_finished();
+      run_next_test();
+    }
+  )
+});
+
 // End of tests
 // Utility functions follow
 
 function httpd_setup (handlers, port=-1) {
   let server = new HttpServer();
   for (let path in handlers) {
     server.registerPathHandler(path, handlers[path]);
   }
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -18,17 +18,19 @@ DEFINES += \
 
 DEFINES += -DJAREXT=
 
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
 ifdef WIN32_REDIST_DIR
 ifdef MOZ_NO_DEBUG_RTL
-DEFINES += -DMOZ_MSVC_REDIST=$(_MSC_VER)
+DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
+DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
+DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
 endif
 endif
 
 ifdef ENABLE_MARIONETTE
 DEFINES += -DENABLE_MARIONETTE=1
 endif
 
 ifdef MOZ_PKG_MANIFEST_P
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -64,25 +64,19 @@
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
-#if MOZ_MSVC_REDIST == 1600
-@BINPATH@/msvcp100.dll
-@BINPATH@/msvcr100.dll
-#elif MOZ_MSVC_REDIST == 1700
-@BINPATH@/msvcp110.dll
-@BINPATH@/msvcr110.dll
-#elif MOZ_MSVC_REDIST == 1800
-@BINPATH@/msvcp120.dll
-@BINPATH@/msvcr120.dll
+#if MOZ_PACKAGE_MSVC_DLLS
+@BINPATH@/@MSVC_C_RUNTIME_DLL@
+@BINPATH@/@MSVC_CXX_RUNTIME_DLL@
 #endif
 #endif
 #ifdef MOZ_SHARED_MOZGLUE
 @BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
 #endif
 #ifdef MOZ_REPLACE_MALLOC
 #ifndef MOZ_JEMALLOC3
 @BINPATH@/@DLL_PREFIX@replace_jemalloc@DLL_SUFFIX@
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -490,17 +490,20 @@ var gPluginHandler = {
     let keyVals = {};
     if (plugin) {
       let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
       if (userComment)
         keyVals.PluginUserComment = userComment;
       if (this.getPluginUI(plugin, "submitURLOptIn").checked)
         keyVals.PluginContentURL = plugin.ownerDocument.URL;
     }
-    this.CrashSubmit.submit(pluginDumpID, { extraExtraKeyVals: keyVals });
+
+    let pluginProcessType = Services.crashmanager.PROCESS_TYPE_PLUGIN;
+    this.CrashSubmit.submit(pluginDumpID, { processType: pluginProcessType,
+                                            extraExtraKeyVals: keyVals });
     if (browserDumpID)
       this.CrashSubmit.submit(browserDumpID);
   },
 #endif
 
   // Callback for user clicking a "reload page" link
   reloadPage: function (browser) {
     browser.reload();
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -17,36 +17,91 @@ loop.panel = (function(_, mozL10n) {
 
   /**
    * Panel router.
    * @type {loop.desktopRouter.DesktopRouter}
    */
   var router;
 
   /**
-   * Do not disturb panel subview.
+   * Availability drop down menu subview.
    */
-  var DoNotDisturb = React.createClass({displayName: 'DoNotDisturb',
+  var AvailabilityDropdown = React.createClass({displayName: 'AvailabilityDropdown',
     getInitialState: function() {
-      return {doNotDisturb: navigator.mozLoop.doNotDisturb};
+      return {
+        doNotDisturb: navigator.mozLoop.doNotDisturb,
+        showMenu: false
+      };
+    },
+
+    showDropdownMenu: function() {
+      this.setState({showMenu: true});
+    },
+
+    hideDropdownMenu: function() {
+      this.setState({showMenu: false});
     },
 
-    handleCheckboxChange: function() {
-      // Note: side effect!
-      navigator.mozLoop.doNotDisturb = !navigator.mozLoop.doNotDisturb;
-      this.setState({doNotDisturb: navigator.mozLoop.doNotDisturb});
+    // XXX target event can either be the li, the span or the i tag
+    // this makes it easier to figure out the target by making a
+    // closure with the desired status already passed in.
+    changeAvailability: function(newAvailabilty) {
+      return function(event) {
+        // Note: side effect!
+        switch (newAvailabilty) {
+          case 'available':
+            this.setState({doNotDisturb: false});
+            navigator.mozLoop.doNotDisturb = false;
+            break;
+          case 'do-not-disturb':
+            this.setState({doNotDisturb: true});
+            navigator.mozLoop.doNotDisturb = true;
+            break;
+        }
+        this.hideDropdownMenu();
+      }.bind(this);
     },
 
     render: function() {
       // XXX https://github.com/facebook/react/issues/310 for === htmlFor
+      var cx = React.addons.classSet;
+      var availabilityStatus = cx({
+        'status': true,
+        'status-dnd': this.state.doNotDisturb,
+        'status-available': !this.state.doNotDisturb
+      });
+      var availabilityDropdown = cx({
+        'dnd-menu': true,
+        'hide': !this.state.showMenu
+      });
+      var availabilityText = this.state.doNotDisturb ?
+                              __("display_name_dnd_status") :
+                              __("display_name_available_status");
+
       return (
-        React.DOM.p( {className:"dnd"}, 
-          React.DOM.input( {type:"checkbox", checked:this.state.doNotDisturb,
-                 id:"dnd-component", onChange:this.handleCheckboxChange} ),
-          React.DOM.label( {htmlFor:"dnd-component"}, __("do_not_disturb"))
+        React.DOM.div( {className:"footer component-spacer"}, 
+          React.DOM.div( {className:"do-not-disturb"}, 
+            React.DOM.p( {className:"dnd-status", onClick:this.showDropdownMenu}, 
+              React.DOM.span(null, availabilityText),
+              React.DOM.i( {className:availabilityStatus})
+            ),
+            React.DOM.ul( {className:availabilityDropdown,
+                onMouseLeave:this.hideDropdownMenu}, 
+              React.DOM.li( {onClick:this.changeAvailability("available"),
+                  className:"dnd-menu-item dnd-make-available"}, 
+                React.DOM.i( {className:"status status-available"}),
+                React.DOM.span(null, __("display_name_available_status"))
+              ),
+              React.DOM.li( {onClick:this.changeAvailability("do-not-disturb"),
+                  className:"dnd-menu-item dnd-make-unavailable"}, 
+                React.DOM.i( {className:"status status-dnd"}),
+                React.DOM.span(null, __("display_name_dnd_status"))
+              )
+            )
+          )
         )
       );
     }
   });
 
   var ToSView = React.createClass({displayName: 'ToSView',
     getInitialState: function() {
       return {seenToS: navigator.mozLoop.getLoopCharPref('seenToS')};
@@ -55,99 +110,65 @@ loop.panel = (function(_, mozL10n) {
     render: function() {
       var tosHTML = __("legal_text_and_links", {
         "terms_of_use_url": "https://accounts.firefox.com/legal/terms",
         "privacy_notice_url": "www.mozilla.org/privacy/"
       });
 
       if (!this.state.seenToS) {
         navigator.mozLoop.setLoopCharPref('seenToS', 'seen');
-        return React.DOM.p( {className:"tos",
+        return React.DOM.p( {className:"terms-service",
                   dangerouslySetInnerHTML:{__html: tosHTML}});
       } else {
         return React.DOM.div(null );
       }
     }
   });
 
   var PanelLayout = React.createClass({displayName: 'PanelLayout',
     propTypes: {
       summary: React.PropTypes.string.isRequired
     },
 
     render: function() {
       return (
-        React.DOM.div( {className:"share generate-url"}, 
+        React.DOM.div( {className:"component-spacer share generate-url"}, 
           React.DOM.div( {className:"description"}, 
-            React.DOM.p(null, this.props.summary)
+            React.DOM.p( {className:"description-content"}, this.props.summary)
           ),
           React.DOM.div( {className:"action"}, 
             this.props.children
           )
         )
       );
     }
   });
 
   var CallUrlResult = React.createClass({displayName: 'CallUrlResult',
-    propTypes: {
-      callUrl: React.PropTypes.string.isRequired,
-      retry: React.PropTypes.func.isRequired
-    },
-
-    handleButtonClick: function() {
-      this.props.retry();
-    },
-
-    render: function() {
-      // XXX setting elem value from a state (in the callUrl input)
-      // makes it immutable ie read only but that is fine in our case.
-      // readOnly attr will suppress a warning regarding this issue
-      // from the react lib.
-      return (
-        PanelLayout( {summary:__("share_link_url")}, 
-          React.DOM.div( {className:"invite"}, 
-            React.DOM.input( {type:"url", value:this.props.callUrl, readOnly:"true"} ),
-            React.DOM.button( {onClick:this.handleButtonClick,
-                    className:"btn btn-success"}, __("new_url"))
-          )
-        )
-      );
-    }
-  });
-
-  var CallUrlForm = React.createClass({displayName: 'CallUrlForm',
-    propTypes: {
-      client: React.PropTypes.object.isRequired,
-      notifier: React.PropTypes.object.isRequired
-    },
 
     getInitialState: function() {
       return {
         pending: false,
-        disabled: true,
-        callUrl: false
+        callUrl: ''
       };
     },
 
-    retry: function() {
-      this.setState(this.getInitialState());
-    },
-
-    handleTextChange: function(event) {
-      this.setState({disabled: !event.currentTarget.value});
+    /**
+    * Returns a random 5 character string used to identify
+    * the conversation.
+    * XXX this will go away once the backend changes
+    */
+    conversationIdentifier: function() {
+      return Math.random().toString(36).substring(5);
     },
 
-    handleFormSubmit: function(event) {
-      event.preventDefault();
-
+    componentDidMount: function() {
       this.setState({pending: true});
-
-      this.props.client.requestCallUrl(
-        this.refs.caller.getDOMNode().value, this._onCallUrlReceived);
+      this.props.client.requestCallUrl(this.conversationIdentifier(),
+                                       this._onCallUrlReceived);
     },
 
     _onCallUrlReceived: function(err, callUrlData) {
       var callUrl = false;
 
       this.props.notifier.clear();
 
       if (err) {
@@ -155,40 +176,27 @@ loop.panel = (function(_, mozL10n) {
       } else {
         callUrl = callUrlData.callUrl || callUrlData.call_url;
       }
 
       this.setState({pending: false, callUrl: callUrl});
     },
 
     render: function() {
-      // If we have a call url, render result
-      if (this.state.callUrl) {
-        return (
-          CallUrlResult( {callUrl:this.state.callUrl, retry:this.retry})
-        );
-      }
-
-      // If we don't display the form
+      // XXX setting elem value from a state (in the callUrl input)
+      // makes it immutable ie read only but that is fine in our case.
+      // readOnly attr will suppress a warning regarding this issue
+      // from the react lib.
       var cx = React.addons.classSet;
       return (
-        PanelLayout( {summary:__("get_link_to_share")}, 
-          React.DOM.form( {className:"invite", onSubmit:this.handleFormSubmit}, 
-
-            React.DOM.input( {type:"text", name:"caller", ref:"caller", required:"required",
-                   className:cx({'pending': this.state.pending}),
-                   onChange:this.handleTextChange,
-                   placeholder:__("call_identifier_textinput_placeholder")} ),
-
-            React.DOM.button( {type:"submit", className:"get-url btn btn-success",
-                    disabled:this.state.disabled}, 
-              __("get_a_call_url")
-            )
-          ),
-          ToSView(null )
+        PanelLayout( {summary:__("share_link_header_text")}, 
+          React.DOM.div( {className:"invite"}, 
+            React.DOM.input( {type:"url", value:this.state.callUrl, readOnly:"true",
+                   className:cx({'pending': this.state.pending})} )
+          )
         )
       );
     }
   });
 
   /**
    * Panel view.
    */
@@ -196,19 +204,20 @@ loop.panel = (function(_, mozL10n) {
     propTypes: {
       notifier: React.PropTypes.object.isRequired,
       client: React.PropTypes.object.isRequired
     },
 
     render: function() {
       return (
         React.DOM.div(null, 
-          CallUrlForm( {client:this.props.client,
+          CallUrlResult( {client:this.props.client,
                        notifier:this.props.notifier} ),
-          DoNotDisturb(null )
+          ToSView(null ),
+          AvailabilityDropdown(null )
         )
       );
     }
   });
 
   var PanelRouter = loop.desktopRouter.DesktopRouter.extend({
     /**
      * DOM document object.
@@ -224,42 +233,49 @@ loop.panel = (function(_, mozL10n) {
       options = options || {};
       if (!options.document) {
         throw new Error("missing required document");
       }
       this.document = options.document;
 
       this._registerVisibilityChangeEvent();
 
-      this.on("panel:open panel:closed", this.reset, this);
+      this.on("panel:open panel:closed", this.clearNotifications, this);
+      this.on("panel:open", this.reset, this);
     },
 
     /**
      * Register the DOM visibility API event for the whole document, and trigger
      * appropriate events accordingly:
      *
      * - `panel:opened` when the panel is open
      * - `panel:closed` when the panel is closed
      *
      * @link  http://www.w3.org/TR/page-visibility/
      */
     _registerVisibilityChangeEvent: function() {
+      // XXX pass in the visibility status to detect when to generate a new
+      // panel view
       this.document.addEventListener("visibilitychange", function(event) {
         this.trigger(event.currentTarget.hidden ? "panel:closed"
                                                 : "panel:open");
       }.bind(this));
     },
 
     /**
      * Default entry point.
      */
     home: function() {
       this.reset();
     },
 
+    clearNotifications: function() {
+      this._notifier.clear();
+    },
+
     /**
      * Resets this router to its initial state.
      */
     reset: function() {
       this._notifier.clear();
       var client = new loop.Client({
         baseServerUrl: navigator.mozLoop.serverUrl
       });
@@ -285,15 +301,15 @@ loop.panel = (function(_, mozL10n) {
     // Notify the window that we've finished initalization and initial layout
     var evtObject = document.createEvent('Event');
     evtObject.initEvent('loopPanelInitialized', true, false);
     window.dispatchEvent(evtObject);
   }
 
   return {
     init: init,
-    DoNotDisturb: DoNotDisturb,
-    CallUrlForm: CallUrlForm,
+    AvailabilityDropdown: AvailabilityDropdown,
+    CallUrlResult: CallUrlResult,
     PanelView: PanelView,
     PanelRouter: PanelRouter,
     ToSView: ToSView
   };
 })(_, document.mozL10n);
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -17,37 +17,92 @@ loop.panel = (function(_, mozL10n) {
 
   /**
    * Panel router.
    * @type {loop.desktopRouter.DesktopRouter}
    */
   var router;
 
   /**
-   * Do not disturb panel subview.
+   * Availability drop down menu subview.
    */
-  var DoNotDisturb = React.createClass({
+  var AvailabilityDropdown = React.createClass({
     getInitialState: function() {
-      return {doNotDisturb: navigator.mozLoop.doNotDisturb};
+      return {
+        doNotDisturb: navigator.mozLoop.doNotDisturb,
+        showMenu: false
+      };
+    },
+
+    showDropdownMenu: function() {
+      this.setState({showMenu: true});
+    },
+
+    hideDropdownMenu: function() {
+      this.setState({showMenu: false});
     },
 
-    handleCheckboxChange: function() {
-      // Note: side effect!
-      navigator.mozLoop.doNotDisturb = !navigator.mozLoop.doNotDisturb;
-      this.setState({doNotDisturb: navigator.mozLoop.doNotDisturb});
+    // XXX target event can either be the li, the span or the i tag
+    // this makes it easier to figure out the target by making a
+    // closure with the desired status already passed in.
+    changeAvailability: function(newAvailabilty) {
+      return function(event) {
+        // Note: side effect!
+        switch (newAvailabilty) {
+          case 'available':
+            this.setState({doNotDisturb: false});
+            navigator.mozLoop.doNotDisturb = false;
+            break;
+          case 'do-not-disturb':
+            this.setState({doNotDisturb: true});
+            navigator.mozLoop.doNotDisturb = true;
+            break;
+        }
+        this.hideDropdownMenu();
+      }.bind(this);
     },
 
     render: function() {
       // XXX https://github.com/facebook/react/issues/310 for === htmlFor
+      var cx = React.addons.classSet;
+      var availabilityStatus = cx({
+        'status': true,
+        'status-dnd': this.state.doNotDisturb,
+        'status-available': !this.state.doNotDisturb
+      });
+      var availabilityDropdown = cx({
+        'dnd-menu': true,
+        'hide': !this.state.showMenu
+      });
+      var availabilityText = this.state.doNotDisturb ?
+                              __("display_name_dnd_status") :
+                              __("display_name_available_status");
+
       return (
-        <p className="dnd">
-          <input type="checkbox" checked={this.state.doNotDisturb}
-                 id="dnd-component" onChange={this.handleCheckboxChange} />
-          <label htmlFor="dnd-component">{__("do_not_disturb")}</label>
-        </p>
+        <div className="footer component-spacer">
+          <div className="do-not-disturb">
+            <p className="dnd-status" onClick={this.showDropdownMenu}>
+              <span>{availabilityText}</span>
+              <i className={availabilityStatus}></i>
+            </p>
+            <ul className={availabilityDropdown}
+                onMouseLeave={this.hideDropdownMenu}>
+              <li onClick={this.changeAvailability("available")}
+                  className="dnd-menu-item dnd-make-available">
+                <i className="status status-available"></i>
+                <span>{__("display_name_available_status")}</span>
+              </li>
+              <li onClick={this.changeAvailability("do-not-disturb")}
+                  className="dnd-menu-item dnd-make-unavailable">
+                <i className="status status-dnd"></i>
+                <span>{__("display_name_dnd_status")}</span>
+              </li>
+            </ul>
+          </div>
+        </div>
       );
     }
   });
 
   var ToSView = React.createClass({
     getInitialState: function() {
       return {seenToS: navigator.mozLoop.getLoopCharPref('seenToS')};
     },
@@ -55,99 +110,65 @@ loop.panel = (function(_, mozL10n) {
     render: function() {
       var tosHTML = __("legal_text_and_links", {
         "terms_of_use_url": "https://accounts.firefox.com/legal/terms",
         "privacy_notice_url": "www.mozilla.org/privacy/"
       });
 
       if (!this.state.seenToS) {
         navigator.mozLoop.setLoopCharPref('seenToS', 'seen');
-        return <p className="tos"
+        return <p className="terms-service"
                   dangerouslySetInnerHTML={{__html: tosHTML}}></p>;
       } else {
         return <div />;
       }
     }
   });
 
   var PanelLayout = React.createClass({
     propTypes: {
       summary: React.PropTypes.string.isRequired
     },
 
     render: function() {
       return (
-        <div className="share generate-url">
+        <div className="component-spacer share generate-url">
           <div className="description">
-            <p>{this.props.summary}</p>
+            <p className="description-content">{this.props.summary}</p>
           </div>
           <div className="action">
             {this.props.children}
           </div>
         </div>
       );
     }
   });
 
   var CallUrlResult = React.createClass({
-    propTypes: {
-      callUrl: React.PropTypes.string.isRequired,
-      retry: React.PropTypes.func.isRequired
-    },
-
-    handleButtonClick: function() {
-      this.props.retry();
-    },
-
-    render: function() {
-      // XXX setting elem value from a state (in the callUrl input)
-      // makes it immutable ie read only but that is fine in our case.
-      // readOnly attr will suppress a warning regarding this issue
-      // from the react lib.
-      return (
-        <PanelLayout summary={__("share_link_url")}>
-          <div className="invite">
-            <input type="url" value={this.props.callUrl} readOnly="true" />
-            <button onClick={this.handleButtonClick}
-                    className="btn btn-success">{__("new_url")}</button>
-          </div>
-        </PanelLayout>
-      );
-    }
-  });
-
-  var CallUrlForm = React.createClass({
-    propTypes: {
-      client: React.PropTypes.object.isRequired,
-      notifier: React.PropTypes.object.isRequired
-    },
 
     getInitialState: function() {
       return {
         pending: false,
-        disabled: true,
-        callUrl: false
+        callUrl: ''
       };
     },
 
-    retry: function() {
-      this.setState(this.getInitialState());
-    },
-
-    handleTextChange: function(event) {
-      this.setState({disabled: !event.currentTarget.value});
+    /**
+    * Returns a random 5 character string used to identify
+    * the conversation.
+    * XXX this will go away once the backend changes
+    */
+    conversationIdentifier: function() {
+      return Math.random().toString(36).substring(5);
     },
 
-    handleFormSubmit: function(event) {
-      event.preventDefault();
-
+    componentDidMount: function() {
       this.setState({pending: true});
-
-      this.props.client.requestCallUrl(
-        this.refs.caller.getDOMNode().value, this._onCallUrlReceived);
+      this.props.client.requestCallUrl(this.conversationIdentifier(),
+                                       this._onCallUrlReceived);
     },
 
     _onCallUrlReceived: function(err, callUrlData) {
       var callUrl = false;
 
       this.props.notifier.clear();
 
       if (err) {
@@ -155,40 +176,27 @@ loop.panel = (function(_, mozL10n) {
       } else {
         callUrl = callUrlData.callUrl || callUrlData.call_url;
       }
 
       this.setState({pending: false, callUrl: callUrl});
     },
 
     render: function() {
-      // If we have a call url, render result
-      if (this.state.callUrl) {
-        return (
-          <CallUrlResult callUrl={this.state.callUrl} retry={this.retry}/>
-        );
-      }
-
-      // If we don't display the form
+      // XXX setting elem value from a state (in the callUrl input)
+      // makes it immutable ie read only but that is fine in our case.
+      // readOnly attr will suppress a warning regarding this issue
+      // from the react lib.
       var cx = React.addons.classSet;
       return (
-        <PanelLayout summary={__("get_link_to_share")}>
-          <form className="invite" onSubmit={this.handleFormSubmit}>
-
-            <input type="text" name="caller" ref="caller" required="required"
-                   className={cx({'pending': this.state.pending})}
-                   onChange={this.handleTextChange}
-                   placeholder={__("call_identifier_textinput_placeholder")} />
-
-            <button type="submit" className="get-url btn btn-success"
-                    disabled={this.state.disabled}>
-              {__("get_a_call_url")}
-            </button>
-          </form>
-          <ToSView />
+        <PanelLayout summary={__("share_link_header_text")}>
+          <div className="invite">
+            <input type="url" value={this.state.callUrl} readOnly="true"
+                   className={cx({'pending': this.state.pending})} />
+          </div>
         </PanelLayout>
       );
     }
   });
 
   /**
    * Panel view.
    */
@@ -196,19 +204,20 @@ loop.panel = (function(_, mozL10n) {
     propTypes: {
       notifier: React.PropTypes.object.isRequired,
       client: React.PropTypes.object.isRequired
     },
 
     render: function() {
       return (
         <div>
-          <CallUrlForm client={this.props.client}
+          <CallUrlResult client={this.props.client}
                        notifier={this.props.notifier} />
-          <DoNotDisturb />
+          <ToSView />
+          <AvailabilityDropdown />
         </div>
       );
     }
   });
 
   var PanelRouter = loop.desktopRouter.DesktopRouter.extend({
     /**
      * DOM document object.
@@ -224,42 +233,49 @@ loop.panel = (function(_, mozL10n) {
       options = options || {};
       if (!options.document) {
         throw new Error("missing required document");
       }
       this.document = options.document;
 
       this._registerVisibilityChangeEvent();
 
-      this.on("panel:open panel:closed", this.reset, this);
+      this.on("panel:open panel:closed", this.clearNotifications, this);
+      this.on("panel:open", this.reset, this);
     },
 
     /**
      * Register the DOM visibility API event for the whole document, and trigger
      * appropriate events accordingly:
      *
      * - `panel:opened` when the panel is open
      * - `panel:closed` when the panel is closed
      *
      * @link  http://www.w3.org/TR/page-visibility/
      */
     _registerVisibilityChangeEvent: function() {
+      // XXX pass in the visibility status to detect when to generate a new
+      // panel view
       this.document.addEventListener("visibilitychange", function(event) {
         this.trigger(event.currentTarget.hidden ? "panel:closed"
                                                 : "panel:open");
       }.bind(this));
     },
 
     /**
      * Default entry point.
      */
     home: function() {
       this.reset();
     },
 
+    clearNotifications: function() {
+      this._notifier.clear();
+    },
+
     /**
      * Resets this router to its initial state.
      */
     reset: function() {
       this._notifier.clear();
       var client = new loop.Client({
         baseServerUrl: navigator.mozLoop.serverUrl
       });
@@ -285,15 +301,15 @@ loop.panel = (function(_, mozL10n) {
     // Notify the window that we've finished initalization and initial layout
     var evtObject = document.createEvent('Event');
     evtObject.initEvent('loopPanelInitialized', true, false);
     window.dispatchEvent(evtObject);
   }
 
   return {
     init: init,
-    DoNotDisturb: DoNotDisturb,
-    CallUrlForm: CallUrlForm,
+    AvailabilityDropdown: AvailabilityDropdown,
+    CallUrlResult: CallUrlResult,
     PanelView: PanelView,
     PanelRouter: PanelRouter,
     ToSView: ToSView
   };
 })(_, document.mozL10n);
--- a/browser/components/loop/content/shared/css/common.css
+++ b/browser/components/loop/content/shared/css/common.css
@@ -12,17 +12,17 @@
   box-sizing: border-box;
 }
 
 body {
   margin: 0;
   padding: 0;
   font-family: "Helvetica Neue", Helvetica, Arial, sans;
   font-size: 14px;
-  background: #f2f2f2;
+  background: #fbfbfb;
 }
 
 button {
   font-size: .9em; /* for some reason, text is larger within <button> */
 }
 
 img {
   border: none;
@@ -65,17 +65,25 @@ img {
   border: none;
   color: #fff;
   text-decoration: none;
   padding: .25em .5em .3em;
   border-radius: .2em;
 }
 
 .btn-info {
-  background: #428BCA;
+  background: #0095dd;
+}
+
+.btn-info:hover {
+  background: #008acb;
+}
+
+.btn-info:active {
+  background: #006b9d;
 }
 
 .btn-success {
   background: #5cb85c;
 }
 
 .btn-warning {
   background: #f0ad4e;
--- a/browser/components/loop/content/shared/css/panel.css
+++ b/browser/components/loop/content/shared/css/panel.css
@@ -1,36 +1,33 @@
 /* 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/. */
 
 /* Panel styles */
-
-a {
-  color: #0095DD;
+body {
+  font-size: 12px;
 }
 
 .panel {
   /* XXX the Social API panel behaves weirdly on inner element size changes,
      adding unwanted scrollbars; quickfix is to hide these for now. */
   overflow: hidden;
 }
 
+.component-spacer {
+  padding: 5px 10px;
+}
+
 .spacer {
   margin-bottom: 1em;
 }
 
 .share {
-  background: #f2f2f2;
-}
-
-.share .description {
-  background: #f7f7f7 url("../img/icon_32.png") no-repeat 1em 1.5em;
-  border-bottom: 1px solid #c3c3c3;
-  padding: 1em 1em 0 4em;
+  background: #fbfbfb;
 }
 
 .share .description .field {
   padding-bottom: 1em;
   border-bottom: 1px dotted #ddd;
 }
 
 .share .description select {
@@ -38,61 +35,146 @@ a {
 }
 
 .share .description .preview video {
   background: #ccc;
   float: right;
   width: 180px;
 }
 
-.share .action {
-  clear: right;
-  padding: 1em;
-  border-top: 1px solid #fafafa;
+.description-content {
+  margin: .5em 0;
+  font-size: 1em;
+  font-weight: 700;
+  font-family: Open Sans,sans-serif;
+  color: #666;
 }
 
-.share .action p {
-  margin: 0 0 1em 0;
-}
-
-p.dnd {
-  margin: 0 10px 10px 10px;
-  /* The panel won't increase its height when using a bottom margin, while it
-     works using a padding */
-  padding-bottom: 10px;
+.share .action {
+  clear: right;
 }
 
 .share .action input[type="text"],
 .share .action input[type="url"] {
   border: 1px solid #ccc; /* Overriding background style for a text input (see
                              below) resets its borders to a weird beveled style;
                              defining a default 1px border solves the issue. */
-  font-size: .9em;
-  width: 65%;
-  padding: .5em;
-  margin-right: .35em;
+  font-size: 1em;
+  width: 100%;
+  padding: 0 10px;
+  margin: 5px 0;
+  border-radius: 2px;
+  outline: 0;
+  height: 24px;
 }
 
 .share .action input.pending {
   background-image: url(../img/loading-icon.gif);
   background-repeat: no-repeat;
   background-position: right;
 }
 
 /* For some reason, buttons have a bigger default font size in FF; we're
    reducing a bit for graphical consistency here. */
 .share .action button {
   font-size: .9em;
   padding-top: 6px;
 }
 
-.tos {
-  font-size: .6rem;
-  color: #a8a8a8;
-  text-align: center;
-  padding: 1rem;
-}
-
 /* Specific cases */
 
 .panel #messages .alert {
   margin-bottom: 0;
 }
+
+/* DnD menu */
+
+.dnd-status {
+  border: 1px solid transparent;
+  padding: 2px 4px;
+  font-size: .9em;
+  cursor: pointer;
+  border-radius: 3px;
+}
+
+.dnd-status:hover {
+  border: 1px solid #DDD;
+  background: #F1F1F1;
+}
+
+.do-not-disturb {
+  position: relative;
+}
+
+.dnd-menu {
+  position: absolute;
+  top: -35px;
+  left: 10px;
+  background: #fdfdfd;
+  box-shadow: 0 1px 3px rgba(0,0,0,.3);
+  list-style: none;
+  padding: 5px;
+  border-radius: 2px;
+}
+
+.dnd-menu-item {
+  text-align: left;
+  margin: .3em 0;
+  padding: .2em .5em;
+  cursor: pointer;
+  border: 1px solid transparent;
+  border-radius: 2px;
+  font-size: 1em;
+  white-space: nowrap;
+}
+
+.dnd-menu-item:hover {
+  border: 1px solid #ccc;
+  background: #eee;
+}
+
+/* Status badges -- Available/Unavailable */
+
+.status {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  margin: 0 5px;
+  border-radius: 50%;
+}
+
+.status-available {
+  background: #6cb23e;
+}
+
+.status-dnd {
+  border: 1px solid #888;
+}
+
+/* Terms of Service */
+
+.terms-service {
+  padding: 3px 10px 10px;
+  background: #FFF;
+  text-align: center;
+  opacity: .5;
+  transition: opacity .3s;
+  font-family: 'Lucida Grande', sans-serif;
+  font-size: .9em;
+}
+
+.terms-service a {
+  color: #0095dd;
+}
+
+/* Footer */
+
+.footer {
+  font-size: 1em;
+  border-top: 1px solid #D1D1D1;
+  background: #EAEAEA;
+  color: #7F7F7F;
+  display: flex;
+  align-items: center;
+  margin-top: auto;
+  flex-direction: row;
+}
+
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -140,158 +140,169 @@ describe("loop.panel", function() {
           var router = createTestRouter({
             hidden: false,
             addEventListener: function(name, cb) {
               cb({currentTarget: {hidden: false}});
             }
           });
 
           sinon.assert.calledOnce(router.trigger);
-          sinon.assert.calledWithExactly(router.trigger, "panel:open");
+          sinon.assert.calledWith(router.trigger, "panel:open");
         });
 
       it("should trigger panel:closed when the panel document is hidden",
         function() {
           var router = createTestRouter({
             hidden: true,
             addEventListener: function(name, cb) {
               cb({currentTarget: {hidden: true}});
             }
           });
 
           sinon.assert.calledOnce(router.trigger);
-          sinon.assert.calledWithExactly(router.trigger, "panel:closed");
+          sinon.assert.calledWith(router.trigger, "panel:closed");
         });
     });
   });
 
-  describe("loop.panel.DoNotDisturb", function() {
+  describe("loop.panel.AvailabilityDropdown", function() {
     var view;
 
     beforeEach(function() {
-      view = TestUtils.renderIntoDocument(loop.panel.DoNotDisturb());
+      view = TestUtils.renderIntoDocument(loop.panel.AvailabilityDropdown());
     });
 
-    describe("Checkbox change event", function() {
+    describe("doNotDisturb preference change", function() {
       beforeEach(function() {
-        navigator.mozLoop.doNotDisturb = false;
-
-        var checkbox = TestUtils.findRenderedDOMComponentWithTag(view, "input");
-        TestUtils.Simulate.change(checkbox);
+        navigator.mozLoop.doNotDisturb = true;
       });
 
       it("should toggle the value of mozLoop.doNotDisturb", function() {
-        expect(navigator.mozLoop.doNotDisturb).eql(true);
+        var availableMenuOption = view.getDOMNode()
+                                    .querySelector(".dnd-make-available");
+
+        TestUtils.Simulate.click(availableMenuOption);
+
+        expect(navigator.mozLoop.doNotDisturb).eql(false);
       });
 
-      it("should update the DnD checkbox value", function() {
-        expect(view.getDOMNode().querySelector("input").checked).eql(true);
+      it("should toggle the dropdown menu", function() {
+        var availableMenuOption = view.getDOMNode()
+                                    .querySelector(".dnd-status span");
+
+        TestUtils.Simulate.click(availableMenuOption);
+
+        expect(view.state.showMenu).eql(true);
       });
     });
   });
 
-  describe("loop.panel.CallUrlForm", function() {
+  describe("loop.panel.PanelView", function() {
     var fakeClient, callUrlData, view;
 
     beforeEach(function() {
       callUrlData = {
         call_url: "http://call.invalid/",
         expiresAt: 1000
       };
 
       fakeClient = {
         requestCallUrl: function(_, cb) {
           cb(null, callUrlData);
         }
       };
 
-      view = TestUtils.renderIntoDocument(loop.panel.CallUrlForm({
+      view = TestUtils.renderIntoDocument(loop.panel.PanelView({
         notifier: notifier,
         client: fakeClient
       }));
     });
 
     describe("#render", function() {
       it("should render a ToSView", function() {
         TestUtils.findRenderedComponentWithType(view, loop.panel.ToSView);
       });
     });
 
-    describe("Form submit event", function() {
+  });
+
+  describe("loop.panel.CallUrlResult", function() {
+    var fakeClient, callUrlData, view;
 
-      function submitForm(callerValue) {
-        // fill caller field
-        TestUtils.Simulate.change(
-          TestUtils.findRenderedDOMComponentWithTag(view, "input"), {
-            target: {value: callerValue}
-          });
+    beforeEach(function() {
+      callUrlData = {
+        call_url: "http://call.invalid/",
+        expiresAt: 1000
+      };
 
-        // submit form
-        TestUtils.Simulate.submit(
-          TestUtils.findRenderedDOMComponentWithTag(view, "form"));
-      }
+      fakeClient = {
+        requestCallUrl: function(_, cb) {
+          cb(null, callUrlData);
+        }
+      };
 
-      it("should reset all pending notifications", function() {
-        submitForm("foo");
+      view = TestUtils.renderIntoDocument(loop.panel.CallUrlResult({
+        notifier: notifier,
+        client: fakeClient
+      }));
+    });
 
-        sinon.assert.calledOnce(notifier.clear, "clear");
-      });
+    describe("Rendering the component should generate a call URL", function() {
 
-      it("should request a call url to the server", function() {
-        fakeClient.requestCallUrl = sandbox.stub();
+      it("should make a request to requestCallUrl", function() {
+        sandbox.stub(fakeClient, "requestCallUrl");
+        var view = TestUtils.renderIntoDocument(loop.panel.CallUrlResult({
+          notifier: notifier,
+          client: fakeClient
+        }));
 
-        submitForm("foo");
-
-        sinon.assert.calledOnce(fakeClient.requestCallUrl);
-        sinon.assert.calledWith(fakeClient.requestCallUrl, "foo");
+        sinon.assert.calledOnce(view.props.client.requestCallUrl);
+        sinon.assert.calledWithExactly(view.props.client.requestCallUrl,
+                                       sinon.match.string, sinon.match.func);
       });
 
       it("should set the call url form in a pending state", function() {
         // Cancel requestCallUrl effect to keep the state pending
         fakeClient.requestCallUrl = sandbox.stub();
-
-        submitForm("foo");
+        var view = TestUtils.renderIntoDocument(loop.panel.CallUrlResult({
+          notifier: notifier,
+          client: fakeClient
+        }));
 
         expect(view.state.pending).eql(true);
       });
 
       it("should update state with the call url received", function() {
-        submitForm("foo");
-
         expect(view.state.pending).eql(false);
         expect(view.state.callUrl).eql(callUrlData.call_url);
       });
 
       it("should clear the pending state when a response is received",
         function() {
-          submitForm("foo");
-
           expect(view.state.pending).eql(false);
         });
 
       it("should update CallUrlResult with the call url", function() {
-        submitForm("foo");
-
         var urlField = view.getDOMNode().querySelector("input[type='url']");
 
         expect(urlField.value).eql(callUrlData.call_url);
       });
 
       it("should reset all pending notifications", function() {
-        submitForm("foo");
-
         sinon.assert.calledOnce(view.props.notifier.clear);
       });
 
       it("should notify the user when the operation failed", function() {
         fakeClient.requestCallUrl = function(_, cb) {
           cb("fake error");
         };
-
-        submitForm("foo");
+        var view = TestUtils.renderIntoDocument(loop.panel.CallUrlResult({
+          notifier: notifier,
+          client: fakeClient
+        }));
 
         sinon.assert.calledOnce(notifier.errorL10n);
         sinon.assert.calledWithExactly(notifier.errorL10n,
                                        "unable_retrieve_url");
       });
     });
   });
 
@@ -315,17 +326,17 @@ describe("loop.panel", function() {
         TestUtils.renderIntoDocument(loop.panel.ToSView());
 
         sinon.assert.notCalled(navigator.mozLoop.setLoopCharPref);
       });
 
     it("should render when the value of loop.seenToS is not set", function() {
       var view = TestUtils.renderIntoDocument(loop.panel.ToSView());
 
-      TestUtils.findRenderedDOMComponentWithClass(view, "tos");
+      TestUtils.findRenderedDOMComponentWithClass(view, "terms-service");
     });
 
     it("should not render when the value of loop.seenToS is set to 'seen'",
       function(done) {
         navigator.mozLoop.getLoopCharPref = function() {
           return "seen";
         };
 
--- a/browser/components/loop/test/xpcshell/test_loopservice_locales.js
+++ b/browser/components/loop/test/xpcshell/test_loopservice_locales.js
@@ -11,17 +11,17 @@ function test_locale() {
 }
 
 function test_getStrings() {
   // Try an invalid string
   Assert.equal(MozLoopService.getStrings("invalid_not_found_string"), "");
 
   // XXX This depends on the L10n values, which I'd prefer not to do, but is the
   // simplest way for now.
-  Assert.equal(MozLoopService.getStrings("get_link_to_share"),
-               '{"textContent":"Get a link and invite someone to talk"}');
+  Assert.equal(MozLoopService.getStrings("share_link_header_text"),
+               '{"textContent":"Share this link to invite someone to talk:"}');
 }
 
 function run_test()
 {
   test_locale();
   test_getStrings();
 }
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -153,16 +153,39 @@ var gAdvancedPane = {
    */
   writeCheckSpelling: function ()
   {
     var checkbox = document.getElementById("checkSpelling");
     return checkbox.checked ? (this._storedSpellCheck == 2 ? 2 : 1) : 0;
   },
 
   /**
+   * security.OCSP.enabled is an integer value for legacy reasons.
+   * A value of 1 means OCSP is enabled. Any other value means it is disabled.
+   */
+  readEnableOCSP: function ()
+  {
+    var preference = document.getElementById("security.OCSP.enabled");
+    // This is the case if the preference is the default value.
+    if (preference.value === undefined) {
+      return true;
+    }
+    return preference.value == 1;
+  },
+
+  /**
+   * See documentation for readEnableOCSP.
+   */
+  writeEnableOCSP: function ()
+  {
+    var checkbox = document.getElementById("enableOCSP");
+    return checkbox.checked ? 1 : 0;
+  },
+
+  /**
    * When the user toggles the layers.acceleration.disabled pref,
    * sync its new value to the gfx.direct2d.disabled pref too.
    */
   updateHardwareAcceleration: function()
   {
 #ifdef XP_WIN
     var fromPref = document.getElementById("layers.acceleration.disabled");
     var toPref = document.getElementById("gfx.direct2d.disabled");
@@ -818,25 +841,16 @@ var gAdvancedPane = {
   showCertificates: function ()
   {
     document.documentElement.openWindow("mozilla:certmanager",
                                         "chrome://pippki/content/certManager.xul",
                                         "", null);
   },
 
   /**
-   * Displays a dialog in which OCSP preferences can be configured.
-   */
-  showOCSP: function ()
-  {
-    document.documentElement.openSubDialog("chrome://mozapps/content/preferences/ocsp.xul",
-                                           "", null);
-  },
-
-  /**
    * Displays a dialog from which the user can manage his security devices.
    */
   showSecurityDevices: function ()
   {
     document.documentElement.openWindow("mozilla:devicemanager",
                                         "chrome://pippki/content/device_manager.xul",
                                         "", null);
   }
--- a/browser/components/preferences/advanced.xul
+++ b/browser/components/preferences/advanced.xul
@@ -86,25 +86,28 @@
       <preference id="app.update.service.enabled"
                   name="app.update.service.enabled"
                   type="bool"/>
 #endif
 #endif
 
       <preference id="browser.search.update"           name="browser.search.update"           type="bool"/>
 
-      <!-- Encryption tab -->
+      <!-- Certificates tab -->
       <preference id="security.default_personal_cert"  name="security.default_personal_cert"  type="string"/>
 
       <preference id="security.disable_button.openCertManager"
                   name="security.disable_button.openCertManager"
                   type="bool"/>
       <preference id="security.disable_button.openDeviceManager"
                   name="security.disable_button.openDeviceManager"
                   type="bool"/>
+      <preference id="security.OCSP.enabled"
+                  name="security.OCSP.enabled"
+                  type="int"/>
     </preferences>
 
 #ifdef HAVE_SHELL_SERVICE
     <stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
     <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
 #endif
     <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
 
@@ -412,24 +415,30 @@
               <radio label="&certs.auto;" accesskey="&certs.auto.accesskey;"
                      value="Select Automatically"/>
               <radio label="&certs.ask;" accesskey="&certs.ask.accesskey;"
                      value="Ask Every Time"/>
             </radiogroup>
 
             <separator/>
 
+            <checkbox id="enableOCSP"
+                      label="&enableOCSP.label;"
+                      accesskey="&enableOCSP.accesskey;"
+                      onsyncfrompreference="return gAdvancedPane.readEnableOCSP();"
+                      onsynctopreference="return gAdvancedPane.writeEnableOCSP();"
+                      preference="security.OCSP.enabled"/>
+
+            <separator/>
+
             <hbox>
               <button id="viewCertificatesButton"
                       label="&viewCerts.label;" accesskey="&viewCerts.accesskey;"
                       oncommand="gAdvancedPane.showCertificates();"
                       preference="security.disable_button.openCertManager"/>
-              <button id="verificationButton"
-                      label="&verify2.label;" accesskey="&verify2.accesskey;"
-                      oncommand="gAdvancedPane.showOCSP();"/>
               <button id="viewSecurityDevicesButton"
                       label="&viewSecurityDevices.label;" accesskey="&viewSecurityDevices.accesskey;"
                       oncommand="gAdvancedPane.showSecurityDevices();"
                       preference="security.disable_button.openDeviceManager"/>
             </hbox>
         </tabpanel>
 
       </tabpanels>
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -139,16 +139,38 @@ var gAdvancedPane = {
    * unchanged and represents a value not strictly allowed in UI.
    */
   writeCheckSpelling: function ()
   {
     var checkbox = document.getElementById("checkSpelling");
     return checkbox.checked ? (this._storedSpellCheck == 2 ? 2 : 1) : 0;
   },
 
+  /**
+   * security.OCSP.enabled is an integer value for legacy reasons.
+   * A value of 1 means OCSP is enabled. Any other value means it is disabled.
+   */
+  readEnableOCSP: function ()
+  {
+    var preference = document.getElementById("security.OCSP.enabled");
+    // This is the case if the preference is the default value.
+    if (preference.value === undefined) {
+      return true;
+    }
+    return preference.value == 1;
+  },
+
+  /**
+   * See documentation for readEnableOCSP.
+   */
+  writeEnableOCSP: function ()
+  {
+    var checkbox = document.getElementById("enableOCSP");
+    return checkbox.checked ? 1 : 0;
+  },
 
   /**
    * When the user toggles the layers.acceleration.disabled pref,
    * sync its new value to the gfx.direct2d.disabled pref too.
    */
   updateHardwareAcceleration: function()
   {
 #ifdef XP_WIN
@@ -790,26 +812,16 @@ var gAdvancedPane = {
   showCertificates: function ()
   {
     openDialog("chrome://pippki/content/certManager.xul",
                "mozilla:certmanager",
                "modal=yes", null);
   },
 
   /**
-   * Displays a dialog in which OCSP preferences can be configured.
-   */
-  showOCSP: function ()
-  {
-    openDialog("chrome://mozapps/content/preferences/ocsp.xul",
-               "mozilla:crlmanager",
-               "modal=yes", null);
-  },
-
-  /**
    * Displays a dialog from which the user can manage his security devices.
    */
   showSecurityDevices: function ()
   {
     openDialog("chrome://pippki/content/device_manager.xul",
                "mozilla:devicemanager",
                "modal=yes", null);
   }
--- a/browser/components/preferences/in-content/advanced.xul
+++ b/browser/components/preferences/in-content/advanced.xul
@@ -102,27 +102,32 @@
               type="bool"/>
 #endif
 #endif
 
   <preference id="browser.search.update"
               name="browser.search.update"
               type="bool"/>
 
-  <!-- Encryption tab -->
+  <!-- Certificates tab -->
   <preference id="security.default_personal_cert"
               name="security.default_personal_cert"
               type="string"/>
 
   <preference id="security.disable_button.openCertManager"
               name="security.disable_button.openCertManager"
               type="bool"/>
+
   <preference id="security.disable_button.openDeviceManager"
               name="security.disable_button.openDeviceManager"
               type="bool"/>
+
+  <preference id="security.OCSP.enabled"
+              name="security.OCSP.enabled"
+              type="int"/>
 </preferences>
 
 #ifdef HAVE_SHELL_SERVICE
   <stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
   <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
 #endif
   <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
 
@@ -434,24 +439,30 @@
           <radio label="&certs.auto;" accesskey="&certs.auto.accesskey;"
                 value="Select Automatically"/>
           <radio label="&certs.ask;" accesskey="&certs.ask.accesskey;"
                 value="Ask Every Time"/>
         </radiogroup>
 
         <separator/>
 
+        <checkbox id="enableOCSP"
+                  label="&enableOCSP.label;"
+                  accesskey="&enableOCSP.accesskey;"
+                  onsyncfrompreference="return gAdvancedPane.readEnableOCSP();"
+                  onsynctopreference="return gAdvancedPane.writeEnableOCSP();"
+                  preference="security.OCSP.enabled"/>
+
+        <separator/>
+
         <hbox>
           <button id="viewCertificatesButton"
                   label="&viewCerts.label;" accesskey="&viewCerts.accesskey;"
                   oncommand="gAdvancedPane.showCertificates();"
                   preference="security.disable_button.openCertManager"/>
-          <button id="verificationButton"
-                  label="&verify2.label;" accesskey="&verify2.accesskey;"
-                  oncommand="gAdvancedPane.showOCSP();"/>
           <button id="viewSecurityDevicesButton"
                   label="&viewSecurityDevices.label;" accesskey="&viewSecurityDevices.accesskey;"
                   oncommand="gAdvancedPane.showSecurityDevices();"
                   preference="security.disable_button.openDeviceManager"/>
         </hbox>
     </tabpanel>
   </tabpanels>
 </tabbox>
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -31,17 +31,16 @@
       -->
       <xul:textbox class="searchbar-textbox"
                    anonid="searchbar-textbox"
                    type="autocomplete"
                    flex="1"
                    autocompletepopup="PopupAutoComplete"
                    autocompletesearch="search-autocomplete"
                    autocompletesearchparam="searchbar-history"
-                   timeout="250"
                    maxrows="10"
                    completeselectedindex="true"
                    showcommentcolumn="true"
                    tabscrolling="true"
                    xbl:inherits="disabled,disableautocomplete,searchengine,src,newlines">
         <!--
         Empty <box> to properly position the icon within the autocomplete
         binding's anonymous children (the autocomplete binding positions <box>
@@ -531,32 +530,17 @@
                phase="capturing"
                modifiers="accel"
                action="this.selectEngine(event, (event.detail > 0));"/>
 
       <handler event="focus">
       <![CDATA[
         // Speculatively connect to the current engine's search URI (and
         // suggest URI, if different) to reduce request latency
-
-        const SUGGEST_TYPE = "application/x-suggestions+json";
-        var engine = this.currentEngine;
-        var connector =
-            Services.io.QueryInterface(Components.interfaces.nsISpeculativeConnect);
-        var searchURI = engine.getSubmission("dummy", null, "searchbar").uri;
-        let callbacks = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                              .getInterface(Components.interfaces.nsIWebNavigation)
-                              .QueryInterface(Components.interfaces.nsILoadContext);
-        connector.speculativeConnect(searchURI, callbacks);
-
-        if (engine.supportsResponseType(SUGGEST_TYPE)) {
-          var suggestURI = engine.getSubmission("dummy", SUGGEST_TYPE, "searchbar").uri;
-          if (suggestURI.prePath != searchURI.prePath)
-            connector.speculativeConnect(suggestURI, callbacks);
-        }
+        this.currentEngine.speculativeConnect({window: window});
       ]]></handler>
     </handlers>
   </binding>
 
   <binding id="searchbar-textbox"
       extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
     <implementation implements="nsIObserver">
       <constructor><![CDATA[
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -50,20 +50,16 @@ endif
 ifdef MOZ_NATIVE_NSS
 DEFINES += -DMOZ_NATIVE_NSS=1
 endif
 
 ifdef NSS_DISABLE_DBM
 DEFINES += -DNSS_DISABLE_DBM=1
 endif
 
-ifdef _MSC_VER
-DEFINES += -D_MSC_VER=$(_MSC_VER)
-endif
-
 DEFINES += -DJAREXT=
 
 ifdef MOZ_ANGLE_RENDERER
 DEFINES += -DMOZ_ANGLE_RENDERER=$(MOZ_ANGLE_RENDERER)
 ifdef MOZ_D3DCOMPILER_VISTA_DLL
 DEFINES += -DMOZ_D3DCOMPILER_VISTA_DLL=$(MOZ_D3DCOMPILER_VISTA_DLL)
 endif
 ifdef MOZ_D3DCOMPILER_XP_DLL
@@ -71,17 +67,19 @@ DEFINES += -DMOZ_D3DCOMPILER_XP_DLL=$(MO
 endif
 endif
 
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
 ifdef WIN32_REDIST_DIR
 ifdef MOZ_NO_DEBUG_RTL
-DEFINES += -DMOZ_MSVC_REDIST=$(_MSC_VER)
+DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
+DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
+DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
 endif
 endif
 
 ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
 DEFINES += -DMOZ_SHARED_MOZGLUE=1
 endif
 
 ifdef NECKO_WIFI
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -80,25 +80,19 @@
 #ifdef XP_MACOSX
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 @BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
 @BINPATH@/plugin-hang-ui@BIN_SUFFIX@
-#if MOZ_MSVC_REDIST == 1600
-@BINPATH@/msvcp100.dll
-@BINPATH@/msvcr100.dll
-#elif MOZ_MSVC_REDIST == 1700
-@BINPATH@/msvcp110.dll
-@BINPATH@/msvcr110.dll
-#elif MOZ_MSVC_REDIST == 1800
-@BINPATH@/msvcp120.dll
-@BINPATH@/msvcr120.dll
+#if MOZ_PACKAGE_MSVC_DLLS
+@BINPATH@/@MSVC_C_RUNTIME_DLL@
+@BINPATH@/@MSVC_CXX_RUNTIME_DLL@
 #endif
 #endif
 #ifndef MOZ_NATIVE_ICU
 #ifdef MOZ_SHARED_ICU
 #ifdef XP_WIN
 @BINPATH@/icudt@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
 @BINPATH@/icuin@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
 @BINPATH@/icuuc@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -1,21 +1,19 @@
 # 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/.
 
 # Panel Strings
 
-get_link_to_share=Get a link and invite someone to talk
-share_link_url=Share the link below with your friend to start your call!
-do_not_disturb=Do not disturb
+share_link_header_text=Share this link to invite someone to talk:
 
-get_a_call_url=Get a call url
-new_url=New url
-call_identifier_textinput_placeholder=Identify this call
+# Status text
+display_name_dnd_status=Do Not Disturb
+display_name_available_status=Available
 
 unable_retrieve_url=Sorry, we were unable to retrieve a call url.
 
 # Conversation Window Strings
 
 incoming_call_title=Incoming Call…
 incoming_call=Incoming call
 accept_button=Accept
@@ -33,9 +31,9 @@ close_window=Close this window
 cannot_start_call_session_not_ready=Can't start call, session is not ready.
 network_disconnected=The network connection terminated abruptly.
 
 connection_error_see_console_notification=Call failed; see console for details.
 ## LOCALIZATION NOTE (legal_text_and_links): In this item, don't translate the
 ## part between {{..}}
 legal_text_and_links=By using this product you agree to the <a \
   target="_blank" href="{{terms_of_use_url}}">Terms of Use</a> and <a \
-  href="{{privacy_notice_url}}">Privacy Notice</a>
+  href="{{privacy_notice_url}}">Privacy Notice</a>.
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -123,14 +123,14 @@
 <!ENTITY offlineAppRemove.confirm        "Remove offline data">
 
 <!ENTITY certificateTab.label            "Certificates">
 <!ENTITY certSelection.description       "When a server requests my personal certificate:">
 <!ENTITY certs.auto                      "Select one automatically">
 <!ENTITY certs.auto.accesskey            "S">
 <!ENTITY certs.ask                       "Ask me every time">
 <!ENTITY certs.ask.accesskey             "A">
+<!ENTITY enableOCSP.label                "Query OCSP responder servers to confirm the current validity of certificates">
+<!ENTITY enableOCSP.accesskey            "Q">
 <!ENTITY viewCerts.label                 "View Certificates">
 <!ENTITY viewCerts.accesskey             "C">
-<!ENTITY verify2.label                   "Validation">
-<!ENTITY verify2.accesskey               "V">
 <!ENTITY viewSecurityDevices.label       "Security Devices">
 <!ENTITY viewSecurityDevices.accesskey   "D">
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -179,20 +179,16 @@ if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBU
     export MOZ_DEBUG_SYMBOLS
 fi
 
 ])
 
 dnl A high level macro for selecting compiler options.
 AC_DEFUN([MOZ_COMPILER_OPTS],
 [
-  if test "${MOZ_PSEUDO_DERECURSE-unset}" = unset; then
-    MOZ_PSEUDO_DERECURSE=1
-  fi
-
   MOZ_DEBUGGING_OPTS
   MOZ_RTTI
 if test "$CLANG_CXX"; then
     ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
     ## returned by C functions. This is possible because we use knowledge about the ABI
     ## to typedef it to a C type with the same layout when the headers are included
     ## from C.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
--- a/build/autoconf/config.status.m4
+++ b/build/autoconf/config.status.m4
@@ -204,10 +204,8 @@ m4exit(1)
 define([AC_OUTPUT], [ifelse($#_$1, 1_, [MOZ_CREATE_CONFIG_STATUS()
 MOZ_RUN_CONFIG_STATUS()],
 [m4_fatal([Use CONFIGURE_SUBST_FILES in moz.build files to create substituted files.])]
 )])
 
 define([AC_CONFIG_HEADER],
 [m4_fatal([Use CONFIGURE_DEFINE_FILES in moz.build files to produce header files.])
 ])
-
-AC_SUBST([MOZ_PSEUDO_DERECURSE])
--- a/build/docs/build-targets.rst
+++ b/build/docs/build-targets.rst
@@ -15,33 +15,31 @@ partial tree builds can be unreliable. U
 
 export
    Build the *export* tier. The *export* tier builds everything that is
    required for C/C++ compilation. It stages all header files, processes
    IDLs, etc.
 
 compile
    Build the *compile* tier. The *compile* tier compiles all C/C++ files.
-   Only applies to builds with ``MOZ_PSEUDO_DERECURSE``.
 
 libs
    Build the *libs* tier. The *libs* tier performs linking and performs
    most build steps which aren't related to compilation.
 
 tools
    Build the *tools* tier. The *tools* tier mostly deals with supplementary
    tools and compiled tests. It will link tools against libXUL, including
    compiled test binaries.
 
 binaries:
    Recompiles and relinks C/C++ files. Only works after a complete normal
    build, but allows for much faster rebuilds of C/C++ code. For performance
    reasons, however, it skips nss, nspr, icu and ffi. This is targeted to
    improve local developer workflow when touching C/C++ code.
-   Only applies to builds with ``MOZ_PSEUDO_DERECURSE``.
 
 install-manifests
    Process install manifests. Install manifests handle the installation of
    files into the object directory.
 
    Unless ``NO_REMOVE=1`` is defined in the environment, files not accounted
    in the install manifests will be deleted from the object directory.
 
--- a/build/docs/environment-variables.rst
+++ b/build/docs/environment-variables.rst
@@ -24,26 +24,8 @@ REBUILD_CHECK
 MACH_NO_TERMINAL_FOOTER
    If defined, the terminal footer displayed when building with mach in
    a TTY is disabled.
 
 MACH_NO_WRITE_TIMES
    If defined, mach commands will not prefix output lines with the
    elapsed time since program start. This option is equivalent to
    passing ``--log-no-times`` to mach.
-
-MOZ_PSEUDO_DERECURSE
-   Activate an *experimental* build mode where make directory traversal
-   is derecursified. This mode should result in faster build times at
-   the expense of busted builds from time-to-time. The end goal is for
-   this build mode to be the default. At which time, this variable will
-   likely go away.
-
-   A value of ``1`` activates the mode with full optimizations.
-
-   A value of ``no-parallel-export`` activates the mode without
-   optimizations to the *export* tier, which are known to be slightly
-   buggy.
-
-   A value of ``no-skip`` activates the mode without optimizations to skip
-   some directories during traversal.
-
-   Values may be combined with a comma.
--- a/build/win32/Makefile.in
+++ b/build/win32/Makefile.in
@@ -3,45 +3,27 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOZ_GLUE_LDFLAGS =
 
 include $(topsrcdir)/config/rules.mk
 
 ifdef WIN32_REDIST_DIR
 
-ifeq (1600,$(_MSC_VER))
 REDIST_FILES = \
-  msvcp100.dll \
-  msvcr100.dll \
+  $(MSVC_C_RUNTIME_DLL) \
+  $(MSVC_CXX_RUNTIME_DLL) \
   $(NULL)
-endif
 
-ifeq (1700,$(_MSC_VER))
-REDIST_FILES = \
-  msvcp110.dll \
-  msvcr110.dll \
-  $(NULL)
-endif
-
-ifeq (1800,$(_MSC_VER))
-REDIST_FILES = \
-  msvcp120.dll \
-  msvcr120.dll \
-  $(NULL)
-endif
-
-ifdef REDIST_FILES
 libs-preqs = \
   $(call mkdir_deps,$(FINAL_TARGET)) \
   $(NULL)
 
 libs:: $(libs-preqs)
 	install --preserve-timestamps $(foreach f,$(REDIST_FILES),'$(WIN32_REDIST_DIR)'/$(f)) $(FINAL_TARGET)
-endif
 
 endif # WIN32_REDIST_DIR
 
 # run the binscope tool to make sure the binary and all libraries
 # are using all available Windows OS-level security mechanisms
 check::
 	$(PYTHON) $(srcdir)/autobinscope.py $(DIST)/bin/$(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/crashreporter-symbols/
 	$(PYTHON) $(srcdir)/autobinscope.py $(DIST)/bin/plugin-container.exe $(DIST)/crashreporter-symbols/
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -59,16 +59,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/BindingUtils.h"
 #include <stdint.h>
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsJSUtils.h"
+#include "nsILoadInfo.h"
 
 // This should be probably defined on some other place... but I couldn't find it
 #define WEBAPPS_PERM_NAME "webapps-manage"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
@@ -260,16 +261,30 @@ nsScriptSecurityManager::GetChannelPrinc
     aChannel->GetOwner(getter_AddRefs(owner));
     if (owner) {
         CallQueryInterface(owner, aPrincipal);
         if (*aPrincipal) {
             return NS_OK;
         }
     }
 
+    // Check whether we have an nsILoadInfo that says what we should do.
+    nsCOMPtr<nsILoadInfo> loadInfo;
+    aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+    if (loadInfo) {
+        if (loadInfo->GetLoadingSandboxed()) {
+            return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, aPrincipal);
+        }
+
+        if (loadInfo->GetForceInheritPrincipal()) {
+            NS_ADDREF(*aPrincipal = loadInfo->LoadingPrincipal());
+            return NS_OK;
+        }
+    }
+
     // OK, get the principal from the URI.  Make sure this does the same thing
     // as nsDocument::Reset and XULDocument::StartDocumentLoad.
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
 
 
     nsCOMPtr<nsILoadContext> loadContext;
--- a/config/config.mk
+++ b/config/config.mk
@@ -193,21 +193,16 @@ BUILD_TOOLS	= $(WIN_TOP_SRC)/build/unix
 else
 win_srcdir	:= $(srcdir)
 BUILD_TOOLS	= $(topsrcdir)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(topsrcdir)/build/autoconf
 
-# Disable MOZ_PSEUDO_DERECURSE on PGO builds until it's fixed.
-ifneq (,$(MOZ_PROFILE_USE)$(MOZ_PROFILE_GENERATE))
-MOZ_PSEUDO_DERECURSE :=
-endif
-
 #
 # Strip off the excessively long version numbers on these platforms,
 # but save the version to allow multiple versions of the same base
 # platform to be built in the same tree.
 #
 ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
 OS_RELEASE	:= $(basename $(OS_RELEASE))
 
--- a/config/makefiles/target_binaries.mk
+++ b/config/makefiles/target_binaries.mk
@@ -95,28 +95,22 @@ ifdef HOST_LIBRARY
 HOST_LIBRARY_FILES = $(HOST_LIBRARY)
 HOST_LIBRARY_DEST ?= $(DIST)/host/lib
 HOST_LIBRARY_TARGET = binaries libs
 INSTALL_TARGETS += HOST_LIBRARY
 endif
 
 endif # !NO_DIST_INSTALL
 
-ifdef MOZ_PSEUDO_DERECURSE
 BINARIES_INSTALL_TARGETS := $(foreach category,$(INSTALL_TARGETS),$(if $(filter binaries,$($(category)_TARGET)),$(category)))
 
 # Fill a dependency file with all the binaries installed somewhere in $(DIST)
 # and with dependencies on the relevant backend files.
 BINARIES_PP := $(MDDEPDIR)/binaries.pp
 
 $(BINARIES_PP): Makefile $(wildcard backend.mk) $(call mkdir_deps,$(MDDEPDIR))
 	@echo '$(strip $(foreach category,$(BINARIES_INSTALL_TARGETS),\
 		$(foreach file,$($(category)_FILES) $($(category)_EXECUTABLES),\
 			$($(category)_DEST)/$(notdir $(file)): $(file)%\
 		)\
 	))binaries: Makefile $(wildcard backend.mk)' | tr % '\n' > $@
 
-else
-binaries::
-	$(error The binaries target is not supported without MOZ_PSEUDO_DERECURSE)
-endif
-
 # EOF
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -17,18 +17,17 @@ endif
 #     Entering qux
 #
 # Pseudo derecurse transforms the above into:
 #   make -C foo
 #   make -C foo/bar
 #   make -C foo/baz
 #   make -C qux
 
-# MOZ_PSEUDO_DERECURSE can have values other than 1.
-ifeq (1_.,$(if $(MOZ_PSEUDO_DERECURSE),1)_$(DEPTH))
+ifeq (.,$(DEPTH))
 
 include root.mk
 
 # Disable build status for mach in top directories without TIERS.
 # In practice this disables it when recursing under js/src, which confuses mach.
 ifndef TIERS
 BUILDSTATUS =
 endif
@@ -101,16 +100,18 @@ GARBAGE_DIRS += subtiers
 
 # The export tier requires nsinstall, which is built from config. So every
 # subdirectory traversal needs to happen after traversing config.
 ifeq ($(CURRENT_TIER),export)
 $(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER)
 endif
 
 ifdef COMPILE_ENVIRONMENT
+# Disable dependency aggregation on PGO builds because of bug 934166.
+ifeq (,$(MOZ_PGO)$(MOZ_PROFILE_USE)$(MOZ_PROFILE_GENERATE))
 ifneq (,$(filter libs binaries,$(CURRENT_TIER)))
 # When doing a "libs" build, target_libs.mk ensures the interesting dependency data
 # is available in the "binaries" stamp. Once recursion is done, aggregate all that
 # dependency info so that stamps depend on relevant files and relevant other stamps.
 # When doing a "binaries" build, the aggregate dependency file and those stamps are
 # used and allow to skip recursing directories where changes are not going to require
 # rebuild. A few directories, however, are still traversed all the time, mostly, the
 # gyp managed ones and js/src.
@@ -130,16 +131,18 @@ ifeq (recurse_binaries,$(MAKECMDGOALS))
 endif
 
 endif
 
 DIST_GARBAGE += binaries-deps.mk binaries-deps
 
 endif
 
+endif
+
 else
 
 # Don't recurse if MAKELEVEL is NO_RECURSE_MAKELEVEL as defined above
 ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
 
 compile binaries libs export tools::
 
 else
@@ -180,40 +183,39 @@ endef
 
 tools export:: $(SUBMAKEFILES)
 	$(LOOP_OVER_TOOL_DIRS)
 
 endif # ifdef TIERS
 
 endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
 
-endif # ifeq (1_.,$(MOZ_PSEUDO_DERECURSE)_$(DEPTH))
-
-ifdef MOZ_PSEUDO_DERECURSE
+endif # ifeq (.,$(DEPTH))
 
 ifdef COMPILE_ENVIRONMENT
 
 # Aggregate all dependency files relevant to a binaries build except in
 # the mozilla top-level directory.
 ifneq (.,$(DEPTH))
 ALL_DEP_FILES := \
   $(BINARIES_PP) \
   $(addsuffix .pp,$(addprefix $(MDDEPDIR)/,$(sort \
     $(TARGETS) \
     $(filter-out $(SOBJS) $(ASOBJS) $(EXCLUDED_OBJS),$(OBJ_TARGETS)) \
   ))) \
   $(NULL)
 endif
 
 binaries libs:: $(TARGETS) $(BINARIES_PP)
+# Disable dependency aggregation on PGO builds because of bug 934166.
+ifeq (,$(MOZ_PGO)$(MOZ_PROFILE_USE)$(MOZ_PROFILE_GENERATE))
 ifneq (.,$(DEPTH))
 	@$(if $^,$(call py_action,link_deps,-o binaries --group-all --topsrcdir $(topsrcdir) --topobjdir $(DEPTH) --dist $(DIST) $(ALL_DEP_FILES)))
 endif
+endif
 
 endif
 
-endif # ifdef MOZ_PSEUDO_DERECURSE
-
 recurse:
 	@$(RECURSED_COMMAND)
 	$(LOOP_OVER_PARALLEL_DIRS)
 	$(LOOP_OVER_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -172,27 +172,29 @@ IMPORT_LIBRARY		:= $(LIB_PREFIX)$(SHARED
 endif
 
 ifdef MAKE_FRAMEWORK
 SHARED_LIBRARY		:= $(SHARED_LIBRARY_NAME)
 else
 SHARED_LIBRARY		:= $(DLL_PREFIX)$(SHARED_LIBRARY_NAME)$(DLL_SUFFIX)
 endif
 
+EMBED_MANIFEST_AT=2
+
+endif # MKSHLIB
+endif # FORCE_SHARED_LIB
+endif # LIBRARY
+
+ifdef MKSHLIB
 ifdef SONAME
 DSO_SONAME			= $(DLL_PREFIX)$(SONAME)$(DLL_SUFFIX)
 else
 DSO_SONAME			= $(notdir $@)
 endif
-
-EMBED_MANIFEST_AT=2
-
 endif # MKSHLIB
-endif # FORCE_SHARED_LIB
-endif # LIBRARY
 
 ifdef FORCE_STATIC_LIB
 ifndef FORCE_SHARED_LIB
 SHARED_LIBRARY		:= $(NULL)
 DEF_FILE		:= $(NULL)
 IMPORT_LIBRARY		:= $(NULL)
 endif
 endif
@@ -576,21 +578,19 @@ endif
 endif
 
 # The root makefile doesn't want to do a plain export/libs, because
 # of the tiers and because of libxul. Suppress the default rules in favor
 # of something else. Makefiles which use this var *must* provide a sensible
 # default rule before including rules.mk
 default all::
 	$(MAKE) export
-ifdef MOZ_PSEUDO_DERECURSE
 ifdef COMPILE_ENVIRONMENT
 	$(MAKE) compile
 endif
-endif
 	$(MAKE) libs
 	$(MAKE) tools
 
 ifeq ($(findstring s,$(filter-out --%, $(MAKEFLAGS))),)
 ECHO := echo
 QUIET :=
 else
 ECHO := true
--- a/configure.in
+++ b/configure.in
@@ -476,26 +476,34 @@ case "$target" in
         fi
 
         AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
         AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
 
         if test "$_CC_MAJOR_VERSION" = "16"; then
             _CC_SUITE=10
             MSVS_VERSION=2010
+            MSVC_C_RUNTIME_DLL=msvcr100.dll
+            MSVC_CXX_RUNTIME_DLL=msvcp100.dll
         elif test "$_CC_MAJOR_VERSION" = "17"; then
             _CC_SUITE=11
             MSVS_VERSION=2012
+            MSVC_C_RUNTIME_DLL=msvcr110.dll
+            MSVC_CXX_RUNTIME_DLL=msvcp110.dll
         elif test "$_CC_MAJOR_VERSION" = "18"; then
             _CC_SUITE=12
             MSVS_VERSION=2013
+            MSVC_C_RUNTIME_DLL=msvcr120.dll
+            MSVC_CXX_RUNTIME_DLL=msvcp120.dll
         else
             AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         fi
         AC_SUBST(MSVS_VERSION)
+        AC_SUBST(MSVC_C_RUNTIME_DLL)
+        AC_SUBST(MSVC_CXX_RUNTIME_DLL)
 
         # Disable SEH on clang-cl because it doesn't implement them yet.
         if test -z "$CLANG_CL"; then
             AC_DEFINE(HAVE_SEH_EXCEPTIONS)
         fi
 
         if test -n "$WIN32_REDIST_DIR"; then
           if test ! -d "$WIN32_REDIST_DIR"; then
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1988,30 +1988,37 @@ public:
 
   /**
    * Test whether the given URI always inherits a security context
    * from the document it comes from.
    */
   static nsresult URIInheritsSecurityContext(nsIURI *aURI, bool *aResult);
 
   /**
-   * Set the given principal as the owner of the given channel, if
-   * needed.  aURI must be the URI of aChannel.  aPrincipal may be
-   * null.  If aSetUpForAboutBlank is true, then about:blank will get
-   * the principal set up on it. If aForceOwner is true, the owner
-   * will be set on the channel, even if the principal can be determined
-   * from the channel.
-   * The return value is whether the principal was set up as the owner
-   * of the channel.
+   * Set the given principal as the principal on the nsILoadInfo of the given
+   * channel, and tell the channel to inherit it if needed.  aPrincipal may be
+   * null, in which case this method is a no-op.
+   *
+   * If aLoadingPrincipal is not null, aURI must be the URI of aChannel.  If
+   * aInheritForAboutBlank is true, then about:blank will be told to inherit the
+   * principal. If aForceInherit is true, the channel will be told to inherit
+   * the principal no matter what, as long as the principal is not null.
+   *
+   * If aIsSandboxed is true, then aLoadingPrincipal must not be null.  In this
+   * case, the owner on the channel, if any, will be reset to null and the
+   * nsILoadInfo will say the channel should be sandboxed.
+   *
+   * The return value is whether the channel was told to inherit the principal.
    */
   static bool SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
                                 nsIChannel* aChannel,
                                 nsIURI* aURI,
-                                bool aSetUpForAboutBlank,
-                                bool aForceOwner = false);
+                                bool aInheritForAboutBlank,
+                                bool aIsSandboxed,
+                                bool aForceInherit);
 
   static nsresult Btoa(const nsAString& aBinaryData,
                        nsAString& aAsciiBase64String);
 
   static nsresult Atob(const nsAString& aAsciiString,
                        nsAString& aBinaryData);
 
   /**
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -127,18 +127,18 @@ template<typename> class OwningNonNull;
 template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0xc9e11955, 0xaa55, 0x49a1, \
-  { 0x94, 0x29, 0x58, 0xe9, 0xbe, 0xf6, 0x79, 0x54 } }
+{ 0xa45ef8f0, 0x7c5b, 0x425d, \
+  { 0xa5, 0xe7, 0x11, 0x41, 0x5c, 0x41, 0x0c, 0x7a } }
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
   DocumentFlavorSVG, // SVGDocument
   DocumentFlavorPlain, // Just a Document
 };
@@ -846,16 +846,17 @@ public:
   enum additionalSheetType {
     eAgentSheet,
     eUserSheet,
     eAuthorSheet,
     SheetTypeCount
   };
 
   virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) = 0;
+  virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aSheet) = 0;
   virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI) = 0;
   virtual nsIStyleSheet* FirstAdditionalAuthorSheet() = 0;
 
   /**
    * Get this document's CSSLoader.  This is guaranteed to not return null.
    */
   mozilla::css::Loader* CSSLoader() const {
     return mCSSLoader;
--- a/content/base/src/DOMParser.cpp
+++ b/content/base/src/DOMParser.cpp
@@ -10,16 +10,17 @@
 #include "nsStringStream.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCRT.h"
 #include "nsStreamUtils.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsError.h"
 #include "nsPIDOMWindow.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 DOMParser::DOMParser()
   : mAttemptedInit(false)
 {
@@ -236,18 +237,21 @@ DOMParser::ParseFromStream(nsIInputStrea
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create a fake channel 
   nsCOMPtr<nsIChannel> parserChannel;
   NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nullptr,
                            nsDependentCString(contentType), nullptr);
   NS_ENSURE_STATE(parserChannel);
 
-  // More principal-faking here 
-  parserChannel->SetOwner(mOriginalPrincipal);
+  // More principal-faking here
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new LoadInfo(mOriginalPrincipal, LoadInfo::eInheritPrincipal,
+                 LoadInfo::eNotSandboxed);
+  parserChannel->SetLoadInfo(loadInfo);
 
   if (charset) {
     parserChannel->SetContentCharset(nsDependentCString(charset));
   }
 
   // Tell the document to start loading
   nsCOMPtr<nsIStreamListener> listener;
 
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/EventSource.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/EventSourceBinding.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "js/OldDebugAPI.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
@@ -370,17 +371,20 @@ EventSource::OnStartRequest(nsIRequest *
   }
 
   nsCOMPtr<nsIPrincipal> principal = mPrincipal;
   if (nsContentUtils::IsSystemPrincipal(principal)) {
     // Don't give this channel the system principal.
     principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  rv = httpChannel->SetOwner(principal);
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new LoadInfo(principal, LoadInfo::eInheritPrincipal,
+                 LoadInfo::eNotSandboxed);
+  rv = httpChannel->SetLoadInfo(loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(this, &EventSource::AnnounceConnection);
   NS_ENSURE_STATE(event);
 
   rv = NS_DispatchToMainThread(event);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -29,16 +29,17 @@
 // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h.
 #include "nsNPAPIPluginInstance.h"
 #include "mozAutoDocUpdate.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Base64.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLContentElement.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TextDecoder.h"
 #include "mozilla/dom/TouchEvent.h"
@@ -6424,83 +6425,76 @@ nsContentUtils::URIInheritsSecurityConte
                              aResult);
 }
 
 // static
 bool
 nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
                                   nsIChannel* aChannel,
                                   nsIURI* aURI,
-                                  bool aSetUpForAboutBlank,
-                                  bool aForceOwner)
-{
+                                  bool aInheritForAboutBlank,
+                                  bool aIsSandboxed,
+                                  bool aForceInherit)
+{
+  if (!aLoadingPrincipal) {
+    // Nothing to do here
+    MOZ_ASSERT(!aIsSandboxed);
+    return false;
+  }
+
+  // If we're sandboxed, make sure to clear any owner the channel
+  // might already have.
+  if (aIsSandboxed) {
+    aChannel->SetOwner(nullptr);
+  }
+
+  // Set the loadInfo of the channel, but only tell the channel to
+  // inherit if it can't provide its own security context.
   //
-  // Set the owner of the channel, but only for channels that can't
-  // provide their own security context.
-  //
-  // XXX: It seems wrong that the owner is ignored - even if one is
-  //      supplied) unless the URI is javascript or data or about:blank.
   // XXX: If this is ever changed, check all callers for what owners
   //      they're passing in.  In particular, see the code and
   //      comments in nsDocShell::LoadURI where we fall back on
   //      inheriting the owner if called from chrome.  That would be
   //      very wrong if this code changed anything but channels that
   //      can't provide their own security context!
   //
-  //      (Currently chrome URIs set the owner when they are created!
-  //      So setting a nullptr owner would be bad!)
-  //
-  // If aForceOwner is true, the owner will be set, even for a channel that
-  // can provide its own security context. This is used for the HTML5 IFRAME
-  // sandbox attribute, so we can force the channel (and its document) to
-  // explicitly have a null principal.
-  bool inherit;
-  // We expect URIInheritsSecurityContext to return success for an
-  // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
-  // This condition needs to match the one in nsDocShell::InternalLoad where
-  // we're checking for things that will use the owner.
-  if (aForceOwner || ((NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) &&
-      (inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))))) {
-#ifdef DEBUG
-    // Assert that aForceOwner is only set for null principals for non-srcdoc
-    // loads.  (Strictly speaking not all uses of about:srcdoc would be 
-    // srcdoc loads, but the URI is non-resolvable in cases where it is not).
-    if (aForceOwner) {
-      nsAutoCString uriStr;
-      aURI->GetSpec(uriStr);
-      if(!uriStr.EqualsLiteral("about:srcdoc") &&
-         !uriStr.EqualsLiteral("view-source:about:srcdoc")) {
-        nsCOMPtr<nsIURI> ownerURI;
-        nsresult rv = aLoadingPrincipal->GetURI(getter_AddRefs(ownerURI));
-        MOZ_ASSERT(NS_SUCCEEDED(rv) && SchemeIs(ownerURI, NS_NULLPRINCIPAL_SCHEME));
-      }
-    }
-#endif
-    aChannel->SetOwner(aLoadingPrincipal);
-    return true;
-  }
-
-  //
-  // file: uri special-casing
-  //
-  // If this is a file: load opened from another file: then it may need
-  // to inherit the owner from the referrer so they can script each other.
-  // If we don't set the owner explicitly then each file: gets an owner
-  // based on its own codebase later.
-  //
-  if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
-      NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) &&
-      // One more check here.  CheckMayLoad will always return true for the
-      // system principal, but we do NOT want to inherit in that case.
-      !IsSystemPrincipal(aLoadingPrincipal)) {
-    aChannel->SetOwner(aLoadingPrincipal);
-    return true;
-  }
-
-  return false;
+  // If aForceInherit is true, we will inherit, even for a channel that
+  // can provide its own security context. This is used for srcdoc loads.
+  bool inherit = aForceInherit;
+  if (!inherit) {
+    bool uriInherits;
+    // We expect URIInheritsSecurityContext to return success for an
+    // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
+    // This condition needs to match the one in nsDocShell::InternalLoad where
+    // we're checking for things that will use the owner.
+    inherit =
+      (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &uriInherits)) &&
+       (uriInherits || (aInheritForAboutBlank && NS_IsAboutBlank(aURI)))) ||
+      //
+      // file: uri special-casing
+      //
+      // If this is a file: load opened from another file: then it may need
+      // to inherit the owner from the referrer so they can script each other.
+      // If we don't set the owner explicitly then each file: gets an owner
+      // based on its own codebase later.
+      //
+      (URIIsLocalFile(aURI) &&
+       NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) &&
+       // One more check here.  CheckMayLoad will always return true for the
+       // system principal, but we do NOT want to inherit in that case.
+       !IsSystemPrincipal(aLoadingPrincipal));
+  }
+
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new LoadInfo(aLoadingPrincipal,
+                 inherit ?
+                   LoadInfo::eInheritPrincipal : LoadInfo::eDontInheritPrincipal,
+                 aIsSandboxed ? LoadInfo::eSandboxed : LoadInfo::eNotSandboxed);
+  aChannel->SetLoadInfo(loadInfo);
+  return inherit && !aIsSandboxed;
 }
 
 /* static */
 bool
 nsContentUtils::IsFullScreenApiEnabled()
 {
   return sIsFullScreenApiEnabled;
 }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4216,32 +4216,44 @@ nsDocument::LoadAdditionalStyleSheet(add
   // Loading the sheet sync.
   nsRefPtr<mozilla::css::Loader> loader = new mozilla::css::Loader();
 
   nsRefPtr<CSSStyleSheet> sheet;
   nsresult rv = loader->LoadSheetSync(aSheetURI, aType == eAgentSheet,
     true, getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mAdditionalSheets[aType].AppendObject(sheet);
   sheet->SetOwningDocument(this);
   MOZ_ASSERT(sheet->IsApplicable());
 
+  return AddAdditionalStyleSheet(aType, sheet);
+}
+
+nsresult
+nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aSheet)
+{
+  if (mAdditionalSheets[aType].Contains(aSheet))
+    return NS_ERROR_INVALID_ARG;
+
+  if (!aSheet->IsApplicable())
+    return NS_ERROR_INVALID_ARG;
+
+  mAdditionalSheets[aType].AppendObject(aSheet);
+
   BeginUpdate(UPDATE_STYLE);
   nsCOMPtr<nsIPresShell> shell = GetShell();
   if (shell) {
     nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType);
-    shell->StyleSet()->AppendStyleSheet(type, sheet);
+    shell->StyleSet()->AppendStyleSheet(type, aSheet);
   }
 
   // Passing false, so documet.styleSheets.length will not be affected by
   // these additional sheets.
-  NotifyStyleSheetAdded(sheet, false);
+  NotifyStyleSheetAdded(aSheet, false);
   EndUpdate(UPDATE_STYLE);
-
   return NS_OK;
 }
 
 void
 nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI)
 {
   MOZ_ASSERT(aSheetURI);
 
@@ -11870,16 +11882,20 @@ nsIDocument::DocAddSizeOfIncludingThis(n
   DocAddSizeOfExcludingThis(aWindowSizes);
 }
 
 static size_t
 SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet* aStyleSheet,
                                       MallocSizeOf aMallocSizeOf,
                                       void* aData)
 {
+  if (!aStyleSheet->GetOwningDocument()) {
+    // Avoid over-reporting shared sheets.
+    return 0;
+  }
   return aStyleSheet->SizeOfIncludingThis(aMallocSizeOf);
 }
 
 size_t
 nsDocument::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   // This SizeOfExcludingThis() overrides the one from nsINode.  But
   // nsDocuments can only appear at the top of the DOM tree, and we use the
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -804,16 +804,17 @@ public:
   virtual void AddStyleSheetToStyleSets(nsIStyleSheet* aSheet);
   virtual void RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet);
 
   virtual void InsertStyleSheetAt(nsIStyleSheet* aSheet, int32_t aIndex) MOZ_OVERRIDE;
   virtual void SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
                                             bool aApplicable) MOZ_OVERRIDE;
 
   virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) MOZ_OVERRIDE;
+  virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aSheet) MOZ_OVERRIDE;
   virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI) MOZ_OVERRIDE;
   virtual nsIStyleSheet* FirstAdditionalAuthorSheet() MOZ_OVERRIDE;
 
   virtual nsIChannel* GetChannel() const MOZ_OVERRIDE {
     return mChannel;
   }
 
   virtual nsIChannel* GetFailedChannel() const MOZ_OVERRIDE {
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -10,18 +10,20 @@
 #include "nsClassHashtable.h"
 #include "nsNetUtil.h"
 #include "nsIPrincipal.h"
 #include "nsDOMFile.h"
 #include "nsIDOMMediaStream.h"
 #include "mozilla/dom/MediaSource.h"
 #include "nsIMemoryReporter.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/LoadInfo.h"
 
 using mozilla::dom::DOMFileImpl;
+using mozilla::LoadInfo;
 
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   // mObject is expected to be an nsIDOMBlob, nsIDOMMediaStream, or MediaSource
   nsCOMPtr<nsISupports> mObject;
   nsCOMPtr<nsIPrincipal> mPrincipal;
@@ -501,34 +503,35 @@ nsHostObjectProtocolHandler::NewChannel(
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
                                 uri,
                                 stream);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal);
-
   nsString type;
   rv = blob->GetType(type);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (blob->IsFile()) {
     nsString filename;
     rv = blob->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
     channel->SetContentDispositionFilename(filename);
   }
 
   uint64_t size;
   rv = blob->GetSize(&size);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  channel->SetOwner(owner);
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new mozilla::LoadInfo(info->mPrincipal, LoadInfo::eInheritPrincipal,
+                          LoadInfo::eNotSandboxed);
+  channel->SetLoadInfo(loadInfo);
   channel->SetOriginalURI(uri);
   channel->SetContentType(NS_ConvertUTF16toUTF8(type));
   channel->SetContentLength(size);
 
   channel.forget(result);
 
   return NS_OK;
 }
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -2362,28 +2362,21 @@ nsObjectLoadingContent::OpenChannel()
     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));
     if (timedChannel) {
       timedChannel->SetInitiatorType(thisContent->LocalName());
     }
   }
 
   // Set up the channel's principal and such, like nsDocShell::DoURILoad does.
   // If the content being loaded should be sandboxed with respect to origin we
-  // create a new null principal here. nsContentUtils::SetUpChannelOwner is
-  // used with a flag to force it to be set as the channel owner.
-  nsCOMPtr<nsIPrincipal> ownerPrincipal;
-  uint32_t sandboxFlags = doc->GetSandboxFlags();
-  if (sandboxFlags & SANDBOXED_ORIGIN) {
-    ownerPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
-  } else {
-    // Not sandboxed - we allow the content to assume its natural owner.
-    ownerPrincipal = thisContent->NodePrincipal();
-  }
-  nsContentUtils::SetUpChannelOwner(ownerPrincipal, chan, mURI, true,
-                                    sandboxFlags & SANDBOXED_ORIGIN);
+  // tell SetUpChannelOwner that.
+  nsContentUtils::SetUpChannelOwner(thisContent->NodePrincipal(), chan, mURI,
+                                    true,
+                                    doc->GetSandboxFlags() & SANDBOXED_ORIGIN,
+                                    false);
 
   nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
   if (scriptChannel) {
     // Allow execution against our context if the principals match
     scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
   }
 
   // AsyncOpen can fail if a file does not exist.
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -8,16 +8,17 @@
 
 #ifndef XP_WIN
 #include <unistd.h>
 #endif
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/XMLHttpRequestUploadBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsIDOMDocument.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "nsIJARChannel.h"
 #include "nsIJARURI.h"
 #include "nsLayoutCID.h"
 #include "nsReadableUtils.h"
@@ -1968,17 +1969,20 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
     // principal.
     nsresult rv;
     documentPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     documentPrincipal = mPrincipal;
   }
 
-  channel->SetOwner(documentPrincipal);
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new LoadInfo(documentPrincipal, LoadInfo::eInheritPrincipal,
+                 LoadInfo::eNotSandboxed);
+  channel->SetLoadInfo(loadInfo);
 
   nsresult status;
   request->GetStatus(&status);
   mErrorLoad = mErrorLoad || NS_FAILED(status);
 
   if (mUpload && !mUploadComplete && !mErrorLoad &&
       (mState & XML_HTTP_REQUEST_ASYNC)) {
     if (mProgressTimerIsActive) {
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -2107,33 +2107,33 @@ WebGLContext::ReadPixels(GLint x, GLint 
 
     // Check the type param
     bool isReadTypeValid = false;
     bool isReadTypeFloat = false;
     switch (type) {
         case LOCAL_GL_UNSIGNED_BYTE:
             isReadTypeValid = true;
             bytesPerPixel = 1*channels;
-            requiredDataType = js::ArrayBufferView::TYPE_UINT8;
+            requiredDataType = js::Scalar::Uint8;
             break;
         case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
         case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
         case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
             isReadTypeValid = true;
             bytesPerPixel = 2;
-            requiredDataType = js::ArrayBufferView::TYPE_UINT16;
+            requiredDataType = js::Scalar::Uint16;
             break;
         case LOCAL_GL_FLOAT:
             if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
                 IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
             {
                 isReadTypeValid = true;
                 isReadTypeFloat = true;
                 bytesPerPixel = 4*channels;
-                requiredDataType = js::ArrayBufferView::TYPE_FLOAT32;
+                requiredDataType = js::Scalar::Float32;
             }
             break;
     }
     if (!isReadTypeValid)
         return ErrorInvalidEnum("readPixels: Bad type", type);
 
     const ArrayBufferView& pixbuf = pixels.Value();
     int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -1197,35 +1197,35 @@ bool
 WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func)
 {
     bool validInput = false;
     const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
 
     // First, we check for packed types
     switch (type) {
     case LOCAL_GL_UNSIGNED_BYTE:
-        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT8);
+        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint8);
         break;
 
     case LOCAL_GL_HALF_FLOAT:
     case LOCAL_GL_HALF_FLOAT_OES:
     case LOCAL_GL_UNSIGNED_SHORT:
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT16);
+        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint16);
         break;
 
     case LOCAL_GL_UNSIGNED_INT:
     case LOCAL_GL_UNSIGNED_INT_24_8:
-        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT32);
+        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint32);
         break;
 
     case LOCAL_GL_FLOAT:
-        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_FLOAT32);
+        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Float32);
         break;
 
     default:
         break;
     }
 
     if (!validInput)
         ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -78,16 +78,17 @@
 #include "nsArrayUtils.h"
 #include "nsIEffectiveTLDService.h"
 
 //AHMED 12-2
 #include "nsBidiUtils.h"
 
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/FallbackEncoding.h"
+#include "mozilla/LoadInfo.h"
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsNodeInfoManager.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsIEditorStyleSheets.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsRange.h"
@@ -1520,17 +1521,20 @@ nsHTMLDocument::Open(JSContext* cx,
     return nullptr;
   }
 
   // We can't depend on channels implementing property bags, so do our
   // base URI manually after reset.
 
   // Set the caller principal, if any, on the channel so that we'll
   // make sure to use it when we reset.
-  rv = channel->SetOwner(callerPrincipal);
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new LoadInfo(callerPrincipal, LoadInfo::eInheritPrincipal,
+                 LoadInfo::eNotSandboxed);
+  rv = channel->SetLoadInfo(loadInfo);
   if (rv.Failed()) {
     return nullptr;
   }
 
   if (callerChannel) {
     nsLoadFlags callerLoadFlags;
     rv = callerChannel->GetLoadFlags(&callerLoadFlags);
     if (rv.Failed()) {
@@ -2383,17 +2387,20 @@ nsHTMLDocument::CreateAndAddWyciwygChann
 
   // Note: we want to treat this like a "previous document" hint so that,
   // e.g. a <meta> tag in the document.write content can override it.
   SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc);
   mWyciwygChannel->SetCharsetAndSource(kCharsetFromHintPrevDoc,
                                        GetDocumentCharacterSet());
 
   // Use our new principal
-  channel->SetOwner(NodePrincipal());
+  nsCOMPtr<nsILoadInfo> loadInfo =
+    new LoadInfo(NodePrincipal(), LoadInfo::eInheritPrincipal,
+                 LoadInfo::eNotSandboxed);
+  channel->SetLoadInfo(loadInfo);
 
   // Inherit load flags from the original document's channel
   channel->SetLoadFlags(mLoadFlags);
 
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
 
   // Use the Parent document's loadgroup to trigger load notifications
   if (loadGroup && channel) {
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -808,17 +808,17 @@ public:
 
   // Seeking has started. Inform the element on the main
   // thread.
   void SeekingStarted();
 
   // Called when the backend has changed the current playback
   // position. It dispatches a timeupdate event and invalidates the frame.
   // This must be called on the main thread only.
-  void PlaybackPositionChanged();
+  virtual void PlaybackPositionChanged();
 
   // Calls mElement->UpdateReadyStateForData, telling it whether we have
   // data for the next frame and if we're buffering. Main thread only.
   virtual void UpdateReadyStateForData();
 
   // Find the end of the cached data starting at the current decoder
   // position.
   int64_t GetDownloadPosition();
--- a/content/media/fmp4/moz.build
+++ b/content/media/fmp4/moz.build
@@ -18,27 +18,27 @@ UNIFIED_SOURCES += [
 SOURCES += [
     'MP4Decoder.cpp',
     'MP4Reader.cpp',
 ]
 
 if CONFIG['MOZ_WMF']:
   EXPORTS += [
       'wmf/MFTDecoder.h',
-      'wmf/WMFAudioOutputSource.h',
+      'wmf/WMFAudioMFTManager.h',
       'wmf/WMFDecoderModule.h',
       'wmf/WMFMediaDataDecoder.h',
-      'wmf/WMFVideoOutputSource.h',
+      'wmf/WMFVideoMFTManager.h',
   ]
   UNIFIED_SOURCES += [
       'wmf/MFTDecoder.cpp',
-      'wmf/WMFAudioOutputSource.cpp',
+      'wmf/WMFAudioMFTManager.cpp',
       'wmf/WMFDecoderModule.cpp',
       'wmf/WMFMediaDataDecoder.cpp',
-      'wmf/WMFVideoOutputSource.cpp',
+      'wmf/WMFVideoMFTManager.cpp',
   ]
 
 if CONFIG['MOZ_FFMPEG']:
   EXPORTS += [
       'ffmpeg/FFmpegRuntimeLinker.h',
   ]
   UNIFIED_SOURCES += [
       'ffmpeg/FFmpegLog.cpp',
--- a/content/media/fmp4/wmf/MFTDecoder.cpp
+++ b/content/media/fmp4/wmf/MFTDecoder.cpp
@@ -16,16 +16,17 @@ PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...)
 #endif
 
 
 namespace mozilla {
 
 MFTDecoder::MFTDecoder()
   : mMFTProvidesOutputSamples(false)
+  , mDiscontinuity(true)
 {
   memset(&mInputStreamInfo, 0, sizeof(MFT_INPUT_STREAM_INFO));
   memset(&mOutputStreamInfo, 0, sizeof(MFT_OUTPUT_STREAM_INFO));
 }
 
 MFTDecoder::~MFTDecoder()
 {
 }
@@ -232,16 +233,21 @@ MFTDecoder::Output(RefPtr<IMFSample>* aO
     // so don't warn on encountering it.
     return hr;
   }
   // Treat other errors as unexpected, and warn.
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   MOZ_ASSERT(output.pSample);
 
+  if (mDiscontinuity) {
+    output.pSample->SetUINT32(MFSampleExtension_Discontinuity, TRUE);
+    mDiscontinuity = false;
+  }
+
   *aOutput = output.pSample; // AddRefs
   if (mMFTProvidesOutputSamples) {
     // If the MFT is providing samples, we must release the sample here.
     // Typically only the H.264 MFT provides samples when using DXVA,
     // and it always re-uses the same sample, so if we don't release it
     // MFT::ProcessOutput() deadlocks waiting for the sample to be released.
     output.pSample->Release();
     output.pSample = nullptr;
@@ -272,16 +278,18 @@ MFTDecoder::Input(const uint8_t* aData,
 }
 
 HRESULT
 MFTDecoder::Flush()
 {
   HRESULT hr = SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
+  mDiscontinuity = true;
+
   return S_OK;
 }
 
 HRESULT
 MFTDecoder::GetOutputMediaType(RefPtr<IMFMediaType>& aMediaType)
 {
   NS_ENSURE_TRUE(mDecoder, E_POINTER);
   return mDecoder->GetOutputCurrentType(0, byRef(aMediaType));
--- a/content/media/fmp4/wmf/MFTDecoder.h
+++ b/content/media/fmp4/wmf/MFTDecoder.h
@@ -91,13 +91,16 @@ private:
   MFT_OUTPUT_STREAM_INFO mOutputStreamInfo;
 
   RefPtr<IMFTransform> mDecoder;
 
   GUID mOutputSubtype;
 
   // True if the IMFTransform allocates the samples that it returns.
   bool mMFTProvidesOutputSamples;
+
+  // True if we need to mark the next sample as a discontinuity.
+  bool mDiscontinuity;
 };
 
 } // namespace mozilla
 
 #endif
rename from content/media/fmp4/wmf/WMFAudioOutputSource.cpp
rename to content/media/fmp4/wmf/WMFAudioMFTManager.cpp
--- a/content/media/fmp4/wmf/WMFAudioOutputSource.cpp
+++ b/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "WMFAudioOutputSource.h"
+#include "WMFAudioMFTManager.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "VideoUtils.h"
 #include "WMFUtils.h"
 #include "nsTArray.h"
 
 #include "prlog.h"
 
 #ifdef PR_LOGGING
@@ -61,38 +61,38 @@ AACAudioSpecificConfigToUserData(const u
   WORD* w = (WORD*)heeInfo;
   w[0] = 0x1; // Payload type ADTS
   w[1] = 0xFE; // Profile level indication, none specified.
 
   aOutUserData.AppendElements(heeInfo, heeInfoLen);
   aOutUserData.AppendElements(aAudioSpecConfig, aConfigLength);
 }
 
-WMFAudioOutputSource::WMFAudioOutputSource(
+WMFAudioMFTManager::WMFAudioMFTManager(
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : mAudioChannels(aConfig.channel_count)
   , mAudioBytesPerSample(aConfig.bits_per_sample / 8)
   , mAudioRate(aConfig.samples_per_second)
   , mAudioFrameOffset(0)
   , mAudioFrameSum(0)
   , mMustRecaptureAudioPosition(true)
 {
-  MOZ_COUNT_CTOR(WMFAudioOutputSource);
+  MOZ_COUNT_CTOR(WMFAudioMFTManager);
   AACAudioSpecificConfigToUserData(&aConfig.audio_specific_config[0],
                                    aConfig.audio_specific_config.length(),
                                    mUserData);
 }
 
-WMFAudioOutputSource::~WMFAudioOutputSource()
+WMFAudioMFTManager::~WMFAudioMFTManager()
 {
-  MOZ_COUNT_DTOR(WMFAudioOutputSource);
+  MOZ_COUNT_DTOR(WMFAudioMFTManager);
 }
 
 TemporaryRef<MFTDecoder>
-WMFAudioOutputSource::Init()
+WMFAudioMFTManager::Init()
 {
   RefPtr<MFTDecoder> decoder(new MFTDecoder());
 
   HRESULT hr = decoder->Create(CLSID_CMSAACDecMFT);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   // Setup input/output media types
   RefPtr<IMFMediaType> type;
@@ -124,26 +124,26 @@ WMFAudioOutputSource::Init()
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   mDecoder = decoder;
 
   return decoder.forget();
 }
 
 HRESULT
-WMFAudioOutputSource::Input(mp4_demuxer::MP4Sample* aSample)
+WMFAudioMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
 {
   const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
   uint32_t length = aSample->size;
   return mDecoder->Input(data, length, aSample->composition_timestamp);
 }
 
 HRESULT
-WMFAudioOutputSource::Output(int64_t aStreamOffset,
-                        nsAutoPtr<MediaData>& aOutData)
+WMFAudioMFTManager::Output(int64_t aStreamOffset,
+                           nsAutoPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   RefPtr<IMFSample> sample;
   HRESULT hr = mDecoder->Output(&sample);
   if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
     return MF_E_TRANSFORM_NEED_MORE_INPUT;
   }
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
rename from content/media/fmp4/wmf/WMFAudioOutputSource.h
rename to content/media/fmp4/wmf/WMFAudioMFTManager.h
--- a/content/media/fmp4/wmf/WMFAudioOutputSource.h
+++ b/content/media/fmp4/wmf/WMFAudioMFTManager.h
@@ -10,20 +10,20 @@
 #include "WMF.h"
 #include "MP4Reader.h"
 #include "MFTDecoder.h"
 #include "mozilla/RefPtr.h"
 #include "WMFMediaDataDecoder.h"
 
 namespace mozilla {
 
-class WMFAudioOutputSource : public WMFOutputSource {
+class WMFAudioMFTManager : public MFTManager {
 public:
-  WMFAudioOutputSource(const mp4_demuxer::AudioDecoderConfig& aConfig);
-  ~WMFAudioOutputSource();
+  WMFAudioMFTManager(const mp4_demuxer::AudioDecoderConfig& aConfig);
+  ~WMFAudioMFTManager();
 
   virtual TemporaryRef<MFTDecoder> Init() MOZ_OVERRIDE;
 
   virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   // Note WMF's AAC decoder sometimes output negatively timestamped samples,
   // presumably they're the preroll samples, and we strip them. We may return
   // a null aOutput in this case.
--- a/content/media/fmp4/wmf/WMFDecoderModule.cpp
+++ b/content/media/fmp4/wmf/WMFDecoderModule.cpp
@@ -2,18 +2,18 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WMF.h"
 #include "WMFDecoderModule.h"
 #include "WMFDecoder.h"
-#include "WMFVideoOutputSource.h"
-#include "WMFAudioOutputSource.h"
+#include "WMFVideoMFTManager.h"
+#include "WMFAudioMFTManager.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/DebugOnly.h"
 #include "WMFMediaDataDecoder.h"
 
 namespace mozilla {
 
 bool WMFDecoderModule::sIsWMFEnabled = false;
 bool WMFDecoderModule::sDXVAEnabled = false;
@@ -65,27 +65,27 @@ WMFDecoderModule::Shutdown()
 
 MediaDataDecoder*
 WMFDecoderModule::CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                                     mozilla::layers::LayersBackend aLayersBackend,
                                     mozilla::layers::ImageContainer* aImageContainer,
                                     MediaTaskQueue* aVideoTaskQueue,
                                     MediaDataDecoderCallback* aCallback)
 {
-  return new WMFMediaDataDecoder(new WMFVideoOutputSource(aConfig,
-                                                          aLayersBackend,
-                                                          aImageContainer,
-                                                          sDXVAEnabled),
+  return new WMFMediaDataDecoder(new WMFVideoMFTManager(aConfig,
+                                                        aLayersBackend,
+                                                        aImageContainer,
+                                                        sDXVAEnabled),
                                  aVideoTaskQueue,
                                  aCallback);
 }
 
 MediaDataDecoder*
 WMFDecoderModule::CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                                    MediaTaskQueue* aAudioTaskQueue,
                                    MediaDataDecoderCallback* aCallback)
 {
-  return new WMFMediaDataDecoder(new WMFAudioOutputSource(aConfig),
+  return new WMFMediaDataDecoder(new WMFAudioMFTManager(aConfig),
                                  aAudioTaskQueue,
                                  aCallback);
 }
 
 } // namespace mozilla
--- a/content/media/fmp4/wmf/WMFMediaDataDecoder.cpp
+++ b/content/media/fmp4/wmf/WMFMediaDataDecoder.cpp
@@ -16,35 +16,35 @@ PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
 #endif
 
 
 namespace mozilla {
 
-WMFMediaDataDecoder::WMFMediaDataDecoder(WMFOutputSource* aSource,
+WMFMediaDataDecoder::WMFMediaDataDecoder(MFTManager* aMFTManager,
                                          MediaTaskQueue* aTaskQueue,
                                          MediaDataDecoderCallback* aCallback)
   : mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
-  , mSource(aSource)
+  , mMFTManager(aMFTManager)
 {
   MOZ_COUNT_CTOR(WMFMediaDataDecoder);
 }
 
 WMFMediaDataDecoder::~WMFMediaDataDecoder()
 {
   MOZ_COUNT_DTOR(WMFMediaDataDecoder);
 }
 
 nsresult
 WMFMediaDataDecoder::Init()
 {
-  mDecoder = mSource->Init();
+  mDecoder = mMFTManager->Init();
   NS_ENSURE_TRUE(mDecoder, NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 nsresult
 WMFMediaDataDecoder::Shutdown()
 {
@@ -62,34 +62,34 @@ WMFMediaDataDecoder::Input(mp4_demuxer::
       &WMFMediaDataDecoder::ProcessDecode,
       nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
   return NS_OK;
 }
 
 void
 WMFMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
 {
-  HRESULT hr = mSource->Input(aSample);
+  HRESULT hr = mMFTManager->Input(aSample);
   if (FAILED(hr)) {
-    NS_WARNING("WMFOutputSource rejected sample");
+    NS_WARNING("MFTManager rejected sample");
     mCallback->Error();
     return;
   }
 
   mLastStreamOffset = aSample->byte_offset;
 
   ProcessOutput();
 }
 
 void
 WMFMediaDataDecoder::ProcessOutput()
 {
   nsAutoPtr<MediaData> output;
   HRESULT hr = S_OK;
-  while (SUCCEEDED(hr = mSource->Output(mLastStreamOffset, output)) &&
+  while (SUCCEEDED(hr = mMFTManager->Output(mLastStreamOffset, output)) &&
          output) {
     mCallback->Output(output.forget());
   }
   if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
     if (mTaskQueue->IsEmpty()) {
       mCallback->InputExhausted();
     }
   } else if (FAILED(hr)) {
--- a/content/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/content/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -17,19 +17,19 @@ namespace mp4_demuxer {
 class MP4Sample;
 }
 
 namespace mozilla {
 
 // Encapsulates the initialization of the MFTDecoder appropriate for decoding
 // a given stream, and the process of converting the IMFSample produced
 // by the MFT into a MediaData object.
-class WMFOutputSource {
+class MFTManager {
 public:
-  virtual ~WMFOutputSource() {}
+  virtual ~MFTManager() {}
 
   // Creates an initializs the MFTDecoder.
   // Returns nullptr on failure.
   virtual TemporaryRef<MFTDecoder> Init() = 0;
 
   // Submit a compressed sample for decoding.
   // This should forward to the MFTDecoder after performing
   // any required sample formatting.
@@ -41,23 +41,23 @@ public:
   // enough data to produce more output. If this returns a failure code other
   // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the
   // MP4Reader.
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsAutoPtr<MediaData>& aOutput) = 0;
 };
 
 // Decodes audio and video using Windows Media Foundation. Samples are decoded
-// using the MFTDecoder created by the WMFOutputSource. This class implements
+// using the MFTDecoder created by the MFTManager. This class implements
 // the higher-level logic that drives mapping the MFT to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
-// type are handled by WMFOutputSource and the MFTDecoder it creates.
+// type are handled by MFTManager and the MFTDecoder it creates.
 class WMFMediaDataDecoder : public MediaDataDecoder {
 public:
-  WMFMediaDataDecoder(WMFOutputSource* aOutputSource,
+  WMFMediaDataDecoder(MFTManager* aOutputSource,
                       MediaTaskQueue* aAudioTaskQueue,
                       MediaDataDecoderCallback* aCallback);
   ~WMFMediaDataDecoder();
 
   virtual nsresult Init() MOZ_OVERRIDE;
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
 
@@ -80,17 +80,17 @@ private:
   // Called on the task queue. Orders the MFT to drain, and then extracts
   // all available output.
   void ProcessDrain();
 
   RefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
   RefPtr<MFTDecoder> mDecoder;
-  nsAutoPtr<WMFOutputSource> mSource;
+  nsAutoPtr<MFTManager> mMFTManager;
 
   // The last offset into the media resource that was passed into Input().
   // This is used to approximate the decoder's position in the media resource.
   int64_t mLastStreamOffset;
 };
 
 } // namespace mozilla
 
rename from content/media/fmp4/wmf/WMFVideoOutputSource.cpp
rename to content/media/fmp4/wmf/WMFVideoMFTManager.cpp
--- a/content/media/fmp4/wmf/WMFVideoOutputSource.cpp
+++ b/content/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "WMFVideoOutputSource.h"
+#include "WMFVideoMFTManager.h"
 #include "MediaDecoderReader.h"
 #include "WMFUtils.h"
 #include "ImageContainer.h"
 #include "VideoUtils.h"
 #include "DXVA2Manager.h"
 #include "nsThreadUtils.h"
 #include "Layers.h"
 #include "mozilla/layers/LayersTypes.h"
@@ -27,54 +27,54 @@ PRLogModuleInfo* GetDemuxerLog();
 
 using mozilla::gfx::ToIntRect;
 using mozilla::layers::Image;
 using mozilla::layers::LayerManager;
 using mozilla::layers::LayersBackend;
 
 namespace mozilla {
 
-WMFVideoOutputSource::WMFVideoOutputSource(
+WMFVideoMFTManager::WMFVideoMFTManager(
                             const mp4_demuxer::VideoDecoderConfig& aConfig,
                             mozilla::layers::LayersBackend aLayersBackend,
                             mozilla::layers::ImageContainer* aImageContainer,
                             bool aDXVAEnabled)
   : mVideoStride(0)
   , mVideoWidth(0)
   , mVideoHeight(0)
   , mConfig(aConfig)
   , mImageContainer(aImageContainer)
   , mDXVAEnabled(aDXVAEnabled)
   , mLayersBackend(aLayersBackend)
   , mUseHwAccel(false)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
   MOZ_ASSERT(mImageContainer);
-  MOZ_COUNT_CTOR(WMFVideoOutputSource);
+  MOZ_COUNT_CTOR(WMFVideoMFTManager);
 }
 
-WMFVideoOutputSource::~WMFVideoOutputSource()
+WMFVideoMFTManager::~WMFVideoMFTManager()
 {
-  MOZ_COUNT_DTOR(WMFVideoOutputSource);
+  MOZ_COUNT_DTOR(WMFVideoMFTManager);
   // Ensure DXVA/D3D9 related objects are released on the main thread.
   DeleteOnMainThread(mDXVA2Manager);
 }
 
 class CreateDXVAManagerEvent : public nsRunnable {
 public:
   NS_IMETHOD Run() {
     NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
     mDXVA2Manager = DXVA2Manager::Create();
     return NS_OK;
   }
   nsAutoPtr<DXVA2Manager> mDXVA2Manager;
 };
 
 bool
-WMFVideoOutputSource::InitializeDXVA()
+WMFVideoMFTManager::InitializeDXVA()
 {
   // If we use DXVA but aren't running with a D3D layer manager then the
   // readback of decoded video frames from GPU to CPU memory grinds painting
   // to a halt, and makes playback performance *worse*.
   if (!mDXVAEnabled ||
       (mLayersBackend != LayersBackend::LAYERS_D3D9 &&
        mLayersBackend != LayersBackend::LAYERS_D3D10 &&
        mLayersBackend != LayersBackend::LAYERS_D3D11)) {
@@ -85,17 +85,17 @@ WMFVideoOutputSource::InitializeDXVA()
   nsRefPtr<CreateDXVAManagerEvent> event(new CreateDXVAManagerEvent());
   NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
   mDXVA2Manager = event->mDXVA2Manager;
 
   return mDXVA2Manager != nullptr;
 }
 
 TemporaryRef<MFTDecoder>
-WMFVideoOutputSource::Init()
+WMFVideoMFTManager::Init()
 {
   bool useDxva = InitializeDXVA();
 
   RefPtr<MFTDecoder> decoder(new MFTDecoder());
 
   HRESULT hr = decoder->Create(CLSID_CMSH264DecoderMFT);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
@@ -139,28 +139,28 @@ WMFVideoOutputSource::Init()
 
   mDecoder = decoder;
   LOG("Video Decoder initialized, Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
 
   return decoder.forget();
 }
 
 HRESULT
-WMFVideoOutputSource::Input(mp4_demuxer::MP4Sample* aSample)
+WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
 {
   // We must prepare samples in AVC Annex B.
   mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
   // Forward sample data to the decoder.
   const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
   uint32_t length = aSample->size;
   return mDecoder->Input(data, length, aSample->composition_timestamp);
 }
 
 HRESULT
-WMFVideoOutputSource::ConfigureVideoFrameGeometry()
+WMFVideoMFTManager::ConfigureVideoFrameGeometry()
 {
   RefPtr<IMFMediaType> mediaType;
   HRESULT hr = mDecoder->GetOutputMediaType(mediaType);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   // Verify that the video subtype is what we expect it to be.
   // When using hardware acceleration/DXVA2 the video format should
   // be NV12, which is DXVA2's preferred format. For software decoding
@@ -211,19 +211,19 @@ WMFVideoOutputSource::ConfigureVideoFram
       mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
       displaySize.width, displaySize.height,
       aspectNum, aspectDenom);
 
   return S_OK;
 }
 
 HRESULT
-WMFVideoOutputSource::CreateBasicVideoFrame(IMFSample* aSample,
-                                       int64_t aStreamOffset,
-                                       VideoData** aOutVideoData)
+WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
+                                          int64_t aStreamOffset,
+                                          VideoData** aOutVideoData)
 {
   NS_ENSURE_TRUE(aSample, E_POINTER);
   NS_ENSURE_TRUE(aOutVideoData, E_POINTER);
 
   *aOutVideoData = nullptr;
 
   HRESULT hr;
   RefPtr<IMFMediaBuffer> buffer;
@@ -306,19 +306,19 @@ WMFVideoOutputSource::CreateBasicVideoFr
   }
 
   *aOutVideoData = v;
 
   return S_OK;
 }
 
 HRESULT
-WMFVideoOutputSource::CreateD3DVideoFrame(IMFSample* aSample,
-                                     int64_t aStreamOffset,
-                                     VideoData** aOutVideoData)
+WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
+                                        int64_t aStreamOffset,
+                                        VideoData** aOutVideoData)
 {
   NS_ENSURE_TRUE(aSample, E_POINTER);
   NS_ENSURE_TRUE(aOutVideoData, E_POINTER);
   NS_ENSURE_TRUE(mDXVA2Manager, E_ABORT);
   NS_ENSURE_TRUE(mUseHwAccel, E_ABORT);
 
   *aOutVideoData = nullptr;
   HRESULT hr;
@@ -346,18 +346,18 @@ WMFVideoOutputSource::CreateD3DVideoFram
   NS_ENSURE_TRUE(v, E_FAIL);
   *aOutVideoData = v;
 
   return S_OK;
 }
 
 // Blocks until decoded sample is produced by the deoder.
 HRESULT
-WMFVideoOutputSource::Output(int64_t aStreamOffset,
-                        nsAutoPtr<MediaData>& aOutData)
+WMFVideoMFTManager::Output(int64_t aStreamOffset,
+                           nsAutoPtr<MediaData>& aOutData)
 {
   RefPtr<IMFSample> sample;
   HRESULT hr;
   aOutData = nullptr;
 
   // Loop until we decode a sample, or an unexpected error that we can't
   // handle occurs.
   while (true) {
@@ -374,17 +374,17 @@ WMFVideoOutputSource::Output(int64_t aSt
       NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
       // Loop back and try decoding again...
       continue;
     }
     if (SUCCEEDED(hr)) {
       break;
     }
     // Else unexpected error, assert, and bail.
-    NS_WARNING("WMFVideoOutputSource::Output() unexpected error");
+    NS_WARNING("WMFVideoMFTManager::Output() unexpected error");
     return E_FAIL;
   }
 
   VideoData* frame = nullptr;
   if (mUseHwAccel) {
     hr = CreateD3DVideoFrame(sample, aStreamOffset, &frame);
   } else {
     hr = CreateBasicVideoFrame(sample, aStreamOffset, &frame);
rename from content/media/fmp4/wmf/WMFVideoOutputSource.h
rename to content/media/fmp4/wmf/WMFVideoMFTManager.h
--- a/content/media/fmp4/wmf/WMFVideoOutputSource.h
+++ b/content/media/fmp4/wmf/WMFVideoMFTManager.h
@@ -1,35 +1,35 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#if !defined(WMFVideoOutputSource_h_)
-#define WMFVideoOutputSource_h_
+#if !defined(WMFVideoMFTManager_h_)
+#define WMFVideoMFTManager_h_
 
 #include "WMF.h"
 #include "MP4Reader.h"
 #include "MFTDecoder.h"
 #include "nsRect.h"
 #include "WMFMediaDataDecoder.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
 class DXVA2Manager;
 
-class WMFVideoOutputSource : public WMFOutputSource {
+class WMFVideoMFTManager : public MFTManager {
 public:
-  WMFVideoOutputSource(const mp4_demuxer::VideoDecoderConfig& aConfig,
-                       mozilla::layers::LayersBackend aLayersBackend,
-                       mozilla::layers::ImageContainer* aImageContainer,
-                       bool aDXVAEnabled);
-  ~WMFVideoOutputSource();
+  WMFVideoMFTManager(const mp4_demuxer::VideoDecoderConfig& aConfig,
+                     mozilla::layers::LayersBackend aLayersBackend,
+                     mozilla::layers::ImageContainer* aImageContainer,
+                     bool aDXVAEnabled);
+  ~WMFVideoMFTManager();
 
   virtual TemporaryRef<MFTDecoder> Init() MOZ_OVERRIDE;
 
   virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
@@ -64,9 +64,9 @@ private:
 
   const bool mDXVAEnabled;
   const layers::LayersBackend mLayersBackend;
   bool mUseHwAccel;
 };
 
 } // namespace mozilla
 
-#endif // WMFVideoOutputSource_h_
+#endif // WMFVideoMFTManager_h_
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -175,32 +175,38 @@ public:
   }
 
 private:
 
   // These are read and written on the decode task queue threads.
   int64_t mTimeThreshold;
   bool mDropVideoBeforeThreshold;
 
-  bool MaybeSwitchVideoReaders() {
+  enum SwitchState {
+    SWITCHSTATE_SEEKING,
+    SWITCHSTATE_PLAYING
+  };
+
+  bool MaybeSwitchVideoReaders(SwitchState aState = SWITCHSTATE_PLAYING) {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     MOZ_ASSERT(mActiveVideoDecoder != -1);
 
     InitializePendingDecoders();
 
     for (uint32_t i = mActiveVideoDecoder + 1; i < mDecoders.Length(); ++i) {
-      if (!mDecoders[i]->GetReader()->GetMediaInfo().HasVideo()) {
+      SubBufferDecoder* decoder = mDecoders[i];
+      if (decoder->IsDiscarded() || !decoder->GetReader()->GetMediaInfo().HasVideo()) {
         continue;
       }
-      if (mTimeThreshold >= mDecoders[i]->GetMediaStartTime()) {
+
+      if (aState == SWITCHSTATE_SEEKING || mTimeThreshold >= mDecoders[i]->GetMediaStartTime()) {
         GetVideoReader()->SetIdle();
 
         mActiveVideoDecoder = i;
         MSE_DEBUG("%p MSR::DecodeVF switching to %d", this, mActiveVideoDecoder);
-
         return true;
       }
     }
 
     return false;
   }
 
   MediaDecoderReader* GetAudioReader() {
@@ -473,17 +479,17 @@ MediaSourceReader::Seek(int64_t aTime, i
 
   // Loop until we have the requested time range in the source buffers.
   // This is a workaround for our lack of async functionality in the
   // MediaDecoderStateMachine. Bug 979104 implements what we need and
   // we'll remove this for an async approach based on that in bug XXXXXXX.
   while (!mMediaSource->ActiveSourceBuffers()->AllContainsTime(target)
          && !IsShutdown()) {
     mMediaSource->WaitForData();
-    MaybeSwitchVideoReaders();
+    MaybeSwitchVideoReaders(SWITCHSTATE_SEEKING);
   }
 
   if (IsShutdown()) {
     return NS_OK;
   }
 
   ResetDecode();
   if (GetAudioReader()) {
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -407,17 +407,17 @@ SourceBuffer::InitNewDecoder()
   mDecoderInitialized = false;
   return true;
 }
 
 void
 SourceBuffer::DiscardDecoder()
 {
   if (mDecoder) {
-    mDecoder->GetResource()->Ended();
+    mDecoder->SetDiscarded();
   }
   mDecoder = nullptr;
   mDecoderInitialized = false;
 }
 
 void
 SourceBuffer::StartUpdating()
 {
--- a/content/media/mediasource/SubBufferDecoder.h
+++ b/content/media/mediasource/SubBufferDecoder.h
@@ -16,17 +16,17 @@ class MediaSourceDecoder;
 
 class SubBufferDecoder : public BufferDecoder
 {
 public:
   // This class holds a weak pointer to MediaResource.  It's the responsibility
   // of the caller to manage the memory of the MediaResource object.
   SubBufferDecoder(MediaResource* aResource, MediaSourceDecoder* aParentDecoder)
     : BufferDecoder(aResource), mParentDecoder(aParentDecoder), mReader(nullptr)
-    , mMediaDuration(-1), mMediaStartTime(0)
+    , mMediaDuration(-1), mMediaStartTime(0), mDiscarded(false)
   {
   }
 
   void SetReader(MediaDecoderReader* aReader)
   {
     MOZ_ASSERT(!mReader);
     mReader = aReader;
   }
@@ -78,18 +78,30 @@ public:
     return mMediaStartTime;
   }
 
   void SetMediaStartTime(int64_t aMediaStartTime)
   {
     mMediaStartTime = aMediaStartTime;
   }
 
+  bool IsDiscarded()
+  {
+    return mDiscarded;
+  }
+
+  void SetDiscarded()
+  {
+    GetResource()->Ended();
+    mDiscarded = true;
+  }
+
 private:
   MediaSourceDecoder* mParentDecoder;
   nsRefPtr<MediaDecoderReader> mReader;
   int64_t mMediaDuration;
   int64_t mMediaStartTime;
+  bool mDiscarded;
 };
 
 } // namespace mozilla
 
 #endif /* MOZILLA_SUBBUFFERDECODER_H_ */
--- a/content/media/webrtc/LoadMonitor.cpp
+++ b/content/media/webrtc/LoadMonitor.cpp
@@ -269,77 +269,89 @@ nsresult WinProcMon::QuerySystemLoad(flo
   }
 
   // The result is a percent value, reduce to match expected scale.
   *load_percent = (float)(counter.doubleValue / 100.0f);
   return NS_OK;
 }
 #endif
 
-class LoadStats
+// Use a non-generic class name, because otherwise we can get name collisions
+// with other classes in the codebase.  The normal way of dealing with that is
+// to put the class in an anonymous namespace, but this class is used as a
+// member of RTCLoadInfo, which can't be in the anonymous namespace, so it also
+// can't be in an anonymous namespace: gcc warns about that setup and this
+// directory is fail-on-warnings.
+class RTCLoadStats
 {
 public:
-  LoadStats() :
+  RTCLoadStats() :
     mPrevTotalTimes(0),
     mPrevCpuTimes(0),
     mPrevLoad(0) {};
 
   double GetLoad() { return (double)mPrevLoad; };
 
   uint64_t mPrevTotalTimes;
   uint64_t mPrevCpuTimes;
   float mPrevLoad;               // Previous load value.
 };
 
-class LoadInfo : public mozilla::RefCounted<LoadInfo>
+// Use a non-generic class name, because otherwise we can get name collisions
+// with other classes in the codebase.  The normal way of dealing with that is
+// to put the class in an anonymous namespace, but this class is used as a
+// member of LoadInfoCollectRunner, which can't be in the anonymous namespace,
+// so it also can't be in an anonymous namespace: gcc warns about that setup
+// and this directory is fail-on-warnings.
+class RTCLoadInfo : public mozilla::RefCounted<RTCLoadInfo>
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_TYPENAME(LoadInfo)
-  LoadInfo(): mLoadUpdateInterval(0) {};
+  MOZ_DECLARE_REFCOUNTED_TYPENAME(RTCLoadInfo)
+  RTCLoadInfo(): mLoadUpdateInterval(0) {};
   nsresult Init(int aLoadUpdateInterval);
   double GetSystemLoad() { return mSystemLoad.GetLoad(); };
   double GetProcessLoad() { return mProcessLoad.GetLoad(); };
   nsresult UpdateSystemLoad();
   nsresult UpdateProcessLoad();
 
 private:
   void UpdateCpuLoad(uint64_t ticks_per_interval,
                      uint64_t current_total_times,
                      uint64_t current_cpu_times,
-                     LoadStats* loadStat);
+                     RTCLoadStats* loadStat);
 #ifdef XP_WIN
   WinProcMon mSysMon;
   HANDLE mProcHandle;
   int mNumProcessors;
 #endif
-  LoadStats mSystemLoad;
-  LoadStats mProcessLoad;
+  RTCLoadStats mSystemLoad;
+  RTCLoadStats mProcessLoad;
   uint64_t mTicksPerInterval;
   int mLoadUpdateInterval;
 };
 
-nsresult LoadInfo::Init(int aLoadUpdateInterval)
+nsresult RTCLoadInfo::Init(int aLoadUpdateInterval)
 {
   mLoadUpdateInterval = aLoadUpdateInterval;
 #ifdef XP_WIN
   mTicksPerInterval = (WinProcMon::TicksPerSec /*Hz*/
                        * mLoadUpdateInterval /*msec*/) / 1000 ;
   mNumProcessors = PR_GetNumberOfProcessors();
   mProcHandle = GetCurrentProcess();
   return mSysMon.Init();
 #else
   mTicksPerInterval = (sysconf(_SC_CLK_TCK) * mLoadUpdateInterval) / 1000;
   return NS_OK;
 #endif
 }
 
-void LoadInfo::UpdateCpuLoad(uint64_t ticks_per_interval,
-                             uint64_t current_total_times,
-                             uint64_t current_cpu_times,
-                             LoadStats *loadStat) {
+void RTCLoadInfo::UpdateCpuLoad(uint64_t ticks_per_interval,
+                                uint64_t current_total_times,
+                                uint64_t current_cpu_times,
+                                RTCLoadStats *loadStat) {
   // Check if we get an inconsistent number of ticks.
   if (((current_total_times - loadStat->mPrevTotalTimes)
        > (ticks_per_interval * 10))
       || current_total_times < loadStat->mPrevTotalTimes
       || current_cpu_times < loadStat->mPrevCpuTimes) {
     // Bug at least on the Nexus 4 and Galaxy S4
     // https://code.google.com/p/android/issues/detail?id=41630
     // We do need to update our previous times, or we can get stuck
@@ -361,17 +373,17 @@ void LoadInfo::UpdateCpuLoad(uint64_t ti
     float result =  (float)cpu_diff / (float)total_diff;
 #endif
     loadStat->mPrevLoad = result;
   }
   loadStat->mPrevTotalTimes = current_total_times;
   loadStat->mPrevCpuTimes = current_cpu_times;
 }
 
-nsresult LoadInfo::UpdateSystemLoad()
+nsresult RTCLoadInfo::UpdateSystemLoad()
 {
 #if defined(LINUX) || defined(ANDROID)
   nsCOMPtr<nsIFile> procStatFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
   procStatFile->InitWithPath(NS_LITERAL_STRING("/proc/stat"));
 
   nsCOMPtr<nsIInputStream> fileInputStream;
   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
                                            procStatFile);
@@ -467,17 +479,17 @@ nsresult LoadInfo::UpdateSystemLoad()
 
   return rv;
 #else
   // Not implemented
   return NS_OK;
 #endif
 }
 
-nsresult LoadInfo::UpdateProcessLoad() {
+nsresult RTCLoadInfo::UpdateProcessLoad() {
 #if defined(XP_UNIX)
   struct timeval tv;
   gettimeofday(&tv, nullptr);
   const uint64_t total_times = tv.tv_sec * PR_USEC_PER_SEC + tv.tv_usec;
 
   rusage usage;
   if (getrusage(RUSAGE_SELF, &usage) < 0) {
     LOG(("getrusage failed"));
@@ -513,21 +525,23 @@ nsresult LoadInfo::UpdateProcessLoad() {
   UpdateCpuLoad(mTicksPerInterval,
                 total_times,
                 cpu_times,
                 &mProcessLoad);
 #endif
   return NS_OK;
 }
 
+// Note: This class can't be in the anonymous namespace, because then we can't
+// declare it as a friend of LoadMonitor.
 class LoadInfoCollectRunner : public nsRunnable
 {
 public:
   LoadInfoCollectRunner(nsRefPtr<LoadMonitor> loadMonitor,
-                        RefPtr<LoadInfo> loadInfo,
+                        RefPtr<RTCLoadInfo> loadInfo,
                         nsIThread *loadInfoThread)
     : mThread(loadInfoThread),
       mLoadUpdateInterval(loadMonitor->mLoadUpdateInterval),
       mLoadNoiseCounter(0)
   {
     mLoadMonitor = loadMonitor;
     mLoadInfo = loadInfo;
   }
@@ -566,17 +580,17 @@ public:
     }
     // ok, we need to exit safely and can't shut ourselves down (DARN)
     NS_DispatchToMainThread(this);
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIThread> mThread;
-  RefPtr<LoadInfo> mLoadInfo;
+  RefPtr<RTCLoadInfo> mLoadInfo;
   nsRefPtr<LoadMonitor> mLoadMonitor;
   int mLoadUpdateInterval;
   int mLoadNoiseCounter;
 };
 
 void
 LoadMonitor::SetProcessLoad(float load) {
   mLock.AssertCurrentThreadOwns();
@@ -610,21 +624,21 @@ LoadMonitor::GetSystemLoad() {
   return load;
 }
 
 nsresult
 LoadMonitor::Init(nsRefPtr<LoadMonitor> &self)
 {
   LOG(("Initializing LoadMonitor"));
 
-  RefPtr<LoadInfo> load_info = new LoadInfo();
+  RefPtr<RTCLoadInfo> load_info = new RTCLoadInfo();
   nsresult rv = load_info->Init(mLoadUpdateInterval);
 
   if (NS_FAILED(rv)) {
-    LOG(("LoadInfo::Init error"));
+    LOG(("RTCLoadInfo::Init error"));
     return rv;
   }
 
   nsRefPtr<LoadMonitorAddObserver> addObsRunner = new LoadMonitorAddObserver(self);
   NS_DispatchToMainThread(addObsRunner);
 
   NS_NewNamedThread("Sys Load Info", getter_AddRefs(mLoadInfoThread));
 
--- a/content/svg/content/test/mochitest.ini
+++ b/content/svg/content/test/mochitest.ini
@@ -56,16 +56,17 @@ skip-if = true
 [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_pointer-events-6.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]
new file mode 100644
--- /dev/null
+++ b/content/svg/content/test/test_pointer-events-6.xhtml
@@ -0,0 +1,70 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=500174
+-->
+<head>
+  <title>Test pointer events for clip-path on non-SVG elements</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="run()">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+  var div = document.getElementById("div");
+  // Get the coords of the origin of the SVG canvas:
+  var originX = div.offsetLeft;
+  var originY = div.offsetTop;
+  var elementFromPoint;
+
+  elementFromPoint = document.elementFromPoint(originX + 18, originY + 30);
+  isnot(elementFromPoint, div, 'Outside left edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 22, originY + 30);
+  is(elementFromPoint, div, 'Inside left edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 30, originY + 18);
+  isnot(elementFromPoint, div, 'Outside top edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 30, originY + 22);
+  is(elementFromPoint, div, 'Inside top edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 42, originY + 30);
+  isnot(elementFromPoint, div, 'Outside right edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 38, originY + 30);
+  is(elementFromPoint, div, 'Inside right edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 30, originY + 42);
+  isnot(elementFromPoint, div, 'Outside bottom edge of clipped area');
+
+  elementFromPoint = document.elementFromPoint(originX + 30, originY + 38);
+  is(elementFromPoint, div, 'Inside bottom edge of clipped area');
+
+  SimpleTest.finish();
+}
+
+]]>
+</script>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500174">Mozilla Bug 500174</a>
+<p id="display"></p>
+<div id="content">
+
+  <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" id="svg">
+    <defs>
+      <clipPath id="clip">
+        <rect x="20" y="20" width="20" height="20"/>
+      </clipPath>
+    </defs>
+  </svg>
+  <div id="div" style="width:100px; height:100px; clip-path:url(#clip)"></div>
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -84,16 +84,17 @@
 #include "nsURILoader.h"
 #include "mozilla/AddonPathService.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/NodeInfoInlines.h"
 #include "mozilla/dom/ProcessingInstruction.h"
 #include "mozilla/dom/XULDocumentBinding.h"
 #include "mozilla/EventDispatcher.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/Preferences.h"
 #include "nsTextNode.h"
 #include "nsJSUtils.h"
 #include "mozilla/dom/URL.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -2824,17 +2825,20 @@ XULDocument::LoadOverlayInternal(nsIURI*
         nsCOMPtr<nsIChannel> channel;
         rv = NS_NewChannel(getter_AddRefs(channel), aURI, nullptr, group);
 
         if (NS_SUCCEEDED(rv)) {
             // Set the owner of the channel to be our principal so
             // that the overlay's JSObjects etc end up being created
             // with the right principal and in the correct
             // compartment.
-            channel->SetOwner(NodePrincipal());
+            nsCOMPtr<nsILoadInfo> loadInfo =
+                new LoadInfo(NodePrincipal(), LoadInfo::eInheritPrincipal,
+                             LoadInfo::eNotSandboxed);
+            channel->SetLoadInfo(loadInfo);
 
             rv = channel->AsyncOpen(listener, nullptr);
         }
 
         if (NS_FAILED(rv)) {
             // Abandon this prototype
             mCurrentPrototype = nullptr;
 
new file mode 100644
--- /dev/null
+++ b/docshell/base/LoadInfo.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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/LoadInfo.h"
+
+#include "mozilla/Assertions.h"
+#include "nsISupportsImpl.h"
+#include "nsISupportsUtils.h"
+
+namespace mozilla {
+
+LoadInfo::LoadInfo(nsIPrincipal* aPrincipal,
+                   InheritType aInheritPrincipal,
+                   SandboxType aSandboxed)
+  : mPrincipal(aPrincipal)
+  , mInheritPrincipal(aInheritPrincipal == eInheritPrincipal &&
+                      aSandboxed != eSandboxed)
+  , mSandboxed(aSandboxed == eSandboxed)
+{
+  MOZ_ASSERT(aPrincipal);
+}
+
+LoadInfo::~LoadInfo()
+{
+}
+
+NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo)
+
+NS_IMETHODIMP
+LoadInfo::GetLoadingPrincipal(nsIPrincipal** aPrincipal)
+{
+  NS_ADDREF(*aPrincipal = mPrincipal);
+  return NS_OK;
+}
+
+nsIPrincipal*
+LoadInfo::LoadingPrincipal()
+{
+  return mPrincipal;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetForceInheritPrincipal(bool* aInheritPrincipal)
+{
+  *aInheritPrincipal = mInheritPrincipal;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetLoadingSandboxed(bool* aLoadingSandboxed)
+{
+  *aLoadingSandboxed = mSandboxed;
+  return NS_OK;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/docshell/base/LoadInfo.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_LoadInfo_h
+#define mozilla_LoadInfo_h
+
+#include "nsIPrincipal.h"
+#include "nsILoadInfo.h"
+
+namespace mozilla {
+
+/**
+ * Class that provides an nsILoadInfo implementation.
+ */
+class LoadInfo MOZ_FINAL : public nsILoadInfo
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSILOADINFO
+
+  enum InheritType
+  {
+    eInheritPrincipal,
+    eDontInheritPrincipal
+  };
+
+  enum SandboxType
+  {
+    eSandboxed,
+    eNotSandboxed
+  };
+
+  // aPrincipal MUST NOT BE NULL.  If aSandboxed is eSandboxed, the
+  // value passed for aInheritPrincipal will be ignored and
+  // eDontInheritPrincipal will be used instead.
+  LoadInfo(nsIPrincipal* aPrincipal,
+           InheritType aInheritPrincipal,
+           SandboxType aSandboxed);
+
+private:
+  ~LoadInfo();
+
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  bool mInheritPrincipal;
+  bool mSandboxed;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_LoadInfo_h
+
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -15,16 +15,17 @@ XPIDL_SOURCES += [
     'nsIDocShell.idl',
     'nsIDocShellLoadInfo.idl',
     'nsIDocShellTreeItem.idl',
     'nsIDocShellTreeOwner.idl',
     'nsIDocumentLoaderFactory.idl',
     'nsIDownloadHistory.idl',
     'nsIGlobalHistory2.idl',
     'nsILoadContext.idl',
+    'nsILoadInfo.idl',
     'nsIMarkupDocumentViewer.idl',
     'nsIPrivacyTransitionObserver.idl',
     'nsIReflowObserver.idl',
     'nsIRefreshURI.idl',
     'nsIScrollable.idl',
     'nsITextScroll.idl',
     'nsIURIFixup.idl',
     'nsIWebNavigation.idl',
@@ -40,20 +41,22 @@ EXPORTS += [
     'nsIScrollObserver.h',
     'nsIWebShellServices.h',
     'SerializedLoadContext.h',
 ]
 
 EXPORTS.mozilla += [
     'IHistory.h',
     'LoadContext.h',
+    'LoadInfo.h',
 ]
 
 UNIFIED_SOURCES += [
     'LoadContext.cpp',
+    'LoadInfo.cpp',
     'nsAboutRedirector.cpp',
     'nsDefaultURIFixup.cpp',
     'nsDocShellEditorData.cpp',
     'nsDocShellEnumerator.cpp',
     'nsDocShellLoadInfo.cpp',
     'nsDocShellTransferableHooks.cpp',
     'nsDownloadHistory.cpp',
     'nsDSURIContentListener.cpp',
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -96,16 +96,17 @@
 // Interfaces Needed
 #include "nsIUploadChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIWebProgress.h"
 #include "nsILayoutHistoryState.h"
 #include "nsITimer.h"
 #include "nsISHistoryInternal.h"
 #include "nsIPrincipal.h"
+#include "nsNullPrincipal.h"
 #include "nsISHEntry.h"
 #include "nsIWindowWatcher.h"
 #include "nsIPromptFactory.h"
 #include "nsITransportSecurityInfo.h"
 #include "nsINSSErrorsService.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIApplicationCacheContainer.h"
 #include "nsStreamUtils.h"
@@ -163,16 +164,17 @@
 #include "nsIDocumentViewerPrint.h"
 #include "nsIWebBrowserPrint.h"
 #endif
 
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
+#include "nsILoadInfo.h"
 #include "nsSandboxFlags.h"
 #include "nsXULAppAPI.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsISecurityUITelemetry.h"
 #include "nsIAppsService.h"
 #include "nsDSURIContentListener.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsDocShellTransferableHooks.h"
@@ -10001,31 +10003,19 @@ nsDocShell::DoURILoad(nsIURI * aURI,
         }
         // Set the referrer explicitly
         if (aReferrerURI && aSendReferrer) {
             // Referrer is currenly only set for link clicks here.
             httpChannel->SetReferrer(aReferrerURI);
         }
     }
 
-    nsCOMPtr<nsIPrincipal> ownerPrincipal;
-
-    // If the content being loaded should be sandboxed with respect to origin
-    // we need to create a new null principal here, and then tell
-    // nsContentUtils::SetUpChannelOwner to force it to be set as the
-    // channel owner.
-    if (mSandboxFlags & SANDBOXED_ORIGIN) {
-        ownerPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
-    } else {
-        // Not sandboxed - we allow the content to assume its natural owner.
-        ownerPrincipal = do_QueryInterface(aOwner);
-    }
-
+    nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(aOwner);
     nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true,
-                                      (mSandboxFlags & SANDBOXED_ORIGIN) ||
+                                      mSandboxFlags & SANDBOXED_ORIGIN,
                                       isSrcdoc);
 
     nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
     if (scriptChannel) {
         // Allow execution against our context if the principals match
         scriptChannel->
             SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
     }
@@ -11086,16 +11076,31 @@ nsDocShell::AddToSessionHistory(nsIURI *
             if (uploadChannel) {
                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
             }
             httpChannel->GetReferrer(getter_AddRefs(referrerURI));
 
             discardLayoutState = ShouldDiscardLayoutState(httpChannel);
         }
         aChannel->GetOwner(getter_AddRefs(owner));
+        if (!owner) {
+            nsCOMPtr<nsILoadInfo> loadInfo;
+            aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+            if (loadInfo) {
+                // For now keep storing just the principal in the SHEntry.
+                if (loadInfo->GetLoadingSandboxed()) {
+                    owner = do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID, &rv);
+                    if (NS_WARN_IF(NS_FAILED(rv))) {
+                        return rv;
+                    }
+                } else if (loadInfo->GetForceInheritPrincipal()) {
+                    owner = loadInfo->LoadingPrincipal();
+                }
+            }
+        }
     }
 
     //Title is set in nsDocShell::SetTitle()
     entry->Create(aURI,              // uri
                   EmptyString(),     // Title
                   inputStream,       // Post data stream
                   nullptr,            // LayoutHistory state
                   cacheKey,          // CacheKey
new file mode 100644
--- /dev/null
+++ b/docshell/base/nsILoadInfo.idl
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: ft=cpp tw=78 sw=2 et ts=2 sts=2 cin
+ * 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 "nsISupports.idl"
+
+interface nsIPrincipal;
+/**
+ * An nsILoadOwner represents per-load information about who started the load.
+ */
+[scriptable, builtinclass, uuid(046db047-a1c1-4519-8ec7-99f3054bc9ac)]
+interface nsILoadInfo : nsISupports
+{
+  /**
+   * loadingPrincipal is the principal that started the load.  Will
+   * never be null.
+   */
+  readonly attribute nsIPrincipal loadingPrincipal;
+
+  /**
+   * A C++-friendly version of loadingPrincipal.
+   */
+  [noscript, notxpcom, nostdcall, binaryname(LoadingPrincipal)]
+  nsIPrincipal binaryLoadingPrincipal();
+
+  /**
+   * If forceInheritPrincipal is true, the data coming from the channel should
+   * use loadingPrincipal for its principal, even when the data is loaded over
+   * http:// or another protocol that would normally use a URI-based principal.
+   * This attribute will never be true when loadingSandboxed is true.
+   */
+  [infallible] readonly attribute boolean forceInheritPrincipal;
+
+  /**
+   * If loadingSandboxed is true, the data coming from the channel is
+   * being loaded sandboxed, so it should have a nonce origin and
+   * hence should use a NullPrincipal.
+   */
+  [infallible] readonly attribute boolean loadingSandboxed;
+};
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -10,18 +10,16 @@
 #include "nsXULAppAPI.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/CryptoBinding.h"
 #include "nsServiceManagerUtils.h"
 
 using mozilla::dom::ContentChild;
 
-using namespace js::ArrayBufferView;
-
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Crypto)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
 NS_INTERFACE_MAP_END
@@ -62,23 +60,23 @@ Crypto::GetRandomValues(JSContext* aCx, 
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Called on the wrong thread");
 
   JS::Rooted<JSObject*> view(aCx, aArray.Obj());
 
   // Throw if the wrong type of ArrayBufferView is passed in
   // (Part of the Web Crypto API spec)
   switch (JS_GetArrayBufferViewType(view)) {
-    case TYPE_INT8:
-    case TYPE_UINT8:
-    case TYPE_UINT8_CLAMPED:
-    case TYPE_INT16:
-    case TYPE_UINT16:
-    case TYPE_INT32:
-    case TYPE_UINT32:
+    case js::Scalar::Int8:
+    case js::Scalar::Uint8:
+    case js::Scalar::Uint8Clamped:
+    case js::Scalar::Int16:
+    case js::Scalar::Uint16:
+    case js::Scalar::Int32:
+    case js::Scalar::Uint32:
       break;
     default:
       aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
       return;
   }
 
   aArray.ComputeLengthAndData();
   uint32_t dataLen = aArray.Length();
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -156,16 +156,17 @@ LOCAL_INCLUDES += [
     '../src/geolocation',
     '../src/storage',
     '../time',
     '../workers',
     '../xbl',
     '/content/base/src',
     '/content/html/document/src',
     '/content/xul/document/src',
+    '/layout/base',
     '/layout/generic',
     '/layout/style',
     '/layout/xul',
     '/widget/shared',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     LOCAL_INCLUDES += [
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -85,16 +85,18 @@
 #include "nsDisplayList.h"
 #include "nsROCSSPrimitiveValue.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "GeckoProfiler.h"
 #include "mozilla/Preferences.h"
 #include "nsIContentIterator.h"
+#include "nsIDOMStyleSheet.h"
+#include "nsIStyleSheet.h"
 #include "nsContentPermissionHelper.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -3363,16 +3365,38 @@ nsDOMWindowUtils::LoadSheet(nsIURI *aShe
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
 
   return doc->LoadAdditionalStyleSheet(type, aSheetURI);
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType)
+{
+  MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
+
+  NS_ENSURE_ARG_POINTER(aSheet);
+  NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
+                aSheetType == USER_SHEET ||
+                aSheetType == AUTHOR_SHEET);
+
+  nsCOMPtr<nsIDocument> doc = GetDocument();
+  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+  nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
+  nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
+  NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
+  if (sheet->GetOwningDocument()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  return doc->AddAdditionalStyleSheet(type, sheet);
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   NS_ENSURE_ARG_POINTER(aSheetURI);
   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
                 aSheetType == USER_SHEET ||
                 aSheetType == AUTHOR_SHEET);
@@ -3637,17 +3661,17 @@ HandlingUserInputHelper::Destruct()
   mDestructCalled = true;
   if (mHandlingUserInput) {
     EventStateManager::StopHandlingUserInput();
   }
 
   return NS_OK;
 }
 
-}
+} // unnamed namespace
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetHandlingUserInput(bool aHandlingUserInput,
                                        nsIJSRAIIHelper** aHelper)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -123,17 +123,17 @@ TouchEvent::InitTouchEvent(const nsAStri
 
 TouchList*
 TouchEvent::Touches()
 {
   if (!mTouches) {
     WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
     if (mEvent->message == NS_TOUCH_END || mEvent->message == NS_TOUCH_CANCEL) {
       // for touchend events, remove any changed touches from the touches array
-      WidgetTouchEvent::TouchArray unchangedTouches;
+      WidgetTouchEvent::AutoTouchArray unchangedTouches;
       const WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
       for (uint32_t i = 0; i < touches.Length(); ++i) {
         if (!touches[i]->mChanged) {
           unchangedTouches.AppendElement(touches[i]);
         }
       }
       mTouches = new TouchList(ToSupports(this), unchangedTouches);
     } else {
@@ -142,17 +142,17 @@ TouchEvent::Touches()
   }
   return mTouches;
 }
 
 TouchList*
 TouchEvent::TargetTouches()
 {
   if (!mTargetTouches) {
-    nsTArray< nsRefPtr<Touch> > targetTouches;
+    WidgetTouchEvent::AutoTouchArray targetTouches;
     WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
     const WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
     for (uint32_t i = 0; i < touches.Length(); ++i) {
       // for touchend/cancel events, don't append to the target list if this is a
       // touch that is ending
       if ((mEvent->message != NS_TOUCH_END &&
            mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) {
         if (touches[i]->mTarget == mEvent->originalTarget) {
@@ -164,17 +164,17 @@ TouchEvent::TargetTouches()
   }
   return mTargetTouches;
 }
 
 TouchList*
 TouchEvent::ChangedTouches()
 {
   if (!mChangedTouches) {
-    nsTArray< nsRefPtr<Touch> > changedTouches;
+    WidgetTouchEvent::AutoTouchArray changedTouches;
     WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
     const WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
     for (uint32_t i = 0; i < touches.Length(); ++i) {
       if (touches[i]->mChanged) {
         changedTouches.AppendElement(touches[i]);
       }
     }
     mChangedTouches = new TouchList(ToSupports(this), changedTouches);
--- a/dom/events/TouchEvent.h
+++ b/dom/events/TouchEvent.h
@@ -5,18 +5,18 @@
 #ifndef mozilla_dom_TouchEvent_h_
 #define mozilla_dom_TouchEvent_h_
 
 #include "mozilla/dom/Touch.h"
 #include "mozilla/dom/TouchEventBinding.h"
 #include "mozilla/dom/UIEvent.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
+#include "mozilla/TouchEvents.h"
 #include "nsJSEnvironment.h"
-#include "nsTArray.h"
 #include "nsWrapperCache.h"
 
 class nsAString;
 
 namespace mozilla {
 namespace dom {
 
 class TouchList MOZ_FINAL : public nsISupports
@@ -28,17 +28,17 @@ public:
 
   TouchList(nsISupports* aParent)
     : mParent(aParent)
   {
     SetIsDOMBinding();
     nsJSContext::LikelyShortLivingObjectCreated();
   }
   TouchList(nsISupports* aParent,
-            const nsTArray<nsRefPtr<Touch> >& aTouches)
+            const WidgetTouchEvent::TouchArray& aTouches)
     : mParent(aParent)
     , mPoints(aTouches)
   {
     SetIsDOMBinding();
     nsJSContext::LikelyShortLivingObjectCreated();
   }
 
   void Append(Touch* aPoint)
@@ -73,17 +73,17 @@ public:
     return mPoints[aIndex];
   }
   Touch* IdentifiedTouch(int32_t aIdentifier) const;
 
 protected:
   ~TouchList() {}
 
   nsCOMPtr<nsISupports> mParent;
-  nsTArray<nsRefPtr<Touch> > mPoints;
+  WidgetTouchEvent::TouchArray mPoints;
 };
 
 class TouchEvent : public UIEvent
 {
 public:
   TouchEvent(EventTarget* aOwner,
              nsPresContext* aPresContext,
              WidgetTouchEvent* aEvent);
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -30,32 +30,33 @@ native nscolor(nscolor);
 typedef unsigned long long nsViewID;
 
 interface nsICycleCollectorListener;
 interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
+interface nsIDOMStyleSheet;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 
-[scriptable, uuid(ca202fa7-7b8f-4814-acc3-a8545f67320b)]
+[scriptable, uuid(0ef9e8bb-b934-4f6b-ae05-e98774d8d3d3)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1558,25 +1559,32 @@ interface nsIDOMWindowUtils : nsISupport
    * of additional style sheets of the document.
    *
    * These additional style sheets are very much like user/agent sheets loaded 
    * with loadAndRegisterSheet. The only difference is that they are applied only
    * on the document owned by this window.
    *
    * Sheets added via this API take effect immediately on the document.
    */
-  void loadSheet(in nsIURI sheetURI,
-                           in unsigned long type);
+  void loadSheet(in nsIURI sheetURI, in unsigned long type);
+
+  /**
+   * Adds a style sheet to the list of additional style sheets of the document.
+   *
+   * Style sheets can be preloaded with nsIStyleSheetService.preloadSheet.
+   *
+   * Sheets added via this API take effect immediately on the document.
+   */
+  void addSheet(in nsIDOMStyleSheet sheet, in unsigned long type);
 
   /**
    * Remove the document style sheet at |sheetURI| from the list of additional 
    * style sheets of the document.  The removal takes effect immediately.
    */
-  void removeSheet(in nsIURI sheetURI,
-                                in unsigned long type);
+  void removeSheet(in nsIURI sheetURI, in unsigned long type);
 
   /**
    * Returns true if a user input is being handled.
    *
    * This calls EventStateManager::IsHandlingUserInput().
    */
   readonly attribute boolean isHandlingUserInput;
 
@@ -1636,18 +1644,20 @@ interface nsIDOMWindowUtils : nsISupport
    /*
     * Returns the value of a given property animated on the compositor thread.
     * If the property is NOT currently being animated on the compositor thread,
     * returns an empty string.
     */
    AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty);
 
    /**
-    * If we are currently handling user input, this informs the event state
-    * manager. Remember to call destruct() on the return value!
+    * If aHandlingInput is true, this informs the event state manager that
+    * we're handling user input. Otherwise, this is a no-op (as by default
+    * we're not handling user input).
+    * Remember to call destruct() on the return value!
     * See also nsIDOMWindowUtils::isHandlingUserInput.
     */
    nsIJSRAIIHelper setHandlingUserInput(in boolean aHandlingInput);
 
    /**
     * Get the content- and compositor-side APZ test data instances.
     * The return values are of type APZTestData (see APZTestData.webidl).
     */
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -36,16 +36,17 @@
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
+#include "nsILoadInfo.h"
 #include "nsIPromptFactory.h"
 #include "nsIURI.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIWindowCreator2.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsIXULWindow.h"
 #include "nsViewManager.h"
 #include "nsIWidget.h"
@@ -2180,16 +2181,26 @@ public:
   NS_IMETHOD GetURI(nsIURI** aUri)
   {
     NS_IF_ADDREF(mUri);
     *aUri = mUri;
     return NS_OK;
   }
   NS_IMETHOD GetOwner(nsISupports**) NO_IMPL
   NS_IMETHOD SetOwner(nsISupports*) NO_IMPL
+  NS_IMETHOD GetLoadInfo(nsILoadInfo** aLoadInfo)
+  {
+    NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
+    return NS_OK;
+  }
+  NS_IMETHOD SetLoadInfo(nsILoadInfo* aLoadInfo)
+  {
+    mLoadInfo = aLoadInfo;
+    return NS_OK;
+  }
   NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor** aRequestor)
   {
     NS_ADDREF(*aRequestor = this);
     return NS_OK;
   }
   NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor*) NO_IMPL
   NS_IMETHOD GetSecurityInfo(nsISupports**) NO_IMPL
   NS_IMETHOD GetContentType(nsACString&) NO_IMPL
@@ -2232,16 +2243,17 @@ public:
 #undef NO_IMPL
 
 protected:
   ~FakeChannel() {}
 
   nsCOMPtr<nsIURI> mUri;
   uint64_t mCallbackId;
   nsCOMPtr<Element> mElement;
+  nsCOMPtr<nsILoadInfo> mLoadInfo;
 };
 
 NS_IMPL_ISUPPORTS(FakeChannel, nsIChannel, nsIAuthPromptCallback,
                   nsIRequest, nsIInterfaceRequestor, nsILoadContext);
 
 bool
 TabParent::RecvAsyncAuthPrompt(const nsCString& aUri,
                                const nsString& aRealm,
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -43,16 +43,17 @@
 #include "nsPluginLogging.h"
 #include "nsIScriptChannel.h"
 #include "nsIBlocklistService.h"
 #include "nsVersionComparator.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsICategoryManager.h"
 #include "nsPluginStreamListenerPeer.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/Preferences.h"
 
 #include "nsEnumeratorUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMCID.h"
 #include "nsISupportsPrimitives.h"
 
 #include "nsXULAppAPI.h"
@@ -2846,17 +2847,20 @@ nsresult nsPluginHost::NewPluginURLStrea
             on the load group otherwise this channel could be canceled
             form |nsDocShell::OnLinkClickSync| bug 166613 */
     listenerPeer);
   if (NS_FAILED(rv))
     return rv;
 
   if (doc) {
     // Set the owner of channel to the document principal...
-    channel->SetOwner(doc->NodePrincipal());
+    nsCOMPtr<nsILoadInfo> loadInfo =
+      new LoadInfo(doc->NodePrincipal(), LoadInfo::eInheritPrincipal,
+                   LoadInfo::eNotSandboxed);
+    channel->SetLoadInfo(loadInfo);
 
     // And if it's a script allow it to execute against the
     // document's script context.
     nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
     if (scriptChannel) {
       scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
       // Plug-ins seem to depend on javascript: URIs running synchronously
       scriptChannel->SetExecuteAsync(false);
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -1,8 +1,9 @@
+/* jshint moz: true, esnext: true */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Don't modify this, instead set services.push.debug.
 let gDebuggingEnabled = false;
@@ -445,16 +446,51 @@ this.PushService = {
    * WebSocket because it will wake up the client via UDP, then the client
    * shouldn't re-establish the connection. If the server says that it will
    * wake up the client over UDP, this is set to true in wsOnServerClose. It is
    * checked in wsOnStop.
    */
   _willBeWokenUpByUDP: false,
 
   /**
+   * Holds if the adaptive ping is enabled. This is read on init().
+   * If adaptive ping is enabled, a new ping is calculed each time we receive
+   * a pong message, trying to maximize network resources while minimizing
+   * cellular signalling storms.
+   */
+  _adaptiveEnabled: false,
+
+  /**
+   * This saves a flag about if we need to recalculate a new ping, based on:
+   *   1) the gap between the maximum working ping and the first ping that
+   *      gives an error (timeout) OR
+   *   2) we have reached the pref of the maximum value we allow for a ping
+   *      (services.push.adaptive.upperLimit)
+   */
+  _recalculatePing: true,
+
+  /**
+   * This map holds a (pingInterval, triedTimes) of each pingInterval tried.
+   * It is used to check if the pingInterval has been tested enough to know that
+   * is incorrect and is above the limit the network allow us to keep the
+   * connection open.
+   */
+  _pingIntervalRetryTimes: {},
+
+  /**
+   * Holds the lastGoodPingInterval for our current connection.
+   */
+  _lastGoodPingInterval: 0,
+
+  /**
+   * Maximum ping interval that we can reach.
+   */
+  _upperLimit: 0,
+
+  /**
    * Sends a message to the Push Server through an open websocket.
    * typeof(msg) shall be an object
    */
   _wsSendMessage: function(msg) {
     if (!this._ws) {
       debug("No WebSocket initialized. Cannot send a message.");
       return;
     }
@@ -475,16 +511,18 @@ this.PushService = {
 
     kCHILD_PROCESS_MESSAGES.forEach(function addMessage(msgName) {
         ppmm.addMessageListener(msgName, this);
     }.bind(this));
 
     this._alarmID = null;
 
     this._requestTimeout = prefs.get("requestTimeout");
+    this._adaptiveEnabled = prefs.get('adaptive.enabled');
+    this._upperLimit = prefs.get('adaptive.upperLimit');
 
     this._startListeningIfChannelsPresent();
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
     Services.obs.addObserver(this, "webapps-clear-data", false);
 
     // On B2G the NetworkManager interface fires a network-active-changed
     // event.
@@ -587,28 +625,170 @@ this.PushService = {
    * a register/unregister is called, we don't want to wait around anymore.
    * _sendRequest will automatically call beginWSSetup(), which will cancel the
    * timer. In addition since the state will have changed, even if a pending
    * timer event comes in (because the timer fired the event before it was
    * cancelled), so the connection won't be reset.
    */
   _reconnectAfterBackoff: function() {
     debug("reconnectAfterBackoff()");
+    //Calculate new ping interval
+    this._calculateAdaptivePing(true /* wsWentDown */);
 
     // Calculate new timeout, but cap it to pingInterval.
     let retryTimeout = prefs.get("retryBaseInterval") *
                        Math.pow(2, this._retryFailCount);
     retryTimeout = Math.min(retryTimeout, prefs.get("pingInterval"));
 
     this._retryFailCount++;
 
     debug("Retry in " + retryTimeout + " Try number " + this._retryFailCount);
     this._setAlarm(retryTimeout);
   },
 
+  /**
+   * We need to calculate a new ping based on:
+   *  1) Latest good ping
+   *  2) A safe gap between 1) and the calculated new ping (which is
+   *  by default, 1 minute)
+   *
+   * This is for 3G networks, whose connections keepalives differ broadly,
+   * for example:
+   *  1) Movistar Spain: 29 minutes
+   *  2) VIVO Brazil: 5 minutes
+   *  3) Movistar Colombia: XXX minutes
+   *
+   * So a fixed ping is not good for us for two reasons:
+   *  1) We might lose the connection, so we need to reconnect again (wasting
+   *  resources)
+   *  2) We use a lot of network signaling just for pinging.
+   *
+   * This algorithm tries to search the best value between a disconnection and a
+   * valid ping, to ensure better battery life and network resources usage.
+   *
+   * The value is saved in services.push.pingInterval
+   * @param wsWentDown [Boolean] if the WebSocket was closed or it is still alive
+   *
+   */
+  _calculateAdaptivePing: function(wsWentDown) {
+    debug('_calculateAdaptivePing()');
+    if (!this._adaptiveEnabled) {
+      debug('Adaptive ping is disabled');
+      return;
+    }
+
+    if (this._retryFailCount > 0) {
+      debug('Push has failed to connect to the Push Server ' +
+        this._retryFailCount + ' times. ' +
+        'Do not calculate a new pingInterval now');
+      return;
+    }
+
+    if (!this._recalculatePing && !wsWentDown) {
+      debug('We do not need to recalculate the ping now, based on previous data');
+      return;
+    }
+
+    // Save actual state of the network
+    let ns = this._getNetworkInformation();
+
+    if (ns.ip) {
+      // mobile
+      debug('mobile');
+      let oldNetwork = prefs.get('adaptive.mobile');
+      let newNetwork = 'mobile-' + ns.mcc + '-' + ns.mnc;
+
+      // Mobile networks differ, reset all intervals and pings
+      if (oldNetwork !== newNetwork) {
+        // Network differ, reset all values
+        debug('Mobile networks differ. Old network is ' + oldNetwork +
+              ' and new is ' + newNetwork);
+        prefs.set('adaptive.mobile', newNetwork);
+        //We reset the upper bound member
+        this._recalculatePing = true;
+        this._pingIntervalRetryTimes = {};
+
+        // Put default values
+        let defaultPing = prefs.get('pingInterval.default');
+        prefs.set('pingInterval', defaultPing);
+        this._lastGoodPingInterval = defaultPing;
+
+      } else {
+        // Mobile network is the same, let's just update things
+        prefs.set('pingInterval', prefs.get('pingInterval.mobile'));
+        this._lastGoodPingInterval = prefs.get('adaptive.lastGoodPingInterval.mobile');
+      }
+
+    } else {
+      // wifi
+      debug('wifi');
+      prefs.set('pingInterval', prefs.get('pingInterval.wifi'));
+      this._lastGoodPingInterval = prefs.get('adaptive.lastGoodPingInterval.wifi');
+    }
+
+    let nextPingInterval;
+    let lastTriedPingInterval = prefs.get('pingInterval');
+    if (wsWentDown) {
+      debug('The WebSocket was disconnected, calculating next ping');
+
+      // If we have not tried this pingInterval yet, initialize
+      this._pingIntervalRetryTimes[lastTriedPingInterval] =
+           (this._pingIntervalRetryTimes[lastTriedPingInterval] || 0) + 1;
+
+       // Try the pingInterval at least 3 times, just to be sure that the
+       // calculated interval is not valid.
+       if (this._pingIntervalRetryTimes[lastTriedPingInterval] < 2) {
+         debug('pingInterval= ' + lastTriedPingInterval + ' tried only ' +
+           this._pingIntervalRetryTimes[lastTriedPingInterval] + ' times');
+         return;
+       }
+
+       // Latest ping was invalid, we need to lower the limit to limit / 2
+       nextPingInterval = Math.floor(lastTriedPingInterval / 2);
+
+      // If the new ping interval is close to the last good one, we are near
+      // optimum, so stop calculating.
+      if (nextPingInterval - this._lastGoodPingInterval < prefs.get('adaptive.gap')) {
+        debug('We have reached the gap, we have finished the calculation');
+        debug('nextPingInterval=' + nextPingInterval);
+        debug('lastGoodPing=' + this._lastGoodPingInterval);
+        nextPingInterval = this._lastGoodPingInterval;
+        this._recalculatePing = false;
+      } else {
+        debug('We need to calculate next time');
+        this._recalculatePing = true;
+      }
+
+    } else {
+      debug('The WebSocket is still up');
+      this._lastGoodPingInterval = lastTriedPingInterval;
+      nextPingInterval = Math.floor(lastTriedPingInterval * 1.5);
+    }
+
+    // Check if we have reached the upper limit
+    if (this._upperLimit < nextPingInterval) {
+      debug('Next ping will be bigger than the configured upper limit, capping interval');
+      this._recalculatePing = false;
+      this._lastGoodPingInterval = lastTriedPingInterval;
+      nextPingInterval = lastTriedPingInterval;
+    }
+
+    debug('Setting the pingInterval to ' + nextPingInterval);
+    prefs.set('pingInterval', nextPingInterval);
+
+    //Save values for our current network
+    if (ns.ip) {
+      prefs.set('pingInterval.mobile', nextPingInterval);
+      prefs.set('adaptive.lastGoodPingInterval.mobile', this._lastGoodPingInterval);
+    } else {
+      prefs.set('pingInterval.wifi', nextPingInterval);
+      prefs.set('adaptive.lastGoodPingInterval.wifi', this._lastGoodPingInterval);
+    }
+  },
+
   _beginWSSetup: function() {
     debug("beginWSSetup()");
     if (this._currentState != STATE_SHUT_DOWN) {
       debug("_beginWSSetup: Not in shutdown state! Current state " +
             this._currentState);
       return;
     }
 
@@ -1388,30 +1568,47 @@ this.PushService = {
     this._shutdownWS();
   },
 
   _wsOnMessageAvailable: function(context, message) {
     debug("wsOnMessageAvailable() " + message);
 
     this._waitingForPong = false;
 
-    // Reset the ping timer.  Note: This path is executed at every step of the
-    // handshake, so this alarm does not need to be set explicitly at startup.
-    this._setAlarm(prefs.get("pingInterval"));
-
     let reply = undefined;
     try {
       reply = JSON.parse(message);
     } catch(e) {
       debug("Parsing JSON failed. text : " + message);
       return;
     }
 
-    if (typeof reply.messageType != "string") {
-      debug("messageType not a string " + reply.messageType);
+    // If we are not waiting for a hello message, reset the retry fail count
+    if (this._currentState != STATE_WAITING_FOR_HELLO) {
+      debug('Reseting _retryFailCount and _pingIntervalRetryTimes');
+      this._retryFailCount = 0;
+      this._pingIntervalRetryTimes = {};
+    }
+
+    let doNotHandle = false;
+    if ((message === '{}') ||
+        (reply.messageType === undefined) ||
+        (reply.messageType === "ping") ||
+        (typeof reply.messageType != "string")) {
+      debug('Pong received');
+      this._calculateAdaptivePing(false);
+      doNotHandle = true;
+    }
+
+    // Reset the ping timer.  Note: This path is executed at every step of the
+    // handshake, so this alarm does not need to be set explicitly at startup.
+    this._setAlarm(prefs.get("pingInterval"));
+
+    // If it is a ping, do not handle the message.
+    if (doNotHandle) {
       return;
     }
 
     // A whitelist of protocol handlers. Add to these if new messages are added
     // in the protocol.
     let handlers = ["Hello", "Register", "Notification"];
 
     // Build up the handler name to call from messageType.
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -36,22 +36,24 @@
 #include "nsIContentViewer.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIScriptChannel.h"
 #include "nsIDocument.h"
+#include "nsILoadInfo.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsSandboxFlags.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "nsILoadInfo.h"
 
 using mozilla::dom::AutoEntryScript;
 
 static NS_DEFINE_CID(kJSURICID, NS_JSURI_CID);
 
 class nsJSThunk : public nsIInputStream
 {
 public:
@@ -147,20 +149,26 @@ nsresult nsJSThunk::EvaluateScript(nsICh
     
     NS_ENSURE_ARG_POINTER(aChannel);
 
     // Get principal of code for execution
     nsCOMPtr<nsISupports> owner;
     aChannel->GetOwner(getter_AddRefs(owner));
     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner);
     if (!principal) {
-        // No execution without a principal!
-        NS_ASSERTION(!owner, "Non-principal owner?");
-        NS_WARNING("No principal to execute JS with");
-        return NS_ERROR_DOM_RETVAL_UNDEFINED;
+        nsCOMPtr<nsILoadInfo> loadInfo;
+        aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+        if (loadInfo && loadInfo->GetForceInheritPrincipal()) {
+            principal = loadInfo->LoadingPrincipal();
+        } else {
+            // No execution without a principal!
+            NS_ASSERTION(!owner, "Non-principal owner?");
+            NS_WARNING("No principal to execute JS with");
+            return NS_ERROR_DOM_RETVAL_UNDEFINED;
+        }
     }
 
     nsresult rv;
 
     // CSP check: javascript: URIs disabled unless "inline" scripts are
     // allowed.
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     rv = principal->GetCsp(getter_AddRefs(csp));
@@ -885,16 +893,28 @@ nsJSChannel::GetOwner(nsISupports* *aOwn
 
 NS_IMETHODIMP
 nsJSChannel::SetOwner(nsISupports* aOwner)
 {
     return mStreamChannel->SetOwner(aOwner);
 }
 
 NS_IMETHODIMP
+nsJSChannel::GetLoadInfo(nsILoadInfo* *aLoadInfo)
+{
+    return mStreamChannel->GetLoadInfo(aLoadInfo);
+}
+
+NS_IMETHODIMP
+nsJSChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
+{
+    return mStreamChannel->SetLoadInfo(aLoadInfo);
+}
+
+NS_IMETHODIMP
 nsJSChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
 {
     return mStreamChannel->GetNotificationCallbacks(aCallbacks);
 }
 
 NS_IMETHODIMP
 nsJSChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
 {
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -16,16 +16,17 @@
 #include "nsIScriptContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
+#include "BackgroundChild.h"
 #include "GeckoProfiler.h"
 #include "js/OldDebugAPI.h"
 #include "jsfriendapi.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
@@ -35,16 +36,17 @@
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
+#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsISupportsImpl.h"
 #include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
@@ -59,16 +61,22 @@
 #include "nsThreadManager.h"
 #endif
 
 #include "ServiceWorker.h"
 #include "SharedWorker.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 
+#ifdef ENABLE_TESTS
+#include "BackgroundChildImpl.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "prrng.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
 using mozilla::MutexAutoUnlock;
 using mozilla::Preferences;
@@ -156,16 +164,20 @@ const JS::ContextOptions kRequiredContex
 uint32_t gMaxWorkersPerDomain = MAX_WORKERS_PER_DOMAIN;
 
 // Does not hold an owning reference.
 RuntimeService* gRuntimeService = nullptr;
 
 // Only non-null during the call to Init.
 RuntimeService* gRuntimeServiceDuringInit = nullptr;
 
+#ifdef ENABLE_TESTS
+bool gTestPBackground = false;
+#endif // ENABLE_TESTS
+
 enum {
   ID_Worker = 0,
   ID_ChromeWorker,
   ID_Event,
   ID_MessageEvent,
   ID_ErrorEvent,
 
   ID_COUNT
@@ -896,16 +908,48 @@ public:
       nsCycleCollector_collect(nullptr);
     }
   }
 
 private:
   WorkerPrivate* mWorkerPrivate;
 };
 
+class WorkerBackgroundChildCallback MOZ_FINAL :
+  public nsIIPCBackgroundChildCreateCallback
+{
+  bool* mDone;
+
+public:
+  WorkerBackgroundChildCallback(bool* aDone)
+  : mDone(aDone)
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+    MOZ_ASSERT(mDone);
+  }
+
+  NS_DECL_ISUPPORTS
+
+private:
+  ~WorkerBackgroundChildCallback()
+  { }
+
+  virtual void
+  ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
+  {
+    *mDone = true;
+  }
+
+  virtual void
+  ActorFailed() MOZ_OVERRIDE
+  {
+    *mDone = true;
+  }
+};
+
 class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
   nsRefPtr<RuntimeService::WorkerThread> mThread;
   JSRuntime* mParentRuntime;
 
   class FinishedRunnable MOZ_FINAL : public nsRunnable
   {
@@ -938,16 +982,19 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
 private:
   ~WorkerThreadPrimaryRunnable()
   { }
 
+  nsresult
+  SynchronouslyCreatePBackground();
+
   NS_DECL_NSIRUNNABLE
 };
 
 class WorkerTaskRunnable MOZ_FINAL : public WorkerRunnable
 {
   nsRefPtr<WorkerTask> mTask;
 
 public:
@@ -1037,16 +1084,38 @@ public:
   void
   SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables)
   {
     MutexAutoLock lock(mLock);
     mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables;
   }
 #endif
 
+#ifdef ENABLE_TESTS
+  void
+  TestPBackground()
+  {
+    using namespace mozilla::ipc;
+    if (gTestPBackground) {
+      // Randomize value to validate workers are not cross-posting messages.
+      uint32_t testValue;
+      PRSize randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
+      MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
+      nsCString testStr;
+      testStr.AppendInt(testValue);
+      testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
+      PBackgroundChild* existingBackgroundChild =
+        BackgroundChild::GetForCurrentThread();
+      MOZ_RELEASE_ASSERT(existingBackgroundChild);
+      bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
+      MOZ_RELEASE_ASSERT(ok);
+    }
+  }
+#endif // #ENABLE_TESTS
+
 private:
   WorkerThread()
   : nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
     mWorkerPrivate(nullptr)
 #ifdef DEBUG
     , mAcceptingNonWorkerRunnables(true)
 #endif
   { }
@@ -1242,16 +1311,20 @@ RuntimeService::GetOrCreateService()
   if (!gRuntimeService) {
     nsRefPtr<RuntimeService> service = new RuntimeService();
     if (NS_FAILED(service->Init())) {
       NS_WARNING("Failed to initialize!");
       service->Cleanup();
       return nullptr;
     }
 
+#ifdef ENABLE_TESTS
+    gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false);
+#endif // ENABLE_TESTS
+
     // The observer service now owns us until shutdown.
     gRuntimeService = service;
   }
 
   return gRuntimeService;
 }
 
 // static
@@ -1531,20 +1604,16 @@ RuntimeService::ScheduleWorker(JSContext
   nsCOMPtr<nsIRunnable> runnable =
     new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx));
   if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
     UnregisterWorker(aCx, aWorkerPrivate);
     JS_ReportError(aCx, "Could not dispatch to thread!");
     return false;
   }
 
-#ifdef DEBUG
-  thread->SetAcceptingNonWorkerRunnables(false);
-#endif
-
   return true;
 }
 
 // static
 void
 RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */)
 {
   AssertIsOnMainThread();
@@ -2523,18 +2592,30 @@ RuntimeService::WorkerThread::Observer::
 }
 
 NS_IMETHODIMP
 RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
                                                nsIThreadInternal* /* aThread */,
                                                bool aMayWait,
                                                uint32_t aRecursionDepth)
 {
+  using mozilla::ipc::BackgroundChild;
+
   mWorkerPrivate->AssertIsOnWorkerThread();
-  MOZ_ASSERT(!aMayWait);
+
+  // If the PBackground child is not created yet, then we must permit
+  // blocking event processing to support SynchronouslyCreatePBackground().
+  // If this occurs then we are spinning on the event queue at the start of
+  // PrimaryWorkerRunnable::Run() and don't want to process the event in
+  // mWorkerPrivate yet.
+  if (aMayWait) {
+    MOZ_ASSERT(aRecursionDepth == 2);
+    MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
+    return NS_OK;
+  }
 
   mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RuntimeService::WorkerThread::Observer::AfterProcessNextEvent(
                                                nsIThreadInternal* /* aThread */,
@@ -2568,21 +2649,25 @@ LogViolationDetailsRunnable::Run()
   nsRefPtr<MainThreadStopSyncLoopRunnable> response =
     new MainThreadStopSyncLoopRunnable(mWorkerPrivate, mSyncLoopTarget.forget(),
                                        true);
   MOZ_ALWAYS_TRUE(response->Dispatch(nullptr));
 
   return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
+
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::Run()
 {
+  using mozilla::ipc::BackgroundChild;
+
 #ifdef MOZ_NUWA_PROCESS
   if (IsNuwaProcess()) {
     NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
                   "NuwaMarkCurrentThread is undefined!");
     NuwaMarkCurrentThread(nullptr, nullptr);
     NuwaFreezeCurrentThread();
   }
 #endif
@@ -2591,16 +2676,29 @@ WorkerThreadPrimaryRunnable::Run()
 
   nsAutoCString threadName;
   threadName.AssignLiteral("WebWorker '");
   threadName.Append(NS_LossyConvertUTF16toASCII(mWorkerPrivate->ScriptURL()));
   threadName.Append('\'');
 
   profiler_register_thread(threadName.get(), &stackBaseGuess);
 
+  // Note: SynchronouslyCreatePBackground() must be called prior to
+  //       mThread->SetWorker() in order to avoid accidentally consuming
+  //       worker messages here.
+  nsresult rv = SynchronouslyCreatePBackground();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // XXX need to fire an error at parent.
+    return rv;
+  }
+
+#ifdef ENABLE_TESTS
+  mThread->TestPBackground();
+#endif
+
   mThread->SetWorker(mWorkerPrivate);
 
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   {
     nsCycleCollector_startup();
 
     WorkerJSRuntime runtime(mParentRuntime, mWorkerPrivate);
@@ -2624,16 +2722,22 @@ WorkerThreadPrimaryRunnable::Run()
       {
         JSAutoRequest ar(cx);
 
         mWorkerPrivate->DoRunLoop(cx);
 
         JS_ReportPendingException(cx);
       }
 
+#ifdef ENABLE_TESTS
+      mThread->TestPBackground();
+#endif
+
+      BackgroundChild::CloseForCurrentThread();
+
 #ifdef MOZ_ENABLE_PROFILER_SPS
       if (stack) {
         stack->sampleRuntime(nullptr);
       }
 #endif
     }
 
     // Destroy the main context.  This will unroot the main worker global and
@@ -2662,16 +2766,48 @@ WorkerThreadPrimaryRunnable::Run()
     new FinishedRunnable(mThread.forget());
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread->Dispatch(finishedRunnable,
                                                     NS_DISPATCH_NORMAL)));
 
   profiler_unregister_thread();
   return NS_OK;
 }
 
+nsresult
+WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground()
+{
+  using mozilla::ipc::BackgroundChild;
+
+  MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
+
+  bool done = false;
+  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
+    new WorkerBackgroundChildCallback(&done);
+
+  if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  while (!done) {
+    if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWait */))) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
+    return NS_ERROR_FAILURE;
+  }
+
+#ifdef DEBUG
+  mThread->SetAcceptingNonWorkerRunnables(false);
+#endif
+
+  return NS_OK;
+}
+
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
                              nsRunnable)
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::FinishedRunnable::Run()
 {
   AssertIsOnMainThread();
 
--- a/dom/xslt/base/txURIUtils.cpp
+++ b/dom/xslt/base/txURIUtils.cpp
@@ -2,16 +2,19 @@
 /* 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 "txURIUtils.h"
 #include "nsNetUtil.h"
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
+#include "mozilla/LoadInfo.h"
+
+using mozilla::LoadInfo;
 
 /**
  * URIUtils
  * A set of utilities for handling URIs
 **/
 
 /**
  * Resolves the given href argument, using the given documentBase
@@ -57,17 +60,20 @@ URIUtils::ResetWithSource(nsIDocument *a
     if (!channel) {
         // Need to synthesize one
         if (NS_FAILED(NS_NewChannel(getter_AddRefs(channel),
                                     sourceDoc->GetDocumentURI(),
                                     nullptr,
                                     loadGroup))) {
             return;
         }
-        channel->SetOwner(sourcePrincipal);
+        nsCOMPtr<nsILoadInfo> loadInfo =
+            new LoadInfo(sourcePrincipal, LoadInfo::eInheritPrincipal,
+                         LoadInfo::eNotSandboxed);
+        channel->SetLoadInfo(loadInfo);
     }
     aNewDoc->Reset(channel, loadGroup);
     aNewDoc->SetPrincipal(sourcePrincipal);
     aNewDoc->SetBaseURI(sourceDoc->GetDocBaseURI());
 
     // Copy charset
     aNewDoc->SetDocumentCharacterSetSource(
           sourceDoc->GetDocumentCharacterSetSource());
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -203,17 +203,20 @@ public:
    * by RotatedContentBuffer and must be redrawn on the screen.
    * mRegionToInvalidate is set when the buffer has changed from
    * opaque to transparent or vice versa, since the details of rendering can
    * depend on the buffer type.  mDidSelfCopy is true if we kept our buffer
    * but used MovePixels() to shift its content.
    */
   struct PaintState {
     PaintState()
-      : mMode(SurfaceMode::SURFACE_NONE)
+      : mRegionToDraw()
+      , mRegionToInvalidate()
+      , mMode(SurfaceMode::SURFACE_NONE)
+      , mClip(DrawRegionClip::CLIP_NONE)
       , mContentType(gfxContentType::SENTINEL)
       , mDidSelfCopy(false)
     {}
 
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
     SurfaceMode mMode;
     DrawRegionClip mClip;
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -803,16 +803,20 @@ APZCTreeManager::DispatchScroll(AsyncPan
 
     next = mOverscrollHandoffChain[aOverscrollHandoffChainIndex];
   }
 
   if (next == nullptr) {
     return false;
   }
 
+  if (next->GetGuid().mLayersId != aPrev->GetGuid().mLayersId) {
+    NS_WARNING("Handing off scroll across a layer tree boundary; may need to revise approach to bug 1031067");
+  }
+
   // Convert the start and end points from |aPrev|'s coordinate space to
   // |next|'s coordinate space. Since |aPrev| may be the same as |next|
   // (if |aPrev| is the APZC that is initiating the scroll and there is no
   // scroll grabbing to grab the scroll from it), don't bother doing the
   // transformations in that case.
   if (next != aPrev) {
     TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint);
   }
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1235,16 +1235,25 @@ nsEventStatus AsyncPanZoomController::On
   if (!TouchActionAllowPinchZoom()) {
     return nsEventStatus_eIgnore;
   }
 
   SetState(NOTHING);
 
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
+
+    // We can get into a situation where we are overscrolled at the end of a
+    // pinch if we go into overscroll with a two-finger pan, and then turn
+    // that into a pinch by increasing the span sufficiently. In such a case,
+    // there is no snap-back animation to get us out of overscroll, so we need
+    // to get out of it somehow.
+    mX.ClearOverscroll();
+    mY.ClearOverscroll();
+
     ScheduleComposite();
     RequestContentRepaint();
     UpdateSharedCompositorFrameMetrics();
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
--- a/gfx/skia/trunk/include/core/SkTDArray.h
+++ b/gfx/skia/trunk/include/core/SkTDArray.h
@@ -7,17 +7,17 @@
  */
 
 
 #ifndef SkTDArray_DEFINED
 #define SkTDArray_DEFINED
 
 #include "SkTypes.h"
 
-template <typename T> class SK_API SkTDArray {
+template <typename T> class SkTDArray {
 public:
     SkTDArray() {
         fReserve = fCount = 0;
         fArray = NULL;
 #ifdef SK_DEBUG
         fData = NULL;
 #endif
     }
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1764,42 +1764,53 @@ gfxContext::PointInStroke(const gfxPoint
 gfxRect
 gfxContext::GetUserPathExtent()
 {
   if (mCairo) {
     double xmin, ymin, xmax, ymax;
     cairo_path_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
+    if (mPathIsRect) {
+      return ThebesRect(mTransform.TransformBounds(mRect));
+    }
     EnsurePath();
     return ThebesRect(mPath->GetBounds());
   }
 }
 
 gfxRect
 gfxContext::GetUserFillExtent()
 {
   if (mCairo) {
     double xmin, ymin, xmax, ymax;
     cairo_fill_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
+    if (mPathIsRect) {
+      return ThebesRect(mTransform.TransformBounds(mRect));
+    }
     EnsurePath();
     return ThebesRect(mPath->GetBounds());
   }
 }
 
 gfxRect
 gfxContext::GetUserStrokeExtent()
 {
   if (mCairo) {
     double xmin, ymin, xmax, ymax;
     cairo_stroke_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
+    if (mPathIsRect) {
+      Rect rect = mRect;
+      rect.Inflate(CurrentState().strokeOptions.mLineWidth / 2);
+      return ThebesRect(mTransform.TransformBounds(rect));
+    }
     EnsurePath();
     return ThebesRect(mPath->GetStrokedBounds(CurrentState().strokeOptions, mTransform));
   }
 }
 
 bool
 gfxContext::HasError()
 {
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -5175,17 +5175,17 @@ gfxFontGroup::FindPlatformFont(const nsA
         // First, look up in the user font set...
         // If the fontSet matches the family, we must not look for a platform
         // font of the same name, even if we fail to actually get a fontEntry
         // here; we'll fall back to the next name in the CSS font-family list.
         if (mUserFontSet) {
             // If the fontSet matches the family, but the font has not yet finished
             // loading (nor has its load timeout fired), the fontGroup should wait
             // for the download, and not actually draw its text yet.
-            family = mUserFontSet->GetFamily(aName);
+            family = mUserFontSet->LookupFamily(aName);
             if (family) {
                 bool waitForUserFont = false;
                 fe = mUserFontSet->FindFontEntry(family, mStyle,
                                                  needsBold, waitForUserFont);
                 if (!fe && waitForUserFont) {
                     mSkipDrawing = true;
                 }
             }
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -813,17 +813,21 @@ public:
     void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) {
         // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
         // of Times New Roman, because of buggy table in those fonts
         if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() &&
             Name().EqualsLiteral("Times New Roman"))
         {
             aFontEntry->mIgnoreGDEF = true;
         }
-        aFontEntry->mFamilyName = Name();
+        if (aFontEntry->mFamilyName.IsEmpty()) {
+            aFontEntry->mFamilyName = Name();
+        } else {
+            MOZ_ASSERT(aFontEntry->mFamilyName.Equals(Name()));
+        }
         aFontEntry->mSkipDefaultFeatureSpaceCheck = mSkipDefaultFeatureSpaceCheck;
         mAvailableFonts.AppendElement(aFontEntry);
     }
 
     // note that the styles for this family have been added
     bool HasStyles() { return mHasStyles; }
     void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; }
 
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -789,17 +789,17 @@ FindFontPatterns(gfxUserFontSet *mUserFo
     bool needsBold;
 
     gfxFontStyle style;
     style.style = aStyle;
     style.weight = aWeight;
     style.stretch = aStretch;
 
     gfxUserFcFontEntry *fontEntry = nullptr;
-    gfxFontFamily *family = mUserFontSet->GetFamily(utf16Family);
+    gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family);
     if (family) {
         fontEntry = static_cast<gfxUserFcFontEntry*>
             (mUserFontSet->FindFontEntry(family, style, needsBold,
                                          aWaitForUserFont));
 
         // Accept synthetic oblique for italic and oblique.
         if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
             style.style = NS_FONT_STYLE_NORMAL;
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -15,16 +15,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsIPresShell.h"
 #include "nsNetUtil.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "nsStreamUtils.h"
 #include "nsIPrincipal.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/LoadInfo.h"
 #include "nsSVGUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsContentUtils.h"
 #include "gfxFont.h"
 #include "nsSMILAnimationController.h"
 #include "gfxContext.h"
 #include "gfxColor.h"
@@ -366,17 +367,20 @@ gfxSVGGlyphsDocument::ParseDocument(cons
         return NS_ERROR_FAILURE;
     }
 
     nsCOMPtr<nsIChannel> channel;
     rv = NS_NewInputStreamChannel(getter_AddRefs(channel), uri, nullptr /* stream */,
                                   SVG_CONTENT_TYPE, UTF8_CHARSET);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    channel->SetOwner(principal);
+    nsCOMPtr<nsILoadInfo> loadInfo =
+      new LoadInfo(principal, LoadInfo::eInheritPrincipal,
+                   LoadInfo::eNotSandboxed);
+    channel->SetLoadInfo(loadInfo);
 
     // Set this early because various decisions during page-load depend on it.
     document->SetIsBeingUsedAsImage();
     document->SetReadyStateInternal(nsIDocument::READYSTATE_UNINITIALIZED);
 
     nsCOMPtr<nsIStreamListener> listener;
     rv = document->StartDocumentLoad("external-resource", channel,
                                      nullptr,    // aLoadGroup
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -30,240 +30,21 @@ gfxUserFontSet::GetUserFontsLog()
 {
     static PRLogModuleInfo *sLog;
     if (!sLog)
         sLog = PR_NewLogModule("userfonts");
     return sLog;
 }
 #endif /* PR_LOGGING */
 
-#define LOG(args) PR_LOG(GetUserFontsLog(), PR_LOG_DEBUG, args)
-#define LOG_ENABLED() PR_LOG_TEST(GetUserFontsLog(), PR_LOG_DEBUG)
+#define LOG(args) PR_LOG(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG)
 
 static uint64_t sFontSetGeneration = 0;
 
-// TODO: support for unicode ranges not yet implemented
-
-gfxProxyFontEntry::gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-             uint32_t aWeight,
-             int32_t aStretch,
-             uint32_t aItalicStyle,
-             const nsTArray<gfxFontFeature>& aFeatureSettings,
-             uint32_t aLanguageOverride,
-             gfxSparseBitSet *aUnicodeRanges)
-    : gfxFontEntry(NS_LITERAL_STRING("Proxy")),
-      mLoadingState(NOT_LOADING),
-      mUnsupportedFormat(false),
-      mLoader(nullptr)
-{
-    mIsProxy = true;
-    mSrcList = aFontFaceSrcList;
-    mSrcIndex = 0;
-    mWeight = aWeight;
-    mStretch = aStretch;
-    // XXX Currently, we don't distinguish 'italic' and 'oblique' styles;
-    // we need to fix this. (Bug 543715)
-    mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
-    mFeatureSettings.AppendElements(aFeatureSettings);
-    mLanguageOverride = aLanguageOverride;
-    mIsUserFont = true;
-}
-
-gfxProxyFontEntry::~gfxProxyFontEntry()
-{
-}
-
-bool
-gfxProxyFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                           uint32_t aWeight,
-                           int32_t aStretch,
-                           uint32_t aItalicStyle,
-                           const nsTArray<gfxFontFeature>& aFeatureSettings,
-                           uint32_t aLanguageOverride,
-                           gfxSparseBitSet *aUnicodeRanges)
-{
-    // XXX font entries don't distinguish italic from oblique (bug 543715)
-    bool isItalic =
-        (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
-
-    return mWeight == aWeight &&
-           mStretch == aStretch &&
-           mItalic == isItalic &&
-           mFeatureSettings == aFeatureSettings &&
-           mLanguageOverride == aLanguageOverride &&
-           mSrcList == aFontFaceSrcList;
-           // XXX once we support unicode-range (bug 475891),
-           // we'll need to compare that here as well
-}
-
-gfxFont*
-gfxProxyFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
-{
-    // cannot create an actual font for a proxy entry
-    return nullptr;
-}
-
-gfxUserFontSet::gfxUserFontSet()
-    : mFontFamilies(5), mLocalRulesUsed(false)
-{
-    IncrementGeneration();
-    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
-    if (fp) {
-        fp->AddUserFontSet(this);
-    }
-}
-
-gfxUserFontSet::~gfxUserFontSet()
-{
-    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
-    if (fp) {
-        fp->RemoveUserFontSet(this);
-    }
-}
-
-gfxFontEntry*
-gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
-                            const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                            uint32_t aWeight,
-                            int32_t aStretch,
-                            uint32_t aItalicStyle,
-                            const nsTArray<gfxFontFeature>& aFeatureSettings,
-                            uint32_t aLanguageOverride,
-                            gfxSparseBitSet *aUnicodeRanges)
-{
-    MOZ_ASSERT(aWeight != 0,
-               "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
-
-    nsAutoString key(aFamilyName);
-    ToLowerCase(key);
-
-    bool found;
-
-    // stretch, italic/oblique ==> zero implies normal
-
-    gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
-    if (!family) {
-        family = new gfxMixedFontFamily(aFamilyName);
-        mFontFamilies.Put(key, family);
-    }
-
-    // If there's already a proxy in the family whose descriptors all match,
-    // we can just move it to the end of the list instead of adding a new
-    // face that will always "shadow" the old one.
-    // Note that we can't do this for "real" (non-proxy) entries, even if the
-    // style descriptors match, as they might have had a different source list,
-    // but we no longer have the old source list available to check.
-    nsTArray<nsRefPtr<gfxFontEntry> >& fontList = family->GetFontList();
-    for (uint32_t i = 0, count = fontList.Length(); i < count; i++) {
-        if (!fontList[i]->mIsProxy) {
-            continue;
-        }
-
-        gfxProxyFontEntry *existingProxyEntry =
-            static_cast<gfxProxyFontEntry*>(fontList[i].get());
-        if (!existingProxyEntry->Matches(aFontFaceSrcList,
-                                         aWeight, aStretch, aItalicStyle,
-                                         aFeatureSettings, aLanguageOverride,
-                                         aUnicodeRanges)) {
-            continue;
-        }
-
-        // We've found an entry that matches the new face exactly, so just add
-        // it to the end of the list. gfxMixedFontFamily::AddFontEntry() will
-        // automatically remove any earlier occurrence of the same proxy.
-        family->AddFontEntry(existingProxyEntry);
-        return existingProxyEntry;
-    }
-
-    // construct a new face and add it into the family
-    gfxProxyFontEntry *proxyEntry =
-        new gfxProxyFontEntry(aFontFaceSrcList, aWeight, aStretch,
-                              aItalicStyle,
-                              aFeatureSettings,
-                              aLanguageOverride,
-                              aUnicodeRanges);
-    family->AddFontEntry(proxyEntry);
-#ifdef PR_LOGGING
-    if (LOG_ENABLED()) {
-        LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
-             this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
-             (aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
-                 (aItalicStyle & NS_FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
-             aWeight, aStretch));
-    }
-#endif
-
-    return proxyEntry;
-}
-
-void
-gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
-                            gfxFontEntry     *aFontEntry)
-{
-    nsAutoString key(aFamilyName);
-    ToLowerCase(key);
-
-    bool found;
-
-    gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
-    if (!family) {
-        family = new gfxMixedFontFamily(aFamilyName);
-        mFontFamilies.Put(key, family);
-    }
-
-    family->AddFontEntry(aFontEntry);
-}
-
-gfxFontEntry*
-gfxUserFontSet::FindFontEntry(gfxFontFamily *aFamily,
-                              const gfxFontStyle& aFontStyle,
-                              bool& aNeedsBold,
-                              bool& aWaitForUserFont)
-{
-    aWaitForUserFont = false;
-    gfxMixedFontFamily *family = static_cast<gfxMixedFontFamily*>(aFamily);
-
-    gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
-
-    // if not a proxy, font has already been loaded
-    if (!fe->mIsProxy) {
-        return fe;
-    }
-
-    gfxProxyFontEntry *proxyEntry = static_cast<gfxProxyFontEntry*> (fe);
-
-    // if currently loading, return null for now
-    if (proxyEntry->mLoadingState > gfxProxyFontEntry::NOT_LOADING) {
-        aWaitForUserFont =
-            (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
-        return nullptr;
-    }
-
-    // hasn't been loaded yet, start the load process
-    LoadStatus status;
-
-    // NOTE that if all sources in the entry fail, this will delete proxyEntry,
-    // so we cannot use it again if status==STATUS_END_OF_LIST
-    status = LoadNext(family, proxyEntry);
-
-    // if the load succeeded immediately, the font entry was replaced so
-    // search again
-    if (status == STATUS_LOADED) {
-        return family->FindFontForStyle(aFontStyle, aNeedsBold);
-    }
-
-    // check whether we should wait for load to complete before painting
-    // a fallback font -- but not if all sources failed (bug 633500)
-    aWaitForUserFont = (status != STATUS_END_OF_LIST) &&
-        (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
-
-    // if either loading or an error occurred, return null
-    return nullptr;
-}
-
 // Based on ots::ExpandingMemoryStream from ots-memory-stream.h,
 // adapted to use Mozilla allocators and to allow the final
 // memory buffer to be adopted by the client.
 class ExpandingMemoryStream : public ots::OTSStream {
 public:
     ExpandingMemoryStream(size_t initial, size_t limit)
         : mLength(initial), mLimit(limit), mOff(0) {
         mPtr = NS_Alloc(mLength);
@@ -321,16 +102,79 @@ public:
 
 private:
     void*        mPtr;
     size_t       mLength;
     const size_t mLimit;
     off_t        mOff;
 };
 
+// TODO: support for unicode ranges not yet implemented
+
+gfxProxyFontEntry::gfxProxyFontEntry(gfxUserFontSet *aFontSet,
+             const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+             uint32_t aWeight,
+             int32_t aStretch,
+             uint32_t aItalicStyle,
+             const nsTArray<gfxFontFeature>& aFeatureSettings,
+             uint32_t aLanguageOverride,
+             gfxSparseBitSet *aUnicodeRanges)
+    : gfxFontEntry(NS_LITERAL_STRING("Proxy")),
+      mLoadingState(NOT_LOADING),
+      mUnsupportedFormat(false),
+      mLoader(nullptr),
+      mFontSet(aFontSet)
+{
+    mIsProxy = true;
+    mSrcList = aFontFaceSrcList;
+    mSrcIndex = 0;
+    mWeight = aWeight;
+    mStretch = aStretch;
+    // XXX Currently, we don't distinguish 'italic' and 'oblique' styles;
+    // we need to fix this. (Bug 543715)
+    mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
+    mFeatureSettings.AppendElements(aFeatureSettings);
+    mLanguageOverride = aLanguageOverride;
+    mIsUserFont = true;
+}
+
+gfxProxyFontEntry::~gfxProxyFontEntry()
+{
+}
+
+bool
+gfxProxyFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+                           uint32_t aWeight,
+                           int32_t aStretch,
+                           uint32_t aItalicStyle,
+                           const nsTArray<gfxFontFeature>& aFeatureSettings,
+                           uint32_t aLanguageOverride,
+                           gfxSparseBitSet *aUnicodeRanges)
+{
+    // XXX font entries don't distinguish italic from oblique (bug 543715)
+    bool isItalic =
+        (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
+
+    return mWeight == aWeight &&
+           mStretch == aStretch &&
+           mItalic == isItalic &&
+           mFeatureSettings == aFeatureSettings &&
+           mLanguageOverride == aLanguageOverride &&
+           mSrcList == aFontFaceSrcList;
+           // XXX once we support unicode-range (bug 475891),
+           // we'll need to compare that here as well
+}
+
+gfxFont*
+gfxProxyFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
+{
+    // cannot create an actual font for a proxy entry
+    return nullptr;
+}
+
 static ots::TableAction
 OTSTableAction(uint32_t aTag, void *aUserData)
 {
     // preserve Graphite, color glyph and SVG tables
     if (aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
         aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
         aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
         aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
@@ -339,86 +183,87 @@ OTSTableAction(uint32_t aTag, void *aUse
         aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
         aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
         return ots::TABLE_ACTION_PASSTHRU;
     }
     return ots::TABLE_ACTION_DEFAULT;
 }
 
 struct OTSCallbackUserData {
-    gfxUserFontSet     *mFontSet;
     gfxMixedFontFamily *mFamily;
     gfxProxyFontEntry  *mProxy;
 };
 
 /* static */ bool
-gfxUserFontSet::OTSMessage(void *aUserData, const char *format, ...)
+gfxProxyFontEntry::OTSMessage(void *aUserData, const char *format, ...)
 {
     va_list va;
     va_start(va, format);
 
     // buf should be more than adequate for any message OTS generates,
     // so we don't worry about checking the result of vsnprintf()
     char buf[512];
     (void)vsnprintf(buf, sizeof(buf), format, va);
 
     va_end(va);
 
     OTSCallbackUserData *d = static_cast<OTSCallbackUserData*>(aUserData);
-    d->mFontSet->LogMessage(d->mFamily, d->mProxy, buf);
+    d->mProxy->mFontSet->LogMessage(d->mFamily, d->mProxy, buf);
 
     return false;
 }
 
 // Call the OTS library to sanitize an sfnt before attempting to use it.
 // Returns a newly-allocated block, or nullptr in case of fatal errors.
 const uint8_t*
-gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
-                                     gfxProxyFontEntry *aProxy,
-                                     const uint8_t* aData, uint32_t aLength,
-                                     uint32_t& aSaneLength, bool aIsCompressed)
+gfxProxyFontEntry::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
+                                        const uint8_t* aData,
+                                        uint32_t       aLength,
+                                        uint32_t&      aSaneLength,
+                                        bool           aIsCompressed)
 {
     // limit output/expansion to 256MB
     ExpandingMemoryStream output(aIsCompressed ? aLength * 2 : aLength,
                                  1024 * 1024 * 256);
 
     OTSCallbackUserData userData;
-    userData.mFontSet = this;
     userData.mFamily = aFamily;
-    userData.mProxy = aProxy;
+    userData.mProxy = this;
 
     ots::OTSContext otsContext;
     otsContext.SetTableActionCallback(&OTSTableAction, nullptr);
-    otsContext.SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData);
+    otsContext.SetMessageCallback(&OTSMessage, &userData);
 
     if (otsContext.Process(&output, aData, aLength)) {
         aSaneLength = output.Tell();
         return static_cast<uint8_t*>(output.forget());
     } else {
         aSaneLength = 0;
         return nullptr;
     }
 }
 
-static void
-StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
-                  bool aPrivate, const nsAString& aOriginalName,
-                  FallibleTArray<uint8_t>* aMetadata, uint32_t aMetaOrigLen)
+void
+gfxProxyFontEntry::StoreUserFontData(gfxFontEntry* aFontEntry,
+                                     bool aPrivate,
+                                     const nsAString& aOriginalName,
+                                     FallibleTArray<uint8_t>* aMetadata,
+                                     uint32_t aMetaOrigLen)
 {
     if (!aFontEntry->mUserFontData) {
         aFontEntry->mUserFontData = new gfxUserFontData;
     }
     gfxUserFontData* userFontData = aFontEntry->mUserFontData;
-    userFontData->mSrcIndex = aProxy->mSrcIndex;
-    const gfxFontFaceSrc& src = aProxy->mSrcList[aProxy->mSrcIndex];
+    userFontData->mSrcIndex = mSrcIndex;
+    const gfxFontFaceSrc& src = mSrcList[mSrcIndex];
     if (src.mIsLocal) {
         userFontData->mLocalName = src.mLocalName;
     } else {
         userFontData->mURI = src.mURI;
-        userFontData->mPrincipal = aProxy->mPrincipal;
+        userFontData->mPrincipal = mPrincipal;
     }
     userFontData->mPrivate = aPrivate;
     userFontData->mFormat = src.mFormatFlags;
     userFontData->mRealName = aOriginalName;
     if (aMetadata) {
         userFontData->mMetadata.SwapElements(*aMetadata);
         userFontData->mMetaOrigLen = aMetaOrigLen;
     }
@@ -435,21 +280,21 @@ struct WOFFHeader {
     AutoSwap_PRUint16 minorVersion;
     AutoSwap_PRUint32 metaOffset;
     AutoSwap_PRUint32 metaCompLen;
     AutoSwap_PRUint32 metaOrigLen;
     AutoSwap_PRUint32 privOffset;
     AutoSwap_PRUint32 privLen;
 };
 
-void
-gfxUserFontSet::CopyWOFFMetadata(const uint8_t* aFontData,
-                                 uint32_t aLength,
-                                 FallibleTArray<uint8_t>* aMetadata,
-                                 uint32_t* aMetaOrigLen)
+static void
+CopyWOFFMetadata(const uint8_t* aFontData,
+                 uint32_t aLength,
+                 FallibleTArray<uint8_t>* aMetadata,
+                 uint32_t* aMetaOrigLen)
 {
     // This function may be called with arbitrary, unvalidated "font" data
     // from @font-face, so it needs to be careful to bounds-check, etc.,
     // before trying to read anything.
     // This just saves a copy of the compressed data block; it does NOT check
     // that the block can be successfully decompressed, or that it contains
     // well-formed/valid XML metadata.
     if (aLength < sizeof(WOFFHeader)) {
@@ -466,32 +311,421 @@ gfxUserFontSet::CopyWOFFMetadata(const u
     }
     if (!aMetadata->SetLength(woff->metaCompLen)) {
         return;
     }
     memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
     *aMetaOrigLen = woff->metaOrigLen;
 }
 
+gfxProxyFontEntry::LoadStatus
+gfxProxyFontEntry::LoadNext(gfxMixedFontFamily *aFamily,
+                            bool& aLocalRulesUsed)
+{
+    uint32_t numSrc = mSrcList.Length();
+
+    NS_ASSERTION(mSrcIndex < numSrc,
+                 "already at the end of the src list for user font");
+
+    if (mLoadingState == NOT_LOADING) {
+        mLoadingState = LOADING_STARTED;
+        mUnsupportedFormat = false;
+    } else {
+        // we were already loading; move to the next source,
+        // but don't reset state - if we've already timed out,
+        // that counts against the new download
+        mSrcIndex++;
+    }
+
+    // load each src entry in turn, until a local face is found
+    // or a download begins successfully
+    while (mSrcIndex < numSrc) {
+        const gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex];
+
+        // src local ==> lookup and load immediately
+
+        if (currSrc.mIsLocal) {
+            gfxFontEntry *fe =
+                gfxPlatform::GetPlatform()->LookupLocalFont(this,
+                                                            currSrc.mLocalName);
+            aLocalRulesUsed = true;
+            if (fe) {
+                LOG(("fontset (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
+                     mFontSet, mSrcIndex,
+                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
+                     NS_ConvertUTF16toUTF8(mFamilyName).get(),
+                     uint32_t(mFontSet->mGeneration)));
+                fe->mFeatureSettings.AppendElements(mFeatureSettings);
+                fe->mLanguageOverride = mLanguageOverride;
+                fe->mFamilyName = mFamilyName;
+                // For src:local(), we don't care whether the request is from
+                // a private window as there's no issue of caching resources;
+                // local fonts are just available all the time.
+                StoreUserFontData(fe, false, nsString(), nullptr, 0);
+                mFontSet->ReplaceFontEntry(aFamily, this, fe);
+                return STATUS_LOADED;
+            } else {
+                LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
+                     mFontSet, mSrcIndex,
+                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
+                     NS_ConvertUTF16toUTF8(mFamilyName).get()));
+            }
+        }
+
+        // src url ==> start the load process
+        else {
+            if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
+                    currSrc.mFormatFlags)) {
+
+                nsIPrincipal *principal = nullptr;
+                bool bypassCache;
+                nsresult rv = mFontSet->CheckFontLoad(&currSrc, &principal,
+                                                      &bypassCache);
+
+                if (NS_SUCCEEDED(rv) && principal != nullptr) {
+                    if (!bypassCache) {
+                        // see if we have an existing entry for this source
+                        gfxFontEntry *fe = gfxUserFontSet::
+                            UserFontCache::GetFont(currSrc.mURI,
+                                                   principal,
+                                                   this,
+                                                   mFontSet->GetPrivateBrowsing());
+                        if (fe) {
+                            mFontSet->ReplaceFontEntry(aFamily, this, fe);
+                            return STATUS_LOADED;
+                        }
+                    }
+
+                    // record the principal returned by CheckFontLoad,
+                    // for use when creating a channel
+                    // and when caching the loaded entry
+                    mPrincipal = principal;
+
+                    bool loadDoesntSpin = false;
+                    rv = NS_URIChainHasFlags(currSrc.mURI,
+                           nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
+                           &loadDoesntSpin);
+
+                    if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
+                        uint8_t *buffer = nullptr;
+                        uint32_t bufferLength = 0;
+
+                        // sync load font immediately
+                        rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer,
+                                                        bufferLength);
+
+                        if (NS_SUCCEEDED(rv) &&
+                            LoadFont(aFamily, buffer, bufferLength)) {
+                            return STATUS_LOADED;
+                        } else {
+                            mFontSet->LogMessage(aFamily, this,
+                                                 "font load failed",
+                                                 nsIScriptError::errorFlag,
+                                                 rv);
+                        }
+
+                    } else {
+                        // otherwise load font async
+                        rv = mFontSet->StartLoad(aFamily, this, &currSrc);
+                        bool loadOK = NS_SUCCEEDED(rv);
+
+                        if (loadOK) {
+#ifdef PR_LOGGING
+                            if (LOG_ENABLED()) {
+                                nsAutoCString fontURI;
+                                currSrc.mURI->GetSpec(fontURI);
+                                LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
+                                     mFontSet, mSrcIndex, fontURI.get(),
+                                     NS_ConvertUTF16toUTF8(mFamilyName).get()));
+                            }
+#endif
+                            return STATUS_LOADING;
+                        } else {
+                            mFontSet->LogMessage(aFamily, this,
+                                                 "download failed",
+                                                 nsIScriptError::errorFlag,
+                                                 rv);
+                        }
+                    }
+                } else {
+                    mFontSet->LogMessage(aFamily, this, "download not allowed",
+                                         nsIScriptError::errorFlag, rv);
+                }
+            } else {
+                // We don't log a warning to the web console yet,
+                // as another source may load successfully
+                mUnsupportedFormat = true;
+            }
+        }
+
+        mSrcIndex++;
+    }
+
+    if (mUnsupportedFormat) {
+        mFontSet->LogMessage(aFamily, this, "no supported format found",
+                             nsIScriptError::warningFlag);
+    }
+
+    // all src's failed; mark this entry as unusable (so fallback will occur)
+    LOG(("userfonts (%p) failed all src for (%s)\n",
+        mFontSet, NS_ConvertUTF16toUTF8(mFamilyName).get()));
+    mLoadingState = LOADING_FAILED;
+
+    return STATUS_END_OF_LIST;
+}
+
+gfxFontEntry*
+gfxProxyFontEntry::LoadFont(gfxMixedFontFamily *aFamily,
+                            const uint8_t *aFontData, uint32_t &aLength)
+{
+    gfxFontEntry *fe = nullptr;
+
+    gfxUserFontType fontType =
+        gfxFontUtils::DetermineFontDataType(aFontData, aLength);
+
+    // Unwrap/decompress/sanitize or otherwise munge the downloaded data
+    // to make a usable sfnt structure.
+
+    // Because platform font activation code may replace the name table
+    // in the font with a synthetic one, we save the original name so that
+    // it can be reported via the nsIDOMFontFace API.
+    nsAutoString originalFullName;
+
+    // Call the OTS sanitizer; this will also decode WOFF to sfnt
+    // if necessary. The original data in aFontData is left unchanged.
+    uint32_t saneLen;
+    const uint8_t* saneData =
+        SanitizeOpenTypeData(aFamily, aFontData, aLength, saneLen,
+                             fontType == GFX_USERFONT_WOFF);
+    if (!saneData) {
+        mFontSet->LogMessage(aFamily, this, "rejected by sanitizer");
+    }
+    if (saneData) {
+        // The sanitizer ensures that we have a valid sfnt and a usable
+        // name table, so this should never fail unless we're out of
+        // memory, and GetFullNameFromSFNT is not directly exposed to
+        // arbitrary/malicious data from the web.
+        gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
+                                          originalFullName);
+        // Here ownership of saneData is passed to the platform,
+        // which will delete it when no longer required
+        fe = gfxPlatform::GetPlatform()->MakePlatformFont(this,
+                                                          saneData,
+                                                          saneLen);
+        if (!fe) {
+            mFontSet->LogMessage(aFamily, this, "not usable by platform");
+        }
+    }
+
+    if (fe) {
+        // Save a copy of the metadata block (if present) for nsIDOMFontFace
+        // to use if required. Ownership of the metadata block will be passed
+        // to the gfxUserFontData record below.
+        FallibleTArray<uint8_t> metadata;
+        uint32_t metaOrigLen = 0;
+        if (fontType == GFX_USERFONT_WOFF) {
+            CopyWOFFMetadata(aFontData, aLength, &metadata, &metaOrigLen);
+        }
+
+        // copy OpenType feature/language settings from the proxy to the
+        // newly-created font entry
+        fe->mFeatureSettings.AppendElements(mFeatureSettings);
+        fe->mLanguageOverride = mLanguageOverride;
+        fe->mFamilyName = mFamilyName;
+        StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
+                          &metadata, metaOrigLen);
+#ifdef PR_LOGGING
+        if (LOG_ENABLED()) {
+            nsAutoCString fontURI;
+            mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
+            LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
+                 this, mSrcIndex, fontURI.get(),
+                 NS_ConvertUTF16toUTF8(mFamilyName).get(),
+                 uint32_t(mFontSet->mGeneration)));
+        }
+#endif
+        mFontSet->ReplaceFontEntry(aFamily, this, fe);
+        gfxUserFontSet::UserFontCache::CacheFont(fe);
+    } else {
+#ifdef PR_LOGGING
+        if (LOG_ENABLED()) {
+            nsAutoCString fontURI;
+            mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
+            LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
+                 " error making platform font\n",
+                 this, mSrcIndex, fontURI.get(),
+                 NS_ConvertUTF16toUTF8(mFamilyName).get()));
+        }
+#endif
+    }
+
+    // The downloaded data can now be discarded; the font entry is using the
+    // sanitized copy
+    NS_Free((void*)aFontData);
+
+    return fe;
+}
+
+gfxUserFontSet::gfxUserFontSet()
+    : mFontFamilies(5), mLocalRulesUsed(false)
+{
+    IncrementGeneration();
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    if (fp) {
+        fp->AddUserFontSet(this);
+    }
+}
+
+gfxUserFontSet::~gfxUserFontSet()
+{
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    if (fp) {
+        fp->RemoveUserFontSet(this);
+    }
+}
+
+gfxFontEntry*
+gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
+                            const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+                            uint32_t aWeight,
+                            int32_t aStretch,
+                            uint32_t aItalicStyle,
+                            const nsTArray<gfxFontFeature>& aFeatureSettings,
+                            uint32_t aLanguageOverride,
+                            gfxSparseBitSet *aUnicodeRanges)
+{
+    MOZ_ASSERT(aWeight != 0,
+               "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
+
+    // stretch, italic/oblique ==> zero implies normal
+
+    gfxMixedFontFamily* family = GetFamily(aFamilyName);
+
+    // If there's already a proxy in the family whose descriptors all match,
+    // we can just move it to the end of the list instead of adding a new
+    // face that will always "shadow" the old one.
+    // Note that we can't do this for "real" (non-proxy) entries, even if the
+    // style descriptors match, as they might have had a different source list,
+    // but we no longer have the old source list available to check.
+    nsTArray<nsRefPtr<gfxFontEntry> >& fontList = family->GetFontList();
+    for (uint32_t i = 0, count = fontList.Length(); i < count; i++) {
+        if (!fontList[i]->mIsProxy) {
+            continue;
+        }
+
+        gfxProxyFontEntry *existingProxyEntry =
+            static_cast<gfxProxyFontEntry*>(fontList[i].get());
+        if (!existingProxyEntry->Matches(aFontFaceSrcList,
+                                         aWeight, aStretch, aItalicStyle,
+                                         aFeatureSettings, aLanguageOverride,
+                                         aUnicodeRanges)) {
+            continue;
+        }
+
+        // We've found an entry that matches the new face exactly, so just add
+        // it to the end of the list. gfxMixedFontFamily::AddFontEntry() will
+        // automatically remove any earlier occurrence of the same proxy.
+        family->AddFontEntry(existingProxyEntry);
+        return existingProxyEntry;
+    }
+
+    // construct a new face and add it into the family
+    gfxProxyFontEntry *proxyEntry =
+        new gfxProxyFontEntry(this, aFontFaceSrcList,
+                              aWeight, aStretch,
+                              aItalicStyle,
+                              aFeatureSettings,
+                              aLanguageOverride,
+                              aUnicodeRanges);
+    proxyEntry->mFamilyName = aFamilyName;
+    family->AddFontEntry(proxyEntry);
+#ifdef PR_LOGGING
+    if (LOG_ENABLED()) {
+        LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
+             this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
+             (aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
+                 (aItalicStyle & NS_FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
+             aWeight, aStretch));
+    }
+#endif
+
+    return proxyEntry;
+}
+
+void
+gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
+                            gfxFontEntry     *aFontEntry)
+{
+    gfxMixedFontFamily* family = GetFamily(aFamilyName);
+    family->AddFontEntry(aFontEntry);
+}
+
+gfxFontEntry*
+gfxUserFontSet::FindFontEntry(gfxFontFamily *aFamily,
+                              const gfxFontStyle& aFontStyle,
+                              bool& aNeedsBold,
+                              bool& aWaitForUserFont)
+{
+    aWaitForUserFont = false;
+    gfxMixedFontFamily *family = static_cast<gfxMixedFontFamily*>(aFamily);
+
+    gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
+
+    // if not a proxy, font has already been loaded
+    if (!fe->mIsProxy) {
+        return fe;
+    }
+
+    gfxProxyFontEntry *proxyEntry = static_cast<gfxProxyFontEntry*> (fe);
+
+    // if currently loading, return null for now
+    if (proxyEntry->mLoadingState > gfxProxyFontEntry::NOT_LOADING) {
+        aWaitForUserFont =
+            (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
+        return nullptr;
+    }
+
+    // hasn't been loaded yet, start the load process
+    gfxProxyFontEntry::LoadStatus status;
+
+    // NOTE that if all sources in the entry fail, this will delete proxyEntry,
+    // so we cannot use it again if status==STATUS_END_OF_LIST
+    status = proxyEntry->LoadNext(family, mLocalRulesUsed);
+
+    // if the load succeeded immediately, the font entry was replaced so
+    // search again
+    if (status == gfxProxyFontEntry::STATUS_LOADED) {
+        return family->FindFontForStyle(aFontStyle, aNeedsBold);
+    }
+
+    // check whether we should wait for load to complete before painting
+    // a fallback font -- but not if all sources failed (bug 633500)
+    aWaitForUserFont = (status != gfxProxyFontEntry::STATUS_END_OF_LIST) &&
+        (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
+
+    // if either loading or an error occurred, return null
+    return nullptr;
+}
+
 // This is called when a font download finishes.
 // Ownership of aFontData passes in here, and the font set must
 // ensure that it is eventually deleted via NS_Free().
 bool
 gfxUserFontSet::OnLoadComplete(gfxMixedFontFamily *aFamily,
                                gfxProxyFontEntry *aProxy,
                                const uint8_t *aFontData, uint32_t aLength,
                                nsresult aDownloadStatus)
 {
     // forget about the loader, as we no longer potentially need to cancel it
     // if the entry is obsoleted
     aProxy->mLoader = nullptr;
 
     // download successful, make platform font using font data
     if (NS_SUCCEEDED(aDownloadStatus)) {
-        gfxFontEntry *fe = LoadFont(aFamily, aProxy, aFontData, aLength);
+        gfxFontEntry *fe = aProxy->LoadFont(aFamily, aFontData, aLength);
         aFontData = nullptr;
 
         if (fe) {
             IncrementGeneration();
             return true;
         }
 
     } else {
@@ -501,173 +735,26 @@ gfxUserFontSet::OnLoadComplete(gfxMixedF
                    aDownloadStatus);
     }
 
     if (aFontData) {
         NS_Free((void*)aFontData);
     }
 
     // error occurred, load next src
-    (void)LoadNext(aFamily, aProxy);
+    (void)aProxy->LoadNext(aFamily, mLocalRulesUsed);
 
     // We ignore the status returned by LoadNext();
     // even if loading failed, we need to bump the font-set generation
     // and return true in order to trigger reflow, so that fallback
     // will be used where the text was "masked" by the pending download
     IncrementGeneration();
     return true;
 }
 
-
-gfxUserFontSet::LoadStatus
-gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
-                         gfxProxyFontEntry *aProxyEntry)
-{
-    uint32_t numSrc = aProxyEntry->mSrcList.Length();
-
-    NS_ASSERTION(aProxyEntry->mSrcIndex < numSrc,
-                 "already at the end of the src list for user font");
-
-    if (aProxyEntry->mLoadingState == gfxProxyFontEntry::NOT_LOADING) {
-        aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_STARTED;
-        aProxyEntry->mUnsupportedFormat = false;
-    } else {
-        // we were already loading; move to the next source,
-        // but don't reset state - if we've already timed out,
-        // that counts against the new download
-        aProxyEntry->mSrcIndex++;
-    }
-
-    // load each src entry in turn, until a local face is found
-    // or a download begins successfully
-    while (aProxyEntry->mSrcIndex < numSrc) {
-        const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[aProxyEntry->mSrcIndex];
-
-        // src local ==> lookup and load immediately
-
-        if (currSrc.mIsLocal) {
-            gfxFontEntry *fe =
-                gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
-                                                            currSrc.mLocalName);
-            mLocalRulesUsed = true;
-            if (fe) {
-                LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
-                     this, aProxyEntry->mSrcIndex,
-                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
-                     NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
-                     uint32_t(mGeneration)));
-                fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
-                fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
-                // For src:local(), we don't care whether the request is from
-                // a private window as there's no issue of caching resources;
-                // local fonts are just available all the time.
-                StoreUserFontData(fe, aProxyEntry, false, nsString(), nullptr, 0);
-                ReplaceFontEntry(aFamily, aProxyEntry, fe);
-                return STATUS_LOADED;
-            } else {
-                LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
-                     this, aProxyEntry->mSrcIndex,
-                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
-                     NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
-            }
-        }
-
-        // src url ==> start the load process
-        else {
-            if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
-                    currSrc.mFormatFlags)) {
-
-                nsIPrincipal *principal = nullptr;
-                bool bypassCache;
-                nsresult rv = CheckFontLoad(&currSrc, &principal, &bypassCache);
-
-                if (NS_SUCCEEDED(rv) && principal != nullptr) {
-                    if (!bypassCache) {
-                        // see if we have an existing entry for this source
-                        gfxFontEntry *fe =
-                            UserFontCache::GetFont(currSrc.mURI, principal,
-                                                   aProxyEntry,
-                                                   GetPrivateBrowsing());
-                        if (fe) {
-                            ReplaceFontEntry(aFamily, aProxyEntry, fe);
-                            return STATUS_LOADED;
-                        }
-                    }
-
-                    // record the principal returned by CheckFontLoad,
-                    // for use when creating a channel
-                    // and when caching the loaded entry
-                    aProxyEntry->mPrincipal = principal;
-
-                    bool loadDoesntSpin = false;
-                    rv = NS_URIChainHasFlags(currSrc.mURI,
-                           nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
-                           &loadDoesntSpin);
-                    if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
-                        uint8_t *buffer = nullptr;
-                        uint32_t bufferLength = 0;
-
-                        // sync load font immediately
-                        rv = SyncLoadFontData(aProxyEntry, &currSrc,
-                                              buffer, bufferLength);
-                        if (NS_SUCCEEDED(rv) && LoadFont(aFamily, aProxyEntry,
-                                                         buffer, bufferLength)) {
-                            return STATUS_LOADED;
-                        } else {
-                            LogMessage(aFamily, aProxyEntry,
-                                       "font load failed",
-                                       nsIScriptError::errorFlag, rv);
-                        }
-                    } else {
-                        // otherwise load font async
-                        rv = StartLoad(aFamily, aProxyEntry, &currSrc);
-                        if (NS_SUCCEEDED(rv)) {
-#ifdef PR_LOGGING
-                            if (LOG_ENABLED()) {
-                                nsAutoCString fontURI;
-                                currSrc.mURI->GetSpec(fontURI);
-                                LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
-                                     this, aProxyEntry->mSrcIndex, fontURI.get(),
-                                     NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
-                            }
-#endif
-                            return STATUS_LOADING;
-                        } else {
-                            LogMessage(aFamily, aProxyEntry,
-                                       "download failed",
-                                       nsIScriptError::errorFlag, rv);
-                        }
-                    }
-                } else {
-                    LogMessage(aFamily, aProxyEntry, "download not allowed",
-                               nsIScriptError::errorFlag, rv);
-                }
-            } else {
-                // We don't log a warning to the web console yet,
-                // as another source may load successfully
-                aProxyEntry->mUnsupportedFormat = true;
-            }
-        }
-
-        aProxyEntry->mSrcIndex++;
-    }
-
-    if (aProxyEntry->mUnsupportedFormat) {
-        LogMessage(aFamily, aProxyEntry, "no supported format found",
-                   nsIScriptError::warningFlag);
-    }
-
-    // all src's failed; mark this entry as unusable (so fallback will occur)
-    LOG(("userfonts (%p) failed all src for (%s)\n",
-        this, NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
-    aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_FAILED;
-
-    return STATUS_END_OF_LIST;
-}
-
 void
 gfxUserFontSet::IncrementGeneration()
 {
     // add one, increment again if zero
     ++sFontSetGeneration;
     if (sFontSetGeneration == 0)
        ++sFontSetGeneration;
     mGeneration = sFontSetGeneration;
@@ -676,117 +763,39 @@ gfxUserFontSet::IncrementGeneration()
 void
 gfxUserFontSet::RebuildLocalRules()
 {
     if (mLocalRulesUsed) {
         DoRebuildUserFontSet();
     }
 }
 
-gfxFontEntry*
-gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
-                         gfxProxyFontEntry *aProxy,
-                         const uint8_t *aFontData, uint32_t &aLength)
-{
-    gfxFontEntry *fe = nullptr;
-
-    gfxUserFontType fontType =
-        gfxFontUtils::DetermineFontDataType(aFontData, aLength);
-
-    // Unwrap/decompress/sanitize or otherwise munge the downloaded data
-    // to make a usable sfnt structure.
-
-    // Because platform font activation code may replace the name table
-    // in the font with a synthetic one, we save the original name so that
-    // it can be reported via the nsIDOMFontFace API.
-    nsAutoString originalFullName;
-
-    // Call the OTS sanitizer; this will also decode WOFF to sfnt
-    // if necessary. The original data in aFontData is left unchanged.
-    uint32_t saneLen;
-    const uint8_t* saneData =
-        SanitizeOpenTypeData(aFamily, aProxy, aFontData, aLength, saneLen,
-                             fontType == GFX_USERFONT_WOFF);
-    if (!saneData) {
-        LogMessage(aFamily, aProxy, "rejected by sanitizer");
-    }
-    if (saneData) {
-        // The sanitizer ensures that we have a valid sfnt and a usable
-        // name table, so this should never fail unless we're out of
-        // memory, and GetFullNameFromSFNT is not directly exposed to
-        // arbitrary/malicious data from the web.
-        gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
-                                          originalFullName);
-        // Here ownership of saneData is passed to the platform,
-        // which will delete it when no longer required
-        fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
-                                                          saneData,
-                                                          saneLen);
-        if (!fe) {
-            LogMessage(aFamily, aProxy, "not usable by platform");
-        }
-    }
-
-    if (fe) {
-        // Save a copy of the metadata block (if present) for nsIDOMFontFace
-        // to use if required. Ownership of the metadata block will be passed
-        // to the gfxUserFontData record below.
-        FallibleTArray<uint8_t> metadata;
-        uint32_t metaOrigLen = 0;
-        if (fontType == GFX_USERFONT_WOFF) {
-            CopyWOFFMetadata(aFontData, aLength, &metadata, &metaOrigLen);
-        }
-
-        // copy OpenType feature/language settings from the proxy to the
-        // newly-created font entry
-        fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
-        fe->mLanguageOverride = aProxy->mLanguageOverride;
-        StoreUserFontData(fe, aProxy, GetPrivateBrowsing(),
-                          originalFullName, &metadata, metaOrigLen);
-#ifdef PR_LOGGING
-        if (LOG_ENABLED()) {
-            nsAutoCString fontURI;
-            aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
-            LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
-                 this, aProxy->mSrcIndex, fontURI.get(),
-                 NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
-                 uint32_t(mGeneration)));
-        }
-#endif
-        ReplaceFontEntry(aFamily, aProxy, fe);
-        UserFontCache::CacheFont(fe);
-    } else {
-#ifdef PR_LOGGING
-        if (LOG_ENABLED()) {
-            nsAutoCString fontURI;
-            aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
-            LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
-                 " error making platform font\n",
-                 this, aProxy->mSrcIndex, fontURI.get(),
-                 NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
-        }
-#endif
-    }
-
-    // The downloaded data can now be discarded; the font entry is using the
-    // sanitized copy
-    NS_Free((void*)aFontData);
-
-    return fe;
-}
-
-gfxFontFamily*
-gfxUserFontSet::GetFamily(const nsAString& aFamilyName) const
+gfxMixedFontFamily*
+gfxUserFontSet::LookupFamily(const nsAString& aFamilyName) const
 {
     nsAutoString key(aFamilyName);
     ToLowerCase(key);
 
     return mFontFamilies.GetWeak(key);
 }
 
+gfxMixedFontFamily*
+gfxUserFontSet::GetFamily(const nsAString& aFamilyName)
+{
+    nsAutoString key(aFamilyName);
+    ToLowerCase(key);
+
+    gfxMixedFontFamily* family = mFontFamilies.GetWeak(key);
+    if (!family) {
+        family = new gfxMixedFontFamily(aFamilyName);
+        mFontFamilies.Put(key, family);
+    }
+    return family;
+}
+
 struct FindFamilyCallbackData {
     gfxFontEntry  *mFontEntry;
     gfxFontFamily *mFamily;
 };
 
 static PLDHashOperator
 FindFamilyCallback(const nsAString&    aName,
                    gfxMixedFontFamily* aFamily,
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -98,48 +98,57 @@ public:
         mAvailableFonts.AppendElement(aFontEntry);
         uint32_t i = mAvailableFonts.Length() - 1;
         while (i > 0) {
             if (mAvailableFonts[--i] == aFontEntry) {
                 mAvailableFonts.RemoveElementAt(i);
                 break;
             }
         }
-        aFontEntry->mFamilyName = Name();
+        if (aFontEntry->mFamilyName.IsEmpty()) {
+            aFontEntry->mFamilyName = Name();
+        } else {
+            MOZ_ASSERT(aFontEntry->mFamilyName.Equals(Name()));
+        }
         ResetCharacterMap();
     }
 
     // Replace aProxyFontEntry in the family's list with aRealFontEntry.
     void ReplaceFontEntry(gfxFontEntry *aProxyFontEntry,
                           gfxFontEntry *aRealFontEntry) {
         uint32_t numFonts = mAvailableFonts.Length();
         uint32_t i;
         for (i = 0; i < numFonts; i++) {
             gfxFontEntry *fe = mAvailableFonts[i];
             if (fe == aProxyFontEntry) {
                 // Note that this may delete aProxyFontEntry, if there's no
                 // other reference to it except from its family.
                 mAvailableFonts[i] = aRealFontEntry;
-                aRealFontEntry->mFamilyName = Name();
+                if (aRealFontEntry->mFamilyName.IsEmpty()) {
+                    aRealFontEntry->mFamilyName = Name();
+                } else {
+                    MOZ_ASSERT(aRealFontEntry->mFamilyName.Equals(Name()));
+                }
                 break;
             }
         }
         NS_ASSERTION(i < numFonts, "font entry not found in family!");
         ResetCharacterMap();
     }
 
     // Remove all font entries from the family
     void DetachFontEntries() {
         mAvailableFonts.Clear();
     }
 };
 
 class gfxProxyFontEntry;
 
 class gfxUserFontSet {
+    friend class gfxProxyFontEntry;
 
 public:
 
     NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet)
 
     gfxUserFontSet();
 
     enum {
@@ -152,24 +161,16 @@ public:
         FLAG_FORMAT_EOT            = 1 << 4,
         FLAG_FORMAT_SVG            = 1 << 5,
         FLAG_FORMAT_WOFF           = 1 << 6,
 
         // mask of all unused bits, update when adding new formats
         FLAG_FORMAT_NOT_USED       = ~((1 << 7)-1)
     };
 
-    enum LoadStatus {
-        STATUS_LOADING = 0,
-        STATUS_LOADED,
-        STATUS_FORMAT_NOT_SUPPORTED,
-        STATUS_ERROR,
-        STATUS_END_OF_LIST
-    };
-
 
     // add in a font face
     // weight - [100, 900] (multiples of 100)
     // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
     // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
     // language override = result of calling gfxFontStyle::ParseFontLanguageOverride
     // TODO: support for unicode ranges not yet implemented
     gfxFontEntry *AddFontFace(const nsAString& aFamilyName,
@@ -182,23 +183,25 @@ public:
                               gfxSparseBitSet *aUnicodeRanges = nullptr);
 
     // add in a font face for which we have the gfxFontEntry already
     void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry);
 
     // Whether there is a face with this family name
     bool HasFamily(const nsAString& aFamilyName) const
     {
-        return GetFamily(aFamilyName) != nullptr;
+        return LookupFamily(aFamilyName) != nullptr;
     }
 
-    gfxFontFamily *GetFamily(const nsAString& aName) const;
+    // Look up and return the gfxMixedFontFamily in mFontFamilies with
+    // the given name
+    gfxMixedFontFamily* LookupFamily(const nsAString& aName) const;
 
     // Lookup a font entry for a given style, returns null if not loaded.
-    // aFamily must be a family returned by our GetFamily method.
+    // aFamily must be a family returned by our LookupFamily method.
     gfxFontEntry *FindFontEntry(gfxFontFamily *aFamily,
                                 const gfxFontStyle& aFontStyle,
                                 bool& aNeedsBold,
                                 bool& aWaitForUserFont);
 
     // Find a family (possibly one of several!) that owns the given entry.
     // This may be somewhat expensive, as it enumerates all the fonts in
     // the set. Currently used only by the Linux (gfxPangoFontGroup) backend,
@@ -408,78 +411,65 @@ public:
 
 protected:
     // Protected destructor, to discourage deletion outside of Release():
     virtual ~gfxUserFontSet();
 
     // Return whether the font set is associated with a private-browsing tab.
     virtual bool GetPrivateBrowsing() = 0;
 
-    // for a given proxy font entry, attempt to load the next resource
-    // in the src list
-    LoadStatus LoadNext(gfxMixedFontFamily *aFamily,
-                        gfxProxyFontEntry *aProxyEntry);
-
-    // helper method for creating a platform font
-    // returns font entry if platform font creation successful
-    // Ownership of aFontData is passed in here; the font set must
-    // ensure that it is eventually deleted with NS_Free().
-    gfxFontEntry* LoadFont(gfxMixedFontFamily *aFamily,
-                           gfxProxyFontEntry *aProxy,
-                           const uint8_t *aFontData, uint32_t &aLength);
-
     // parse data for a data URL
     virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad,
                                       const gfxFontFaceSrc *aFontFaceSrc,
                                       uint8_t* &aBuffer,
                                       uint32_t &aBufferLength) = 0;
 
     // report a problem of some kind (implemented in nsUserFontSet)
     virtual nsresult LogMessage(gfxMixedFontFamily *aFamily,
                                 gfxProxyFontEntry *aProxy,
                                 const char *aMessage,
                                 uint32_t aFlags = nsIScriptError::errorFlag,
                                 nsresult aStatus = NS_OK) = 0;
 
-    const uint8_t* SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
-                                        gfxProxyFontEntry *aProxy,
-                                        const uint8_t* aData,
-                                        uint32_t aLength,
-                                        uint32_t& aSaneLength,
-                                        bool aIsCompressed);
-
-    static bool OTSMessage(void *aUserData, const char *format, ...);
-
     // helper method for performing the actual userfont set rebuild
     virtual void DoRebuildUserFontSet() = 0;
 
+    // creates a new gfxMixedFontFamily in mFontFamilies, or returns an existing
+    // family if there is one
+    gfxMixedFontFamily* GetFamily(const nsAString& aFamilyName);
+
     // font families defined by @font-face rules
     nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;
 
     uint64_t        mGeneration;
 
     // true when local names have been looked up, false otherwise
     bool mLocalRulesUsed;
 
     static PRLogModuleInfo* GetUserFontsLog();
-
-private:
-    static void CopyWOFFMetadata(const uint8_t* aFontData,
-                                 uint32_t aLength,
-                                 FallibleTArray<uint8_t>* aMetadata,
-                                 uint32_t* aMetaOrigLen);
 };
 
 // acts a placeholder until the real font is downloaded
 
 class gfxProxyFontEntry : public gfxFontEntry {
     friend class gfxUserFontSet;
+    friend class nsUserFontSet;
+    friend class nsFontFaceLoader;
 
 public:
-    gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+    enum LoadStatus {
+        STATUS_LOADING = 0,
+        STATUS_LOADED,
+        STATUS_FORMAT_NOT_SUPPORTED,
+        STATUS_ERROR,
+        STATUS_END_OF_LIST
+    };
+
+    gfxProxyFontEntry(gfxUserFontSet *aFontSet,
+                      const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                       uint32_t aWeight,
                       int32_t aStretch,
                       uint32_t aItalicStyle,
                       const nsTArray<gfxFontFeature>& aFeatureSettings,
                       uint32_t aLanguageOverride,
                       gfxSparseBitSet *aUnicodeRanges);
 
     virtual ~gfxProxyFontEntry();
@@ -490,29 +480,59 @@ public:
                  int32_t aStretch,
                  uint32_t aItalicStyle,
                  const nsTArray<gfxFontFeature>& aFeatureSettings,
                  uint32_t aLanguageOverride,
                  gfxSparseBitSet *aUnicodeRanges);
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
 
+protected:
+    const uint8_t* SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
+                                        const uint8_t* aData,
+                                        uint32_t aLength,
+                                        uint32_t& aSaneLength,
+                                        bool aIsCompressed);
+
+    // Attempt to load the next resource in the src list.
+    // aLocalRules is set to true if an attempt was made to load a
+    // local() font was loaded, and left as it is otherwise.
+    LoadStatus LoadNext(gfxMixedFontFamily *aFamily,
+                        bool& aLocalRulesUsed);
+
+    // helper method for creating a platform font
+    // returns font entry if platform font creation successful
+    // Ownership of aFontData is passed in here; the font must
+    // ensure that it is eventually deleted with NS_Free().
+    gfxFontEntry* LoadFont(gfxMixedFontFamily *aFamily,
+                           const uint8_t *aFontData, uint32_t &aLength);
+
+    // store metadata and src details for current src into aFontEntry
+    void StoreUserFontData(gfxFontEntry*      aFontEntry,
+                           bool               aPrivate,
+                           const nsAString&   aOriginalName,
+                           FallibleTArray<uint8_t>* aMetadata,
+                           uint32_t           aMetaOrigLen);
+
+    static bool OTSMessage(void *aUserData, const char *format, ...);
+
     // note that code depends on the ordering of these values!
     enum LoadingState {
         NOT_LOADING = 0,     // not started to load any font resources yet
         LOADING_STARTED,     // loading has started; hide fallback font
         LOADING_ALMOST_DONE, // timeout happened but we're nearly done,
                              // so keep hiding fallback font
         LOADING_SLOWLY,      // timeout happened and we're not nearly done,
                              // so use the fallback font
         LOADING_FAILED       // failed to load any source: use fallback
     };
     LoadingState             mLoadingState;
     bool                     mUnsupportedFormat;
 
     nsTArray<gfxFontFaceSrc> mSrcList;
     uint32_t                 mSrcIndex; // index of loading src item
     nsFontFaceLoader        *mLoader; // current loader for this entry, if any
+    gfxUserFontSet          *mFontSet; // font-set to which the proxy belongs
     nsCOMPtr<nsIPrincipal>   mPrincipal;
 };
 
 
 #endif /* GFX_USER_FONT_SET_H */
--- a/image/decoders/icon/mac/nsIconChannel.h
+++ b/image/decoders/icon/mac/nsIconChannel.h
@@ -8,16 +8,17 @@
 #define nsIconChannel_h___
 
 #include "mozilla/Attributes.h"
 
 #include "nsCOMPtr.h"
 #include "nsXPIDLString.h"
 #include "nsIChannel.h"
 #include "nsILoadGroup.h"
+#include "nsILoadInfo.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIInputStreamPump.h"
 #include "nsIStreamListener.h"
 #include "nsIURI.h"
 
 class nsIFile;
 
@@ -37,17 +38,18 @@ public:
 protected:
   virtual ~nsIconChannel();
 
   nsCOMPtr<nsIURI> mUrl;
   nsCOMPtr<nsIURI> mOriginalURI;
   int64_t          mContentLength;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
-  nsCOMPtr<nsISupports>  mOwner; 
+  nsCOMPtr<nsISupports>  mOwner;
+  nsCOMPtr<nsILoadInfo>  mLoadInfo;
   
   nsCOMPtr<nsIInputStreamPump> mPump;
   nsCOMPtr<nsIStreamListener>  mListener;
   
   nsresult MakeInputStream(nsIInputStream** _retval, bool nonBlocking);
   
   nsresult ExtractIconInfoFromUrl(nsIFile ** aLocalFile, uint32_t * aDesiredImageSize,
                            nsACString &aContentType, nsACString &aFileExtension);
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -432,16 +432,28 @@ NS_IMETHODIMP nsIconChannel::GetOwner(ns
 }
 
 NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner)
 {
   mOwner = aOwner;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsIconChannel::GetLoadInfo(nsILoadInfo* *aLoadInfo)
+{
+  NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsIconChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
+{
+  mLoadInfo = aLoadInfo;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
 {
   *aNotificationCallbacks = mCallbacks.get();
   NS_IF_ADDREF(*aNotificationCallbacks);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -659,16 +659,28 @@ NS_IMETHODIMP nsIconChannel::GetOwner(ns
 }
 
 NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner)
 {
   mOwner = aOwner;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsIconChannel::GetLoadInfo(nsILoadInfo* *aLoadInfo)
+{
+  NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsIconChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
+{
+  mLoadInfo = aLoadInfo;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
 {
   *aNotificationCallbacks = mCallbacks.get();
   NS_IF_ADDREF(*aNotificationCallbacks);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
--- a/image/decoders/icon/win/nsIconChannel.h
+++ b/image/decoders/icon/win/nsIconChannel.h
@@ -8,16 +8,17 @@
 #define nsIconChannel_h___
 
 #include "mozilla/Attributes.h"
 
 #include "nsCOMPtr.h"
 #include "nsXPIDLString.h"
 #include "nsIChannel.h"
 #include "nsILoadGroup.h"
+#include "nsILoadInfo.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIURI.h"
 #include "nsIInputStreamPump.h"
 #include "nsIStreamListener.h"
 #include "nsIIconURI.h"
 
 #include <windows.h>
@@ -40,16 +41,17 @@ public:
 
 protected:
   nsCOMPtr<nsIURI> mUrl;
   nsCOMPtr<nsIURI> mOriginalURI;
   int64_t          mContentLength;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   nsCOMPtr<nsISupports>  mOwner; 
+  nsCOMPtr<nsILoadInfo>  mLoadInfo;
 
   nsCOMPtr<nsIInputStreamPump> mPump;
   nsCOMPtr<nsIStreamListener>  mListener;
 
   nsresult ExtractIconInfoFromUrl(nsIFile ** aLocalFile, uint32_t * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension);
   nsresult GetHIconFromFile(HICON *hIcon);
   nsresult MakeInputStream(nsIInputStream** _retval, bool nonBlocking);
 
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -632,17 +632,18 @@ static nsresult NewImageChannel(nsIChann
 
     if (aLoadFlags & nsIRequest::LOAD_BACKGROUND)
       ++priority; // further reduce priority for background loads
 
     p->AdjustPriority(priority);
   }
 
   bool setOwner = nsContentUtils::SetUpChannelOwner(aLoadingPrincipal,
-                                                      *aResult, aURI, false);
+                                                    *aResult, aURI, false,
+                                                    false, false);
   *aForcePrincipalCheckForCacheEntry = setOwner;
 
   // Create a new loadgroup for this new channel, using the old group as
   // the parent. The indirection keeps the channel insulated from cancels,
   // but does allow a way for this revalidation to be associated with at
   // least one base load group for scheduling/caching purposes.
 
   nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
--- a/image/test/reftest/bmp/bmp-4bpp/reftest.list
+++ b/image/test/reftest/bmp/bmp-4bpp/reftest.list
@@ -14,8 +14,11 @@
 == bmp-size-16x16-4bpp.bmp bmp-size-16x16-4bpp.png
 == bmp-size-17x17-4bpp.bmp bmp-size-17x17-4bpp.png
 == bmp-size-31x31-4bpp.bmp bmp-size-31x31-4bpp.png
 == bmp-size-32x32-4bpp.bmp bmp-size-32x32-4bpp.png
 == bmp-size-33x33-4bpp.bmp bmp-size-33x33-4bpp.png
 == bmp-not-square-4bpp.bmp bmp-not-square-4bpp.png
 == os2bmp-size-32x32-4bpp.bmp bmp-size-32x32-4bpp.png
 == top-to-bottom-16x16-4bpp.bmp  bmp-size-16x16-4bpp.png
+# test that delta skips are drawn as transparent
+# taken from http://bmptestsuite.sourceforge.net/
+== rle4-delta-320x240.bmp rle4-delta-320x240.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..78a09278704143f846a944af2d59fe8f6d75fcf5
GIT binary patch
literal 3686
zc%1E*F%H5o3`M`=(82&BS72gfWJHLSF;_sS2jG-B2xD&$oTL#Tp;9D9w|#P6^kZ4s
zdOTlN$j?pK3I_susRRonwO;~vF04xwQQo>5KExOiLYRa!rh>tB1Jj{9NeeYKH8nLg
zH8nLgHMJjX?{=f!IPx>co~16F^(I4pE;JvqR!CWs^XY8i|9R`5vvFR3>(4L!r_MCx
Y47*mcX^uKmy{A_8#_#vthrc{}0P4ZRqyPW_
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f9a3ceae232b8b43c5c08348bde8fb3e0bdabe36
GIT binary patch
literal 886
zc%17D@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*+7ad$=lt9;Xep2*t>i(P=vF<
zBeIx*f%ydpGj6R80x4rJ@$_|NzsJrlVlAEaUQQ1v$L#6i7*cWT?d^+wO$GuE7yCZ`
zuit4mamFPs-_C_!<}8n$qB`sDYo9}IewK`DUOd%h2>W_(Ux!G)9P9J?Ld!q9?!~KU
zUsbW?5LQTFx^vZVyZsTRr0;XyM!dcA{`jfvD{|R$>%aY&naym%9Kp7h$Fp+HpMNj@
z95!9_@z1S~7qb~(Z(?FrJD|Pw+T(klvnMaVDz>AP!JYZ)W+vu{M#g`JjBZCh%=(=j
zy6;gsv&^=f-{BVKPWS(b{!p3mkpEQgh0R|M^j>HX{h=r<<RCAspwPg;#6dAZxd{-0
wO2#w{N7n#}0d~!ot~r~^84Vbj);wWeVCBhR{9(~7U=CsMboFyt=akR{0N!cTXaE2J
--- a/intl/unicharutil/util/Makefile.in
+++ b/intl/unicharutil/util/Makefile.in
@@ -10,14 +10,8 @@
 DIST_INSTALL = 1
 SDK_LIBRARY = $(LIBRARY)
 
 include $(topsrcdir)/config/rules.mk
 
 ifdef ENABLE_INTL_API
 LOCAL_INCLUDES += $(MOZ_ICU_CFLAGS)
 endif
-
-ifdef _MSC_VER
-# Don't include directives about which CRT to use
-OS_COMPILE_CXXFLAGS += -Zl
-OS_COMPILE_CFLAGS += -Zl
-endif
--- a/intl/unicharutil/util/moz.build
+++ b/intl/unicharutil/util/moz.build
@@ -28,8 +28,11 @@ FORCE_STATIC_LIB = True
 LOCAL_INCLUDES += [
     '../src',
 ]
 
 USE_STATIC_LIBS = True
 
 if CONFIG['_MSC_VER']:
     DEFINES['_USE_ANSI_CPP'] = True
+    # Don't include directives about which CRT to use
+    CFLAGS += ['-Zl']
+    CXXFLAGS += ['-Zl']
--- a/ipc/glue/BackgroundChild.h
+++ b/ipc/glue/BackgroundChild.h
@@ -32,16 +32,21 @@ class PBackgroundChild;
 //
 // Creation of PBackground is asynchronous. GetForCurrentThread() will return
 // null until the sequence is complete. GetOrCreateForCurrentThread() will start
 // the creation sequence and will call back via the
 // nsIIPCBackgroundChildCreateCallback interface when completed. Thereafter
 // (assuming success) GetForCurrentThread() will return the same actor every
 // time.
 //
+// CloseForCurrentThread() will close the current PBackground actor.  Subsequent
+// calls to GetForCurrentThread will return null.  CloseForCurrentThread() may
+// only be called exactly once for each thread-specific actor.  Currently it is
+// illegal to call this before the PBackground actor has been created.
+//
 // The PBackgroundChild actor and all its sub-protocol actors will be
 // automatically destroyed when its designated thread completes.
 class BackgroundChild MOZ_FINAL
 {
   friend class mozilla::dom::ContentChild;
   friend class mozilla::dom::ContentParent;
 
   typedef base::ProcessId ProcessId;
@@ -51,16 +56,20 @@ public:
   // See above.
   static PBackgroundChild*
   GetForCurrentThread();
 
   // See above.
   static bool
   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
 
+  // See above.
+  static void
+  CloseForCurrentThread();
+
 private:
   // Only called by ContentChild or ContentParent.
   static void
   Startup();
 
   // Only called by ContentChild.
   static PBackgroundChild*
   Alloc(Transport* aTransport, ProcessId aOtherProcess);
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -345,16 +345,18 @@ class ChildImpl MOZ_FINAL : public Backg
   static bool sShutdownHasStarted;
 
 #ifdef RELEASE_BUILD
   DebugOnly<nsIThread*> mBoundThread;
 #else
   nsIThread* mBoundThread;
 #endif
 
+  DebugOnly<bool> mActorDestroyed;
+
 public:
   static bool
   OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
 
   static void
   Shutdown();
 
   void
@@ -367,18 +369,25 @@ public:
 #else
     bool current;
 #endif
     THREADSAFETY_ASSERT(
       NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
     THREADSAFETY_ASSERT(current);
   }
 
+  void
+  AssertActorDestroyed()
+  {
+    MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
+  }
+
   ChildImpl()
   : mBoundThread(nullptr)
+  , mActorDestroyed(false)
   {
     AssertIsOnMainThread();
   }
 
   NS_INLINE_DECL_REFCOUNTING(ChildImpl)
 
 private:
   // Forwarded from BackgroundChild.
@@ -392,39 +401,57 @@ private:
   // Forwarded from BackgroundChild.
   static PBackgroundChild*
   GetForCurrentThread();
 
   // Forwarded from BackgroundChild.
   static bool
   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
 
+  // Forwarded from BackgroundChild.
+  static void
+  CloseForCurrentThread();
+
   // Forwarded from BackgroundChildImpl.
   static BackgroundChildImpl::ThreadLocal*
   GetThreadLocalForCurrentThread();
 
   static void
   ThreadLocalDestructor(void* aThreadLocal)
   {
     auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
 
     if (threadLocalInfo) {
       if (threadLocalInfo->mActor) {
         threadLocalInfo->mActor->Close();
+        threadLocalInfo->mActor->AssertActorDestroyed();
+
+        // Since the actor is created on the main thread it must only
+        // be released on the main thread as well.
+        if (!NS_IsMainThread()) {
+          ChildImpl* actor;
+          threadLocalInfo->mActor.forget(&actor);
+
+          nsCOMPtr<nsIRunnable> releaser =
+            NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release);
+          MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser)));
+        }
       }
       delete threadLocalInfo;
     }
   }
 
   static void
   DispatchFailureCallback(nsIEventTarget* aEventTarget);
 
   // This class is reference counted.
   ~ChildImpl()
-  { }
+  {
+    AssertActorDestroyed();
+  }
 
   void
   SetBoundThread()
   {
     THREADSAFETY_ASSERT(!mBoundThread);
 
 #if defined(DEBUG) || !defined(RELEASE_BUILD)
     mBoundThread = NS_GetCurrentThread();
@@ -830,16 +857,23 @@ BackgroundChild::GetForCurrentThread()
 // static
 bool
 BackgroundChild::GetOrCreateForCurrentThread(
                                  nsIIPCBackgroundChildCreateCallback* aCallback)
 {
   return ChildImpl::GetOrCreateForCurrentThread(aCallback);
 }
 
+// static
+void
+BackgroundChild::CloseForCurrentThread()
+{
+  ChildImpl::CloseForCurrentThread();
+}
+
 // -----------------------------------------------------------------------------
 // BackgroundChildImpl Public Methods
 // -----------------------------------------------------------------------------
 
 // static
 BackgroundChildImpl::ThreadLocal*
 BackgroundChildImpl::GetThreadLocalForCurrentThread()
 {
@@ -1573,17 +1607,21 @@ ChildImpl::Alloc(Transport* aTransport, 
 PBackgroundChild*
 ChildImpl::GetForCurrentThread()
 {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
 
   auto threadLocalInfo =
     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
 
-  return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
+  if (!threadLocalInfo) {
+    return nullptr;
+  }
+
+  return threadLocalInfo->mActor;
 }
 
 // static
 bool
 ChildImpl::GetOrCreateForCurrentThread(
                                  nsIIPCBackgroundChildCreateCallback* aCallback)
 {
   MOZ_ASSERT(aCallback);
@@ -1638,16 +1676,43 @@ ChildImpl::GetOrCreateForCurrentThread(
     CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
     return false;
   }
 
   return true;
 }
 
 // static
+void
+ChildImpl::CloseForCurrentThread()
+{
+  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
+             "BackgroundChild::Startup() was never called!");
+  auto threadLocalInfo =
+    static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
+
+  // If we don't have a thread local we are in one of these conditions:
+  //   1) Startup has not completed and we are racing
+  //   2) We were called again after a previous close or shutdown
+  // For now, these should not happen, so crash.  We can add extra complexity
+  // in the future if it turns out we need to support these cases.
+  if (!threadLocalInfo) {
+    MOZ_CRASH("Attempting to close a non-existent PBackground actor!");
+  }
+
+  if (threadLocalInfo->mActor) {
+    threadLocalInfo->mActor->FlushPendingInterruptQueue();
+  }
+
+  // Clearing the thread local will synchronously close the actor.
+  DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
+  MOZ_ASSERT(status == PR_SUCCESS);
+}
+
+// static
 BackgroundChildImpl::ThreadLocal*
 ChildImpl::GetThreadLocalForCurrentThread()
 {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
              "BackgroundChild::Startup() was never called!");
 
   auto threadLocalInfo =
     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
@@ -1941,16 +2006,19 @@ ChildImpl::DispatchFailureCallback(nsIEv
   }
 }
 
 void
 ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsOnBoundThread();
 
+  MOZ_ASSERT(!mActorDestroyed);
+  mActorDestroyed = true;
+
   BackgroundChildImpl::ActorDestroy(aWhy);
 }
 
 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
 
 NS_IMETHODIMP
 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
                                      const char* aTopic,
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -1657,20 +1657,21 @@ MessageChannel::Close()
             if (mListener) {
                 MonitorAutoUnlock unlock(*mMonitor);
                 NotifyMaybeChannelError();
             }
             return;
         }
 
         if (ChannelOpening == mChannelState) {
-            // Mimic CloseWithError().
+            // SynchronouslyClose() waits for an ack from the other side, so
+            // the opening sequence should complete before this returns.
             SynchronouslyClose();
             mChannelState = ChannelError;
-            PostErrorNotifyTask();
+            NotifyMaybeChannelError();
             return;
         }
 
         if (ChannelConnected != mChannelState) {
             // XXX be strict about this until there's a compelling reason
             // to relax
             NS_RUNTIMEABORT("Close() called on closed channel!");
         }
--- a/ipc/glue/MessageLink.cpp
+++ b/ipc/glue/MessageLink.cpp
@@ -183,36 +183,41 @@ ProcessLink::SendClose()
 ThreadLink::ThreadLink(MessageChannel *aChan, MessageChannel *aTargetChan)
   : MessageLink(aChan),
     mTargetChan(aTargetChan)
 {
 }
 
 ThreadLink::~ThreadLink()
 {
-    // :TODO: MonitorAutoLock lock(*mChan->mMonitor);
+    MOZ_ASSERT(mChan);
+    MOZ_ASSERT(mChan->mMonitor);
+    MonitorAutoLock lock(*mChan->mMonitor);
+
     // Bug 848949: We need to prevent the other side
     // from sending us any more messages to avoid Use-After-Free.
     // The setup here is as shown:
     //
     //          (Us)         (Them)
     //       MessageChannel  MessageChannel
     //         |  ^     \ /     ^ |
     //         |  |      X      | |
     //         v  |     / \     | v
     //        ThreadLink   ThreadLink
     //
     // We want to null out the diagonal link from their ThreadLink
     // to our MessageChannel.  Note that we must hold the monitor so
     // that we do this atomically with respect to them trying to send
-    // us a message.
+    // us a message.  Since the channels share the same monitor this
+    // also protects against the two ~ThreadLink() calls racing.
     if (mTargetChan) {
-        static_cast<ThreadLink*>(mTargetChan->mLink)->mTargetChan = 0;
+        MOZ_ASSERT(mTargetChan->mLink);
+        static_cast<ThreadLink*>(mTargetChan->mLink)->mTargetChan = nullptr;
     }
-    mTargetChan = 0;
+    mTargetChan = nullptr;
 }
 
 void
 ThreadLink::EchoMessage(Message *msg)
 {
     mChan->AssertWorkerThread();
     mChan->mMonitor->AssertCurrentThreadOwns();
 
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MessagePump.h"
 
 #include "nsIRunnable.h"
 #include "nsIThread.h"
 #include "nsITimer.h"
+#include "nsICancelableRunnable.h"
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/scoped_nsautorelease_pool.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
@@ -35,35 +36,38 @@ using namespace mozilla::ipc;
 
 NS_DEFINE_NAMED_CID(NS_TIMER_CID);
 
 static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate;
 
 namespace mozilla {
 namespace ipc {
 
-class DoWorkRunnable MOZ_FINAL : public nsIRunnable,
+class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable,
                                  public nsITimerCallback
 {
 public:
   DoWorkRunnable(MessagePump* aPump)
   : mPump(aPump)
   {
     MOZ_ASSERT(aPump);
   }
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSITIMERCALLBACK
+  NS_DECL_NSICANCELABLERUNNABLE
 
 private:
   ~DoWorkRunnable()
   { }
 
   MessagePump* mPump;
+  // DoWorkRunnable is designed as a stateless singleton.  Do not add stateful
+  // members here!
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 MessagePump::MessagePump()
 : mThread(nullptr)
 {
@@ -206,17 +210,18 @@ void
 MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
 {
   aDelegate->DoDelayedWork(&delayed_work_time_);
   if (!delayed_work_time_.is_null()) {
     ScheduleDelayedWork(delayed_work_time_);
   }
 }
 
-NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback)
+NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback,
+                                  nsICancelableRunnable)
 
 NS_IMETHODIMP
 DoWorkRunnable::Run()
 {
   MessageLoop* loop = MessageLoop::current();
   MOZ_ASSERT(loop);
 
   bool nestableTasksAllowed = loop->NestableTasksAllowed();
@@ -237,16 +242,30 @@ DoWorkRunnable::Notify(nsITimer* aTimer)
   MessageLoop* loop = MessageLoop::current();
   MOZ_ASSERT(loop);
 
   mPump->DoDelayedWork(loop);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DoWorkRunnable::Cancel()
+{
+  // Workers require cancelable runnables, but we can't really cancel cleanly
+  // here.  If we don't process this runnable then we will leave something
+  // unprocessed in the message_loop.  Therefore, eagerly complete our work
+  // instead by immediately calling Run().  Run() should be called separately
+  // after this.  Unfortunately we cannot use flags to verify this because
+  // DoWorkRunnable is a stateless singleton that can be in the event queue
+  // multiple times simultaneously.
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(Run()));
+  return NS_OK;
+}
+
 void
 MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate)
 {
   if (mFirstRun) {
     MOZ_ASSERT(aDelegate && !gFirstDelegate);
     gFirstDelegate = aDelegate;
 
     mFirstRun = false;
--- a/ipc/nfc/Nfc.cpp
+++ b/ipc/nfc/Nfc.cpp
@@ -101,19 +101,19 @@ PostToNFC(JSContext* aCx,
     } else if (!v.isPrimitive()) {
         JSObject* obj = v.toObjectOrNull();
         if (!JS_IsTypedArrayObject(obj)) {
             JS_ReportError(aCx, "Object passed in wasn't a typed array");
             return false;
         }
 
         uint32_t type = JS_GetArrayBufferViewType(obj);
-        if (type != js::ArrayBufferView::TYPE_INT8 &&
-            type != js::ArrayBufferView::TYPE_UINT8 &&
-            type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
+        if (type != js::Scalar::Int8 &&
+            type != js::Scalar::Uint8 &&
+            type != js::Scalar::Uint8Clamped) {
             JS_ReportError(aCx, "Typed array data is not octets");
             return false;
         }
 
         size = JS_GetTypedArrayByteLength(obj);
         data = JS_GetArrayBufferViewData(obj);
     } else {
         JS_ReportError(aCx,
--- a/ipc/ril/Ril.cpp
+++ b/ipc/ril/Ril.cpp
@@ -106,19 +106,19 @@ PostToRIL(JSContext *aCx,
     } else if (!v.isPrimitive()) {
         JSObject *obj = v.toObjectOrNull();
         if (!JS_IsTypedArrayObject(obj)) {
             JS_ReportError(aCx, "Object passed in wasn't a typed array");
             return false;
         }
 
         uint32_t type = JS_GetArrayBufferViewType(obj);
-        if (type != js::ArrayBufferView::TYPE_INT8 &&
-            type != js::ArrayBufferView::TYPE_UINT8 &&
-            type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
+        if (type != js::Scalar::Int8 &&
+            type != js::Scalar::Uint8 &&
+            type != js::Scalar::Uint8Clamped) {
             JS_ReportError(aCx, "Typed array data is not octets");
             return false;
         }
 
         size = JS_GetTypedArrayByteLength(obj);
         data = JS_GetArrayBufferViewData(obj);
     } else {
         JS_ReportError(aCx,
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -227,22 +227,16 @@ DEFINES += -DUSE_ZLIB
 endif
 
 ifdef MOZ_SHARED_ICU
 EXTRA_DSO_LDOPTS += $(MOZ_ICU_LIBS)
 else
 SHARED_LIBRARY_LIBS += $(MOZ_ICU_LIBS)
 endif
 
-# Prevent floating point errors caused by VC++ optimizations
-ifdef _MSC_VER
-# XXX We should add this to CXXFLAGS, too?
-CFLAGS += -fp:precise
-endif # _MSC_VER
-
 ifeq ($(OS_ARCH),FreeBSD)
 EXTRA_LIBS	+= -pthread
 endif
 ifeq ($(OS_ARCH),Linux)
 EXTRA_LIBS	+= -ldl
 endif
 # Silence warnings on AIX/HP-UX from non-GNU compilers
 ifndef GNU_CC
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -247,42 +247,38 @@ const Class js::ScalarTypeDescr::class_ 
 
 const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
 
-static int32_t ScalarSizes[] = {
-#define SCALAR_SIZE(_kind, _type, _name)                        \
-    sizeof(_type),
-    JS_FOR_EACH_SCALAR_TYPE_REPR(SCALAR_SIZE) 0
-#undef SCALAR_SIZE
-};
-
 int32_t
 ScalarTypeDescr::size(Type t)
 {
-    return ScalarSizes[t];
+    return Scalar::byteSize(t);
 }
 
 int32_t
 ScalarTypeDescr::alignment(Type t)
 {
-    return ScalarSizes[t];
+    return Scalar::byteSize(t);
 }
 
 /*static*/ const char *
 ScalarTypeDescr::typeName(Type type)
 {
     switch (type) {
 #define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
         case constant_: return #name_;
         JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+#undef NUMERIC_TYPE_TO_STRING
+      case Scalar::TypeMax:
+        MOZ_CRASH();
     }
     MOZ_ASSUME_UNREACHABLE("Invalid type");
 }
 
 bool
 ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -294,30 +290,31 @@ ScalarTypeDescr::call(JSContext *cx, uns
 
     Rooted<ScalarTypeDescr *> descr(cx, &args.callee().as<ScalarTypeDescr>());
     ScalarTypeDescr::Type type = descr->type();
 
     double number;
     if (!ToNumber(cx, args[0], &number))
         return false;
 
-    if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED)
+    if (type == Scalar::Uint8Clamped)
         number = ClampDoubleToUint8(number);
 
     switch (type) {
 #define SCALARTYPE_CALL(constant_, type_, name_)                             \
       case constant_: {                                                       \
           type_ converted = ConvertScalar<type_>(number);                     \
           args.rval().setNumber((double) converted);                          \
           return true;                                                        \
       }
 
         JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL)
 #undef SCALARTYPE_CALL
-
+      case Scalar::TypeMax:
+        MOZ_CRASH();
     }
     return true;
 }
 
 /***************************************************************************
  * Reference type objects
  *
  * Reference type objects like `Any` or `Object` basically work the
@@ -372,16 +369,17 @@ ReferenceTypeDescr::alignment(Type t)
 
 /*static*/ const char *
 ReferenceTypeDescr::typeName(Type type)
 {
     switch (type) {
 #define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
         case constant_: return #name_;
         JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+#undef NUMERIC_TYPE_TO_STRING
     }
     MOZ_ASSUME_UNREACHABLE("Invalid type");
 }
 
 bool
 js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -234,68 +234,65 @@ class SimpleTypeDescr : public SizedType
 
 // Type for scalar type constructors like `uint8`. All such type
 // constructors share a common js::Class and JSFunctionSpec. Scalar
 // types are non-opaque (their storage is visible unless combined with
 // an opaque reference type.)
 class ScalarTypeDescr : public SimpleTypeDescr
 {
   public:
-    // Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
-    enum Type {
-        TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
-        TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
-        TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
-        TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
-        TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
-        TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
-        TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
-        TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
-
-        /*
-         * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
-         * Treat the raw data type as a uint8_t.
-         */
-        TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
-    };
-    static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
+    typedef Scalar::Type Type;
 
     static const type::Kind Kind = type::Scalar;
     static const bool Opaque = false;
     static int32_t size(Type t);
     static int32_t alignment(Type t);
     static const char *typeName(Type type);
 
     static const Class class_;
     static const JSFunctionSpec typeObjectMethods[];
 
-    ScalarTypeDescr::Type type() const {
-        return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
+    Type type() const {
+        // Make sure the values baked into TypedObjectConstants.h line up with
+        // the Scalar::Type enum. We don't define Scalar::Type directly in
+        // terms of these constants to avoid making TypedObjectConstants.h a
+        // public header file.
+        JS_STATIC_ASSERT(Scalar::Int8 == JS_SCALARTYPEREPR_INT8);
+        JS_STATIC_ASSERT(Scalar::Uint8 == JS_SCALARTYPEREPR_UINT8);
+        JS_STATIC_ASSERT(Scalar::Int16 == JS_SCALARTYPEREPR_INT16);
+        JS_STATIC_ASSERT(Scalar::Uint16 == JS_SCALARTYPEREPR_UINT16);
+        JS_STATIC_ASSERT(Scalar::Int32 == JS_SCALARTYPEREPR_INT32);
+        JS_STATIC_ASSERT(Scalar::Uint32 == JS_SCALARTYPEREPR_UINT32);
+        JS_STATIC_ASSERT(Scalar::Float32 == JS_SCALARTYPEREPR_FLOAT32);
+        JS_STATIC_ASSERT(Scalar::Float64 == JS_SCALARTYPEREPR_FLOAT64);
+        JS_STATIC_ASSERT(Scalar::Uint8Clamped == JS_SCALARTYPEREPR_UINT8_CLAMPED);
+
+        return (Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
     }
 
     static bool call(JSContext *cx, unsigned argc, Value *vp);
 };
 
 // Enumerates the cases of ScalarTypeDescr::Type which have
 // unique C representation. In particular, omits Uint8Clamped since it
 // is just a Uint8.
-#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                     \
-    macro_(ScalarTypeDescr::TYPE_INT8,    int8_t,   int8)            \
-    macro_(ScalarTypeDescr::TYPE_UINT8,   uint8_t,  uint8)           \
-    macro_(ScalarTypeDescr::TYPE_INT16,   int16_t,  int16)           \
-    macro_(ScalarTypeDescr::TYPE_UINT16,  uint16_t, uint16)          \
-    macro_(ScalarTypeDescr::TYPE_INT32,   int32_t,  int32)           \
-    macro_(ScalarTypeDescr::TYPE_UINT32,  uint32_t, uint32)          \
-    macro_(ScalarTypeDescr::TYPE_FLOAT32, float,    float32)         \
-    macro_(ScalarTypeDescr::TYPE_FLOAT64, double,   float64)
+#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)       \
+    macro_(Scalar::Int8,    int8_t,   int8)                     \
+    macro_(Scalar::Uint8,   uint8_t,  uint8)                    \
+    macro_(Scalar::Int16,   int16_t,  int16)                    \
+    macro_(Scalar::Uint16,  uint16_t, uint16)                   \
+    macro_(Scalar::Int32,   int32_t,  int32)                    \
+    macro_(Scalar::Uint32,  uint32_t, uint32)                   \
+    macro_(Scalar::Float32, float,    float32)                  \
+    macro_(Scalar::Float64, double,   float64)
 
 // Must be in same order as the enum ScalarTypeDescr::Type:
-#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
-    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
-    macro_(ScalarTypeDescr::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
+#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                    \
+    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)           \
+    macro_(Scalar::Uint8Clamped, uint8_t, uint8Clamped)
 
 // Type for reference type constructors like `Any`, `String`, and
 // `Object`. All such type constructors share a common js::Class and
 // JSFunctionSpec. All these types are opaque.
 class ReferenceTypeDescr : public SimpleTypeDescr
 {
   public:
     // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -55,19 +55,18 @@
 #define JS_TYPEREPR_MAX_UNSIZED_KIND    0    // Unsized kinds go above here
 #define JS_TYPEREPR_SCALAR_KIND         1
 #define JS_TYPEREPR_REFERENCE_KIND      2
 #define JS_TYPEREPR_STRUCT_KIND         3
 #define JS_TYPEREPR_SIZED_ARRAY_KIND    4
 #define JS_TYPEREPR_X4_KIND             5
 
 // These constants are for use exclusively in JS code. In C++ code,
-// prefer ScalarTypeRepresentation::TYPE_INT8 etc, which allows
-// you to write a switch which will receive a warning if you omit a
-// case.
+// prefer Scalar::Int8 etc, which allows you to write a switch which will
+// receive a warning if you omit a case.
 #define JS_SCALARTYPEREPR_INT8          0
 #define JS_SCALARTYPEREPR_UINT8         1
 #define JS_SCALARTYPEREPR_INT16         2
 #define JS_SCALARTYPEREPR_UINT16        3
 #define JS_SCALARTYPEREPR_INT32         4
 #define JS_SCALARTYPEREPR_UINT32        5
 #define JS_SCALARTYPEREPR_FLOAT32       6
 #define JS_SCALARTYPEREPR_FLOAT64       7
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2219,39 +2219,39 @@ ConvertToJS(JSContext* cx,
 // ctypes.int8_t, UInt8Array to ctypes.uint8_t, etc.
 bool CanConvertTypedArrayItemTo(JSObject *baseType, JSObject *valObj, JSContext *cx) {
   TypeCode baseTypeCode = CType::GetTypeCode(baseType);
   if (baseTypeCode == TYPE_void_t) {
     return true;
   }
   TypeCode elementTypeCode;
   switch (JS_GetArrayBufferViewType(valObj)) {
-  case ScalarTypeDescr::TYPE_INT8:
+  case Scalar::Int8:
     elementTypeCode = TYPE_int8_t;
     break;
-  case ScalarTypeDescr::TYPE_UINT8:
-  case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
+  case Scalar::Uint8:
+  case Scalar::Uint8Clamped:
     elementTypeCode = TYPE_uint8_t;
     break;
-  case ScalarTypeDescr::TYPE_INT16:
+  case Scalar::Int16:
     elementTypeCode = TYPE_int16_t;
     break;
-  case ScalarTypeDescr::TYPE_UINT16:
+  case Scalar::Uint16:
     elementTypeCode = TYPE_uint16_t;
     break;
-  case ScalarTypeDescr::TYPE_INT32:
+  case Scalar::Int32:
     elementTypeCode = TYPE_int32_t;
     break;
-  case ScalarTypeDescr::TYPE_UINT32:
+  case Scalar::Uint32:
     elementTypeCode = TYPE_uint32_t;
     break;
-  case ScalarTypeDescr::TYPE_FLOAT32:
+  case Scalar::Float32:
     elementTypeCode = TYPE_float32_t;
     break;
-  case ScalarTypeDescr::TYPE_FLOAT64:
+  case Scalar::Float64:
     elementTypeCode = TYPE_float64_t;
     break;
   default:
     return false;
   }
   return elementTypeCode == baseTypeCode;
 }
 
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -717,29 +717,29 @@ bool operator!=(const Signature &lhs, co
 {
     return !(lhs == rhs);
 }
 
 /*****************************************************************************/
 // Typed array utilities
 
 static Type
-TypedArrayLoadType(ArrayBufferView::ViewType viewType)
+TypedArrayLoadType(Scalar::Type viewType)
 {
     switch (viewType) {
-      case ArrayBufferView::TYPE_INT8:
-      case ArrayBufferView::TYPE_INT16:
-      case ArrayBufferView::TYPE_INT32:
-      case ArrayBufferView::TYPE_UINT8:
-      case ArrayBufferView::TYPE_UINT16:
-      case ArrayBufferView::TYPE_UINT32:
+      case Scalar::Int8:
+      case Scalar::Int16:
+      case Scalar::Int32:
+      case Scalar::Uint8:
+      case Scalar::Uint16:
+      case Scalar::Uint32:
         return Type::Intish;
-      case ArrayBufferView::TYPE_FLOAT32:
+      case Scalar::Float32:
         return Type::MaybeFloat;
-      case ArrayBufferView::TYPE_FLOAT64:
+      case Scalar::Float64:
         return Type::MaybeDouble;
       default:;
     }
     MOZ_ASSUME_UNREACHABLE("Unexpected array type");
 }
 
 enum NeedsBoundsCheck {
     NO_BOUNDS_CHECK,
@@ -873,17 +873,17 @@ class MOZ_STACK_CLASS ModuleCompiler
             struct {
                 VarType::Which type_;
                 uint32_t index_;
                 Value literalValue_;
             } varOrConst;
             uint32_t funcIndex_;
             uint32_t funcPtrTableIndex_;
             uint32_t ffiIndex_;
-            ArrayBufferView::ViewType viewType_;
+            Scalar::Type viewType_;
             AsmJSMathBuiltinFunction mathBuiltinFunc_;
         } u;
 
         friend class ModuleCompiler;
         friend class js::LifoAlloc;
 
         explicit Global(Which which) : which_(which) {}
 
@@ -913,17 +913,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         uint32_t funcPtrTableIndex() const {
             JS_ASSERT(which_ == FuncPtrTable);
             return u.funcPtrTableIndex_;
         }
         unsigned ffiIndex() const {
             JS_ASSERT(which_ == FFI);
             return u.ffiIndex_;
         }
-        ArrayBufferView::ViewType viewType() const {
+        Scalar::Type viewType() const {
             JS_ASSERT(which_ == ArrayView);
             return u.viewType_;
         }
         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
             JS_ASSERT(which_ == MathBuiltinFunction);
             return u.mathBuiltinFunc_;
         }
     };
@@ -1343,17 +1343,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         if (!global)
             return false;
         uint32_t index;
         if (!module_->addFFI(field, &index))
             return false;
         global->u.ffiIndex_ = index;
         return globals_.putNew(varName, global);
     }
-    bool addArrayView(PropertyName *varName, ArrayBufferView::ViewType vt, PropertyName *fieldName) {
+    bool addArrayView(PropertyName *varName, Scalar::Type vt, PropertyName *fieldName) {
         Global *global = moduleLifo_.new_<Global>(Global::ArrayView);
         if (!global)
             return false;
         if (!module_->addArrayView(vt, fieldName))
             return false;
         global->u.viewType_ = vt;
         return globals_.putNew(varName, global);
     }
@@ -2114,28 +2114,28 @@ class FunctionCompiler
 
     void assign(const Local &local, MDefinition *def)
     {
         if (inDeadCode())
             return;
         curBlock_->setSlot(info().localSlot(local.slot), def);
     }
 
-    MDefinition *loadHeap(ArrayBufferView::ViewType vt, MDefinition *ptr, NeedsBoundsCheck chk)
+    MDefinition *loadHeap(Scalar::Type vt, MDefinition *ptr, NeedsBoundsCheck chk)
     {
         if (inDeadCode())
             return nullptr;
         MAsmJSLoadHeap *load = MAsmJSLoadHeap::New(alloc(), vt, ptr);
         curBlock_->add(load);
         if (chk == NO_BOUNDS_CHECK)
             load->setSkipBoundsCheck(true);
         return load;
     }
 
-    void storeHeap(ArrayBufferView::ViewType vt, MDefinition *ptr, MDefinition *v, NeedsBoundsCheck chk)
+    void storeHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *v, NeedsBoundsCheck chk)
     {
         if (inDeadCode())
             return;
         MAsmJSStoreHeap *store = MAsmJSStoreHeap::New(alloc(), vt, ptr, v);
         curBlock_->add(store);
         if (chk == NO_BOUNDS_CHECK)
             store->setSkipBoundsCheck(true);
     }
@@ -2989,33 +2989,33 @@ CheckNewArrayView(ModuleCompiler &m, Pro
 
     PropertyName *bufferName = m.module().bufferArgumentName();
     if (!bufferName)
         return m.fail(bufArg, "cannot create array view without an asm.js heap parameter");
     if (!IsUseOfName(bufArg, bufferName))
         return m.failName(bufArg, "argument to array view constructor must be '%s'", bufferName);
 
     JSAtomState &names = m.cx()->names();
-    ArrayBufferView::ViewType type;
+    Scalar::Type type;
     if (field == names.Int8Array)
-        type = ArrayBufferView::TYPE_INT8;
+        type = Scalar::Int8;
     else if (field == names.Uint8Array)
-        type = ArrayBufferView::TYPE_UINT8;
+        type = Scalar::Uint8;
     else if (field == names.Int16Array)
-        type = ArrayBufferView::TYPE_INT16;
+        type = Scalar::Int16;
     else if (field == names.Uint16Array)
-        type = ArrayBufferView::TYPE_UINT16;
+        type = Scalar::Uint16;
     else if (field == names.Int32Array)
-        type = ArrayBufferView::TYPE_INT32;
+        type = Scalar::Int32;
     else if (field == names.Uint32Array)
-        type = ArrayBufferView::TYPE_UINT32;
+        type = Scalar::Uint32;
     else if (field == names.Float32Array)
-        type = ArrayBufferView::TYPE_FLOAT32;
+        type = Scalar::Float32;
     else if (field == names.Float64Array)
-        type = ArrayBufferView::TYPE_FLOAT64;
+        type = Scalar::Float64;
     else
         return m.fail(ctorExpr, "could not match typed array name");
 
     return m.addArrayView(varName, type, field);
 }
 
 static bool
 CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode)
@@ -3351,17 +3351,17 @@ FoldMaskedArrayIndex(FunctionCompiler &f
         *indexExpr = indexNode;
         return true;
     }
 
     return false;
 }
 
 static bool
-CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType *viewType,
+CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, Scalar::Type *viewType,
                  MDefinition **def, NeedsBoundsCheck *needsBoundsCheck)
 {
     ParseNode *viewName = ElemBase(elem);
     ParseNode *indexExpr = ElemIndex(elem);
     *needsBoundsCheck = NEEDS_BOUNDS_CHECK;
 
     if (!viewName->isKind(PNK_NAME))
         return f.fail(viewName, "base of array access must be a typed array view name");
@@ -3456,58 +3456,58 @@ CheckArrayAccess(FunctionCompiler &f, Pa
         *def = f.bitwise<MBitAnd>(pointerDef, f.constant(Int32Value(mask), Type::Int));
 
     return true;
 }
 
 static bool
 CheckLoadArray(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type)
 {
-    ArrayBufferView::ViewType viewType;
+    Scalar::Type viewType;
     MDefinition *pointerDef;
     NeedsBoundsCheck needsBoundsCheck;
     if (!CheckArrayAccess(f, elem, &viewType, &pointerDef, &needsBoundsCheck))
         return false;
 
     *def = f.loadHeap(viewType, pointerDef, needsBoundsCheck);
     *type = TypedArrayLoadType(viewType);
     return true;
 }
 
 static bool
 CheckStoreArray(FunctionCompiler &f, ParseNode *lhs, ParseNode *rhs, MDefinition **def, Type *type)
 {
-    ArrayBufferView::ViewType viewType;
+    Scalar::Type viewType;
     MDefinition *pointerDef;
     NeedsBoundsCheck needsBoundsCheck;
     if (!CheckArrayAccess(f, lhs, &viewType, &pointerDef, &needsBoundsCheck))
         return false;
 
     MDefinition *rhsDef;
     Type rhsType;
     if (!CheckExpr(f, rhs, &rhsDef, &rhsType))
         return false;
 
     switch (viewType) {
-      case ArrayBufferView::TYPE_INT8:
-      case ArrayBufferView::TYPE_INT16:
-      case ArrayBufferView::TYPE_INT32:
-      case ArrayBufferView::TYPE_UINT8:
-      case ArrayBufferView::TYPE_UINT16:
-      case ArrayBufferView::TYPE_UINT32:
+      case Scalar::Int8:
+      case Scalar::Int16:
+      case Scalar::Int32:
+      case Scalar::Uint8:
+      case Scalar::Uint16:
+      case Scalar::Uint32:
         if (!rhsType.isIntish())
             return f.failf(lhs, "%s is not a subtype of intish", rhsType.toChars());
         break;
-      case ArrayBufferView::TYPE_FLOAT32:
+      case Scalar::Float32:
         if (rhsType.isMaybeDouble())
             rhsDef = f.unary<MToFloat32>(rhsDef);
         else if (!rhsType.isFloatish())
             return f.failf(lhs, "%s is not a subtype of double? or floatish", rhsType.toChars());
         break;
-      case ArrayBufferView::TYPE_FLOAT64:
+      case Scalar::Float64:
         if (rhsType.isMaybeFloat())
             rhsDef = f.unary<MToDouble>(rhsDef);
         else if (!rhsType.isMaybeDouble())
             return f.failf(lhs, "%s is not a subtype of float? or double?", rhsType.toChars());
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected view type");
     }
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -74,17 +74,17 @@ class AsmJSModule
                     uint32_t index_;
                     VarInitKind initKind_;
                     AsmJSCoercion coercion_;
                     union {
                         Value constant_; // will only contain int32/double
                     } init;
                 } var;
                 uint32_t ffiIndex_;
-                ArrayBufferView::ViewType viewType_;
+                Scalar::Type viewType_;
                 AsmJSMathBuiltinFunction mathBuiltinFunc_;
                 struct {
                     ConstantKind kind_;
                     double value_;
                 } constant;
             } u;
         } pod;
         PropertyName *name_;
@@ -138,17 +138,17 @@ class AsmJSModule
         uint32_t ffiIndex() const {
             JS_ASSERT(pod.which_ == FFI);
             return pod.u.ffiIndex_;
         }
         PropertyName *viewName() const {
             JS_ASSERT(pod.which_ == ArrayView);
             return name_;
         }
-        ArrayBufferView::ViewType viewType() const {
+        Scalar::Type viewType() const {
             JS_ASSERT(pod.which_ == ArrayView);
             return pod.u.viewType_;
         }
         PropertyName *mathName() const {
             JS_ASSERT(pod.which_ == MathBuiltinFunction);
             return name_;
         }
         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
@@ -640,17 +640,17 @@ class AsmJSModule
     bool addFFI(PropertyName *field, uint32_t *ffiIndex) {
         JS_ASSERT(!isFinishedWithModulePrologue());
         if (pod.numFFIs_ == UINT32_MAX)
             return false;
         Global g(Global::FFI, field);
         g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++;
         return globals_.append(g);
     }
-    bool addArrayView(ArrayBufferView::ViewType vt, PropertyName *field) {
+    bool addArrayView(Scalar::Type vt, PropertyName *field) {
         JS_ASSERT(!isFinishedWithModulePrologue());
         pod.hasArrayView_ = true;
         Global g(Global::ArrayView, field);
         g.pod.u.viewType_ = vt;
         return globals_.append(g);
     }
     bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName *field) {
         JS_ASSERT(!isFinishedWithModulePrologue());
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -1051,17 +1051,18 @@ js::RequestInterruptForAsmJSCode(JSRunti
     AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread();
     if (!activation)
         return;
 
     JS_ASSERT(rt->currentThreadOwnsInterruptLock());
     activation->module().protectCode(rt);
 }
 
-#if defined(MOZ_ASAN) && defined(JS_STANDALONE)
+// This is not supported by clang-cl yet.
+#if defined(MOZ_ASAN) && defined(JS_STANDALONE) && !defined(_MSC_VER)
 // Usually, this definition is found in mozglue (see mozglue/build/AsanOptions.cpp).
 // However, when doing standalone JS builds, mozglue is not used and we must ensure
 // that we still allow custom SIGSEGV handlers for asm.js and ion to work correctly.
 extern "C" MOZ_ASAN_BLACKLIST
 const char* __asan_default_options() {
     return "allow_user_segv_handler=1";
 }
 #endif
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3883,19 +3883,19 @@ static bool TryAttachNativeGetElemStub(J
 
     return true;
 }
 
 static bool
 TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr)
 {
     uint32_t type = tarr->type();
-    return (type == ScalarTypeDescr::TYPE_UINT32 ||
-            type == ScalarTypeDescr::TYPE_FLOAT32 ||
-            type == ScalarTypeDescr::TYPE_FLOAT64);
+    return (type == Scalar::Uint32 ||
+            type == Scalar::Float32 ||
+            type == Scalar::Float64);
 }
 
 static bool
 TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_Fallback *stub,
                      HandleValue lhs, HandleValue rhs, HandleValue res)
 {
     bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM);
 
@@ -4641,17 +4641,17 @@ ICGetElem_TypedArray::Compiler::generate
     // Bounds check.
     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), scratchReg);
     masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
 
     // Load the elements vector.
     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), scratchReg);
 
     // Load the value.
-    BaseIndex source(scratchReg, key, ScaleFromElemWidth(TypedArrayObject::slotWidth(type_)));
+    BaseIndex source(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
     masm.loadFromTypedArray(type_, source, R0, false, scratchReg, &failure);
 
     // Todo: Allow loading doubles from uint32 arrays, but this requires monitoring.
     EmitReturnFromIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
@@ -5530,39 +5530,39 @@ ICSetElem_TypedArray::Compiler::generate
     Label oobWrite;
     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), scratchReg);
     masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
                   expectOutOfBounds_ ? &oobWrite : &failure);
 
     // Load the elements vector.
     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), scratchReg);
 
-    BaseIndex dest(scratchReg, key, ScaleFromElemWidth(TypedArrayObject::slotWidth(type_)));
+    BaseIndex dest(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
     Address value(BaselineStackReg, ICStackValueOffset);
 
     // We need a second scratch register. It's okay to clobber the type tag of
     // R0 or R1, as long as it's restored before jumping to the next stub.
     regs = availableGeneralRegs(0);
     regs.takeUnchecked(obj);
     regs.takeUnchecked(key);
     regs.take(scratchReg);
     Register secondScratch = regs.takeAny();
 
-    if (type_ == ScalarTypeDescr::TYPE_FLOAT32 || type_ == ScalarTypeDescr::TYPE_FLOAT64) {
+    if (type_ == Scalar::Float32 || type_ == Scalar::Float64) {
         masm.ensureDouble(value, FloatReg0, &failure);
         if (LIRGenerator::allowFloat32Optimizations() &&
-            type_ == ScalarTypeDescr::TYPE_FLOAT32)
+            type_ == Scalar::Float32)
         {
             masm.convertDoubleToFloat32(FloatReg0, ScratchFloat32Reg);
             masm.storeToTypedFloatArray(type_, ScratchFloat32Reg, dest);
         } else {
             masm.storeToTypedFloatArray(type_, FloatReg0, dest);
         }
         EmitReturnFromIC(masm);
-    } else if (type_ == ScalarTypeDescr::TYPE_UINT8_CLAMPED) {
+    } else if (type_ == Scalar::Uint8Clamped) {
         Label notInt32;
         masm.branchTestInt32(Assembler::NotEqual, value, &notInt32);
         masm.unboxInt32(value, secondScratch);
         masm.clampIntToUint8(secondScratch);
 
         Label clamped;
         masm.bind(&clamped);
         masm.storeToTypedIntArray(type_, secondScratch, dest);
@@ -6067,16 +6067,58 @@ ICGetIntrinsic_Constant::Compiler::gener
     return true;
 }
 
 //
 // GetProp_Fallback
 //
 
 static bool
+TryAttachMagicArgumentsGetPropStub(JSContext *cx, JSScript *script, ICGetProp_Fallback *stub,
+                                   HandlePropertyName name, HandleValue val, HandleValue res,
+                                   bool *attached)
+{
+    MOZ_ASSERT(!*attached);
+
+    if (!val.isMagic(JS_OPTIMIZED_ARGUMENTS))
+        return true;
+
+    // Try handling arguments.callee on optimized arguments.
+    if (name == cx->names().callee) {
+        IonSpew(IonSpew_BaselineIC, "  Generating GetProp(MagicArgs.callee) stub");
+
+        // Unlike ICGetProp_ArgumentsLength, only magic argument stubs are
+        // supported at the moment.
+        ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
+
+        // XXXshu the compiler really should be stack allocated, but stack
+        // allocating it causes the test_temporary_storage indexedDB test to
+        // fail on GCC 4.7-compiled ARMv6 optimized builds on Android 2.3 and
+        // below with a NotFoundError, despite that test never exercising this
+        // code.
+        //
+        // Instead of tracking down the GCC bug, I've opted to heap allocate
+        // instead.
+        ScopedJSDeletePtr<ICGetProp_ArgumentsCallee::Compiler> compiler;
+        compiler = js_new<ICGetProp_ArgumentsCallee::Compiler>(cx, monitorStub);
+        if (!compiler)
+            return false;
+        ICStub *newStub = compiler->getStub(compiler->getStubSpace(script));
+        if (!newStub)
+            return false;
+        stub->addNewStub(newStub);
+
+        *attached = true;
+        return true;
+    }
+
+    return true;
+}
+
+static bool
 TryAttachLengthStub(JSContext *cx, JSScript *script, ICGetProp_Fallback *stub, HandleValue val,
                     HandleValue res, bool *attached)
 {
     JS_ASSERT(!*attached);
 
     if (val.isString()) {
         JS_ASSERT(res.isInt32());
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(String.length) stub");
@@ -6421,64 +6463,66 @@ TryAttachNativeDoesNotExistStub(JSContex
         return false;
 
     stub->addNewStub(newStub);
     *attached = true;
     return true;
 }
 
 static bool
+ComputeGetPropResult(JSContext *cx, BaselineFrame *frame, JSOp op, HandlePropertyName name,
+                     MutableHandleValue val, MutableHandleValue res)
+{
+    // Handle arguments.length and arguments.callee on optimized arguments, as
+    // it is not an object.
+    if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && IsOptimizedArguments(frame, val.address())) {
+        if (op == JSOP_LENGTH) {
+            res.setInt32(frame->numActualArgs());
+        } else {
+            MOZ_ASSERT(name == cx->names().callee);
+            res.setObject(*frame->callee());
+        }
+    } else {
+        // Handle when val is an object.
+        RootedObject obj(cx, ToObjectFromStack(cx, val));
+        if (!obj)
+            return false;
+
+        RootedId id(cx, NameToId(name));
+        if (!JSObject::getGeneric(cx, obj, obj, id, res))
+            return false;
+
+#if JS_HAS_NO_SUCH_METHOD
+        // Handle objects with __noSuchMethod__.
+        if (op == JSOP_CALLPROP && MOZ_UNLIKELY(res.isUndefined()) && val.isObject()) {
+            if (!OnUnknownMethod(cx, obj, IdToValue(id), res))
+                return false;
+        }
+#endif
+    }
+
+    return true;
+}
+
+static bool
 DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_,
                   MutableHandleValue val, MutableHandleValue res)
 {
     // This fallback stub may trigger debug mode toggling.
     DebugModeOSRVolatileStub<ICGetProp_Fallback *> stub(frame, stub_);
 
     jsbytecode *pc = stub->icEntry()->pc(frame->script());
     JSOp op = JSOp(*pc);
     FallbackICSpew(cx, stub, "GetProp(%s)", js_CodeName[op]);
 
     JS_ASSERT(op == JSOP_GETPROP || op == JSOP_CALLPROP || op == JSOP_LENGTH || op == JSOP_GETXPROP);
 
     RootedPropertyName name(cx, frame->script()->getName(pc));
-
-    if (op == JSOP_LENGTH && val.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
-        // Handle arguments.length access.
-        if (IsOptimizedArguments(frame, val.address())) {
-            res.setInt32(frame->numActualArgs());
-
-            // Monitor result
-            types::TypeScript::Monitor(cx, frame->script(), pc, res);
-            if (!stub->addMonitorStubForValue(cx, frame->script(), res))
-                return false;
-
-            bool attached = false;
-            if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
-                return false;
-            JS_ASSERT(attached);
-
-            return true;
-        }
-    }
-
-    RootedObject obj(cx, ToObjectFromStack(cx, val));
-    if (!obj)
-        return false;
-
-    RootedId id(cx, NameToId(name));
-    if (!JSObject::getGeneric(cx, obj, obj, id, res))
-        return false;
-
-#if JS_HAS_NO_SUCH_METHOD
-    // Handle objects with __noSuchMethod__.
-    if (op == JSOP_CALLPROP && MOZ_UNLIKELY(res.isUndefined()) && val.isObject()) {
-        if (!OnUnknownMethod(cx, obj, IdToValue(id), res))
-            return false;
-    }
-#endif
+    if (!ComputeGetPropResult(cx, frame, op, name, val, res))
+        return false;
 
     types::TypeScript::Monitor(cx, frame->script(), pc, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Add a type monitor stub for the resulting value.
@@ -6494,16 +6538,21 @@ DoGetPropFallback(JSContext *cx, Baselin
 
     if (op == JSOP_LENGTH) {
         if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
             return false;
         if (attached)
             return true;
     }
 
+    if (!TryAttachMagicArgumentsGetPropStub(cx, frame->script(), stub, name, val, res, &attached))
+        return false;
+    if (attached)
+        return true;
+
     RootedScript script(cx, frame->script());
 
     if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, res, &attached))
         return false;
     if (attached)
         return true;
 
     if (val.isString() || val.isNumber() || val.isBoolean()) {
@@ -7309,16 +7358,45 @@ ICGetProp_ArgumentsLength::Compiler::gen
     masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
     EmitReturnFromIC(masm);
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
+ICGetProp_ArgumentsCallee::ICGetProp_ArgumentsCallee(JitCode *stubCode, ICStub *firstMonitorStub)
+  : ICMonitoredStub(GetProp_ArgumentsCallee, stubCode, firstMonitorStub)
+{ }
+
+bool
+ICGetProp_ArgumentsCallee::Compiler::generateStubCode(MacroAssembler &masm)
+{
+    Label failure;
+
+    // Ensure that this is lazy arguments.
+    masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure);
+
+    // Ensure that frame has not loaded different arguments object since.
+    masm.branchTest32(Assembler::NonZero,
+                      Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
+                      Imm32(BaselineFrame::HAS_ARGS_OBJ),
+                      &failure);
+
+    Address callee(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
+    masm.loadPtr(callee, R0.scratchReg());
+    masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
+
+    EmitEnterTypeMonitorIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
 void
 BaselineScript::noteAccessedGetter(uint32_t pcOffset)
 {
     ICEntry &entry = icEntryFromPCOffset(pcOffset);
     ICFallbackStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
         stub->toGetProp_Fallback()->noteAccessedGetter();
@@ -10179,17 +10257,17 @@ ICGetElem_Dense::ICGetElem_Dense(JitCode
 /* static */ ICGetElem_Dense *
 ICGetElem_Dense::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                        ICGetElem_Dense &other)
 {
     RootedShape shape(cx, other.shape_);
     return New(space, other.jitCode(), firstMonitorStub, shape);
 }
 
-ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type)
+ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, Scalar::Type type)
   : ICStub(GetElem_TypedArray, stubCode),
     shape_(shape)
 {
     extra_ = uint16_t(type);
     JS_ASSERT(extra_ == type);
 }
 
 /* static */ ICGetElem_Arguments *
@@ -10220,17 +10298,17 @@ ICSetElemDenseAddCompiler::getStubSpecif
 {
     RootedTypeObject objType(cx, obj_->getType(cx));
     if (!objType)
         return nullptr;
     Rooted<JitCode *> stubCode(cx, getStubCode());
     return ICSetElem_DenseAddImpl<ProtoChainDepth>::New(space, stubCode, objType, shapes);
 }
 
-ICSetElem_TypedArray::ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type,
+ICSetElem_TypedArray::ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, Scalar::Type type,
                                            bool expectOutOfBounds)
   : ICStub(SetElem_TypedArray, stubCode),
     shape_(shape)
 {
     extra_ = uint8_t(type);
     JS_ASSERT(extra_ == type);
     extra_ |= (static_cast<uint16_t>(expectOutOfBounds) << 8);
 }
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -418,16 +418,17 @@ class ICEntry
     _(GetProp_NativePrototype)  \
     _(GetProp_CallScripted)     \
     _(GetProp_CallNative)       \
     _(GetProp_CallNativePrototype)\
     _(GetProp_CallDOMProxyNative)\
     _(GetProp_CallDOMProxyWithGenerationNative)\
     _(GetProp_DOMProxyShadowed) \
     _(GetProp_ArgumentsLength)  \
+    _(GetProp_ArgumentsCallee)  \
                                 \
     _(SetProp_Fallback)         \
     _(SetProp_Native)           \
     _(SetProp_NativeAdd)        \
     _(SetProp_CallScripted)     \
     _(SetProp_CallNative)       \
                                 \
     _(TableSwitch)              \
@@ -3401,48 +3402,48 @@ class ICGetElem_Dense : public ICMonitor
 
 class ICGetElem_TypedArray : public ICStub
 {
     friend class ICStubSpace;
 
   protected: // Protected to silence Clang warning.
     HeapPtrShape shape_;
 
-    ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type);
+    ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, Scalar::Type type);
 
   public:
     static inline ICGetElem_TypedArray *New(ICStubSpace *space, JitCode *code,
-                                            HandleShape shape, uint32_t type)
+                                            HandleShape shape, Scalar::Type type)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_TypedArray>(code, shape, type);
     }
 
     static size_t offsetOfShape() {
         return offsetof(ICGetElem_TypedArray, shape_);
     }
 
     HeapPtrShape &shape() {
         return shape_;
     }
 
     class Compiler : public ICStubCompiler {
       RootedShape shape_;
-      uint32_t type_;
+      Scalar::Type type_;
 
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16);
         }
 
       public:
-        Compiler(JSContext *cx, Shape *shape, uint32_t type)
+        Compiler(JSContext *cx, Shape *shape, Scalar::Type type)
           : ICStubCompiler(cx, ICStub::GetElem_TypedArray),
             shape_(cx, shape),
             type_(type)
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICGetElem_TypedArray::New(space, getStubCode(), shape_, type_);
         }
@@ -3716,60 +3717,60 @@ class ICSetElemDenseAddCompiler : public
 
 class ICSetElem_TypedArray : public ICStub
 {
     friend class ICStubSpace;
 
   protected: // Protected to silence Clang warning.
     HeapPtrShape shape_;
 
-    ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type,
+    ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, Scalar::Type type,
                          bool expectOutOfBounds);
 
   public:
     static inline ICSetElem_TypedArray *New(ICStubSpace *space, JitCode *code,
-                                            HandleShape shape, uint32_t type,
+                                            HandleShape shape, Scalar::Type type,
                                             bool expectOutOfBounds)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICSetElem_TypedArray>(code, shape, type, expectOutOfBounds);
     }
 
-    uint32_t type() const {
-        return extra_ & 0xff;
+    Scalar::Type type() const {
+        return (Scalar::Type) (extra_ & 0xff);
     }
 
     bool expectOutOfBounds() const {
         return (extra_ >> 8) & 1;
     }
 
     static size_t offsetOfShape() {
         return offsetof(ICSetElem_TypedArray, shape_);
     }
 
     HeapPtrShape &shape() {
         return shape_;
     }
 
     class Compiler : public ICStubCompiler {
         RootedShape shape_;
-        uint32_t type_;
+        Scalar::Type type_;
         bool expectOutOfBounds_;
 
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16) |
                    (static_cast<int32_t>(expectOutOfBounds_) << 24);
         }
 
       public:
-        Compiler(JSContext *cx, Shape *shape, uint32_t type, bool expectOutOfBounds)
+        Compiler(JSContext *cx, Shape *shape, Scalar::Type type, bool expectOutOfBounds)
           : ICStubCompiler(cx, ICStub::SetElem_TypedArray),
             shape_(cx, shape),
             type_(type),
             expectOutOfBounds_(expectOutOfBounds)
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_,
@@ -5072,16 +5073,49 @@ class ICGetProp_ArgumentsLength : public
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICGetProp_ArgumentsLength::New(space, getStubCode());
         }
     };
 };
 
+class ICGetProp_ArgumentsCallee : public ICMonitoredStub
+{
+    friend class ICStubSpace;
+
+  protected:
+    ICGetProp_ArgumentsCallee(JitCode *stubCode, ICStub *firstMonitorStub);
+
+  public:
+    static inline ICGetProp_ArgumentsCallee *New(ICStubSpace *space, JitCode *code,
+                                                 ICStub *firstMonitorStub)
+    {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICGetProp_ArgumentsCallee>(code, firstMonitorStub);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        ICStub *firstMonitorStub_;
+        bool generateStubCode(MacroAssembler &masm);
+
+      public:
+        Compiler(JSContext *cx, ICStub *firstMonitorStub)
+          : ICStubCompiler(cx, ICStub::GetProp_ArgumentsCallee),
+            firstMonitorStub_(firstMonitorStub)
+        {}
+
+        ICStub *getStub(ICStubSpace *space) {
+            return ICGetProp_ArgumentsCallee::New(space, getStubCode(), firstMonitorStub_);
+        }
+    };
+};
+
 // SetProp
 //     JSOP_SETPROP
 //     JSOP_SETNAME
 //     JSOP_SETGNAME
 //     JSOP_INITPROP
 
 class ICSetProp_Fallback : public ICFallbackStub
 {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7865,18 +7865,18 @@ CodeGenerator::visitLoadElementHole(LLoa
 
 bool
 CodeGenerator::visitLoadTypedArrayElement(LLoadTypedArrayElement *lir)
 {
     Register elements = ToRegister(lir->elements());
     Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
     AnyRegister out = ToAnyRegister(lir->output());
 
-    int arrayType = lir->mir()->arrayType();
-    int width = TypedArrayObject::slotWidth(arrayType);
+    Scalar::Type arrayType = lir->mir()->arrayType();
+    int width = Scalar::byteSize(arrayType);
 
     Label fail;
     if (lir->index()->isConstant()) {
         Address source(elements, ToInt32(lir->index()) * width);
         masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
     } else {
         BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
         masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
@@ -7904,18 +7904,18 @@ CodeGenerator::visitLoadTypedArrayElemen
     masm.branchKey(Assembler::Above, scratch, key, &inbounds);
     masm.moveValue(UndefinedValue(), out);
     masm.jump(&done);
 
     // Load the elements vector.
     masm.bind(&inbounds);
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch);
 
-    int arrayType = lir->mir()->arrayType();
-    int width = TypedArrayObject::slotWidth(arrayType);
+    Scalar::Type arrayType = lir->mir()->arrayType();
+    int width = Scalar::byteSize(arrayType);
 
     Label fail;
     if (key.isConstant()) {
         Address source(scratch, key.constant() * width);
         masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
                                 out.scratchReg(), &fail);
     } else {
         BaseIndex source(scratch, key.reg(), ScaleFromElemWidth(width));
@@ -7927,38 +7927,36 @@ CodeGenerator::visitLoadTypedArrayElemen
         return false;
 
     masm.bind(&done);
     return true;
 }
 
 template <typename T>
 static inline void
-StoreToTypedArray(MacroAssembler &masm, int arrayType, const LAllocation *value, const T &dest)
-{
-    if (arrayType == ScalarTypeDescr::TYPE_FLOAT32 ||
-        arrayType == ScalarTypeDescr::TYPE_FLOAT64)
-    {
+StoreToTypedArray(MacroAssembler &masm, Scalar::Type arrayType, const LAllocation *value, const T &dest)
+{
+    if (arrayType == Scalar::Float32 || arrayType == Scalar::Float64) {
         masm.storeToTypedFloatArray(arrayType, ToFloatRegister(value), dest);
     } else {
         if (value->isConstant())
             masm.storeToTypedIntArray(arrayType, Imm32(ToInt32(value)), dest);
         else
             masm.storeToTypedIntArray(arrayType, ToRegister(value), dest);
     }
 }
 
 bool
 CodeGenerator::visitStoreTypedArrayElement(LStoreTypedArrayElement *lir)
 {
     Register elements = ToRegister(lir->elements());
     const LAllocation *value = lir->value();
 
-    int arrayType = lir->mir()->arrayType();
-    int width = TypedArrayObject::slotWidth(arrayType);
+    Scalar::Type arrayType = lir->mir()->arrayType();
+    int width = Scalar::byteSize(arrayType);
 
     if (lir->index()->isConstant()) {
         Address dest(elements, ToInt32(lir->index()) * width);
         StoreToTypedArray(masm, arrayType, value, dest);
     } else {
         BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
         StoreToTypedArray(masm, arrayType, value, dest);
     }
@@ -7967,18 +7965,18 @@ CodeGenerator::visitStoreTypedArrayEleme
 }
 
 bool
 CodeGenerator::visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole *lir)
 {
     Register elements = ToRegister(lir->elements());
     const LAllocation *value = lir->value();
 
-    int arrayType = lir->mir()->arrayType();
-    int width = TypedArrayObject::slotWidth(arrayType);
+    Scalar::Type arrayType = lir->mir()->arrayType();
+    int width = Scalar::byteSize(arrayType);
 
     bool guardLength = true;
     if (lir->index()->isConstant() && lir->length()->isConstant()) {
         uint32_t idx = ToInt32(lir->index());
         uint32_t len = ToInt32(lir->length());
         if (idx >= len)
             return true;
         guardLength = false;
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2414,19 +2414,24 @@ ArgumentsUseCanBeLazy(JSContext *cx, JSS
         *argumentsContentsObserved = true;
         return true;
     }
 
     // MGetArgumentsObjectArg needs to be considered as a use that allows laziness.
     if (ins->isGetArgumentsObjectArg() && index == 0)
         return true;
 
-    // arguments.length length can read fp->numActualArgs() directly.
-    if (ins->isCallGetProperty() && index == 0 && ins->toCallGetProperty()->name() == cx->names().length)
+    // arguments.length length can read fp->numActualArgs() directly and
+    // arguments.callee can read fp->callee() directly.
+    if (ins->isCallGetProperty() && index == 0 &&
+        (ins->toCallGetProperty()->name() == cx->names().length ||
+         ins->toCallGetProperty()->name() == cx->names().callee))
+    {
         return true;
+    }
 
     return false;
 }
 
 bool
 jit::AnalyzeArgumentsUsage(JSContext *cx, JSScript *scriptArg)
 {
     RootedScript script(cx, scriptArg);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6818,18 +6818,17 @@ IonBuilder::getElemTryTypedObject(bool *
       case type::UnsizedArray:
         MOZ_ASSUME_UNREACHABLE("Unsized arrays cannot be element types");
     }
 
     MOZ_ASSUME_UNREACHABLE("Bad kind");
 }
 
 static MIRType
-MIRTypeForTypedArrayRead(ScalarTypeDescr::Type arrayType,
-                         bool observedDouble);
+MIRTypeForTypedArrayRead(Scalar::Type arrayType, bool observedDouble);
 
 bool
 IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
                                           MDefinition *obj,
                                           MDefinition *index,
                                           TypedObjectPrediction objPrediction,
                                           MDefinition **indexAsByteOffset,
                                           bool *canBeNeutered)
@@ -7062,17 +7061,17 @@ IonBuilder::getElemTryDense(bool *emitte
     return true;
 }
 
 bool
 IonBuilder::getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition *index)
 {
     JS_ASSERT(*emitted == false);
 
-    ScalarTypeDescr::Type arrayType;
+    Scalar::Type arrayType;
     if (!ElementAccessIsTypedArray(obj, index, &arrayType))
         return true;
 
     if (!LIRGenerator::allowStaticTypedArrayAccesses())
         return true;
 
     if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
         return true;
@@ -7086,18 +7085,18 @@ IonBuilder::getElemTryTypedStatic(bool *
 
     TypedArrayObject *tarr = &tarrObj->as<TypedArrayObject>();
 
     types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
     if (tarrType->unknownProperties())
         return true;
 
     // LoadTypedArrayElementStatic currently treats uint32 arrays as int32.
-    ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
-    if (viewType == ArrayBufferView::TYPE_UINT32)
+    Scalar::Type viewType = tarr->type();
+    if (viewType == Scalar::Uint32)
         return true;
 
     MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
     if (!ptr)
         return true;
 
     // Emit LoadTypedArrayElementStatic.
     tarrType->watchStateChangeForTypedArrayData(constraints());
@@ -7109,17 +7108,17 @@ IonBuilder::getElemTryTypedStatic(bool *
     current->add(load);
     current->push(load);
 
     // The load is infallible if an undefined result will be coerced to the
     // appropriate numeric type if the read is out of bounds. The truncation
     // analysis picks up some of these cases, but is incomplete with respect
     // to others. For now, sniff the bytecode for simple patterns following
     // the load which guarantee a truncation or numeric conversion.
-    if (viewType == ArrayBufferView::TYPE_FLOAT32 || viewType == ArrayBufferView::TYPE_FLOAT64) {
+    if (viewType == Scalar::Float32 || viewType == Scalar::Float64) {
         jsbytecode *next = pc + JSOP_GETELEM_LENGTH;
         if (*next == JSOP_POS)
             load->setInfallible();
     } else {
         jsbytecode *next = pc + JSOP_GETELEM_LENGTH;
         if (*next == JSOP_ZERO && *(next + JSOP_ZERO_LENGTH) == JSOP_BITOR)
             load->setInfallible();
     }
@@ -7128,17 +7127,17 @@ IonBuilder::getElemTryTypedStatic(bool *
     return true;
 }
 
 bool
 IonBuilder::getElemTryTypedArray(bool *emitted, MDefinition *obj, MDefinition *index)
 {
     JS_ASSERT(*emitted == false);
 
-    ScalarTypeDescr::Type arrayType;
+    Scalar::Type arrayType;
     if (!ElementAccessIsTypedArray(obj, index, &arrayType))
         return true;
 
     // Emit typed getelem variant.
     if (!jsop_getelem_typed(obj, index, arrayType))
         return false;
 
     *emitted = true;
@@ -7500,17 +7499,17 @@ IonBuilder::addTypedArrayLengthAndData(M
 
         *elements = MTypedArrayElements::New(alloc(), obj);
         current->add(*elements);
     }
 }
 
 MDefinition *
 IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id,
-                                                  ArrayBufferView::ViewType viewType)
+                                                  Scalar::Type viewType)
 {
     // No shifting is necessary if the typed array has single byte elements.
     if (TypedArrayShift(viewType) == 0)
         return id;
 
     // If the index is an already shifted constant, undo the shift to get the
     // absolute offset being accessed.
     if (id->isConstant() && id->toConstant()->value().isInt32()) {
@@ -7538,40 +7537,41 @@ IonBuilder::convertShiftToMaskForStaticT
 
     current->add(mask);
     current->add(ptr);
 
     return ptr;
 }
 
 static MIRType
-MIRTypeForTypedArrayRead(ScalarTypeDescr::Type arrayType,
-                         bool observedDouble)
+MIRTypeForTypedArrayRead(Scalar::Type arrayType, bool observedDouble)
 {
     switch (arrayType) {
-      case ScalarTypeDescr::TYPE_INT8:
-      case ScalarTypeDescr::TYPE_UINT8:
-      case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
-      case ScalarTypeDescr::TYPE_INT16:
-      case ScalarTypeDescr::TYPE_UINT16:
-      case ScalarTypeDescr::TYPE_INT32:
+      case Scalar::Int8:
+      case Scalar::Uint8:
+      case Scalar::Uint8Clamped:
+      case Scalar::Int16:
+      case Scalar::Uint16:
+      case Scalar::Int32:
         return MIRType_Int32;
-      case ScalarTypeDescr::TYPE_UINT32:
+      case Scalar::Uint32:
         return observedDouble ? MIRType_Double : MIRType_Int32;
-      case ScalarTypeDescr::TYPE_FLOAT32:
+      case Scalar::Float32:
         return (LIRGenerator::allowFloat32Optimizations()) ? MIRType_Float32 : MIRType_Double;
-      case ScalarTypeDescr::TYPE_FLOAT64:
+      case Scalar::Float64:
         return MIRType_Double;
+      default:
+        break;
     }
     MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
 }
 
 bool
 IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
-                               ScalarTypeDescr::Type arrayType)
+                               Scalar::Type arrayType)
 {
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
 
     bool maybeUndefined = types->hasType(types::Type::UndefinedType());
 
     // Reading from an Uint32Array will result in a double for values
     // that don't fit in an int32. We have to bailout if this happens
     // and the instruction is not known to return a double.
@@ -7608,28 +7608,28 @@ IonBuilder::jsop_getelem_typed(MDefiniti
         return true;
     } else {
         // We need a type barrier if the array's element type has never been
         // observed (we've only read out-of-bounds values). Note that for
         // Uint32Array, we only check for int32: if allowDouble is false we
         // will bailout when we read a double.
         BarrierKind barrier = BarrierKind::TypeSet;
         switch (arrayType) {
-          case ScalarTypeDescr::TYPE_INT8:
-          case ScalarTypeDescr::TYPE_UINT8:
-          case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
-          case ScalarTypeDescr::TYPE_INT16:
-          case ScalarTypeDescr::TYPE_UINT16:
-          case ScalarTypeDescr::TYPE_INT32:
-          case ScalarTypeDescr::TYPE_UINT32:
+          case Scalar::Int8:
+          case Scalar::Uint8:
+          case Scalar::Uint8Clamped:
+          case Scalar::Int16:
+          case Scalar::Uint16:
+          case Scalar::Int32:
+          case Scalar::Uint32:
             if (types->hasType(types::Type::Int32Type()))
                 barrier = BarrierKind::NoBarrier;
             break;
-          case ScalarTypeDescr::TYPE_FLOAT32:
-          case ScalarTypeDescr::TYPE_FLOAT64:
+          case Scalar::Float32:
+          case Scalar::Float64:
             if (allowDouble)
                 barrier = BarrierKind::NoBarrier;
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
         }
 
         // Assume we will read out-of-bound values. In this case the
@@ -7762,17 +7762,17 @@ IonBuilder::setElemTryScalarElemOfTypedO
 }
 
 bool
 IonBuilder::setElemTryTypedStatic(bool *emitted, MDefinition *object,
                                   MDefinition *index, MDefinition *value)
 {
     JS_ASSERT(*emitted == false);
 
-    ScalarTypeDescr::Type arrayType;
+    Scalar::Type arrayType;
     if (!ElementAccessIsTypedArray(object, index, &arrayType))
         return true;
 
     if (!LIRGenerator::allowStaticTypedArrayAccesses())
         return true;
 
     if (ElementAccessHasExtraIndexedProperty(constraints(), object))
         return true;
@@ -7789,30 +7789,30 @@ IonBuilder::setElemTryTypedStatic(bool *
     if (tarr->runtimeFromMainThread()->gc.nursery.isInside(tarr->viewData()))
         return true;
 #endif
 
     types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
     if (tarrType->unknownProperties())
         return true;
 
-    ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
+    Scalar::Type viewType = tarr->type();
     MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
     if (!ptr)
         return true;
 
     // Emit StoreTypedArrayElementStatic.
     tarrType->watchStateChangeForTypedArrayData(constraints());
 
     object->setImplicitlyUsedUnchecked();
     index->setImplicitlyUsedUnchecked();
 
     // Clamp value to [0, 255] for Uint8ClampedArray.
     MDefinition *toWrite = value;
-    if (viewType == ArrayBufferView::TYPE_UINT8_CLAMPED) {
+    if (viewType == Scalar::Uint8Clamped) {
         toWrite = MClampToUint8::New(alloc(), value);
         current->add(toWrite->toInstruction());
     }
 
     MInstruction *store = MStoreTypedArrayElementStatic::New(alloc(), tarr, ptr, toWrite);
     current->add(store);
     current->push(value);
 
@@ -7824,17 +7824,17 @@ IonBuilder::setElemTryTypedStatic(bool *
 }
 
 bool
 IonBuilder::setElemTryTypedArray(bool *emitted, MDefinition *object,
                                  MDefinition *index, MDefinition *value)
 {
     JS_ASSERT(*emitted == false);
 
-    ScalarTypeDescr::Type arrayType;
+    Scalar::Type arrayType;
     if (!ElementAccessIsTypedArray(object, index, &arrayType))
         return true;
 
     // Emit typed setelem variant.
     if (!jsop_setelem_typed(arrayType, SetElem_Normal, object, index, value))
         return false;
 
     *emitted = true;
@@ -8048,18 +8048,17 @@ IonBuilder::jsop_setelem_dense(types::Te
     if (elementType != MIRType_None && packed)
         store->setElementType(elementType);
 
     return true;
 }
 
 
 bool
-IonBuilder::jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
-                               SetElemSafety safety,
+IonBuilder::jsop_setelem_typed(Scalar::Type arrayType, SetElemSafety safety,
                                MDefinition *obj, MDefinition *id, MDefinition *value)
 {
     bool expectOOB;
     if (safety == SetElem_Normal) {
         SetElemICInspector icInspect(inspector->setElemICInspector(pc));
         expectOOB = icInspect.sawOOBTypedArrayWrite();
     } else {
         expectOOB = false;
@@ -8078,17 +8077,17 @@ IonBuilder::jsop_setelem_typed(ScalarTyp
     MInstruction *elements;
     BoundsChecking checking = (!expectOOB && safety == SetElem_Normal)
                               ? DoBoundsCheck
                               : SkipBoundsCheck;
     addTypedArrayLengthAndData(obj, checking, &id, &length, &elements);
 
     // Clamp value to [0, 255] for Uint8ClampedArray.
     MDefinition *toWrite = value;
-    if (arrayType == ScalarTypeDescr::TYPE_UINT8_CLAMPED) {
+    if (arrayType == Scalar::Uint8Clamped) {
         toWrite = MClampToUint8::New(alloc(), value);
         current->add(toWrite->toInstruction());
     }
 
     // Store the value.
     MInstruction *ins;
     if (expectOOB) {
         ins = MStoreTypedArrayElementHole::New(alloc(), elements, length, id, toWrite, arrayType);
@@ -8104,19 +8103,17 @@ IonBuilder::jsop_setelem_typed(ScalarTyp
 
     if (safety == SetElem_Normal)
         current->push(value);
 
     return resumeAfter(ins);
 }
 
 bool
-IonBuilder::jsop_setelem_typed_object(ScalarTypeDescr::Type arrayType,
-                                      SetElemSafety safety,
-                                      bool racy,
+IonBuilder::jsop_setelem_typed_object(Scalar::Type arrayType, SetElemSafety safety, bool racy,
                                       MDefinition *object, MDefinition *index, MDefinition *value)
 {
     JS_ASSERT(safety == SetElem_Unsafe); // Can be fixed, but there's been no reason to as of yet
 
     MInstruction *int_index = MToInt32::New(alloc(), index);
     current->add(int_index);
 
     size_t elemSize = ScalarTypeDescr::alignment(arrayType);
@@ -8593,16 +8590,20 @@ IonBuilder::jsop_getprop(PropertyName *n
     bool emitted = false;
 
     MDefinition *obj = current->pop();
 
     // Try to optimize arguments.length.
     if (!getPropTryArgumentsLength(&emitted, obj) || emitted)
         return emitted;
 
+    // Try to optimize arguments.callee.
+    if (!getPropTryArgumentsCallee(&emitted, obj, name) || emitted)
+        return emitted;
+
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
     BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
                                                        obj, name, types);
 
     // Always use a call if we are performing analysis and
     // not actually emitting code, to simplify later analysis. Also skip deeper
     // analysis if there are no known types for this operation, as it will
     // always invalidate when executing.
@@ -8657,27 +8658,44 @@ IonBuilder::jsop_getprop(PropertyName *n
     current->push(call);
     if (!resumeAfter(call))
         return false;
 
     return pushTypeBarrier(call, types, BarrierKind::TypeSet);
 }
 
 bool
-IonBuilder::getPropTryArgumentsLength(bool *emitted, MDefinition *obj)
-{
-    JS_ASSERT(*emitted == false);
+IonBuilder::checkIsDefinitelyOptimizedArguments(MDefinition *obj, bool *isOptimizedArgs)
+{
     if (obj->type() != MIRType_MagicOptimizedArguments) {
         if (script()->argumentsHasVarBinding() &&
             obj->mightBeType(MIRType_MagicOptimizedArguments))
         {
             return abort("Type is not definitely lazy arguments.");
         }
-        return true;
-    }
+
+        *isOptimizedArgs = false;
+        return true;
+    }
+
+    *isOptimizedArgs = true;
+    return true;
+}
+
+bool
+IonBuilder::getPropTryArgumentsLength(bool *emitted, MDefinition *obj)
+{
+    JS_ASSERT(*emitted == false);
+
+    bool isOptimizedArgs = false;
+    if (!checkIsDefinitelyOptimizedArguments(obj, &isOptimizedArgs))
+        return false;
+    if (!isOptimizedArgs)
+        return true;
+
     if (JSOp(*pc) != JSOP_LENGTH)
         return true;
 
     *emitted = true;
 
     obj->setImplicitlyUsedUnchecked();
 
     // We don't know anything from the callee
@@ -8688,16 +8706,37 @@ IonBuilder::getPropTryArgumentsLength(bo
         return true;
     }
 
     // We are inlining and know the number of arguments the callee pushed
     return pushConstant(Int32Value(inlineCallInfo_->argv().length()));
 }
 
 bool
+IonBuilder::getPropTryArgumentsCallee(bool *emitted, MDefinition *obj, PropertyName *name)
+{
+    JS_ASSERT(*emitted == false);
+
+    bool isOptimizedArgs = false;
+    if (!checkIsDefinitelyOptimizedArguments(obj, &isOptimizedArgs))
+        return false;
+    if (!isOptimizedArgs)
+        return true;
+
+    if (name != names().callee)
+        return true;
+
+    obj->setImplicitlyUsedUnchecked();
+    current->push(getCallee());
+
+    *emitted = true;
+    return true;
+}
+
+bool
 IonBuilder::getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *name,
                                types::TemporaryTypeSet *types)
 {
     JS_ASSERT(*emitted == false);
     JSObject *singleton = types ? types->getSingleton() : nullptr;
     if (!singleton)
         return true;
 
@@ -8765,17 +8804,17 @@ IonBuilder::getPropTryTypedObject(bool *
 
 bool
 IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedObj,
                                               int32_t fieldOffset,
                                               TypedObjectPrediction fieldPrediction,
                                               types::TemporaryTypeSet *resultTypes)
 {
     // Must always be loading the same scalar type
-    ScalarTypeDescr::Type fieldType = fieldPrediction.scalarType();
+    Scalar::Type fieldType = fieldPrediction.scalarType();
 
     // OK, perform the optimization.
     return pushScalarLoadFromTypedObject(emitted, typedObj, constantInt(fieldOffset),
                                          fieldType, true);
 }
 
 bool
 IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
@@ -9400,17 +9439,17 @@ IonBuilder::setPropTryTypedObject(bool *
 bool
 IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
                                               MDefinition *obj,
                                               int32_t fieldOffset,
                                               MDefinition *value,
                                               TypedObjectPrediction fieldPrediction)
 {
     // Must always be loading the same scalar type
-    ScalarTypeDescr::Type fieldType = fieldPrediction.scalarType();
+    Scalar::Type fieldType = fieldPrediction.scalarType();
 
     // OK! Perform the optimization.
 
     if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldType, true, false, value))
         return false;
 
     current->push(value);
 
@@ -10465,17 +10504,17 @@ IonBuilder::storeScalarTypedObjectValue(
     // Find location within the owner object.
     MDefinition *elements, *scaledOffset;
     size_t alignment = ScalarTypeDescr::alignment(type);
     loadTypedObjectElements(typedObj, byteOffset, alignment, canBeNeutered,
                             &elements, &scaledOffset);
 
     // Clamp value to [0, 255] when type is Uint8Clamped
     MDefinition *toWrite = value;
-    if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED) {
+    if (type == Scalar::Uint8Clamped) {
         toWrite = MClampToUint8::New(alloc(), value);
         current->add(toWrite->toInstruction());
     }
 
     MStoreTypedArrayElement *store =
         MStoreTypedArrayElement::New(alloc(), elements, scaledOffset, toWrite,
                                      type);
     if (racy)
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -376,17 +376,17 @@ class IonBuilder : public MIRGenerator
 
     MDefinition *walkScopeChain(unsigned hops);
 
     MInstruction *addConvertElementsToDoubles(MDefinition *elements);
     MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
     MInstruction *addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bailoutKind);
 
     MDefinition *convertShiftToMaskForStaticTypedArray(MDefinition *id,
-                                                       ArrayBufferView::ViewType viewType);
+                                                       Scalar::Type viewType);
 
     bool invalidatedIdempotentCache();
 
     bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall);
     bool loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType,
                   BarrierKind barrier, types::TemporaryTypeSet *types);
     bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
                   BarrierKind barrier, types::TemporaryTypeSet *types);
@@ -394,17 +394,19 @@ class IonBuilder : public MIRGenerator
                    MDefinition *value, bool needsBarrier,
                    MIRType slotType = MIRType_None);
     bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
                    MIRType slotType = MIRType_None);
 
     MDefinition *tryInnerizeWindow(MDefinition *obj);
 
     // jsop_getprop() helpers.
+    bool checkIsDefinitelyOptimizedArguments(MDefinition *obj, bool *isOptimizedArgs);
     bool getPropTryArgumentsLength(bool *emitted, MDefinition *obj);
+    bool getPropTryArgumentsCallee(bool *emitted, MDefinition *obj, PropertyName *name);
     bool getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *name,
                             types::TemporaryTypeSet *types);
     bool getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName *name,
                                 BarrierKind barrier, types::TemporaryTypeSet *types);
     bool getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName *name,
                                 types::TemporaryTypeSet *types);
     bool getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName *name,
                                 BarrierKind barrier, types::TemporaryTypeSet *types);
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1078,17 +1078,17 @@ GenerateTypedArrayLength(JSContext *cx, 
     }
     JS_ASSERT(object != tmpReg);
 
     // Implement the negated version of JSObject::isTypedArray predicate.
     masm.loadObjClass(object, tmpReg);
     masm.branchPtr(Assembler::Below, tmpReg, ImmPtr(&TypedArrayObject::classes[0]),
                    &failures);
     masm.branchPtr(Assembler::AboveOrEqual, tmpReg,
-                   ImmPtr(&TypedArrayObject::classes[ScalarTypeDescr::TYPE_MAX]),
+                   ImmPtr(&TypedArrayObject::classes[Scalar::TypeMax]),
                    &failures);
 
     // Load length.
     masm.loadTypedOrValue(Address(object, TypedArrayObject::lengthOffset()), output);
 
     /* Success. */
     attacher.jumpRejoin(masm);
 
@@ -3169,37 +3169,34 @@ GetElementIC::canAttachTypedArrayElement
             return false;
     }
     if (index >= obj->as<TypedArrayObject>().length())
         return false;
 
     // The output register is not yet specialized as a float register, the only
     // way to accept float typed arrays for now is to return a Value type.
     uint32_t arrayType = obj->as<TypedArrayObject>().type();
-    if (arrayType == ScalarTypeDescr::TYPE_FLOAT32 ||
-        arrayType == ScalarTypeDescr::TYPE_FLOAT64)
-    {
+    if (arrayType == Scalar::Float32 || arrayType == Scalar::Float64)
         return output.hasValue();
-    }
 
     return output.hasValue() || !output.typedReg().isFloat();
 }
 
 static void
 GenerateGetTypedArrayElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                              HandleTypedArrayObject tarr, const Value &idval, Register object,
                              ConstantOrRegister index, TypedOrValueRegister output,
                              bool allowDoubleResult)
 {
     JS_ASSERT(GetElementIC::canAttachTypedArrayElement(tarr, idval, output));
 
     Label failures;
 
     // The array type is the object within the table of typed array classes.
-    int arrayType = tarr->type();
+    Scalar::Type arrayType = tarr->type();
 
     // Guard on the shape.
     Shape *shape = tarr->lastProperty();
     masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
 
     // Decide to what type index the stub should be optimized
     Register tmpReg = output.scratchReg().gpr();
     JS_ASSERT(tmpReg != InvalidReg);
@@ -3262,17 +3259,17 @@ GenerateGetTypedArrayElement(JSContext *
     Register elementReg = object;
     masm.push(object);
 
     // Load elements vector.
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg);
 
     // Load the value. We use an invalid register because the destination
     // register is necessary a non double register.
-    int width = TypedArrayObject::slotWidth(arrayType);
+    int width = Scalar::byteSize(arrayType);
     BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
     if (output.hasValue()) {
         masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult,
                                 elementReg, &popAndFail);
     } else {
         masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popAndFail);
     }
 
@@ -3728,44 +3725,44 @@ GenerateSetTypedArrayElement(JSContext *
     masm.unboxInt32(length, temp);
     masm.branch32(Assembler::BelowOrEqual, temp, index, &done);
 
     // Load the elements vector.
     Register elements = temp;
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elements);
 
     // Set the value.
-    int arrayType = tarr->type();
-    int width = TypedArrayObject::slotWidth(arrayType);
+    Scalar::Type arrayType = tarr->type();
+    int width = Scalar::byteSize(arrayType);
     BaseIndex target(elements, index, ScaleFromElemWidth(width));
 
-    if (arrayType == ScalarTypeDescr::TYPE_FLOAT32) {
+    if (arrayType == Scalar::Float32) {
         FloatRegister ftemp;
         if (LIRGenerator::allowFloat32Optimizations()) {
             JS_ASSERT(tempFloat32 != InvalidFloatReg);
             if (!masm.convertConstantOrRegisterToFloat(cx, value, tempFloat32, &failures))
                 return false;
             ftemp = tempFloat32;
         } else {
             if (!masm.convertConstantOrRegisterToDouble(cx, value, tempDouble, &failures))
                 return false;
             ftemp = tempDouble;
         }
         masm.storeToTypedFloatArray(arrayType, ftemp, target);
-    } else if (arrayType == ScalarTypeDescr::TYPE_FLOAT64) {
+    } else if (arrayType == Scalar::Float64) {
         if (!masm.convertConstantOrRegisterToDouble(cx, value, tempDouble, &failures))
             return false;
         masm.storeToTypedFloatArray(arrayType, tempDouble, target);
     } else {
         // On x86 we only have 6 registers available to use, so reuse the object
         // register to compute the intermediate value to store and restore it
         // afterwards.
         masm.push(object);
 
-        if (arrayType == ScalarTypeDescr::TYPE_UINT8_CLAMPED) {
+        if (arrayType == Scalar::Uint8Clamped) {
             if (!masm.clampConstantOrRegisterToUint8(cx, value, tempDouble, object,
                                                      &popObjectAndFail))
             {
                 return false;
             }
         } else {
             if (!masm.truncateConstantOrRegisterToInt32(cx, value, tempDouble, object,
                                                         &popObjectAndFail))
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -272,127 +272,127 @@ MacroAssembler::moveNurseryPtr(ImmMaybeN
     movePtr(ptr, reg);
 }
 
 template<typename S, typename T>
 static void
 StoreToTypedFloatArray(MacroAssembler &masm, int arrayType, const S &value, const T &dest)
 {
     switch (arrayType) {
-      case ScalarTypeDescr::TYPE_FLOAT32:
+      case Scalar::Float32:
         if (LIRGenerator::allowFloat32Optimizations()) {
             masm.storeFloat32(value, dest);
         } else {
 #ifdef JS_MORE_DETERMINISTIC
             // See the comment in TypedArrayObjectTemplate::doubleToNative.
             masm.canonicalizeDouble(value);
 #endif
             masm.convertDoubleToFloat32(value, ScratchFloat32Reg);
             masm.storeFloat32(ScratchFloat32Reg, dest);
         }
         break;
-      case ScalarTypeDescr::TYPE_FLOAT64:
+      case Scalar::Float64:
 #ifdef JS_MORE_DETERMINISTIC
         // See the comment in TypedArrayObjectTemplate::doubleToNative.
         masm.canonicalizeDouble(value);
 #endif
         masm.storeDouble(value, dest);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid typed array type");
     }
 }
 
 void
-MacroAssembler::storeToTypedFloatArray(int arrayType, FloatRegister value,
+MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value,
                                        const BaseIndex &dest)
 {
     StoreToTypedFloatArray(*this, arrayType, value, dest);
 }
 void
-MacroAssembler::storeToTypedFloatArray(int arrayType, FloatRegister value,
+MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value,
                                        const Address &dest)
 {
     StoreToTypedFloatArray(*this, arrayType, value, dest);
 }
 
 template<typename T>
 void
-MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp,
+MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp,
                                    Label *fail)
 {
     switch (arrayType) {
-      case ScalarTypeDescr::TYPE_INT8:
+      case Scalar::Int8:
         load8SignExtend(src, dest.gpr());
         break;
-      case ScalarTypeDescr::TYPE_UINT8:
-      case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
+      case Scalar::Uint8:
+      case Scalar::Uint8Clamped:
         load8ZeroExtend(src, dest.gpr());
         break;
-      case ScalarTypeDescr::TYPE_INT16:
+      case Scalar::Int16:
         load16SignExtend(src, dest.gpr());
         break;
-      case ScalarTypeDescr::TYPE_UINT16:
+      case Scalar::Uint16:
         load16ZeroExtend(src, dest.gpr());
         break;
-      case ScalarTypeDescr::TYPE_INT32:
+      case Scalar::Int32:
         load32(src, dest.gpr());
         break;
-      case ScalarTypeDescr::TYPE_UINT32:
+      case Scalar::Uint32:
         if (dest.isFloat()) {
             load32(src, temp);
             convertUInt32ToDouble(temp, dest.fpu());
         } else {
             load32(src, dest.gpr());
 
             // Bail out if the value doesn't fit into a signed int32 value. This
             // is what allows MLoadTypedArrayElement to have a type() of
             // MIRType_Int32 for UInt32 array loads.
             branchTest32(Assembler::Signed, dest.gpr(), dest.gpr(), fail);
         }
         break;
-      case ScalarTypeDescr::TYPE_FLOAT32:
+      case Scalar::Float32:
         if (LIRGenerator::allowFloat32Optimizations()) {
             loadFloat32(src, dest.fpu());
             canonicalizeFloat(dest.fpu());
         } else {
             loadFloatAsDouble(src, dest.fpu());
             canonicalizeDouble(dest.fpu());
         }
         break;
-      case ScalarTypeDescr::TYPE_FLOAT64:
+      case Scalar::Float64:
         loadDouble(src, dest.fpu());
         canonicalizeDouble(dest.fpu());
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid typed array type");
     }
 }
 
-template void MacroAssembler::loadFromTypedArray(int arrayType, const Address &src, AnyRegister dest,
+template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const Address &src, AnyRegister dest,
                                                  Register temp, Label *fail);
-template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex &src, AnyRegister dest,
+template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex &src, AnyRegister dest,
                                                  Register temp, Label *fail);
 
 template<typename T>
 void
-MacroAssembler::loadFromTypedArray(int arrayType, const T &src, const ValueOperand &dest,
+MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, const ValueOperand &dest,
                                    bool allowDouble, Register temp, Label *fail)
 {
     switch (arrayType) {
-      case ScalarTypeDescr::TYPE_INT8:
-      case ScalarTypeDescr::TYPE_UINT8:
-      case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
-      case ScalarTypeDescr::TYPE_INT16:
-      case ScalarTypeDescr::TYPE_UINT16:
-      case ScalarTypeDescr::TYPE_INT32:
+      case Scalar::Int8:
+      case Scalar::Uint8:
+      case Scalar::Uint8Clamped:
+      case Scalar::Int16:
+      case Scalar::Uint16:
+      case Scalar::Int32:
         loadFromTypedArray(arrayType, src, AnyRegister(dest.scratchReg()), InvalidReg, nullptr);
         tagValue(JSVAL_TYPE_INT32, dest.scratchReg(), dest);
         break;
-      case ScalarTypeDescr::TYPE_UINT32:
+      case Scalar::Uint32:
         // Don't clobber dest when we could fail, instead use temp.
         load32(src, temp);
         if (allowDouble) {
             // If the value fits in an int32, store an int32 type tag.
             // Else, convert the value to double and box it.
             Label done, isDouble;
             branchTest32(Assembler::Signed, temp, temp, &isDouble);
             {
@@ -406,36 +406,36 @@ MacroAssembler::loadFromTypedArray(int a
             }
             bind(&done);
         } else {
             // Bailout if the value does not fit in an int32.
             branchTest32(Assembler::Signed, temp, temp, fail);
             tagValue(JSVAL_TYPE_INT32, temp, dest);
         }
         break;
-      case ScalarTypeDescr::TYPE_FLOAT32:
+      case Scalar::Float32:
         loadFromTypedArray(arrayType, src, AnyRegister(ScratchFloat32Reg), dest.scratchReg(),
                            nullptr);
         if (LIRGenerator::allowFloat32Optimizations())
             convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
         boxDouble(ScratchDoubleReg, dest);
         break;
-      case ScalarTypeDescr::TYPE_FLOAT64:
+      case Scalar::Float64:
         loadFromTypedArray(arrayType, src, AnyRegister(ScratchDoubleReg), dest.scratchReg(),
                            nullptr);
         boxDouble(ScratchDoubleReg, dest);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid typed array type");
     }
 }
 
-template void MacroAssembler::loadFromTypedArray(int arrayType, const Address &src, const ValueOperand &dest,
+template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const Address &src, const ValueOperand &dest,
                                                  bool allowDouble, Register temp, Label *fail);
-template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex &src, const ValueOperand &dest,
+template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex &src, const ValueOperand &dest,
                                                  bool allowDouble, Register temp, Label *fail);
 
 // Inlined version of gc::CheckAllocatorState that checks the bare essentials
 // and bails for anything that cannot be handled with our jit allocators.
 void
 MacroAssembler::checkAllocatorState(Label *fail)
 {
     // Don't execute the inline path if we are tracing allocations.
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -703,45 +703,45 @@ class MacroAssembler : public MacroAssem
     void canonicalizeFloat(FloatRegister reg) {
         Label notNaN;
         branchFloat(DoubleOrdered, reg, reg, &notNaN);
         loadConstantFloat32(float(JS::GenericNaN()), reg);
         bind(&notNaN);
     }
 
     template<typename T>
-    void loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp, Label *fail);
+    void loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp, Label *fail);
 
     template<typename T>
-    void loadFromTypedArray(int arrayType, const T &src, const ValueOperand &dest, bool allowDouble,
+    void loadFromTypedArray(Scalar::Type arrayType, const T &src, const ValueOperand &dest, bool allowDouble,
                             Register temp, Label *fail);
 
     template<typename S, typename T>
-    void storeToTypedIntArray(int arrayType, const S &value, const T &dest) {
+    void storeToTypedIntArray(Scalar::Type arrayType, const S &value, const T &dest) {
         switch (arrayType) {
-          case ScalarTypeDescr::TYPE_INT8:
-          case ScalarTypeDescr::TYPE_UINT8:
-          case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
+          case Scalar::Int8:
+          case Scalar::Uint8:
+          case Scalar::Uint8Clamped:
             store8(value, dest);
             break;
-          case ScalarTypeDescr::TYPE_INT16:
-          case ScalarTypeDescr::TYPE_UINT16:
+          case Scalar::Int16:
+          case Scalar::Uint16:
             store16(value, dest);
             break;
-          case ScalarTypeDescr::TYPE_INT32:
-          case ScalarTypeDescr::TYPE_UINT32:
+          case Scalar::Int32:
+          case Scalar::Uint32:
             store32(value, dest);
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Invalid typed array type");
         }
     }
 
-    void storeToTypedFloatArray(int arrayType, FloatRegister value, const BaseIndex &dest);
-    void storeToTypedFloatArray(int arrayType, FloatRegister value, const Address &dest);
+    void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const BaseIndex &dest);
+    void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address &dest);
 
     Register extractString(const Address &address, Register scratch) {
         return extractObject(address, scratch);
     }
     Register extractString(const ValueOperand &value, Register scratch) {
         return extractObject(value, scratch);
     }
 
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -414,17 +414,18 @@ class SnapshotIterator
             *rval = read();
         else
             skip();
     }
 
     template <class Op>
     void readFunctionFrameArgs(Op &op, ArgumentsObject **argsObj, Value *thisv,
                                unsigned start, unsigned end, JSScript *script,
-                               const Value &unreadablePlaceholder = UndefinedValue())
+                               const Value &unreadablePlaceholder = UndefinedValue(),
+                               bool silentFailure = false)
     {
         // Assumes that the common frame arguments have already been read.
         if (script->argumentsHasVarBinding()) {
             if (argsObj) {
                 Value v = read();
                 if (v.isObject())
                     *argsObj = &v.toObject().as<ArgumentsObject>();
             } else {
@@ -442,17 +443,17 @@ class SnapshotIterator
             i = start;
 
         for (; i < start; i++)
             skip();
         for (; i < end; i++) {
             // We are not always able to read values from the snapshots, some values
             // such as non-gc things may still be live in registers and cause an
             // error while reading the machine state.
-            Value v = maybeRead(unreadablePlaceholder);
+            Value v = maybeRead(unreadablePlaceholder, silentFailure);
             op(v);
         }
     }
 
     Value maybeReadAllocByIndex(size_t index) {
         while (index--) {
             JS_ASSERT(moreAllocations());
             skip();
@@ -530,17 +531,18 @@ class InlineFrameIterator
         return frame_->numActualArgs();
     }
 
     template <class ArgOp, class LocalOp>
     void readFrameArgsAndLocals(ThreadSafeContext *cx, ArgOp &argOp, LocalOp &localOp,
                                 JSObject **scopeChain, Value *rval,
                                 ArgumentsObject **argsObj, Value *thisv,
                                 ReadFrameArgsBehavior behavior,
-                                const Value &unreadablePlaceholder = UndefinedValue()) const
+                                const Value &unreadablePlaceholder = UndefinedValue(),
+                                bool silentFailure = false) const
     {
         SnapshotIterator s(si_);
 
         // Read frame slots common to both function and global frames.
         Value scopeChainValue;
         s.readCommonFrameSlots(&scopeChainValue, rval);
 
         if (scopeChain)
@@ -551,17 +553,17 @@ class InlineFrameIterator
             unsigned nactual = numActualArgs();
             unsigned nformal = callee()->nargs();
 
             // Get the non overflown arguments, which are taken from the inlined
             // frame, because it will have the updated value when JSOP_SETARG is
             // done.
             if (behavior != ReadFrame_Overflown) {
                 s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, nformal, script(),
-                                        unreadablePlaceholder);
+                                        unreadablePlaceholder, silentFailure);
             }
 
             if (behavior != ReadFrame_Formals) {
                 if (more()) {
                     // There is still a parent frame of this inlined frame.  All
                     // arguments (also the overflown) are the last pushed values
                     // in the parent frame.  To get the overflown arguments, we
                     // need to take them from there.
@@ -600,17 +602,17 @@ class InlineFrameIterator
         // At this point we've read all the formals in s, and can read the
         // locals.
         for (unsigned i = 0; i < script()->nfixed(); i++) {
             // We have to use maybeRead here, some of these might be recover
             // instructions, and currently InlineFrameIter does not support
             // recovering slots.
             //
             // FIXME bug 1029963.
-            localOp(s.maybeRead(unreadablePlaceholder));
+            localOp(s.maybeRead(unreadablePlaceholder, silentFailure));
         }
     }
 
     template <class Op>
     void unaliasedForEachActual(ThreadSafeContext *cx, Op op,
                                 ReadFrameArgsBehavior behavior) const
     {
         Nop nop;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2775,17 +2775,17 @@ LIRGenerator::visitLoadTypedArrayElement
 
     const LUse elements = useRegister(ins->elements());
     const LAllocation index = useRegisterOrConstant(ins->index());
 
     JS_ASSERT(IsNumberType(ins->type()));
 
     // We need a temp register for Uint32Array with known double result.
     LDefinition tempDef = LDefinition::BogusTemp();
-    if (ins->arrayType() == ScalarTypeDescr::TYPE_UINT32 && IsFloatingPointType(ins->type()))
+    if (ins->arrayType() == Scalar::Uint32 && IsFloatingPointType(ins->type()))
         tempDef = temp();
 
     LLoadTypedArrayElement *lir = new(alloc()) LLoadTypedArrayElement(elements, index, tempDef);
     if (ins->fallible() && !assignSnapshot(lir, Bailout_Overflow))
         return false;
     return define(lir, ins);
 }
 
@@ -2851,19 +2851,19 @@ LIRGenerator::visitLoadTypedArrayElement
 bool
 LIRGenerator::visitStoreTypedArrayElement(MStoreTypedArrayElement *ins)
 {
     JS_ASSERT(ins->elements()->type() == MIRType_Elements);
     JS_ASSERT(ins->index()->type() == MIRType_Int32);
 
     if (ins->isFloatArray()) {
         DebugOnly<bool> optimizeFloat32 = allowFloat32Optimizations();
-        JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT32,
+        JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == Scalar::Float32,
                      ins->value()->type() == MIRType_Float32);
-        JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT64,
+        JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == Scalar::Float64,
                      ins->value()->type() == MIRType_Double);
     } else {
         JS_ASSERT(ins->value()->type() == MIRType_Int32);
     }
 
     LUse elements = useRegister(ins->elements());
     LAllocation index = useRegisterOrConstant(ins->index());
     LAllocation value;
@@ -2880,19 +2880,19 @@ bool
 LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins)
 {
     JS_ASSERT(ins->elements()->type() == MIRType_Elements);
     JS_ASSERT(ins->index()->type() == MIRType_Int32);
     JS_ASSERT(ins->length()->type() == MIRType_Int32);
 
     if (ins->isFloatArray()) {
         DebugOnly<bool> optimizeFloat32 = allowFloat32Optimizations();
-        JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT32,
+        JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == Scalar::Float32,
                      ins->value()->type() == MIRType_Float32);
-        JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT64,
+        JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == Scalar::Float64,
                      ins->value()->type() == MIRType_Double);
     } else {
         JS_ASSERT(ins->value()->type() == MIRType_Int32);
     }
 
     LUse elements = useRegister(ins->elements());
     LAllocation length = useAnyOrConstant(ins->length());
     LAllocation index = useRegisterOrConstant(ins->index());
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -219,20 +219,18 @@ IonBuilder::inlineNativeGetter(CallInfo 
 
     types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
     JS_ASSERT(callInfo.argc() == 0);
 
     // Try to optimize typed array lengths. There is one getter for each
     // typed array prototype, and make sure we are accessing the right one
     // for the type of the instance object.
     if (thisTypes) {
-        ScalarTypeDescr::Type type = (ScalarTypeDescr::Type) thisTypes->getTypedArrayType();
-        if (type != ScalarTypeDescr::TYPE_MAX &&
-            TypedArrayObject::isOriginalLengthGetter(type, native))
-        {
+        Scalar::Type type = thisTypes->getTypedArrayType();
+        if (type != Scalar::TypeMax && TypedArrayObject::isOriginalLengthGetter(type, native)) {
             MInstruction *length = addTypedArrayLength(callInfo.thisArg());
             current->push(length);
             return InliningStatus_Inlined;
         }
     }
 
     return InliningStatus_NotInlined;
 }
@@ -1387,17 +1385,17 @@ IonBuilder::inlineUnsafePutElements(Call
         if (isDenseNative) {
             writeNeedsBarrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
                                                               &obj, nullptr, &elem,
                                                               /* canModify = */ false);
         }
 
         // We can only inline setelem on dense arrays that do not need type
         // barriers and on typed arrays and on typed object arrays.
-        ScalarTypeDescr::Type arrayType;
+        Scalar::Type arrayType;
         if ((!isDenseNative || writeNeedsBarrier) &&
             !ElementAccessIsTypedArray(obj, id, &arrayType) &&
             !elementAccessIsTypedObjectArrayOfScalarType(obj, id, &arrayType))
         {
             return InliningStatus_NotInlined;
         }
     }
 
@@ -1417,17 +1415,17 @@ IonBuilder::inlineUnsafePutElements(Call
         MDefinition *id = callInfo.getArg(idxi);
 
         if (ElementAccessIsDenseNative(obj, id)) {
             if (!inlineUnsafeSetDenseArrayElement(callInfo, base))
                 return InliningStatus_Error;
             continue;
         }
 
-        ScalarTypeDescr::Type arrayType;
+        Scalar::Type arrayType;
         if (ElementAccessIsTypedArray(obj, id, &arrayType)) {
             if (!inlineUnsafeSetTypedArrayElement(callInfo, base, arrayType))
                 return InliningStatus_Error;
             continue;
         }
 
         if (elementAccessIsTypedObjectArrayOfScalarType(obj, id, &arrayType)) {
             if (!inlineUnsafeSetTypedObjectArrayElement(callInfo, base, arrayType))
@@ -1438,17 +1436,17 @@ IonBuilder::inlineUnsafePutElements(Call
         MOZ_ASSUME_UNREACHABLE("Element access not dense array nor typed array");
     }
 
     return InliningStatus_Inlined;
 }
 
 bool
 IonBuilder::elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
-                                                        ScalarTypeDescr::Type *arrayType)
+                                                        Scalar::Type *arrayType)
 {
     if (obj->type() != MIRType_Object) // lookupTypeDescrSet() tests for TypedObject
         return false;
 
     if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
         return false;
 
     TypedObjectPrediction prediction = typedObjectPrediction(obj);
@@ -1483,17 +1481,17 @@ IonBuilder::inlineUnsafeSetDenseArrayEle
     if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
         return false;
     return true;
 }
 
 bool
 IonBuilder::inlineUnsafeSetTypedArrayElement(CallInfo &callInfo,
                                              uint32_t base,
-                                             ScalarTypeDescr::Type arrayType)
+                                             Scalar::Type arrayType)
 {
     // Note: we do not check the conditions that are asserted as true
     // in intrinsic_UnsafePutElements():
     // - arr is a typed array
     // - idx < length
 
     MDefinition *obj = callInfo.getArg(base + 0);
     MDefinition *id = callInfo.getArg(base + 1);
@@ -1503,17 +1501,17 @@ IonBuilder::inlineUnsafeSetTypedArrayEle
         return false;
 
     return true;
 }
 
 bool
 IonBuilder::inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo,
                                                    uint32_t base,
-                                                   ScalarTypeDescr::Type arrayType)
+                                                   Scalar::Type arrayType)
 {
     // Note: we do not check the conditions that are asserted as true
     // in intrinsic_UnsafePutElements():
     // - arr is a typed array
     // - idx < length
 
     MDefinition *obj = callInfo.getArg(base + 0);
     MDefinition *id = callInfo.getArg(base + 1);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp