merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 10 Jul 2014 14:47:01 +0200
changeset 193272 6e9f72bdd32ed5533d1f90b75b39ac6dafaf2bb8
parent 193185 41e1a83bd7f7d31fde5c9f52dc707a086f003b84 (current diff)
parent 193271 18ed7626a49b5ef1293d6b327967eadaf956ea04 (diff)
child 193285 9c138b12276d36f4455d04894f6bc3ac2db60952
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone33.0a1
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
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "jit/MIR.h"
 
 #include "mozilla/FloatingPoint.h"
+#include "mozilla/MathAlgorithms.h"
 
 #include <ctype.h>
 
 #include "jslibmath.h"
 #include "jsstr.h"
 
 #include "jit/BaselineInspector.h"
 #include "jit/IonBuilder.h"
@@ -129,16 +130,48 @@ EvaluateConstantOperands(TempAllocator &
         if (ptypeChange)
             *ptypeChange = true;
         return nullptr;
     }
 
     return MConstant::New(alloc, ret);
 }
 
+static MMul *
+EvaluateExactReciprocal(TempAllocator &alloc, MDiv *ins)
+{
+    // we should fold only when it is a floating point operation
+    if (!IsFloatingPointType(ins->type()))
+        return nullptr;
+
+    MDefinition *left = ins->getOperand(0);
+    MDefinition *right = ins->getOperand(1);
+
+    if (!right->isConstant())
+        return nullptr;
+
+    Value rhs = right->toConstant()->value();
+
+    int32_t num;
+    if (!mozilla::NumberIsInt32(rhs.toNumber(), &num))
+        return nullptr;
+
+    // check if rhs is a power of two
+    if (mozilla::Abs(num) & (mozilla::Abs(num) - 1))
+        return nullptr;
+
+    Value ret;
+    ret.setDouble(1.0 / (double) num);
+    MConstant *foldedRhs = MConstant::New(alloc, ret);
+    foldedRhs->setResultType(ins->type());
+    ins->block()->insertBefore(ins, foldedRhs);
+
+    return MMul::New(alloc, left, foldedRhs, ins->type());
+}
+
 void
 MDefinition::printName(FILE *fp) const
 {
     PrintOpcodeName(fp, op());
     fprintf(fp, "%u", id());
 }
 
 HashNumber
@@ -1500,16 +1533,19 @@ MDefinition *
 MDiv::foldsTo(TempAllocator &alloc)
 {</