Merge m-c to b2g-inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 11 Feb 2014 14:59:11 -0500
changeset 168269 562a915cea9cfc51fdfbaaae02ce4b5c501aa488
parent 168268 b9355c4aa0afb042e9160de2165185803298a25a (current diff)
parent 168182 802d87c77e76506e7ff16b285f02d31d73f5c8d9 (diff)
child 168270 b18d742be7eabfc6a159cb6ac79f57f8ad4df487
push id39685
push userryanvm@gmail.com
push dateWed, 12 Feb 2014 13:39:08 +0000
treeherdermozilla-inbound@a523d5b55989 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound.
config/autoconf.mk.in
config/emptyvars.mk.in
content/xml/content/src/Makefile.in
dom/events/test/test_bug432698.html
editor/composer/src/Makefile.in
gfx/layers/opengl/FPSCounter.h
layout/mathml/Makefile.in
toolkit/mozapps/update/common-standalone/Makefile.in
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +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 969164 changes the directory layout under js/src during gecko builds, and that causes a build failure on incremental builds because of the js shell trying to replace a directory with the same name.
+Recent Android build system changes from bug 961339 and bug 946083 seem to be needs-clobbery.
--- a/accessible/public/ia2/Makefile.in
+++ b/accessible/public/ia2/Makefile.in
@@ -1,14 +1,12 @@
 # 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/.
 
-DEFFILE       = $(win_srcdir)/IA2Marshal.def
-
 IA2DIR        = $(topsrcdir)/other-licenses/ia2
 
 GARBAGE       += $(MIDL_GENERATED_FILES)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
--- a/accessible/public/ia2/moz.build
+++ b/accessible/public/ia2/moz.build
@@ -4,8 +4,10 @@
 # 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/.
 
 LIBRARY_NAME = 'IA2Marshal'
 
 FORCE_SHARED_LIB = True
 
 DEFINES['REGISTER_PROXY_DLL'] = True
+
+DEFFILE = SRCDIR + '/IA2Marshal.def'
--- a/accessible/public/msaa/Makefile.in
+++ b/accessible/public/msaa/Makefile.in
@@ -1,14 +1,12 @@
 # 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/.
 
-DEFFILE = $(win_srcdir)/AccessibleMarshal.def
-
 GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
 
 MIDL_GENERATED_FILES = \
 	ISimpleDOMNode.h \
 	ISimpleDOMNode_p.c \
 	ISimpleDOMNode_i.c \
 	ISimpleDOMDocument.h \
 	ISimpleDOMDocument_p.c \
--- a/accessible/public/msaa/moz.build
+++ b/accessible/public/msaa/moz.build
@@ -14,8 +14,10 @@ GENERATED_SOURCES += [
     'ISimpleDOMNode_p.c',
     'ISimpleDOMText_i.c',
     'ISimpleDOMText_p.c',
 ]
 
 FORCE_SHARED_LIB = True
 
 DEFINES['REGISTER_PROXY_DLL'] = True
+
+DEFFILE = SRCDIR + '/AccessibleMarshal.def'
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 #filter substitution
 
-pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.html");
-pref("browser.chromeURL", "chrome://browser/content/");
+pref("toolkit.defaultChromeURI", "chrome://b2g/content/shell.html");
+pref("browser.chromeURL", "chrome://b2g/content/");
 
 // Bug 945235: Prevent all bars to be considered visible:
 pref("toolkit.defaultChromeFeatures", "chrome,dialog=no,close,resizable,scrollbars,extrachrome");
 
 // Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
 pref("browser.viewport.scaleRatio", -1);
 
 /* disable text selection */
@@ -132,19 +132,16 @@ pref("privacy.popups.showBrowserMessage"
 pref("keyword.enabled", true);
 
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.flashBar", 1);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.casesensitive", 0);
 
-// pointer to the default engine name
-pref("browser.search.defaultenginename", "chrome://browser/locale/region.properties");
-
 // SSL error page behaviour
 pref("browser.ssl_override_behavior", 2);
 pref("browser.xul.error_pages.expert_bad_cert", false);
 
 // disable logging for the search service by default
 pref("browser.search.log", false);
 
 // disable updating
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c982426f2ade2fdb8e56304cdd333e7fd924e668
GIT binary patch
literal 246
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Hh8)?hFF}w
zI%zNOAp?O{dnLAnrWV1Vo2|1qFhnZO-oT}OfXVN%QsyQm1J1K2z2+QNlHGIc(#zWS
zbtylp-!k-+@?K!LUdYield#5`N%lg&^9$~k)eo3_j_tByzJ5R@jz2(U9`l2(0xK&&
zx`=u$4n3hRk)WT?YBP1h<(#7;>mCU%^`6=CB&655LYK*`#ic^@gX;;VuzroUu*TaW
tVd^t{i`epvf9(4?Tk5q}<jeN2Y)_oc_He%Ju>rcB!PC{xWt~$(69CB-T~z=8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..859e98ba64b6621aa74d1998242ece6e22ce2dba
GIT binary patch
literal 235
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*D5XdOcknLn>}1{rUgjo>{d)@Fqhsw=}!LR(a33e@{A<`#(q?
zXgOBy@YtS3O3S^Ak-Omsvu2yYqISlBjf_{MnKH6AR<#R8D?BnhBA;<Wt%+?y5{L4>
zj25XPxo(j=);>HUOlnNq-XB+b+AlNX3cpL&BEc1rj8Yjcna9M~IG1D`OFO_AWFqXt
feuSZcftg|b_Xx?Q*F*jT9me44>gTe~DWM4f+X7Dh
--- a/b2g/chrome/content/netError.css
+++ b/b2g/chrome/content/netError.css
@@ -42,34 +42,34 @@ li {
   background-color: #EFD400;
 }
 
 #errorPage.blockedsite {
   background-color: #BF0000;
 }
 
 #errorTitle {
-  background: url("chrome://browser/content/images/errorpage-warning.png") left center no-repeat;
+  background: url("chrome://b2g/content/images/errorpage-warning.png") left center no-repeat;
   /* Scaled by .666 of their actual size */
   background-size: 40px 40px;
   background-origin: content-box;
   min-height: 60px;
   margin-left: auto;
   margin-right: auto;
   max-width: 500px;
   margin-left: auto;
   margin-right: auto;
 }
 
 #errorPage.certerror #errorTitle {
-  background-image: url("chrome://browser/content/images/errorpage-larry-black.png");
+  background-image: url("chrome://b2g/content/images/errorpage-larry-black.png");
 }
 
 #errorPage.blockedsite #errorTitle {
-  background-image: url("chrome://browser/content/images/errorpage-larry-white.png");
+  background-image: url("chrome://b2g/content/images/errorpage-larry-white.png");
   color: white;
 }
 
 .errorTitleText {
   padding: 0px 0px 0px 50px;
   display: inline-block;
   vertical-align: middle
 }
@@ -102,28 +102,28 @@ li {
 }
 
 #securityOverrideDiv {
   padding-top: 10px;
 }
 
 div[collapsed] {
   padding-left: 15px;
-  background-image: url("chrome://browser/skin/images/arrowright-16.png");
+  background-image: url("chrome://b2g/content/images/arrowright-16.png");
   background-size: 11px 11px;
   background-repeat: no-repeat;
   background-position: left 0.3em;
 }
 
 div[collapsed="true"] {
-  background-image: url("chrome://browser/skin/images/arrowright-16.png");
+  background-image: url("chrome://b2g/content/images/arrowright-16.png");
 }
 
 div[collapsed="false"] {
-  background-image: url("chrome://browser/skin/images/arrowdown-16.png");
+  background-image: url("chrome://b2g/content/images/arrowdown-16.png");
 }
 
 div[collapsed="true"] > p,
 div[collapsed="true"] > div {
   display: none;
 }
 
 button {
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -219,17 +219,17 @@ Components.utils.import('resource://gre/
 
 // =================== DevTools ====================
 
 let devtoolsWidgetPanel;
 SettingsListener.observe('devtools.overlay', false, (value) => {
   if (value) {
     if (!devtoolsWidgetPanel) {
       let scope = {};
-      Services.scriptloader.loadSubScript('chrome://browser/content/devtools.js', scope);
+      Services.scriptloader.loadSubScript('chrome://b2g/content/devtools.js', scope);
       devtoolsWidgetPanel = scope.devtoolsWidgetPanel;
     }
     devtoolsWidgetPanel.init();
   } else {
     if (devtoolsWidgetPanel) {
       devtoolsWidgetPanel.uninit();
     }
   }
--- a/b2g/chrome/content/shell.html
+++ b/b2g/chrome/content/shell.html
@@ -9,30 +9,30 @@
 #ifdef ANDROID
       sizemode="fullscreen"
 #endif
       style="background: black; overflow: hidden; width:100%; height:100%; padding: 0px !important"
       onunload="shell.stop();">
 
 <head>
   <script type="application/javascript;version=1.8"
-          src="chrome://browser/content/settings.js"> </script>
+          src="chrome://b2g/content/settings.js"> </script>
   <script type="application/javascript;version=1.8"
-          src="chrome://browser/content/shell.js"> </script>
+          src="chrome://b2g/content/shell.js"> </script>
 
 #ifndef MOZ_WIDGET_GONK
   <!-- various task that has to happen only on desktop -->
   <script type="application/javascript;version=1.8"
-          src="chrome://browser/content/desktop.js"> </script>
+          src="chrome://b2g/content/desktop.js"> </script>
   <!-- this script handles the screen argument for desktop builds -->
   <script type="application/javascript;version=1.8"
-          src="chrome://browser/content/screen.js"> </script>
+          src="chrome://b2g/content/screen.js"> </script>
   <!-- this script handles the "runapp" argument for desktop builds -->
   <script type="application/javascript;version=1.8"
-          src="chrome://browser/content/runapp.js"> </script>
+          src="chrome://b2g/content/runapp.js"> </script>
 #endif
 </head>
   <body id="container" style="margin: 0px; width:100%; height:100%;">
 #ifdef MOZ_WIDGET_COCOA
     <!--
      If the document is empty at startup, we don't display the window
      at all on Mac OS...
     -->
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1091,17 +1091,17 @@ let RemoteDebugger = {
     if (!DebuggerServer.initialized) {
       // Ask for remote connections.
       DebuggerServer.init(this.prompt.bind(this));
 
       // Add Firefox-specific actors, but prevent tab actors to be loaded in
       // the parent process, unless we enable certified apps debugging.
       let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
       DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
-      DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
+      DebuggerServer.addActors('chrome://b2g/content/dbg-browser-actors.js');
 
 #ifdef MOZ_WIDGET_GONK
       DebuggerServer.onConnectionChange = function(what) {
         AdbController.updateState();
       }
 #endif
     }
 
--- a/b2g/chrome/content/touchcontrols.css
+++ b/b2g/chrome/content/touchcontrols.css
@@ -32,47 +32,47 @@
 .muteButton {
   -moz-appearance: none;
   min-height: 42px;
   min-width: 42px;
   border: none !important;
 }
 
 .fullscreenButton {
-  background: url("chrome://browser/content/images/fullscreen-hdpi.png") no-repeat center;
+  background: url("chrome://b2g/content/images/fullscreen-hdpi.png") no-repeat center;
 }
 
 .fullscreenButton[fullscreened="true"] {
-  background: url("chrome://browser/content/images/exitfullscreen-hdpi.png") no-repeat center;
+  background: url("chrome://b2g/content/images/exitfullscreen-hdpi.png") no-repeat center;
 }
 
 .playButton {
-  background: url("chrome://browser/content/images/pause-hdpi.png") no-repeat center;
+  background: url("chrome://b2g/content/images/pause-hdpi.png") no-repeat center;
 }
 
 /*
  * Normally the button bar has fullscreen spacer play spacer mute, but if
  * this is an audio control rather than a video control, the fullscreen button
  * is hidden by videocontrols.xml, and that alters the position of the
  * play button.  This workaround moves it back to center.
  */
 .controlBar.audio-only .playButton {
   transform: translateX(28px);
 }
 
 .playButton[paused="true"] {
-  background: url("chrome://browser/content/images/play-hdpi.png") no-repeat center;
+  background: url("chrome://b2g/content/images/play-hdpi.png") no-repeat center;
 }
 
 .muteButton {
-  background: url("chrome://browser/content/images/mute-hdpi.png") no-repeat center;
+  background: url("chrome://b2g/content/images/mute-hdpi.png") no-repeat center;
 }
 
 .muteButton[muted="true"] {
-  background: url("chrome://browser/content/images/unmute-hdpi.png") no-repeat center;
+  background: url("chrome://b2g/content/images/unmute-hdpi.png") no-repeat center;
 }
 
 /* bars */
 .scrubberStack {
   width: 100%;
   min-height: 32px;
   max-height: 32px;
   padding: 0px 8px;
@@ -116,17 +116,17 @@
   margin-left: -16px;
   margin-right: -16px;
 }
 
 .scrubber .scale-thumb {
   display: -moz-box;
   margin: 0px !important;
   padding: 0px !important;
-  background: url("chrome://browser/content/images/scrubber-hdpi.png") no-repeat;
+  background: url("chrome://b2g/content/images/scrubber-hdpi.png") no-repeat;
   background-size: 32px 32px;
   height: 32px;
   width: 32px;
 }
 
 .durationBox {
   -moz-box-orient: horizontal;
   -moz-box-pack: start;
@@ -149,21 +149,21 @@
 
 .statusIcon {
   margin-bottom: 28px;
   width: 36px;
   height: 36px;
 }
 
 .statusIcon[type="throbber"] {
-  background: url("chrome://browser/content/images/throbber.png") no-repeat center;
+  background: url("chrome://b2g/content/images/throbber.png") no-repeat center;
 }
 
 .statusIcon[type="error"] {
-  background: url("chrome://browser/content/images/error.png") no-repeat center;
+  background: url("chrome://b2g/content/images/error.png") no-repeat center;
 }
 
 /* CSS Transitions */
 .controlBar:not([immediate]) {
   -moz-transition-property: opacity;
   -moz-transition-duration: 200ms;
 }
 
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -1,17 +1,17 @@
 #filter substitution
 # 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/.
 
 
 chrome.jar:
 % content branding %content/branding/
-% content browser %content/
+% content b2g %content/
 
   content/arrow.svg                     (content/arrow.svg)
 * content/dbg-browser-actors.js         (content/dbg-browser-actors.js)
 * content/settings.js                   (content/settings.js)
 * content/shell.html                    (content/shell.html)
 * content/shell.js                      (content/shell.js)
   content/devtools.js                   (content/devtools.js)
 #ifndef ANDROID
@@ -20,26 +20,28 @@ chrome.jar:
   content/runapp.js                     (content/runapp.js)
 #endif
 * content/content.css                   (content/content.css)
   content/touchcontrols.css             (content/touchcontrols.css)
 
 * content/payment.js                    (content/payment.js)
   content/identity.js                   (content/identity.js)
 
-% override chrome://global/skin/media/videocontrols.css chrome://browser/content/touchcontrols.css
-% override chrome://global/content/aboutCertError.xhtml chrome://browser/content/aboutCertError.xhtml
-% override chrome://global/skin/netError.css chrome://browser/content/netError.css
+% override chrome://global/skin/media/videocontrols.css chrome://b2g/content/touchcontrols.css
+% override chrome://global/content/aboutCertError.xhtml chrome://b2g/content/aboutCertError.xhtml
+% override chrome://global/skin/netError.css chrome://b2g/content/netError.css
 
   content/ErrorPage.js                  (content/ErrorPage.js)
   content/aboutCertError.xhtml          (content/aboutCertError.xhtml)
   content/netError.css                  (content/netError.css)
   content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png)
   content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png)
   content/images/errorpage-warning.png (content/images/errorpage-warning.png)
+  content/images/arrowdown-16.png      (content/images/arrowdown-16.png)
+  content/images/arrowright-16.png     (content/images/arrowright-16.png)
   content/images/scrubber-hdpi.png     (content/images/scrubber-hdpi.png)
   content/images/unmute-hdpi.png       (content/images/unmute-hdpi.png)
   content/images/pause-hdpi.png        (content/images/pause-hdpi.png)
   content/images/play-hdpi.png         (content/images/play-hdpi.png)
   content/images/mute-hdpi.png         (content/images/mute-hdpi.png)
   content/images/fullscreen-hdpi.png     (content/images/fullscreen-hdpi.png)
   content/images/exitfullscreen-hdpi.png (content/images/exitfullscreen-hdpi.png)
   content/images/throbber.png          (content/images/throbber.png)
--- a/b2g/chrome/moz.build
+++ b/b2g/chrome/moz.build
@@ -1,13 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE']
-DEFINES['PACKAGE'] = 'browser'
+DEFINES['PACKAGE'] = 'b2g'
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 
 JAR_MANIFESTS += ['jar.mn']
 
 TEST_DIRS += ['content/test/mochitest']
--- a/b2g/components/B2GAboutRedirector.js
+++ b/b2g/components/B2GAboutRedirector.js
@@ -16,17 +16,17 @@ function netErrorURL() {
   try {
     uri = Services.prefs.getCharPref("b2g.neterror.url");
   } catch(e) {}
   return uri;
 }
 
 let modules = {
   certerror: {
-    uri: "chrome://browser/content/aboutCertError.xhtml",
+    uri: "chrome://b2g/content/aboutCertError.xhtml",
     privileged: false,
     hide: true
   },
   neterror: {
     uri: netErrorURL(),
     privileged: false,
     hide: true
   }
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -1,10 +1,10 @@
 # Scrollbars
-category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
+category agent-style-sheets browser-content-stylesheet chrome://b2g/content/content.css
 
 # AlertsService.js
 component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js
 contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9}
 
 # ContentPermissionPrompt.js
 component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js
 contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467}
--- a/b2g/components/ErrorPage.jsm
+++ b/b2g/components/ErrorPage.jsm
@@ -4,17 +4,17 @@
 
 'use strict';
 
 this.EXPORTED_SYMBOLS = ['ErrorPage'];
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
-const kErrorPageFrameScript = 'chrome://browser/content/ErrorPage.js';
+const kErrorPageFrameScript = 'chrome://b2g/content/ErrorPage.js';
 
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "CertOverrideService", function () {
   return Cc["@mozilla.org/security/certoverride;1"]
          .getService(Ci.nsICertOverrideService);
 });
--- a/b2g/components/PaymentGlue.js
+++ b/b2g/components/PaymentGlue.js
@@ -6,17 +6,17 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 // JS shim that contains the callback functions to be triggered from the
 // payment provider's code in order to fire DOMRequest events.
-const kPaymentShimFile = "chrome://browser/content/payment.js";
+const kPaymentShimFile = "chrome://b2g/content/payment.js";
 
 // Type of MozChromEvents to handle payment dialogs.
 const kOpenPaymentConfirmationEvent = "open-payment-confirmation-dialog";
 const kOpenPaymentFlowEvent = "open-payment-flow-dialog";
 
 const PREF_DEBUG = "dom.payment.debug";
 
 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
--- a/b2g/components/SignInToWebsite.jsm
+++ b/b2g/components/SignInToWebsite.jsm
@@ -95,17 +95,17 @@ let kPersonaUri = "https://firefoxos.per
 try {
   kPersonaUri = Services.prefs.getCharPref("toolkit.identity.uri");
 } catch(noSuchPref) {
   // stick with the default value
 }
 
 // JS shim that contains the callback functions that
 // live within the identity UI provisioning frame.
-const kIdentityShimFile = "chrome://browser/content/identity.js";
+const kIdentityShimFile = "chrome://b2g/content/identity.js";
 
 // Type of MozChromeEvents to handle id dialogs.
 const kOpenIdentityDialog = "id-dialog-open";
 const kDoneIdentityDialog = "id-dialog-done";
 const kCloseIdentityDialog = "id-dialog-close-iframe";
 
 // Observer messages to communicate to shim
 const kIdentityDelegateWatch = "identity-delegate-watch";
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1147,16 +1147,17 @@ pref("devtools.profiler.ui.show-platform
 
 // Enable the Network Monitor
 pref("devtools.netmonitor.enabled", true);
 
 // The default Network Monitor UI settings
 pref("devtools.netmonitor.panes-network-details-width", 450);
 pref("devtools.netmonitor.panes-network-details-height", 450);
 pref("devtools.netmonitor.statistics", true);
+pref("devtools.netmonitor.filters", "[\"all\"]");
 
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
 pref("devtools.tilt.intro_transition", true);
 pref("devtools.tilt.outro_transition", true);
 
 // Scratchpad settings
 // - recentFileMax: The maximum number of recently-opened files
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -182,17 +182,17 @@ gImageView.getCellText = function(row, c
   return value || "";
 };
 
 gImageView.onPageMediaSort = function(columnname) {
   var tree = document.getElementById(this.treeid);
   var treecol = tree.columns.getNamedColumn(columnname);
 
   var comparator;
-  if (treecol.index == COL_IMAGE_SIZE) {
+  if (treecol.index == COL_IMAGE_SIZE || treecol.index == COL_IMAGE_COUNT) {
     comparator = function numComparator(a, b) { return a - b; };
   } else {
     comparator = function textComparator(a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); };
   }
 
   this.sortdir =
     gTreeUtils.sort(
       tree,
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -686,17 +686,18 @@ NetworkEventsHandler.prototype = {
 let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
 
 /**
  * Shortcuts for accessing various network monitor preferences.
  */
 let Prefs = new ViewHelpers.Prefs("devtools.netmonitor", {
   networkDetailsWidth: ["Int", "panes-network-details-width"],
   networkDetailsHeight: ["Int", "panes-network-details-height"],
-  statistics: ["Bool", "statistics"]
+  statistics: ["Bool", "statistics"],
+  filters: ["Json", "filters"]
 });
 
 /**
  * Returns true if this is document is in RTL mode.
  * @return boolean
  */
 XPCOMUtils.defineLazyGetter(window, "isRTL", function() {
   return window.getComputedStyle(document.documentElement, null).direction == "rtl";
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -333,17 +333,19 @@ RequestsMenuView.prototype = Heritage.ex
   initialize: function() {
     dumpn("Initializing the RequestsMenuView");
 
     this.widget = new SideMenuWidget($("#requests-menu-contents"));
     this._splitter = $("#network-inspector-view-splitter");
     this._summary = $("#requests-menu-network-summary-label");
     this._summary.setAttribute("value", L10N.getStr("networkMenu.empty"));
 
+    Prefs.filters.forEach(type => this.filterOn(type));
     this.sortContents(this._byTiming);
+
     this.allowFocusOnRightClick = true;
     this.maintainSelectionVisible = true;
     this.widget.autoscrollWithAppendedItems = true;
 
     this.widget.addEventListener("select", this._onSelect, false);
     this._splitter.addEventListener("mousemove", this._onResize, false);
     window.addEventListener("resize", this._onResize, false);
 
@@ -381,16 +383,18 @@ RequestsMenuView.prototype = Heritage.ex
   },
 
   /**
    * Destruction function, called when the network monitor is closed.
    */
   destroy: function() {
     dumpn("Destroying the SourcesView");
 
+    Prefs.filters = this._activeFilters;
+
     this.widget.removeEventListener("select", this._onSelect, false);
     this._splitter.removeEventListener("mousemove", this._onResize, false);
     window.removeEventListener("resize", this._onResize, false);
 
     $("#toolbar-labels").removeEventListener("click", this.requestsMenuSortEvent, false);
     $("#requests-menu-footer").removeEventListener("click", this.requestsMenuFilterEvent, false);
     $("#requests-menu-clear-button").removeEventListener("click", this.reqeustsMenuClearEvent, false);
     $("#network-request-popup").removeEventListener("popupshowing", this._onContextShowing, false);
@@ -409,17 +413,16 @@ RequestsMenuView.prototype = Heritage.ex
     $("#headers-summary-resend").removeEventListener("click", this.cloneSelectedRequestEvent, false);
   },
 
   /**
    * Resets this container (removes all the networking information).
    */
   reset: function() {
     this.empty();
-    this.filterOn("all");
     this._firstRequestStartedMillis = -1;
     this._lastRequestEndedMillis = -1;
   },
 
   /**
    * Specifies if this view may be updated lazily.
    */
   lazyUpdate: true,
@@ -583,34 +586,46 @@ RequestsMenuView.prototype = Heritage.ex
     }
 
     this.filterContents(this._filterPredicate);
     this.refreshSummary();
     this.refreshZebra();
   },
 
   /**
+   * Same as `filterOn`, except that it only allows a single type exclusively.
+   *
+   * @param string aType
+   *        @see RequestsMenuView.prototype.fitlerOn
+   */
+  filterOnlyOn: function(aType = "all") {
+    this._activeFilters.slice().forEach(this._disableFilter, this);
+    this.filterOn(aType);
+  },
+
+  /**
    * Disables the given filter, its button and toggles 'all' on if the filter to
    * be disabled is the last one active.
    *
    * @param string aType
    *        Either "all", "html", "css", "js", "xhr", "fonts", "images", "media"
    *        "flash" or "other".
    */
   _disableFilter: function (aType) {
     // Remove the filter from list of active filters.
     this._activeFilters.splice(this._activeFilters.indexOf(aType), 1);
 
     // Remove the checked status from the filter.
     let target = $("#requests-menu-filter-" + aType + "-button");
     target.removeAttribute("checked");
 
     // Check if the filter disabled was the last one. If so, toggle all on.
-    if (this._activeFilters.length === 0)
+    if (this._activeFilters.length === 0) {
       this._enableFilter("all");
+    }
   },
 
   /**
    * Enables the given filter, its button and toggles 'all' off if the filter to
    * be enabled is the first one active.
    *
    * @param string aType
    *        Either "all", "html", "css", "js", "xhr", "fonts", "images", "media"
@@ -2456,17 +2471,17 @@ PerformanceStatisticsView.prototype = {
       title: L10N.getStr(title),
       data: data,
       strings: strings,
       totals: totals,
       sorted: sorted
     });
 
     chart.on("click", (_, item) => {
-      NetMonitorView.RequestsMenu.filterOn(item.label);
+      NetMonitorView.RequestsMenu.filterOnlyOn(item.label);
       NetMonitorView.showNetworkInspectorView();
     });
 
     container.appendChild(chart.node);
   },
 
   /**
    * Sanitizes the data source used for creating charts, to follow the
--- a/browser/devtools/netmonitor/netmonitor.css
+++ b/browser/devtools/netmonitor/netmonitor.css
@@ -34,23 +34,16 @@
   #details-pane-toggle,
   #details-pane[pane-collapsed],
   .requests-menu-waterfall,
   .requests-menu-footer-label {
     display: none;
   }
 }
 
-@media (min-width: 701px) and (max-width: 1280px) {
-  #body:not([pane-collapsed]) .requests-menu-filter-button,
-  #body:not([pane-collapsed]) .requests-menu-footer-spacer {
-    display: none;
-  }
-}
-
 @media (min-width: 701px) {
   #network-table[waterfall-overflows] .requests-menu-waterfall {
     display: none;
   }
 
   #network-table[size-overflows] .requests-menu-size {
     display: none;
   }
--- a/browser/devtools/netmonitor/netmonitor.xul
+++ b/browser/devtools/netmonitor/netmonitor.xul
@@ -38,139 +38,391 @@
       <menuitem id="request-menu-context-perf"
                 label="&netmonitorUI.context.perfTools;"
                 accesskey="&netmonitorUI.context.perfTools.accesskey;"/>
     </menupopup>
   </popupset>
 
   <deck id="body" class="theme-sidebar" flex="1">
 
-  <box id="network-inspector-view" class="devtools-responsive-container">
-    <vbox id="network-table" flex="1">
-      <toolbar id="requests-menu-toolbar"
-               class="devtools-toolbar"
-               align="center">
-        <hbox id="toolbar-labels" flex="1">
-          <hbox id="requests-menu-status-and-method-header-box"
-                class="requests-menu-header requests-menu-status-and-method"
-                align="center">
-            <button id="requests-menu-status-button"
-                    class="requests-menu-header-button requests-menu-status"
-                    data-key="status"
-                    label="&netmonitorUI.toolbar.status2;">
-            </button>
-            <button id="requests-menu-method-button"
-                    class="requests-menu-header-button requests-menu-method"
-                    data-key="method"
-                    label="&netmonitorUI.toolbar.method;"
-                    flex="1">
-            </button>
-          </hbox>
-          <hbox id="requests-menu-file-header-box"
-                class="requests-menu-header requests-menu-file"
-                align="center">
-            <button id="requests-menu-file-button"
-                    class="requests-menu-header-button requests-menu-file"
-                    data-key="file"
-                    label="&netmonitorUI.toolbar.file;"
+    <vbox id="network-inspector-view" flex="1">
+      <hbox id="network-table-and-sidebar"
+            class="devtools-responsive-container"
+            flex="1">
+        <vbox id="network-table" flex="1">
+          <toolbar id="requests-menu-toolbar"
+                   class="devtools-toolbar"
+                   align="center">
+            <hbox id="toolbar-labels" flex="1">
+              <hbox id="requests-menu-status-and-method-header-box"
+                    class="requests-menu-header requests-menu-status-and-method"
+                    align="center">
+                <button id="requests-menu-status-button"
+                        class="requests-menu-header-button requests-menu-status"
+                        data-key="status"
+                        label="&netmonitorUI.toolbar.status2;">
+                </button>
+                <button id="requests-menu-method-button"
+                        class="requests-menu-header-button requests-menu-method"
+                        data-key="method"
+                        label="&netmonitorUI.toolbar.method;"
+                        flex="1">
+                </button>
+              </hbox>
+              <hbox id="requests-menu-file-header-box"
+                    class="requests-menu-header requests-menu-file"
+                    align="center">
+                <button id="requests-menu-file-button"
+                        class="requests-menu-header-button requests-menu-file"
+                        data-key="file"
+                        label="&netmonitorUI.toolbar.file;"
+                        flex="1">
+                </button>
+              </hbox>
+              <hbox id="requests-menu-domain-header-box"
+                    class="requests-menu-header requests-menu-domain"
+                    align="center">
+                <button id="requests-menu-domain-button"
+                        class="requests-menu-header-button requests-menu-domain"
+                        data-key="domain"
+                        label="&netmonitorUI.toolbar.domain;"
+                        flex="1">
+                </button>
+              </hbox>
+              <hbox id="requests-menu-type-header-box"
+                    class="requests-menu-header requests-menu-type"
+                    align="center">
+                <button id="requests-menu-type-button"
+                        class="requests-menu-header-button requests-menu-type"
+                        data-key="type"
+                        label="&netmonitorUI.toolbar.type;"
+                        flex="1">
+                </button>
+              </hbox>
+              <hbox id="requests-menu-size-header-box"
+                    class="requests-menu-header requests-menu-size"
+                    align="center">
+                <button id="requests-menu-size-button"
+                        class="requests-menu-header-button requests-menu-size"
+                        data-key="size"
+                        label="&netmonitorUI.toolbar.size;"
+                        flex="1">
+                </button>
+              </hbox>
+              <hbox id="requests-menu-waterfall-header-box"
+                    class="requests-menu-header requests-menu-waterfall"
+                    align="center"
                     flex="1">
-            </button>
-          </hbox>
-          <hbox id="requests-menu-domain-header-box"
-                class="requests-menu-header requests-menu-domain"
-                align="center">
-            <button id="requests-menu-domain-button"
-                    class="requests-menu-header-button requests-menu-domain"
-                    data-key="domain"
-                    label="&netmonitorUI.toolbar.domain;"
-                    flex="1">
-            </button>
-          </hbox>
-          <hbox id="requests-menu-type-header-box"
-                class="requests-menu-header requests-menu-type"
-                align="center">
-            <button id="requests-menu-type-button"
-                    class="requests-menu-header-button requests-menu-type"
-                    data-key="type"
-                    label="&netmonitorUI.toolbar.type;"
-                    flex="1">
-            </button>
-          </hbox>
-          <hbox id="requests-menu-size-header-box"
-                class="requests-menu-header requests-menu-size"
-                align="center">
-            <button id="requests-menu-size-button"
-                    class="requests-menu-header-button requests-menu-size"
-                    data-key="size"
-                    label="&netmonitorUI.toolbar.size;"
+                <button id="requests-menu-waterfall-button"
+                        class="requests-menu-header-button requests-menu-waterfall"
+                        data-key="waterfall"
+                        pack="start"
+                        flex="1">
+                  <label id="requests-menu-waterfall-label"
+                         class="plain requests-menu-waterfall"
+                         value="&netmonitorUI.toolbar.waterfall;"/>
+                </button>
+              </hbox>
+            </hbox>
+            <toolbarbutton id="details-pane-toggle"
+                           class="devtools-toolbarbutton"
+                           tooltiptext="&netmonitorUI.panesButton.tooltip;"
+                           disabled="true"
+                           tabindex="0"/>
+          </toolbar>
+
+          <vbox id="requests-menu-empty-notice"
+                class="side-menu-widget-empty-text">
+            <hbox id="notice-perf-message" align="center">
+              <label value="&netmonitorUI.perfNotice1;"/>
+              <button id="requests-menu-perf-notice-button"
+                      class="devtools-toolbarbutton"/>
+              <label value="&netmonitorUI.perfNotice2;"/>
+            </hbox>
+            <hbox id="notice-reload-message" align="center">
+              <label value="&netmonitorUI.emptyNotice3;"/>
+            </hbox>
+          </vbox>
+
+          <vbox id="requests-menu-contents" flex="1" context="network-request-popup">
+            <hbox id="requests-menu-item-template" hidden="true">
+              <hbox class="requests-menu-subitem requests-menu-status-and-method"
+                    align="center">
+                <box class="requests-menu-status"/>
+                <label class="plain requests-menu-method"
+                       crop="end"
+                       flex="1"/>
+              </hbox>
+              <label class="plain requests-menu-subitem requests-menu-file"
+                     crop="end"/>
+              <label class="plain requests-menu-subitem requests-menu-domain"
+                     crop="end"/>
+              <label class="plain requests-menu-subitem requests-menu-type"
+                     crop="end"/>
+              <label class="plain requests-menu-subitem requests-menu-size"
+                     crop="end"/>
+              <hbox class="requests-menu-subitem requests-menu-waterfall"
+                    align="center"
                     flex="1">
-            </button>
-          </hbox>
-          <hbox id="requests-menu-waterfall-header-box"
-                class="requests-menu-header requests-menu-waterfall"
-                align="center"
-                flex="1">
-            <button id="requests-menu-waterfall-button"
-                    class="requests-menu-header-button requests-menu-waterfall"
-                    data-key="waterfall"
-                    pack="start"
-                    flex="1">
-              <label id="requests-menu-waterfall-label"
-                     class="plain requests-menu-waterfall"
-                     value="&netmonitorUI.toolbar.waterfall;"/>
-            </button>
-          </hbox>
-        </hbox>
-        <toolbarbutton id="details-pane-toggle"
-                       class="devtools-toolbarbutton"
-                       tooltiptext="&netmonitorUI.panesButton.tooltip;"
-                       disabled="true"
-                       tabindex="0"/>
-      </toolbar>
+                <hbox class="requests-menu-timings"
+                      align="center">
+                  <label class="plain requests-menu-timings-total"/>
+                </hbox>
+              </hbox>
+            </hbox>
+          </vbox>
+        </vbox>
+
+        <splitter id="network-inspector-view-splitter"
+                  class="devtools-side-splitter"/>
 
-      <vbox id="requests-menu-empty-notice"
-            class="side-menu-widget-empty-text">
-        <hbox id="notice-perf-message" align="center">
-          <label value="&netmonitorUI.perfNotice1;"/>
-          <button id="requests-menu-perf-notice-button"
-                  class="devtools-toolbarbutton"/>
-          <label value="&netmonitorUI.perfNotice2;"/>
-        </hbox>
-        <hbox id="notice-reload-message" align="center">
-          <label value="&netmonitorUI.emptyNotice3;"/>
-        </hbox>
-      </vbox>
+        <deck id="details-pane"
+              hidden="true">
+          <vbox id="custom-pane"
+                class="tabpanel-content">
+            <hbox align="baseline">
+              <label value="&netmonitorUI.custom.newRequest;"
+                     class="plain tabpanel-summary-label
+                            custom-header"/>
+              <hbox flex="1" pack="end">
+                <button id="custom-request-send-button"
+                        class="devtools-toolbarbutton"
+                        label="&netmonitorUI.custom.send;"/>
+                <button id="custom-request-close-button"
+                        class="devtools-toolbarbutton"
+                        label="&netmonitorUI.custom.cancel;"/>
+              </hbox>
+            </hbox>
+            <hbox id="custom-method-and-url"
+                  class="tabpanel-summary-container"
+                  align="center">
+              <textbox id="custom-method-value"
+                       data-key="method"/>
+              <textbox id="custom-url-value"
+                       flex="1"
+                       data-key="url"/>
+            </hbox>
+            <vbox id="custom-query"
+                  class="tabpanel-summary-container custom-section">
+              <label class="plain tabpanel-summary-label"
+                     value="&netmonitorUI.custom.query;"/>
+              <textbox id="custom-query-value"
+                       class="tabpanel-summary-input"
+                       multiline="true"
+                       rows="4"
+                       wrap="off"
+                       data-key="query"/>
+            </vbox>
+            <vbox id="custom-headers"
+                  class="tabpanel-summary-container custom-section">
+              <label class="plain tabpanel-summary-label"
+                     value="&netmonitorUI.custom.headers;"/>
+              <textbox id="custom-headers-value"
+                       class="tabpanel-summary-input"
+                       multiline="true"
+                       rows="8"
+                       wrap="off"
+                       data-key="headers"/>
+            </vbox>
+            <vbox id="custom-postdata"
+                  class="tabpanel-summary-container custom-section">
+              <label class="plain tabpanel-summary-label"
+                     value="&netmonitorUI.custom.postData;"/>
+              <textbox id="custom-postdata-value"
+                       class="tabpanel-summary-input"
+                       multiline="true"
+                       rows="6"
+                       wrap="off"
+                       data-key="body"/>
+            </vbox>
+          </vbox>
+          <tabbox id="event-details-pane"
+                  class="devtools-sidebar-tabs"
+                  handleCtrlTab="false">
+            <tabs>
+              <tab label="&netmonitorUI.tab.headers;"/>
+              <tab label="&netmonitorUI.tab.cookies;"/>
+              <tab label="&netmonitorUI.tab.params;"/>
+              <tab label="&netmonitorUI.tab.response;"/>
+              <tab label="&netmonitorUI.tab.timings;"/>
+            </tabs>
+            <tabpanels flex="1">
+              <tabpanel id="headers-tabppanel"
+                        class="tabpanel-content">
+                <vbox flex="1">
+                  <hbox id="headers-summary-url"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.summary.url;"/>
+                    <label id="headers-summary-url-value"
+                           class="plain tabpanel-summary-value devtools-monospace"
+                           crop="end"
+                           flex="1"/>
+                  </hbox>
+                  <hbox id="headers-summary-method"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.summary.method;"/>
+                    <label id="headers-summary-method-value"
+                           class="plain tabpanel-summary-value devtools-monospace"
+                           crop="end"
+                           flex="1"/>
+                  </hbox>
+                  <hbox id="headers-summary-status"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.summary.status;"/>
+                    <box id="headers-summary-status-circle"
+                         class="requests-menu-status"/>
+                    <label id="headers-summary-status-value"
+                           class="plain tabpanel-summary-value devtools-monospace"
+                           crop="end"
+                           flex="1"/>
+                    <button id="headers-summary-resend"
+                            class="devtools-toolbarbutton"
+                            label="&netmonitorUI.summary.editAndResend;"/>
+                  </hbox>
+                  <hbox id="headers-summary-version"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.summary.version;"/>
+                    <label id="headers-summary-version-value"
+                           class="plain tabpanel-summary-value devtools-monospace"
+                           crop="end"
+                           flex="1"/>
+                  </hbox>
+                  <vbox id="all-headers" flex="1"/>
+                </vbox>
+              </tabpanel>
+              <tabpanel id="cookies-tabpanel"
+                        class="tabpanel-content">
+                <vbox flex="1">
+                  <vbox id="all-cookies" flex="1"/>
+                </vbox>
+              </tabpanel>
+              <tabpanel id="params-tabpanel"
+                        class="tabpanel-content">
+                <vbox flex="1">
+                  <vbox id="request-params-box" flex="1" hidden="true">
+                    <vbox id="request-params" flex="1"/>
+                  </vbox>
+                  <vbox id="request-post-data-textarea-box" flex="1" hidden="true">
+                    <vbox id="request-post-data-textarea" flex="1"/>
+                  </vbox>
+                </vbox>
+              </tabpanel>
+              <tabpanel id="response-tabpanel"
+                        class="tabpanel-content">
+                <vbox flex="1">
+                  <label id="response-content-info-header"/>
+                  <vbox id="response-content-json-box" flex="1" hidden="true">
+                    <vbox id="response-content-json" flex="1"/>
+                  </vbox>
+                  <vbox id="response-content-textarea-box" flex="1" hidden="true">
+                    <vbox id="response-content-textarea" flex="1"/>
+                  </vbox>
+                  <vbox id="response-content-image-box" flex="1" hidden="true">
+                    <image id="response-content-image"/>
+                    <hbox>
+                      <label class="plain tabpanel-summary-label"
+                             value="&netmonitorUI.response.name;"/>
+                      <label id="response-content-image-name-value"
+                             class="plain tabpanel-summary-value devtools-monospace"
+                             crop="end"
+                             flex="1"/>
+                    </hbox>
+                    <hbox>
+                      <label class="plain tabpanel-summary-label"
+                             value="&netmonitorUI.response.dimensions;"/>
+                      <label id="response-content-image-dimensions-value"
+                             class="plain tabpanel-summary-value devtools-monospace"
+                             crop="end"
+                             flex="1"/>
+                    </hbox>
+                    <hbox>
+                      <label class="plain tabpanel-summary-label"
+                             value="&netmonitorUI.response.mime;"/>
+                      <label id="response-content-image-mime-value"
+                             class="plain tabpanel-summary-value devtools-monospace"
+                             crop="end"
+                             flex="1"/>
+                    </hbox>
+                    <hbox>
+                      <label class="plain tabpanel-summary-label"
+                             value="&netmonitorUI.response.encoding;"/>
+                      <label id="response-content-image-encoding-value"
+                             class="plain tabpanel-summary-value devtools-monospace"
+                             crop="end"
+                             flex="1"/>
+                    </hbox>
+                  </vbox>
+                </vbox>
+              </tabpanel>
+              <tabpanel id="timings-tabpanel"
+                        class="tabpanel-content">
+                <vbox flex="1">
+                  <hbox id="timings-summary-blocked"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.timings.blocked;"/>
+                    <hbox class="requests-menu-timings-box blocked"/>
+                    <label class="plain requests-menu-timings-total"/>
+                  </hbox>
+                  <hbox id="timings-summary-dns"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.timings.dns;"/>
+                    <hbox class="requests-menu-timings-box dns"/>
+                    <label class="plain requests-menu-timings-total"/>
+                  </hbox>
+                  <hbox id="timings-summary-connect"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.timings.connect;"/>
+                    <hbox class="requests-menu-timings-box connect"/>
+                    <label class="plain requests-menu-timings-total"/>
+                  </hbox>
+                  <hbox id="timings-summary-send"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.timings.send;"/>
+                    <hbox class="requests-menu-timings-box send"/>
+                    <label class="plain requests-menu-timings-total"/>
+                  </hbox>
+                  <hbox id="timings-summary-wait"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.timings.wait;"/>
+                    <hbox class="requests-menu-timings-box wait"/>
+                    <label class="plain requests-menu-timings-total"/>
+                  </hbox>
+                  <hbox id="timings-summary-receive"
+                        class="tabpanel-summary-container"
+                        align="center">
+                    <label class="plain tabpanel-summary-label"
+                           value="&netmonitorUI.timings.receive;"/>
+                    <hbox class="requests-menu-timings-box receive"/>
+                    <label class="plain requests-menu-timings-total"/>
+                  </hbox>
+                </vbox>
+              </tabpanel>
+            </tabpanels>
+          </tabbox>
+        </deck>
+      </hbox>
 
-      <vbox id="requests-menu-contents" flex="1" context="network-request-popup">
-        <hbox id="requests-menu-item-template" hidden="true">
-          <hbox class="requests-menu-subitem requests-menu-status-and-method"
-                align="center">
-            <box class="requests-menu-status"/>
-            <label class="plain requests-menu-method"
-                   crop="end"
-                   flex="1"/>
-          </hbox>
-          <label class="plain requests-menu-subitem requests-menu-file"
-                 crop="end"/>
-          <label class="plain requests-menu-subitem requests-menu-domain"
-                 crop="end"/>
-          <label class="plain requests-menu-subitem requests-menu-type"
-                 crop="end"/>
-          <label class="plain requests-menu-subitem requests-menu-size"
-                 crop="end"/>
-          <hbox class="requests-menu-subitem requests-menu-waterfall"
-                align="center"
-                flex="1">
-            <hbox class="requests-menu-timings"
-                  align="center">
-              <label class="plain requests-menu-timings-total"/>
-            </hbox>
-          </hbox>
-        </hbox>
-      </vbox>
       <hbox id="requests-menu-footer">
         <button id="requests-menu-filter-all-button"
                 class="requests-menu-filter-button requests-menu-footer-button"
                 checked="true"
                 data-key="all"
                 label="&netmonitorUI.footer.filterAll;">
         </button>
         <button id="requests-menu-filter-html-button"
@@ -227,278 +479,32 @@
         <label id="requests-menu-network-summary-label"
                class="plain requests-menu-footer-label"
                crop="end"
                tooltiptext="&netmonitorUI.footer.perf;"/>
         <button id="requests-menu-clear-button"
                 class="requests-menu-footer-button"
                 label="&netmonitorUI.footer.clear;"/>
       </hbox>
+
     </vbox>
 
-    <splitter id="network-inspector-view-splitter"
-              class="devtools-side-splitter"/>
-
-    <deck id="details-pane"
-          hidden="true">
-      <vbox id="custom-pane"
-            class="tabpanel-content">
-        <hbox align="baseline">
-          <label value="&netmonitorUI.custom.newRequest;"
-                 class="plain tabpanel-summary-label
-                        custom-header"/>
-          <hbox flex="1" pack="end">
-            <button id="custom-request-send-button"
-                    class="devtools-toolbarbutton"
-                    label="&netmonitorUI.custom.send;"/>
-            <button id="custom-request-close-button"
-                    class="devtools-toolbarbutton"
-                    label="&netmonitorUI.custom.cancel;"/>
-          </hbox>
-        </hbox>
-        <hbox id="custom-method-and-url"
-              class="tabpanel-summary-container"
-              align="center">
-          <textbox id="custom-method-value"
-                   data-key="method"/>
-          <textbox id="custom-url-value"
-                   flex="1"
-                   data-key="url"/>
-        </hbox>
-        <vbox id="custom-query"
-              class="tabpanel-summary-container custom-section">
-          <label class="plain tabpanel-summary-label"
-                 value="&netmonitorUI.custom.query;"/>
-          <textbox id="custom-query-value"
-                   class="tabpanel-summary-input"
-                   multiline="true"
-                   rows="4"
-                   wrap="off"
-                   data-key="query"/>
-        </vbox>
-        <vbox id="custom-headers"
-              class="tabpanel-summary-container custom-section">
-          <label class="plain tabpanel-summary-label"
-                 value="&netmonitorUI.custom.headers;"/>
-          <textbox id="custom-headers-value"
-                   class="tabpanel-summary-input"
-                   multiline="true"
-                   rows="8"
-                   wrap="off"
-                   data-key="headers"/>
-        </vbox>
-        <vbox id="custom-postdata"
-              class="tabpanel-summary-container custom-section">
-          <label class="plain tabpanel-summary-label"
-                 value="&netmonitorUI.custom.postData;"/>
-          <textbox id="custom-postdata-value"
-                   class="tabpanel-summary-input"
-                   multiline="true"
-                   rows="6"
-                   wrap="off"
-                   data-key="body"/>
-        </vbox>
-      </vbox>
-      <tabbox id="event-details-pane"
-              class="devtools-sidebar-tabs"
-              handleCtrlTab="false">
-        <tabs>
-          <tab label="&netmonitorUI.tab.headers;"/>
-          <tab label="&netmonitorUI.tab.cookies;"/>
-          <tab label="&netmonitorUI.tab.params;"/>
-          <tab label="&netmonitorUI.tab.response;"/>
-          <tab label="&netmonitorUI.tab.timings;"/>
-        </tabs>
-        <tabpanels flex="1">
-          <tabpanel id="headers-tabppanel"
-                    class="tabpanel-content">
-            <vbox flex="1">
-              <hbox id="headers-summary-url"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.summary.url;"/>
-                <label id="headers-summary-url-value"
-                       class="plain tabpanel-summary-value devtools-monospace"
-                       crop="end"
-                       flex="1"/>
-              </hbox>
-              <hbox id="headers-summary-method"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.summary.method;"/>
-                <label id="headers-summary-method-value"
-                       class="plain tabpanel-summary-value devtools-monospace"
-                       crop="end"
-                       flex="1"/>
-              </hbox>
-              <hbox id="headers-summary-status"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.summary.status;"/>
-                <box id="headers-summary-status-circle"
-                     class="requests-menu-status"/>
-                <label id="headers-summary-status-value"
-                       class="plain tabpanel-summary-value devtools-monospace"
-                       crop="end"
-                       flex="1"/>
-                <button id="headers-summary-resend"
-                        class="devtools-toolbarbutton"
-                        label="&netmonitorUI.summary.editAndResend;"/>
-              </hbox>
-              <hbox id="headers-summary-version"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.summary.version;"/>
-                <label id="headers-summary-version-value"
-                       class="plain tabpanel-summary-value devtools-monospace"
-                       crop="end"
-                       flex="1"/>
-              </hbox>
-              <vbox id="all-headers" flex="1"/>
-            </vbox>
-          </tabpanel>
-          <tabpanel id="cookies-tabpanel"
-                    class="tabpanel-content">
-            <vbox flex="1">
-              <vbox id="all-cookies" flex="1"/>
-            </vbox>
-          </tabpanel>
-          <tabpanel id="params-tabpanel"
-                    class="tabpanel-content">
-            <vbox flex="1">
-              <vbox id="request-params-box" flex="1" hidden="true">
-                <vbox id="request-params" flex="1"/>
-              </vbox>
-              <vbox id="request-post-data-textarea-box" flex="1" hidden="true">
-                <vbox id="request-post-data-textarea" flex="1"/>
-              </vbox>
-            </vbox>
-          </tabpanel>
-          <tabpanel id="response-tabpanel"
-                    class="tabpanel-content">
-            <vbox flex="1">
-              <label id="response-content-info-header"/>
-              <vbox id="response-content-json-box" flex="1" hidden="true">
-                <vbox id="response-content-json" flex="1"/>
-              </vbox>
-              <vbox id="response-content-textarea-box" flex="1" hidden="true">
-                <vbox id="response-content-textarea" flex="1"/>
-              </vbox>
-              <vbox id="response-content-image-box" flex="1" hidden="true">
-                <image id="response-content-image"/>
-                <hbox>
-                  <label class="plain tabpanel-summary-label"
-                         value="&netmonitorUI.response.name;"/>
-                  <label id="response-content-image-name-value"
-                         class="plain tabpanel-summary-value devtools-monospace"
-                         crop="end"
-                         flex="1"/>
-                </hbox>
-                <hbox>
-                  <label class="plain tabpanel-summary-label"
-                         value="&netmonitorUI.response.dimensions;"/>
-                  <label id="response-content-image-dimensions-value"
-                         class="plain tabpanel-summary-value devtools-monospace"
-                         crop="end"
-                         flex="1"/>
-                </hbox>
-                <hbox>
-                  <label class="plain tabpanel-summary-label"
-                         value="&netmonitorUI.response.mime;"/>
-                  <label id="response-content-image-mime-value"
-                         class="plain tabpanel-summary-value devtools-monospace"
-                         crop="end"
-                         flex="1"/>
-                </hbox>
-                <hbox>
-                  <label class="plain tabpanel-summary-label"
-                         value="&netmonitorUI.response.encoding;"/>
-                  <label id="response-content-image-encoding-value"
-                         class="plain tabpanel-summary-value devtools-monospace"
-                         crop="end"
-                         flex="1"/>
-                </hbox>
-              </vbox>
-            </vbox>
-          </tabpanel>
-          <tabpanel id="timings-tabpanel"
-                    class="tabpanel-content">
-            <vbox flex="1">
-              <hbox id="timings-summary-blocked"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.timings.blocked;"/>
-                <hbox class="requests-menu-timings-box blocked"/>
-                <label class="plain requests-menu-timings-total"/>
-              </hbox>
-              <hbox id="timings-summary-dns"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.timings.dns;"/>
-                <hbox class="requests-menu-timings-box dns"/>
-                <label class="plain requests-menu-timings-total"/>
-              </hbox>
-              <hbox id="timings-summary-connect"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.timings.connect;"/>
-                <hbox class="requests-menu-timings-box connect"/>
-                <label class="plain requests-menu-timings-total"/>
-              </hbox>
-              <hbox id="timings-summary-send"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.timings.send;"/>
-                <hbox class="requests-menu-timings-box send"/>
-                <label class="plain requests-menu-timings-total"/>
-              </hbox>
-              <hbox id="timings-summary-wait"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.timings.wait;"/>
-                <hbox class="requests-menu-timings-box wait"/>
-                <label class="plain requests-menu-timings-total"/>
-              </hbox>
-              <hbox id="timings-summary-receive"
-                    class="tabpanel-summary-container"
-                    align="center">
-                <label class="plain tabpanel-summary-label"
-                       value="&netmonitorUI.timings.receive;"/>
-                <hbox class="requests-menu-timings-box receive"/>
-                <label class="plain requests-menu-timings-total"/>
-              </hbox>
-            </vbox>
-          </tabpanel>
-        </tabpanels>
-      </tabbox>
-    </deck>
-  </box>
-
-  <box id="network-statistics-view">
-    <toolbar id="network-statistics-toolbar"
-             class="devtools-toolbar">
-      <button id="network-statistics-back-button"
-              class="devtools-toolbarbutton"
-              onclick="NetMonitorView.toggleFrontendMode()"
-              label="&netmonitorUI.backButton;"/>
-    </toolbar>
-    <box id="network-statistics-charts"
-         class="devtools-responsive-container"
-         flex="1">
-      <vbox id="primed-cache-chart" pack="center" flex="1"/>
-      <splitter id="network-statistics-view-splitter"
-                class="devtools-side-splitter"/>
-      <vbox id="empty-cache-chart" pack="center" flex="1"/>
+    <box id="network-statistics-view">
+      <toolbar id="network-statistics-toolbar"
+               class="devtools-toolbar">
+        <button id="network-statistics-back-button"
+                class="devtools-toolbarbutton"
+                onclick="NetMonitorView.toggleFrontendMode()"
+                label="&netmonitorUI.backButton;"/>
+      </toolbar>
+      <box id="network-statistics-charts"
+           class="devtools-responsive-container"
+           flex="1">
+        <vbox id="primed-cache-chart" pack="center" flex="1"/>
+        <splitter id="network-statistics-view-splitter"
+                  class="devtools-side-splitter"/>
+        <vbox id="empty-cache-chart" pack="center" flex="1"/>
+      </box>
     </box>
-  </box>
 
   </deck>
 
 </window>
--- a/browser/devtools/netmonitor/test/browser.ini
+++ b/browser/devtools/netmonitor/test/browser.ini
@@ -64,11 +64,12 @@ support-files =
 [browser_net_simple-request-data.js]
 [browser_net_simple-request-details.js]
 [browser_net_simple-request.js]
 [browser_net_sort-01.js]
 [browser_net_sort-02.js]
 [browser_net_sort-03.js]
 [browser_net_statistics-01.js]
 [browser_net_statistics-02.js]
+[browser_net_statistics-03.js]
 [browser_net_status-codes.js]
 [browser_net_timeline_ticks.js]
 [browser_net_timing-division.js]
--- a/browser/devtools/netmonitor/test/browser_net_filter-01.js
+++ b/browser/devtools/netmonitor/test/browser_net_filter-01.js
@@ -20,154 +20,112 @@ function test() {
       isnot(RequestsMenu.selectedItem, null,
         "There should be a selected item in the requests menu.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be selected in the requests menu.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should not be hidden after toggle button was pressed.");
 
       // First test with single filters...
-      testButtons("all");
+      testFilterButtons(aMonitor, "all");
       testContents([1, 1, 1, 1, 1, 1, 1, 1])
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           // Reset filters
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
-          testButtons("css");
+          testFilterButtons(aMonitor, "css");
           return testContents([0, 1, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
-          testButtons("js");
+          testFilterButtons(aMonitor, "js");
           return testContents([0, 0, 1, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-xhr-button"));
-          testButtons("xhr");
+          testFilterButtons(aMonitor, "xhr");
           return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-fonts-button"));
-          testButtons("fonts");
+          testFilterButtons(aMonitor, "fonts");
           return testContents([0, 0, 0, 1, 0, 0, 0, 0]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-images-button"));
-          testButtons("images");
+          testFilterButtons(aMonitor, "images");
           return testContents([0, 0, 0, 0, 1, 0, 0, 0]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-media-button"));
-          testButtons("media");
+          testFilterButtons(aMonitor, "media");
           return testContents([0, 0, 0, 0, 0, 1, 1, 0]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
-          testButtons("flash");
+          testFilterButtons(aMonitor, "flash");
           return testContents([0, 0, 0, 0, 0, 0, 0, 1]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
-          testButtons("all");
+          testFilterButtons(aMonitor, "all");
           return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
         })
         // ...then combine multiple filters together.
         .then(() => {
           // Enable filtering for html and css; should show request of both type.
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
-          testButtonsCustom([0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
+          testFilterButtonsCustom(aMonitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
           return testContents([1, 1, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
-          testButtonsCustom([0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
+          testFilterButtonsCustom(aMonitor, [0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
           return testContents([1, 1, 0, 0, 0, 0, 0, 1]);
         })
         .then(() => {
           // Disable some filters. Only one left active.
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           // Disable last active filter. Should toggle to all.
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
-          testButtons("all");
+          testFilterButtons(aMonitor, "all");
           return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
         })
         .then(() => {
           // Enable few filters and click on all. Only "all" should be checked.
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
-          testButtonsCustom([0, 1, 1, 0, 0, 0, 0, 0, 0]);
+          testFilterButtonsCustom(aMonitor, [0, 1, 1, 0, 0, 0, 0, 0, 0]);
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
-          testButtons("all");
+          testFilterButtons(aMonitor, "all");
           return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
         })
         .then(() => {
           return teardown(aMonitor);
         })
         .then(finish);
     });
 
-    /**
-     * Tests if a button for a filter of given type is the only one checked.
-     *
-     * @param string aFilterType
-     *        The type of the filter that should be the only one checked.
-     *
-     */
-    function testButtons(aFilterType) {
-      let doc = aMonitor.panelWin.document;
-      let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
-      let buttons = doc.querySelectorAll(".requests-menu-footer-button");
-
-      // Only target should be checked.
-      let checkStatus = [(button == target) ? 1 : 0 for (button of buttons)]
-
-      testButtonsCustom(checkStatus);
-    }
-
-    /**
-     * Tests if filter buttons have 'checked' attributes set correctly.
-     *
-     * @param array aIsChecked
-     *        An array specifying if a button at given index should have a 
-     *        'checked' attribute. For example, if the third item of the array
-     *        evaluates to true, the third button should be checked.
-     *
-     */
-    function testButtonsCustom(aIsChecked) {
-      let doc = aMonitor.panelWin.document;
-      let buttons = doc.querySelectorAll(".requests-menu-footer-button");
-      for (let i = 0; i < aIsChecked.length; i++) {
-        let button = buttons[i];
-        if (aIsChecked[i]) {
-          is(button.hasAttribute("checked"), true,
-            "The " + button.id + " button should have a 'checked' attribute.");
-        } else {
-          is(button.hasAttribute("checked"), false,
-            "The " + button.id + " button should not have a 'checked' attribute.");
-        }
-      }
-    }
-
     function testContents(aVisibility) {
       isnot(RequestsMenu.selectedItem, null,
         "There should still be a selected item after filtering.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be still selected after filtering.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should still be visible after filtering.");
 
--- a/browser/devtools/netmonitor/test/browser_net_filter-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_filter-02.js
@@ -19,66 +19,56 @@ function test() {
 
       isnot(RequestsMenu.selectedItem, null,
         "There should be a selected item in the requests menu.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be selected in the requests menu.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should not be hidden after toggle button was pressed.");
 
-      testButtons("all");
+      testFilterButtons(aMonitor, "all");
       testContents([1, 1, 1, 1, 1, 1, 1, 1])
         .then(() => {
           info("Testing html filtering.");
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           info("Performing more requests.");
           aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
           return waitForNetworkEvents(aMonitor, 8);
         })
         .then(() => {
           info("Testing html filtering again.");
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
           info("Performing more requests.");
           aDebuggee.performRequests('{ "getMedia": true, "getFlash": true }');
           return waitForNetworkEvents(aMonitor, 8);
         })
         .then(() => {
           info("Testing html filtering again.");
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
         })
         .then(() => {
+          info("Resetting filters.");
+          EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
+          testFilterButtons(aMonitor, "all");
+          return testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
+        })
+        .then(() => {
           return teardown(aMonitor);
         })
         .then(finish);
     });
 
-    function testButtons(aFilterType) {
-      let doc = aMonitor.panelWin.document;
-      let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
-      let buttons = doc.querySelectorAll(".requests-menu-footer-button");
-
-      for (let button of buttons) {
-        if (button != target) {
-          is(button.hasAttribute("checked"), false,
-            "The " + button.id + " button should not have a 'checked' attribute.");
-        } else {
-          is(button.hasAttribute("checked"), true,
-            "The " + button.id + " button should have a 'checked' attribute.");
-        }
-      }
-    }
-
     function testContents(aVisibility) {
       isnot(RequestsMenu.selectedItem, null,
         "There should still be a selected item after filtering.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be still selected after filtering.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should still be visible after filtering.");
 
--- a/browser/devtools/netmonitor/test/browser_net_filter-03.js
+++ b/browser/devtools/netmonitor/test/browser_net_filter-03.js
@@ -20,79 +20,63 @@ function test() {
 
       isnot(RequestsMenu.selectedItem, null,
         "There should be a selected item in the requests menu.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be selected in the requests menu.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should not be hidden after toggle button was pressed.");
 
-      testButtons("all");
+      testFilterButtons(aMonitor, "all");
       testContents([0, 1, 2, 3, 4, 5, 6], 7, 0)
         .then(() => {
           info("Sorting by size, ascending.");
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
-          testButtons("all");
+          testFilterButtons(aMonitor, "all");
           return testContents([6, 4, 5, 0, 1, 2, 3], 7, 6);
         })
         .then(() => {
           info("Testing html filtering.");
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([6, 4, 5, 0, 1, 2, 3], 1, 6);
         })
         .then(() => {
           info("Performing more requests.");
           aDebuggee.performRequests('{ "getMedia": true }');
           return waitForNetworkEvents(aMonitor, 7);
         })
         .then(() => {
           info("Testing html filtering again.");
           resetSorting();
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([8, 13, 9, 11, 10, 12, 0, 4, 1, 5, 2, 6, 3, 7], 2, 13);
         })
         .then(() => {
           info("Performing more requests.");
           aDebuggee.performRequests('{ "getMedia": true }');
           return waitForNetworkEvents(aMonitor, 7);
         })
         .then(() => {
           info("Testing html filtering again.");
           resetSorting();
-          testButtons("html");
+          testFilterButtons(aMonitor, "html");
           return testContents([12, 13, 20, 14, 16, 18, 15, 17, 19, 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11], 3, 20);
         })
         .then(() => {
           return teardown(aMonitor);
         })
         .then(finish);
     });
 
     function resetSorting() {
       EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-waterfall-button"));
       EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
     }
 
-    function testButtons(aFilterType) {
-      let doc = aMonitor.panelWin.document;
-      let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
-      let buttons = doc.querySelectorAll(".requests-menu-footer-button");
-
-      for (let button of buttons) {
-        if (button != target) {
-          is(button.hasAttribute("checked"), false,
-            "The " + button.id + " button should not have a 'checked' attribute.");
-        } else {
-          is(button.hasAttribute("checked"), true,
-            "The " + button.id + " button should have a 'checked' attribute.");
-        }
-      }
-    }
-
     function testContents(aOrder, aVisible, aSelection) {
       isnot(RequestsMenu.selectedItem, null,
         "There should still be a selected item after filtering.");
       is(RequestsMenu.selectedIndex, aSelection,
         "The first item should be still selected after filtering.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should still be visible after filtering.");
 
--- a/browser/devtools/netmonitor/test/browser_net_prefs-reload.js
+++ b/browser/devtools/netmonitor/test/browser_net_prefs-reload.js
@@ -8,27 +8,43 @@
 function test() {
   initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
     info("Starting test... ");
 
     // This test reopens the network monitor a bunch of times, for different
     // hosts (bottom, side, window). This seems to be slow on debug builds.
     requestLongerTimeout(3);
 
+    // Use these getters instead of caching instances inside the panel win,
+    // since the tool is reopened a bunch of times during this test
+    // and the instances will differ.
+    let getView = () => aMonitor.panelWin.NetMonitorView;
+    let getController = () => aMonitor.panelWin.NetMonitorController;
+
     let prefsToCheck = {
+      filters: {
+        // A custom new value to be used for the verified preference.
+        newValue: ["html", "css"],
+        // Getter used to retrieve the current value from the frontend, in order
+        // to verify that the pref was applied properly.
+        validateValue: ($) => getView().RequestsMenu._activeFilters,
+        // Predicate used to modify the frontend when setting the new pref value,
+        // before trying to validate the changes.
+        modifyFrontend: ($, aValue) => aValue.forEach(e => getView().RequestsMenu.filterOn(e))
+      },
       networkDetailsWidth: {
         newValue: ~~(Math.random() * 200 + 100),
-        validate: ($) => ~~$("#details-pane").getAttribute("width"),
+        validateValue: ($) => ~~$("#details-pane").getAttribute("width"),
         modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("width", aValue)
       },
       networkDetailsHeight: {
         newValue: ~~(Math.random() * 300 + 100),
-        validate: ($) => ~~$("#details-pane").getAttribute("height"),
+        validateValue: ($) => ~~$("#details-pane").getAttribute("height"),
         modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("height", aValue)
-      },
+      }
       /* add more prefs here... */
     };
 
     function storeFirstPrefValues() {
       info("Caching initial pref values.");
 
       for (let name in prefsToCheck) {
         let currentValue = aMonitor.panelWin.Prefs[name];
@@ -37,83 +53,83 @@ function test() {
     }
 
     function validateFirstPrefValues() {
       info("Validating current pref values to the UI elements.");
 
       for (let name in prefsToCheck) {
         let currentValue = aMonitor.panelWin.Prefs[name];
         let firstValue = prefsToCheck[name].firstValue;
-        let validate = prefsToCheck[name].validate;
+        let validateValue = prefsToCheck[name].validateValue;
 
-        is(currentValue, firstValue,
+        is(currentValue.toSource(), firstValue.toSource(),
           "Pref " + name + " should be equal to first value: " + firstValue);
-        is(currentValue, validate(aMonitor.panelWin.$),
+        is(currentValue.toSource(), validateValue(aMonitor.panelWin.$).toSource(),
           "Pref " + name + " should validate: " + currentValue);
       }
     }
 
     function modifyFrontend() {
       info("Modifying UI elements to the specified new values.");
 
       for (let name in prefsToCheck) {
         let currentValue = aMonitor.panelWin.Prefs[name];
         let firstValue = prefsToCheck[name].firstValue;
         let newValue = prefsToCheck[name].newValue;
-        let validate = prefsToCheck[name].validate;
+        let validateValue = prefsToCheck[name].validateValue;
         let modifyFrontend = prefsToCheck[name].modifyFrontend;
 
         modifyFrontend(aMonitor.panelWin.$, newValue);
         info("Modified UI element affecting " + name + " to: " + newValue);
 
-        is(currentValue, firstValue,
+        is(currentValue.toSource(), firstValue.toSource(),
           "Pref " + name + " should still be equal to first value: " + firstValue);
-        isnot(currentValue, newValue,
+        isnot(currentValue.toSource(), newValue.toSource(),
           "Pref " + name + " should't yet be equal to second value: " + newValue);
-        is(newValue, validate(aMonitor.panelWin.$),
+        is(newValue.toSource(), validateValue(aMonitor.panelWin.$).toSource(),
           "The UI element affecting " + name + " should validate: " + newValue);
       }
     }
 
     function validateNewPrefValues() {
       info("Invalidating old pref values to the modified UI elements.");
 
       for (let name in prefsToCheck) {
         let currentValue = aMonitor.panelWin.Prefs[name];
         let firstValue = prefsToCheck[name].firstValue;
         let newValue = prefsToCheck[name].newValue;
-        let validate = prefsToCheck[name].validate;
+        let validateValue = prefsToCheck[name].validateValue;
 
-        isnot(currentValue, firstValue,
+        isnot(currentValue.toSource(), firstValue.toSource(),
           "Pref " + name + " should't be equal to first value: " + firstValue);
-        is(currentValue, newValue,
+        is(currentValue.toSource(), newValue.toSource(),
           "Pref " + name + " should now be equal to second value: " + newValue);
-        is(newValue, validate(aMonitor.panelWin.$),
+        is(newValue.toSource(), validateValue(aMonitor.panelWin.$).toSource(),
           "The UI element affecting " + name + " should validate: " + newValue);
       }
     }
 
     function resetFrontend() {
       info("Resetting UI elements to the cached initial pref values.");
 
       for (let name in prefsToCheck) {
         let currentValue = aMonitor.panelWin.Prefs[name];
         let firstValue = prefsToCheck[name].firstValue;
         let newValue = prefsToCheck[name].newValue;
-        let validate = prefsToCheck[name].validate;
+        let validateValue = prefsToCheck[name].validateValue;
         let modifyFrontend = prefsToCheck[name].modifyFrontend;
 
         modifyFrontend(aMonitor.panelWin.$, firstValue);
         info("Modified UI element affecting " + name + " to: " + firstValue);
 
-        isnot(currentValue, firstValue,
+        isnot(currentValue.toSource(), firstValue.toSource(),
           "Pref " + name + " should't yet be equal to first value: " + firstValue);
-        is(currentValue, newValue,
+        is(currentValue.toSource(), newValue.toSource(),
           "Pref " + name + " should still be equal to second value: " + newValue);
-        is(firstValue, validate(aMonitor.panelWin.$),
+        is(firstValue.toSource(), validateValue(aMonitor.panelWin.$).toSource(),
           "The UI element affecting " + name + " should validate: " + firstValue);
       }
     }
 
     function testBottom() {
       info("Testing prefs reload for a bottom host.");
       storeFirstPrefValues();
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_statistics-03.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if the correct filtering predicates are used when filtering from
+ * the performance analysis view.
+ */
+
+function test() {
+  initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
+    info("Starting test... ");
+
+    let panel = aMonitor.panelWin;
+    let { $, EVENTS, NetMonitorView } = panel;
+
+    EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
+    EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
+    EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
+    EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-other-button"));
+    testFilterButtonsCustom(aMonitor, [0, 1, 1, 1, 0, 0, 0, 0, 0, 1]);
+    ok(true, "The correct filtering predicates are used before entering perf. analysis mode.");
+
+    promise.all([
+      waitFor(panel, EVENTS.PRIMED_CACHE_CHART_DISPLAYED),
+      waitFor(panel, EVENTS.EMPTY_CACHE_CHART_DISPLAYED)
+    ]).then(() => {
+      EventUtils.sendMouseEvent({ type: "click" }, $(".pie-chart-slice"));
+      testFilterButtons(aMonitor, "html");
+      ok(true, "The correct filtering predicate is used when exiting perf. analysis mode.");
+
+      teardown(aMonitor).then(finish);
+    });
+
+    NetMonitorView.toggleFrontendMode();
+  });
+}
--- a/browser/devtools/netmonitor/test/head.js
+++ b/browser/devtools/netmonitor/test/head.js
@@ -39,22 +39,26 @@ const STATUS_CODES_SJS = EXAMPLE_URL + "
 const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
 
 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 // Enable logging for all the relevant tests.
-let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
+const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 Services.prefs.setBoolPref("devtools.debugger.log", true);
 
+// Always reset some prefs to their original values after the test finishes.
+const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
+
 registerCleanupFunction(() => {
   info("finish() was called, cleaning up...");
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
+  Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
 });
 
 function addTab(aUrl, aWindow) {
   info("Adding tab: " + aUrl);
 
   let deferred = promise.defer();
   let targetWindow = aWindow || window;
   let targetBrowser = targetWindow.gBrowser;
@@ -298,8 +302,47 @@ function verifyRequestItemTarget(aReques
  * @return object
  *        Returns a promise that resolves upon firing of the event.
  */
 function waitFor (subject, eventName) {
   let deferred = promise.defer();
   subject.once(eventName, deferred.resolve);
   return deferred.promise;
 }
+
+/**
+ * Tests if a button for a filter of given type is the only one checked.
+ *
+ * @param string aFilterType
+ *        The type of the filter that should be the only one checked.
+ */
+function testFilterButtons(aMonitor, aFilterType) {
+  let doc = aMonitor.panelWin.document;
+  let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
+  let buttons = doc.querySelectorAll(".requests-menu-footer-button");
+
+  // Only target should be checked.
+  let checkStatus = [(button == target) ? 1 : 0 for (button of buttons)]
+  testFilterButtonsCustom(aMonitor, checkStatus);
+}
+
+/**
+ * Tests if filter buttons have 'checked' attributes set correctly.
+ *
+ * @param array aIsChecked
+ *        An array specifying if a button at given index should have a
+ *        'checked' attribute. For example, if the third item of the array
+ *        evaluates to true, the third button should be checked.
+ */
+function testFilterButtonsCustom(aMonitor, aIsChecked) {
+  let doc = aMonitor.panelWin.document;
+  let buttons = doc.querySelectorAll(".requests-menu-footer-button");
+  for (let i = 0; i < aIsChecked.length; i++) {
+    let button = buttons[i];
+    if (aIsChecked[i]) {
+      is(button.hasAttribute("checked"), true,
+        "The " + button.id + " button should have a 'checked' attribute.");
+    } else {
+      is(button.hasAttribute("checked"), false,
+        "The " + button.id + " button should not have a 'checked' attribute.");
+    }
+  }
+}
--- a/browser/devtools/shared/widgets/ViewHelpers.jsm
+++ b/browser/devtools/shared/widgets/ViewHelpers.jsm
@@ -390,25 +390,33 @@ ViewHelpers.Prefs.prototype = {
    */
   _set: function(aType, aPrefName, aValue) {
     Services.prefs["set" + aType + "Pref"](aPrefName, aValue);
     this[aPrefName] = aValue;
   },
 
   /**
    * Maps a property name to a pref, defining lazy getters and setters.
+   * Supported types are "Bool", "Char", "Int" and "Json" (which is basically
+   * just sugar for "Char" using the standard JSON serializer).
    *
    * @param string aAccessorName
    * @param string aType
    * @param string aPrefName
+   * @param array aSerializer
    */
-  map: function(aAccessorName, aType, aPrefName) {
+  map: function(aAccessorName, aType, aPrefName, aSerializer = { in: e => e, out: e => e }) {
+    if (aType == "Json") {
+      this.map(aAccessorName, "Char", aPrefName, { in: JSON.parse, out: JSON.stringify });
+      return;
+    }
+
     Object.defineProperty(this, aAccessorName, {
-      get: () => this._get(aType, [this.root, aPrefName].join(".")),
-      set: (aValue) => this._set(aType, [this.root, aPrefName].join("."), aValue)
+      get: () => aSerializer.in(this._get(aType, [this.root, aPrefName].join("."))),
+      set: (e) => this._set(aType, [this.root, aPrefName].join("."), aSerializer.out(e))
     });
   }
 };
 
 /**
  * A generic Item is used to describe children present in a Widget.
  *
  * This is basically a very thin wrapper around an nsIDOMNode, with a few
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -573,17 +573,17 @@ StyleEditorUI.prototype = {
    */
   _updateSummaryForEditor: function(editor, summary) {
     summary = summary || editor.summary;
     if (!summary) {
       return;
     }
 
     let ruleCount = editor.styleSheet.ruleCount;
-    if (editor.styleSheet.relatedStyleSheet) {
+    if (editor.styleSheet.relatedStyleSheet && editor.linkedCSSFile) {
       ruleCount = editor.styleSheet.relatedStyleSheet.ruleCount;
     }
     if (ruleCount === undefined) {
       ruleCount = "-";
     }
 
     var flags = [];
     if (editor.styleSheet.disabled) {
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
@@ -7,83 +7,74 @@
 
 // Tests that the Web Console limits the number of lines displayed according to
 // the user's preferences.
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>test for bug 642108.";
 const LOG_LIMIT = 20;
 
 function test() {
-  addTab(TEST_URI);
-  browser.addEventListener("load", function onLoad(){
-    browser.removeEventListener("load", onLoad, false);
+  let hud;
+
+  Task.spawn(runner).then(finishTest);
+
+  function* runner() {
+    let {tab} = yield loadTab(TEST_URI);
 
     Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", LOG_LIMIT);
+    Services.prefs.setBoolPref("devtools.webconsole.filter.cssparser", true);
 
     registerCleanupFunction(function() {
       Services.prefs.clearUserPref("devtools.hud.loglimit.cssparser");
+      Services.prefs.clearUserPref("devtools.webconsole.filter.cssparser");
     });
 
-    openConsole(null, testCSSPruning);
-  }, true);
-}
+    hud = yield openConsole(tab);
 
-function populateConsoleRepeats(aHudRef) {
-  for (let i = 0; i < 5; i++) {
-    let node = aHudRef.ui.createMessageNode(CATEGORY_CSS, SEVERITY_WARNING,
-                                            "css log x");
-    aHudRef.ui.outputMessage(CATEGORY_CSS, node);
-  }
-}
+    for (let i = 0; i < 5; i++) {
+      logCSSMessage("css log x");
+    }
 
-function populateConsole(aHudRef) {
-  for (let i = 0; i < LOG_LIMIT + 5; i++) {
-    let node = aHudRef.ui.createMessageNode(CATEGORY_CSS, SEVERITY_WARNING,
-                                            "css log " + i);
-    aHudRef.ui.outputMessage(CATEGORY_CSS, node);
-  }
-}
-
-function testCSSPruning(hudRef) {
-  populateConsoleRepeats(hudRef);
+    yield waitForMessages({
+      webconsole: hud,
+      messages: [{
+        text: "css log x",
+        category: CATEGORY_CSS,
+        severity: SEVERITY_WARNING,
+        repeats: 5,
+      }],
+    });
 
-  waitForMessages({
-    webconsole: hudRef,
-    messages: [{
-      text: "css log x",
-      category: CATEGORY_CSS,
-      severity: SEVERITY_WARNING,
-      repeats: 5,
-    }],
-  }).then(() => {
-    populateConsole(hudRef);
-    waitForMessages({
-      webconsole: hudRef,
+    for (let i = 0; i < LOG_LIMIT + 5; i++) {
+      logCSSMessage("css log " + i);
+    }
+
+    let [result] = yield waitForMessages({
+      webconsole: hud,
       messages: [{
-        text: "css log 0",
+        text: "css log 5",
         category: CATEGORY_CSS,
         severity: SEVERITY_WARNING,
       },
       {
         text: "css log 24", // LOG_LIMIT + 5
         category: CATEGORY_CSS,
         severity: SEVERITY_WARNING,
       }],
-    }).then(([result]) => {
-      is(countMessageNodes(), LOG_LIMIT, "number of messages");
+    });
 
-      is(Object.keys(hudRef.ui._repeatNodes).length, LOG_LIMIT,
-         "repeated nodes pruned from repeatNodes");
+    is(hud.ui.outputNode.querySelectorAll(".message").length, LOG_LIMIT,
+       "number of messages");
+
+    is(Object.keys(hud.ui._repeatNodes).length, LOG_LIMIT,
+       "repeated nodes pruned from repeatNodes");
 
-      let msg = [...result.matched][0];
-      let repeats = msg.querySelector(".message-repeats");
-      is(repeats.getAttribute("value"), 1,
-         "repeated nodes pruned from repeatNodes (confirmed)");
+    let msg = [...result.matched][0];
+    let repeats = msg.querySelector(".message-repeats");
+    is(repeats.getAttribute("value"), 1,
+       "repeated nodes pruned from repeatNodes (confirmed)");
+  }
 
-      finishTest();
-    });
-  });
+  function logCSSMessage(msg) {
+    let node = hud.ui.createMessageNode(CATEGORY_CSS, SEVERITY_WARNING, msg);
+    hud.ui.outputMessage(CATEGORY_CSS, node);
+  }
 }
-
-function countMessageNodes() {
-  let outputNode = HUDService.getHudByWindow(content).outputNode;
-  return outputNode.querySelectorAll(".message").length;
-}
--- a/browser/metro/shell/testing/Makefile.in
+++ b/browser/metro/shell/testing/Makefile.in
@@ -1,15 +1,12 @@
 # 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/.
 
-# static win runtime linking
-USE_STATIC_LIBS = 1
-
 # don't use moz glue libs
 MOZ_GLUE_LDFLAGS =
 MOZ_GLUE_PROGRAM_LDFLAGS =
 
 include $(topsrcdir)/config/config.mk
 
 OS_LIBS = \
 	kernel32.lib \
--- a/browser/metro/shell/testing/moz.build
+++ b/browser/metro/shell/testing/moz.build
@@ -12,8 +12,11 @@ SOURCES += [
 
 # We want this exe in dist/bin
 DIST_SUBDIR = ''
 
 for var in ('UNICODE', '_UNICODE'):
     DEFINES[var] = True
 
 NO_PGO = True
+
+# static win runtime linking
+USE_STATIC_LIBS = True
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -518,25 +518,21 @@ toolbar .toolbarbutton-1:not([type="menu
   #forward-button:hover:active:not([disabled="true"]) {
     -moz-image-region: rect(18px, 72px, 36px, 54px);
   }
 
   #home-button@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 126px, 36px, 108px);
   }
 
-  #bookmarks-menu-button@toolbarButtonPressed@ {
+  #bookmarks-menu-button[buttonover]@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 144px, 36px, 126px);
   }
 
-  #bookmarks-menu-button[open] {
-    -moz-image-region: rect(36px, 144px, 54px, 126px);
-  }
-
-  #bookmarks-menu-button[starred]@toolbarButtonPressed@ {
+  #bookmarks-menu-button[starred][buttonover]@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 162px, 36px, 144px);
   }
 
   #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
     -moz-image-region: rect(0px, 630px, 18px, 612px);
   }
 
   #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover:active:not([disabled="true"]) > .dropmarker-icon {
@@ -725,29 +721,25 @@ toolbar .toolbarbutton-1:not([type="menu
   #home-button[cui-areatype="toolbar"]:hover:active {
     -moz-image-region: rect(36px, 252px, 72px, 216px);
   }
 
   #bookmarks-menu-button[cui-areatype="toolbar"] {
     -moz-image-region: rect(0, 288px, 36px, 252px);
   }
 
-  #bookmarks-menu-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+  #bookmarks-menu-button[cui-areatype="toolbar"][buttonover]:hover:active:not([disabled="true"]) {
     -moz-image-region: rect(36px, 288px, 72px, 252px);
   }
 
-  #bookmarks-menu-button[cui-areatype="toolbar"][open] {
-    -moz-image-region: rect(72px, 288px, 108px, 252px);
-  }
-
   #bookmarks-menu-button[cui-areatype="toolbar"][starred] {
     -moz-image-region: rect(0, 324px, 36px, 288px);
   }
 
-  #bookmarks-menu-button[cui-areatype="toolbar"][starred]:hover:active:not([disabled="true"]) {
+  #bookmarks-menu-button[cui-areatype="toolbar"][starred][buttonover]:hover:active:not([disabled="true"]) {
     -moz-image-region: rect(36px, 324px, 72px, 288px);
   }
 
   #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
     -moz-image-region: rect(0px, 1260px, 36px, 1224px);
   }
 
   #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover:active:not([disabled="true"]) > .dropmarker-icon {
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -196,18 +196,18 @@ toolbaritem[cui-areatype="menu-panel"][s
 .panel-customization-placeholder-child {
   -moz-appearance: none;
   -moz-box-orient: vertical;
   width: calc(@menuPanelButtonWidth@);
   height: calc(40px + 4em);
 }
 
 /* Help SDK buttons fit in. */
-toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-placeholder,
-#personal-bookmarks[cui-areatype="menu-panel"] > #bookmarks-toolbar-placeholder {
+toolbarpaletteitem[place="palette"] > toolbarbutton[sdk-button="true"] > .toolbarbutton-icon,
+toolbarbutton[sdk-button="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon {
   height: 32px;
   width: 32px;
 }
 
 .customization-palette .toolbarbutton-1 {
   -moz-appearance: none;
   -moz-box-orient: vertical;
 }
--- a/browser/themes/shared/devtools/netmonitor.inc.css
+++ b/browser/themes/shared/devtools/netmonitor.inc.css
@@ -370,20 +370,16 @@ box.requests-menu-status {
 }
 
 .theme-light .side-menu-widget-item:not(.selected)[odd] {
   background: rgba(128,128,128,0.05);
 }
 
 /* Network request details */
 
-#details-pane {
-  max-width: 500px;
-}
-
 #details-pane-toggle {
   background: none;
   box-shadow: none;
   border-color: transparent;
   list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
   -moz-image-region: rect(0px,16px,16px,0px);
 }
 
@@ -497,22 +493,30 @@ box.requests-menu-status {
 }
 
 /* Footer */
 
 #requests-menu-footer {
   border-top: solid 1px hsla(210,5%,5%,.3);
 }
 
+.theme-dark #requests-menu-footer {
+  background: url(background-noise-toolbar.png), #343c45; /* Toolbars */
+}
+
+.theme-light #requests-menu-footer {
+  background: url(background-noise-toolbar.png), #f0f1f2; /* Toolbars */
+}
+
 .requests-menu-footer-button,
 .requests-menu-footer-label {
   min-width: 1em;
   margin: 0;
   border: none;
-  padding: 2px 0.75vw;
+  padding: 2px 1vw;
 }
 
 .theme-dark .requests-menu-footer-button,
 .theme-dark .requests-menu-footer-label {
   color: #f5f7fa; /* Light foreground text */
 }
 
 .theme-light .requests-menu-footer-button,
@@ -735,23 +739,17 @@ box.requests-menu-status {
   #requests-menu-toolbar {
     height: 22px;
   }
 
   .requests-menu-header-button {
     min-height: 20px;
   }
 
-  .requests-menu-footer-button,
-  .requests-menu-footer-label {
-    padding: 2px 1vw;
-  }
-
   #details-pane {
-    max-width: none;
     margin: 0 !important;
     /* To prevent all the margin hacks to hide the sidebar. */
   }
 
   .requests-menu-status-and-method {
     width: 16vw;
   }
 
--- a/browser/themes/shared/devtools/toolbars.inc.css
+++ b/browser/themes/shared/devtools/toolbars.inc.css
@@ -1,16 +1,19 @@
 %if 0
 /* 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/. */
 %endif
 %filter substitution
-%define smallSeparator linear-gradient(transparent 15%, #5a6169 15%, #5a6169 85%, transparent 85%)
-%define solidSeparator linear-gradient(#2d5b7d, #2d5b7d)
+%define smallSeparatorDark linear-gradient(transparent 15%, #5a6169 15%, #5a6169 85%, transparent 85%)
+%define smallSeparatorLight linear-gradient(transparent 15%, #aaa 15%, #aaa 85%, transparent 85%)
+%define solidSeparatorDark linear-gradient(#2d5b7d, #2d5b7d)
+%define solidSeparatorLight linear-gradient(#aaa, #aaa)
+
 
 .devtools-toolbar {
   -moz-appearance: none;
   padding: 4px 3px;
   border-bottom-width: 1px;
   border-bottom-style: solid;
 }
 
@@ -379,72 +382,75 @@
 }
 
 .devtools-sidebar-tabs:-moz-locale-dir(rtl) > tabs > tab {
   background-position: calc(100% - 1px), 100%;
 }
 
 .devtools-sidebar-tabs > tabs > tab {
   background-color: transparent;
-  background-image: linear-gradient(transparent, transparent), @smallSeparator@;
 }
 
-.theme-dark .devtools-sidebar-tabs > tabs > tab:hover {
-  background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @smallSeparator@;
+.theme-dark .devtools-sidebar-tabs > tabs > tab {
+  background-image: linear-gradient(transparent, transparent), @smallSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab:hover:active {
-  background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @smallSeparator@;
+  background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @smallSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab[selected] + tab {
-  background-image: linear-gradient(transparent, transparent), @solidSeparator@;
+  background-image: linear-gradient(transparent, transparent), @solidSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab[selected] + tab:hover {
-  background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @solidSeparator@;
+  background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @solidSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab[selected] + tab:hover:active {
-  background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @solidSeparator@;
+  background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @solidSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab[selected] {
   color: #f5f7fa;
-  background-image: linear-gradient(#1d4f73, #1d4f73), @solidSeparator@;
+  background-image: linear-gradient(#1d4f73, #1d4f73), @solidSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab[selected]:hover {
-  background-image: linear-gradient(#274f64, #274f64), @solidSeparator@;
+  background-image: linear-gradient(#274f64, #274f64), @solidSeparatorDark@;
 }
 
 .theme-dark .devtools-sidebar-tabs > tabs > tab[selected]:hover:active {
-  background-image: linear-gradient(#1f3e4f, #1f3e4f), @solidSeparator@;
+  background-image: linear-gradient(#1f3e4f, #1f3e4f), @solidSeparatorDark@;
+}
+
+.theme-light .devtools-sidebar-tabs > tabs > tab {
+  background-image: linear-gradient(transparent, transparent), @smallSeparatorLight@;
 }
 
 .theme-light .devtools-sidebar-tabs > tabs > tab:hover {
-  background-image: linear-gradient(#ddd, #ddd), @smallSeparator@;
+  background-image: linear-gradient(#ddd, #ddd), @smallSeparatorLight@;
 }
 
 .theme-light .devtools-sidebar-tabs > tabs > tab:hover:active {
-  background-image: linear-gradient(#ddd, #ddd), @smallSeparator@;
+  background-image: linear-gradient(#ddd, #ddd), @smallSeparatorLight@;
 }
 
 .theme-light .devtools-sidebar-tabs > tabs > tab[selected] + tab {
-  background-image: linear-gradient(transparent, transparent), @solidSeparator@;
+  background-image: linear-gradient(transparent, transparent), @solidSeparatorLight@;
 }
 
 .theme-light .devtools-sidebar-tabs > tabs > tab[selected] + tab:hover {
-  background-image: linear-gradient(#ddd, #ddd), @solidSeparator@;
+  background-image: linear-gradient(#ddd, #ddd), @solidSeparatorLight@;
 }
 
 .theme-light .devtools-sidebar-tabs > tabs > tab[selected],
 .theme-light .devtools-sidebar-tabs > tabs > tab[selected]:hover:active {
   color: #f5f7fa;
-  background-image: linear-gradient(#4c9ed9, #4c9ed9), @solidSeparator@;
+  background-image: linear-gradient(#4c9ed9, #4c9ed9), @solidSeparatorLight@;
 }
 
 /* Toolbox - moved from toolbox.css.
  * Rules that apply to the global toolbox like command buttons,
  * devtools tabs, docking buttons, etc. */
 
 #toolbox-controls {
   margin: 0 4px;
--- a/build/win32/Makefile.in
+++ b/build/win32/Makefile.in
@@ -1,18 +1,12 @@
 # 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/.
 
-ifdef ENABLE_TESTS
-
-USE_STATIC_LIBS = 1
-
-endif # ENABLE_TESTS
-
 MOZ_GLUE_LDFLAGS =
 
 include $(topsrcdir)/config/rules.mk
 
 ifdef WIN32_REDIST_DIR
 ifndef MOZ_DEBUG
 
 ifeq (1600,$(_MSC_VER))
--- a/build/win32/crashinjectdll/Makefile.in
+++ b/build/win32/crashinjectdll/Makefile.in
@@ -1,8 +1,5 @@
 # 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/.
 
-DEFFILE = $(srcdir)/crashinjectdll.def
-USE_STATIC_LIBS = 1
-
 MOZ_GLUE_LDFLAGS =
--- a/build/win32/crashinjectdll/moz.build
+++ b/build/win32/crashinjectdll/moz.build
@@ -6,8 +6,12 @@
 
 SOURCES += [
     'crashinjectdll.cpp',
 ]
 
 LIBRARY_NAME = 'crashinjectdll'
 
 FORCE_SHARED_LIB = True
+
+DEFFILE = SRCDIR + '/crashinjectdll.def'
+
+USE_STATIC_LIBS = True
--- a/build/win32/moz.build
+++ b/build/win32/moz.build
@@ -9,10 +9,11 @@ if CONFIG['_MSC_VER'] and CONFIG['OS_TES
 
 TEST_DIRS += ['crashinjectdll']
 
 if CONFIG['ENABLE_TESTS']:
     PROGRAM = 'crashinject'
     SOURCES += [
         'crashinject.cpp',
     ]
+    USE_STATIC_LIBS = True
 
 NO_PGO = True
--- a/build/win32/vmwarerecordinghelper/Makefile.in
+++ b/build/win32/vmwarerecordinghelper/Makefile.in
@@ -1,9 +1,5 @@
 # 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/.
 
-DEFFILE = $(srcdir)/$(LIBRARY_NAME).def
-
-USE_STATIC_LIBS = 1
-
 MOZ_GLUE_LDFLAGS =
--- a/build/win32/vmwarerecordinghelper/moz.build
+++ b/build/win32/vmwarerecordinghelper/moz.build
@@ -6,8 +6,12 @@
 
 SOURCES += [
     'vmwarerecordinghelper.cpp',
 ]
 
 LIBRARY_NAME = 'vmwarerecordinghelper'
 
 FORCE_SHARED_LIB = True
+
+DEFFILE = '%s/%s.def' % (SRCDIR, LIBRARY_NAME)
+
+USE_STATIC_LIBS = True
--- a/config/config.mk
+++ b/config/config.mk
@@ -56,16 +56,17 @@ endif
   JS_MODULES_PATH \
   LIBRARY_NAME \
   LIBXUL_LIBRARY \
   MODULE \
   MSVC_ENABLE_PGO \
   NO_DIST_INSTALL \
   PARALLEL_DIRS \
   PROGRAM \
+  RESOURCE_FILES \
   SDK_HEADERS \
   SIMPLE_PROGRAMS \
   TEST_DIRS \
   TIERS \
   TOOL_DIRS \
   XPCSHELL_TESTS \
   XPIDL_MODULE \
   $(NULL)
--- a/configure.in
+++ b/configure.in
@@ -3843,16 +3843,17 @@ MOZ_OGG=1
 MOZ_RAW=
 MOZ_VORBIS=
 MOZ_TREMOR=
 MOZ_WAVE=1
 MOZ_SAMPLE_TYPE_FLOAT32=
 MOZ_SAMPLE_TYPE_S16=
 MOZ_OPUS=1
 MOZ_WEBM=1
+MOZ_GSTREAMER=
 MOZ_DIRECTSHOW=
 MOZ_WMF=
 MOZ_FMP4=
 MOZ_WEBRTC=1
 MOZ_PEERCONNECTION=
 MOZ_SRTP=
 MOZ_WEBRTC_SIGNALING=
 MOZ_WEBRTC_ASSERT_ALWAYS=1
@@ -5475,54 +5476,69 @@ AC_SUBST(MOZ_PULSEAUDIO_CFLAGS)
 dnl ========================================================
 dnl = Enable GStreamer
 dnl ========================================================
 case "$OS_TARGET" in
 WINNT|Darwin|Android)
     ;;
 *)
     MOZ_GSTREAMER=1
+    GST_API_VERSION=0.10
     ;;
 esac
 
-MOZ_ARG_ENABLE_BOOL(gstreamer,
-[  --enable-gstreamer           Enable GStreamer support],
-MOZ_GSTREAMER=1,
-MOZ_GSTREAMER=)
-
-if test "$MOZ_GSTREAMER"; then
-    # API version, eg 0.10, 1.0 etc
+MOZ_ARG_ENABLE_STRING(gstreamer,
+[  --enable-gstreamer[=0.10]           Enable GStreamer support],
+[ MOZ_GSTREAMER=1
+  # API version, eg 0.10, 1.0 etc
+  if test -z "$enableval" -o "$enableval" = "yes"; then
     GST_API_VERSION=0.10
+  else
+    GST_API_VERSION=$enableval
+  fi],
+)
+
+if test -n "$MOZ_GSTREAMER"; then
     # core/base release number
-    GST_VERSION=0.10.25
+    if test "$GST_API_VERSION" = "1.0"; then
+      GST_VERSION=1.0
+    else
+      GST_VERSION=0.10.25
+    fi
+
     PKG_CHECK_MODULES(GSTREAMER,
                       gstreamer-$GST_API_VERSION >= $GST_VERSION
                       gstreamer-app-$GST_API_VERSION
-                      gstreamer-plugins-base-$GST_API_VERSION, ,
-                      AC_MSG_ERROR([gstreamer and gstreamer-plugins-base development packages are needed to build gstreamer backend. Install them or disable gstreamer support with --disable-gstreamer]))
-    if test -n "$GSTREAMER_LIBS"; then
-       _SAVE_LDFLAGS=$LDFLAGS
-       LDFLAGS="$LDFLAGS $GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION"
-       AC_TRY_LINK(,[return 0;],_HAVE_LIBGSTVIDEO=1,_HAVE_LIBGSTVIDEO=)
-       if test -n "$_HAVE_LIBGSTVIDEO" ; then
-          GSTREAMER_LIBS="$GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION"
-       else
-          AC_MSG_ERROR([gstreamer-plugins-base found, but no libgstvideo. Something has gone terribly wrong. Try reinstalling gstreamer-plugins-base; failing that, disable the gstreamer backend with --disable-gstreamer.])
-       fi
-       LDFLAGS=$_SAVE_LDFLAGS
+                      gstreamer-plugins-base-$GST_API_VERSION,
+                      [_HAVE_GSTREAMER=1],
+                      [_HAVE_GSTREAMER=])
+    if test -z "$_HAVE_GSTREAMER"; then
+        AC_MSG_ERROR([gstreamer and gstreamer-plugins-base development packages are needed to build gstreamer backend. Install them or disable gstreamer support with --disable-gstreamer])
+    fi
+
+    _SAVE_LDFLAGS=$LDFLAGS
+    LDFLAGS="$LDFLAGS $GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION"
+    AC_TRY_LINK(,[return 0;],_HAVE_LIBGSTVIDEO=1,_HAVE_LIBGSTVIDEO=)
+    if test -n "$_HAVE_LIBGSTVIDEO" ; then
+        GSTREAMER_LIBS="$GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION"
     else
-       AC_MSG_ERROR([gstreamer and gstreamer-plugins-base development packages are needed to build gstreamer backend. Install them or disable gstreamer support with --disable-gstreamer])
-    fi
-fi
-AC_SUBST(GSTREAMER_CFLAGS)
-AC_SUBST(GSTREAMER_LIBS)
+        AC_MSG_ERROR([gstreamer-plugins-base found, but no libgstvideo. Something has gone terribly wrong. Try reinstalling gstreamer-plugins-base; failing that, disable the gstreamer backend with --disable-gstreamer.])
+    fi
+    LDFLAGS=$_SAVE_LDFLAGS
+
+    AC_SUBST(GSTREAMER_CFLAGS)
+    AC_SUBST(GSTREAMER_LIBS)
+fi
+
 AC_SUBST(MOZ_GSTREAMER)
+AC_SUBST(GST_API_VERSION)
 
 if test -n "$MOZ_GSTREAMER"; then
-   AC_DEFINE(MOZ_GSTREAMER)
+     AC_DEFINE(MOZ_GSTREAMER)
+     AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION")
 fi
 
 
 dnl ========================================================
 dnl Permissions System
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(permissions,
 [  --disable-permissions   Disable permissions (popup and cookie blocking)],
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -40,17 +40,26 @@ var gETLDService = Components.classes["@
 // scheme          = <scheme production from RFC 3986>
 const R_SCHEME     = new RegExp ("([a-zA-Z0-9\\-]+)", 'i');
 const R_GETSCHEME  = new RegExp ("^" + R_SCHEME.source + "(?=\\:)", 'i');
 
 // scheme-source   = scheme ":"
 const R_SCHEMESRC  = new RegExp ("^" + R_SCHEME.source + "\\:$", 'i');
 
 // host-char       = ALPHA / DIGIT / "-"
-const R_HOSTCHAR   = new RegExp ("[a-zA-Z0-9\\-]", 'i');
+// For the app: protocol, we need to add {} to the valid character set
+const HOSTCHAR     = "{}a-zA-Z0-9\\-";
+const R_HOSTCHAR   = new RegExp ("[" + HOSTCHAR + "]", 'i');
+
+// Complementary character set of HOSTCHAR (characters that can't appear)
+const R_COMP_HCHAR = new RegExp ("[^" + HOSTCHAR + "]", "i");
+
+// Invalid character set for host strings (which can include dots and star)
+const R_INV_HCHAR  = new RegExp ("[^" + HOSTCHAR + "\\.\\*]", 'i');
+
 
 // host            = "*" / [ "*." ] 1*host-char *( "." 1*host-char )
 const R_HOST       = new RegExp ("\\*|(((\\*\\.)?" + R_HOSTCHAR.source +
                               "+)" + "(\\." + R_HOSTCHAR.source + "+)*)", 'i');
 
 // port            = ":" ( 1*DIGIT / "*" )
 const R_PORT       = new RegExp ("(\\:([0-9]+|\\*))", 'i');
 
@@ -279,20 +288,24 @@ CSPRep.ALLOW_DIRECTIVE   = "allow";
   *        URI representing the "self" source
   * @param reportOnly (optional)
   *        whether or not this CSP is report-only (defaults to false)
   * @param docRequest (optional)
   *        request for the parent document which may need to be suspended
   *        while the policy-uri is asynchronously fetched
   * @param csp (optional)
   *        the CSP object to update once the policy has been fetched
+  * @param enforceSelfChecks (optional)
+  *        if present, and "true", will check to be sure "self" has the
+  *        appropriate values to inherit when they are omitted from the source.
   * @returns
   *        an instance of CSPRep
   */
-CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp) {
+CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp,
+                             enforceSelfChecks) {
   var SD = CSPRep.SRC_DIRECTIVES_OLD;
   var UD = CSPRep.URI_DIRECTIVES;
   var aCSPR = new CSPRep();
   aCSPR._originalText = aStr;
   aCSPR._innerWindowID = innerWindowFromRequest(docRequest);
   if (typeof reportOnly === 'undefined') reportOnly = false;
   aCSPR._reportOnlyMode = reportOnly;
 
@@ -356,28 +369,30 @@ CSPRep.fromString = function(aStr, self,
       cspWarn(aCSPR, CSPLocalizer.getStr("allowDirectiveIsDeprecated"));
       if (aCSPR._directives.hasOwnProperty(SD.DEFAULT_SRC)) {
         // Check for duplicate default-src and allow directives
         cspError(aCSPR, CSPLocalizer.getFormatStr("duplicateDirective",
                                                   [dirname]));
         CSPdebug("Skipping duplicate directive: \"" + dir + "\"");
         continue directive;
       }
-      var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri, true);
+      var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri,
+                                        enforceSelfChecks);
       if (dv) {
         aCSPR._directives[SD.DEFAULT_SRC] = dv;
         continue directive;
       }
     }
 
     // SOURCE DIRECTIVES ////////////////////////////////////////////////
     for each(var sdi in SD) {
       if (dirname === sdi) {
         // process dirs, and enforce that 'self' is defined.
-        var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri, true);
+        var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri,
+                                          enforceSelfChecks);
         if (dv) {
           aCSPR._directives[sdi] = dv;
           continue directive;
         }
       }
     }
 
     // REPORT URI ///////////////////////////////////////////////////////
@@ -521,22 +536,26 @@ CSPRep.fromString = function(aStr, self,
   *        URI representing the "self" source
   * @param reportOnly (optional)
   *        whether or not this CSP is report-only (defaults to false)
   * @param docRequest (optional)
   *        request for the parent document which may need to be suspended
   *        while the policy-uri is asynchronously fetched
   * @param csp (optional)
   *        the CSP object to update once the policy has been fetched
+  * @param enforceSelfChecks (optional)
+  *        if present, and "true", will check to be sure "self" has the
+  *        appropriate values to inherit when they are omitted from the source.
   * @returns
   *        an instance of CSPRep
   */
 // When we deprecate our original CSP implementation, we rename this to
 // CSPRep.fromString and remove the existing CSPRep.fromString above.
-CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, csp) {
+CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, csp,
+                                          enforceSelfChecks) {
   var SD = CSPRep.SRC_DIRECTIVES_NEW;
   var UD = CSPRep.URI_DIRECTIVES;
   var aCSPR = new CSPRep(true);
   aCSPR._originalText = aStr;
   aCSPR._innerWindowID = innerWindowFromRequest(docRequest);
   if (typeof reportOnly === 'undefined') reportOnly = false;
   aCSPR._reportOnlyMode = reportOnly;
 
@@ -602,17 +621,18 @@ CSPRep.fromStringSpecCompliant = functio
       CSPdebug("Skipping duplicate directive: \"" + dir + "\"");
       continue directive;
     }
 
     // SOURCE DIRECTIVES ////////////////////////////////////////////////
     for each(var sdi in SD) {
       if (dirname === sdi) {
         // process dirs, and enforce that 'self' is defined.
-        var dv = CSPSourceList.fromString(dirvalue, aCSPR, self, true);
+        var dv = CSPSourceList.fromString(dirvalue, aCSPR, self,
+                                          enforceSelfChecks);
         if (dv) {
           // Check for unsafe-inline in style-src
           if (sdi === "style-src" && dv._allowUnsafeInline) {
              aCSPR._allowInlineStyles = true;
           } else if (sdi === "script-src") {
             // Check for unsafe-inline and unsafe-eval in script-src
             if (dv._allowUnsafeInline) {
               aCSPR._allowInlineScripts = true;
@@ -1316,16 +1336,28 @@ CSPSource.fromString = function(aStr, aC
     cspError(aCSPRep, CSPLocalizer.getStr("selfDataNotProvided"));
     return null;
   }
 
   if (self && !(self instanceof CSPSource)) {
     self = CSPSource.create(self, aCSPRep, undefined, false);
   }
 
+  // check for 'unsafe-inline' (case insensitive)
+  if (aStr.toLowerCase() === "'unsafe-inline'"){
+    sObj._allowUnsafeInline = true;
+    return sObj;
+  }
+
+  // check for 'unsafe-eval' (case insensitive)
+  if (aStr.toLowerCase() === "'unsafe-eval'"){
+    sObj._allowUnsafeEval = true;
+    return sObj;
+  }
+
   // Check for scheme-source match - this only matches if the source
   // string is just a scheme with no host.
   if (R_SCHEMESRC.test(aStr)) {
     var schemeSrcMatch = R_GETSCHEME.exec(aStr);
     sObj._scheme = schemeSrcMatch[0];
     if (!sObj._host) sObj._host = CSPHost.fromString("*");
     if (!sObj._port) sObj._port = "*";
     return sObj;
@@ -1404,28 +1436,16 @@ CSPSource.fromString = function(aStr, aC
       cspError(aCSPRep, CSPLocalizer.getStr("selfKeywordNoSelfData"));
       return null;
     }
     sObj._self = self.clone();
     sObj._isSelf = true;
     return sObj;
   }
 
-  // check for 'unsafe-inline' (case insensitive)
-  if (aStr.toLowerCase() === "'unsafe-inline'"){
-    sObj._allowUnsafeInline = true;
-    return sObj;
-  }
-
-  // check for 'unsafe-eval' (case insensitive)
-  if (aStr.toLowerCase() === "'unsafe-eval'"){
-    sObj._allowUnsafeEval = true;
-    return sObj;
-  }
-
   cspError(aCSPRep, CSPLocalizer.getFormatStr("couldntParseInvalidSource",
                                               [aStr]));
   return null;
 };
 
 CSPSource.validSchemeName = function(aStr) {
   // <scheme-name>       ::= <alpha><scheme-suffix>
   // <scheme-suffix>     ::= <scheme-chr>
@@ -1485,20 +1505,20 @@ CSPSource.prototype = {
    * Generates canonical string representation of the Source.
    */
   toString:
   function() {
     if (this._isSelf)
       return this._self.toString();
 
     if (this._allowUnsafeInline)
-      return "unsafe-inline";
+      return "'unsafe-inline'";
 
     if (this._allowUnsafeEval)
-      return "unsafe-eval";
+      return "'unsafe-eval'";
 
     var s = "";
     if (this.scheme)
       s = s + this.scheme + "://";
     if (this._host)
       s = s + this._host;
     if (this.port)
       s = s + ":" + this.port;
@@ -1602,17 +1622,17 @@ this.CSPHost = function CSPHost() {
  *        string rep of a CSP Host
  * @returns
  *        an instance of CSPHost
  */
 CSPHost.fromString = function(aStr) {
   if (!aStr) return null;
 
   // host string must be LDH with dots and stars.
-  var invalidChar = aStr.match(/[^a-zA-Z0-9\-\.\*]/);
+  var invalidChar = aStr.match(R_INV_HCHAR);
   if (invalidChar) {
     CSPdebug("Invalid character '" + invalidChar + "' in host " + aStr);
     return null;
   }
 
   var hObj = new CSPHost();
   hObj._segments = aStr.split(/\./);
   if (hObj._segments.length < 1)
@@ -1623,17 +1643,17 @@ CSPHost.fromString = function(aStr) {
     var seg = hObj._segments[i];
     if (seg == "*") {
       if (i > 0) {
         // Wildcard must be FIRST
         CSPdebug("Wildcard char located at invalid position in '" + aStr + "'");
         return null;
       }
     }
-    else if (seg.match(/[^a-zA-Z0-9\-]/)) {
+    else if (seg.match(R_COMP_HCHAR)) {
       // Non-wildcard segment must be LDH string
       CSPdebug("Invalid segment '" + seg + "' in host value");
       return null;
     }
   }
   return hObj;
 };
 
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -696,17 +696,19 @@ nsIContent::PreHandleEvent(nsEventChainP
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = true;
   aVisitor.mMayHaveListenerManager = HasListenerManager();
 
   // Don't propagate mouseover and mouseout events when mouse is moving
   // inside chrome access only content.
   bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
   if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
-       aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
+       aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH ||
+       aVisitor.mEvent->message == NS_POINTER_OVER ||
+       aVisitor.mEvent->message == NS_POINTER_OUT) &&
       // Check if we should stop event propagation when event has just been
       // dispatched or when we're about to propagate from
       // chrome access only subtree.
       ((this == aVisitor.mEvent->originalTarget &&
         !ChromeOnlyAccess()) || isAnonForEvents)) {
      nsCOMPtr<nsIContent> relatedTarget =
        do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
     if (relatedTarget &&
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -406,16 +406,28 @@ ContentSecurityPolicy.prototype = {
 /* ........ Methods .............. */
 
   /**
    * Adds a new policy to our list of policies for this CSP context.
    * @returns the count of policies.
    */
   appendPolicy:
   function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant) {
+    return this._appendPolicyInternal(aPolicy, selfURI, aReportOnly,
+                                      aSpecCompliant, true);
+  },
+
+  /**
+   * Adds a new policy to our list of policies for this CSP context.
+   * Only to be called from this module (not exported)
+   * @returns the count of policies.
+   */
+  _appendPolicyInternal:
+  function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant,
+                            aEnforceSelfChecks) {
 #ifndef MOZ_B2G
     CSPdebug("APPENDING POLICY: " + aPolicy);
     CSPdebug("            SELF: " + (selfURI ? selfURI.asciiSpec : " null"));
     CSPdebug("CSP 1.0 COMPLIANT : " + aSpecCompliant);
 #endif
 
     // For nested schemes such as view-source: make sure we are taking the
     // innermost URI to use as 'self' since that's where we will extract the
@@ -438,23 +450,25 @@ ContentSecurityPolicy.prototype = {
     // If we want to be CSP 1.0 spec compliant, use the new parser.
     // The old one will be deprecated in the future and will be
     // removed at that time.
     if (aSpecCompliant) {
       newpolicy = CSPRep.fromStringSpecCompliant(aPolicy,
                                                  selfURI,
                                                  aReportOnly,
                                                  this._weakDocRequest.get(),
-                                                 this);
+                                                 this,
+                                                 aEnforceSelfChecks);
     } else {
       newpolicy = CSPRep.fromString(aPolicy,
                                     selfURI,
                                     aReportOnly,
                                     this._weakDocRequest.get(),
-                                    this);
+                                    this,
+                                    aEnforceSelfChecks);
     }
 
     newpolicy._specCompliant = !!aSpecCompliant;
     newpolicy._isInitialized = true;
     this._policies.push(newpolicy);
     this._cache.clear(); // reset cache since effective policy changes
   },
 
@@ -945,17 +959,18 @@ ContentSecurityPolicy.prototype = {
     this._requestOrigin.QueryInterface(Ci.nsIURI);
 
     for (let pCount = aStream.read32(); pCount > 0; pCount--) {
       let polStr        = aStream.readString();
       let reportOnly    = aStream.readBoolean();
       let specCompliant = aStream.readBoolean();
       // don't need self info because when the policy is turned back into a
       // string, 'self' is replaced with the explicit source expression.
-      this.appendPolicy(polStr, null, reportOnly, specCompliant);
+      this._appendPolicyInternal(polStr, null, reportOnly, specCompliant,
+                                 false);
     }
 
     // NOTE: the document instance that's deserializing this object (via its
     // principal) should hook itself into this._principal manually.  If they
     // don't, the CSP reports will likely be blocked by nsMixedContentBlocker.
   },
 
   write:
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -539,17 +539,19 @@ nsDOMFileReader::GetAsDataURL(nsIDOMBlob
     aResult.AppendLiteral("application/octet-stream");
   }
   aResult.AppendLiteral(";base64,");
 
   nsCString encodedData;
   rv = Base64Encode(Substring(aFileData, aDataLen), encodedData);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  AppendASCIItoUTF16(encodedData, aResult);
+  if (!AppendASCIItoUTF16(encodedData, aResult, fallible_t())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   return NS_OK;
 }
 
 /* virtual */ JSObject*
 nsDOMFileReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return FileReaderBinding::Wrap(aCx, aScope, this);
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1026,17 +1026,17 @@ nsFrameMessageManager::ReceiveMessage(ns
         JS::Rooted<JSObject*> thisObject(cx, thisValue.toObjectOrNull());
 
         JSAutoCompartment tac(cx, thisObject);
         if (!JS_WrapValue(cx, &argv)) {
           return NS_ERROR_UNEXPECTED;
         }
 
         if (!JS_CallFunctionValue(cx, thisObject,
-                                  funval, 1, argv.address(), rval.address())) {
+                                  funval, argv, rval.address())) {
           nsJSUtils::ReportPendingException(cx);
           continue;
         }
         if (aJSONRetVal) {
           nsString json;
           if (!JS_Stringify(cx, &rval, JS::NullPtr(), JS::NullHandleValue,
                            JSONCreator, &json)) {
             nsJSUtils::ReportPendingException(cx);
@@ -1414,17 +1414,17 @@ nsFrameScriptExecutor::LoadFrameScriptIn
     if (funobj) {
       JS::Rooted<JSObject*> method(cx, JS_CloneFunctionObject(cx, funobj, global));
       if (!method) {
         return;
       }
       JS::Rooted<JS::Value> rval(cx);
       JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
       ok = JS_CallFunctionValue(cx, global, methodVal,
-                                0, nullptr, rval.address());
+                                JS::EmptyValueArray, rval.address());
     } else if (script) {
       ok = JS_ExecuteScript(cx, global, script, nullptr);
     }
 
     if (!ok) {
       nsJSUtils::ReportPendingException(cx);
     }
   }
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -498,16 +498,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
             window->SetHasAudioAvailableEventListeners();
           }
           if (elm->MayHaveTouchEventListener()) {
             window->SetHasTouchEventListeners();
           }
           if (elm->MayHaveMouseEnterLeaveEventListener()) {
             window->SetHasMouseEnterLeaveEventListeners();
           }
+          if (elm->MayHavePointerEnterLeaveEventListener()) {
+            window->SetHasPointerEnterLeaveEventListeners();
+          }
         }
       }
     }
 
     if (wasRegistered && oldDoc != newDoc) {
       nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
       if (domMediaElem) {
         HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aNode);
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -3173,20 +3173,24 @@ nsObjectLoadingContent::LegacyCall(JSCon
   if (nsDOMClassInfo::ObjectIsNativeWrapper(aCx, obj)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return JS::UndefinedValue();
   }
 
   obj = thisContent->GetWrapper();
   // Now wrap things up into the compartment of "obj"
   JSAutoCompartment ac(aCx, obj);
-  nsTArray<JS::Value> args(aArguments);
-  JS::AutoArrayRooter rooter(aCx, args.Length(), args.Elements());
-  for (size_t i = 0; i < args.Length(); i++) {
-    if (!JS_WrapValue(aCx, rooter.handleAt(i))) {
+  JS::AutoValueVector args(aCx);
+  if (!args.append(aArguments.Elements(), aArguments.Length())) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return JS::UndefinedValue();
+  }
+
+  for (size_t i = 0; i < args.length(); i++) {
+    if (!JS_WrapValue(aCx, args.handleAt(i))) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return JS::UndefinedValue();
     }
   }
 
   JS::Rooted<JS::Value> thisVal(aCx, aThisVal);
   if (!JS_WrapValue(aCx, &thisVal)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
@@ -3216,18 +3220,17 @@ nsObjectLoadingContent::LegacyCall(JSCon
   }
 
   if (!pi_obj) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return JS::UndefinedValue();
   }
 
   JS::Rooted<JS::Value> retval(aCx);
-  bool ok = JS::Call(aCx, thisVal, pi_obj, rooter.length(), rooter.start(),
-                     &retval);
+  bool ok = JS::Call(aCx, thisVal, pi_obj, args, &retval);
   if (!ok) {
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::UndefinedValue();
   }
 
   Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true);
   return retval;
 }
--- a/content/base/test/unit/test_csputils.js
+++ b/content/base/test/unit/test_csputils.js
@@ -109,18 +109,22 @@ test(
     do_check_neq(null, h); // "lone symbol should not fail"
 
     h = CSPHost.fromString("f00b4r.com");
     do_check_neq(null, h); // "Numbers in hosts should work"
 
     h = CSPHost.fromString("foo-bar.com");
     do_check_neq(null, h); // "dashes in hosts should work"
 
+
     h = CSPHost.fromString("foo!bar.com");
     do_check_eq(null, h); // "special chars in hosts should fail"
+
+    h = CSPHost.fromString("{app-url-is-uid}");
+    do_check_neq(null, h); // "Packaged apps URLs failed"
   });
 
 test(
   function test_CSPHost_clone() {
     h = CSPHost.fromString("*.a.b.c");
     h2 = h.clone();
     for(var i in h._segments) {
       // "cloned segments should match"
@@ -172,16 +176,19 @@ test(
       //"failed to parse host with scheme and port.");
       do_check_neq(null, CSPSource.create("https://a.com:200", undefined, "http://a.com"));
 
       //Check to make sure we don't match multiple instances with regex
       do_check_eq(null, CSPSource.create("http://foo.com:bar.com:23"));
       //Port parsing should work for all schemes
       do_check_neq(null, CSPSource.create("data:"));
       do_check_neq(null, CSPSource.create("javascript:"));
+
+      //"app:// URLs should work, including the {} characters.");
+      do_check_neq(null, CSPSource.fromString("{app-host-is-uid}", undefined, "app://{app-host-is-uid}"));
     });
 
 test(
     function test_CSPSource_fromString_withSelf() {
       var src;
       src = CSPSource.create("a.com", undefined, "https://foobar.com:443");
       //"src should inherit port *
       do_check_true(src.permits("https://a.com:443"));
@@ -213,16 +220,22 @@ test(
       //"hostless schemes should be parseable."
       var aUri = NetUtil.newURI("javascript:alert('foo');");
       do_check_true(src.permits(aUri));
       //"src should reject other hosts"
       do_check_false(src.permits("https://a.com"));
       //"nothing else should be allowed"
       do_check_false(src.permits("https://foobar.com"));
 
+      src = CSPSource.create("{app-host-is-uid}", undefined, "app://{app-host-is-uid}");
+      //"src should inherit and require 'app' scheme"
+      do_check_false(src.permits("https://{app-host-is-uid}"));
+      //"src should inherit scheme 'app'"
+      do_check_true(src.permits("app://{app-host-is-uid}"));
+
     });
 
 ///////////////////// Test the source list //////////////////////
 
 test(
     function test_CSPSourceList_fromString() {
       var sd = CSPSourceList.fromString("'none'");
       //"'none' -- should parse"
new file mode 100644
--- /dev/null
+++ b/content/media/gstreamer/GStreamerAllocator.cpp
@@ -0,0 +1,197 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "GStreamerAllocator.h"
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+
+#include "GStreamerLoader.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+typedef struct
+{
+  GstAllocator parent;
+  GStreamerReader *reader;
+} MozGfxMemoryAllocator;
+
+typedef struct
+{
+  GstAllocatorClass parent;
+} MozGfxMemoryAllocatorClass;
+
+typedef struct
+{
+  GstMemory memory;
+  PlanarYCbCrImage* image;
+  guint8* data;
+} MozGfxMemory;
+
+typedef struct
+{
+  GstMeta meta;
+} MozGfxMeta;
+
+typedef struct
+{
+  GstVideoBufferPoolClass parent_class;
+} MozGfxBufferPoolClass;
+
+typedef struct
+{
+  GstVideoBufferPool pool;
+} MozGfxBufferPool;
+
+G_DEFINE_TYPE(MozGfxMemoryAllocator, moz_gfx_memory_allocator, GST_TYPE_ALLOCATOR);
+G_DEFINE_TYPE(MozGfxBufferPool, moz_gfx_buffer_pool, GST_TYPE_VIDEO_BUFFER_POOL);
+
+void
+moz_gfx_memory_reset(MozGfxMemory *mem)
+{
+  if (mem->image)
+    mem->image->Release();
+
+  ImageContainer* container = ((MozGfxMemoryAllocator*) mem->memory.allocator)->reader->GetImageContainer();
+  mem->image = reinterpret_cast<PlanarYCbCrImage*>(container->CreateImage(ImageFormat::PLANAR_YCBCR).get());
+  mem->data = mem->image->AllocateAndGetNewBuffer(mem->memory.size);
+}
+
+static GstMemory*
+moz_gfx_memory_allocator_alloc(GstAllocator* aAllocator, gsize aSize,
+    GstAllocationParams* aParams)
+{
+  MozGfxMemory* mem = g_slice_new (MozGfxMemory);
+  gsize maxsize = aSize + aParams->prefix + aParams->padding;
+  gst_memory_init(GST_MEMORY_CAST (mem),
+                  (GstMemoryFlags)aParams->flags,
+                  aAllocator, NULL, maxsize, aParams->align,
+                  aParams->prefix, aSize);
+  mem->image = NULL;
+  moz_gfx_memory_reset(mem);
+
+  return (GstMemory *) mem;
+}
+
+static void
+moz_gfx_memory_allocator_free (GstAllocator * allocator, GstMemory * gmem)
+{
+  MozGfxMemory *mem = (MozGfxMemory *) gmem;
+
+  if (mem->memory.parent)
+    goto sub_mem;
+
+  if (mem->image)
+    mem->image->Release();
+
+sub_mem:
+  g_slice_free (MozGfxMemory, mem);
+}
+
+static gpointer
+moz_gfx_memory_map (MozGfxMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+  // check that the allocation didn't fail
+  if (mem->data == nullptr)
+    return nullptr;
+
+  return mem->data + mem->memory.offset;
+}
+
+static gboolean
+moz_gfx_memory_unmap (MozGfxMemory * mem)
+{
+  return TRUE;
+}
+
+static MozGfxMemory *
+moz_gfx_memory_share (MozGfxMemory * mem, gssize offset, gsize size)
+{
+  MozGfxMemory *sub;
+  GstMemory *parent;
+
+  /* find the real parent */
+  if ((parent = mem->memory.parent) == NULL)
+    parent = (GstMemory *) mem;
+
+  if (size == (gsize) -1)
+    size = mem->memory.size - offset;
+
+  /* the shared memory is always readonly */
+  sub = g_slice_new (MozGfxMemory);
+
+  gst_memory_init (GST_MEMORY_CAST (sub),
+      (GstMemoryFlags) (GST_MINI_OBJECT_FLAGS (parent) | GST_MINI_OBJECT_FLAG_LOCK_READONLY),
+      mem->memory.allocator, &mem->memory, mem->memory.maxsize, mem->memory.align,
+      mem->memory.offset + offset, size);
+
+  sub->image = mem->image;
+  sub->data = mem->data;
+
+  return sub;
+}
+
+static void
+moz_gfx_memory_allocator_class_init (MozGfxMemoryAllocatorClass * klass)
+{
+  GstAllocatorClass *allocator_class;
+
+  allocator_class = (GstAllocatorClass *) klass;
+
+  allocator_class->alloc = moz_gfx_memory_allocator_alloc;
+  allocator_class->free = moz_gfx_memory_allocator_free;
+}
+
+static void
+moz_gfx_memory_allocator_init (MozGfxMemoryAllocator * allocator)
+{
+  GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+  alloc->mem_type = "moz-gfx-image";
+  alloc->mem_map = (GstMemoryMapFunction) moz_gfx_memory_map;
+  alloc->mem_unmap = (GstMemoryUnmapFunction) moz_gfx_memory_unmap;
+  alloc->mem_share = (GstMemoryShareFunction) moz_gfx_memory_share;
+  /* fallback copy and is_span */
+}
+
+void
+moz_gfx_memory_allocator_set_reader(GstAllocator* aAllocator, GStreamerReader* aReader)
+{
+  MozGfxMemoryAllocator *allocator = (MozGfxMemoryAllocator *) aAllocator;
+  allocator->reader = aReader;
+}
+
+nsRefPtr<PlanarYCbCrImage>
+moz_gfx_memory_get_image(GstMemory *aMemory)
+{
+  NS_ASSERTION(GST_IS_MOZ_GFX_MEMORY_ALLOCATOR(aMemory->allocator), "Should be a gfx image");
+
+  return ((MozGfxMemory *) aMemory)->image;
+}
+
+void
+moz_gfx_buffer_pool_reset_buffer (GstBufferPool* aPool, GstBuffer* aBuffer)
+{
+  GstMemory* mem = gst_buffer_peek_memory(aBuffer, 0);
+
+  NS_ASSERTION(GST_IS_MOZ_GFX_MEMORY_ALLOCATOR(mem->allocator), "Should be a gfx image");
+  moz_gfx_memory_reset((MozGfxMemory *) mem);
+  GST_BUFFER_POOL_CLASS(moz_gfx_buffer_pool_parent_class)->reset_buffer(aPool, aBuffer);
+}
+
+static void
+moz_gfx_buffer_pool_class_init (MozGfxBufferPoolClass * klass)
+{
+  GstBufferPoolClass *pool_class = (GstBufferPoolClass *) klass;
+  pool_class->reset_buffer = moz_gfx_buffer_pool_reset_buffer;
+}
+
+static void
+moz_gfx_buffer_pool_init (MozGfxBufferPool * pool)
+{
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/gstreamer/GStreamerAllocator.h
@@ -0,0 +1,25 @@
+/* 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(GStreamerAllocator_h_)
+#define GStreamerAllocator_h_
+
+#include "GStreamerReader.h"
+
+#define GST_TYPE_MOZ_GFX_MEMORY_ALLOCATOR   (moz_gfx_memory_allocator_get_type())
+#define GST_IS_MOZ_GFX_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MOZ_GFX_MEMORY_ALLOCATOR))
+#define GST_TYPE_MOZ_GFX_BUFFER_POOL   (moz_gfx_buffer_pool_get_type())
+#define GST_IS_MOZ_GFX_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MOZ_GFX_BUFFER_POOL))
+
+namespace mozilla {
+
+GType moz_gfx_memory_allocator_get_type();
+void moz_gfx_memory_allocator_set_reader(GstAllocator *aAllocator, GStreamerReader* aReader);
+nsRefPtr<layers::PlanarYCbCrImage> moz_gfx_memory_get_image(GstMemory *aMemory);
+
+GType moz_gfx_buffer_pool_get_type();
+
+} // namespace mozilla
+
+#endif
--- a/content/media/gstreamer/GStreamerFormatHelper.cpp
+++ b/content/media/gstreamer/GStreamerFormatHelper.cpp
@@ -289,21 +289,32 @@ bool GStreamerFormatHelper::CanHandleCod
   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
 
   return gst_caps_can_intersect(aCaps, mSupportedCodecCaps);
 }
 
 GList* GStreamerFormatHelper::GetFactories() {
   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
 
-  uint32_t cookie = gst_default_registry_get_feature_list_cookie ();
+#if GST_VERSION_MAJOR >= 1
+  uint32_t cookie = gst_registry_get_feature_list_cookie(gst_registry_get());
+#else
+  uint32_t cookie = gst_default_registry_get_feature_list_cookie();
+#endif
   if (cookie != mCookie) {
     g_list_free(mFactories);
+#if GST_VERSION_MAJOR >= 1
+    mFactories =
+      gst_registry_feature_filter(gst_registry_get(),
+                                  (GstPluginFeatureFilter)FactoryFilter,
+                                  false, nullptr);
+#else
     mFactories =
       gst_default_registry_feature_filter((GstPluginFeatureFilter)FactoryFilter,
                                           false, nullptr);
+#endif
     mCookie = cookie;
   }
 
   return mFactories;
 }
 
 } // namespace mozilla
--- a/content/media/gstreamer/GStreamerFunctionList.h
+++ b/content/media/gstreamer/GStreamerFunctionList.h
@@ -4,102 +4,165 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __APPLE__
 
 /*
  * List of symbol names we need to dlsym from the gstreamer library.
  */
 GST_FUNC(LIBGSTAPP, gst_app_sink_get_type)
-GST_FUNC(LIBGSTAPP, gst_app_sink_pull_buffer)
 GST_FUNC(LIBGSTAPP, gst_app_sink_set_callbacks)
 GST_FUNC(LIBGSTAPP, gst_app_src_end_of_stream)
 GST_FUNC(LIBGSTAPP, gst_app_src_get_size)
 GST_FUNC(LIBGSTAPP, gst_app_src_get_type)
 GST_FUNC(LIBGSTAPP, gst_app_src_push_buffer)
 GST_FUNC(LIBGSTAPP, gst_app_src_set_callbacks)
 GST_FUNC(LIBGSTAPP, gst_app_src_set_caps)
 GST_FUNC(LIBGSTAPP, gst_app_src_set_size)
 GST_FUNC(LIBGSTAPP, gst_app_src_set_stream_type)
 GST_FUNC(LIBGSTREAMER, gst_bin_get_by_name)
 GST_FUNC(LIBGSTREAMER, gst_bin_get_type)
 GST_FUNC(LIBGSTREAMER, gst_bin_iterate_recurse)
-GST_FUNC(LIBGSTREAMER, gst_buffer_copy_metadata)
 GST_FUNC(LIBGSTREAMER, gst_buffer_get_type)
 GST_FUNC(LIBGSTREAMER, gst_buffer_new)
-GST_FUNC(LIBGSTREAMER, gst_buffer_new_and_alloc)
 GST_FUNC(LIBGSTREAMER, gst_bus_set_sync_handler)
 GST_FUNC(LIBGSTREAMER, gst_bus_timed_pop_filtered)
 GST_FUNC(LIBGSTREAMER, gst_caps_append)
 GST_FUNC(LIBGSTREAMER, gst_caps_can_intersect)
 GST_FUNC(LIBGSTREAMER, gst_caps_from_string)
 GST_FUNC(LIBGSTREAMER, gst_caps_get_size)
 GST_FUNC(LIBGSTREAMER, gst_caps_get_structure)
 GST_FUNC(LIBGSTREAMER, gst_caps_new_any)
 GST_FUNC(LIBGSTREAMER, gst_caps_new_empty)
 GST_FUNC(LIBGSTREAMER, gst_caps_new_full)
 GST_FUNC(LIBGSTREAMER, gst_caps_new_simple)
-GST_FUNC(LIBGSTREAMER, gst_caps_unref)
-GST_FUNC(LIBGSTREAMER, gst_element_factory_get_klass)
+GST_FUNC(LIBGSTREAMER, gst_caps_set_simple)
 GST_FUNC(LIBGSTREAMER, gst_element_factory_get_static_pad_templates)
 GST_FUNC(LIBGSTREAMER, gst_element_factory_get_type)
 GST_FUNC(LIBGSTREAMER, gst_element_factory_make)
 GST_FUNC(LIBGSTREAMER, gst_element_get_factory)
-GST_FUNC(LIBGSTREAMER, gst_element_get_pad)
+GST_FUNC(LIBGSTREAMER, gst_element_get_static_pad)
 GST_FUNC(LIBGSTREAMER, gst_element_get_type)
 GST_FUNC(LIBGSTREAMER, gst_element_query_convert)
 GST_FUNC(LIBGSTREAMER, gst_element_query_duration)
 GST_FUNC(LIBGSTREAMER, gst_element_seek_simple)
 GST_FUNC(LIBGSTREAMER, gst_element_set_state)
-GST_FUNC(LIBGSTREAMER, gst_event_parse_new_segment)
 GST_FUNC(LIBGSTREAMER, gst_flow_get_name)
 GST_FUNC(LIBGSTREAMER, gst_init)
 GST_FUNC(LIBGSTREAMER, gst_init_check)
 GST_FUNC(LIBGSTREAMER, gst_iterator_next)
 GST_FUNC(LIBGSTREAMER, gst_message_parse_error)
 GST_FUNC(LIBGSTREAMER, gst_message_type_get_name)
-GST_FUNC(LIBGSTREAMER, gst_mini_object_get_type)
-GST_FUNC(LIBGSTREAMER, gst_mini_object_new)
 GST_FUNC(LIBGSTREAMER, gst_mini_object_ref)
 GST_FUNC(LIBGSTREAMER, gst_mini_object_unref)
 GST_FUNC(LIBGSTREAMER, gst_object_get_name)
 GST_FUNC(LIBGSTREAMER, gst_object_get_parent)
 GST_FUNC(LIBGSTREAMER, gst_object_unref)
-GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe)
-GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer)
 GST_FUNC(LIBGSTREAMER, gst_pad_get_element_private)
-GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps)
-GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function)
 GST_FUNC(LIBGSTREAMER, gst_pad_set_element_private)
 GST_FUNC(LIBGSTREAMER, gst_parse_bin_from_description)
 GST_FUNC(LIBGSTREAMER, gst_pipeline_get_bus)
 GST_FUNC(LIBGSTREAMER, gst_pipeline_get_type)
 GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_rank)
 GST_FUNC(LIBGSTREAMER, gst_registry_feature_filter)
-GST_FUNC(LIBGSTREAMER, gst_registry_get_default)
 GST_FUNC(LIBGSTREAMER, gst_registry_get_feature_list_cookie)
 GST_FUNC(LIBGSTREAMER, gst_segment_init)
-GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment)
 GST_FUNC(LIBGSTREAMER, gst_segment_to_stream_time)
 GST_FUNC(LIBGSTREAMER, gst_static_caps_get)
 GST_FUNC(LIBGSTREAMER, gst_structure_copy)
 GST_FUNC(LIBGSTREAMER, gst_structure_get_fraction)
 GST_FUNC(LIBGSTREAMER, gst_structure_get_int)
 GST_FUNC(LIBGSTREAMER, gst_structure_get_value)
 GST_FUNC(LIBGSTREAMER, gst_structure_new)
 GST_FUNC(LIBGSTREAMER, gst_util_uint64_scale)
+
+#if GST_VERSION_MAJOR == 0
+GST_FUNC(LIBGSTAPP, gst_app_sink_pull_buffer)
+GST_FUNC(LIBGSTREAMER, gst_buffer_copy_metadata)
+GST_FUNC(LIBGSTREAMER, gst_buffer_new_and_alloc)
+GST_FUNC(LIBGSTREAMER, gst_caps_unref)
+GST_FUNC(LIBGSTREAMER, gst_element_factory_get_klass)
+GST_FUNC(LIBGSTREAMER, gst_element_get_pad)
+GST_FUNC(LIBGSTREAMER, gst_event_parse_new_segment)
+GST_FUNC(LIBGSTREAMER, gst_mini_object_get_type)
+GST_FUNC(LIBGSTREAMER, gst_mini_object_new)
+GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe)
+GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer)
+GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps)
+GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function)
+GST_FUNC(LIBGSTREAMER, gst_registry_get_default)
+GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment)
 GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_height)
 GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_offset)
 GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_width)
+GST_FUNC(LIBGSTVIDEO, gst_video_format_get_pixel_stride)
 GST_FUNC(LIBGSTVIDEO, gst_video_format_get_row_stride)
 GST_FUNC(LIBGSTVIDEO, gst_video_format_parse_caps)
+#else
+
+GST_FUNC(LIBGSTAPP, gst_app_sink_pull_sample)
+GST_FUNC(LIBGSTREAMER, _gst_caps_any)
+GST_FUNC(LIBGSTREAMER, gst_allocator_get_type)
+GST_FUNC(LIBGSTREAMER, gst_buffer_copy_into)
+GST_FUNC(LIBGSTREAMER, gst_buffer_extract)
+GST_FUNC(LIBGSTREAMER, gst_buffer_get_meta)
+GST_FUNC(LIBGSTREAMER, gst_buffer_get_size)
+GST_FUNC(LIBGSTREAMER, gst_buffer_map)
+GST_FUNC(LIBGSTREAMER, gst_buffer_new_allocate)
+GST_FUNC(LIBGSTREAMER, gst_buffer_n_memory)
+GST_FUNC(LIBGSTREAMER, gst_buffer_peek_memory)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_acquire_buffer)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_config_set_allocator)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_config_set_params)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_get_config)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_get_type)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_is_active)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_set_active)
+GST_FUNC(LIBGSTREAMER, gst_buffer_pool_set_config)
+GST_FUNC(LIBGSTREAMER, gst_buffer_set_size)
+GST_FUNC(LIBGSTREAMER, gst_buffer_unmap)
+GST_FUNC(LIBGSTREAMER, gst_element_factory_get_metadata)
+GST_FUNC(LIBGSTREAMER, gst_event_parse_segment)
+GST_FUNC(LIBGSTREAMER, gst_memory_init)
+GST_FUNC(LIBGSTREAMER, gst_memory_map)
+GST_FUNC(LIBGSTREAMER, gst_memory_unmap)
+GST_FUNC(LIBGSTREAMER, gst_object_get_type)
+GST_FUNC(LIBGSTREAMER, gst_pad_add_probe)
+GST_FUNC(LIBGSTREAMER, gst_pad_get_current_caps)
+GST_FUNC(LIBGSTREAMER, gst_pad_probe_info_get_query)
+GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_meta)
+GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_param)
+GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_pool)
+GST_FUNC(LIBGSTREAMER, gst_query_parse_allocation)
+GST_FUNC(LIBGSTREAMER, gst_registry_get)
+GST_FUNC(LIBGSTREAMER, gst_sample_get_buffer)
+GST_FUNC(LIBGSTREAMER, gst_segment_copy_into)
+GST_FUNC(LIBGSTREAMER, gst_structure_free)
+GST_FUNC(LIBGSTVIDEO, gst_buffer_pool_config_get_video_alignment)
+GST_FUNC(LIBGSTVIDEO, gst_buffer_pool_has_option)
+GST_FUNC(LIBGSTVIDEO, gst_video_buffer_pool_get_type)
+GST_FUNC(LIBGSTVIDEO, gst_video_frame_map)
+GST_FUNC(LIBGSTVIDEO, gst_video_frame_unmap)
+GST_FUNC(LIBGSTVIDEO, gst_video_info_align)
+GST_FUNC(LIBGSTVIDEO, gst_video_info_from_caps)
+GST_FUNC(LIBGSTVIDEO, gst_video_info_init)
+GST_FUNC(LIBGSTVIDEO, gst_video_meta_api_get_type)
+GST_FUNC(LIBGSTVIDEO, gst_video_meta_map)
+GST_FUNC(LIBGSTVIDEO, gst_video_meta_unmap)
+
+#endif
 
 /*
  * Functions that have been defined in the header file. We replace them so that
  * they don't try to use the global gstreamer functions.
  */
 #ifdef REPLACE_FUNC
 REPLACE_FUNC(gst_buffer_ref);
 REPLACE_FUNC(gst_buffer_unref);
 REPLACE_FUNC(gst_message_unref);
+
+#if GST_VERSION_MAJOR == 1
+REPLACE_FUNC(gst_caps_unref);
+REPLACE_FUNC(gst_sample_unref);
+#endif
 #endif
 
 #endif // !defined(__APPLE__)
--- a/content/media/gstreamer/GStreamerLoader.cpp
+++ b/content/media/gstreamer/GStreamerLoader.cpp
@@ -1,23 +1,31 @@
 /* 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 <dlfcn.h>
 #include <stdio.h>
 
+#include "nsDebug.h"
+#include "mozilla/NullPtr.h"
+
 #include "GStreamerLoader.h"
-#include "mozilla/NullPtr.h"
 
 #define LIBGSTREAMER 0
 #define LIBGSTAPP 1
 #define LIBGSTVIDEO 2
 
+#ifdef __OpenBSD__
+#define LIB_GST_SUFFIX ".so"
+#else
+#define LIB_GST_SUFFIX ".so.0"
+#endif
+
 namespace mozilla {
 
 /*
  * Declare our function pointers using the types from the global gstreamer
  * definitions.
  */
 #define GST_FUNC(_, func) typeof(::func)* func;
 #define REPLACE_FUNC(func) GST_FUNC(-1, func)
@@ -27,16 +35,21 @@ namespace mozilla {
 
 /*
  * Redefinitions of functions that have been defined in the gstreamer headers to
  * stop them calling the gstreamer functions in global scope.
  */
 GstBuffer * gst_buffer_ref_impl(GstBuffer *buf);
 void gst_buffer_unref_impl(GstBuffer *buf);
 void gst_message_unref_impl(GstMessage *msg);
+void gst_caps_unref_impl(GstCaps *caps);
+
+#if GST_VERSION_MAJOR == 1
+void gst_sample_unref_impl(GstSample *sample);
+#endif
 
 bool
 load_gstreamer()
 {
 #ifdef __APPLE__
   return true;
 #endif
   static bool loaded = false;
@@ -53,42 +66,35 @@ load_gstreamer()
   typedef typeof(::gst_version) VersionFuncType;
   if (VersionFuncType *versionFunc = (VersionFuncType*)dlsym(RTLD_DEFAULT, "gst_version")) {
     versionFunc(&major, &minor, &micro, &nano);
   }
 
   if (major == GST_VERSION_MAJOR && minor == GST_VERSION_MINOR) {
     gstreamerLib = RTLD_DEFAULT;
   } else {
-#ifdef __OpenBSD__
-    gstreamerLib = dlopen("libgstreamer-0.10.so", RTLD_NOW | RTLD_LOCAL);
-#else
-    gstreamerLib = dlopen("libgstreamer-0.10.so.0", RTLD_NOW | RTLD_LOCAL);
-#endif
+    gstreamerLib = dlopen("libgstreamer-" GST_API_VERSION LIB_GST_SUFFIX, RTLD_NOW | RTLD_LOCAL);
   }
 
-  void *handles[] = {
+  void *handles[3] = {
     gstreamerLib,
-#ifdef __OpenBSD__
-    dlopen("libgstapp-0.10.so", RTLD_NOW | RTLD_LOCAL),
-    dlopen("libgstvideo-0.10.so", RTLD_NOW | RTLD_LOCAL)
-#else
-    dlopen("libgstapp-0.10.so.0", RTLD_NOW | RTLD_LOCAL),
-    dlopen("libgstvideo-0.10.so.0", RTLD_NOW | RTLD_LOCAL)
-#endif
+    dlopen("libgstapp-" GST_API_VERSION LIB_GST_SUFFIX, RTLD_NOW | RTLD_LOCAL),
+    dlopen("libgstvideo-" GST_API_VERSION LIB_GST_SUFFIX, RTLD_NOW | RTLD_LOCAL)
   };
 
   for (size_t i = 0; i < sizeof(handles) / sizeof(handles[0]); i++) {
     if (!handles[i]) {
+      NS_WARNING("Couldn't link gstreamer libraries");
       goto fail;
     }
   }
 
 #define GST_FUNC(lib, symbol) \
   if (!(symbol = (typeof(symbol))dlsym(handles[lib], #symbol))) { \
+    NS_WARNING("Couldn't link symbol " #symbol); \
     goto fail; \
   }
 #define REPLACE_FUNC(symbol) symbol = symbol##_impl;
 #include "GStreamerFunctionList.h"
 #undef GST_FUNC
 #undef REPLACE_FUNC
 
   loaded = true;
@@ -118,9 +124,23 @@ gst_buffer_unref_impl(GstBuffer *buf)
 }
 
 void
 gst_message_unref_impl(GstMessage *msg)
 {
   gst_mini_object_unref(GST_MINI_OBJECT_CAST(msg));
 }
 
+#if GST_VERSION_MAJOR == 1
+void
+gst_sample_unref_impl(GstSample *sample)
+{
+  gst_mini_object_unref(GST_MINI_OBJECT_CAST(sample));
 }
+#endif
+
+void
+gst_caps_unref_impl(GstCaps *caps)
+{
+  gst_mini_object_unref(GST_MINI_OBJECT_CAST(caps));
+}
+
+}
--- a/content/media/gstreamer/GStreamerLoader.h
+++ b/content/media/gstreamer/GStreamerLoader.h
@@ -17,16 +17,21 @@
 // -Wunknown-pragmas on clang (unknown pragma).
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
 #pragma GCC diagnostic ignored "-Wpragmas"
 #pragma GCC diagnostic ignored "-Wreserved-user-defined-literal"
 #include <gst/video/video.h>
 #pragma GCC diagnostic pop
 
+#if GST_VERSION_MAJOR == 1
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+#endif
+
 namespace mozilla {
 
 /*
  * dlopens the required libraries and dlsyms the functions we need.
  * Returns true on success, false otherwise.
  */
 bool load_gstreamer();
 
@@ -37,9 +42,12 @@ bool load_gstreamer();
 #define GST_FUNC(_, func) extern typeof(::func)* func;
 #define REPLACE_FUNC(func) GST_FUNC(-1, func)
 #include "GStreamerFunctionList.h"
 #undef GST_FUNC
 #undef REPLACE_FUNC
 
 }
 
+#undef GST_CAPS_ANY
+#define GST_CAPS_ANY (*_gst_caps_any)
+
 #endif // GStreamerLoader_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gstreamer/GStreamerReader-0.10.cpp
@@ -0,0 +1,200 @@
+#include "nsError.h"
+#include "MediaDecoderStateMachine.h"
+#include "AbstractMediaDecoder.h"
+#include "MediaResource.h"
+#include "GStreamerReader.h"
+#include "GStreamerMozVideoBuffer.h"
+#include "GStreamerFormatHelper.h"
+#include "VideoUtils.h"
+#include "mozilla/dom/TimeRanges.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+using mozilla::layers::PlanarYCbCrImage;
+using mozilla::layers::ImageContainer;
+
+GstFlowReturn GStreamerReader::AllocateVideoBufferCb(GstPad* aPad,
+                                                     guint64 aOffset,
+                                                     guint aSize,
+                                                     GstCaps* aCaps,
+                                                     GstBuffer** aBuf)
+{
+  GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(gst_pad_get_element_private(aPad));
+  return reader->AllocateVideoBuffer(aPad, aOffset, aSize, aCaps, aBuf);
+}
+
+GstFlowReturn GStreamerReader::AllocateVideoBuffer(GstPad* aPad,
+                                                   guint64 aOffset,
+                                                   guint aSize,
+                                                   GstCaps* aCaps,
+                                                   GstBuffer** aBuf)
+{
+  nsRefPtr<PlanarYCbCrImage> image;
+  return AllocateVideoBufferFull(aPad, aOffset, aSize, aCaps, aBuf, image);
+}
+
+GstFlowReturn GStreamerReader::AllocateVideoBufferFull(GstPad* aPad,
+                                                       guint64 aOffset,
+                                                       guint aSize,
+                                                       GstCaps* aCaps,
+                                                       GstBuffer** aBuf,
+                                                       nsRefPtr<PlanarYCbCrImage>& aImage)
+{
+  /* allocate an image using the container */
+  ImageContainer* container = mDecoder->GetImageContainer();
+  if (container == nullptr) {
+    return GST_FLOW_ERROR;
+  }
+  PlanarYCbCrImage* img = reinterpret_cast<PlanarYCbCrImage*>(container->CreateImage(ImageFormat::PLANAR_YCBCR).get());
+  nsRefPtr<PlanarYCbCrImage> image = dont_AddRef(img);
+
+  /* prepare a GstBuffer pointing to the underlying PlanarYCbCrImage buffer */
+  GstBuffer* buf = GST_BUFFER(gst_moz_video_buffer_new());
+  GST_BUFFER_SIZE(buf) = aSize;
+  /* allocate the actual YUV buffer */
+  GST_BUFFER_DATA(buf) = image->AllocateAndGetNewBuffer(aSize);
+
+  aImage = image;
+
+  /* create a GstMozVideoBufferData to hold the image */
+  GstMozVideoBufferData* bufferdata = new GstMozVideoBufferData(image);
+
+  /* Attach bufferdata to our GstMozVideoBuffer, it will take care to free it */
+  gst_moz_video_buffer_set_data(GST_MOZ_VIDEO_BUFFER(buf), bufferdata);
+
+  *aBuf = buf;
+  return GST_FLOW_OK;
+}
+
+gboolean GStreamerReader::EventProbe(GstPad* aPad, GstEvent* aEvent)
+{
+  GstElement* parent = GST_ELEMENT(gst_pad_get_parent(aPad));
+  switch(GST_EVENT_TYPE(aEvent)) {
+    case GST_EVENT_NEWSEGMENT:
+    {
+      gboolean update;
+      gdouble rate;
+      GstFormat format;
+      gint64 start, stop, position;
+      GstSegment* segment;
+
+      /* Store the segments so we can convert timestamps to stream time, which
+       * is what the upper layers sync on.
+       */
+      ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
+      gst_event_parse_new_segment(aEvent, &update, &rate, &format,
+          &start, &stop, &position);
+      if (parent == GST_ELEMENT(mVideoAppSink))
+        segment = &mVideoSegment;
+      else
+        segment = &mAudioSegment;
+      gst_segment_set_newsegment(segment, update, rate, format,
+          start, stop, position);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      /* Reset on seeks */
+      ResetDecode();
+      break;
+    default:
+      break;
+  }
+  gst_object_unref(parent);
+
+  return TRUE;
+}
+
+gboolean GStreamerReader::EventProbeCb(GstPad* aPad,
+                                         GstEvent* aEvent,
+                                         gpointer aUserData)
+{
+  GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(aUserData);
+  return reader->EventProbe(aPad, aEvent);
+}
+
+nsRefPtr<PlanarYCbCrImage> GStreamerReader::GetImageFromBuffer(GstBuffer* aBuffer)
+{
+  if (!GST_IS_MOZ_VIDEO_BUFFER (aBuffer))
+    return nullptr;
+
+  nsRefPtr<PlanarYCbCrImage> image;
+  GstMozVideoBufferData* bufferdata = reinterpret_cast<GstMozVideoBufferData*>(gst_moz_video_buffer_get_data(GST_MOZ_VIDEO_BUFFER(aBuffer)));
+  image = bufferdata->mImage;
+
+  PlanarYCbCrImage::Data data;
+  data.mPicX = data.mPicY = 0;
+  data.mPicSize = gfx::IntSize(mPicture.width, mPicture.height);
+  data.mStereoMode = StereoMode::MONO;
+
+  data.mYChannel = GST_BUFFER_DATA(aBuffer);
+  data.mYStride = gst_video_format_get_row_stride(mFormat, 0, mPicture.width);
+  data.mYSize = gfx::IntSize(data.mYStride,
+      gst_video_format_get_component_height(mFormat, 0, mPicture.height));
+  data.mYSkip = 0;
+  data.mCbCrStride = gst_video_format_get_row_stride(mFormat, 1, mPicture.width);
+  data.mCbCrSize = gfx::IntSize(data.mCbCrStride,
+      gst_video_format_get_component_height(mFormat, 1, mPicture.height));
+  data.mCbChannel = data.mYChannel + gst_video_format_get_component_offset(mFormat, 1,
+      mPicture.width, mPicture.height);
+  data.mCrChannel = data.mYChannel + gst_video_format_get_component_offset(mFormat, 2,
+      mPicture.width, mPicture.height);
+  data.mCbSkip = 0;
+  data.mCrSkip = 0;
+
+  image->SetDataNoCopy(data);
+
+  return image;
+}
+
+void GStreamerReader::CopyIntoImageBuffer(GstBuffer* aBuffer,
+                                          GstBuffer** aOutBuffer,
+                                          nsRefPtr<PlanarYCbCrImage> &aImage)
+{
+  AllocateVideoBufferFull(nullptr, GST_BUFFER_OFFSET(aBuffer),
+      GST_BUFFER_SIZE(aBuffer), nullptr, aOutBuffer, aImage);
+
+  gst_buffer_copy_metadata(*aOutBuffer, aBuffer, (GstBufferCopyFlags)GST_BUFFER_COPY_ALL);
+  memcpy(GST_BUFFER_DATA(*aOutBuffer), GST_BUFFER_DATA(aBuffer), GST_BUFFER_SIZE(*aOutBuffer));
+
+  aImage = GetImageFromBuffer(*aOutBuffer);
+}
+
+GstCaps* GStreamerReader::BuildAudioSinkCaps()
+{
+  GstCaps* caps;
+#ifdef IS_LITTLE_ENDIAN
+  int endianness = 1234;
+#else
+  int endianness = 4321;
+#endif
+  gint width;
+#ifdef MOZ_SAMPLE_TYPE_FLOAT32
+  caps = gst_caps_from_string("audio/x-raw-float, channels={1,2}");
+  width = 32;
+#else /* !MOZ_SAMPLE_TYPE_FLOAT32 */
+  caps = gst_caps_from_string("audio/x-raw-int, channels={1,2}");
+  width = 16;
+#endif
+  gst_caps_set_simple(caps,
+      "width", G_TYPE_INT, width,
+      "endianness", G_TYPE_INT, endianness,
+      NULL);
+
+  return caps;
+}
+
+void GStreamerReader::InstallPadCallbacks()
+{
+  GstPad* sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink");
+  gst_pad_add_event_probe(sinkpad,
+                          G_CALLBACK(&GStreamerReader::EventProbeCb), this);
+
+  gst_pad_set_bufferalloc_function(sinkpad, GStreamerReader::AllocateVideoBufferCb);
+  gst_pad_set_element_private(sinkpad, this);
+  gst_object_unref(sinkpad);
+
+  sinkpad = gst_element_get_static_pad(GST_ELEMENT(mAudioAppSink), "sink");
+  gst_pad_add_event_probe(sinkpad,
+                          G_CALLBACK(&GStreamerReader::EventProbeCb), this);
+  gst_object_unref(sinkpad);
+}
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -5,18 +5,20 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsError.h"
 #include "nsMimeTypes.h"
 #include "MediaDecoderStateMachine.h"
 #include "AbstractMediaDecoder.h"
 #include "MediaResource.h"
 #include "GStreamerReader.h"
+#if GST_VERSION_MAJOR >= 1
+#include "GStreamerAllocator.h"
+#endif
 #include "GStreamerFormatHelper.h"
-#include "GStreamerMozVideoBuffer.h"
 #include "VideoUtils.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "mozilla/Preferences.h"
 #include "GStreamerLoader.h"
 #include "gfx2DGlue.h"
 
 namespace mozilla {
 
@@ -28,24 +30,26 @@ using namespace layers;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define LOG(type, msg)
 #endif
 
-extern bool
-IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
-             const VideoData::YCbCrBuffer::Plane& aCbPlane,
-             const VideoData::YCbCrBuffer::Plane& aCrPlane);
-
+#if DEBUG
 static const unsigned int MAX_CHANNELS = 4;
-// Let the demuxer work in pull mode for short files
-static const int SHORT_FILE_SIZE = 1024 * 1024;
+#endif
+// Let the demuxer work in pull mode for short files. This used to be a micro
+// optimization to have more accurate durations for ogg files in mochitests.
+// Since as of today we aren't using gstreamer to demux ogg, and having demuxers
+// work in pull mode over http makes them slower (since they really assume
+// near-zero latency in pull mode) set the constant to 0 for now, which
+// effectively disables it.
+static const int SHORT_FILE_SIZE = 0;
 // The default resource->Read() size when working in push mode
 static const int DEFAULT_SOURCE_READ_SIZE = 50 * 1024;
 
 typedef enum {
   GST_PLAY_FLAG_VIDEO         = (1 << 0),
   GST_PLAY_FLAG_AUDIO         = (1 << 1),
   GST_PLAY_FLAG_TEXT          = (1 << 2),
   GST_PLAY_FLAG_VIS           = (1 << 3),
@@ -57,41 +61,52 @@ typedef enum {
   GST_PLAY_FLAG_DEINTERLACE   = (1 << 9),
   GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
 } PlayFlags;
 
 GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder),
   mMP3FrameParser(aDecoder->GetResource()->GetLength()),
   mUseParserDuration(false),
+#if GST_VERSION_MAJOR >= 1
+  mAllocator(nullptr),
+  mBufferPool(nullptr),
+#endif
   mPlayBin(nullptr),
   mBus(nullptr),
   mSource(nullptr),
   mVideoSink(nullptr),
   mVideoAppSink(nullptr),
   mAudioSink(nullptr),
   mAudioAppSink(nullptr),
   mFormat(GST_VIDEO_FORMAT_UNKNOWN),
   mVideoSinkBufferCount(0),
   mAudioSinkBufferCount(0),
   mGstThreadsMonitor("media.gst.threads"),
   mReachedEos(false),
+#if GST_VERSION_MAJOR >= 1
+  mConfigureAlignment(true),
+#endif
   fpsNum(0),
   fpsDen(0)
 {
   MOZ_COUNT_CTOR(GStreamerReader);
 
   mSrcCallbacks.need_data = GStreamerReader::NeedDataCb;
   mSrcCallbacks.enough_data = GStreamerReader::EnoughDataCb;
   mSrcCallbacks.seek_data = GStreamerReader::SeekDataCb;
 
   mSinkCallbacks.eos = GStreamerReader::EosCb;
   mSinkCallbacks.new_preroll = GStreamerReader::NewPrerollCb;
+#if GST_VERSION_MAJOR >= 1
+  mSinkCallbacks.new_sample = GStreamerReader::NewBufferCb;
+#else
   mSinkCallbacks.new_buffer = GStreamerReader::NewBufferCb;
   mSinkCallbacks.new_buffer_list = nullptr;
+#endif
 
   gst_segment_init(&mVideoSegment, GST_FORMAT_UNDEFINED);
   gst_segment_init(&mAudioSegment, GST_FORMAT_UNDEFINED);
 }
 
 GStreamerReader::~GStreamerReader()
 {
   MOZ_COUNT_DTOR(GStreamerReader);
@@ -105,75 +120,69 @@ GStreamerReader::~GStreamerReader()
     gst_object_unref(mPlayBin);
     mPlayBin = nullptr;
     mVideoSink = nullptr;
     mVideoAppSink = nullptr;
     mAudioSink = nullptr;
     mAudioAppSink = nullptr;
     gst_object_unref(mBus);
     mBus = nullptr;
+#if GST_VERSION_MAJOR >= 1
+    g_object_unref(mAllocator);
+    g_object_unref(mBufferPool);
+#endif
   }
 }
 
 nsresult GStreamerReader::Init(MediaDecoderReader* aCloneDonor)
 {
-  GError* error = nullptr;
-  if (!gst_init_check(0, 0, &error)) {
-    LOG(PR_LOG_ERROR, ("gst initialization failed: %s", error->message));
-    g_error_free(error);
-    return NS_ERROR_FAILURE;
-  }
+  GStreamerFormatHelper::Instance();
+
+#if GST_VERSION_MAJOR >= 1
+  mAllocator = static_cast<GstAllocator*>(g_object_new(GST_TYPE_MOZ_GFX_MEMORY_ALLOCATOR, nullptr));
+  moz_gfx_memory_allocator_set_reader(mAllocator, this);
 
+  mBufferPool = static_cast<GstBufferPool*>(g_object_new(GST_TYPE_MOZ_GFX_BUFFER_POOL, nullptr));
+#endif
+
+#if GST_VERSION_MAJOR >= 1
+  mPlayBin = gst_element_factory_make("playbin", nullptr);
+#else
   mPlayBin = gst_element_factory_make("playbin2", nullptr);
+#endif
   if (!mPlayBin) {
-    LOG(PR_LOG_ERROR, ("couldn't create playbin2"));
+    LOG(PR_LOG_ERROR, ("couldn't create playbin"));
     return NS_ERROR_FAILURE;
   }
   g_object_set(mPlayBin, "buffer-size", 0, nullptr);
   mBus = gst_pipeline_get_bus(GST_PIPELINE(mPlayBin));
 
   mVideoSink = gst_parse_bin_from_description("capsfilter name=filter ! "
-      "appsink name=videosink sync=true max-buffers=1 "
+      "appsink name=videosink sync=false max-buffers=1 "
+#if GST_VERSION_MAJOR >= 1
+      "caps=video/x-raw,format=I420"
+#else
       "caps=video/x-raw-yuv,format=(fourcc)I420"
+#endif
       , TRUE, nullptr);
   mVideoAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mVideoSink),
         "videosink"));
+  mAudioSink = gst_parse_bin_from_description("capsfilter name=filter ! "
+        "appsink name=audiosink sync=false max-buffers=1", TRUE, nullptr);
+  mAudioAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mAudioSink),
+                                                   "audiosink"));
+  GstCaps* caps = BuildAudioSinkCaps();
+  g_object_set(mAudioAppSink, "caps", caps, nullptr);
+  gst_caps_unref(caps);
+
   gst_app_sink_set_callbacks(mVideoAppSink, &mSinkCallbacks,
       (gpointer) this, nullptr);
-  GstPad* sinkpad = gst_element_get_pad(GST_ELEMENT(mVideoAppSink), "sink");
-  gst_pad_add_event_probe(sinkpad,
-      G_CALLBACK(&GStreamerReader::EventProbeCb), this);
-  gst_object_unref(sinkpad);
-  gst_pad_set_bufferalloc_function(sinkpad, GStreamerReader::AllocateVideoBufferCb);
-  gst_pad_set_element_private(sinkpad, this);
-
-  mAudioSink = gst_parse_bin_from_description("capsfilter name=filter ! "
-#ifdef MOZ_SAMPLE_TYPE_FLOAT32
-        "appsink name=audiosink max-buffers=2 sync=false caps=audio/x-raw-float,"
-#ifdef IS_LITTLE_ENDIAN
-        "channels={1,2},width=32,endianness=1234", TRUE, nullptr);
-#else
-        "channels={1,2},width=32,endianness=4321", TRUE, nullptr);
-#endif
-#else
-        "appsink name=audiosink max-buffers=2 sync=false caps=audio/x-raw-int,"
-#ifdef IS_LITTLE_ENDIAN
-        "channels={1,2},width=16,endianness=1234", TRUE, nullptr);
-#else
-        "channels={1,2},width=16,endianness=4321", TRUE, nullptr);
-#endif
-#endif
-  mAudioAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mAudioSink),
-                                                   "audiosink"));
   gst_app_sink_set_callbacks(mAudioAppSink, &mSinkCallbacks,
                              (gpointer) this, nullptr);
-  sinkpad = gst_element_get_pad(GST_ELEMENT(mAudioAppSink), "sink");
-  gst_pad_add_event_probe(sinkpad,
-                          G_CALLBACK(&GStreamerReader::EventProbeCb), this);
-  gst_object_unref(sinkpad);
+  InstallPadCallbacks();
 
   g_object_set(mPlayBin, "uri", "appsrc://",
                "video-sink", mVideoSink,
                "audio-sink", mAudioSink,
                nullptr);
 
   g_signal_connect(G_OBJECT(mPlayBin), "notify::source",
                    G_CALLBACK(GStreamerReader::PlayBinSourceSetupCb), this);
@@ -315,23 +324,23 @@ nsresult GStreamerReader::ReadMetadata(M
       filter = gst_bin_get_by_name(GST_BIN(mAudioSink), "filter");
     else if (!(current_flags & GST_PLAY_FLAG_VIDEO))
       filter = gst_bin_get_by_name(GST_BIN(mVideoSink), "filter");
 
     if (filter) {
       /* Little trick: set the target caps to "skip" so that playbin2 fails to
        * find a decoder for the stream we want to skip.
        */
-      GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr);
+      GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr, nullptr);
       g_object_set(filter, "caps", filterCaps, nullptr);
       gst_caps_unref(filterCaps);
       gst_object_unref(filter);
     }
 
-    /* start the pipeline */
+    LOG(PR_LOG_DEBUG, ("starting metadata pipeline"));
     gst_element_set_state(mPlayBin, GST_STATE_PAUSED);
 
     /* Wait for ASYNC_DONE, which is emitted when the pipeline is built,
      * prerolled and ready to play. Also watch for errors.
      */
     message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE,
                  (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
@@ -342,125 +351,160 @@ nsresult GStreamerReader::ReadMetadata(M
       LOG(PR_LOG_ERROR, ("read metadata error: %s: %s", error->message,
                          debug));
       g_error_free(error);
       g_free(debug);
       gst_element_set_state(mPlayBin, GST_STATE_NULL);
       gst_message_unref(message);
       ret = NS_ERROR_FAILURE;
     } else {
+      LOG(PR_LOG_DEBUG, ("read metadata pipeline prerolled"));
       gst_message_unref(message);
       ret = NS_OK;
       break;
     }
   }
 
   if (NS_SUCCEEDED(ret))
     ret = CheckSupportedFormats();
 
   if (NS_FAILED(ret))
     /* we couldn't get this to play */
     return ret;
 
   /* FIXME: workaround for a bug in matroskademux. This seek makes matroskademux
    * parse the index */
+  LOG(PR_LOG_DEBUG, ("doing matroskademux seek hack"));
   if (gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME,
         GST_SEEK_FLAG_FLUSH, 0)) {
     /* after a seek we need to wait again for ASYNC_DONE */
-    message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE,
+    message = gst_bus_timed_pop_filtered(mBus, 5 * GST_SECOND,
        (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
-    if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
+    LOG(PR_LOG_DEBUG, ("matroskademux seek hack done"));
+    if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ASYNC_DONE) {
       gst_element_set_state(mPlayBin, GST_STATE_NULL);
       gst_message_unref(message);
       return NS_ERROR_FAILURE;
     }
+  } else {
+    LOG(PR_LOG_DEBUG, ("matroskademux seek hack failed (non fatal)"));
   }
 
   bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
   if (isMP3) {
     ParseMP3Headers();
   }
 
   /* report the duration */
   gint64 duration;
-  GstFormat format = GST_FORMAT_TIME;
 
   if (isMP3 && mMP3FrameParser.IsMP3()) {
     // The MP3FrameParser has reported a duration; use that over the gstreamer
     // reported duration for inter-platform consistency.
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mUseParserDuration = true;
     mLastParserDuration = mMP3FrameParser.GetDuration();
     mDecoder->SetMediaDuration(mLastParserDuration);
-
-  } else if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
-      &format, &duration) && format == GST_FORMAT_TIME) {
+  } else {
+    LOG(PR_LOG_DEBUG, ("querying duration"));
     // Otherwise use the gstreamer duration.
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    LOG(PR_LOG_DEBUG, ("returning duration %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (duration)));
-    duration = GST_TIME_AS_USECONDS (duration);
-    mDecoder->SetMediaDuration(duration);
-
-  } else {
-    mDecoder->SetMediaSeekable(false);
+#if GST_VERSION_MAJOR >= 1
+    if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
+          GST_FORMAT_TIME, &duration)) {
+#else
+    GstFormat format = GST_FORMAT_TIME;
+    if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
+      &format, &duration) && format == GST_FORMAT_TIME) {
+#endif
+      ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+      LOG(PR_LOG_DEBUG, ("have duration %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (duration)));
+      duration = GST_TIME_AS_USECONDS (duration);
+      mDecoder->SetMediaDuration(duration);
+    } else {
+      mDecoder->SetMediaSeekable(false);
+    }
   }
 
   int n_video = 0, n_audio = 0;
   g_object_get(mPlayBin, "n-video", &n_video, "n-audio", &n_audio, nullptr);
   mInfo.mVideo.mHasVideo = n_video != 0;
   mInfo.mAudio.mHasAudio = n_audio != 0;
 
   *aInfo = mInfo;
 
   *aTags = nullptr;
 
   // Watch the pipeline for fatal errors
+#if GST_VERSION_MAJOR >= 1
+  gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this, nullptr);
+#else
   gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this);
+#endif
 
   /* set the pipeline to PLAYING so that it starts decoding and queueing data in
    * the appsinks */
   gst_element_set_state(mPlayBin, GST_STATE_PLAYING);
 
   return NS_OK;
 }
 
 nsresult GStreamerReader::CheckSupportedFormats()
 {
   bool done = false;
   bool unsupported = false;
 
-  GstIterator *it = gst_bin_iterate_recurse(GST_BIN(mPlayBin));
+  GstIterator* it = gst_bin_iterate_recurse(GST_BIN(mPlayBin));
   while (!done) {
+    GstIteratorResult res;
     GstElement* element;
-    GstIteratorResult res = gst_iterator_next(it, (void **)&element);
+
+#if GST_VERSION_MAJOR >= 1
+    GValue value = {0,};
+    res = gst_iterator_next(it, &value);
+#else
+    res = gst_iterator_next(it, (void **) &element);
+#endif
     switch(res) {
       case GST_ITERATOR_OK:
       {
+#if GST_VERSION_MAJOR >= 1
+        element = GST_ELEMENT (g_value_get_object (&value));
+#endif
         GstElementFactory* factory = gst_element_get_factory(element);
         if (factory) {
           const char* klass = gst_element_factory_get_klass(factory);
-          GstPad* pad = gst_element_get_pad(element, "sink");
+          GstPad* pad = gst_element_get_static_pad(element, "sink");
           if (pad) {
-            GstCaps* caps = gst_pad_get_negotiated_caps(pad);
+            GstCaps* caps;
+
+#if GST_VERSION_MAJOR >= 1
+            caps = gst_pad_get_current_caps(pad);
+#else
+            caps = gst_pad_get_negotiated_caps(pad);
+#endif
 
             if (caps) {
               /* check for demuxers but ignore elements like id3demux */
               if (strstr (klass, "Demuxer") && !strstr(klass, "Metadata"))
                 unsupported = !GStreamerFormatHelper::Instance()->CanHandleContainerCaps(caps);
               else if (strstr (klass, "Decoder") && !strstr(klass, "Generic"))
                 unsupported = !GStreamerFormatHelper::Instance()->CanHandleCodecCaps(caps);
 
               gst_caps_unref(caps);
             }
             gst_object_unref(pad);
           }
         }
 
+#if GST_VERSION_MAJOR >= 1
+        g_value_unset (&value);
+#else
         gst_object_unref(element);
+#endif
         done = unsupported;
         break;
       }
       case GST_ITERATOR_RESYNC:
         unsupported = false;
         done = false;
         break;
       case GST_ITERATOR_ERROR:
@@ -474,26 +518,33 @@ nsresult GStreamerReader::CheckSupported
 
   return unsupported ? NS_ERROR_FAILURE : NS_OK;
 }
 
 nsresult GStreamerReader::ResetDecode()
 {
   nsresult res = NS_OK;
 
+  LOG(PR_LOG_DEBUG, ("reset decode"));
+
   if (NS_FAILED(MediaDecoderReader::ResetDecode())) {
     res = NS_ERROR_FAILURE;
   }
 
   mVideoQueue.Reset();
   mAudioQueue.Reset();
 
   mVideoSinkBufferCount = 0;
   mAudioSinkBufferCount = 0;
   mReachedEos = false;
+#if GST_VERSION_MAJOR >= 1
+  mConfigureAlignment = true;
+#endif
+
+  LOG(PR_LOG_DEBUG, ("reset decode done"));
 
   return res;
 }
 
 bool GStreamerReader::DecodeAudioData()
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
@@ -507,61 +558,82 @@ bool GStreamerReader::DecodeAudioData()
     }
 
     /* Wait something to be decoded before return or continue */
     if (!mAudioSinkBufferCount) {
       if(!mVideoSinkBufferCount) {
         /* We have nothing decoded so it makes no sense to return to the state machine
          * as it will call us back immediately, we'll return again and so on, wasting
          * CPU cycles for no job done. So, block here until there is either video or
-         * audio data available 
+         * audio data available
         */
         mon.Wait();
         if (!mAudioSinkBufferCount) {
-          /* There is still no audio data available, so either there is video data or 
+          /* There is still no audio data available, so either there is video data or
            * something else has happened (Eos, etc...). Return to the state machine
            * to process it.
            */
           return true;
         }
       }
       else {
         return true;
       }
     }
 
+#if GST_VERSION_MAJOR >= 1
+    GstSample *sample = gst_app_sink_pull_sample(mAudioAppSink);
+    buffer = gst_buffer_ref(gst_sample_get_buffer(sample));
+    gst_sample_unref(sample);
+#else
     buffer = gst_app_sink_pull_buffer(mAudioAppSink);
+#endif
+
     mAudioSinkBufferCount--;
   }
 
   int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer);
   timestamp = gst_segment_to_stream_time(&mAudioSegment,
       GST_FORMAT_TIME, timestamp);
+
   timestamp = GST_TIME_AS_USECONDS(timestamp);
 
   int64_t offset = GST_BUFFER_OFFSET(buffer);
+  guint8* data;
+#if GST_VERSION_MAJOR >= 1
+  GstMapInfo info;
+  gst_buffer_map(buffer, &info, GST_MAP_READ);
+  unsigned int size = info.size;
+  data = info.data;
+#else
   unsigned int size = GST_BUFFER_SIZE(buffer);
+  data = GST_BUFFER_DATA(buffer);
+#endif
   int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudio.mChannels;
 
   typedef AudioCompactor::NativeCopy GstCopy;
   mAudioCompactor.Push(offset,
                        timestamp,
                        mInfo.mAudio.mRate,
                        frames,
                        mInfo.mAudio.mChannels,
-                       GstCopy(GST_BUFFER_DATA(buffer),
+                       GstCopy(data,
                                size,
                                mInfo.mAudio.mChannels));
+#if GST_VERSION_MAJOR >= 1
+  gst_buffer_unmap(buffer, &info);
+#endif
+
   gst_buffer_unref(buffer);
 
   return true;
 }
 
 bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
-                                         int64_t aTimeThreshold)
+                                       int64_t aTimeThreshold)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   GstBuffer *buffer = nullptr;
 
   {
     ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
 
@@ -570,121 +642,110 @@ bool GStreamerReader::DecodeVideoFrame(b
     }
 
     /* Wait something to be decoded before return or continue */
     if (!mVideoSinkBufferCount) {
       if (!mAudioSinkBufferCount) {
         /* We have nothing decoded so it makes no sense to return to the state machine
          * as it will call us back immediately, we'll return again and so on, wasting
          * CPU cycles for no job done. So, block here until there is either video or
-         * audio data available 
+         * audio data available
         */
         mon.Wait();
         if (!mVideoSinkBufferCount) {
-          /* There is still no video data available, so either there is audio data or 
+          /* There is still no video data available, so either there is audio data or
            * something else has happened (Eos, etc...). Return to the state machine
            * to process it
            */
           return true;
         }
       }
       else {
         return true;
       }
     }
 
     mDecoder->NotifyDecodedFrames(0, 1);
 
+#if GST_VERSION_MAJOR >= 1
+    GstSample *sample = gst_app_sink_pull_sample(mVideoAppSink);
+    buffer = gst_buffer_ref(gst_sample_get_buffer(sample));
+    gst_sample_unref(sample);
+#else
     buffer = gst_app_sink_pull_buffer(mVideoAppSink);
+#endif
     mVideoSinkBufferCount--;
   }
 
-  bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
+  bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
   if ((aKeyFrameSkip && !isKeyframe)) {
     gst_buffer_unref(buffer);
     return true;
   }
 
   int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer);
   {
     ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
     timestamp = gst_segment_to_stream_time(&mVideoSegment,
                                            GST_FORMAT_TIME, timestamp);
   }
   NS_ASSERTION(GST_CLOCK_TIME_IS_VALID(timestamp),
                "frame has invalid timestamp");
 
   timestamp = GST_TIME_AS_USECONDS(timestamp);
+  int64_t duration;
+  if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
+    duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
+  else if (fpsNum && fpsDen)
+    /* add 1-frame duration */
+    duration = gst_util_uint64_scale(GST_USECOND, fpsDen, fpsNum);
+
   if (timestamp < aTimeThreshold) {
     LOG(PR_LOG_DEBUG, ("skipping frame %" GST_TIME_FORMAT
                        " threshold %" GST_TIME_FORMAT,
-                       GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold)));
+                       GST_TIME_ARGS(timestamp * 1000),
+                       GST_TIME_ARGS(aTimeThreshold * 1000)));
     gst_buffer_unref(buffer);
     return true;
   }
 
   if (!buffer)
     /* no more frames */
     return false;
 
-  int64_t duration = 0;
-  if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
-    duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
-  else if (fpsNum && fpsDen)
-    /* 1-frame duration */
-    duration = gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen);
+#if GST_VERSION_MAJOR >= 1
+  if (mConfigureAlignment && buffer->pool) {
+    GstStructure *config = gst_buffer_pool_get_config(buffer->pool);
+    GstVideoAlignment align;
+    if (gst_buffer_pool_config_get_video_alignment(config, &align))
+      gst_video_info_align(&mVideoInfo, &align);
+    gst_structure_free(config);
+    mConfigureAlignment = false;
+  }
+#endif
 
-  nsRefPtr<PlanarYCbCrImage> image;
-  GstMozVideoBufferData* bufferdata = reinterpret_cast<GstMozVideoBufferData*>
-      GST_IS_MOZ_VIDEO_BUFFER(buffer)?gst_moz_video_buffer_get_data(GST_MOZ_VIDEO_BUFFER(buffer)):nullptr;
-
-  if(bufferdata)
-    image = bufferdata->mImage;
-
+  nsRefPtr<PlanarYCbCrImage> image = GetImageFromBuffer(buffer);
   if (!image) {
     /* Ugh, upstream is not calling gst_pad_alloc_buffer(). Fallback to
      * allocating a PlanarYCbCrImage backed GstBuffer here and memcpy.
      */
     GstBuffer* tmp = nullptr;
-    AllocateVideoBufferFull(nullptr, GST_BUFFER_OFFSET(buffer),
-        GST_BUFFER_SIZE(buffer), nullptr, &tmp, image);
-
-    /* copy */
-    gst_buffer_copy_metadata(tmp, buffer, (GstBufferCopyFlags)GST_BUFFER_COPY_ALL);
-    memcpy(GST_BUFFER_DATA(tmp), GST_BUFFER_DATA(buffer),
-        GST_BUFFER_SIZE(tmp));
+    CopyIntoImageBuffer(buffer, &tmp, image);
     gst_buffer_unref(buffer);
     buffer = tmp;
   }
 
-  guint8* data = GST_BUFFER_DATA(buffer);
-
-  int width = mPicture.width;
-  int height = mPicture.height;
-  GstVideoFormat format = mFormat;
+  int64_t offset = mDecoder->GetResource()->Tell(); // Estimate location in media.
+  VideoData* video = VideoData::CreateFromImage(mInfo.mVideo,
+                                                mDecoder->GetImageContainer(),
+                                                offset, timestamp, duration,
+                                                static_cast<Image*>(image.get()),
+                                                isKeyframe, -1, mPicture);
+  mVideoQueue.Push(video);
 
-  VideoData::YCbCrBuffer b;
-  for(int i = 0; i < 3; i++) {
-    b.mPlanes[i].mData = data + gst_video_format_get_component_offset(format, i,
-        width, height);
-    b.mPlanes[i].mStride = gst_video_format_get_row_stride(format, i, width);
-    b.mPlanes[i].mHeight = gst_video_format_get_component_height(format,
-        i, height);
-    b.mPlanes[i].mWidth = gst_video_format_get_component_width(format,
-        i, width);
-    b.mPlanes[i].mOffset = 0;
-    b.mPlanes[i].mSkip = 0;
-  }
-
-  isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
-  int64_t offset = mDecoder->GetResource()->Tell(); // Estimate location in media.
-  VideoData* video = VideoData::Create(mInfo.mVideo, image, offset,
-                                       timestamp, duration, b,
-                                       isKeyframe, -1, mPicture);
-  mVideoQueue.Push(video);
   gst_buffer_unref(buffer);
 
   return true;
 }
 
 nsresult GStreamerReader::Seek(int64_t aTarget,
                                  int64_t aStartTime,
                                  int64_t aEndTime,
@@ -697,28 +758,34 @@ nsresult GStreamerReader::Seek(int64_t a
         mDecoder, GST_TIME_ARGS(seekPos)));
 
   if (!gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME,
     static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), seekPos)) {
     LOG(PR_LOG_ERROR, ("seek failed"));
     return NS_ERROR_FAILURE;
   }
   LOG(PR_LOG_DEBUG, ("seek succeeded"));
+  GstMessage* message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE,
+               (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
+  gst_message_unref(message);
+  LOG(PR_LOG_DEBUG, ("seek completed"));
 
   return DecodeToTarget(aTarget);
 }
 
 nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
                                       int64_t aStartTime)
 {
   if (!mInfo.HasValidMedia()) {
     return NS_OK;
   }
 
+#if GST_VERSION_MAJOR == 0
   GstFormat format = GST_FORMAT_TIME;
+#endif
   MediaResource* resource = mDecoder->GetResource();
   nsTArray<MediaByteRange> ranges;
   resource->GetCachedRanges(ranges);
 
   if (resource->IsDataCachedToEndOfResource(0)) {
     /* fast path for local or completely cached files */
     gint64 duration = 0;
 
@@ -730,22 +797,31 @@ nsresult GStreamerReader::GetBuffered(do
     return NS_OK;
   }
 
   for(uint32_t index = 0; index < ranges.Length(); index++) {
     int64_t startOffset = ranges[index].mStart;
     int64_t endOffset = ranges[index].mEnd;
     gint64 startTime, endTime;
 
+#if GST_VERSION_MAJOR >= 1
+    if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES,
+      startOffset, GST_FORMAT_TIME, &startTime))
+      continue;
+    if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES,
+      endOffset, GST_FORMAT_TIME, &endTime))
+      continue;
+#else
     if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES,
       startOffset, &format, &startTime) || format != GST_FORMAT_TIME)
       continue;
     if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES,
       endOffset, &format, &endTime) || format != GST_FORMAT_TIME)
       continue;
+#endif
 
     double start = (double) GST_TIME_AS_USECONDS (startTime) / GST_MSECOND;
     double end = (double) GST_TIME_AS_USECONDS (endTime) / GST_MSECOND;
     LOG(PR_LOG_DEBUG, ("adding range [%f, %f] for [%li %li] size %li",
           start, end, startOffset, endOffset, resource->GetLength()));
     aBuffered->Add(start, end);
   }
 
@@ -754,49 +830,65 @@ nsresult GStreamerReader::GetBuffered(do
 
 void GStreamerReader::ReadAndPushData(guint aLength)
 {
   MediaResource* resource = mDecoder->GetResource();
   NS_ASSERTION(resource, "Decoder has no media resource");
   nsresult rv = NS_OK;
 
   GstBuffer* buffer = gst_buffer_new_and_alloc(aLength);
+#if GST_VERSION_MAJOR >= 1
+  GstMapInfo info;
+  gst_buffer_map(buffer, &info, GST_MAP_WRITE);
+  guint8 *data = info.data;
+#else
   guint8* data = GST_BUFFER_DATA(buffer);
+#endif
   uint32_t size = 0, bytesRead = 0;
   while(bytesRead < aLength) {
     rv = resource->Read(reinterpret_cast<char*>(data + bytesRead),
         aLength - bytesRead, &size);
     if (NS_FAILED(rv) || size == 0)
       break;
 
     bytesRead += size;
   }
 
+#if GST_VERSION_MAJOR >= 1
+  gst_buffer_unmap(buffer, &info);
+  gst_buffer_set_size(buffer, bytesRead);
+#else
   GST_BUFFER_SIZE(buffer) = bytesRead;
+#endif
 
   GstFlowReturn ret = gst_app_src_push_buffer(mSource, gst_buffer_ref(buffer));
   if (ret != GST_FLOW_OK) {
     LOG(PR_LOG_ERROR, ("ReadAndPushData push ret %s", gst_flow_get_name(ret)));
   }
 
-  if (GST_BUFFER_SIZE (buffer) < aLength) {
+  if (bytesRead < aLength) {
     /* If we read less than what we wanted, we reached the end */
     gst_app_src_end_of_stream(mSource);
   }
 
   gst_buffer_unref(buffer);
 }
 
 int64_t GStreamerReader::QueryDuration()
 {
   gint64 duration = 0;
   GstFormat format = GST_FORMAT_TIME;
 
+#if GST_VERSION_MAJOR >= 1
+  if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
+      format, &duration)) {
+#else
   if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
       &format, &duration)) {
+#endif
     if (format == GST_FORMAT_TIME) {
       LOG(PR_LOG_DEBUG, ("pipeline duration %" GST_TIME_FORMAT,
             GST_TIME_ARGS (duration)));
       duration = GST_TIME_AS_USECONDS (duration);
     }
   }
 
   {
@@ -865,137 +957,38 @@ gboolean GStreamerReader::SeekData(GstAp
 
   if (NS_FAILED(rv)) {
     LOG(PR_LOG_ERROR, ("seek at %lu failed", aOffset));
   }
 
   return NS_SUCCEEDED(rv);
 }
 
-gboolean GStreamerReader::EventProbeCb(GstPad* aPad,
-                                         GstEvent* aEvent,
-                                         gpointer aUserData)
-{
-  GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(aUserData);
-  return reader->EventProbe(aPad, aEvent);
-}
-
-gboolean GStreamerReader::EventProbe(GstPad* aPad, GstEvent* aEvent)
-{
-  GstElement* parent = GST_ELEMENT(gst_pad_get_parent(aPad));
-  switch(GST_EVENT_TYPE(aEvent)) {
-    case GST_EVENT_NEWSEGMENT:
-    {
-      gboolean update;
-      gdouble rate;
-      GstFormat format;
-      gint64 start, stop, position;
-      GstSegment* segment;
-
-      /* Store the segments so we can convert timestamps to stream time, which
-       * is what the upper layers sync on.
-       */
-      ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
-      gst_event_parse_new_segment(aEvent, &update, &rate, &format,
-          &start, &stop, &position);
-      if (parent == GST_ELEMENT(mVideoAppSink))
-        segment = &mVideoSegment;
-      else
-        segment = &mAudioSegment;
-      gst_segment_set_newsegment(segment, update, rate, format,
-          start, stop, position);
-      break;
-    }
-    case GST_EVENT_FLUSH_STOP:
-      /* Reset on seeks */
-      ResetDecode();
-      break;
-    default:
-      break;
-  }
-  gst_object_unref(parent);
-
-  return TRUE;
-}
-
-GstFlowReturn GStreamerReader::AllocateVideoBufferFull(GstPad* aPad,
-                                                       guint64 aOffset,
-                                                       guint aSize,
-                                                       GstCaps* aCaps,
-                                                       GstBuffer** aBuf,
-                                                       nsRefPtr<PlanarYCbCrImage>& aImage)
-{
-  /* allocate an image using the container */
-  ImageContainer* container = mDecoder->GetImageContainer();
-  if (!container) {
-    // We don't have an ImageContainer. We probably belong to an <audio>
-    // element.
-    return GST_FLOW_NOT_SUPPORTED;
-  }
-  PlanarYCbCrImage* img =
-    reinterpret_cast<PlanarYCbCrImage*>(
-      container->CreateImage(ImageFormat::PLANAR_YCBCR).get());
-  nsRefPtr<PlanarYCbCrImage> image = dont_AddRef(img);
-
-  /* prepare a GstBuffer pointing to the underlying PlanarYCbCrImage buffer */
-  GstBuffer* buf = GST_BUFFER(gst_moz_video_buffer_new());
-  GST_BUFFER_SIZE(buf) = aSize;
-  /* allocate the actual YUV buffer */
-  GST_BUFFER_DATA(buf) = image->AllocateAndGetNewBuffer(aSize);
-
-  aImage = image;
-
-  /* create a GstMozVideoBufferData to hold the image */
-  GstMozVideoBufferData* bufferdata = new GstMozVideoBufferData(image);
-
-  /* Attach bufferdata to our GstMozVideoBuffer, it will take care to free it */
-  gst_moz_video_buffer_set_data(GST_MOZ_VIDEO_BUFFER(buf), bufferdata);
-
-  *aBuf = buf;
-  return GST_FLOW_OK;
-}
-
-GstFlowReturn GStreamerReader::AllocateVideoBufferCb(GstPad* aPad,
-                                                     guint64 aOffset,
-                                                     guint aSize,
-                                                     GstCaps* aCaps,
-                                                     GstBuffer** aBuf)
-{
-  GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(gst_pad_get_element_private(aPad));
-  return reader->AllocateVideoBuffer(aPad, aOffset, aSize, aCaps, aBuf);
-}
-
-GstFlowReturn GStreamerReader::AllocateVideoBuffer(GstPad* aPad,
-                                                   guint64 aOffset,
-                                                   guint aSize,
-                                                   GstCaps* aCaps,
-                                                   GstBuffer** aBuf)
-{
-  nsRefPtr<PlanarYCbCrImage> image;
-  return AllocateVideoBufferFull(aPad, aOffset, aSize, aCaps, aBuf, image);
-}
-
 GstFlowReturn GStreamerReader::NewPrerollCb(GstAppSink* aSink,
                                               gpointer aUserData)
 {
   GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(aUserData);
 
   if (aSink == reader->mVideoAppSink)
     reader->VideoPreroll();
   else
     reader->AudioPreroll();
   return GST_FLOW_OK;
 }
 
 void GStreamerReader::AudioPreroll()
 {
   /* The first audio buffer has reached the audio sink. Get rate and channels */
   LOG(PR_LOG_DEBUG, ("Audio preroll"));
-  GstPad* sinkpad = gst_element_get_pad(GST_ELEMENT(mAudioAppSink), "sink");
+  GstPad* sinkpad = gst_element_get_static_pad(GST_ELEMENT(mAudioAppSink), "sink");
+#if GST_VERSION_MAJOR >= 1
+  GstCaps *caps = gst_pad_get_current_caps(sinkpad);
+#else
   GstCaps* caps = gst_pad_get_negotiated_caps(sinkpad);
+#endif
   GstStructure* s = gst_caps_get_structure(caps, 0);
   mInfo.mAudio.mRate = mInfo.mAudio.mChannels = 0;
   gst_structure_get_int(s, "rate", (gint*) &mInfo.mAudio.mRate);
   gst_structure_get_int(s, "channels", (gint*) &mInfo.mAudio.mChannels);
   NS_ASSERTION(mInfo.mAudio.mRate != 0, ("audio rate is zero"));
   NS_ASSERTION(mInfo.mAudio.mChannels != 0, ("audio channels is zero"));
   NS_ASSERTION(mInfo.mAudio.mChannels > 0 && mInfo.mAudio.mChannels <= MAX_CHANNELS,
       "invalid audio channels number");
@@ -1003,19 +996,28 @@ void GStreamerReader::AudioPreroll()
   gst_caps_unref(caps);
   gst_object_unref(sinkpad);
 }
 
 void GStreamerReader::VideoPreroll()
 {
   /* The first video buffer has reached the video sink. Get width and height */
   LOG(PR_LOG_DEBUG, ("Video preroll"));
-  GstPad* sinkpad = gst_element_get_pad(GST_ELEMENT(mVideoAppSink), "sink");
+  GstPad* sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink");
+#if GST_VERSION_MAJOR >= 1
+  GstCaps* caps = gst_pad_get_current_caps(sinkpad);
+  memset (&mVideoInfo, 0, sizeof (mVideoInfo));
+  gst_video_info_from_caps(&mVideoInfo, caps);
+  mFormat = mVideoInfo.finfo->format;
+  mPicture.width = mVideoInfo.width;
+  mPicture.height = mVideoInfo.height;
+#else
   GstCaps* caps = gst_pad_get_negotiated_caps(sinkpad);
   gst_video_format_parse_caps(caps, &mFormat, &mPicture.width, &mPicture.height);
+#endif
   GstStructure* structure = gst_caps_get_structure(caps, 0);
   gst_structure_get_fraction(structure, "framerate", &fpsNum, &fpsDen);
   NS_ASSERTION(mPicture.width && mPicture.height, "invalid video resolution");
   mInfo.mVideo.mDisplay = ThebesIntSize(mPicture.Size());
   mInfo.mVideo.mHasVideo = true;
   gst_caps_unref(caps);
   gst_object_unref(sinkpad);
 }
@@ -1034,16 +1036,17 @@ GstFlowReturn GStreamerReader::NewBuffer
 }
 
 void GStreamerReader::NewVideoBuffer()
 {
   ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
   /* We have a new video buffer queued in the video sink. Increment the counter
    * and notify the decode thread potentially blocked in DecodeVideoFrame
    */
+
   mDecoder->NotifyDecodedFrames(1, 0);
   mVideoSinkBufferCount++;
   mon.NotifyAll();
 }
 
 void GStreamerReader::NewAudioBuffer()
 {
   ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
@@ -1170,10 +1173,203 @@ void GStreamerReader::NotifyDataArrived(
   int64_t duration = mMP3FrameParser.GetDuration();
   if (duration != mLastParserDuration && mUseParserDuration) {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mLastParserDuration = duration;
     mDecoder->UpdateEstimatedMediaDuration(mLastParserDuration);
   }
 }
 
+#if GST_VERSION_MAJOR >= 1
+GstCaps* GStreamerReader::BuildAudioSinkCaps()
+{
+  GstCaps* caps = gst_caps_from_string("audio/x-raw, channels={1,2}");
+  const char* format;
+#ifdef MOZ_SAMPLE_TYPE_FLOAT32
+#ifdef IS_LITTLE_ENDIAN
+  format = "F32LE";
+#else
+  format = "F32BE";
+#endif
+#else /* !MOZ_SAMPLE_TYPE_FLOAT32 */
+#ifdef IS_LITTLE_ENDIAN
+  format = "S16LE";
+#else
+  format = "S16BE";
+#endif
+#endif
+  gst_caps_set_simple(caps, "format", G_TYPE_STRING, format, nullptr);
+
+  return caps;
+}
+
+void GStreamerReader::InstallPadCallbacks()
+{
+  GstPad* sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink");
+
+  gst_pad_add_probe(sinkpad,
+      (GstPadProbeType) (GST_PAD_PROBE_TYPE_SCHEDULING |
+        GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
+        GST_PAD_PROBE_TYPE_EVENT_UPSTREAM |
+        GST_PAD_PROBE_TYPE_EVENT_FLUSH),
+      &GStreamerReader::EventProbeCb, this, nullptr);
+  gst_pad_add_probe(sinkpad, GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
+      GStreamerReader::QueryProbeCb, nullptr, nullptr);
+
+  gst_pad_set_element_private(sinkpad, this);
+  gst_object_unref(sinkpad);
+
+  sinkpad = gst_element_get_static_pad(GST_ELEMENT(mAudioAppSink), "sink");
+  gst_pad_add_probe(sinkpad,
+      (GstPadProbeType) (GST_PAD_PROBE_TYPE_SCHEDULING |
+        GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
+        GST_PAD_PROBE_TYPE_EVENT_UPSTREAM |
+        GST_PAD_PROBE_TYPE_EVENT_FLUSH),
+      &GStreamerReader::EventProbeCb, this, nullptr);
+  gst_object_unref(sinkpad);
+}
+
+GstPadProbeReturn GStreamerReader::EventProbeCb(GstPad *aPad,
+                                                GstPadProbeInfo *aInfo,
+                                                gpointer aUserData)
+{
+  GStreamerReader *reader = (GStreamerReader *) aUserData;
+  GstEvent *aEvent = (GstEvent *)aInfo->data;
+  return reader->EventProbe(aPad, aEvent);
+}
+
+GstPadProbeReturn GStreamerReader::EventProbe(GstPad *aPad, GstEvent *aEvent)
+{
+  GstElement* parent = GST_ELEMENT(gst_pad_get_parent(aPad));
+
+  LOG(PR_LOG_DEBUG, ("event probe %s", GST_EVENT_TYPE_NAME (aEvent)));
+
+  switch(GST_EVENT_TYPE(aEvent)) {
+    case GST_EVENT_SEGMENT:
+    {
+      const GstSegment *newSegment;
+      GstSegment* segment;
+
+      /* Store the segments so we can convert timestamps to stream time, which
+       * is what the upper layers sync on.
+       */
+      ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
+#if GST_VERSION_MINOR <= 1 && GST_VERSION_MICRO < 1
+      ResetDecode();
+#endif
+      gst_event_parse_segment(aEvent, &newSegment);
+      if (parent == GST_ELEMENT(mVideoAppSink))
+        segment = &mVideoSegment;
+      else
+        segment = &mAudioSegment;
+      gst_segment_copy_into (newSegment, segment);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      /* Reset on seeks */
+      ResetDecode();
+      break;
+    default:
+      break;
+  }
+  gst_object_unref(parent);
+
+  return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn GStreamerReader::QueryProbeCb(GstPad* aPad, GstPadProbeInfo* aInfo, gpointer aUserData)
+{
+  GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(gst_pad_get_element_private(aPad));
+  return reader->QueryProbe(aPad, aInfo, aUserData);
+}
+
+GstPadProbeReturn GStreamerReader::QueryProbe(GstPad* aPad, GstPadProbeInfo* aInfo, gpointer aUserData)
+{
+  GstQuery *query = gst_pad_probe_info_get_query(aInfo);
+  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_ALLOCATION:
+      GstCaps *caps;
+      GstVideoInfo info;
+      gboolean need_pool;
+
+      gst_query_parse_allocation(query, &caps, &need_pool);
+      gst_video_info_init(&info);
+      gst_video_info_from_caps(&info, caps);
+      gst_query_add_allocation_param(query, mAllocator, nullptr);
+      gst_query_add_allocation_pool(query, mBufferPool, info.size, 0, 0);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+void GStreamerReader::ImageDataFromVideoFrame(GstVideoFrame *aFrame,
+                                              PlanarYCbCrImage::Data *aData)
+{
+  NS_ASSERTION(GST_VIDEO_INFO_IS_YUV(&mVideoInfo),
+               "Non-YUV video frame formats not supported");
+  NS_ASSERTION(GST_VIDEO_FRAME_N_COMPONENTS(aFrame) == 3,
+               "Unsupported number of components in video frame");
+
+  aData->mPicX = aData->mPicY = 0;
+  aData->mPicSize = gfx::IntSize(mPicture.width, mPicture.height);
+  aData->mStereoMode = StereoMode::MONO;
+
+  aData->mYChannel = GST_VIDEO_FRAME_COMP_DATA(aFrame, 0);
+  aData->mYStride = GST_VIDEO_FRAME_COMP_STRIDE(aFrame, 0);
+  aData->mYSize = gfx::IntSize(GST_VIDEO_FRAME_COMP_WIDTH(aFrame, 0),
+                          GST_VIDEO_FRAME_COMP_HEIGHT(aFrame, 0));
+  aData->mYSkip = GST_VIDEO_FRAME_COMP_PSTRIDE(aFrame, 0) - 1;
+  aData->mCbCrStride = GST_VIDEO_FRAME_COMP_STRIDE(aFrame, 1);
+  aData->mCbCrSize = gfx::IntSize(GST_VIDEO_FRAME_COMP_WIDTH(aFrame, 1),
+                             GST_VIDEO_FRAME_COMP_HEIGHT(aFrame, 1));
+  aData->mCbChannel = GST_VIDEO_FRAME_COMP_DATA(aFrame, 1);
+  aData->mCrChannel = GST_VIDEO_FRAME_COMP_DATA(aFrame, 2);
+  aData->mCbSkip = GST_VIDEO_FRAME_COMP_PSTRIDE(aFrame, 1) - 1;
+  aData->mCrSkip = GST_VIDEO_FRAME_COMP_PSTRIDE(aFrame, 2) - 1;
+}
+
+nsRefPtr<PlanarYCbCrImage> GStreamerReader::GetImageFromBuffer(GstBuffer* aBuffer)
+{
+  nsRefPtr<PlanarYCbCrImage> image = nullptr;
+
+  if (gst_buffer_n_memory(aBuffer) == 1) {
+    GstMemory* mem = gst_buffer_peek_memory(aBuffer, 0);
+    if (GST_IS_MOZ_GFX_MEMORY_ALLOCATOR(mem->allocator)) {
+      image = moz_gfx_memory_get_image(mem);
+
+      GstVideoFrame frame;
+      gst_video_frame_map(&frame, &mVideoInfo, aBuffer, GST_MAP_READ);
+      PlanarYCbCrImage::Data data;
+      ImageDataFromVideoFrame(&frame, &data);
+      image->SetDataNoCopy(data);
+      gst_video_frame_unmap(&frame);
+    }
+  }
+
+  return image;
+}
+
+void GStreamerReader::CopyIntoImageBuffer(GstBuffer* aBuffer,
+                                          GstBuffer** aOutBuffer,
+                                          nsRefPtr<PlanarYCbCrImage> &image)
+{
+  *aOutBuffer = gst_buffer_new_allocate(mAllocator, gst_buffer_get_size(aBuffer), nullptr);
+  GstMemory *mem = gst_buffer_peek_memory(*aOutBuffer, 0);
+  GstMapInfo map_info;
+  gst_memory_map(mem, &map_info, GST_MAP_WRITE);
+  gst_buffer_extract(aBuffer, 0, map_info.data, gst_buffer_get_size(aBuffer));
+  gst_memory_unmap(mem, &map_info);
+
+  /* create a new gst buffer with the newly created memory and copy the
+   * metadata over from the incoming buffer */
+  gst_buffer_copy_into(*aOutBuffer, aBuffer,
+      (GstBufferCopyFlags)(GST_BUFFER_COPY_METADATA), 0, -1);
+  image = GetImageFromBuffer(*aOutBuffer);
+}
+#endif
+
 } // namespace mozilla
 
--- a/content/media/gstreamer/GStreamerReader.h
+++ b/content/media/gstreamer/GStreamerReader.h
@@ -17,28 +17,25 @@
 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
 #pragma GCC diagnostic ignored "-Wpragmas"
 #pragma GCC diagnostic ignored "-Wreserved-user-defined-literal"
 #include <gst/video/video.h>
 #pragma GCC diagnostic pop
 
 #include "MediaDecoderReader.h"
 #include "MP3FrameParser.h"
+#include "ImageContainer.h"
 #include "nsRect.h"
 
 namespace mozilla {
 
 namespace dom {
 class TimeRanges;
 }
 
-namespace layers {
-class PlanarYCbCrImage;
-}
-
 class AbstractMediaDecoder;
 
 class GStreamerReader : public MediaDecoderReader
 {
   typedef gfx::IntRect IntRect;
 
 public:
   GStreamerReader(AbstractMediaDecoder* aDecoder);
@@ -64,20 +61,30 @@ public:
   virtual bool HasAudio() {
     return mInfo.HasAudio();
   }
 
   virtual bool HasVideo() {
     return mInfo.HasVideo();
   }
 
+  layers::ImageContainer* GetImageContainer() { return mDecoder->GetImageContainer(); }
+
 private:
 
   void ReadAndPushData(guint aLength);
   int64_t QueryDuration();
+  nsRefPtr<layers::PlanarYCbCrImage> GetImageFromBuffer(GstBuffer* aBuffer);
+  void CopyIntoImageBuffer(GstBuffer *aBuffer, GstBuffer** aOutBuffer, nsRefPtr<layers::PlanarYCbCrImage> &image);
+  GstCaps* BuildAudioSinkCaps();
+  void InstallPadCallbacks();
+
+#if GST_VERSION_MAJOR >= 1
+  void ImageDataFromVideoFrame(GstVideoFrame *aFrame, layers::PlanarYCbCrImage::Data *aData);
+#endif
 
   /* Called once the pipeline is setup to check that the stream only contains
    * supported formats
    */
   nsresult CheckSupportedFormats();
 
   /* Gst callbacks */
 
@@ -102,30 +109,41 @@ private:
 
   /* Called when a seek is issued on the pipeline */
   static gboolean SeekDataCb(GstAppSrc* aSrc,
                              guint64 aOffset,
                              gpointer aUserData);
   gboolean SeekData(GstAppSrc* aSrc, guint64 aOffset);
 
   /* Called when events reach the sinks. See inline comments */
+#if GST_VERSION_MAJOR == 1
+  static GstPadProbeReturn EventProbeCb(GstPad *aPad, GstPadProbeInfo *aInfo, gpointer aUserData);
+  GstPadProbeReturn EventProbe(GstPad *aPad, GstEvent *aEvent);
+#else
   static gboolean EventProbeCb(GstPad* aPad, GstEvent* aEvent, gpointer aUserData);
   gboolean EventProbe(GstPad* aPad, GstEvent* aEvent);
+#endif
 
-  /* Called when elements in the video branch of the pipeline call
-   * gst_pad_alloc_buffer(). Used to provide PlanarYCbCrImage backed GstBuffers
-   * to the pipeline so that a memory copy can be avoided when handling YUV
-   * buffers from the pipeline to the gfx side.
+  /* Called when the video part of the pipeline allocates buffers. Used to
+   * provide PlanarYCbCrImage backed GstBuffers to the pipeline so that a memory
+   * copy can be avoided when handling YUV buffers from the pipeline to the gfx
+   * side.
    */
+#if GST_VERSION_MAJOR == 1
+  static GstPadProbeReturn QueryProbeCb(GstPad *aPad, GstPadProbeInfo *aInfo, gpointer aUserData);
+  GstPadProbeReturn QueryProbe(GstPad *aPad, GstPadProbeInfo *aInfo, gpointer aUserData);
+#else
   static GstFlowReturn AllocateVideoBufferCb(GstPad* aPad, guint64 aOffset, guint aSize,
                                              GstCaps* aCaps, GstBuffer** aBuf);
   GstFlowReturn AllocateVideoBufferFull(GstPad* aPad, guint64 aOffset, guint aSize,
                                      GstCaps* aCaps, GstBuffer** aBuf, nsRefPtr<layers::PlanarYCbCrImage>& aImage);
   GstFlowReturn AllocateVideoBuffer(GstPad* aPad, guint64 aOffset, guint aSize,
                                      GstCaps* aCaps, GstBuffer** aBuf);
+#endif
+
 
   /* Called when the pipeline is prerolled, that is when at start or after a
    * seek, the first audio and video buffers are queued in the sinks.
    */
   static GstFlowReturn NewPrerollCb(GstAppSink* aSink, gpointer aUserData);
   void VideoPreroll();
   void AudioPreroll();
 
@@ -164,16 +182,21 @@ private:
   // We want to be able to decide in |ReadMetadata| whether or not we use the
   // duration from the MP3 frame parser, as this backend supports more than just
   // MP3. But |NotifyDataArrived| can update the duration and is often called
   // _before_ |ReadMetadata|. This flag stops the former from using the parser
   // duration until we are sure we want to.
   bool mUseParserDuration;
   int64_t mLastParserDuration;
 
+#if GST_VERSION_MAJOR >= 1
+  GstAllocator *mAllocator;
+  GstBufferPool *mBufferPool;
+  GstVideoInfo mVideoInfo;
+#endif
   GstElement* mPlayBin;
   GstBus* mBus;
   GstAppSrc* mSource;
   /* video sink bin */
   GstElement* mVideoSink;
   /* the actual video app sink */
   GstAppSink* mVideoAppSink;
   /* audio sink bin */
@@ -194,15 +217,18 @@ private:
    * Concurrent access guarded with mGstThreadsMonitor.
    */
   GstSegment mVideoSegment;
   GstSegment mAudioSegment;
   /* bool used to signal when gst has detected the end of stream and
    * DecodeAudioData and DecodeVideoFrame should not expect any more data
    */
   bool mReachedEos;
+#if GST_VERSION_MAJOR >= 1
+  bool mConfigureAlignment;
+#endif
   int fpsNum;
   int fpsDen;
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/gstreamer/moz.build
+++ b/content/media/gstreamer/moz.build
@@ -10,20 +10,29 @@ EXPORTS += [
     'GStreamerLoader.h',
     'GStreamerReader.h',
 ]
 
 SOURCES += [
     'GStreamerDecoder.cpp',
     'GStreamerFormatHelper.cpp',
     'GStreamerLoader.cpp',
-    'GStreamerMozVideoBuffer.cpp',
     'GStreamerReader.cpp',
 ]
 
+if CONFIG['GST_API_VERSION'] == '1.0':
+    SOURCES += [
+        'GStreamerAllocator.cpp',
+    ]
+else:
+    SOURCES += [
+        'GStreamerMozVideoBuffer.cpp',
+        'GStreamerReader-0.10.cpp',
+    ]
+
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/content/html/content/src',
 ]
 
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -360,19 +360,19 @@ function IsWindows8OrLater() {
 
 // These are files that are non seekable, due to problems with the media,
 // for example broken or missing indexes.
 var gUnseekableTests = [
   { name:"no-cues.webm", type:"video/webm" },
   { name:"bogus.duh", type:"bogus/duh"}
 ];
 // Unfortunately big-buck-bunny-unseekable.mp4 is doesn't play on Windows 7, so
-// only include it in the unseekable tests if we're on later versions of Windows.
-if (navigator.userAgent.indexOf("Windows") == -1 ||
-    IsWindows8OrLater()) {
+// only include it in the unseekable tests if we're on later versions of Windows. 
+// This test actually only passes on win8 at the moment.
+if (navigator.userAgent.indexOf("Windows") != -1 && IsWindows8OrLater()) {
   gUnseekableTests = gUnseekableTests.concat([
     { name:"big-buck-bunny-unseekable.mp4", type:"video/mp4" }
   ]);
 }
 // Android supports fragmented MP4 playback from 4.3.
 var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
                                   .getService(SpecialPowers.Ci.nsIPropertyBag2)
                                   .getProperty('version');
deleted file mode 100644
--- a/content/xml/content/src/Makefile.in
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# 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 $(topsrcdir)/config/rules.mk
-
-EXPORT_RESOURCE_CONTENT = \
-		$(srcdir)/htmlmathml-f.ent \
-		$(NULL)
-libs::
-	$(INSTALL) $(EXPORT_RESOURCE_CONTENT) $(DIST)/bin/res/dtd
--- a/content/xml/content/src/moz.build
+++ b/content/xml/content/src/moz.build
@@ -22,8 +22,11 @@ FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
     '/content/base/src',
 ]
 
+RESOURCE_FILES.dtd += [
+    'htmlmathml-f.ent',
+]
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2038,34 +2038,34 @@ BaseStubConstructor(nsIWeakReference* aW
 
       // Check if the object is even callable.
       NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject()));
       {
         // wrap parameters in the target compartment
         // we also pass in the calling window as the first argument
         unsigned argc = args.length() + 1;
         JS::AutoValueVector argv(cx);
-        argv.resize(argc);
+        if (!argv.resize(argc)) {
+          return NS_ERROR_OUT_OF_MEMORY;
+        }
 
         nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner));
         rv = WrapNative(cx, obj, currentWin, &NS_GET_IID(nsIDOMWindow),
                         true, argv.handleAt(0));
         if (!JS_WrapValue(cx, argv.handleAt(0)))
           return NS_ERROR_FAILURE;
 
         for (size_t i = 1; i < argc; ++i) {
           argv[i] = args[i - 1];
           if (!JS_WrapValue(cx, argv.handleAt(i)))
             return NS_ERROR_FAILURE;
         }
 
         JS::Rooted<JS::Value> frval(cx);
-        bool ret = JS_CallFunctionValue(cx, thisObject, funval,
-                                        argc, argv.begin(),
-                                        frval.address());
+        bool ret = JS_CallFunctionValue(cx, thisObject, funval, argv, frval.address());
 
         if (!ret) {
           return NS_ERROR_FAILURE;
         }
       }
     }
   }
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -748,16 +748,98 @@ nsDOMWindowUtils::SendMouseEventCommon(c
   }
   nsresult rv = widget->DispatchEvent(&event, status);
   *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
 
   return rv;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
+                                   float aX,
+                                   float aY,
+                                   int32_t aButton,
+                                   int32_t aClickCount,
+                                   int32_t aModifiers,
+                                   bool aIgnoreRootScrollFrame,
+                                   float aPressure,
+                                   unsigned short aInputSourceArg,
+                                   int32_t aPointerId,
+                                   int32_t aWidth,
+                                   int32_t aHeight,
+                                   int32_t tiltX,
+                                   int32_t tiltY,
+                                   bool aIsPrimary,
+                                   bool aIsSynthesized,
+                                   uint8_t aOptionalArgCount,
+                                   bool* aPreventDefault)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  // get the widget to send the event to
+  nsPoint offset;
+  nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
+  if (!widget) {
+    return NS_ERROR_FAILURE;
+  }
+
+  int32_t msg;
+  if (aType.EqualsLiteral("pointerdown")) {
+    msg = NS_POINTER_DOWN;
+  } else if (aType.EqualsLiteral("pointerup")) {
+    msg = NS_POINTER_UP;
+  } else if (aType.EqualsLiteral("pointermove")) {
+    msg = NS_POINTER_MOVE;
+  } else if (aType.EqualsLiteral("pointerover")) {
+    msg = NS_POINTER_OVER;
+  } else if (aType.EqualsLiteral("pointerout")) {
+    msg = NS_POINTER_OUT;
+  } else {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) {
+    aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
+  }
+
+  WidgetPointerEvent event(true, msg, widget);
+  event.modifiers = GetWidgetModifiers(aModifiers);
+  event.button = aButton;
+  event.buttons = GetButtonsFlagForButton(aButton);
+  event.widget = widget;
+  event.pressure = aPressure;
+  event.inputSource = aInputSourceArg;
+  event.pointerId = aPointerId;
+  event.width = aWidth;
+  event.height = aHeight;
+  event.tiltX = tiltX;
+  event.tiltY = tiltY;
+  event.isPrimary = aIsPrimary;
+  event.clickCount = aClickCount;
+  event.time = PR_IntervalNow();
+  event.mFlags.mIsSynthesizedForTests = aOptionalArgCount >= 10 ? aIsSynthesized : true;
+
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext) {
+    return NS_ERROR_FAILURE;
+  }
+
+  event.refPoint = ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
+  event.ignoreRootScrollFrame = aIgnoreRootScrollFrame;
+
+  nsEventStatus status;
+  nsresult rv = widget->DispatchEvent(&event, status);
+  *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
+
+  return rv;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::SendWheelEvent(float aX,
                                  float aY,
                                  double aDeltaX,
                                  double aDeltaY,
                                  double aDeltaZ,
                                  uint32_t aDeltaMode,
                                  int32_t aModifiers,
                                  int32_t aLineOrPageDeltaX,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -550,16 +550,17 @@ nsTimeout::HasRefCntOne()
 }
 
 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
 : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
   mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
   mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
   mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
   mMayHaveMouseEnterLeaveEventListener(false),
+  mMayHavePointerEnterLeaveEventListener(false),
   mIsModalContentWindow(false),
   mIsActive(false), mIsBackground(false),
   mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
   // Make sure no actual window ends up with mWindowID == 0
   mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false),
   mMarkedCCGeneration(0)
  {}
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -282,40 +282,16 @@ nsJSEnvironmentObserver::Observe(nsISupp
   } else if (!nsCRT::strcmp(aTopic, "quit-application")) {
     sShuttingDown = true;
     KillTimers();
   }
 
   return NS_OK;
 }
 
-class nsRootedJSValueArray {
-public:
-  explicit nsRootedJSValueArray(JSContext *cx) : avr(cx, vals.Length(), vals.Elements()) {}
-
-  void SetCapacity(JSContext *cx, size_t capacity) {
-    vals.SetCapacity(capacity);
-    // Values must be safe for the GC to inspect (they must not contain garbage).
-    memset(vals.Elements(), 0, vals.Capacity() * sizeof(JS::Value));
-    resetRooter(cx);
-  }
-
-  JS::Value *Elements() {
-    return vals.Elements();
-  }
-
-private:
-  void resetRooter(JSContext *cx) {
-    avr.changeArray(vals.Elements(), vals.Length());
-  }
-
-  nsAutoTArray<JS::Value, 16> vals;
-  JS::AutoArrayRooter avr;
-};
-
 /****************************************************************
  ************************** AutoFree ****************************
  ****************************************************************/
 
 class AutoFree {
 public:
   AutoFree(void *aPtr) : mPtr(aPtr) {
   }
@@ -1170,70 +1146,67 @@ nsJSContext::InitializeExternalClasses()
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   return nameSpaceManager->InitForContext(this);
 }
 
 nsresult
 nsJSContext::SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, nsISupports* aArgs)
 {
-  uint32_t  argc;
-  JS::Value *argv = nullptr;
-
   nsCxPusher pusher;
   pusher.Push(mContext);
 
-  Maybe<nsRootedJSValueArray> tempStorage;
+  JS::AutoValueVector args(mContext);
 
   JS::Rooted<JSObject*> global(mContext, GetWindowProxy());
   nsresult rv =
-    ConvertSupportsTojsvals(aArgs, global, &argc, &argv, tempStorage);
+    ConvertSupportsTojsvals(aArgs, global, args);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  JS::AutoArrayRooter array(mContext, argc, argv);
-
   // got the arguments, now attach them.
 
-  for (uint32_t i = 0; i < argc; ++i) {
-    if (!JS_WrapValue(mContext, array.handleAt(i))) {
+  for (uint32_t i = 0; i < args.length(); ++i) {
+    if (!JS_WrapValue(mContext, args.handleAt(i))) {
       return NS_ERROR_FAILURE;
     }
   }
 
-  JSObject *args = ::JS_NewArrayObject(mContext, argc, array.start());
-  if (!args) {
+  JSObject* array = ::JS_NewArrayObject(mContext, args.length(), args.begin());
+  if (!array) {
     return NS_ERROR_FAILURE;
   }
-  JS::Value vargs = OBJECT_TO_JSVAL(args);
-
-  return JS_DefineProperty(mContext, aTarget, aPropName, vargs,
-  						   nullptr, nullptr, 0) ? NS_OK : NS_ERROR_FAILURE;
+  JS::Rooted<JS::Value> arrayVal(mContext, JS::ObjectValue(*array));
+
+  return JS_DefineProperty(mContext, aTarget, aPropName, arrayVal,
+                           nullptr, nullptr, 0) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
-nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
+nsJSContext::ConvertSupportsTojsvals(nsISupports* aArgs,
                                      JS::Handle<JSObject*> aScope,
-                                     uint32_t *aArgc,
-                                     JS::Value **aArgv,
-                                     Maybe<nsRootedJSValueArray> &aTempStorage)
+                                     JS::AutoValueVector& aArgsOut)
 {
   nsresult rv = NS_OK;
 
-  // If the array implements nsIJSArgArray, just grab the values directly.
+  // If the array implements nsIJSArgArray, copy the contents and return.
   nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
-  if (fastArray != nullptr)
-    return fastArray->GetArgs(aArgc, reinterpret_cast<void **>(aArgv));
+  if (fastArray) {
+    uint32_t argc;
+    JS::Value* argv;
+    rv = fastArray->GetArgs(&argc, reinterpret_cast<void **>(&argv));
+    if (NS_SUCCEEDED(rv) && !aArgsOut.append(argv, argc)) {
+      rv = NS_ERROR_OUT_OF_MEMORY;
+    }
+    return rv;
+  }
 
   // Take the slower path converting each item.
   // Handle only nsIArray and nsIVariant.  nsIArray is only needed for
   // SetProperty('arguments', ...);
 
-  *aArgv = nullptr;
-  *aArgc = 0;
-
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
   AutoJSContext cx;
 
   if (!aArgs)
     return NS_OK;
   uint32_t argCount;
   // This general purpose function may need to convert an arg array
@@ -1245,74 +1218,62 @@ nsJSContext::ConvertSupportsTojsvals(nsI
     NS_ENSURE_SUCCESS(rv, rv);
     if (argCount == 0)
       return NS_OK;
   } else {
     argCount = 1; // the nsISupports which is not an array
   }
 
   // Use the caller's auto guards to release and unroot.
-  aTempStorage.construct((JSContext*)cx);
-  aTempStorage.ref().SetCapacity(cx, argCount);
-  JS::Value *argv = aTempStorage.ref().Elements();
+  if (!aArgsOut.resize(argCount)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   if (argsArray) {
     for (uint32_t argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
       nsCOMPtr<nsISupports> arg;
-      JS::Value *thisval = argv + argCtr;
+      JS::MutableHandle<JS::Value> thisVal = aArgsOut.handleAt(argCtr);
       argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
                                 getter_AddRefs(arg));
       if (!arg) {
-        *thisval = JSVAL_NULL;
+        thisVal.setNull();
         continue;
       }
       nsCOMPtr<nsIVariant> variant(do_QueryInterface(arg));
       if (variant != nullptr) {
-        JS::Rooted<JS::Value> temp(cx);
-        rv = xpc->VariantToJS(cx, aScope, variant, &temp);
-        *thisval = temp.get();
+        rv = xpc->VariantToJS(cx, aScope, variant, thisVal);
       } else {
         // And finally, support the nsISupportsPrimitives supplied
         // by the AppShell.  It generally will pass only strings, but
         // as we have code for handling all, we may as well use it.
-        rv = AddSupportsPrimitiveTojsvals(arg, thisval);
+        rv = AddSupportsPrimitiveTojsvals(arg, thisVal.address());
         if (rv == NS_ERROR_NO_INTERFACE) {
           // something else - probably an event object or similar -
           // just wrap it.
 #ifdef DEBUG
           // but first, check its not another nsISupportsPrimitive, as
           // these are now deprecated for use with script contexts.
           nsCOMPtr<nsISupportsPrimitive> prim(do_QueryInterface(arg));
           NS_ASSERTION(prim == nullptr,
                        "Don't pass nsISupportsPrimitives - use nsIVariant!");
 #endif
-          JS::Rooted<JS::Value> v(cx);
-          rv = nsContentUtils::WrapNative(cx, aScope, arg, &v);
-          if (NS_SUCCEEDED(rv)) {
-            *thisval = v;
-          }
+          rv = nsContentUtils::WrapNative(cx, aScope, arg, thisVal);
         }
       }
     }
   } else {
     nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs);
     if (variant) {
-      JS::Rooted<JS::Value> temp(cx);
-      rv = xpc->VariantToJS(cx, aScope, variant, &temp);
-      *argv = temp.get();
+      rv = xpc->VariantToJS(cx, aScope, variant, aArgsOut.handleAt(0));
     } else {
       NS_ERROR("Not an array, not an interface?");
       rv = NS_ERROR_UNEXPECTED;
     }
   }
-  if (NS_FAILED(rv))
-    return rv;
-  *aArgv = argv;
-  *aArgc = argCount;
-  return NS_OK;
+  return rv;
 }
 
 // This really should go into xpconnect somewhere...
 nsresult
 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
 {
   NS_PRECONDITION(aArg, "Empty arg");
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -13,20 +13,23 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsIXPConnect.h"
 #include "nsIArray.h"
 #include "mozilla/Attributes.h"
 #include "nsThreadUtils.h"
 
 class nsICycleCollectorListener;
 class nsIXPConnectJSObjectHolder;
-class nsRootedJSValueArray;
 class nsScriptNameSpaceManager;
 class nsCycleCollectionNoteRootCallback;
 
+namespace JS {
+class AutoValueVector;
+}
+
 namespace mozilla {
 template <class> class Maybe;
 struct CycleCollectorResults;
 }
 
 // The amount of time we wait between a request to GC (due to leaving
 // a page) and doing the actual GC.
 #define NS_GC_DELAY                 4000 // ms
@@ -142,19 +145,17 @@ public:
     return global ? mGlobalObjectRef.get() : nullptr;
   }
 protected:
   nsresult InitializeExternalClasses();
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    JS::Handle<JSObject*> aScope,
-                                   uint32_t *aArgc,
-                                   JS::Value **aArgv,
-                                   mozilla::Maybe<nsRootedJSValueArray> &aPoolRelease);
+                                   JS::AutoValueVector &aArgsOut);
 
   nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv);
 
   // given an nsISupports object (presumably an event target or some other
   // DOM object), get (or create) the JSObject wrapping it.
   nsresult JSObjectFromInterface(nsISupports *aSup,
                                  JS::Handle<JSObject*> aScript,
                                  JSObject **aRet);
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -478,16 +478,35 @@ public:
    * Call this to indicate that some node (this window, its document,
    * or content in that document) has a mouseenter/leave event listener.
    */
   void SetHasMouseEnterLeaveEventListeners()
   {
     mMayHaveMouseEnterLeaveEventListener = true;
   }
 
+  /**
+   * Call this to check whether some node (this window, its document,
+   * or content in that document) has a Pointerenter/leave event listener.
+   */
+  bool HasPointerEnterLeaveEventListeners()
+  {
+    return mMayHavePointerEnterLeaveEventListener;
+  }
+
+  /**
+   * Call this to indicate that some node (this window, its document,
+   * or content in that document) has a Pointerenter/leave event listener.
+   */
+  void SetHasPointerEnterLeaveEventListeners()
+  {
+    mMayHavePointerEnterLeaveEventListener = true;
+  }
+
+
   virtual JSObject* GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey) = 0;
   virtual void CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
                                         JS::Handle<JSObject*> aHandler) = 0;
 
   /*
    * Get and set the currently focused element within the document. If
    * aNeedsFocus is true, then set mNeedsFocus to true to indicate that a
    * document focus event is needed.
@@ -728,16 +747,17 @@ protected:
   uint32_t               mMutationBits;
 
   bool                   mIsDocumentLoaded;
   bool                   mIsHandlingResizeEvent;
   bool                   mIsInnerWindow;
   bool                   mMayHavePaintEventListener;
   bool                   mMayHaveTouchEventListener;
   bool                   mMayHaveMouseEnterLeaveEventListener;
+  bool                   mMayHavePointerEnterLeaveEventListener;
 
   // This variable is used on both inner and outer windows (and they
   // should match).
   bool                   mIsModalContentWindow;
 
   // Tracks activation state that's used for :-moz-window-inactive.
   // Only used on outer windows.
   bool                   mIsActive;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -90,24 +90,24 @@ ThrowInvalidThis(JSContext* aCx, const J
 }
 
 bool
 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
                  const ErrNum aErrorNumber,
                  prototypes::ID aProtoId)
 {
   return ThrowInvalidThis(aCx, aArgs, aErrorNumber,
-                          NamesOfInterfacesWithProtos[aProtoId]);
+                          NamesOfInterfacesWithProtos(aProtoId));
 }
 
 bool
 ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
 {
   nsPrintfCString errorMessage("%s attribute setter",
-                               NamesOfInterfacesWithProtos[aProtoId]);
+                               NamesOfInterfacesWithProtos(aProtoId));
   return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
 }
 
 } // namespace dom
 
 struct ErrorResult::Message {
   nsTArray<nsString> mArgs;
   dom::ErrNum mErrorNumber;
@@ -1603,17 +1603,17 @@ NativeToString(JSContext* cx, JS::Handle
     JSAutoCompartment ac(cx, obj);
     if (toStringDesc.object()) {
       JS::Rooted<JS::Value> toString(cx, toStringDesc.value());
       if (!JS_WrapValue(cx, &toString)) {
         return false;
       }
       MOZ_ASSERT(JS_ObjectIsCallable(cx, &toString.toObject()));
       JS::Rooted<JS::Value> toStringResult(cx);
-      if (JS_CallFunctionValue(cx, obj, toString, 0, nullptr,
+      if (JS_CallFunctionValue(cx, obj, toString, JS::EmptyValueArray,
                                toStringResult.address())) {
         str = toStringResult.toString();
       } else {
         str = nullptr;
       }
     } else {
       const js::Class* clasp = js::GetObjectClass(obj);
       if (IsDOMClass(clasp)) {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -59,16 +59,59 @@ class CGThing():
         assert(False)  # Override me!
     def define(self):
         """Produce code for a cpp file."""
         assert(False) # Override me!
     def deps(self):
         """Produce the deps for a pp file"""
         assert(False) # Override me!
 
+class CGStringTable(CGThing):
+    """
+    Generate a string table for the given strings with a function accessor:
+
+    const char *accessorName(unsigned int index) {
+      static const char table[] = "...";
+      static const uint16_t indices = { ... };
+      return &table[indices[index]];
+    }
+
+    This is more efficient than the more natural:
+
+    const char *table[] = {
+      ...
+    };
+
+    The uint16_t indices are smaller than the pointer equivalents, and the
+    string table requires no runtime relocations.
+    """
+    def __init__(self, accessorName, strings):
+        CGThing.__init__(self)
+        self.accessorName = accessorName
+        self.strings = strings
+
+    def declare(self):
+        return "extern const char *%s(unsigned int aIndex);\n" % self.accessorName
+
+    def define(self):
+        table = ' "\\0" '.join('"%s"' % s for s in self.strings)
+        indices = []
+        currentIndex = 0
+        for s in self.strings:
+            indices.append(currentIndex)
+            currentIndex += len(s) + 1 # for the null terminator
+        return """const char *%s(unsigned int aIndex)
+{
+  static const char table[] = %s;
+  static const uint16_t indices[] = { %s };
+  static_assert(%d <= UINT16_MAX, "string table overflow!");
+  return &table[indices[aIndex]];
+}
+""" % (self.accessorName, table, ", ".join("%d" % index for index in indices), currentIndex)
+
 class CGNativePropertyHooks(CGThing):
     """
     Generate a NativePropertyHooks for a given descriptor
     """
     def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.properties = properties
@@ -298,17 +341,17 @@ class CGPrototypeJSClass(CGThing):
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
         (prototypeID, depth) = PrototypeIDAndDepth(self.descriptor)
         slotCount = "DOM_INTERFACE_PROTO_SLOTS_BASE"
         if UseHolderForUnforgeable(self.descriptor):
             slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */"
-        return """static DOMIfaceAndProtoJSClass PrototypeClass = {
+        return """static const DOMIfaceAndProtoJSClass PrototypeClass = {
   {
     "%sPrototype",
     JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(%s),
     JS_PropertyStub,       /* addProperty */
     JS_DeletePropertyStub, /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
     JS_EnumerateStub,
@@ -355,17 +398,17 @@ class CGInterfaceObjectJSClass(CGThing):
         else:
             hasinstance = "nullptr"
         (prototypeID, depth) = PrototypeIDAndDepth(self.descriptor)
         slotCount = "DOM_INTERFACE_SLOTS_BASE"
         if len(self.descriptor.interface.namedConstructors) > 0:
             slotCount += (" + %i /* slots for the named constructors */" %
                           len(self.descriptor.interface.namedConstructors))
         return """
-static DOMIfaceAndProtoJSClass InterfaceObjectClass = {
+static const DOMIfaceAndProtoJSClass InterfaceObjectClass = {
   {
     "Function",
     JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(%s),
     JS_PropertyStub,       /* addProperty */
     JS_DeletePropertyStub, /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
     JS_EnumerateStub,
@@ -11289,24 +11332,22 @@ class CallbackMethod(CallbackMember):
     def getCall(self):
         replacements = {
             "errorReturn" : self.getDefaultRetval(),
             "thisVal": self.getThisVal(),
             "getCallable": self.getCallableDecl(),
             "callGuard": self.getCallGuard()
             }
         if self.argCount > 0:
-            replacements["argv"] = "argv.begin()"
-            replacements["argc"] = "argc"
-        else:
-            replacements["argv"] = "nullptr"
-            replacements["argc"] = "0"
+            replacements["args"] = "JS::HandleValueArray::subarray(argv, 0, argc)"
+        else:
+            replacements["args"] = "JS::EmptyValueArray"
         return string.Template("${getCallable}"
                 "if (${callGuard}!JS::Call(cx, ${thisVal}, callable,\n"
-                "              ${argc}, ${argv}, &rval)) {\n"
+                "              ${args}, &rval)) {\n"
                 "  aRv.Throw(NS_ERROR_UNEXPECTED);\n"
                 "  return${errorReturn};\n"
                 "}\n").substitute(replacements)
 
 class CallCallback(CallbackMethod):
     def __init__(self, callback, descriptorProvider):
         self.callback = callback
         CallbackMethod.__init__(self, callback.signatures()[0], "Call",
@@ -11560,17 +11601,18 @@ class GlobalGenRoots():
         idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID",
                                       "Too many prototypes!"));
 
         # Wrap all of that in our namespaces.
         idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'],
                                    CGWrapper(idEnum, pre='\n'))
         idEnum = CGWrapper(idEnum, post='\n')
 
-        curr = CGList([idEnum])
+        curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"),
+                       idEnum])
 
         # Let things know the maximum length of the prototype chain.
         maxMacroName = "MAX_PROTOTYPE_CHAIN_LENGTH"
         maxMacro = CGGeneric(declare="#define " + maxMacroName + " " + str(config.maxProtoChainLength))
         curr.append(CGWrapper(maxMacro, post='\n\n'))
         curr.append(fieldSizeAssert(maxMacroName, "depth",
                                     "Some inheritance chain is too long!"));
 
@@ -11587,27 +11629,20 @@ class GlobalGenRoots():
         curr.append(idEnum)
 
         traitsDecls = [CGGeneric(declare="""
 template <prototypes::ID PrototypeID>
 struct PrototypeTraits;
 """)]
         traitsDecls.extend(CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype)
 
-        ifaceNamesWithProto = ['  "%s"' % d.interface.identifier.name
+        ifaceNamesWithProto = [d.interface.identifier.name
                                for d in descriptorsWithPrototype]
-        traitsDecls.append(CGGeneric(
-                declare=("extern const char* NamesOfInterfacesWithProtos[%d];\n\n" %
-                         len(ifaceNamesWithProto)),
-                define=("\n"
-                        "const char* NamesOfInterfacesWithProtos[%d] = {\n"
-                        "%s"
-                        "\n};\n\n" %
-                        (len(ifaceNamesWithProto),
-                         ",\n".join(ifaceNamesWithProto)))))
+        traitsDecls.append(CGStringTable("NamesOfInterfacesWithProtos",
+                                         ifaceNamesWithProto))
 
         traitsDecl = CGNamespace.build(['mozilla', 'dom'],
                                         CGList(traitsDecls, "\n"))
 
         curr.append(traitsDecl)
 
         # Add include guards.
         curr = CGIncludeGuard('PrototypeList', curr)
--- a/dom/events/nsEventListenerManager.cpp
+++ b/dom/events/nsEventListenerManager.cpp
@@ -89,16 +89,17 @@ uint32_t nsEventListenerManager::sMainTh
 nsEventListenerManager::nsEventListenerManager(EventTarget* aTarget) :
   mMayHavePaintEventListener(false),
   mMayHaveMutationListeners(false),
   mMayHaveCapturingListeners(false),
   mMayHaveSystemGroupListeners(false),
   mMayHaveAudioAvailableEventListener(false),
   mMayHaveTouchEventListener(false),
   mMayHaveMouseEnterLeaveEventListener(false),
+  mMayHavePointerEnterLeaveEventListener(false),
   mClearingListeners(false),
   mIsMainThreadELM(NS_IsMainThread()),
   mNoListenerForEvent(0),
   mTarget(aTarget)
 {
   NS_ASSERTION(aTarget, "unexpected null pointer");
 
   if (mIsMainThreadELM) {
@@ -335,16 +336,31 @@ nsEventListenerManager::AddEventListener
              aTypeAtom == nsGkAtoms::ontouchcancel) {
     mMayHaveTouchEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     // we don't want touchevent listeners added by scrollbars to flip this flag
     // so we ignore listeners created with system event flag
     if (window && !aFlags.mInSystemGroup) {
       window->SetHasTouchEventListeners();
     }
+  } else if (aType >= NS_POINTER_EVENT_START && aType <= NS_POINTER_LOST_CAPTURE) {
+    nsPIDOMWindow* window = GetInnerWindowForTarget();
+    if (aTypeAtom == nsGkAtoms::onpointerenter ||
+        aTypeAtom == nsGkAtoms::onpointerleave) {
+      mMayHavePointerEnterLeaveEventListener = true;
+      if (window) {
+#ifdef DEBUG
+        nsCOMPtr<nsIDocument> d = window->GetExtantDoc();
+        NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d),
+                         "Please do not use pointerenter/leave events in chrome. "
+                         "They are slower than pointerover/out!");
+#endif
+        window->SetHasPointerEnterLeaveEventListeners();
+      }
+    }
   } else if (aTypeAtom == nsGkAtoms::onmouseenter ||
              aTypeAtom == nsGkAtoms::onmouseleave) {
     mMayHaveMouseEnterLeaveEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     if (window) {
 #ifdef DEBUG
       nsCOMPtr<nsIDocument> d = window->GetExtantDoc();
       NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d),
--- a/dom/events/nsEventListenerManager.h
+++ b/dom/events/nsEventListenerManager.h
@@ -394,16 +394,17 @@ public:
 
   /**
    * Returns true if there may be a touch event listener registered,
    * false if there definitely isn't.
    */
   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
 
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
+  bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   uint32_t ListenerCount() const
   {
     return mListeners.Length();
   }
 
@@ -543,19 +544,20 @@ protected:
 
   uint32_t mMayHavePaintEventListener : 1;
   uint32_t mMayHaveMutationListeners : 1;
   uint32_t mMayHaveCapturingListeners : 1;
   uint32_t mMayHaveSystemGroupListeners : 1;
   uint32_t mMayHaveAudioAvailableEventListener : 1;
   uint32_t mMayHaveTouchEventListener : 1;
   uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
+  uint32_t mMayHavePointerEnterLeaveEventListener : 1;
   uint32_t mClearingListeners : 1;
   uint32_t mIsMainThreadELM : 1;
-  uint32_t mNoListenerForEvent : 23;
+  uint32_t mNoListenerForEvent : 22;
 
   nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
   mozilla::dom::EventTarget*                mTarget;  //WEAK
   nsCOMPtr<nsIAtom>                         mNoListenerForEventAtom;
 
   friend class ELMCreationDetector;
   static uint32_t                           sMainThreadCreatedCount;
 };
--- a/dom/events/nsEventStateManager.cpp
+++ b/dom/events/nsEventStateManager.cpp
@@ -822,24 +822,40 @@ nsScrollbarsForWheel::DeactivateAllTempo
         scrollbarOwner->ScrollbarActivityStopped();
       }
       *scrollTarget = nullptr;
     }
   }
 }
 
 /******************************************************************/
+/* OverOutElementsWrapper                                         */
+/******************************************************************/
+
+NS_IMPL_CYCLE_COLLECTION_3(OverOutElementsWrapper,
+                           mLastOverElement,
+                           mFirstOverEventElement,
+                           mFirstOutEventElement)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/******************************************************************/
+
+/******************************************************************/
 /* nsEventStateManager                                            */
 /******************************************************************/
 
 nsEventStateManager::nsEventStateManager()
   : mLockCursor(0),
     mPreLockPoint(0,0),
     mCurrentTarget(nullptr),
-    mLastMouseOverFrame(nullptr),
     // init d&d gesture state machine variables
     mGestureDownPoint(0,0),
     mPresContext(nullptr),
     mLClickCount(0),
     mMClickCount(0),
     mRClickCount(0),
     m_haveShutdown(false)
 {
@@ -956,32 +972,31 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
    NS_INTERFACE_MAP_ENTRY(nsIObserver)
    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEventStateManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEventStateManager)
 
-NS_IMPL_CYCLE_COLLECTION_17(nsEventStateManager,
+NS_IMPL_CYCLE_COLLECTION_16(nsEventStateManager,
                             mCurrentTargetContent,
-                            mLastMouseOverElement,
                             mGestureDownContent,
                             mGestureDownFrameOwner,
                             mLastLeftMouseDownContent,
                             mLastLeftMouseDownContentParent,
                             mLastMiddleMouseDownContent,
                             mLastMiddleMouseDownContentParent,
                             mLastRightMouseDownContent,
                             mLastRightMouseDownContentParent,
                             mActiveContent,
                             mHoverContent,
                             mURLTargetContent,
-                            mFirstMouseOverEventElement,
-                            mFirstMouseOutEventElement,
+                            mMouseEnterLeaveHelper,
+                            mPointersEnterLeaveHelper,
                             mDocument,
                             mAccessKeys)
 
 nsresult
 nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
                                     WidgetEvent* aEvent,
                                     nsIFrame* aTargetFrame,
                                     nsEventStatus* aStatus)
@@ -1091,17 +1106,18 @@ nsEventStateManager::PreHandleEvent(nsPr
       mouseEvent->reason = WidgetMouseEvent::eSynthesized;
       // then fall through...
     } else {
       GenerateMouseEnterExit(mouseEvent);
       //This is a window level mouse exit event and should stop here
       aEvent->message = 0;
       break;
     }
-  case NS_MOUSE_MOVE: {
+  case NS_MOUSE_MOVE:
+  case NS_POINTER_MOVE: {
     // on the Mac, GenerateDragGesture() may not return until the drag
     // has completed and so |aTargetFrame| may have been deleted (moving
     // a bookmark, for example).  If this is the case, however, we know
     // that ClearFrameRefs() has been called and it cleared out
     // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
     // into UpdateCursor().
     GenerateDragGesture(aPresContext, mouseEvent);
     UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
@@ -3358,16 +3374,26 @@ nsEventStateManager::PostHandleEvent(nsP
               fm->SetFocusedWindow(mDocument->GetWindow());
             }
           }
         }
       }
       SetActiveManager(this, activeContent);
     }
     break;
+  case NS_POINTER_CANCEL:
+  case NS_POINTER_UP: {
+    WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
+    // After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table
+    // Mouse/Pen pointers are valid all the time (not only between down/up)
+    if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+      mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
+    }
+    break;
+  }
   case NS_MOUSE_BUTTON_UP:
     {
       ClearGlobalActiveContent(this);
       if (IsMouseEventReal(aEvent)) {
         if (!mCurrentTarget) {
           GetEventTarget();
         }
         // Make sure to dispatch the click even if there is no frame for
@@ -3733,16 +3759,17 @@ nsEventStateManager::NotifyDestroyPresCo
   nsIMEStateManager::OnDestroyPresContext(aPresContext);
   if (mHoverContent) {
     // Bug 70855: Presentation is going away, possibly for a reframe.
     // Reset the hover state so that if we're recreating the presentation,
     // we won't have the old hover state still set in the new presentation,
     // as if the new presentation is resized, a new element may be hovered. 
     SetContentState(nullptr, NS_EVENT_STATE_HOVER);
   }
+  mPointersEnterLeaveHelper.Clear();
 }
 
 void
 nsEventStateManager::SetPresContext(nsPresContext* aPresContext)
 {
   mPresContext = aPresContext;
 }
 
@@ -4022,20 +4049,20 @@ nsEventStateManager::IsHandlingUserInput
   }
 
   TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
   return timeout <= TimeDuration(0) ||
          (TimeStamp::Now() - sHandlingInputStart) <= timeout;
 }
 
 nsIFrame*
-nsEventStateManager::DispatchMouseEvent(WidgetMouseEvent* aMouseEvent,
-                                        uint32_t aMessage,
-                                        nsIContent* aTargetContent,
-                                        nsIContent* aRelatedContent)
+nsEventStateManager::DispatchMouseOrPointerEvent(WidgetMouseEvent* aMouseEvent,
+                                                 uint32_t aMessage,
+                                                 nsIContent* aTargetContent,
+                                                 nsIContent* aRelatedContent)
 {
   // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
   // "[When the mouse is locked on an element...e]vents that require the concept
   // of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
   if (sIsPointerLocked &&
       (aMessage == NS_MOUSELEAVE ||
        aMessage == NS_MOUSEENTER ||
        aMessage == NS_MOUSE_ENTER_SYNTH ||
@@ -4046,62 +4073,82 @@ nsEventStateManager::DispatchMouseEvent(
     if (!pointerLockedElement) {
       NS_WARNING("Should have pointer locked element, but didn't.");
       return nullptr;
     }
     nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
     return mPresContext->GetPrimaryFrameFor(content);
   }
 
-  PROFILER_LABEL("Input", "DispatchMouseEvent");
   nsEventStatus status = nsEventStatus_eIgnore;
-  WidgetMouseEvent event(aMouseEvent->mFlags.mIsTrusted, aMessage,
-                         aMouseEvent->widget, WidgetMouseEvent::eReal);
-  event.refPoint = aMouseEvent->refPoint;
-  event.modifiers = aMouseEvent->modifiers;
-  event.buttons = aMouseEvent->buttons;
-  event.pluginEvent = aMouseEvent->pluginEvent;
-  event.relatedTarget = aRelatedContent;
-  event.inputSource = aMouseEvent->inputSource;
+  nsAutoPtr<WidgetPointerEvent> newPointerEvent;
+  nsAutoPtr<WidgetMouseEvent> newMouseEvent;
+  WidgetMouseEvent* event = nullptr;
+  WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
+  if (sourcePointer) {
+    PROFILER_LABEL("Input", "DispatchPointerEvent");
+    newPointerEvent =
+      new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
+                             aMouseEvent->widget);
+    newPointerEvent->isPrimary = sourcePointer->isPrimary;
+    newPointerEvent->pointerId = sourcePointer->pointerId;
+    newPointerEvent->width = sourcePointer->width;
+    newPointerEvent->height = sourcePointer->height;
+    newPointerEvent->inputSource = sourcePointer->inputSource;
+    event = newPointerEvent.get();
+  } else {
+    PROFILER_LABEL("Input", "DispatchMouseEvent");
+    newMouseEvent =
+      new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
+                           aMouseEvent->widget, WidgetMouseEvent::eReal);
+    event = newMouseEvent.get();
+  }
+  event->refPoint = aMouseEvent->refPoint;
+  event->modifiers = aMouseEvent->modifiers;
+  event->buttons = aMouseEvent->buttons;
+  event->pluginEvent = aMouseEvent->pluginEvent;
+  event->relatedTarget = aRelatedContent;
+  event->inputSource = aMouseEvent->inputSource;
 
   nsWeakFrame previousTarget = mCurrentTarget;
 
   mCurrentTargetContent = aTargetContent;
 
   nsIFrame* targetFrame = nullptr;
   if (aTargetContent) {
     nsESMEventCB callback(aTargetContent);
-    nsEventDispatcher::Dispatch(aTargetContent, mPresContext, &event, nullptr,
+    nsEventDispatcher::Dispatch(aTargetContent, mPresContext, event, nullptr,
                                 &status, &callback);
 
     // Although the primary frame was checked in event callback, 
     // it may not be the same object after event dispatching and handling.
     // So we need to refetch it.
     if (mPresContext) {
       targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent);
     }
   }
 
   mCurrentTargetContent = nullptr;
   mCurrentTarget = previousTarget;
 
   return targetFrame;
 }
 
-class MouseEnterLeaveDispatcher
+class EnterLeaveDispatcher
 {
 public:
-  MouseEnterLeaveDispatcher(nsEventStateManager* aESM,
-                            nsIContent* aTarget, nsIContent* aRelatedTarget,
-                            WidgetMouseEvent* aMouseEvent, uint32_t aType)
+  EnterLeaveDispatcher(nsEventStateManager* aESM,
+                       nsIContent* aTarget, nsIContent* aRelatedTarget,
+                       WidgetMouseEvent* aMouseEvent, uint32_t aType)
   : mESM(aESM), mMouseEvent(aMouseEvent), mType(aType)
   {
     nsPIDOMWindow* win =
       aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
-    if (win && win->HasMouseEnterLeaveEventListeners()) {
+    if (aMouseEvent->AsPointerEvent() ? win && win->HasPointerEnterLeaveEventListeners() :
+                                        win && win->HasMouseEnterLeaveEventListeners()) {
       mRelatedTarget = aRelatedTarget ?
         aRelatedTarget->FindFirstNonChromeOnlyAccessContent() : nullptr;
       nsINode* commonParent = nullptr;
       if (aTarget && aRelatedTarget) {
         commonParent =
           nsContentUtils::GetCommonAncestor(aTarget, aRelatedTarget);
       }
       nsIContent* current = aTarget;
@@ -4111,52 +4158,55 @@ public:
           mTargets.AppendObject(current);
         }
         // mouseenter/leave is fired only on elements.
         current = current->GetParent();
       }
     }
   }
 
-  ~MouseEnterLeaveDispatcher()
+  ~EnterLeaveDispatcher()
   {
-    if (mType == NS_MOUSEENTER) {
+    if (mType == NS_MOUSEENTER ||
+        mType == NS_POINTER_ENTER) {
       for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
-        mESM->DispatchMouseEvent(mMouseEvent, mType, mTargets[i],
-                                 mRelatedTarget);
+        mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i],
+                                          mRelatedTarget);
       }
     } else {
       for (int32_t i = 0; i < mTargets.Count(); ++i) {
-        mESM->DispatchMouseEvent(mMouseEvent, mType, mTargets[i],
-                                 mRelatedTarget);
+        mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i],
+                                          mRelatedTarget);
       }
     }
   }
 
   nsEventStateManager*   mESM;
   nsCOMArray<nsIContent> mTargets;
   nsCOMPtr<nsIContent>   mRelatedTarget;
   WidgetMouseEvent*      mMouseEvent;
   uint32_t               mType;
 };
 
 void
 nsEventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
                                     nsIContent* aMovingInto)
 {
-  if (!mLastMouseOverElement)
+  OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
+
+  if (!wrapper->mLastOverElement)
     return;
   // Before firing mouseout, check for recursion
-  if (mLastMouseOverElement == mFirstMouseOutEventElement)
+  if (wrapper->mLastOverElement == wrapper->mFirstOutEventElement)
     return;
 
-  if (mLastMouseOverFrame) {
+  if (wrapper->mLastOverFrame) {
     // if the frame is associated with a subdocument,
     // tell the subdocument that we're moving out of it
-    nsSubDocumentFrame* subdocFrame = do_QueryFrame(mLastMouseOverFrame.GetFrame());
+    nsSubDocumentFrame* subdocFrame = do_QueryFrame(wrapper->mLastOverFrame.GetFrame());
     if (subdocFrame) {
       nsCOMPtr<nsIDocShell> docshell;
       subdocFrame->GetDocShell(getter_AddRefs(docshell));
       if (docshell) {
         nsRefPtr<nsPresContext> presContext;
         docshell->GetPresContext(getter_AddRefs(presContext));
 
         if (presContext) {
@@ -4164,57 +4214,62 @@ nsEventStateManager::NotifyMouseOut(Widg
           // Not moving into any element in this subdocument
           kidESM->NotifyMouseOut(aMouseEvent, nullptr);
         }
       }
     }
   }
   // That could have caused DOM events which could wreak havoc. Reverify
   // things and be careful.
-  if (!mLastMouseOverElement)
+  if (!wrapper->mLastOverElement)
     return;
 
   // Store the first mouseOut event we fire and don't refire mouseOut
   // to that element while the first mouseOut is still ongoing.
-  mFirstMouseOutEventElement = mLastMouseOverElement;
+  wrapper->mFirstOutEventElement = wrapper->mLastOverElement;
 
   // Don't touch hover state if aMovingInto is non-null.  Caller will update
   // hover state itself, and we have optimizations for hover switching between
   // two nearby elements both deep in the DOM tree that would be defeated by
   // switching the hover state to null here.
-  if (!aMovingInto) {
+  bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
+  if (!aMovingInto && !isPointer) {
     // Unset :hover
     SetContentState(nullptr, NS_EVENT_STATE_HOVER);
   }
 
-  MouseEnterLeaveDispatcher leaveDispatcher(this, mLastMouseOverElement, aMovingInto,
-                                            aMouseEvent, NS_MOUSELEAVE);
+  EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
+                                       aMovingInto, aMouseEvent,
+                                       isPointer ? NS_POINTER_LEAVE :
+                                                   NS_MOUSELEAVE);
 
   // Fire mouseout
-  DispatchMouseEvent(aMouseEvent, NS_MOUSE_EXIT_SYNTH,
-                     mLastMouseOverElement, aMovingInto);
-  
-  mLastMouseOverFrame = nullptr;
-  mLastMouseOverElement = nullptr;
-  
+  DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_EXIT_SYNTH,
+                              wrapper->mLastOverElement, aMovingInto);
+
+  wrapper->mLastOverFrame = nullptr;
+  wrapper->mLastOverElement = nullptr;
+
   // Turn recursion protection back off
-  mFirstMouseOutEventElement = nullptr;
+  wrapper->mFirstOutEventElement = nullptr;
 }
 
 void
 nsEventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
                                      nsIContent* aContent)
 {
   NS_ASSERTION(aContent, "Mouse must be over something");
 
-  if (mLastMouseOverElement == aContent)
+  OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
+
+  if (wrapper->mLastOverElement == aContent)
     return;
 
   // Before firing mouseover, check for recursion
-  if (aContent == mFirstMouseOverEventElement)
+  if (aContent == wrapper->mFirstOverEventElement)
     return;
 
   // Check to see if we're a subdocument and if so update the parent
   // document's ESM state to indicate that the mouse is over the
   // content associated with our subdocument.
   EnsureDocument(mPresContext);
   nsIDocument *parentDoc = mDocument->GetParentDocument();
   if (parentDoc) {
@@ -4224,41 +4279,49 @@ nsEventStateManager::NotifyMouseOver(Wid
       if (parentShell) {
         nsEventStateManager* parentESM = parentShell->GetPresContext()->EventStateManager();
         parentESM->NotifyMouseOver(aMouseEvent, docContent);
       }
     }
   }
   // Firing the DOM event in the parent document could cause all kinds
   // of havoc.  Reverify and take care.
-  if (mLastMouseOverElement == aContent)
+  if (wrapper->mLastOverElement == aContent)
     return;
 
-  // Remember mLastMouseOverElement as the related content for the
-  // DispatchMouseEvent() call below, since NotifyMouseOut() resets it, bug 298477.
-  nsCOMPtr<nsIContent> lastMouseOverElement = mLastMouseOverElement;
-
-  MouseEnterLeaveDispatcher enterDispatcher(this, aContent, lastMouseOverElement,
-                                            aMouseEvent, NS_MOUSEENTER);
-  
+  // Remember mLastOverElement as the related content for the
+  // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
+  nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
+
+  bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
+  EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
+                                       aMouseEvent,
+                                       isPointer ? NS_POINTER_ENTER :
+                                                   NS_MOUSEENTER);
+
   NotifyMouseOut(aMouseEvent, aContent);
 
   // Store the first mouseOver event we fire and don't refire mouseOver
   // to that element while the first mouseOver is still ongoing.
-  mFirstMouseOverEventElement = aContent;
-  
-  SetContentState(aContent, NS_EVENT_STATE_HOVER);
-  
+  wrapper->mFirstOverEventElement = aContent;
+
+  if (!isPointer) {
+    SetContentState(aContent, NS_EVENT_STATE_HOVER);
+  }
+
   // Fire mouseover
-  mLastMouseOverFrame = DispatchMouseEvent(aMouseEvent, NS_MOUSE_ENTER_SYNTH,
-                                           aContent, lastMouseOverElement);
-  mLastMouseOverElement = aContent;
-  
+  wrapper->mLastOverFrame =
+    DispatchMouseOrPointerEvent(aMouseEvent,
+                                isPointer ? NS_POINTER_OVER :
+                                            NS_MOUSE_ENTER_SYNTH,
+                                aContent, lastOverElement);
+  wrapper->mLastOverElement = aContent;
+
   // Turn recursion protection back off
-  mFirstMouseOverEventElement = nullptr;
+  wrapper->mFirstOverEventElement = nullptr;
 }
 
 // Returns the center point of the window's inner content area.
 // This is in widget coordinates, i.e. relative to the widget's top
 // left corner, not in screen coordinates, the same units that
 // nsDOMUIEvent::refPoint is in.
 //
 // XXX Hack alert: XXX
@@ -4352,55 +4415,80 @@ nsEventStateManager::GenerateMouseEnterE
         aMouseEvent->lastRefPoint = aMouseEvent->refPoint;
       } else {
         aMouseEvent->lastRefPoint = sLastRefPoint;
       }
 
       // Update the last known refPoint with the current refPoint.
       sLastRefPoint = aMouseEvent->refPoint;
 
+    }
+  case NS_POINTER_MOVE:
+    {
       // Get the target content target (mousemove target == mouseover target)
       nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
       if (!targetElement) {
         // We're always over the document root, even if we're only
         // over dead space in a page (whose frame is not associated with
         // any content) or in print preview dead space
         targetElement = mDocument->GetRootElement();
       }
       if (targetElement) {
         NotifyMouseOver(aMouseEvent, targetElement);
       }
     }
     break;
+  case NS_POINTER_LEAVE:
   case NS_MOUSE_EXIT:
     {
-      // This is actually the window mouse exit event. We're not moving
+      // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
-      if (mLastMouseOverFrame &&
+      OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
+      if (helper->mLastOverFrame &&
           nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
-          nsContentUtils::GetTopLevelWidget(mLastMouseOverFrame->GetNearestWidget())) {
-        // the MouseOut event widget doesn't have same top widget with
-        // mLastMouseOverFrame, it's a spurious event for mLastMouseOverFrame
+          nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
+        // the Mouse/PointerOut event widget doesn't have same top widget with
+        // mLastOverFrame, it's a spurious event for mLastOverFrame
         break;
       }
 
       // Reset sLastRefPoint, so that we'll know not to report any
       // movement the next time we re-enter the window.
       sLastRefPoint = kInvalidRefPoint;
 
       NotifyMouseOut(aMouseEvent, nullptr);
     }
     break;
   }
 
   // reset mCurretTargetContent to what it was
   mCurrentTargetContent = targetBeforeEvent;
 }
 
+OverOutElementsWrapper*
+nsEventStateManager::GetWrapperByEventID(WidgetMouseEvent* aEvent)
+{
+  WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
+  if (!pointer) {
+    MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr);
+    if (!mMouseEnterLeaveHelper) {
+      mMouseEnterLeaveHelper = new OverOutElementsWrapper();
+    }
+    return mMouseEnterLeaveHelper;
+  }
+  nsRefPtr<OverOutElementsWrapper> helper;
+  if (!mPointersEnterLeaveHelper.Get(pointer->pointerId, getter_AddRefs(helper))) {
+    helper = new OverOutElementsWrapper();
+    mPointersEnterLeaveHelper.Put(pointer->pointerId, helper);
+  }
+
+  return helper;
+}
+
 void
 nsEventStateManager::SetPointerLock(nsIWidget* aWidget,
                                     nsIContent* aElement)
 {
   // NOTE: aElement will be nullptr when unlocking.
   sIsPointerLocked = !!aElement;
 
   if (!aWidget) {
@@ -5041,16 +5129,30 @@ nsEventStateManager::SetContentState(nsI
         DoStateChange(notifyContent1, aState, content1StateSet);
       }
     }
   }
 
   return true;
 }
 
+PLDHashOperator
+nsEventStateManager::ResetLastOverForContent(const uint32_t& aIdx,
+                                             nsRefPtr<OverOutElementsWrapper>& aElemWrapper,
+                                             void* aClosure)
+{
+  nsIContent* content = static_cast<nsIContent*>(aClosure);
+  if (aElemWrapper && aElemWrapper->mLastOverElement &&
+      nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement, content)) {
+    aElemWrapper->mLastOverElement = nullptr;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
 void
 nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
 {
   /*
    * Anchor and area elements when focused or hovered might make the UI to show
    * the current link. We want to make sure that the UI gets informed when they
    * are actually removed from the DOM.
    */
@@ -5085,21 +5187,19 @@ nsEventStateManager::ContentRemoved(nsID
   }
 
   if (sDragOverContent &&
       sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
       nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) {
     sDragOverContent = nullptr;
   }
 
-  if (mLastMouseOverElement &&
-      nsContentUtils::ContentIsDescendantOf(mLastMouseOverElement, aContent)) {
-    // See bug 292146 for why we want to null this out
-    mLastMouseOverElement = nullptr;
-  }
+  // See bug 292146 for why we want to null this out
+  ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
+  mPointersEnterLeaveHelper.Enumerate(&nsEventStateManager::ResetLastOverForContent, aContent);
 }
 
 bool
 nsEventStateManager::EventStatusOK(WidgetGUIEvent* aEvent)
 {
   return !(aEvent->message == NS_MOUSE_BUTTON_DOWN &&
            aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
            !sNormalLMouseEventInProcess);
--- a/dom/events/nsEventStateManager.h
+++ b/dom/events/nsEventStateManager.h
@@ -20,27 +20,49 @@
 
 class nsFrameLoader;
 class nsIContent;
 class nsIDocument;
 class nsIDocShell;
 class nsIDocShellTreeItem;
 class imgIContainer;
 class nsDOMDataTransfer;
-class MouseEnterLeaveDispatcher;
+class EnterLeaveDispatcher;
 class nsIMarkupDocumentViewer;
 class nsIScrollableFrame;
 class nsITimer;
 
 namespace mozilla {
 namespace dom {
 class TabParent;
 }
 }
 
+class OverOutElementsWrapper MOZ_FINAL : public nsISupports
+{
+public:
+  OverOutElementsWrapper() : mLastOverFrame(nullptr) {}
+  ~OverOutElementsWrapper() {}
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(OverOutElementsWrapper)
+
+  nsWeakFrame mLastOverFrame;
+
+  nsCOMPtr<nsIContent> mLastOverElement;
+
+  // The last element on which we fired a over event, or null if
+  // the last over event we fired has finished processing.
+  nsCOMPtr<nsIContent> mFirstOverEventElement;
+
+  // The last element on which we fired a out event, or null if
+  // the last out event we fired has finished processing.
+  nsCOMPtr<nsIContent> mFirstOutEventElement;
+};
+
 /*
  * Event listener manager
  */
 
 class nsEventStateManager : public nsSupportsWeakReference,
                             public nsIObserver
 {
   friend class nsMouseWheelTransaction;
@@ -207,17 +229,17 @@ public:
   // frozen at the last mouse position while the pointer is locked.
   static mozilla::CSSIntPoint sLastClientPoint;
 
   static bool sIsPointerLocked;
   static nsWeakPtr sPointerLockedElement;
   static nsWeakPtr sPointerLockedDoc;
 
 protected:
-  friend class MouseEnterLeaveDispatcher;
+  friend class EnterLeaveDispatcher;
 
   /**
    * Prefs class capsules preference management.
    */
   class Prefs
   {
   public:
     static bool KeyCausesActivation() { return sKeyCausesActivation; }
@@ -245,24 +267,24 @@ protected:
    */
   static int32_t GetAccessModifierMaskFor(nsISupports* aDocShell);
 
   void UpdateCursor(nsPresContext* aPresContext,
                     mozilla::WidgetEvent* aEvent,
                     nsIFrame* aTargetFrame,
                     nsEventStatus* aStatus);
   /**
-   * Turn a GUI mouse event into a mouse event targeted at the specified
+   * Turn a GUI mouse/pointer event into a mouse/pointer event targeted at the specified
    * content.  This returns the primary frame for the content (or null
    * if it goes away during the event).
    */
-  nsIFrame* DispatchMouseEvent(mozilla::WidgetMouseEvent* aMouseEvent,
-                               uint32_t aMessage,
-                               nsIContent* aTargetContent,
-                               nsIContent* aRelatedContent);
+  nsIFrame* DispatchMouseOrPointerEvent(mozilla::WidgetMouseEvent* aMouseEvent,
+                                        uint32_t aMessage,
+                                        nsIContent* aTargetContent,
+                                        nsIContent* aRelatedContent);
   /**
    * Synthesize DOM and frame mouseover and mouseout events from this
    * MOUSE_MOVE or MOUSE_EXIT event.
    */
   void GenerateMouseEnterExit(mozilla::WidgetMouseEvent* aMouseEvent);
   /**
    * Tell this ESM and ESMs in parent documents that the mouse is
    * over some content in this document.
@@ -277,16 +299,24 @@ protected:
    *        the relatedTarget for mouseout events.  Also, if it's non-null
    *        NotifyMouseOut will NOT change the current hover content to null;
    *        in that case the caller is responsible for updating hover state.
    */
   void NotifyMouseOut(mozilla::WidgetMouseEvent* aMouseEvent,
                       nsIContent* aMovingInto);
   void GenerateDragDropEnterExit(nsPresContext* aPresContext,
                                  mozilla::WidgetDragEvent* aDragEvent);
+
+  /**
+   * Return mMouseEnterLeaveHelper or relevant mPointersEnterLeaveHelper elements wrapper.
+   * If mPointersEnterLeaveHelper does not contain wrapper for pointerId it create new one
+   */
+  OverOutElementsWrapper*
+  GetWrapperByEventID(mozilla::WidgetMouseEvent* aMouseEvent);
+
   /**
    * Fire the dragenter and dragexit/dragleave events when the mouse moves to a
    * new target.
    *
    * @param aRelatedTarget relatedTarget to set for the event
    * @param aTargetContent target to set for the event
    * @param aTargetFrame target frame for the event
    */
@@ -759,16 +789,19 @@ private:
   static inline void DoStateChange(mozilla::dom::Element* aElement,
                                    nsEventStates aState, bool aAddState);
   static inline void DoStateChange(nsIContent* aContent, nsEventStates aState,
                                    bool aAddState);
   static void UpdateAncestorState(nsIContent* aStartNode,
                                   nsIContent* aStopBefore,
                                   nsEventStates aState,
                                   bool aAddState);
+  static PLDHashOperator ResetLastOverForContent(const uint32_t& aIdx,
+                                                 nsRefPtr<OverOutElementsWrapper>& aChunk,
+                                                 void* aClosure);
 
   int32_t     mLockCursor;
 
   // Last mouse event refPoint (the offset from the widget's origin in
   // device pixels) when mouse was locked, used to restore mouse position
   // after unlocking.
   mozilla::LayoutDeviceIntPoint mPreLockPoint;
 
@@ -776,18 +809,16 @@ private:
   // to re-center the mouse when we were pointer locked. If this is (-1,-1) it
   // means we've not recently dispatched a centering event. We use this to
   // detect when we receive the synth event, so we can cancel and not send it
   // to content.
   static mozilla::LayoutDeviceIntPoint sSynthCenteringPoint;
 
   nsWeakFrame mCurrentTarget;
   nsCOMPtr<nsIContent> mCurrentTargetContent;
-  nsWeakFrame mLastMouseOverFrame;
-  nsCOMPtr<nsIContent> mLastMouseOverElement;
   static nsWeakFrame sLastDragOverFrame;
 
   // Stores the refPoint (the offset from the widget's origin in device
   // pixels) of the last mouse event.
   static mozilla::LayoutDeviceIntPoint sLastRefPoint;
 
   // member variables for the d&d gesture state machine
   mozilla::LayoutDeviceIntPoint mGestureDownPoint; // screen coordinates
@@ -808,36 +839,31 @@ private:
   nsCOMPtr<nsIContent> mLastRightMouseDownContent;
   nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
 
   nsCOMPtr<nsIContent> mActiveContent;
   nsCOMPtr<nsIContent> mHoverContent;
   static nsCOMPtr<nsIContent> sDragOverContent;
   nsCOMPtr<nsIContent> mURLTargetContent;
 
-  // The last element on which we fired a mouseover event, or null if
-  // the last mouseover event we fired has finished processing.
-  nsCOMPtr<nsIContent> mFirstMouseOverEventElement;
-
-  // The last element on which we fired a mouseout event, or null if
-  // the last mouseout event we fired has finished processing.
-  nsCOMPtr<nsIContent> mFirstMouseOutEventElement;
-
   nsPresContext* mPresContext;      // Not refcnted
   nsCOMPtr<nsIDocument> mDocument;   // Doesn't necessarily need to be owner
 
   uint32_t mLClickCount;
   uint32_t mMClickCount;
   uint32_t mRClickCount;
 
   bool m_haveShutdown;
 
   // Time at which we began handling user input.
   static TimeStamp sHandlingInputStart;
 
+  nsRefPtr<OverOutElementsWrapper> mMouseEnterLeaveHelper;
+  nsRefPtrHashtable<nsUint32HashKey, OverOutElementsWrapper> mPointersEnterLeaveHelper;
+
 public:
   static nsresult UpdateUserActivityTimer(void);
   // Array for accesskey support
   nsCOMArray<nsIContent> mAccessKeys;
 
   static int32_t sUserInputEventDepth;
   
   static bool sNormalLMouseEventInProcess;
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -81,16 +81,17 @@ skip-if = true # Disabled due to timeout
 [test_bug741666.html]
 [test_bug742376.html]
 [test_bug812744.html]
 [test_bug847597.html]
 [test_bug855741.html]
 [test_bug864040.html]
 [test_bug930374-content.html]
 [test_bug944847.html]
+[test_bug967796.html]
 skip-if = toolkit == "gonk"
 [test_bug944011.html]
 [test_bug946632.html]
 [test_clickevent_on_input.html]
 [test_continuous_wheel_events.html]
 [test_dblclick_explicit_original_target.html]
 [test_dom_keyboard_event.html]
 [test_dom_mouse_event.html]
copy from dom/events/test/test_bug432698.html
copy to dom/events/test/test_bug967796.html
--- a/dom/events/test/test_bug432698.html
+++ b/dom/events/test/test_bug967796.html
@@ -1,203 +1,208 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=432698
+https://bugzilla.mozilla.org/show_bug.cgi?id=967796
 -->
 <head>
-  <title>Test for Bug 432698</title>
+  <title>Test for Bug 967796</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=432698">Mozilla Bug 432698</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=967796">Mozilla Bug 967796</a>
 <p id="display"></p>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-/** Test for Bug 432698 **/
+/** Test for Bug 967796 **/
+
+SpecialPowers.setBoolPref("dom.w3c_pointer_events.enabled", true);      // Enable Pointer Events
+
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests);
 var outer;
 var middle;
 var inner;
 var outside;
 var container;
 var file;
 var iframe;
 var checkRelatedTarget = false;
 var expectedRelatedEnter = null;
 var expectedRelatedLeave = null;
-var mouseentercount = 0;
-var mouseleavecount = 0;
-var mouseovercount = 0;
-var mouseoutcount = 0;
+var pointerentercount = 0;
+var pointerleavecount = 0;
+var pointerovercount = 0;
+var pointeroutcount = 0;
 
-function sendMouseEvent(t, elem) {
+function sendPointerEvent(t, elem) {
   var r = elem.getBoundingClientRect();
-  synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+  synthesizePointer(elem, r.width / 2, r.height / 2, {type: t});
 }
 
-var expectedMouseEnterTargets = [];
-var expectedMouseLeaveTargets = [];
+var expectedPointerEnterTargets = [];
+var expectedPointerLeaveTargets = [];
 
 function runTests() {
   outer = document.getElementById("outertest");
   middle = document.getElementById("middletest");
   inner = document.getElementById("innertest");
   outside = document.getElementById("outside");
   container = document.getElementById("container");
   file = document.getElementById("file");
   iframe = document.getElementById("iframe");
 
-  // Make sure ESM thinks mouse is outside the test elements.
-  sendMouseEvent("mousemove", outside);
+  // Make sure ESM thinks pointer is outside the test elements.
+  sendPointerEvent("pointermove", outside);
 
-  mouseentercount = 0;
-  mouseleavecount = 0;
-  mouseovercount = 0;
-  mouseoutcount = 0;
+  pointerentercount = 0;
+  pointerleavecount = 0;
+  pointerovercount = 0;
+  pointeroutcount = 0;
   checkRelatedTarget = true;
   expectedRelatedEnter = outside;
   expectedRelatedLeave = inner;
-  expectedMouseEnterTargets = ["outertest", "middletest", "innertest"];
-  sendMouseEvent("mousemove", inner);
-  is(mouseentercount, 3, "Unexpected mouseenter event count!");
-  is(mouseovercount, 1, "Unexpected mouseover event count!");
-  is(mouseoutcount, 0, "Unexpected mouseout event count!");
-  is(mouseleavecount, 0, "Unexpected mouseleave event count!");
+  expectedPointerEnterTargets = ["outertest", "middletest", "innertest"];
+  sendPointerEvent("pointermove", inner);
+  is(pointerentercount, 3, "Unexpected pointerenter event count!");
+  is(pointerovercount, 1, "Unexpected pointerover event count!");
+  is(pointeroutcount, 0, "Unexpected pointerout event count!");
+  is(pointerleavecount, 0, "Unexpected pointerleave event count!");
   expectedRelatedEnter = inner;
   expectedRelatedLeave = outside;
-  expectedMouseLeaveTargets = ["innertest", "middletest", "outertest"];
-  sendMouseEvent("mousemove", outside);
-  is(mouseentercount, 3, "Unexpected mouseenter event count!");
-  is(mouseovercount, 1, "Unexpected mouseover event count!");
-  is(mouseoutcount, 1, "Unexpected mouseout event count!");
-  is(mouseleavecount, 3, "Unexpected mouseleave event count!");
+  expectedPointerLeaveTargets = ["innertest", "middletest", "outertest"];
+  sendPointerEvent("pointermove", outside);
+  is(pointerentercount, 3, "Unexpected pointerenter event count!");
+  is(pointerovercount, 1, "Unexpected pointerover event count!");
+  is(pointeroutcount, 1, "Unexpected pointerout event count!");
+  is(pointerleavecount, 3, "Unexpected pointerleave event count!");
 
   // Event handling over native anonymous content.
   var r = file.getBoundingClientRect();
   expectedRelatedEnter = outside;
   expectedRelatedLeave = file;
-  synthesizeMouse(file, r.width / 6, r.height / 2, {type: "mousemove"});
-  is(mouseentercount, 4, "Unexpected mouseenter event count!");
-  is(mouseovercount, 2, "Unexpected mouseover event count!");
-  is(mouseoutcount, 1, "Unexpected mouseout event count!");
-  is(mouseleavecount, 3, "Unexpected mouseleave event count!");
+  synthesizePointer(file, r.width / 6, r.height / 2, {type: "pointermove"});
+  is(pointerentercount, 4, "Unexpected pointerenter event count!");
+  is(pointerovercount, 2, "Unexpected pointerover event count!");
+  is(pointeroutcount, 1, "Unexpected pointerout event count!");
+  is(pointerleavecount, 3, "Unexpected pointerleave event count!");
 
-  // Moving mouse over type="file" shouldn't cause mouseover/out/enter/leave events
-  synthesizeMouse(file, r.width - (r.width / 6), r.height / 2, {type: "mousemove"});
-  is(mouseentercount, 4, "Unexpected mouseenter event count!");
-  is(mouseovercount, 2, "Unexpected mouseover event count!");
-  is(mouseoutcount, 1, "Unexpected mouseout event count!");
-  is(mouseleavecount, 3, "Unexpected mouseleave event count!");
+  // Moving pointer over type="file" shouldn't cause pointerover/out/enter/leave events
+  synthesizePointer(file, r.width - (r.width / 6), r.height / 2, {type: "pointermove"});
+  is(pointerentercount, 4, "Unexpected pointerenter event count!");
+  is(pointerovercount, 2, "Unexpected pointerover event count!");
+  is(pointeroutcount, 1, "Unexpected pointerout event count!");
+  is(pointerleavecount, 3, "Unexpected pointerleave event count!");
 
   expectedRelatedEnter = file;
   expectedRelatedLeave = outside;
-  sendMouseEvent("mousemove", outside);
-  is(mouseentercount, 4, "Unexpected mouseenter event count!");
-  is(mouseovercount, 2, "Unexpected mouseover event count!");
-  is(mouseoutcount, 2, "Unexpected mouseout event count!");
-  is(mouseleavecount, 4, "Unexpected mouseleave event count!");
-  
+  sendPointerEvent("pointermove", outside);
+  is(pointerentercount, 4, "Unexpected pointerenter event count!");
+  is(pointerovercount, 2, "Unexpected pointerover event count!");
+  is(pointeroutcount, 2, "Unexpected pointerout event count!");
+  is(pointerleavecount, 4, "Unexpected pointerleave event count!");
+
   // Initialize iframe
   iframe.contentDocument.documentElement.style.overflow = "hidden";
   iframe.contentDocument.body.style.margin = "0px";
   iframe.contentDocument.body.style.width = "100%";
   iframe.contentDocument.body.style.height = "100%";
   iframe.contentDocument.body.innerHTML =
     "<div style='width: 100%; height: 50%; border: 1px solid black;'></div>" +
     "<div style='width: 100%; height: 50%; border: 1px solid black;'></div>";
   iframe.contentDocument.body.offsetLeft; // flush
 
-  iframe.contentDocument.body.firstChild.onmouseenter = menter;
-  iframe.contentDocument.body.firstChild.onmouseleave = mleave;
-  iframe.contentDocument.body.lastChild.onmouseenter = menter;
-  iframe.contentDocument.body.lastChild.onmouseleave = mleave;
+  iframe.contentDocument.body.firstChild.onpointerenter = penter;
+  iframe.contentDocument.body.firstChild.onpointerleave = pleave;
+  iframe.contentDocument.body.lastChild.onpointerenter = penter;
+  iframe.contentDocument.body.lastChild.onpointerleave = pleave;
   r = iframe.getBoundingClientRect();
   expectedRelatedEnter = outside;
   expectedRelatedLeave = iframe;
-  // Move mouse inside the iframe.
-  synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height / 4, {type: "mousemove"},
-                  iframe.contentWindow);
-  synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height - (r.height / 4), {type: "mousemove"},
-                  iframe.contentWindow);
-  is(mouseentercount, 7, "Unexpected mouseenter event count!");
+  // Move pointer inside the iframe.
+  synthesizePointer(iframe.contentDocument.body, r.width / 2, r.height / 4, {type: "pointermove"},
+                    iframe.contentWindow);
+  synthesizePointer(iframe.contentDocument.body, r.width / 2, r.height - (r.height / 4), {type: "pointermove"},
+                    iframe.contentWindow);
+  is(pointerentercount, 7, "Unexpected pointerenter event count!");
   expectedRelatedEnter = iframe;
   expectedRelatedLeave = outside;
-  sendMouseEvent("mousemove", outside);
-  is(mouseleavecount, 7, "Unexpected mouseleave event count!");
+  sendPointerEvent("pointermove", outside);
+  is(pointerleavecount, 7, "Unexpected pointerleave event count!");
+
+  SpecialPowers.clearUserPref("dom.w3c_pointer_events.enabled");      // Disable Pointer Events
 
   SimpleTest.finish();
 }
 
-function menter(evt) {
-  ++mouseentercount;
+function penter(evt) {
+  ++pointerentercount;
   evt.stopPropagation();
-  if (expectedMouseEnterTargets.length) {
-    var t = expectedMouseEnterTargets.shift();
+  if (expectedPointerEnterTargets.length) {
+    var t = expectedPointerEnterTargets.shift();
     is(evt.target.id, t, "Wrong event target!");
   }
   is(evt.bubbles, false, evt.type + " should not bubble!");
-  is(evt.cancelable, false, evt.type + " is not cancelable!");
+  is(evt.cancelable, true, evt.type + " is cancelable!");
   is(evt.target, evt.currentTarget, "Wrong event target!");
   ok(!evt.relatedTarget || evt.target.ownerDocument == evt.relatedTarget.ownerDocument,
      "Leaking nodes to another document?");
   if (checkRelatedTarget && evt.target.ownerDocument == document) {
-    is(evt.relatedTarget, expectedRelatedEnter, "Wrong related target (mouseenter)");
+    is(evt.relatedTarget, expectedRelatedEnter, "Wrong related target (pointerenter)");
   }
 }
 
-function mleave(evt) {
-  ++mouseleavecount;
+function pleave(evt) {
+  ++pointerleavecount;
   evt.stopPropagation();
-  if (expectedMouseLeaveTargets.length) {
-    var t = expectedMouseLeaveTargets.shift();
+  if (expectedPointerLeaveTargets.length) {
+    var t = expectedPointerLeaveTargets.shift();
     is(evt.target.id, t, "Wrong event target!");
   }
   is(evt.bubbles, false, evt.type + " should not bubble!");
-  is(evt.cancelable, false, evt.type + " is not cancelable!");
+  is(evt.cancelable, true, evt.type + " is cancelable!");
   is(evt.target, evt.currentTarget, "Wrong event target!");
   ok(!evt.relatedTarget || evt.target.ownerDocument == evt.relatedTarget.ownerDocument,
      "Leaking nodes to another document?");
   if (checkRelatedTarget && evt.target.ownerDocument == document) {
-    is(evt.relatedTarget, expectedRelatedLeave, "Wrong related target (mouseleave)");
+    is(evt.relatedTarget, expectedRelatedLeave, "Wrong related target (pointerleave)");
   }
 }
 
-function mover(evt) {
-  ++mouseovercount;
+function pover(evt) {
+  ++pointerovercount;
   evt.stopPropagation();
 }
 
-function mout(evt) {
-  ++mouseoutcount;
+function pout(evt) {
+  ++pointeroutcount;
   evt.stopPropagation();
 }
 
 </script>
 </pre>
-<div id="container" onmouseenter="menter(event)" onmouseleave="mleave(event)"
-                    onmouseout="mout(event)" onmouseover="mover(event)">
-  <div id="outside" onmouseout="event.stopPropagation()" onmouseover="event.stopPropagation()">foo</div>
-  <div id="outertest" onmouseenter="menter(event)" onmouseleave="mleave(event)"
-                      onmouseout="mout(event)" onmouseover="mover(event)">
-    <div id="middletest" onmouseenter="menter(event)" onmouseleave="mleave(event)"
-                         onmouseout="mout(event)" onmouseover="mover(event)">
-      <div id="innertest" onmouseenter="menter(event)" onmouseleave="mleave(event)"
-                          onmouseout="mout(event)" onmouseover="mover(event)">foo</div>
+<div id="container" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+                    onpointerout="pout(event)" onpointerover="pover(event)">
+  <div id="outside" onpointerout="event.stopPropagation()" onpointerover="event.stopPropagation()">foo</div>
+  <div id="outertest" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+                      onpointerout="pout(event)" onpointerover="pover(event)">
+    <div id="middletest" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+                         onpointerout="pout(event)" onpointerover="pover(event)">
+      <div id="innertest" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+                          onpointerout="pout(event)" onpointerover="pover(event)">foo</div>
     </div>
   </div>
   <input type="file" id="file"
-         onmouseenter="menter(event)" onmouseleave="mleave(event)"
-         onmouseout="mout(event)" onmouseover="mover(event)">
+         onpointerenter="penter(event)" onpointerleave="pleave(event)"
+         onpointerout="pout(event)" onpointerover="pover(event)">
   <br>
   <iframe id="iframe" width="50px" height="50px"
-          onmouseenter="menter(event)" onmouseleave="mleave(event)"
-          onmouseout="mout(event)" onmouseover="mover(event)"></iframe>
+          onpointerenter="penter(event)" onpointerleave="pleave(event)"
+          onpointerout="pout(event)" onpointerover="pover(event)"></iframe>
 </div>
 </body>
 </html>
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -38,17 +38,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 
-[scriptable, uuid(fa0fe174-7c07-11e3-a5ba-000c290c393e)]
+[scriptable, uuid(ce671a4a-92bb-11e3-b2d0-2c27d728e7f9)]
 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.
@@ -262,16 +262,82 @@ interface nsIDOMWindowUtils : nsISupport
                          in long aButton,
                          in long aClickCount,
                          in long aModifiers,
                          [optional] in boolean aIgnoreRootScrollFrame,
                          [optional] in float aPressure,
                          [optional] in unsigned short aInputSourceArg,
                          [optional] in boolean aIsSynthesized);
 
+
+  /** Synthesize a pointer event. The event types supported are:
+   *    pointerdown, pointerup, pointermove, pointerover, pointerout
+   *
+   * Events are sent in coordinates offset by aX and aY from the window.
+   *
+   * Note that additional events may be fired as a result of this call. For
+   * instance, typically a click event will be fired as a result of a
+   * mousedown and mouseup in sequence.
+   *
+   * Normally at this level of events, the pointerover and pointerout events are
+   * only fired when the window is entered or exited. For inter-element
+   * pointerover and pointerout events, a movemove event fired on the new element
+   * should be sufficient to generate the correct over and out events as well.
+   *
+   * Cannot be accessed from unprivileged context (not content-accessible)
+   * Will throw a DOM security error if called without chrome privileges.
+   *
+   * The event is dispatched via the toplevel window, so it could go to any
+   * window under the toplevel window, in some cases it could never reach this
+   * window at all.
+   *
+   * @param aType event type
+   * @param aX x offset in CSS pixels
+   * @param aY y offset in CSS pixels
+   * @param aButton button to synthesize
+   * @param aClickCount number of clicks that have been performed
+   * @param aModifiers modifiers pressed, using constants defined as MODIFIER_*
+   * @param aIgnoreRootScrollFrame whether the event should ignore viewport bounds
+   *                           during dispatch
+   * @param aPressure touch input pressure: 0.0 -> 1.0
+   * @param aInputSourceArg input source, see nsIDOMMouseEvent for values,
+   *        defaults to mouse input.
+   * @param aPointerId A unique identifier for the pointer causing the event. default is 0
+   * @param aWidth The width (magnitude on the X axis), default is 0
+   * @param aHeight The height (magnitude on the Y axis), default is 0
+   * @param aTilt The plane angle between the Y-Z plane
+   *        and the plane containing both the transducer (e.g. pen stylus) axis and the Y axis. default is 0
+   * @param aTiltX The plane angle between the X-Z plane
+   *        and the plane containing both the transducer (e.g. pen stylus) axis and the X axis. default is 0
+   * @param aIsPrimary  Indicates if the pointer represents the primary pointer of this pointer type.
+   * @param aIsSynthesized controls nsIDOMEvent.isSynthesized value
+   *                       that helps identifying test related events,
+   *                       defaults to true
+   *
+   * returns true if the page called prevent default on this event
+   */
+
+  [optional_argc]
+  boolean sendPointerEvent(in AString aType,
+                           in float aX,
+                           in float aY,
+                           in long aButton,
+                           in long aClickCount,
+                           in long aModifiers,
+                           [optional] in boolean aIgnoreRootScrollFrame,
+                           [optional] in float aPressure,
+                           [optional] in unsigned short aInputSourceArg,
+                           [optional] in long aPointerId,
+                           [optional] in long aWidth,
+                           [optional] in long aHeight,
+                           [optional] in long tiltX,
+                           [optional] in long tiltY,
+                           [optional] in boolean aIsPrimary,
+                           [optional] in boolean aIsSynthesized);
+
   /** Synthesize a touch event. The event types supported are:
    *    touchstart, touchend, touchmove, and touchcancel
    *
    * Events are sent in coordinates offset by aX and aY from the window.
    *
    * Cannot be accessed from unprivileged context (not content-accessible)
    * Will throw a DOM security error if called without chrome privileges.
    *
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1042,16 +1042,17 @@ ContentParent::ActorDestroy(ActorDestroy
         obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-gc-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-cc-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-mmu-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "last-pb-context-exited");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "file-watcher-update");
 #ifdef MOZ_WIDGET_GONK
         obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_VOLUME_STATE_CHANGED);
+        obs->RemoveObserver(static_cast<nsIObserver*>(this), "phone-state-changed");
 #endif
 #ifdef ACCESSIBILITY
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "a11y-init-or-shutdown");
 #endif
     }
 
     if (ppm) {
       ppm->Disconnect();
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -654,18 +654,17 @@ doInvoke(NPObject *npobj, NPIdentifier m
     JSObject *newObj =
       ::JS_New(cx, npjsobj->mJSObj, jsargs.length(), jsargs.begin());
 
     if (newObj) {
       v.setObject(*newObj);
       ok = true;
     }
   } else {
-    ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, jsargs.length(),
-                                jsargs.begin(), v.address());
+    ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, jsargs, v.address());
   }
 
   if (ok)
     ok = JSValToNPVariant(npp, cx, v, result);
 
   return ok;
 }
 
@@ -1601,17 +1600,17 @@ NPObjWrapper_Convert(JSContext *cx, JS::
   // methods, none of which are nullary, so the JS-reflected method will behave
   // poorly when called with no arguments.  We work around this problem by
   // giving plugins a [[DefaultValue]] which uses only toString and not valueOf.
 
   JS::Rooted<JS::Value> v(cx, JSVAL_VOID);
   if (!JS_GetProperty(cx, obj, "toString", &v))
     return false;
   if (!JSVAL_IS_PRIMITIVE(v) && JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(v))) {
-    if (!JS_CallFunctionValue(cx, obj, v, 0, nullptr, vp.address()))
+    if (!JS_CallFunctionValue(cx, obj, v, JS::EmptyValueArray, vp.address()))
       return false;
     if (JSVAL_IS_PRIMITIVE(vp))
       return true;
   }
 
   JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
                        JS_GetClass(obj)->name,
                        hint == JSTYPE_VOID
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -557,17 +557,17 @@ nsNPAPIPluginInstance::Start()
 }
 
 nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
 {
   // NPAPI plugins don't want a SetWindow(nullptr).
   if (!window || RUNNING != mRunning)
     return NS_OK;
 
-#if (MOZ_WIDGET_GTK == 2)
+#if MOZ_WIDGET_GTK
   // bug 108347, flash plugin on linux doesn't like window->width <=
   // 0, but Java needs wants this call.
   if (!nsPluginHost::IsJavaMIMEType(mMIMEType) && window->type == NPWindowTypeWindow &&
       (window->width <= 0 || window->height <= 0)) {
     return NS_OK;
   }
 #endif
 
--- a/dom/plugins/test/testplugin/testplugin.mk
+++ b/dom/plugins/test/testplugin/testplugin.mk
@@ -1,31 +1,27 @@
 #
 # 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/.
 
 # Don't use STL wrappers; nptest isn't Gecko code
 STL_FLAGS =
 
-# must link statically with the CRT; nptest isn't Gecko code
-USE_STATIC_LIBS = 1
-
 ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
 include $(topsrcdir)/config/config.mk
 CXXFLAGS        += $(MOZ_QT_CFLAGS)
 CFLAGS          += $(MOZ_QT_CFLAGS)
 EXTRA_DSO_LDOPTS = \
                 $(MOZ_QT_LIBS) \
                 $(XLDFLAGS) \
                 $(XLIBS)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-DEFFILE   = $(win_srcdir)/nptest.def
 OS_LIBS  += $(call EXPAND_LIBNAME,msimg32)
 
 # Windows opt builds without PGO break nptest.dll
 MOZ_OPTIMIZE=
 endif
 
 TEST_PLUGIN_FILES = $(SHARED_LIBRARY)
 
--- a/dom/plugins/test/testplugin/testplugin.mozbuild
+++ b/dom/plugins/test/testplugin/testplugin.mozbuild
@@ -34,11 +34,15 @@ elif toolkit == 'qt':
     ]
 elif toolkit == 'windows':
     UNIFIED_SOURCES += [
         relative_path + '/nptest_windows.cpp',
     ]
 
 FORCE_SHARED_LIB = True
 
+# must link statically with the CRT; nptest isn't Gecko code
+USE_STATIC_LIBS = True
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     RCFILE  = 'nptest.rc'
     RESFILE = 'nptest.res'
+    DEFFILE = SRCDIR + '/nptest.def'
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -215,17 +215,17 @@ nsJSON::EncodeInternal(JSContext* cx, co
    * perfectly fine for GetMethod to fail
    */
   JS::Rooted<JS::Value> val(cx, aValue);
   JS::Rooted<JS::Value> toJSON(cx);
   if (JS_GetProperty(cx, obj, "toJSON", &toJSON) &&
       toJSON.isObject() &&
       JS_ObjectIsCallable(cx, &toJSON.toObject())) {
     // If toJSON is implemented, it must not throw
-    if (!JS_CallFunctionValue(cx, obj, toJSON, 0, nullptr, val.address())) {
+    if (!JS_CallFunctionValue(cx, obj, toJSON, JS::EmptyValueArray, val.address())) {
       if (JS_IsExceptionPending(cx))
         // passing NS_OK will throw the pending exception
         return NS_OK;
 
       // No exception, but still failed
       return NS_ERROR_FAILURE;
     }
 
--- a/dom/workers/Console.cpp
+++ b/dom/workers/Console.cpp
@@ -316,28 +316,23 @@ private:
         if (!JS_DefineElement(cx, stackObj, i, value, nullptr, nullptr, 0)) {
           return;
         }
       }
 
       stackValue = JS::ObjectValue(*stackObj);
     }
 
-    JS::AutoValueVector argv(cx);
-    if (!argv.resize(3)) {
-      return;
-    }
-
-    argv[0] = methodValue;
-    argv[1] = argumentsValue;
-    argv[2] = stackValue;
+    JS::AutoValueArray<3> args(cx);
+    args[0].set(methodValue);
+    args[1].set(argumentsValue);
+    args[2].set(stackValue);
 
     JS::Rooted<JS::Value> ret(cx);
-    JS_CallFunctionName(cx, consoleObj, "queueCall", argv.length(),
-                        argv.begin(), ret.address());
+    JS_CallFunctionName(cx, consoleObj, "queueCall", args, ret.address());
   }
 
   WorkerConsole* mConsole;
   WorkerPrivate* mWorkerPrivate;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
 
   const char* mMethod;
   JSAutoStructuredCloneBuffer mArguments;
@@ -487,24 +482,26 @@ METHOD(Warn, "warn")
 METHOD(Error, "error")
 METHOD(Exception, "exception")
 METHOD(Debug, "debug")
 
 void
 WorkerConsole::Trace(JSContext* aCx)
 {
   Sequence<JS::Value> data;
+  SequenceRooter<JS::Value> rooter(aCx, &data);
   Method(aCx, "trace", data, DEFAULT_MAX_STACKTRACE_DEPTH);
 }
 
 void
 WorkerConsole::Dir(JSContext* aCx,
                    const Optional<JS::Handle<JS::Value>>& aValue)
 {
   Sequence<JS::Value> data;
+  SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (aValue.WasPassed()) {
     data.AppendElement(aValue.Value());
   }
 
   Method(aCx, "dir", data, 1);
 }
 
@@ -512,29 +509,31 @@ METHOD(Group, "group")
 METHOD(GroupCollapsed, "groupCollapsed")
 METHOD(GroupEnd, "groupEnd")
 
 void
 WorkerConsole::Time(JSContext* aCx,
                     const Optional<JS::Handle<JS::Value>>& aTimer)
 {
   Sequence<JS::Value> data;
+  SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (aTimer.WasPassed()) {
     data.AppendElement(aTimer.Value());
   }
 
   Method(aCx, "time", data, 1);
 }
 
 void
 WorkerConsole::TimeEnd(JSContext* aCx,
                        const Optional<JS::Handle<JS::Value>>& aTimer)
 {
   Sequence<JS::Value> data;
+  SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (aTimer.WasPassed()) {
     data.AppendElement(aTimer.Value());
   }
 
   Method(aCx, "timeEnd", data, 1);
 }
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5383,20 +5383,20 @@ WorkerPrivate::RunExpiredTimeouts(JSCont
     // break out of the loop.
 
     if (!info->mTimeoutCallable.isUndefined()) {
       JS::Rooted<JS::Value> rval(aCx);
       /*
        * unsafeGet() is needed below because the argument is a not a const
        * pointer, even though values are not modified.
        */
-      if (!JS_CallFunctionValue(aCx, global, info->mTimeoutCallable,
-                                info->mExtraArgVals.Length(),
-                                info->mExtraArgVals.Elements()->unsafeGet(),
-                                rval.address()) &&
+      JS::HandleValueArray args =
+        JS::HandleValueArray::fromMarkedLocation(info->mExtraArgVals.Length(),
+                                                 info->mExtraArgVals.Elements()->unsafeGet());
+      if (!JS_CallFunctionValue(aCx, global, info->mTimeoutCallable, args, rval.address()) &&
           !JS_ReportPendingException(aCx)) {
         retval = false;
         break;
       }
     }
     else {
       nsString expression = info->mTimeoutString;
 
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -330,17 +330,17 @@ nsXBLProtoImplAnonymousMethod::Execute(n
   // Check whether script is enabled.
   bool scriptAllowed = nsContentUtils::GetSecurityManager()->
                          ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
 
   bool ok = true;
   if (scriptAllowed) {
     JS::Rooted<JS::Value> retval(cx);
     ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method),
-                                0 /* argc */, nullptr /* argv */, retval.address());
+                                JS::EmptyValueArray, retval.address());
   }
 
   if (!ok) {
     // If a constructor or destructor threw an exception, it doesn't stop
     // anything else.  We just report it.  Note that we need to set aside the
     // frame chain here, since the constructor invocation is not related to
     // whatever is on the stack right now, really.
     nsJSUtils::ReportPendingException(cx);
deleted file mode 100644
--- a/editor/composer/src/Makefile.in
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# 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 $(topsrcdir)/config/rules.mk
-
-_FILES = \
-	$(srcdir)/res/EditorOverride.css \
-	$(srcdir)/res/grabber.gif \
-	$(srcdir)/res/table-add-column-after-active.gif \
-	$(srcdir)/res/table-add-column-after-hover.gif \
-	$(srcdir)/res/table-add-column-after.gif \
-	$(srcdir)/res/table-add-column-before-active.gif \
-	$(srcdir)/res/table-add-column-before-hover.gif \
-	$(srcdir)/res/table-add-column-before.gif \
-	$(srcdir)/res/table-add-row-after-active.gif \
-	$(srcdir)/res/table-add-row-after-hover.gif \
-	$(srcdir)/res/table-add-row-after.gif \
-	$(srcdir)/res/table-add-row-before-active.gif \
-	$(srcdir)/res/table-add-row-before-hover.gif \
-	$(srcdir)/res/table-add-row-before.gif \
-	$(srcdir)/res/table-remove-column-active.gif \
-	$(srcdir)/res/table-remove-column-hover.gif \
-	$(srcdir)/res/table-remove-column.gif \
-	$(srcdir)/res/table-remove-row-active.gif \
-	$(srcdir)/res/table-remove-row-hover.gif \
-	$(srcdir)/res/table-remove-row.gif \
-	$(NULL)
-
-libs::
-	$(INSTALL) $(_FILES) $(DIST)/bin/res
--- a/editor/composer/src/moz.build
+++ b/editor/composer/src/moz.build
@@ -13,8 +13,30 @@ UNIFIED_SOURCES += [
     'nsComposeTxtSrvFilter.cpp',
     'nsEditingSession.cpp',
     'nsEditorSpellCheck.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'
+RESOURCE_FILES += [
+    'res/EditorOverride.css',
+    'res/grabber.gif',
+    'res/table-add-column-after-active.gif',
+    'res/table-add-column-after-hover.gif',
+    'res/table-add-column-after.gif',
+    'res/table-add-column-before-active.gif',
+    'res/table-add-column-before-hover.gif',
+    'res/table-add-column-before.gif',
+    'res/table-add-row-after-active.gif',
+    'res/table-add-row-after-hover.gif',
+    'res/table-add-row-after.gif',
+    'res/table-add-row-before-active.gif',
+    'res/table-add-row-before-hover.gif',
+    'res/table-add-row-before.gif',
+    'res/table-remove-column-active.gif',
+    'res/table-remove-column-hover.gif',
+    'res/table-remove-column.gif',
+    'res/table-remove-row-active.gif',
+    'res/table-remove-row-hover.gif',
+    'res/table-remove-row.gif',
+]
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -32,17 +32,17 @@ class ScaledFontDWrite;
 
 const int32_t kLayerCacheSize = 5;
 
 struct PrivateD3D10DataD2D
 {
   RefPtr<ID3D10Effect> mEffect;
   RefPtr<ID3D10InputLayout> mInputLayout;
   RefPtr<ID3D10Buffer> mVB;
-  RefPtr<ID3D10BlendState> mBlendStates[CompositionOp::OP_COUNT];
+  RefPtr<ID3D10BlendState> mBlendStates[size_t(CompositionOp::OP_COUNT)];
 };
 
 class DrawTargetD2D : public DrawTarget
 {
 public:
   DrawTargetD2D();
   virtual ~DrawTargetD2D();
 
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -25,17 +25,17 @@ D2D1_COLORMATRIX_ALPHA_MODE D2DAlphaMode
     return D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT;
   default:
     MOZ_CRASH("Unknown enum value!");
   }
 
   return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED;
 }
 
-D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE D2DAffineTransformInterpolationMode(uint32_t aFilter)
+D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE D2DAffineTransformInterpolationMode(Filter aFilter)
 {
   switch (aFilter) {
   case Filter::GOOD:
     return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
   case Filter::LINEAR:
     return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
   case Filter::POINT:
     return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
@@ -158,17 +158,17 @@ uint32_t ConvertValue(FilterType aType, 
   switch (aType) {
   case FilterType::COLOR_MATRIX:
     if (aAttribute == ATT_COLOR_MATRIX_ALPHA_MODE) {
       aValue = D2DAlphaMode(aValue);
     }
     break;
   case FilterType::TRANSFORM:
     if (aAttribute == ATT_TRANSFORM_FILTER) {
-      aValue = D2DAffineTransformInterpolationMode(aValue);
+      aValue = D2DAffineTransformInterpolationMode(Filter(aValue));
     }
     break;
   case FilterType::BLEND:
     if (aAttribute == ATT_BLEND_BLENDMODE) {
       aValue = D2DBlendMode(aValue);
     }
     break;
   case FilterType::MORPHOLOGY:
--- a/gfx/angle/src/libEGL/Makefile.in
+++ b/gfx/angle/src/libEGL/Makefile.in
@@ -8,17 +8,16 @@ STL_FLAGS =
 ifndef GNU_CC
 # Enable unwind semantics for exception handlers in response to warning C4530.
 OS_CPPFLAGS += -EHsc
 endif
 
 # Below is a transcription of the EGL target from build_angle.gypi.
 # Target: 'libEGL'
 #   Links with: 'libGLESv2'
-DEFFILE = $(srcdir)/libEGL.def
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
 
 #OS_LIBS += $(call EXPAND_LIBNAME,dwmapi)
 
 ifdef GNU_CC
--- a/gfx/angle/src/libEGL/moz.build
+++ b/gfx/angle/src/libEGL/moz.build
@@ -39,8 +39,9 @@ for var in ('LIBEGL_EXPORTS', 'ANGLE_BUI
     DEFINES[var] = True
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
 
 RCFILE = SRCDIR + '/libEGL.rc'
+DEFFILE = SRCDIR + '/libEGL.def'
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -5,18 +5,16 @@
 # ANGLE uses the STL, so we can't use our derpy STL wrappers.
 STL_FLAGS =
 
 ifndef GNU_CC
 # Enable unwind semantics for exception handlers in response to warning C4530.
 OS_CPPFLAGS += -EHsc
 endif
 
-DEFFILE = $(srcdir)/libGLESv2.def
-
 # End build_angle.gypi transcription.
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
 
 ifdef GNU_CC
 
--- a/gfx/angle/src/libGLESv2/moz.build
+++ b/gfx/angle/src/libGLESv2/moz.build
@@ -190,8 +190,9 @@ for var in ('LIBGLESV2_EXPORTS', 'ANGLE_
     DEFINES[var] = True
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
 
 RCFILE = SRCDIR + '/libGLESv2.rc'
+DEFFILE = SRCDIR + '/libGLESv2.def'
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -403,23 +403,16 @@ public:
   }
   void SetCompositorID(uint32_t aID)
   {
     MOZ_ASSERT(mCompositorID == 0, "The compositor ID must be set only once.");
     mCompositorID = aID;
   }
 
   /**
-   * Notify the compositor that a layers transaction has occured. This is only
-   * used for FPS information at the moment.
-   * XXX: surely there is a better way to do this?
-   */
-  virtual void NotifyLayersTransaction() = 0;
-
-  /**
    * Notify the compositor that composition is being paused. This allows the
    * compositor to temporarily release any resources.
    * Between calling Pause and Resume, compositing may fail.
    */
   virtual void Pause() {}
   /**
    * Notify the compositor that composition is being resumed. The compositor
    * regain any resources it requires for compositing.
@@ -448,16 +441,27 @@ public:
    * thread at the same time. The backend type in use can be checked with this
    * static method. We need this for creating texture clients/hosts etc. when we
    * don't have a reference to a Compositor.
    *
    * This can only be used from the compositor thread!
    */
   static LayersBackend GetBackend();
 
+  size_t GetFillRatio() {
+    float fillRatio = 0;
+    if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
+      fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
+      if (fillRatio > 999.0f) {
+        fillRatio = 999.0f;
+      }
+    }
+    return fillRatio;
+  }
+
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -109,18 +109,16 @@ public:
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
   }
 
   virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) { }
 
   virtual void PrepareViewport(const gfx::IntSize& aSize,
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE { }
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE { }
-
   virtual const char* Name() const { return "Basic"; }
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   gfx::DrawTarget *GetDrawTarget() { return mDrawTarget; }
 
 private:
   // Widget associated with this compositor
rename from gfx/layers/opengl/FPSCounter.h
rename to gfx/layers/composite/FPSCounter.h
--- a/gfx/layers/opengl/FPSCounter.h
+++ b/gfx/layers/composite/FPSCounter.h
@@ -14,16 +14,17 @@
 #include "VBOArena.h"                   // for gl::VBOArena
 
 namespace mozilla {
 namespace gl {
 class GLContext;
 }
 namespace layers {
 
+class DataTextureSource;
 class ShaderProgramOGL;
 
 const double kFpsWindowMs = 250.0;
 const size_t kNumFrameTimeStamps = 16;
 struct FPSCounter {
   FPSCounter() : mCurrentFrameIndex(0) {
       mFrames.SetLength(kNumFrameTimeStamps);
   }
@@ -66,26 +67,27 @@ private:
     if (realWindowSecs == 0.0 || numFramesDrawnInWindow == 1) {
       return 0.0;
     }
     return double(numFramesDrawnInWindow - 1) / realWindowSecs;
   }
 };
 
 struct FPSState {
-  GLuint mTexture;
   FPSCounter mCompositionFps;
   FPSCounter mTransactionFps;
-  gl::VBOArena mVBOs;
 
-  FPSState() : mTexture(0) { }
+  FPSState() {}
 
-  void DrawFPS(TimeStamp, unsigned, gl::GLContext*, ShaderProgramOGL*);
+  void DrawFPS(TimeStamp, unsigned, Compositor* aCompositor);
 
   void NotifyShadowTreeTransaction() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
+
+private:
+  RefPtr<DataTextureSource> mFPSTextureSource;
 };
 
 }
 }
 
 #endif // mozilla_layers_opengl_FPSCounter_h_
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -6,16 +6,17 @@
 #include "LayerManagerComposite.h"
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint16_t, uint32_t
 #include "CanvasLayerComposite.h"       // for CanvasLayerComposite
 #include "ColorLayerComposite.h"        // for ColorLayerComposite
 #include "Composer2D.h"                 // for Composer2D
 #include "CompositableHost.h"           // for CompositableHost
 #include "ContainerLayerComposite.h"    // for ContainerLayerComposite, etc
+#include "FPSCounter.h"                 // for FPSState, FPSCounter
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "GeckoProfiler.h"              // for profiler_set_frame_number, etc
 #include "ImageLayerComposite.h"        // for ImageLayerComposite
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "ThebesLayerComposite.h"       // for ThebesLayerComposite
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "Units.h"                      // for ScreenIntRect
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
@@ -297,48 +298,139 @@ LayerManagerComposite::RootLayer() const
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return nullptr;
   }
 
   return ToLayerComposite(mRoot);
 }
 
+// Size of the builtin font.
+static const float FontHeight = 7.f;
+static const float FontWidth = 4.f;
+static const float FontStride = 4.f;
+
+// Scale the font when drawing it to the viewport for better readability.
+static const float FontScaleX = 2.f;
+static const float FontScaleY = 3.f;
+
+static void DrawDigits(unsigned int aValue,
+		       int aOffsetX, int aOffsetY,
+                       Compositor* aCompositor,
+		       EffectChain& aEffectChain)
+{
+  if (aValue > 999) {
+    aValue = 999;
+  }
+
+  unsigned int divisor = 100;
+  float textureWidth = FontWidth * 10;
+  gfx::Float opacity = 1;
+  gfx::Matrix4x4 transform;
+  transform.Scale(FontScaleX, FontScaleY, 1);
+
+  for (size_t n = 0; n < 3; ++n) {
+    unsigned int digit = aValue % (divisor * 10) / divisor;
+    divisor /= 10;
+
+    RefPtr<TexturedEffect> texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
+    texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f);
+
+    Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
+    Rect clipRect = Rect(0, 0, 300, 100);
+    aCompositor->DrawQuad(drawRect, clipRect,
+	aEffectChain, opacity, transform);
+  }
+}
+
+void FPSState::DrawFPS(TimeStamp aNow,
+                       unsigned int aFillRatio,
+                       Compositor* aCompositor)
+{
+  if (!mFPSTextureSource) {
+    const char *text =
+      "                                        "
+      " XXX XX  XXX XXX X X XXX XXX XXX XXX XXX"
+      " X X  X    X   X X X X   X     X X X X X"
+      " X X  X  XXX XXX XXX XXX XXX   X XXX XXX"
+      " X X  X  X     X   X   X X X   X X X   X"
+      " XXX XXX XXX XXX   X XXX XXX   X XXX   X"
+      "                                        ";
+
+    // Convert the text encoding above to RGBA.
+    int w = FontWidth * 10;
+    int h = FontHeight;
+    uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
+    for (int i = 0; i < h; i++) {
+      for (int j = 0; j < w; j++) {
+        uint32_t purple = 0xfff000ff;
+        uint32_t white  = 0xffffffff;
+        buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white;
+      }
+    }
+
+   int bytesPerPixel = 4;
+    RefPtr<DataSourceSurface> fpsSurface = Factory::CreateWrappingDataSourceSurface(
+      reinterpret_cast<uint8_t*>(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
+    mFPSTextureSource = aCompositor->CreateDataTextureSource();
+    mFPSTextureSource->Update(fpsSurface);
+  }
+
+  EffectChain effectChain;
+  effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT);
+
+  unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
+  unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
+
+  DrawDigits(fps, 0, 0, aCompositor, effectChain);
+  DrawDigits(txnFps, FontWidth * 4, 0, aCompositor, effectChain);
+  DrawDigits(aFillRatio, FontWidth * 8, 0, aCompositor, effectChain);
+}
+
 static uint16_t sFrameCount = 0;
 void
 LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds)
 {
-  if (!gfxPlatform::DrawFrameCounter()) {
-    return;
+  if (gfxPlatform::GetPrefLayersDrawFPS()) {
+    if (!mFPS) {
+      mFPS = new FPSState();
+    }
+
+    float fillRatio = mCompositor->GetFillRatio();
+    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mCompositor);
+  } else {
+    mFPS = nullptr;
   }
 
-  profiler_set_frame_number(sFrameCount);
+  if (gfxPlatform::DrawFrameCounter()) {
+    profiler_set_frame_number(sFrameCount);
 
-  uint16_t frameNumber = sFrameCount;
-  const uint16_t bitWidth = 3;
-  float opacity = 1.0;
-  gfx::Rect clip(0,0, bitWidth*16, bitWidth);
-  for (size_t i = 0; i < 16; i++) {
+    uint16_t frameNumber = sFrameCount;
+    const uint16_t bitWidth = 3;
+    float opacity = 1.0;
+    gfx::Rect clip(0,0, bitWidth*16, bitWidth);
+    for (size_t i = 0; i < 16; i++) {
 
-    gfx::Color bitColor;
-    if ((frameNumber >> i) & 0x1) {
-      bitColor = gfx::Color(0, 0, 0, 1.0);
-    } else {
-      bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0);
+      gfx::Color bitColor;
+      if ((frameNumber >> i) & 0x1) {
+        bitColor = gfx::Color(0, 0, 0, 1.0);
+      } else {
+        bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0);
+      }
+      EffectChain effects;
+      effects.mPrimaryEffect = new EffectSolidColor(bitColor);
+      mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth),
+                            clip,
+                            effects,
+                            opacity,
+                            gfx::Matrix4x4());
     }
-    EffectChain effects;
-    effects.mPrimaryEffect = new EffectSolidColor(bitColor);
-    mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth),
-                          clip,
-                          effects,
-                          opacity,
-                          gfx::Matrix4x4());
+    // We intentionally overflow at 2^16.
+    sFrameCount++;
   }
-  // We intentionally overflow at 2^16.
-  sFrameCount++;
 }
 
 void
 LayerManagerComposite::Render()
 {
   PROFILER_LABEL("LayerManagerComposite", "Render");
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
@@ -347,17 +439,21 @@ LayerManagerComposite::Render()
 
   if (gfxPlatform::GetPrefLayersDump()) {
     this->Dump();
   }
 
   /** Our more efficient but less powerful alter ego, if one is available. */
   nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
 
-  if (composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
+  if (mFPS && composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
+    double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
+    if (gfxPlatform::GetPrefLayersDrawFPS()) {
+      printf_stderr("HWComposer: FPS is %g\n", fps);
+    }
     mCompositor->EndFrameForExternalComposition(mWorldMatrix);
     return;
   }
 
   {
     PROFILER_LABEL("LayerManagerComposite", "PreRender");
     if (!mCompositor->GetWidget()->PreRender(this)) {
       return;
@@ -782,16 +878,24 @@ LayerComposite::Destroy()
 
 bool
 LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize &aSize)
 {
   return mCompositor->CanUseCanvasLayerForSize(gfx::IntSize(aSize.width,
                                                             aSize.height));
 }
 
+void
+LayerManagerComposite::NotifyShadowTreeTransaction()
+{
+  if (mFPS) {
+    mFPS->NotifyShadowTreeTransaction();
+  }
+}
+
 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
 
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -56,16 +56,17 @@ class ContainerLayerComposite;
 class EffectChain;
 class ImageLayer;
 class ImageLayerComposite;
 class LayerComposite;
 class RefLayerComposite;
 class SurfaceDescriptor;
 class ThebesLayerComposite;
 class TiledLayerComposer;
+struct FPSState;
 
 class LayerManagerComposite : public LayerManager
 {
 public:
   LayerManagerComposite(Compositor* aCompositor);
   ~LayerManagerComposite();
   
   virtual void Destroy() MOZ_OVERRIDE;
@@ -219,16 +220,18 @@ public:
   /**
    * LayerManagerComposite provides sophisticated debug overlays
    * that can request a next frame.
    */
   bool DebugOverlayWantsNextFrame() { return mDebugOverlayWantsNextFrame; }
   void SetDebugOverlayWantsNextFrame(bool aVal)
   { mDebugOverlayWantsNextFrame = aVal; }
 
+  void NotifyShadowTreeTransaction();
+
 private:
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
   nsIntRect mRenderBounds;
 
   /** Current root layer. */
   LayerComposite* RootLayer() const;
 
@@ -251,23 +254,24 @@ private:
   /**
    * Render debug overlays such as the FPS/FrameCounter above the frame.
    */
   void RenderDebugOverlay(const gfx::Rect& aBounds);
 
   void WorldTransformRect(nsIntRect& aRect);
 
   RefPtr<Compositor> mCompositor;
+  nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
 
   gfx::Matrix mWorldMatrix;
+  nsIntRegion mInvalidRegion;
+  nsAutoPtr<FPSState> mFPS;
 
   bool mInTransaction;
   bool mIsCompositorReady;
-  nsIntRegion mInvalidRegion;
-  nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
   bool mDebugOverlayWantsNextFrame;
 };
 
 /**
  * Composite layers are for use with OMTC on the compositor thread only. There
  * must be corresponding Basic layers on the content thread. For composite
  * layers, the layer manager only maintains the layer tree, all rendering is
  * done by a Compositor (see Compositor.h). As such, composite layers are
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -337,17 +337,17 @@ CompositorD3D11::Initialize()
 
   return true;
 }
 
 TemporaryRef<DataTextureSource>
 CompositorD3D11::CreateDataTextureSource(TextureFlags aFlags)
 {
   RefPtr<DataTextureSource> result = new DataTextureSourceD3D11(gfx::SurfaceFormat::UNKNOWN,
-                                                                this);
+                                                                this, aFlags);
   return result.forget();
 }
 
 TextureFactoryIdentifier
 CompositorD3D11::GetTextureFactoryIdentifier()
 {
   TextureFactoryIdentifier ident;
   ident.mMaxTextureSize = GetMaxTextureSize();
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -131,18 +131,16 @@ public:
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D 11"; }
 #endif
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE { }
-
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   ID3D11Device* GetDevice() { return mDevice; }
 
 private:
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
   void VerifyBufferSize();
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -57,20 +57,21 @@ GetTileRectD3D11(uint32_t aID, IntSize a
 
   return IntRect(horizontalTile * aMaxSize,
                  verticalTile * aMaxSize,
                  horizontalTile < (horizontalTiles - 1) ? aMaxSize : aSize.width % aMaxSize,
                  verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize);
 }
 
 DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat,
-                                               CompositorD3D11* aCompositor)
+                                               CompositorD3D11* aCompositor,
+                                               TextureFlags aFlags)
   : mCompositor(aCompositor)
   , mFormat(aFormat)
-  , mFlags(0)
+  , mFlags(aFlags)
   , mCurrentTile(0)
   , mIsTiled(false)
   , mIterating(false)
 {
   MOZ_COUNT_CTOR(DataTextureSourceD3D11);
 }
 
 DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat,
@@ -416,17 +417,17 @@ DataTextureSourceD3D11::GetTileRect()
   IntRect rect = GetTileRect(mCurrentTile);
   return nsIntRect(rect.x, rect.y, rect.width, rect.height);
 }
 
 void
 DataTextureSourceD3D11::SetCompositor(Compositor* aCompositor)
 {
   CompositorD3D11* d3dCompositor = static_cast<CompositorD3D11*>(aCompositor);
-  if (mCompositor != d3dCompositor) {
+  if (mCompositor && mCompositor != d3dCompositor) {
     Reset();
   }
   mCompositor = d3dCompositor;
 }
 
 TemporaryRef<DeprecatedTextureHost>
 CreateDeprecatedTextureHostD3D11(SurfaceDescriptorType aDescriptorType,
                                  uint32_t aDeprecatedTextureHostFlags,
@@ -900,19 +901,19 @@ DeprecatedTextureHostYCbCrD3D11::UpdateI
   gfx::IntSize gfxCbCrSize = yuvDeserializer.GetCbCrSize();
 
   gfx::IntSize size = yuvDeserializer.GetYSize();
 
   RefPtr<DataTextureSource> srcY;
   RefPtr<DataTextureSource> srcCb;
   RefPtr<DataTextureSource> srcCr;
   if (!mFirstSource) {
-    srcY  = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor);
-    srcCb = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor);
-    srcCr = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor);
+    srcY  = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, TEXTURE_DISALLOW_BIGIMAGE);
+    srcCb = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, TEXTURE_DISALLOW_BIGIMAGE);
+    srcCr = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, TEXTURE_DISALLOW_BIGIMAGE);
     mFirstSource = srcY;
     srcY->SetNextSibling(srcCb);
     srcCb->SetNextSibling(srcCr);
   } else {
     MOZ_ASSERT(mFirstSource->GetNextSibling());
     MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling());
     srcY  = mFirstSource;
     srcCb = mFirstSource->GetNextSibling()->AsDataTextureSource();
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -95,17 +95,18 @@ protected:
  * it can be used without a TextureHost and is able to upload texture data
  * from a gfx::DataSourceSurface.
  */
 class DataTextureSourceD3D11 : public DataTextureSource
                              , public TextureSourceD3D11
                              , public TileIterator
 {
 public:
-  DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, CompositorD3D11* aCompositor);
+  DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, CompositorD3D11* aCompositor,
+                         TextureFlags aFlags);
 
   DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, CompositorD3D11* aCompositor,
                          ID3D11Texture2D* aTexture);
 
   virtual ~DataTextureSourceD3D11();
 
 
   // DataTextureSource
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -84,18 +84,17 @@ int32_t
 CompositorD3D9::GetMaxTextureSize() const
 {
   return mDeviceManager ? mDeviceManager->GetMaxTextureSize() : INT32_MAX;
 }
 
 TemporaryRef<DataTextureSource>
 CompositorD3D9::CreateDataTextureSource(TextureFlags aFlags)
 {
-  return new DataTextureSourceD3D9(SurfaceFormat::UNKNOWN, this,
-                                   !(aFlags & TEXTURE_DISALLOW_BIGIMAGE));
+  return new DataTextureSourceD3D9(SurfaceFormat::UNKNOWN, this, aFlags);
 }
 
 TemporaryRef<CompositingRenderTarget>
 CompositorD3D9::CreateRenderTarget(const gfx::IntRect &aRect,
                                    SurfaceInitMode aInit)
 {
   if (!mDeviceManager) {
     return nullptr;
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -78,18 +78,16 @@ public:
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D9"; }
 #endif
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE {}
-
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   IDirect3DDevice9* device() const
   {
     return mDeviceManager
            ? mDeviceManager->device()
            : nullptr;
   }
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -1209,21 +1209,20 @@ DataTextureSourceD3D9::Update(gfxWindows
 
   return true;
 }
 
 void
 DataTextureSourceD3D9::SetCompositor(Compositor* aCompositor)
 {
   CompositorD3D9* d3dCompositor = static_cast<CompositorD3D9*>(aCompositor);
-
-  if (d3dCompositor != mCompositor) {
+  if (mCompositor && mCompositor != d3dCompositor) {
     Reset();
-    mCompositor = d3dCompositor;
   }
+  mCompositor = d3dCompositor;
 }
 
 void
 DataTextureSourceD3D9::Reset()
 {
   mSize.width = 0;
   mSize.height = 0;
   mIsTiled = false;
@@ -1273,16 +1272,17 @@ CairoTextureClientD3D9::Lock(OpenMode)
 {
   MOZ_ASSERT(!mIsLocked);
   if (!IsValid() || !IsAllocated()) {
     return false;
   }
   if (mNeedsClear) {
     mDrawTarget = GetAsDrawTarget();
     mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
+    mNeedsClear = false;
   }
   mIsLocked = true;
   return true;
 }
 
 void
 CairoTextureClientD3D9::Unlock()
 {
@@ -1334,29 +1334,32 @@ CairoTextureClientD3D9::GetAsDrawTarget(
   if (!mD3D9Surface) {
     HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface));
     if (FAILED(hr)) {
       NS_WARNING("Failed to get texture surface level.");
       return nullptr;
     }
   }
 
-  if (ContentForFormat(mFormat) == gfxContentType::COLOR_ALPHA) {
-    D3DLOCKED_RECT rect;
-    mD3D9Surface->LockRect(&rect, nullptr, 0);
-    mSurface = new gfxImageSurface((uint8_t*)rect.pBits, ThebesIntSize(mSize),
-                                   rect.Pitch, gfxImageFormat::ARGB32);
-    mLockRect = true;
-  } else {
+  if (ContentForFormat(mFormat) == gfxContentType::COLOR) {
     mSurface = new gfxWindowsSurface(mD3D9Surface);
     if (!mSurface || mSurface->CairoStatus()) {
       NS_WARNING("Could not create surface for d3d9 surface");
       mSurface = nullptr;
       return nullptr;
     }
+  } else {
+    // gfxWindowsSurface don't support transparency so we can't use the d3d9
+    // windows surface optimization.
+    // Instead we have to use a gfxImageSurface and fallback for font drawing.
+    D3DLOCKED_RECT rect;
+    mD3D9Surface->LockRect(&rect, nullptr, 0);
+    mSurface = new gfxImageSurface((uint8_t*)rect.pBits, ThebesIntSize(mSize),
+                                   rect.Pitch, SurfaceFormatToImageFormat(mFormat));
+    mLockRect = true;
   }
 
   mDrawTarget =
     gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize);
 
   return mDrawTarget;
 }
 
@@ -1552,20 +1555,25 @@ TextureHostD3D9::TextureHostD3D9(Texture
 bool
 DataTextureSourceD3D9::UpdateFromTexture(IDirect3DTexture9* aTexture,
                                          const nsIntRegion* aRegion)
 {
   MOZ_ASSERT(aTexture);
 
   D3DSURFACE_DESC desc;
   HRESULT hr = aTexture->GetLevelDesc(0, &desc);
-  if (!FAILED(hr)) {
+  if (FAILED(hr)) {
+    return false;
+  } else {
+    // If we changed the compositor, the size might have been reset to zero
+    // Otherwise the texture size must not change.
     MOZ_ASSERT(mFormat == D3D9FormatToSurfaceFormat(desc.Format));
-    MOZ_ASSERT(mSize.width == desc.Width);
-    MOZ_ASSERT(mSize.height == desc.Height);
+    MOZ_ASSERT(!mSize.width || mSize.width == desc.Width);
+    MOZ_ASSERT(!mSize.height || mSize.height == desc.Height);
+    mSize = IntSize(desc.Width, desc.Height);
   }
 
   DeviceManagerD3D9* dm = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
   if (!mTexture) {
     mTexture = dm->CreateTexture(mSize, SurfaceFormatToD3D9Format(mFormat),
                                  D3DPOOL_DEFAULT, this);
     if (!mTexture) {
       NS_WARNING("Failed to create a texture");
@@ -1593,20 +1601,28 @@ DataTextureSourceD3D9::UpdateFromTexture
       rect.left = iterRect->x;
       rect.top = iterRect->y;
       rect.right = iterRect->XMost();
       rect.bottom = iterRect->YMost();
 
       POINT point;
       point.x = iterRect->x;
       point.y = iterRect->y;
-      dm->device()->UpdateSurface(srcSurface, &rect, dstSurface, &point);
+      hr = dm->device()->UpdateSurface(srcSurface, &rect, dstSurface, &point);
+      if (FAILED(hr)) {
+        NS_WARNING("Failed Update the surface");
+        return false;
+      }
     }
   } else {
-    dm->device()->UpdateSurface(srcSurface, nullptr, dstSurface, nullptr);
+    hr = dm->device()->UpdateSurface(srcSurface, nullptr, dstSurface, nullptr);
+    if (FAILED(hr)) {
+      NS_WARNING("Failed Update the surface");
+      return false;
+    }
   }
   mIsTiled = false;
   return true;
 }
 
 void
 TextureHostD3D9::Updated(const nsIntRegion* aRegion)
 {
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -958,31 +958,43 @@ nsEventStatus AsyncPanZoomController::On
   APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   // If mZoomConstraints.mAllowZoom is true we wait for a call to OnSingleTapConfirmed before
   // sending event to content
   if (controller && !AllowZoom()) {
     int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
     CSSIntPoint geckoScreenPoint;
     if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
-      controller->HandleSingleTap(geckoScreenPoint, modifiers, GetGuid());
+      // Because this may be being running as part of APZCTreeManager::ReceiveInputEvent,
+      // calling controller->HandleSingleTap directly might mean that content receives
+      // the single tap message before the corresponding touch-up. To avoid that we
+      // schedule the singletap message to run on the next spin of the event loop.
+      // See bug 965381 for the issue this was causing.
+      controller->PostDelayedTask(
+        NewRunnableMethod(controller.get(), &GeckoContentController::HandleSingleTap,
+                          geckoScreenPoint, modifiers, GetGuid()),
+        0);
       return nsEventStatus_eConsumeNoDefault;
     }
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a single-tap-confirmed in state %d\n", this, mState);
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
     int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
     CSSIntPoint geckoScreenPoint;
     if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
-      controller->HandleSingleTap(geckoScreenPoint, modifiers, GetGuid());
+      // See comment in OnSingleTapUp as to why we do this in PostDelayedTask.
+      controller->PostDelayedTask(
+        NewRunnableMethod(controller.get(), &GeckoContentController::HandleSingleTap,
+                          geckoScreenPoint, modifiers, GetGuid()),
+        0);
       return nsEventStatus_eConsumeNoDefault;
     }
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a double-tap in state %d\n", this, mState);
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -510,17 +510,17 @@ void
 CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint, bool aScheduleComposite)
 {
   if (mApzcTreeManager &&
       mLayerManager &&
       mLayerManager->GetRoot()) {
     AutoResolveRefLayers resolve(mCompositionManager);
     mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId);
 
-    mCompositor->NotifyLayersTransaction();
+    mLayerManager->NotifyShadowTreeTransaction();
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
 }
 
 // Used when layout.frame_rate is -1. Needs to be kept in sync with
 // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
@@ -726,17 +726,17 @@ CompositorParent::ShadowLayersUpdated(La
     SetShadowProperties(root);
     if (mIsTesting) {
       mCompositionManager->TransformShadowTree(mTestTime);
     }
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
-  mCompositor->NotifyLayersTransaction();
+  mLayerManager->NotifyShadowTreeTransaction();
 }
 
 void
 CompositorParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
 {
   NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
   NS_ASSERTION(!mCompositor,   "Already initialised mCompositor");
 
--- a/gfx/layers/ipc/GestureEventListener.cpp
+++ b/gfx/layers/ipc/GestureEventListener.cpp
@@ -275,16 +275,21 @@ nsEventStatus GestureEventListener::Hand
     // If the user left a finger on the screen, spoof a touch start event and
     // send it to APZC so that they can continue panning from that point.
     if (mTouches.Length() == 1) {
       MultiTouchInput touchEvent(MultiTouchInput::MULTITOUCH_START,
                                  aEvent.mTime,
                                  aEvent.modifiers);
       touchEvent.mTouches.AppendElement(mTouches[0]);
       mAsyncPanZoomController->HandleInputEvent(touchEvent);
+
+      // The spoofed touch start will get back to GEL and make us enter the
+      // GESTURE_WAITING_SINGLE_TAP state, but this isn't a new touch, so there
+      // is no condition under which this touch should turn into any tap.
+      mState = GESTURE_NONE;
     }
 
     rv = nsEventStatus_eConsumeNoDefault;
   } else if (mState == GESTURE_WAITING_PINCH) {
     mState = GESTURE_NONE;
   }
 
   return rv;
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -2,17 +2,16 @@
  * 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 "CompositorOGL.h"
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint8_t
 #include <stdlib.h>                     // for free, malloc
-#include "FPSCounter.h"                 // for FPSState, FPSCounter
 #include "GLContextProvider.h"          // for GLContextProvider
 #include "GLContext.h"                  // for GLContext
 #include "GLUploadHelpers.h"
 #include "Layers.h"                     // for WriteSnapshotToDumpFile
 #include "LayerScope.h"                 // for LayerScope
 #include "gfx2DGlue.h"                  // for ThebesFilter
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxASurface.h"                // for gfxASurface, etc
@@ -130,122 +129,16 @@ DrawQuads(GLContext *aGLContext,
   aGLContext->fDisableVertexAttribArray(vertAttribIndex);
   if (texCoords) {
     aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   }
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
-// Size of the builtin font.
-static const float FontHeight = 7.f;
-static const float FontWidth = 5.f;
-static const float FontStride = 4.f;
-
-// Scale the font when drawing it to the viewport for better readability.
-static const float FontScaleX = 2.f;
-static const float FontScaleY = 3.f;
-
-// Size of the font texture (POT).
-static const size_t FontTextureWidth = 64;
-static const size_t FontTextureHeight = 8;
-
-static void
-AddDigits(RectTriangles &aRects,
-          const gfx::IntSize aViewportSize,
-          unsigned int aOffset,
-          unsigned int aValue)
-{
-  unsigned int divisor = 100;
-  for (size_t n = 0; n < 3; ++n) {
-    gfxRect d(aOffset * FontWidth, 0.f, FontWidth, FontHeight);
-    d.Scale(FontScaleX / aViewportSize.width, FontScaleY / aViewportSize.height);
-
-    unsigned int digit = aValue % (divisor * 10) / divisor;
-    gfxRect t(digit * FontStride, 0.f, FontWidth, FontHeight);
-    t.Scale(1.f / FontTextureWidth, 1.f / FontTextureHeight);
-
-    aRects.addRect(d.x, d.y, d.x + d.width, d.y + d.height,
-                   t.x, t.y, t.x + t.width, t.y + t.height,
-                   false);
-    divisor /= 10;
-    ++aOffset;
-  }
-}
-
-void
-FPSState::DrawFPS(TimeStamp aNow,
-                  unsigned int aFillRatio,
-                  GLContext* aContext,
-                  ShaderProgramOGL* aProgram)
-{
-  if (!mTexture) {
-    // Bind the number of textures we need, in this case one.
-    aContext->fGenTextures(1, &mTexture);
-    aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
-    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
-
-    const char *text =
-      "                                         "
-      " XXX XX  XXX XXX X X XXX XXX XXX XXX XXX "
-      " X X  X    X   X X X X   X     X X X X X "
-      " X X  X  XXX XXX XXX XXX XXX   X XXX XXX "
-      " X X  X  X     X   X   X X X   X X X   X "
-      " XXX XXX XXX XXX   X XXX XXX   X XXX   X "
-      "                                         ";
-
-    // Convert the text encoding above to RGBA.
-    uint32_t* buf = (uint32_t *) malloc(64 * 8 * sizeof(uint32_t));
-    for (int i = 0; i < 7; i++) {
-      for (int j = 0; j < 41; j++) {
-        uint32_t purple = 0xfff000ff;
-        uint32_t white  = 0xffffffff;
-        buf[i * 64 + j] = (text[i * 41 + j] == ' ') ? purple : white;
-      }
-    }
-    aContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
-    free(buf);
-  }
-
-  mVBOs.Reset();
-
-  GLint viewport[4];
-  aContext->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
-  gfx::IntSize viewportSize(viewport[2], viewport[3]);
-
-  unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
-  unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
-
-  RectTriangles rects;
-  AddDigits(rects, viewportSize, 0, fps);
-  AddDigits(rects, viewportSize, 4, txnFps);
-  AddDigits(rects, viewportSize, 8, aFillRatio);
-
-  // Turn necessary features on
-  aContext->fEnable(LOCAL_GL_BLEND);
-  aContext->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
-
-  aContext->fActiveTexture(LOCAL_GL_TEXTURE0);
-  aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
-  aProgram->Activate();
-  aProgram->SetTextureUnit(0);
-  aProgram->SetLayerQuadRect(gfx::Rect(0.f, 0.f, viewport[2], viewport[3]));
-  aProgram->SetLayerOpacity(1.f);
-  aProgram->SetTextureTransform(Matrix4x4());
-  aProgram->SetLayerTransform(Matrix4x4());
-  aProgram->SetRenderOffset(0, 0);
-
-  aContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
-                               LOCAL_GL_ONE, LOCAL_GL_ZERO);
-
-  DrawQuads(aContext, mVBOs, aProgram, rects);
-}
-
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
@@ -322,21 +215,16 @@ CompositorOGL::GetTemporaryTexture(GLenu
 void
 CompositorOGL::Destroy()
 {
   if (gl() && gl()->MakeCurrent()) {
     if (mTextures.Length() > 0) {
       gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]);
     }
     mVBOs.Flush(gl());
-    if (mFPS) {
-      if (mFPS->mTexture > 0)
-        gl()->fDeleteTextures(1, &mFPS->mTexture);
-      mFPS->mVBOs.Flush(gl());
-    }
   }
   mTextures.SetLength(0);
   if (!mDestroyed) {
     mDestroyed = true;
     CleanupResources();
   }
 }
 
@@ -364,25 +252,16 @@ CompositorOGL::CleanupResources()
   if (mQuadVBO) {
     ctx->fDeleteBuffers(1, &mQuadVBO);
     mQuadVBO = 0;
   }
 
   mGLContext = nullptr;
 }
 
-// Impl of a a helper-runnable's "Run" method, used in Initialize()
-NS_IMETHODIMP
-CompositorOGL::ReadDrawFPSPref::Run()
-{
-  // NOTE: This must match the code in Initialize()'s NS_IsMainThread check.
-  Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
-  return NS_OK;
-}
-
 bool
 CompositorOGL::Initialize()
 {
   ScopedGfxFeatureReporter reporter("GL Layers", true);
 
   // Do not allow double initialization
   NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
 
@@ -540,24 +419,16 @@ CompositorOGL::Initialize()
     msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
       msg += NS_LITERAL_STRING("TEXTURE_2D");
     else
       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
     console->LogStringMessage(msg.get());
   }
 
-  if (NS_IsMainThread()) {
-    // NOTE: This must match the code in ReadDrawFPSPref::Run().
-    Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
-  } else {
-    // We have to dispatch an event to the main thread to read the pref.
-    NS_DispatchToMainThread(new ReadDrawFPSPref());
-  }
-
   reporter.SetSuccessful();
   return true;
 }
 
 // |aTextureTransform| is the texture transform that will be set on
 // aProg, possibly multiplied with another texture transform of our
 // own.
 // |aTexCoordRect| is the rectangle from the texture that we want to
@@ -751,18 +622,16 @@ GetFrameBufferInternalFormat(GLContext* 
                              nsIWidget* aWidget)
 {
   if (aFrameBuffer == 0) { // default framebuffer
     return aWidget->GetGLFrameBufferFormat();
   }
   return LOCAL_GL_RGBA;
 }
 
-bool CompositorOGL::sDrawFPS = false;
-
 /*
  * Returns a size that is larger than and closest to aSize where both
  * width and height are powers of two.
  * If the OpenGL setup is capable of using non-POT textures, then it
  * will just return aSize.
  */
 static IntSize
 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
@@ -1420,47 +1289,23 @@ CompositorOGL::EndFrame()
     CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     mCurrentRenderTarget = nullptr;
     return;
   }
 
   mCurrentRenderTarget = nullptr;
 
-  if (sDrawFPS && !mFPS) {
-    mFPS = new FPSState();
-  } else if (!sDrawFPS && mFPS) {
-    mFPS = nullptr;
-  }
-
-  if (mFPS) {
-    float fillRatio = 0;
-    if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
-      fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
-      if (fillRatio > 999.0f)
-        fillRatio = 999.0f;
-    }
-    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(RGBXLayerProgramType));
-  }
-
   mGLContext->SwapBuffers();
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
 {
-  if (sDrawFPS) {
-    if (!mFPS) {
-      mFPS = new FPSState();
-    }
-    double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
-    printf_stderr("HWComposer: FPS is %g\n", fps);
-  }
-
   // This lets us reftest and screenshot content rendered externally
   if (mTarget) {
     MakeCurrent();
     CopyToTarget(mTarget, aTransform);
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   }
 }
 
@@ -1527,39 +1372,16 @@ CompositorOGL::CopyToTarget(DrawTarget *
   Matrix oldMatrix = aTarget->GetTransform();
   aTarget->SetTransform(glToCairoTransform);
   Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
   aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
   aTarget->SetTransform(oldMatrix);
   aTarget->Flush();
 }
 
-double
-CompositorOGL::AddFrameAndGetFps(const TimeStamp& timestamp)
-{
-  if (sDrawFPS) {
-    if (!mFPS) {
-      mFPS = new FPSState();
-    }
-    double fps = mFPS->mCompositionFps.AddFrameAndGetFps(timestamp);
-
-    return fps;
-  }
-
-  return 0.;
-}
-
-void
-CompositorOGL::NotifyLayersTransaction()
-{
-  if (mFPS) {
-    mFPS->NotifyShadowTreeTransaction();
-  }
-}
-
 void
 CompositorOGL::Pause()
 {
 #ifdef MOZ_WIDGET_ANDROID
   if (!gl() || gl()->IsDestroyed())
     return;
 
   // ReleaseSurface internally calls MakeCurrent.
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -46,17 +46,16 @@ namespace layers {
 
 class CompositingRenderTarget;
 class CompositingRenderTargetOGL;
 class DataTextureSource;
 class GLManagerCompositor;
 class TextureSource;
 struct Effect;
 struct EffectChain;
-struct FPSState;
 
 class CompositorOGL : public Compositor
 {
   typedef mozilla::gl::GLContext GLContext;
   typedef ShaderProgramType ProgramType;
   
   friend class GLManagerCompositor;
 
@@ -146,18 +145,16 @@ public:
   virtual void PrepareViewport(const gfx::IntSize& aSize,
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "OGL"; }
 #endif // MOZ_DUMP_PAINTING
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE;
-
   virtual void Pause() MOZ_OVERRIDE;
   virtual bool Resume() MOZ_OVERRIDE;
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   GLContext* gl() const { return mGLContext; }
   ShaderProgramType GetFBOLayerProgramType() const {
     return mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB ?
@@ -192,22 +189,16 @@ private:
   nsIntSize mWidgetSize;
   nsRefPtr<GLContext> mGLContext;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
   ScreenPoint mRenderOffset;
 
-  /** Helper-class used by Initialize **/
-  class ReadDrawFPSPref MOZ_FINAL : public nsRunnable {
-  public:
-    NS_IMETHOD Run() MOZ_OVERRIDE;
-  };
-
   already_AddRefed<mozilla::gl::GLContext> CreateContext();
 
   /** Shader Programs */
   struct ShaderProgramVariations {
     nsAutoTArray<nsAutoPtr<ShaderProgramOGL>, NumMaskTypes> mVariations;
     ShaderProgramVariations() {
       MOZ_COUNT_CTOR(ShaderProgramVariations);
       mVariations.SetLength(NumMaskTypes);
@@ -321,34 +312,28 @@ private:
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    * Does not restore the target FBO, so only call from EndFrame.
    */
   void CopyToTarget(gfx::DrawTarget* aTarget, const gfx::Matrix& aWorldMatrix);
 
   /**
-   * Records the passed frame timestamp and returns the current estimated FPS.
-   */
-  double AddFrameAndGetFps(const TimeStamp& timestamp);
-
-  /**
    * Implements the flipping of the y-axis to convert from layers/compositor
    * coordinates to OpenGL coordinates.
    *
    * Indeed, the only coordinate system that OpenGL knows has the y-axis
    * pointing upwards, but the layers/compositor coordinate system has the
    * y-axis pointing downwards, for good reason as Web pages are typically
    * scrolled downwards. So, some flipping has to take place; FlippedY does it.
    */
   GLint FlipY(GLint y) const { return mHeight - y; }
 
   bool mDestroyed;
 
-  nsAutoPtr<FPSState> mFPS;
   // Textures used for direct texturing of buffers like gralloc.
   // The index of the texture in this array must correspond to the texture unit.
   nsTArray<GLuint> mTextures;
   static bool sDrawFPS;
 
   /**
    * Height of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation.
--- a/gfx/qcms/qcmstypes.h
+++ b/gfx/qcms/qcmstypes.h
@@ -1,26 +1,11 @@
 #ifndef QCMS_TYPES_H
 #define QCMS_TYPES_H
 
-#ifdef MOZ_QCMS
-
-#include "prtypes.h"
-#include <stdint.h>
-
-/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */
-
-#if defined(_AIX)
-#include <sys/types.h>
-#elif defined(__OS2__)
-#include <stdlib.h>
-#endif
-
-#else // MOZ_QCMS
-
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define IS_LITTLE_ENDIAN
 #elif BYTE_ORDER == BIG_ENDIAN
 #define IS_BIG_ENDIAN
 #endif
 
 /* all of the platforms that we use _MSC_VER on are little endian
  * so this is sufficient for now */
@@ -33,17 +18,17 @@
 #endif
 
 #if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
 #error Unknown endianess
 #endif
 
 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__)
 #  include <inttypes.h>
-#elif defined (_MSC_VER)
+#elif defined (_MSC_VER) && _MSC_VER < 1600
 typedef __int8 int8_t;
 typedef unsigned __int8 uint8_t;
 typedef __int16 int16_t;
 typedef unsigned __int16 uint16_t;
 typedef __int32 int32_t;
 typedef unsigned __int32 uint32_t;
 typedef __int64 int64_t;
 typedef unsigned __int64 uint64_t;
@@ -54,15 +39,13 @@ typedef unsigned long uintptr_t;
 #endif
 
 #elif defined (_AIX)
 #  include <sys/inttypes.h>
 #else
 #  include <stdint.h>
 #endif
 
-#endif
-
 typedef qcms_bool bool;
 #define true 1
 #define false 0
 
 #endif
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -36,23 +36,46 @@ public:
   MOCK_METHOD3(HandleLongTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(HandleLongTapUp, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
   MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
   MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
 };
 
 class MockContentControllerDelayed : public MockContentController {
 public:
+  MockContentControllerDelayed()
+    : mCurrentTask(nullptr)
+  {
+  }
 
   void PostDelayedTask(Task* aTask, int aDelayMs) {
+    // Ensure we're not clobbering an existing task
+    EXPECT_TRUE(nullptr == mCurrentTask);
     mCurrentTask = aTask;
   }
 
-  Task* GetDelayedTask() {
-    return mCurrentTask;
+  void CheckHasDelayedTask() {
+    EXPECT_TRUE(nullptr != mCurrentTask);
+  }
+
+  void ClearDelayedTask() {
+    mCurrentTask = nullptr;
+  }
+
+  // Note that deleting mCurrentTask is important in order to
+  // release the reference to the callee object. Without this
+  // that object might be leaked. This is also why we don't
+  // expose mCurrentTask to any users of MockContentControllerDelayed.
+  void RunDelayedTask() {
+    // Running mCurrentTask may call PostDelayedTask, so we should
+    // keep a local copy of mCurrentTask and operate on that
+    Task* local = mCurrentTask;
+    mCurrentTask = nullptr;
+    local->Run();
+    delete local;
   }
 
 private:
   Task *mCurrentTask;
 };
 
 
 class TestAPZCContainerLayer : public ContainerLayer {
@@ -260,18 +283,24 @@ ApzcDown(AsyncPanZoomController* apzc, i
 static nsEventStatus
 ApzcUp(AsyncPanZoomController* apzc, int aX, int aY, int& aTime) {
   MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, 0);
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(aX, aY), ScreenSize(0, 0), 0, 0));
   return apzc->ReceiveInputEvent(mti);
 }
 
 static nsEventStatus
-ApzcTap(AsyncPanZoomController* apzc, int aX, int aY, int& aTime, int aTapLength) {
+ApzcTap(AsyncPanZoomController* apzc, int aX, int aY, int& aTime, int aTapLength, MockContentControllerDelayed* mcc = nullptr) {
   nsEventStatus status = ApzcDown(apzc, aX, aY, aTime);
+  if (mcc != nullptr) {
+    // There will be a delayed task posted for the long-tap timeout, but
+    // if we were provided a non-null mcc we want to clear it.
+    mcc->CheckHasDelayedTask();
+    mcc->ClearDelayedTask();
+  }
   EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
   aTime += aTapLength;
   return ApzcUp(apzc, aX, aY, aTime);
 }
 
 TEST(AsyncPanZoomController, Constructor) {
   // RefCounted class can't live in the stack
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
@@ -582,49 +611,59 @@ TEST(AsyncPanZoomController, OverScrollP
 
   // Pan down
   ApzcPan(apzc, tm, time, touchStart, touchEnd);
   apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
   EXPECT_EQ(pointOut, ScreenPoint(0, 90));
 }
 
 TEST(AsyncPanZoomController, ShortPress) {
-  nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
+  nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
-  EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+  int time = 0;
+  nsEventStatus status = ApzcTap(apzc, 10, 10, time, 100, mcc.get());
+  EXPECT_EQ(nsEventStatus_eIgnore, status);
 
-  int time = 0;
-  nsEventStatus status = ApzcTap(apzc, 10, 10, time, 100);
-  EXPECT_EQ(nsEventStatus_eIgnore, status);
+  // This verifies that the single tap notification is sent after the
+  // touchdown is fully processed. The ordering here is important.
+  mcc->CheckHasDelayedTask();
+
+  EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+  mcc->RunDelayedTask();
 
   apzc->Destroy();
 }
 
 TEST(AsyncPanZoomController, MediumPress) {
-  nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
+  nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
-  EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+  int time = 0;
+  nsEventStatus status = ApzcTap(apzc, 10, 10, time, 400, mcc.get());
+  EXPECT_EQ(nsEventStatus_eIgnore, status);
 
-  int time = 0;
-  nsEventStatus status = ApzcTap(apzc, 10, 10, time, 400);
-  EXPECT_EQ(nsEventStatus_eIgnore, status);
+  // This verifies that the single tap notification is sent after the
+  // touchdown is fully processed. The ordering here is important.
+  mcc->CheckHasDelayedTask();
+
+  EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+  mcc->RunDelayedTask();
 
   apzc->Destroy();
 }
 
 TEST(AsyncPanZoomController, LongPress) {
   nsRefPtr<MockContentControllerDelayed> mcc = new MockContentControllerDelayed();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
@@ -634,23 +673,21 @@ TEST(AsyncPanZoomController, LongPress) 
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
   int time = 0;
 
   nsEventStatus status = ApzcDown(apzc, 10, 10, time);
   EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
 
-  Task* t = mcc->GetDelayedTask();
-
-  EXPECT_TRUE(nullptr != t);
+  mcc->CheckHasDelayedTask();
   EXPECT_CALL(*mcc, HandleLongTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
 
   // Manually invoke the longpress while the touch is currently down.
-  t->Run();
+  mcc->RunDelayedTask();
 
   time += 1000;
 
   status = ApzcUp(apzc, 10, 10, time);
   EXPECT_EQ(nsEventStatus_eIgnore, status);
 
   EXPECT_CALL(*mcc, HandleLongTapUp(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
 
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1408,16 +1408,17 @@ gfxContext::SetSource(gfxASurface *surfa
     CurrentState().color = Color(0, 0, 0, 0);
   }
 }
 
 void
 gfxContext::SetPattern(gfxPattern *pattern)
 {
   if (mCairo) {
+    MOZ_ASSERT(!pattern->IsAzure());
     cairo_set_source(mCairo, pattern->CairoPattern());
   } else {
     CurrentState().sourceSurfCairo = nullptr;
     CurrentState().sourceSurface = nullptr;
     CurrentState().patternTransformChanged = false;
     CurrentState().pattern = pattern;
   }
 }
@@ -1452,16 +1453,17 @@ gfxContext::GetPattern()
 }
 
 
 // masking
 void
 gfxContext::Mask(gfxPattern *pattern)
 {
   if (mCairo) {
+    MOZ_ASSERT(!pattern->IsAzure());
     cairo_mask(mCairo, pattern->CairoPattern());
   } else {
     if (pattern->Extend() == gfxPattern::EXTEND_NONE) {
       // In this situation the mask will be fully transparent (i.e. nothing
       // will be drawn) outside of the bounds of the surface. We can support
       // that by clipping out drawing to that area.
       Point offset;
       if (pattern->IsAzure()) {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2058,16 +2058,17 @@ gfxPlatform::GetOrientationSyncMillis() 
  */
 static bool sPrefLayersOffMainThreadCompositionEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionTestingEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionForceEnabled = false;
 static bool sPrefLayersAccelerationForceEnabled = false;
 static bool sPrefLayersAccelerationDisabled = false;
 static bool sPrefLayersPreferOpenGL = false;
 static bool sPrefLayersPreferD3D9 = false;
+static bool sPrefLayersDrawFPS = false;
 static bool sPrefLayersDump = false;
 static bool sPrefLayersScrollGraph = false;
 static bool sPrefLayersEnableTiles = false;
 static bool sLayersSupportsD3D9 = false;
 static int  sPrefLayoutFrameRate = -1;
 static int  sPrefLayersCompositionFrameRate = -1;
 static bool sBufferRotationEnabled = false;
 static bool sComponentAlphaEnabled = true;
@@ -2088,16 +2089,17 @@ InitLayersAccelerationPrefs()
 
     sPrefLayersOffMainThreadCompositionEnabled = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
     sPrefLayersOffMainThreadCompositionTestingEnabled = Preferences::GetBool("layers.offmainthreadcomposition.testing.enabled", false);
     sPrefLayersOffMainThreadCompositionForceEnabled = Preferences::GetBool("layers.offmainthreadcomposition.force-enabled", false);
     sPrefLayersAccelerationForceEnabled = Preferences::GetBool("layers.acceleration.force-enabled", false);
     sPrefLayersAccelerationDisabled = Preferences::GetBool("layers.acceleration.disabled", false);
     sPrefLayersPreferOpenGL = Preferences::GetBool("layers.prefer-opengl", false);
     sPrefLayersPreferD3D9 = Preferences::GetBool("layers.prefer-d3d9", false);
+    sPrefLayersDrawFPS = Preferences::GetBool("layers.acceleration.draw-fps", false);
     sPrefLayersDump = Preferences::GetBool("layers.dump", false);
     sPrefLayersScrollGraph = Preferences::GetBool("layers.scroll-graph", false);
     sPrefLayersEnableTiles = Preferences::GetBool("layers.enable-tiles", false);
     sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
     sPrefLayersCompositionFrameRate = Preferences::GetInt("layers.offmainthreadcomposition.frame-rate", -1);
     sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
     sComponentAlphaEnabled = Preferences::GetBool("layers.componentalpha.enabled", true);
     sPrefBrowserTabsRemote = BrowserTabsRemote();
@@ -2174,16 +2176,23 @@ gfxPlatform::GetPrefLayersPreferOpenGL()
 bool
 gfxPlatform::GetPrefLayersPreferD3D9()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersPreferD3D9;
 }
 
 bool
+gfxPlatform::GetPrefLayersDrawFPS()
+{
+  InitLayersAccelerationPrefs();
+  return sPrefLayersDrawFPS;
+}
+
+bool
 gfxPlatform::CanUseDirect3D9()
 {
   // this function is called from the compositor thread, so it is not
   // safe to init the prefs etc. from here.
   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
   return sLayersSupportsD3D9;
 }
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -508,16 +508,17 @@ public:
     static bool GetPrefLayersPreferOpenGL();
     static bool GetPrefLayersPreferD3D9();
     static bool CanUseDirect3D9();
     static int  GetPrefLayoutFrameRate();
     static int  GetPrefLayersCompositionFrameRate();
     static bool GetPrefLayersDump();
     static bool GetPrefLayersScrollGraph();
     static bool GetPrefLayersEnableTiles();
+    static bool GetPrefLayersDrawFPS();
 
     static bool OffMainThreadCompositionRequired();
 
     /**
      * Is it possible to use buffer rotation
      */
     static bool BufferRotationEnabled();
     static void DisableBufferRotation();
--- a/intl/locale/src/Makefile.in
+++ b/intl/locale/src/Makefile.in
@@ -2,21 +2,13 @@
 # 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/.
 
 ifeq ($(MOZ_WIDGET_TOOLKIT), qt)
 OS_INCLUDES	+= $(MOZ_QT_CFLAGS)
 endif
 
-EXPORT_RESOURCE = \
-		$(srcdir)/langGroups.properties \
-		$(srcdir)/language.properties \
-		$(NULL)
-
-
 include $(topsrcdir)/config/rules.mk
 
 charsetalias.properties.h: props2arrays.py charsetalias.properties
 	$(PYTHON) $^ $@
 
-libs::
-	$(INSTALL) $(EXPORT_RESOURCE) $(DIST)/bin/res
--- a/intl/locale/src/mac/nsDateTimeFormatMac.cpp
+++ b/intl/locale/src/mac/nsDateTimeFormatMac.cpp
@@ -209,28 +209,27 @@ nsresult nsDateTimeFormatMac::FormatTMTi
 
   CFTimeZoneRef timeZone = CFTimeZoneCopySystem(); // tmTime is in local time
   CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone);
   CFRelease(timeZone);
 
   CFStringRef formattedDate = CFDateFormatterCreateStringWithAbsoluteTime(nullptr,
                                                                           formatter,
                                                                           absTime);
-  
+
   CFIndex stringLen = CFStringGetLength(formattedDate);
-  
+
   nsAutoTArray<UniChar, 256> stringBuffer;
-  if (stringBuffer.SetLength(stringLen + 1)) {
-    CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements());
-    stringOut.Assign(reinterpret_cast<char16_t*>(stringBuffer.Elements()), stringLen);
-  }
-  
+  stringBuffer.SetLength(stringLen + 1);
+  CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements());
+  stringOut.Assign(reinterpret_cast<char16_t*>(stringBuffer.Elements()), stringLen);
+
   CFRelease(formattedDate);
   CFRelease(formatter);
-  
+
   return res;
 }
 
 // performs a locale sensitive date formatting operation on the PRTime parameter
 nsresult nsDateTimeFormatMac::FormatPRTime(nsILocale* locale, 
                                            const nsDateFormatSelector  dateFormatSelector, 
                                            const nsTimeFormatSelector timeFormatSelector, 
                                            const PRTime  prTime, 
--- a/intl/locale/src/moz.build
+++ b/intl/locale/src/moz.build
@@ -37,8 +37,13 @@ FINAL_LIBRARY = 'i18n'
 
 GENERATED_FILES = [
     'charsetalias.properties.h',
 ]
 
 LOCAL_INCLUDES += [
     '/intl/uconv/src',
 ]
+
+RESOURCE_FILES += [
+    'langGroups.properties',
+    'language.properties',
+]
--- a/intl/locale/src/nsLocaleService.cpp
+++ b/intl/locale/src/nsLocaleService.cpp
@@ -166,30 +166,28 @@ nsLocaleService::nsLocaleService(void)
 #ifdef XP_MACOSX
     // Get string representation of user's current locale
     CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
     CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
     ::CFRetain(userLocaleStr);
 
     nsAutoTArray<UniChar, 32> buffer;
     int size = ::CFStringGetLength(userLocaleStr);
-    if (buffer.SetLength(size + 1))
-    {
-        CFRange range = ::CFRangeMake(0, size);
-        ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
-        buffer[size] = 0;
+    buffer.SetLength(size + 1);
+    CFRange range = ::CFRangeMake(0, size);
+    ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
+    buffer[size] = 0;
 
-        // Convert the locale string to the format that Mozilla expects
-        nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
-        xpLocale.ReplaceChar('_', '-');
+    // Convert the locale string to the format that Mozilla expects
+    nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
+    xpLocale.ReplaceChar('_', '-');
 
-        nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
-        if (NS_SUCCEEDED(rv)) {
-            mApplicationLocale = mSystemLocale;
-        }
+    nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
+    if (NS_SUCCEEDED(rv)) {
+        mApplicationLocale = mSystemLocale;
     }
 
     ::CFRelease(userLocaleStr);
     ::CFRelease(userLocaleRef);
 
     NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
 #endif // XP_MACOSX
 }
--- a/intl/unicharutil/tables/Makefile.in
+++ b/intl/unicharutil/tables/Makefile.in
@@ -1,23 +1,11 @@
 #
 # 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 $(topsrcdir)/config/rules.mk
 
-_PROP_TABLES = \
-	htmlEntityVersions.properties \
-	html40Latin1.properties \
-	html40Symbols.properties \
-	html40Special.properties \
-	transliterate.properties \
-	mathml20.properties \
-	$(NULL)
-
 ifeq ($(MOZ_WIDGET_TOOLKIT), qt)
 CFLAGS          += $(MOZ_QT_CFLAGS)
 CXXFLAGS        += $(MOZ_QT_CFLAGS)
 endif
-
-libs:: $(_PROP_TABLES)
-	$(INSTALL) $^ $(DIST)/bin/res/entityTables
--- a/intl/unicharutil/tables/moz.build
+++ b/intl/unicharutil/tables/moz.build
@@ -1,6 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+RESOURCE_FILES.entityTables = [
+    'htmlEntityVersions.properties',
+    'html40Latin1.properties',
+    'html40Symbols.properties',
+    'html40Special.properties',
+    'mathml20.properties',
+    'transliterate.properties',
+]
--- a/intl/unicharutil/tests/Makefile.in
+++ b/intl/unicharutil/tests/Makefile.in
@@ -1,13 +1,11 @@
 #
 # 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_STATIC_LIBS = 1
-
 LIBS		= \
 	$(XPCOM_STATICRUNTIME_GLUE_LDOPTS) \
 	$(DIST)/lib/$(LIB_PREFIX)unicharutil_external_s.$(LIB_SUFFIX) \
 	$(XPCOM_LIBS) \
 	$(NSPR_LIBS) \
 	$(NULL)
--- a/intl/unicharutil/tests/moz.build
+++ b/intl/unicharutil/tests/moz.build
@@ -14,8 +14,9 @@ SOURCES += [
 SIMPLE_PROGRAMS += [
     "%s" % (fyl[0:-4]) for fyl in SOURCES
 ]
 
 LOCAL_INCLUDES += [
     '../public',
 ]
 
+USE_STATIC_LIBS = True
--- a/intl/unicharutil/util/Makefile.in
+++ b/intl/unicharutil/util/Makefile.in
@@ -5,18 +5,16 @@
 
 # This makefile builds the unicharutil_external_s library which should be used
 # by frozen (dependent) linkage components. Internal-linkage code should use
 # unicharutil_s which is built in the internal/ subdirectory.
 
 DIST_INSTALL = 1
 SDK_LIBRARY = $(LIBRARY)
 
-USE_STATIC_LIBS = 1
-
 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
--- a/intl/unicharutil/util/moz.build
+++ b/intl/unicharutil/util/moz.build
@@ -22,11 +22,12 @@ UNIFIED_SOURCES += intl_unicharutil_util
 LIBRARY_NAME = 'unicharutil_external_s'
 
 FORCE_STATIC_LIB = True
 
 LOCAL_INCLUDES += [
     '../src',
 ]
 
+USE_STATIC_LIBS = True
 
 if CONFIG['_MSC_VER']:
     DEFINES['_USE_ANSI_CPP'] = True
--- a/ipc/chromium/moz.build
+++ b/ipc/chromium/moz.build
@@ -255,18 +255,16 @@ if os_bsd:
         ]
         GENERATED_SOURCES += [
             'src/base/moc_message_pump_qt.cc',
         ]
     if not CONFIG['MOZ_NATIVE_LIBEVENT']:
         SOURCES += [
             'src/third_party/libevent/kqueue.c',
         ]
-        if not os_freebsd and not os_dragonfly:
-            DEFINES['_EVENT_HAVE_SENDFILE'] = True
 
 if CONFIG['_MSC_VER']:
     SOURCES += [
         'src/base/debug_on_start.cc',
     ]
 
 ost = CONFIG['OS_TEST']
 if ost.find('86') == -1 and ost.find('arm') == -1 and ost.find('mips') == -1:
--- a/ipc/chromium/src/third_party/libevent/bsd/event2/event-config.h
+++ b/ipc/chromium/src/third_party/libevent/bsd/event2/event-config.h
@@ -179,17 +179,17 @@
 
 /* Define to 1 if the system has the type `sa_family_t'. */
 #define _EVENT_HAVE_SA_FAMILY_T 1
 
 /* Define to 1 if you have the `select' function. */
 #define _EVENT_HAVE_SELECT 1
 
 /* Define to 1 if you have the `sendfile' function. */
-/* #undef _EVENT_HAVE_SENDFILE */
+#define _EVENT_HAVE_SENDFILE 1
 
 /* Define to 1 if you have the `setenv' function. */
 #define _EVENT_HAVE_SETENV 1
 
 /* Define if F_SETFD is defined in <fcntl.h> */
 #define _EVENT_HAVE_SETFD 1
 
 /* Define to 1 if you have the `sigaction' function. */
--- a/ipc/nfc/Nfc.cpp
+++ b/ipc/nfc/Nfc.cpp
@@ -152,27 +152,27 @@ public:
 
 private:
     nsAutoPtr<UnixSocketRawData> mMessage;
 };
 
 bool
 DispatchNFCEvent::RunTask(JSContext* aCx)
 {
-    JSObject* obj = JS::CurrentGlobalOrNull(aCx);
+    JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
 
     JSObject* array = JS_NewUint8Array(aCx, mMessage->mSize);
     if (!array) {
         return false;
     }
+    JS::Rooted<JS::Value> arrayVal(aCx, JS::ObjectValue(*array));
 
     memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
-    JS::Value argv[] = { OBJECT_TO_JSVAL(array) };
-    return JS_CallFunctionName(aCx, obj, "onNfcMessage",
-                               mozilla::ArrayLength(argv), argv, argv);
+    JS::Rooted<JS::Value> rval(aCx);
+    return JS_CallFunctionName(aCx, obj, "onNfcMessage", arrayVal, rval.address());
 }
 
 class NfcConnector : public mozilla::ipc::UnixSocketConnector
 {
 public:
     NfcConnector()
     {}
 
--- a/ipc/ril/Ril.cpp
+++ b/ipc/ril/Ril.cpp
@@ -159,27 +159,27 @@ public:
 
 private:
         nsAutoPtr<UnixSocketRawData> mMessage;
 };
 
 bool
 DispatchRILEvent::RunTask(JSContext *aCx)
 {
-    JSObject *obj = JS::CurrentGlobalOrNull(aCx);
+    JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
 
     JSObject *array = JS_NewUint8Array(aCx, mMessage->mSize);
     if (!array) {
         return false;
     }
+    JS::Rooted<JS::Value> arrayVal(aCx, JS::ObjectValue(*array));
 
     memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
-    JS::Value argv[] = { OBJECT_TO_JSVAL(array) };
-    return JS_CallFunctionName(aCx, obj, "onRILMessage",
-                               mozilla::ArrayLength(argv), argv, argv);
+    JS::Rooted<JS::Value> rval(aCx);
+    return JS_CallFunctionName(aCx, obj, "onRILMessage", arrayVal, rval.address());
 }
 
 class RilConnector : public mozilla::ipc::UnixSocketConnector
 {
 public:
   RilConnector(unsigned long aClientId) : mClientId(aClientId)
   {}
 
--- a/ipc/testshell/TestShellParent.cpp
+++ b/ipc/testshell/TestShellParent.cpp
@@ -68,18 +68,17 @@ TestShellCommandParent::RunCallback(cons
   JS::Rooted<JSObject*> global(mCx, JS::CurrentGlobalOrNull(mCx));
 
   JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
   NS_ENSURE_TRUE(str, false);
 
   JS::Rooted<JS::Value> strVal(mCx, JS::StringValue(str));
 
   JS::Rooted<JS::Value> rval(mCx);
-  bool ok = JS_CallFunctionValue(mCx, global, mCallback, 1, strVal.address(),
-                                   rval.address());
+  bool ok = JS_CallFunctionValue(mCx, global, mCallback, strVal, rval.address());
   NS_ENSURE_TRUE(ok, false);
 
   return true;
 }
 
 void
 TestShellCommandParent::ReleaseCallback()
 {
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -496,17 +496,18 @@ JavaScriptChild::AnswerCall(const Object
         }
     }
 
     RootedValue rval(cx);
     {
         AutoSaveContextOptions asco(cx);
         ContextOptionsRef(cx).setDontReportUncaught(true);
 
-        bool success = JS::Call(cx, vals[1], vals[0], vals.length() - 2, vals.begin() + 2, &rval);
+        HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2);
+        bool success = JS::Call(cx, vals[1], vals[0], args, &rval);
         if (!success)
             return fail(cx, rs);
     }
 
     if (!toVariant(cx, rval, result))
         return fail(cx, rs);
 
     // Prefill everything with a dummy jsval.
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -28,17 +28,16 @@ class AutoFunctionVector;
 class AutoIdVector;
 class AutoObjectVector;
 class AutoScriptVector;
 class AutoValueVector;
 
 class AutoIdArray;
 
 class AutoGCRooter;
-class AutoArrayRooter;
 template <typename T> class AutoVectorRooter;
 template<typename K, typename V> class AutoHashMapRooter;
 template<typename T> class AutoHashSetRooter;
 
 }
 
 // Do the importing.
 namespace js {
@@ -69,17 +68,16 @@ using JS::AutoFunctionVector;
 using JS::AutoIdVector;
 using JS::AutoObjectVector;
 using JS::AutoScriptVector;
 using JS::AutoValueVector;
 
 using JS::AutoIdArray;
 
 using JS::AutoGCRooter;
-using JS::AutoArrayRooter;
 using JS::AutoHashMapRooter;
 using JS::AutoHashSetRooter;
 using JS::AutoVectorRooter;
 
 using JS::CallArgs;
 using JS::CallNonGenericMethod;
 using JS::CallReceiver;
 using JS::CompileOptions;
@@ -115,13 +113,16 @@ using JS::HandleValue;
 using JS::MutableHandle;
 using JS::MutableHandleFunction;
 using JS::MutableHandleId;
 using JS::MutableHandleObject;
 using JS::MutableHandleScript;
 using JS::MutableHandleString;
 using JS::MutableHandleValue;
 
+using JS::NullHandleValue;
+using JS::UndefinedHandleValue;
+
 using JS::Zone;
 
 } /* namespace js */
 
 #endif /* NamespaceImports_h */
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -687,29 +687,29 @@ InitCollatorClass(JSContext *cx, HandleO
     /*
      * Install the getter for Collator.prototype.compare, which returns a bound
      * comparison function for the specified Collator object (suitable for
      * passing to methods like Array.prototype.sort).
      */
     RootedValue getter(cx);
     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().CollatorCompareGet, &getter))
         return nullptr;
-    RootedValue undefinedValue(cx, UndefinedValue());
-    if (!JSObject::defineProperty(cx, proto, cx->names().compare, undefinedValue,
+    if (!JSObject::defineProperty(cx, proto, cx->names().compare, UndefinedHandleValue,
                                   JS_DATA_TO_FUNC_PTR(JSPropertyOp, &getter.toObject()),
                                   nullptr, JSPROP_GETTER))
     {
         return nullptr;
     }
 
     // 10.2.1 and 10.3
-    RootedValue locales(cx, UndefinedValue());
-    RootedValue options(cx, UndefinedValue());
-    if (!IntlInitialize(cx, proto, cx->names().InitializeCollator, locales, options))
+    if (!IntlInitialize(cx, proto, cx->names().InitializeCollator, UndefinedHandleValue,
+                        UndefinedHandleValue))
+    {
         return nullptr;
+    }
 
     // 8.1
     RootedValue ctorValue(cx, ObjectValue(*ctor));
     if (!JSObject::defineProperty(cx, Intl, cx->names().Collator, ctorValue,
                                   JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
         return nullptr;